added importer for CafeWagner

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2025-01-02 00:52:21 +01:00
parent e0dde9aa9e
commit 3f80b13d8e
9 changed files with 270 additions and 59 deletions
@@ -2,15 +2,14 @@
package de.srsoftware.cal;
import static de.srsoftware.cal.Util.combine;
import static de.srsoftware.cal.Util.url;
import static de.srsoftware.tools.Error.error;
import static de.srsoftware.tools.Result.transform;
import static de.srsoftware.tools.Tag.HREF;
import static de.srsoftware.tools.TagFilter.*;
import static java.lang.System.Logger.Level.WARNING;
import de.srsoftware.cal.api.*;
import de.srsoftware.tools.*;
import de.srsoftware.tools.Error;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
@@ -26,7 +25,6 @@ import java.util.function.Predicate;
import java.util.stream.Stream;
public abstract class BaseImporter implements Importer {
private static final System.Logger LOG = System.getLogger(BaseImporter.class.getSimpleName());
private static final String SHA256 = "SHA-256";
private final MessageDigest digest;
@@ -48,8 +46,8 @@ public abstract class BaseImporter implements Importer {
.filter(Objects::nonNull)
.map(url -> url.contains("://") ? url : baseUrl()+url)
.map(Payload::of)
.map(BaseImporter::url)
.map(BaseImporter::toAttachment)
.map(Util::url)
.map(Util::toAttachment)
.map(Result::optional)
.flatMap(Optional::stream)
.toList();
@@ -190,7 +188,7 @@ public abstract class BaseImporter implements Importer {
if (href == null) return null;
if (!href.contains("://")) href = baseUrl()+href;
var txt = anchor.strip();
return BaseImporter.url(Payload.of(href)).optional().map(url -> new Link(url,txt)).orElse(null);
return url(Payload.of(href)).optional().map(url -> new Link(url,txt)).orElse(null);
})
.filter(Objects::nonNull)
.toList();
@@ -262,7 +260,7 @@ public abstract class BaseImporter implements Importer {
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()) : error("No title found");
return inner.isPresent() ? Payload.of(inner.get().trim()) : error("No title found");
}
protected Result<Tag> extractTitleTag(Tag eventTag){
@@ -283,11 +281,8 @@ public abstract class BaseImporter implements Importer {
.map(this::extractEventUrls)
.stream();
return urls //
.map(BaseImporter::url)
.map(Util::url)
.map(this::loadEvent)
.peek(e -> {
if (e instanceof Error<Appointment> err) System.err.println(err);
})
.flatMap(result -> result.optional().stream());
}
@@ -351,42 +346,4 @@ public abstract class BaseImporter implements Importer {
protected abstract String programURL();
protected static Result<Attachment> toAttachment(Result<URL> urlResult) {
var opt = urlResult.optional();
if (opt.isEmpty()) return transform(urlResult);
try {
var mime = opt.get().openConnection().getContentType();
return Payload.of(new Attachment(opt.get(), mime));
} catch (Exception e) {
LOG.log(WARNING, "Failed to read mime type of {0}", opt.get());
return error("Failed to read mime type of %s", opt.get());
}
}
protected static Result<Integer> toNumericMonth(String month) {
month = month.toLowerCase();
if (month.startsWith("ja")) return Payload.of(1);
if (month.startsWith("f")) return Payload.of(2);
if ("may".equals(month) || "mai".equals(month)) return Payload.of(5);
if (month.startsWith("m")) return Payload.of(3);
if (month.startsWith("ap")) return Payload.of(4);
if (month.startsWith("jun")) return Payload.of(6);
if (month.startsWith("jul")) return Payload.of(7);
if (month.startsWith("au")) return Payload.of(8);
if (month.startsWith("s")) return Payload.of(9);
if (month.startsWith("o")) return Payload.of(10);
if (month.startsWith("n")) return Payload.of(11);
if (month.startsWith("d")) return Payload.of(12);
return error("Failed to recognize \"%s\" as a month!", month);
}
protected static Result<URL> url(Result<String> urlResult) {
if (urlResult.optional().isEmpty()) return transform(urlResult);
var url = urlResult.optional().get();
try {
return Payload.of(new URI(url).toURL());
} catch (MalformedURLException | URISyntaxException e) {
return error(e, "Failed to create URL of %s", url);
}
}
}
@@ -3,10 +3,18 @@ package de.srsoftware.cal;
import static de.srsoftware.tools.Error.error;
import static de.srsoftware.tools.Result.transform;
import static de.srsoftware.tools.Tag.STYLE;
import static java.lang.System.Logger.Level.WARNING;
import de.srsoftware.cal.api.Attachment;
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;
import java.time.LocalTime;
@@ -33,6 +41,8 @@ public class Util {
public static final Pattern GERMAN_DATE_PATTERN = Pattern.compile("\\D(\\d\\d?)\\.(\\d\\d?)\\.(\\d{4})\\D");
public static final Pattern GERMAN_TIME_PATTERN = Pattern.compile("\\D(\\d\\d?):(\\d\\d?)(:(\\d\\d?))?\\D");
private static final Pattern BG_IMAGE_URL = Pattern.compile("background(-image)?:\\surl\\(([^)]+)\\)");
private static final System.Logger LOG = System.getLogger(Util.class.getSimpleName());
private Util(){}
@@ -114,6 +124,24 @@ public class Util {
return error("Failed to find time");
}
public static Result<Integer> toNumericMonth(String month) {
month = month.toLowerCase();
if (month.startsWith("ja")) return Payload.of(1);
if (month.startsWith("f")) return Payload.of(2);
if ("may".equals(month) || "mai".equals(month)) return Payload.of(5);
if (month.startsWith("m")) return Payload.of(3);
if (month.startsWith("ap")) return Payload.of(4);
if (month.startsWith("jun")) return Payload.of(6);
if (month.startsWith("jul")) return Payload.of(7);
if (month.startsWith("au")) return Payload.of(8);
if (month.startsWith("s")) return Payload.of(9);
if (month.startsWith("o")) return Payload.of(10);
if (month.startsWith("n")) return Payload.of(11);
if (month.startsWith("d")) return Payload.of(12);
return error("Failed to recognize \"%s\" as a month!", month);
}
/**
* wraps a text (list of vevents in a vcalendar, as described in th <a href="https://datatracker.ietf.org/doc/html/rfc5545#section-3.4">iCalendar spec</a>
* @param ical the vevents list
@@ -132,4 +160,38 @@ public class Util {
}
return ical;
}
public static Result<String> extractBackgroundImage(Tag tag, String baseUrl) {
var style = tag.get(STYLE);
if (style != null){
var matcher = BG_IMAGE_URL.matcher(style);
if (matcher.find()) {
var link = matcher.group(2);
return Payload.of(link.contains("://") ? link : baseUrl+link);
}
}
return error("Failed to findbackground image url in %s",tag);
}
public static Result<Attachment> toAttachment(Result<URL> urlResult) {
var opt = urlResult.optional();
if (opt.isEmpty()) return transform(urlResult);
try {
var mime = opt.get().openConnection().getContentType();
return Payload.of(new Attachment(opt.get(), mime));
} catch (Exception e) {
LOG.log(WARNING, "Failed to read mime type of {0}", opt.get());
return error("Failed to read mime type of %s", opt.get());
}
}
public static Result<URL> url(Result<String> urlResult) {
if (urlResult.optional().isEmpty()) return transform(urlResult);
var url = urlResult.optional().get();
try {
return Payload.of(new URI(url).toURL());
} catch (MalformedURLException | URISyntaxException e) {
return error(e, "Failed to create URL of %s", url);
}
}
}