1 changed files with 111 additions and 1 deletions
@ -1,4 +1,114 @@ |
|||||||
|
/* © SRSoftware 2024 */ |
||||||
package de.srsoftware.cal.importer.weimar; |
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