diff --git a/build.gradle b/build.gradle index d0beaaa07..94f260d27 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 group = 'de.mediathekview' archivesBaseName = "MServer" -version = '3.1.231' +version = '3.1.232' def jarName = 'MServer.jar' def mainClass = 'mServer.Main' diff --git a/src/main/java/mServer/crawler/sender/base/JsonUtils.java b/src/main/java/mServer/crawler/sender/base/JsonUtils.java index b21495e37..3b0566f7e 100644 --- a/src/main/java/mServer/crawler/sender/base/JsonUtils.java +++ b/src/main/java/mServer/crawler/sender/base/JsonUtils.java @@ -113,6 +113,13 @@ public static boolean hasElements( return true; } + public static Optional getElementValueAsInteger(final JsonElement aJsonElement, final String... aElementIds) { + Optional rs = JsonUtils.getElement(aJsonElement, aElementIds); + if (rs.isPresent()) { + return Optional.of(rs.get().getAsInt()); + } + return Optional.empty(); + } /** * Checks if the {@link JsonObject} has all given elements and if no element * is null or empty. @@ -142,7 +149,7 @@ public static Optional getElementValueAsString(final JsonElement aJsonEl public static Optional getElement(final JsonElement aJsonElement, final String... aElementIds) { Optional rs = Optional.empty(); - if (aElementIds == null || aElementIds.length == 0) { + if (aElementIds == null || aElementIds.length == 0 || aJsonElement == null || !aJsonElement.isJsonObject()) { return rs; } JsonObject aJsonObject = aJsonElement.getAsJsonObject(); diff --git a/src/main/java/mServer/crawler/sender/orfon/json/OrfOnEpisodeDeserializer.java b/src/main/java/mServer/crawler/sender/orfon/json/OrfOnEpisodeDeserializer.java index 16ce043d9..b4358b1ca 100644 --- a/src/main/java/mServer/crawler/sender/orfon/json/OrfOnEpisodeDeserializer.java +++ b/src/main/java/mServer/crawler/sender/orfon/json/OrfOnEpisodeDeserializer.java @@ -45,6 +45,7 @@ public class OrfOnEpisodeDeserializer implements JsonDeserializer parseSubtitleUrls(JsonElement element) { return JsonUtils.getElementValueAsString(element, TAG_SUBTITLE_TTML); } - private Optional> parseUrl(JsonElement jsonElement) { + private Optional> parseVideoFromSegmentPlaylist(JsonElement jsonElement) { Optional videoPath1 = JsonUtils.getElement(jsonElement, TAG_VIDEO_PATH_1); if (videoPath1.isEmpty() || !videoPath1.get().isJsonArray() || videoPath1.get().getAsJsonArray().size() == 0) { return Optional.empty(); @@ -157,10 +158,10 @@ private Optional> parseUrl(JsonElement jsonElement) { } } } - return parseFallbackVideo(jsonElement); + return parseVideoFromSources(jsonElement); } - private Optional> parseFallbackVideo(JsonElement root) { + private Optional> parseVideoFromSources(JsonElement root) { Optional videoSources = JsonUtils.getElement(root, TAG_VIDEO_FALLBACK); if (videoSources.isPresent()) { Map urls = new EnumMap<>(Qualities.class); @@ -177,7 +178,31 @@ private Optional> parseFallbackVideo(JsonElement root) { } } } - return Optional.empty(); + return parseVideoFromThumbnail(root); + } + + private Optional> parseVideoFromThumbnail(JsonElement root) { + Map urls = new EnumMap<>(Qualities.class); + try { + Optional id = JsonUtils.getElement(root, TAG_ID); + Optional thumbnailSources = JsonUtils.getElement(root, VIDEO_THUMBNAIL); + if (id.isPresent() && thumbnailSources.isPresent() && thumbnailSources.get().isJsonArray() && thumbnailSources.get().getAsJsonArray().size() > 0 ) { + Optional thumbnailSrc = JsonUtils.getElement(thumbnailSources.get().getAsJsonArray().get(0), "src"); + if (thumbnailSrc.isPresent()) { + int indexId = thumbnailSrc.get().getAsString().indexOf(id.get().getAsString()); + String fromSecondIdOnwards = thumbnailSrc.get().getAsString().substring(indexId + id.get().getAsString().length() + 1); + String secondId = fromSecondIdOnwards.substring(0, fromSecondIdOnwards.indexOf("_")); + String url = String.format("https://apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/%s_%s_QXA.mp4/playlist.m3u8", id.get().getAsString(), secondId); + urls.put(Qualities.NORMAL, url); + } + } + } catch (Exception e) { + LOG.error("generateFallbackVideo {}", e); + } + if (urls.size() == 0) { + return Optional.empty(); + } + return Optional.of(urls); } private Optional> readVideoForTargetCodec(JsonElement urlArray, String targetCodec) { diff --git a/src/main/java/mServer/crawler/sender/zdf/json/ZdfFilmDetailDeserializer.java b/src/main/java/mServer/crawler/sender/zdf/json/ZdfFilmDetailDeserializer.java index c0e173561..3c63ec63e 100644 --- a/src/main/java/mServer/crawler/sender/zdf/json/ZdfFilmDetailDeserializer.java +++ b/src/main/java/mServer/crawler/sender/zdf/json/ZdfFilmDetailDeserializer.java @@ -39,7 +39,9 @@ public class ZdfFilmDetailDeserializer implements JsonDeserializer parseDescription(JsonObject aRootNode) { return Optional.empty(); } - private Optional parseTitle(JsonObject aRootNode, JsonObject aTarget) { - Optional title = parseTitleValue(aRootNode, aTarget); - return title.map(s -> s.replaceAll("\\(CC.*\\) - .* Creative Commons.*", "")); + private Optional parseTitle(final JsonObject aRootNode, final JsonObject aTarget) { + final Optional programmTitle = JsonUtils.getElementValueAsString(aRootNode, JSON_ELEMENT_TITLE); + final Optional programmSubtitle = JsonUtils.getElementValueAsString(aRootNode, JSON_ELEMENT_SUBTITLE); + Optional resultingTitle = formatTitle(programmTitle, programmSubtitle); + if (resultingTitle.isEmpty()) { + final Optional targetTitle = JsonUtils.getElementValueAsString(aTarget, JSON_ELEMENT_TITLE); + final Optional targetSubtitle = JsonUtils.getElementValueAsString(aTarget, JSON_ELEMENT_SUBTITLE); + resultingTitle = formatTitle(targetTitle, targetSubtitle); + } + if (resultingTitle.isPresent()) { + final Optional season = JsonUtils.getElementValueAsInteger(aTarget, SEASONNUMBER); + final Optional episode = JsonUtils.getElementValueAsInteger(aTarget, EPISODENUMBER); + final Optional seasonEpisodeTitle = formatEpisodeTitle(season, episode); + final Optional title = cleanupTitle((resultingTitle.get() + " " + seasonEpisodeTitle.orElse("")).trim()); + return title; + } + return Optional.empty(); } - - private Optional parseTitleValue(JsonObject aRootNode, JsonObject aTarget) { - // use property "title" if found - JsonElement titleElement = aRootNode.get(JSON_ELEMENT_TITLE); - if (titleElement != null) { - JsonElement subTitleElement = aRootNode.get(JSON_ELEMENT_SUBTITLE); - if (subTitleElement != null) { - return Optional.of(titleElement.getAsString().trim() + " - " + subTitleElement.getAsString()); - } else { - return Optional.of(titleElement.getAsString()); - } + + private Optional cleanupTitle(String title) { + return Optional.of(title.replaceAll("\\(CC.*\\) - .* Creative Commons.*", "")); + } + + private Optional formatTitle(Optional title, Optional sub) { + if (title.isEmpty()) { + return Optional.empty(); + } + if (sub.isPresent() && !sub.get().isBlank()) { + return Optional.of(title.get().trim() + " - " + sub.get().trim()); } else { - // programmItem target required to determine title - if (aTarget != null && aTarget.has(JSON_ELEMENT_TITLE)) { - String title = aTarget.get(JSON_ELEMENT_TITLE).getAsString(); - String subTitle = aTarget.get(JSON_ELEMENT_SUBTITLE).getAsString(); - - if (subTitle.isEmpty()) { - return Optional.of(title); - } else { - return Optional.of(title.trim() + " - " + subTitle); - } - } + return Optional.of(title.get().trim()); } - - return Optional.empty(); } - + + private Optional formatEpisodeTitle(Optional season, Optional episode) { + if (season.isEmpty() && episode.isEmpty()) { + return Optional.empty(); + } + String result = ""; + if (season.isPresent()) { + result += String.format("S%02d", season.get()); + } + if (episode.isPresent()) { + result += String.format("E%02d", episode.get()); + } + return Optional.of("("+result+")"); + } private Optional parseTopic(JsonObject aRootNode) { JsonObject brand = aRootNode.getAsJsonObject(JSON_ELEMENT_BRAND); JsonObject category = aRootNode.getAsJsonObject(JSON_ELEMENT_CATEGORY);