diff --git a/src/main/java/de/mediathekview/mserver/crawler/orfon/OrfOnCrawler.java b/src/main/java/de/mediathekview/mserver/crawler/orfon/OrfOnCrawler.java index 990697f3c..ff9a40ecd 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/orfon/OrfOnCrawler.java +++ b/src/main/java/de/mediathekview/mserver/crawler/orfon/OrfOnCrawler.java @@ -101,8 +101,12 @@ private Queue createDayUrlsToCrawl() { private Set processAZUrlsToCrawl() throws InterruptedException, ExecutionException { final ForkJoinTask> letterTask = forkJoinPool.submit(new OrfOnAZTask(this, createAZUrlsToCrawl())); final Set letterTaskTopics = letterTask.get(); - final ForkJoinTask> videosFromTopicsTask = forkJoinPool.submit(new OrfOnEpisodesTask(this, new ConcurrentLinkedQueue<>(letterTaskTopics))); - return videosFromTopicsTask.get(); + final ForkJoinTask> episodesFromTopicsTask = forkJoinPool.submit(new OrfOnEpisodesTask(this, new ConcurrentLinkedQueue<>(letterTaskTopics))); + final Set episodesFromTopics = episodesFromTopicsTask.get(); + final ForkJoinTask> videoEpisodeTask = forkJoinPool.submit(new OrfOnEpisodeTask(this, new ConcurrentLinkedQueue<>(episodesFromTopics))); + final Set videoEpisode = videoEpisodeTask.get(); + return videoEpisode; + } diff --git a/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodeDeserializer.java b/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodeDeserializer.java index 49bd56f24..35937ba8e 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodeDeserializer.java +++ b/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodeDeserializer.java @@ -43,12 +43,12 @@ public class OrfOnEpisodeDeserializer implements JsonDeserializer toURL(String aString) { } private Optional> parseUrl(JsonElement jsonElement) { - - for (Map.Entry entry : jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).entrySet()) { - - if (!"hlshdssmoothdashprogressive_download".contains(entry.getKey())) { - LOG.debug("unkown video type {} ", jsonElement); + Optional videoPath1 = JsonUtils.getElement(jsonElement, TAG_VIDEO_PATH_1); + if (videoPath1.isEmpty() || !videoPath1.get().isJsonArray()) { + return Optional.empty(); + } + Optional videoPath2 = JsonUtils.getElement(videoPath1.get().getAsJsonArray().get(0), TAG_VIDEO_PATH_2); + if (videoPath2.isEmpty() || !videoPath2.get().isJsonArray()) { + return Optional.empty(); + } + for (String key : PREFERED_CODEC) { + Optional> resultingVideos = readVideoForTargetCodec(videoPath2.get(),key); + if (resultingVideos.isPresent()) { + return resultingVideos; } } - Optional> urls = Optional.empty(); - Optional codec = Optional.empty(); // - if (jsonElement.getAsJsonObject().has(TAG_VIDEO) && - jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).has("progressive_download")) { - codec = Optional.of("progressive_download"); - } else if (jsonElement.getAsJsonObject().has(TAG_VIDEO) && - jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).has("hls")) { - codec = Optional.of("hls"); - } else if (jsonElement.getAsJsonObject().has(TAG_VIDEO) && - jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).has("hds")) { - codec = Optional.of("hds"); - } else if (jsonElement.getAsJsonObject().has(TAG_VIDEO) && - jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).has("smooth")) { - codec = Optional.of("smooth"); - } else if (jsonElement.getAsJsonObject().has(TAG_VIDEO) && - jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).has("dash")) { - codec = Optional.of("dash"); - } - if (codec.isPresent()) { - urls = Optional.of(new EnumMap<>(Resolution.class)); - for (JsonElement codecUrls : jsonElement.getAsJsonObject().getAsJsonObject(TAG_VIDEO).getAsJsonArray(codec.get())) { + return Optional.empty(); + } + + private Optional> readVideoForTargetCodec(JsonElement urlArray, String targetCodec) { + Map urls = new EnumMap<>(Resolution.class); + for (JsonElement videoElement : urlArray.getAsJsonArray()) { + Optional codec = JsonUtils.getElementValueAsString(videoElement, TAG_VIDEO_CODEC); + Optional quality = JsonUtils.getElementValueAsString(videoElement, TAG_VIDEO_QUALITY); + Optional url = JsonUtils.getElementValueAsString(videoElement, TAG_VIDEO_URL); + if (url.isPresent() && codec.isPresent() && quality.isPresent() && targetCodec.equalsIgnoreCase(codec.get())) { try { - String qualityString = codecUrls.getAsJsonObject().get(TAG_VIDEO_QUALITY).getAsString(); - String url = codecUrls.getAsJsonObject().get(TAG_VIDEO_URL).getAsString(); - urls.get().put( - OrfOnEpisodeDeserializer.getQuality(qualityString).get(), - new FilmUrl(url, 0L) - ); - } catch (Exception e) { - LOG.error( - "parseUrl failed for quality {} and url {} exception {}", - codecUrls.getAsJsonObject().get("quality_key").getAsString(), - codecUrls.getAsJsonObject().get("src").getAsString(), - e - ); + long fileSize = crawler.determineFileSizeInKB(url.get()); + urls.put( + OrfOnEpisodeDeserializer.getQuality(quality.get()).get(), + new FilmUrl(url.get(), fileSize) + ); + } catch (MalformedURLException e) { + LOG.error("Malformed video url {} {}", url.get(), e); } } - if (urls.get().size() == 0) { - return Optional.empty(); - } } - return urls; + if (urls.isEmpty()) { + Optional.empty(); + } + return Optional.of(urls); } + private Optional parseWebsite(Optional text) { Optional result = Optional.empty(); if (text.isPresent()) { diff --git a/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodesDeserializer.java b/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodesDeserializer.java index d8510d988..efacb650d 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodesDeserializer.java +++ b/src/main/java/de/mediathekview/mserver/crawler/orfon/json/OrfOnEpisodesDeserializer.java @@ -3,35 +3,33 @@ import com.google.gson.*; import de.mediathekview.mserver.base.utils.JsonUtils; -import de.mediathekview.mserver.crawler.basic.AbstractCrawler; import de.mediathekview.mserver.crawler.basic.PagedElementListDTO; -import de.mediathekview.mserver.crawler.orfon.OrfOnVideoInfoDTO; +import de.mediathekview.mserver.crawler.orfon.OrfOnBreadCrumsUrlDTO; import java.lang.reflect.Type; import java.util.Optional; -public class OrfOnEpisodesDeserializer implements JsonDeserializer> { +public class OrfOnEpisodesDeserializer implements JsonDeserializer> { private static final String[] TAG_NEXT_PAGE = {"_links", "next", "href"}; private static final String[] TAG_ITEMS = {"_embedded", "items"}; - private OrfOnEpisodeDeserializer itemDeserializer = null; - - public OrfOnEpisodesDeserializer(AbstractCrawler crawler) { - itemDeserializer = new OrfOnEpisodeDeserializer(crawler); - } + private static final String TAG_EPISODE_ID = "id"; + private static final String[] TAG_EPISODE_LINK = { "_links", "self", "href"}; @Override - public PagedElementListDTO deserialize( + public PagedElementListDTO deserialize( final JsonElement jsonElement, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException { JsonObject jsonPage = jsonElement.getAsJsonObject(); // - PagedElementListDTO page = new PagedElementListDTO<>(); + PagedElementListDTO page = new PagedElementListDTO<>(); page.setNextPage(JsonUtils.getElementValueAsString(jsonElement, TAG_NEXT_PAGE)); // final Optional items = JsonUtils.getElement(jsonPage, TAG_ITEMS); if (items.isPresent() && items.get().isJsonArray()) { for (JsonElement item : items.get().getAsJsonArray()) { - page.addElement(itemDeserializer.deserialize(item, null, null)); + Optional episodeId = JsonUtils.getElementValueAsString(item, TAG_EPISODE_ID); + Optional episodeLink = JsonUtils.getElementValueAsString(item, TAG_EPISODE_LINK); + episodeLink.ifPresent( link -> page.addElement(new OrfOnBreadCrumsUrlDTO(episodeId.orElse("EMPTY"), link))); } } return page; diff --git a/src/main/java/de/mediathekview/mserver/crawler/orfon/task/OrfOnEpisodesTask.java b/src/main/java/de/mediathekview/mserver/crawler/orfon/task/OrfOnEpisodesTask.java index 3b625f3b5..ba4ed4627 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/orfon/task/OrfOnEpisodesTask.java +++ b/src/main/java/de/mediathekview/mserver/crawler/orfon/task/OrfOnEpisodesTask.java @@ -1,103 +1,41 @@ package de.mediathekview.mserver.crawler.orfon.task; import java.lang.reflect.Type; -import java.net.URI; -import java.util.Optional; import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import com.google.gson.JsonDeserializer; import com.google.gson.reflect.TypeToken; import de.mediathekview.mserver.crawler.basic.AbstractCrawler; -import de.mediathekview.mserver.crawler.basic.AbstractJsonRestTask; import de.mediathekview.mserver.crawler.basic.AbstractRecursiveConverterTask; import de.mediathekview.mserver.crawler.basic.PagedElementListDTO; import de.mediathekview.mserver.crawler.orfon.OrfOnBreadCrumsUrlDTO; -import de.mediathekview.mserver.crawler.orfon.OrfOnConstants; -import de.mediathekview.mserver.crawler.orfon.OrfOnVideoInfoDTO; import de.mediathekview.mserver.crawler.orfon.json.OrfOnEpisodesDeserializer; -import jakarta.ws.rs.core.Response; // extends AbstractRestTask // return T Class from this task, desirialisation of class R , D , Reasearch in this url -public class OrfOnEpisodesTask extends AbstractJsonRestTask, OrfOnBreadCrumsUrlDTO> { +public class OrfOnEpisodesTask extends OrfOnPagedTask { private static final long serialVersionUID = 1L; - private static final Logger LOG = LogManager.getLogger(OrfOnEpisodesTask.class); public OrfOnEpisodesTask(AbstractCrawler crawler, Queue urlToCrawlDTOs) { - super(crawler, urlToCrawlDTOs, OrfOnConstants.AUTH); - } - - @Override - protected JsonDeserializer> getParser(OrfOnBreadCrumsUrlDTO aDTO) { - return new OrfOnEpisodesDeserializer(this.crawler); + super(crawler, urlToCrawlDTOs); } @Override - protected Type getType() { - return new TypeToken>() {}.getType(); + public JsonDeserializer> getParser(OrfOnBreadCrumsUrlDTO aDTO) { + return new OrfOnEpisodesDeserializer(); } @Override - protected void postProcessing(PagedElementListDTO aResponseObj, OrfOnBreadCrumsUrlDTO aDTO) { - final Optional> subpageCrawler; - if (aResponseObj.getNextPage().isPresent()) { - final Queue nextPageLinks = new ConcurrentLinkedQueue<>(); - nextPageLinks.add(new OrfOnBreadCrumsUrlDTO("", aResponseObj.getNextPage().get())); - subpageCrawler = Optional.of(createNewOwnInstance(nextPageLinks)); - subpageCrawler.get().fork(); - LOG.debug("started paging to url {} for {}", aResponseObj.getNextPage().get(), aDTO.getUrl()); - } else { - subpageCrawler = Optional.empty(); - } - // - for (OrfOnVideoInfoDTO rs : aResponseObj.getElements()) { - if (rs.getTitle().isEmpty() && rs.getTitleWithDate().isEmpty()) { - LOG.warn("Missing title for {} in {}", rs.getId(), aDTO); - crawler.incrementAndGetErrorCount(); - return; - } - if (rs.getTopic().isEmpty()) { - LOG.warn("Missing topic for {} in {}", rs.getId(), aDTO); - crawler.incrementAndGetErrorCount(); - return; - } - if (rs.getVideoUrls().isEmpty()) { - LOG.warn("Missing videoUrls for {} in {}", rs.getId(), aDTO); - crawler.incrementAndGetErrorCount(); - return; - } - if (rs.getDuration().isEmpty()) { - LOG.warn("Missing duration for {} in {}", rs.getId(), aDTO); - } - if (rs.getAired().isEmpty()) { - LOG.warn("Missing aired date for {} in {}", rs.getId(), aDTO); - } - if (rs.getWebsite().isEmpty()) { - LOG.warn("Missing website for {} in {}", rs.getId(), aDTO); - } - taskResults.add(rs); - } - subpageCrawler.ifPresent(paginationResults -> taskResults.addAll(paginationResults.join())); + public Type getType() { + return new TypeToken>() {}.getType(); } @Override - protected AbstractRecursiveConverterTask createNewOwnInstance(Queue aElementsToProcess) { + public AbstractRecursiveConverterTask createNewOwnInstance(Queue aElementsToProcess) { return new OrfOnEpisodesTask(crawler, aElementsToProcess); } - @Override - protected void handleHttpError(OrfOnBreadCrumsUrlDTO dto, URI url, Response response) { - crawler.printErrorMessage(); - LOG.fatal( - "A HTTP error {} occurred when getting REST information from: \"{}\".", - response.getStatus(), - url); - } } diff --git a/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodeTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodeTaskTest.java index 60250d4c7..647ed346a 100644 --- a/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodeTaskTest.java +++ b/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodeTaskTest.java @@ -70,7 +70,12 @@ private Map generateExpectedResult() { Optional.of(new URL("https://tvthek.orf.at/profile/Servus-Kasperl/3272601/Servus-Kasperl-Kasperl-Strolchi-Koko-und-Maximilian/14207792")), Optional.of(List.of(GeoLocations.GEO_NONE)), Optional.of(new URL("https://api-tvthek.orf.at/api/v4.3/subtitle/885340")), - Optional.of(Map.of(Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-worldwide/2024-01-04_0707_tl_01_Servus-Kasperl-_____14207792__o__6332192865__s15543049_9__ORF1HD_07081012P_07300711P_QXB.mp4/playlist.m3u8", 0L))), + Optional.of(Map.of( + Resolution.HD, new FilmUrl("https://dapasfiis.sf.apa.at/ipad/cms-worldwide/2024-01-04_0707_tl_01_Servus-Kasperl-_____14207792__o__6332192865__s15543049_9__ORF1HD_07081012P_07300711P_Q8C.mp4/playlist.m3u8", 0L), + Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-worldwide/2024-01-04_0707_tl_01_Servus-Kasperl-_____14207792__o__6332192865__s15543049_9__ORF1HD_07081012P_07300711P_QXB.mp4/playlist.m3u8", 0L), + Resolution.SMALL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-worldwide/2024-01-04_0707_tl_01_Servus-Kasperl-_____14207792__o__6332192865__s15543049_9__ORF1HD_07081012P_07300711P_Q4A.mp4/playlist.m3u8", 0L), + Resolution.VERY_SMALL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-worldwide/2024-01-04_0707_tl_01_Servus-Kasperl-_____14207792__o__6332192865__s15543049_9__ORF1HD_07081012P_07300711P_Q1A.3gp/playlist.m3u8", 0L) + )), Optional.of(Set.of( new URL("https://api-tvthek.orf.at/assets/subtitles/0166/92/07aead27b4c0b09b36750db54b8ce15ff9b8499c.ttml"), new URL("https://api-tvthek.orf.at/assets/subtitles/0166/92/4dd6932d7cf6ceaad90a536c3e03981267e32941.vtt"), @@ -92,7 +97,12 @@ private Map generateExpectedResult() { Optional.of(new URL("https://tvthek.orf.at/profile/ABC-Baer/4611813/ABC-Baer/14207790")), Optional.of(List.of(GeoLocations.GEO_AT)), Optional.of(new URL("https://api-tvthek.orf.at/api/v4.3/subtitle/885332")), - Optional.of(Map.of(Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2024-01-04_0645_tl_00_ABC-Baer_____14207790__o__4346842346__s15542921_1__KIDS1_06363007P_06500003P_QXB.mp4/playlist.m3u8", 0L))), + Optional.of(Map.of( + Resolution.HD, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2024-01-04_0645_tl_00_ABC-Baer_____14207790__o__4346842346__s15542921_1__KIDS1_06363007P_06500003P_Q8C.mp4/playlist.m3u8", 0L), + Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2024-01-04_0645_tl_00_ABC-Baer_____14207790__o__4346842346__s15542921_1__KIDS1_06363007P_06500003P_QXB.mp4/playlist.m3u8", 0L), + Resolution.SMALL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2024-01-04_0645_tl_00_ABC-Baer_____14207790__o__4346842346__s15542921_1__KIDS1_06363007P_06500003P_Q4A.mp4/playlist.m3u8", 0L), + Resolution.VERY_SMALL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2024-01-04_0645_tl_00_ABC-Baer_____14207790__o__4346842346__s15542921_1__KIDS1_06363007P_06500003P_Q1A.3gp/playlist.m3u8", 0L) + )), Optional.of(Set.of( new URL("https://api-tvthek.orf.at/assets/subtitles/0166/92/b682365a2a3fd1d45a2f029a597735a9df5b7524.ttml"), new URL("https://api-tvthek.orf.at/assets/subtitles/0166/92/20c53ed98f58a5045da663191516bc7fbf09e3d2.srt"), diff --git a/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodesTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodesTaskTest.java index ab806a591..30ae66209 100644 --- a/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodesTaskTest.java +++ b/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodesTaskTest.java @@ -1,23 +1,17 @@ package de.mediathekview.mserver.crawler.orfon; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import java.net.MalformedURLException; -import java.net.URL; -import java.time.LocalDateTime; + +import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Optional; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import org.junit.Test; -import de.mediathekview.mlib.daten.FilmUrl; -import de.mediathekview.mlib.daten.GeoLocations; -import de.mediathekview.mlib.daten.Resolution; import de.mediathekview.mserver.crawler.orfon.task.OrfOnEpisodesTask; import de.mediathekview.mserver.testhelper.WireMockTestBase; @@ -26,18 +20,12 @@ public class OrfOnEpisodesTaskTest extends WireMockTestBase { @Test public void test() { setupSuccessfulJsonResponse("/episodes", "/orfOn/episodes_3.json"); - setupSuccessfulJsonResponse("/api/v4.3/subtitle/868782", "/orfOn/subtitle_868782.json"); - Set result = executeTask("/episodes"); - Map expectedResult = generateExpectedResult(); - assertTrue(result.size() == 3); - for (OrfOnVideoInfoDTO actual : result) { - OrfOnVideoInfoDTO expected = expectedResult.get(actual.getId().get()); - assertNotNull(expected); - OrfOnEpisodeTaskTest.assertVideoInfoDto(expected, actual); - } + Set result = executeTask("/episodes"); + List expectedResult = generateExpectedResult(); + assertIterableEquals(result, expectedResult); } - private Set executeTask(String... requestUrl) { + private Set executeTask(String... requestUrl) { final Queue input = new ConcurrentLinkedQueue<>(); for (String url : requestUrl) { input.add(new OrfOnBreadCrumsUrlDTO("",getWireMockBaseUrlSafe() + url)); @@ -45,82 +33,12 @@ private Set executeTask(String... requestUrl) { return new OrfOnEpisodesTask(OrfOnEpisodeTaskTest.createCrawler(), input).invoke(); } - private Map generateExpectedResult() { - try { - Map expectedResult = Map.of( - "14201133", new OrfOnVideoInfoDTO( - Optional.of("14201133"), - Optional.of("ORF 1"), - Optional.of("Wischen ist Macht: Alles für den Hugo"), - Optional.of("Wischen ist Macht: Alles für den Hugo vom 14.11.2023 um 00:33 Uhr"), - Optional.of("Wischen ist Macht"), - Optional.of("Serie"), - Optional.of(LocalDateTime.of(2023,11,14,00,33,03)), - Optional.of(java.time.Duration.parse("PT24M50S")), - Optional.of("Spezialauftrag für \"Dreck.Weg.Sendracek\": Die russische Botschafterin lädt zu einer Gala und"), - Optional.of(new URL("https://tvthek.orf.at/profile/Wischen-ist-Macht/13891227/Wischen-ist-Macht-Alles-fuer-den-Hugo/14201133")), - Optional.of(List.of(GeoLocations.GEO_AT)), - Optional.of(new URL("https://api-tvthek.orf.at/api/v4.3/subtitle/868782")), - Optional.of(Map.of(Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2023-11-14_0033_in_01_Wischen-ist-Mac_____14201133__o__1340615864__s15523109_QXB.mp4/playlist.m3u8", 0L))), - Optional.of(Set.of( - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/a1ab1313ca03ba35c75d39e08c59840bc97aba76.ttml"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/6cd8a1899f5b56f919a6d809fe001ce3acaf4ce8.smi"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/79738b7eb874c151cde04ec6367a444bd5999db1.srt"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/a0467e2fdfb637c00fe6a450f003cedcf70128fa.xml"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/4b1c81a007271ee90224a9555494148e3116a00e.vtt") - )) - ), - "14202094", new OrfOnVideoInfoDTO( - Optional.of("14202094"), - Optional.of("ORF 1"), - Optional.of("Wischen ist Macht: Shit Happens"), - Optional.of("Wischen ist Macht: Shit Happens vom 21.11.2023 um 00:04 Uhr"), - Optional.of("Wischen ist Macht"), - Optional.of("Wischen ist Macht"), - Optional.of(LocalDateTime.of(2023,11,21,00,04,21)), - Optional.of(java.time.Duration.parse("PT22M12S")), - Optional.of("Dass Ex-Rockstar Johnny Woody gerade seinen Abgang ins Jenseits plant, passt Michelle gar nicht in den Kram - hat er ihr doch immer noch nicht die ausstehenden Honorare überwiesen. Johnny fängt sich jedoch wieder und \"Dreck:Weg.Sendracek\" treten ihren Dienst an. Bei der Arbeit findet Michelle heraus, dass Johnny eine 10.000 Dollar-Gitarre besitzt und er vielleicht doch nicht so knapp bei Kasse ist, woraufhin sie einen Plan schmiedet. Dann aber wird Michelle in die Beziehungskrise zwischen Johnny und seine Freundin Pamela hineingezogen, während seine Frau Janis gewohnt alkoholisiert durchs Haus geistert.\r\n" - + "Mit Ursula Strauss (Michelle Sendracek), Stefano Bernardin (Fernando Pablo Rigoberto Sanchez de la Luz), Zeynep Buyrac (Mira Petrenko), Manuel Sefciuc (Valentin Gradischnig), Lilian Jane Gartner (Zoe), Wolfram Berger (Johnny), Eva Maria Marold (Janis), Doris Hindinger (Pamela), Helmut Bohatsch (Bertram) u.a.\r\n" - + "Bildquelle: ORF/Fabio Eppensteiner"), - Optional.of(new URL("https://tvthek.orf.at/profile/Wischen-ist-Macht/13891227/Wischen-ist-Macht-Shit-Happens/14202094")), - Optional.of(List.of(GeoLocations.GEO_AT)), - Optional.of(new URL("https://api-tvthek.orf.at/api/v4.3/subtitle/868782")), - Optional.of(Map.of(Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2023-11-21_0004_in_01_Wischen-ist-Mac_____14202094__o__1166314613__s15511282_QXB.mp4/playlist.m3u8", 0L))), - Optional.of(Set.of( - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/a1ab1313ca03ba35c75d39e08c59840bc97aba76.ttml"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/6cd8a1899f5b56f919a6d809fe001ce3acaf4ce8.smi"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/79738b7eb874c151cde04ec6367a444bd5999db1.srt"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/a0467e2fdfb637c00fe6a450f003cedcf70128fa.xml"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/4b1c81a007271ee90224a9555494148e3116a00e.vtt") - )) - ), - "14202095", new OrfOnVideoInfoDTO( - Optional.of("14202095"), - Optional.of("ORF 1"), - Optional.of("Wischen ist Macht: Fußball ist meine Religion"), - Optional.of("Wischen ist Macht: Fußball ist meine Religion vom 21.11.2023 um 00:27 Uhr"), - Optional.of("Wischen ist Macht"), - Optional.of("Serie"), - Optional.of(LocalDateTime.of(2023,11,21,00,27,17)), - Optional.of(java.time.Duration.parse("PT25M49S")), - Optional.of("Michelle und ihr Team rücken im Fußballstadion an"), - Optional.of(new URL("https://tvthek.orf.at/profile/Wischen-ist-Macht/13891227/Wischen-ist-Macht-Fussball-ist-meine-Religion/14202095")), - Optional.of(List.of(GeoLocations.GEO_AT)), - Optional.of(new URL("https://api-tvthek.orf.at/api/v4.3/subtitle/868782")), - Optional.of(Map.of(Resolution.NORMAL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-austria/2023-11-21_0027_in_01_Wischen-ist-Mac_____14202095__o__7468851165__s15511283_QXB.mp4/playlist.m3u8", 0L))), - Optional.of(Set.of( - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/a1ab1313ca03ba35c75d39e08c59840bc97aba76.ttml"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/6cd8a1899f5b56f919a6d809fe001ce3acaf4ce8.smi"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/79738b7eb874c151cde04ec6367a444bd5999db1.srt"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/a0467e2fdfb637c00fe6a450f003cedcf70128fa.xml"), - new URL("https://api-tvthek.orf.at/assets/subtitles/0162/100/4b1c81a007271ee90224a9555494148e3116a00e.vtt") - )) - )); - return expectedResult; - } catch (MalformedURLException e) { - e.printStackTrace(); - } - return null; + private List generateExpectedResult() { + ArrayList expectedResult = new ArrayList<>(asList( + new OrfOnBreadCrumsUrlDTO("", "https://api-tvthek.orf.at/api/v4.3/episode/14201133"), + new OrfOnBreadCrumsUrlDTO("", "https://api-tvthek.orf.at/api/v4.3/episode/14202095"), + new OrfOnBreadCrumsUrlDTO("", "https://api-tvthek.orf.at/api/v4.3/episode/14202094"))); + return expectedResult; }