added importer for FHaus and Psychochor

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2025-01-02 12:28:14 +01:00
parent 3f80b13d8e
commit 2491e4fbf0
10 changed files with 421 additions and 24 deletions
+1 -1
View File
@@ -5,6 +5,6 @@ dependencies {
implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.util:1.3.0")
implementation("de.srsoftware:tools.web:1.3.11")
implementation("de.srsoftware:tools.web:1.3.12")
implementation("org.json:json:20240303")
}
@@ -13,6 +13,8 @@ import de.srsoftware.tools.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
@@ -25,10 +27,11 @@ import java.util.function.Predicate;
import java.util.stream.Stream;
public abstract class BaseImporter implements Importer {
public static final System.Logger LOG = System.getLogger(BaseImporter.class.getSimpleName());
private static final String SHA256 = "SHA-256";
private final MessageDigest digest;
protected BaseImporter() throws NoSuchAlgorithmException {
public BaseImporter() throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance(SHA256);
}
@@ -66,7 +69,7 @@ public abstract class BaseImporter implements Importer {
Result<Tag> descriptionTag = extractDescriptionTag(eventTag);
if (descriptionTag.optional().isEmpty()) return transform(descriptionTag);
Tag tag = descriptionTag.optional().get();
tag.find(t -> t.is("iframe")).forEach(Tag::remove);
tag.find(ofType("iframe")).forEach(Tag::remove);
var inner = tag.inner(2);
return inner.isPresent() ? Payload.of(inner.get()) : error("No description found");
}
@@ -126,6 +129,9 @@ public abstract class BaseImporter implements Importer {
long id = 0;
// wird vor extractDescription ausgeführt, da extractDescription das DOM verändert
var coords = extractCoords(eventTag);
var titleResult = extractTitle(eventTag);
if (titleResult.optional().isEmpty()) return transform(titleResult);
String title = titleResult.optional().get();
@@ -151,7 +157,7 @@ public abstract class BaseImporter implements Importer {
.addLinks(eventPage)
.tags(extractTags(eventTag));
extractCoords(eventTag).optional().ifPresent(event::coords);
coords.optional().ifPresent(event::coords);
return Payload.of(event);
}
@@ -205,7 +211,7 @@ public abstract class BaseImporter implements Importer {
protected Result<String> extractLocation(Tag eventTag) {
Result<Tag> locationTag = extractLocationTag(eventTag);
if (locationTag.optional().isEmpty()) return transform(locationTag);
return Payload.of(locationTag.optional().get().toString(2));
return Payload.of(locationTag.optional().get().strip());
}
protected Result<Tag> extractLocationTag(Tag eventTag){
@@ -257,7 +263,7 @@ public abstract class BaseImporter implements Importer {
protected abstract List<String> extractTags(Tag eventTag);
protected Result<String> extractTitle(Tag eventTag) {
Result<Tag> titleTag = extractTitleTag(eventTag);
Result<Tag> titleTag = extractTitleTag(eventTag);
if (titleTag.optional().isEmpty()) return transform(titleTag);
var inner = titleTag.optional().flatMap(tag -> tag.inner(2));
return inner.isPresent() ? Payload.of(inner.get().trim()) : error("No title found");
@@ -283,6 +289,7 @@ public abstract class BaseImporter implements Importer {
return urls //
.map(Util::url)
.map(this::loadEvent)
.peek(res -> { if (res.optional().isEmpty()) LOG.log(System.Logger.Level.WARNING,res); })
.flatMap(result -> result.optional().stream());
}
@@ -0,0 +1,47 @@
/* © SRSoftware 2024 */
package de.srsoftware.cal;
import static de.srsoftware.cal.Util.url;
import de.srsoftware.cal.api.Appointment;
import de.srsoftware.cal.api.Link;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.Tag;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.stream.Stream;
public abstract class SinglePageImporter extends BaseImporter{
public SinglePageImporter() throws NoSuchAlgorithmException {
super();
}
@Override
public Stream<Appointment> fetch() {
var programPage = Payload.of(programURL());
var eventLink = programPage //
.map(Util::url).optional()
.map(url -> new Link(url, "Event-Seite"))
.orElse(null);
Stream<Result<Tag>> eventTags = url(programPage).map(this::open).map(this::preload)
.map(this::parseXML)
.map(this::extractEventTags)
.stream();
return eventTags.map(tagResult -> extractEvent(tagResult, eventLink))
.peek(res -> {
if (res.optional().isEmpty()) LOG.log(System.Logger.Level.WARNING, res);
})
.flatMap(res -> res.optional().stream());
}
protected abstract Result<List<Tag>> extractEventTags(Result<Tag> tagResult);
@Override
protected Result<List<String>> extractEventUrls(Result<Tag> programPage) {
return null; // not needed by this fetch implementation
}
}
@@ -11,9 +11,7 @@ import de.srsoftware.cal.api.Coords;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.Tag;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -190,7 +188,7 @@ public class Util {
var url = urlResult.optional().get();
try {
return Payload.of(new URI(url).toURL());
} catch (MalformedURLException | URISyntaxException e) {
} catch (Exception e) {
return error(e, "Failed to create URL of %s", url);
}
}