1 changed files with 111 additions and 1 deletions
@ -1,4 +1,114 @@
@@ -1,4 +1,114 @@
|
||||
/* © SRSoftware 2024 */ |
||||
package de.srsoftware.cal.importer.weimar; |
||||
|
||||
public class CKeller { |
||||
import static de.srsoftware.tools.Error.error; |
||||
import static de.srsoftware.tools.Optionals.nullable; |
||||
import static de.srsoftware.tools.Result.transform; |
||||
import static de.srsoftware.tools.Tag.*; |
||||
import static de.srsoftware.tools.TagFilter.*; |
||||
import static java.util.Optional.empty; |
||||
|
||||
import de.srsoftware.cal.BaseAppointment; |
||||
import de.srsoftware.cal.Util; |
||||
import de.srsoftware.cal.api.Appointment; |
||||
import de.srsoftware.cal.api.Attachment; |
||||
import de.srsoftware.cal.api.Importer; |
||||
import de.srsoftware.cal.api.Link; |
||||
import de.srsoftware.tools.Payload; |
||||
import de.srsoftware.tools.Result; |
||||
import de.srsoftware.tools.Tag; |
||||
import java.io.IOException; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URI; |
||||
import java.time.LocalDate; |
||||
import java.time.LocalDateTime; |
||||
import java.time.LocalTime; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Objects; |
||||
import java.util.Optional; |
||||
import java.util.regex.Pattern; |
||||
import java.util.stream.Stream; |
||||
|
||||
public class CKeller implements Importer { |
||||
private static final String BASE_URL = "http://c-keller.de"; |
||||
private static final Pattern YEAR_PATTERN = Pattern.compile("^(\\d{4}):?$"); |
||||
private static final Pattern EVENT_PATTERN = Pattern.compile("\\D*(\\d\\d?).(\\d\\d?). *([^&]+)&[^;]+;(.*)"); |
||||
private static final String LOCATION = "C-Keller, Markt 21, 99423 Weimar"; |
||||
private static final LocalTime START_TIME = LocalTime.of(19,0); |
||||
private final Link link; |
||||
|
||||
public CKeller() throws MalformedURLException { |
||||
link = new Link(URI.create(BASE_URL).toURL(),"Homepage"); |
||||
} |
||||
@Override |
||||
public String description() { |
||||
return "Importer für Events des C-Keller in Weimar"; |
||||
} |
||||
|
||||
@Override |
||||
public Stream<Appointment> fetch() throws IOException { |
||||
return Payload.of(BASE_URL) |
||||
.map(Util::url) |
||||
.map(Util::open) |
||||
.map(Util::preload) |
||||
.map(Util::parseXML) |
||||
.map(this::extract) |
||||
.optional() |
||||
.orElseGet(List::of) |
||||
.stream(); |
||||
} |
||||
|
||||
private Result<List<Appointment>> extract(Result<Tag> tagResult) { |
||||
var list = new ArrayList<Appointment>(); |
||||
if (tagResult.optional().isEmpty()) return transform(tagResult); |
||||
Util.dump(tagResult.optional().get()); |
||||
var divs = tagResult.optional().get() |
||||
.find(attributeEquals(ID,"col2_content")).stream() |
||||
.flatMap(tag -> tag.children().stream()) |
||||
.toList(); |
||||
Tag last = null; |
||||
var now = LocalDate.now(); |
||||
for (var div : divs){ |
||||
if ("textumschluss".equals(div.get(ID))){ |
||||
createEvent(last,div,now).ifPresent(list::add); |
||||
} |
||||
last = div; |
||||
} |
||||
return Payload.of(list); |
||||
} |
||||
|
||||
private Optional<Appointment> createEvent(Tag cal, Tag text, LocalDate now) { |
||||
var day = cal.find(attributeEquals(CLASS, "calday")).stream() |
||||
.map(Tag::strip).map(Util::parseInt).findAny().orElseGet(() -> error("No date")).optional(); |
||||
if (day.isEmpty()) return empty(); |
||||
|
||||
Stream<Result<Integer>> stream = cal.find(attributeEquals(CLASS, "calmonth")).stream().map(Tag::strip).flatMap(s -> Util.toNumericMonth(s).stream()); |
||||
Optional<Integer> mon = stream.findAny().orElse(error("Error")).optional(); |
||||
if (mon.isEmpty()) return empty(); |
||||
var title = text.find(attributeEquals(CLASS,"fett")).stream().map(Tag::strip).findAny(); |
||||
if (title.isEmpty()) return empty(); |
||||
var desc = text.find(attributeEquals(CLASS,"kalenderi")).stream().map(Tag::strip).findAny(); |
||||
|
||||
var date = LocalDate.of(now.getYear(),mon.get(),day.get()); |
||||
if (date.isBefore(now)) date = date.withYear(now.getYear()+1); |
||||
var start = LocalDateTime.of(date,START_TIME); |
||||
var app = new BaseAppointment(0,title.get(),desc.orElse(title.get()),start,null,LOCATION); |
||||
|
||||
text.find(IS_IMAGE).stream().map(tag -> imageToAttachment(tag)) |
||||
.map(Result::optional).flatMap(Optional::stream) |
||||
.forEach(app::add); |
||||
app.addLinks(link); |
||||
app.tags("C-Keller","Weimar"); |
||||
return Optional.of(app); |
||||
} |
||||
|
||||
private Result<Attachment> imageToAttachment(Tag img) { |
||||
var parent = img.parent(); |
||||
String url = parent.map(tag -> tag.get(HREF)).orElseGet(() -> img.get("src")); |
||||
if (url == null) return error("No link found"); |
||||
if (url.startsWith("./")) url = url.substring(2); |
||||
if (!url.contains("://")) url = BASE_URL + "/" + url; |
||||
return Payload.of(url).map(Util::url).map(Util::toAttachment); |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue