diff --git a/src/main/java/de/mediathekview/mserver/crawler/CrawlerManager.java b/src/main/java/de/mediathekview/mserver/crawler/CrawlerManager.java index be935a3ac..b7799eaf3 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/CrawlerManager.java +++ b/src/main/java/de/mediathekview/mserver/crawler/CrawlerManager.java @@ -24,7 +24,6 @@ import de.mediathekview.mserver.crawler.dw.DwCrawler; import de.mediathekview.mserver.crawler.funk.FunkCrawler; import de.mediathekview.mserver.crawler.kika.KikaApiCrawler; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; import de.mediathekview.mserver.crawler.orfon.OrfOnCrawler; import de.mediathekview.mserver.crawler.phoenix.PhoenixCrawler; import de.mediathekview.mserver.crawler.sr.SrCrawler; diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfConstants.java b/src/main/java/de/mediathekview/mserver/crawler/orf/OrfConstants.java deleted file mode 100644 index f79832eca..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfConstants.java +++ /dev/null @@ -1,36 +0,0 @@ -package de.mediathekview.mserver.crawler.orf; - -public final class OrfConstants { - - public static final String URL_BASE = "https://tvthek.orf.at"; - - /** - * URL für die Sendungen eines Tages - * Muss am Ende noch um das Datum dd.MM.yyyy ergänzt werden - */ - public static final String URL_DAY = URL_BASE + "/schedule/"; - - /** - * Basis-URL für Übersichtsseite nach Buchstaben - * Muss am Ende noch um Buchstabe bzw. 0 ergänzt werden - */ - public static final String URL_SHOW_LETTER_PAGE = URL_BASE + "/profiles/letter/"; - - /** - * URL für erste Übersichtsseite nach Buchstaben - */ - public static final String URL_SHOW_LETTER_PAGE_A = URL_SHOW_LETTER_PAGE + "A"; - - /** - * URL für verpasste Sendungen eines Tages - * Muss am Ende noch um Datum ergänzt werden im Format DD.MM.YYYY - */ - public static final String URL_DATE = URL_BASE + "/schedule/"; - - /** - * URL für Übersichtsseite des Archivs - */ - public static final String URL_ARCHIVE = URL_BASE + "/history"; - - private OrfConstants() {} -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfCrawler.java b/src/main/java/de/mediathekview/mserver/crawler/orf/OrfCrawler.java deleted file mode 100644 index 3fd9d25c8..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfCrawler.java +++ /dev/null @@ -1,140 +0,0 @@ -package de.mediathekview.mserver.crawler.orf; - -import de.mediathekview.mlib.daten.Film; -import de.mediathekview.mlib.daten.Sender; -import de.mediathekview.mlib.messages.listener.MessageListener; -import de.mediathekview.mserver.base.config.MServerConfigManager; -import de.mediathekview.mserver.base.messages.ServerMessages; -import de.mediathekview.mserver.crawler.basic.AbstractCrawler; -import de.mediathekview.mserver.crawler.basic.CrawlerUrlDTO; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.tasks.*; -import de.mediathekview.mserver.progress.listeners.SenderProgressListener; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; -import java.util.Collection; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.RecursiveTask; - -public class OrfCrawler extends AbstractCrawler { - - private static final Logger LOG = LogManager.getLogger(OrfCrawler.class); - - public OrfCrawler( - final ForkJoinPool aForkJoinPool, - final Collection aMessageListeners, - final Collection aProgressListeners, - final MServerConfigManager rootConfig) { - super(aForkJoinPool, aMessageListeners, aProgressListeners, rootConfig); - - } - - @Override - public Sender getSender() { - return Sender.ORF; - } - - private Set getArchiveEntries() throws InterruptedException, ExecutionException { - final OrfHistoryOverviewTask historyTask = new OrfHistoryOverviewTask(this); - final Queue topics = forkJoinPool.submit(historyTask).get(); - - final OrfHistoryTopicTask topicTask = new OrfHistoryTopicTask(this, topics); - final Set shows = forkJoinPool.submit(topicTask).get(); - - printMessage( - ServerMessages.DEBUG_ALL_SENDUNG_FOLGEN_COUNT, getSender().getName(), shows.size()); - - return shows; - } - - private Set getDaysEntries() throws InterruptedException, ExecutionException { - final OrfDayTask dayTask = new OrfDayTask(this, getDayUrls()); - final Set shows = forkJoinPool.submit(dayTask).get(); - - printMessage( - ServerMessages.DEBUG_ALL_SENDUNG_FOLGEN_COUNT, getSender().getName(), shows.size()); - - return shows; - } - - private Queue getDayUrls() { - final Queue urls = new ConcurrentLinkedQueue<>(); - for (int i = 0; - i - < crawlerConfig.getMaximumDaysForSendungVerpasstSection() - + crawlerConfig.getMaximumDaysForSendungVerpasstSectionFuture(); - i++) { - urls.add( - new CrawlerUrlDTO( - OrfConstants.URL_DAY - + LocalDateTime.now() - .plus( - crawlerConfig.getMaximumDaysForSendungVerpasstSectionFuture(), - ChronoUnit.DAYS) - .minus(i, ChronoUnit.DAYS) - .format(DateTimeFormatter.ofPattern("dd.MM.yyyy")))); - } - - return urls; - } - - private Queue getLetterEntries() throws InterruptedException, ExecutionException { - final OrfLetterPageTask letterTask = new OrfLetterPageTask(this); - final Queue shows = forkJoinPool.submit(letterTask).get(); - - printMessage( - ServerMessages.DEBUG_ALL_SENDUNG_FOLGEN_COUNT, getSender().getName(), shows.size()); - - return shows; - } - - @Override - protected RecursiveTask> createCrawlerTask() { - try { - boolean processMoreEpisodes = false; - - final Queue shows = new ConcurrentLinkedQueue<>(); - - if (Boolean.TRUE.equals(crawlerConfig.getTopicsSearchEnabled())) { - shows.addAll(getArchiveEntries()); - addShows(shows, getLetterEntries()); - processMoreEpisodes = true; - } else { - addShows(shows, getDaysEntries()); - processMoreEpisodes = false; - } - - printMessage( - ServerMessages.DEBUG_ALL_SENDUNG_FOLGEN_COUNT, getSender().getName(), shows.size()); - getAndSetMaxCount(shows.size()); - - return new OrfFilmDetailTask(this, shows, processMoreEpisodes); - } catch (final InterruptedException ex) { - LOG.debug("{} crawler interrupted.", getSender().getName(), ex); - Thread.currentThread().interrupt(); - } catch (final ExecutionException ex) { - LOG.fatal("Exception in {} crawler.", getSender().getName(), ex); - } - return null; - } - - private void addShows(Queue shows, Collection showsToAdd) { - showsToAdd.forEach( - show -> { - // compare only urls because topics can be different in letter and day lists - if (shows.stream().noneMatch(s -> s.getUrl().equals(show.getUrl()))) { - shows.add(show); - } else { - LOG.debug("duplicated url {} of topic {} removed", show.getUrl(), show.getTopic()); - } - }); - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfEpisodeInfoDTO.java b/src/main/java/de/mediathekview/mserver/crawler/orf/OrfEpisodeInfoDTO.java deleted file mode 100644 index ce058688d..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfEpisodeInfoDTO.java +++ /dev/null @@ -1,38 +0,0 @@ -package de.mediathekview.mserver.crawler.orf; - -import java.time.Duration; -import java.util.Optional; - -public class OrfEpisodeInfoDTO { - private final OrfVideoInfoDTO videoInfo; - private final Optional description; - private final Optional duration; - private final Optional title; - - public OrfEpisodeInfoDTO(final OrfVideoInfoDTO aVideoInfo, - final Optional aTitle, - final Optional aDescription, - final Optional aDuration - ) { - title = aTitle; - description = aDescription; - duration = aDuration; - videoInfo = aVideoInfo; - } - - public OrfVideoInfoDTO getVideoInfo() { - return videoInfo; - } - - public Optional getDescription() { - return description; - } - - public Optional getDuration() { - return duration; - } - - public Optional getTitle() { - return title; - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfVideoInfoDTO.java b/src/main/java/de/mediathekview/mserver/crawler/orf/OrfVideoInfoDTO.java deleted file mode 100644 index 596fa9393..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/OrfVideoInfoDTO.java +++ /dev/null @@ -1,50 +0,0 @@ -package de.mediathekview.mserver.crawler.orf; - -import java.util.EnumMap; -import java.util.Map; -import de.mediathekview.mlib.daten.Resolution; - -public class OrfVideoInfoDTO { - - private static final String FILTER_JUGENDSCHUTZ = ".*/Jugendschutz\\d{4}b\\d{4}_.*"; - private final Map videoUrls; - private String subtitleUrl; - - public OrfVideoInfoDTO() { - videoUrls = new EnumMap<>(Resolution.class); - } - - public boolean hasVideoUrls() { - return !videoUrls.isEmpty(); - } - - public Resolution getDefaultQuality() { - if (videoUrls.containsKey(Resolution.NORMAL)) { - return Resolution.NORMAL; - } - return videoUrls.keySet().iterator().next(); - } - - public String getDefaultVideoUrl() { - return videoUrls.get(getDefaultQuality()); - } - - public String getSubtitleUrl() { - return subtitleUrl; - } - - public Map getVideoUrls() { - return videoUrls; - } - - public String put(final Resolution key, final String value) { - if (value == null || value.matches(FILTER_JUGENDSCHUTZ)) { - return ""; - } - return videoUrls.put(key, value); - } - - public void setSubtitleUrl(final String subtitleUrl) { - this.subtitleUrl = subtitleUrl; - } -} \ No newline at end of file diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/json/OrfMoreEpisodesDeserializer.java b/src/main/java/de/mediathekview/mserver/crawler/orf/json/OrfMoreEpisodesDeserializer.java deleted file mode 100644 index 45b52710b..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/json/OrfMoreEpisodesDeserializer.java +++ /dev/null @@ -1,26 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.json; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import de.mediathekview.mserver.base.utils.JsonUtils; -import de.mediathekview.mserver.base.utils.UrlUtils; -import de.mediathekview.mserver.crawler.basic.CrawlerUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfConstants; - -import java.lang.reflect.Type; -import java.util.Optional; - -public class OrfMoreEpisodesDeserializer implements JsonDeserializer { - - private static final String ATTRIBUTE_URL = "url"; - - @Override - public CrawlerUrlDTO deserialize( - JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) { - - final Optional url = - JsonUtils.getAttributeAsString(jsonElement.getAsJsonObject(), ATTRIBUTE_URL); - return url.map(s -> new CrawlerUrlDTO(UrlUtils.addDomainIfMissing(s, OrfConstants.URL_BASE))).orElse(null); - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfMoreEpisodesParser.java b/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfMoreEpisodesParser.java deleted file mode 100644 index 28a6c3418..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfMoreEpisodesParser.java +++ /dev/null @@ -1,25 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.parser; - -import de.mediathekview.mserver.base.HtmlConsts; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import java.util.ArrayList; -import java.util.List; -import org.jsoup.nodes.Document; - -public class OrfMoreEpisodesParser { - private static final String EPISODES_SELECTOR = "article.b-teaser > a.teaser-link"; - - public List parse(final Document document, final String topic) { - final List result = new ArrayList<>(); - - document - .select(EPISODES_SELECTOR) - .forEach( - episode -> { - final String url = episode.attr(HtmlConsts.ATTRIBUTE_HREF); - result.add(new TopicUrlDTO(topic, url)); - }); - - return result; - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfPlaylistDeserializer.java b/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfPlaylistDeserializer.java deleted file mode 100644 index 9716a1e03..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfPlaylistDeserializer.java +++ /dev/null @@ -1,110 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.parser; - -import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import de.mediathekview.mserver.base.utils.JsonUtils; -import de.mediathekview.mserver.crawler.orf.OrfEpisodeInfoDTO; -import de.mediathekview.mserver.crawler.orf.OrfVideoInfoDTO; -import java.lang.reflect.Type; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -public class OrfPlaylistDeserializer implements JsonDeserializer> { - - private static final String ELEMENT_GAPLESS_VIDEO = "gapless_video"; - private static final String ELEMENT_PLAYLIST = "playlist"; - private static final String ELEMENT_VIDEOS = "videos"; - - private static final String ATTRIBUTE_TITLE = "title"; - private static final String ATTRIBUTE_DESCRIPTION = "description"; - private static final String ATTRIBUTE_DURATION = "duration"; - private static final String ATTRIBUTE_DURATION_IN_SECONDS = "duration_in_seconds"; - - @Override - public List deserialize( - JsonElement aJsonElement, Type aType, JsonDeserializationContext aContext) { - - List episodes = new ArrayList<>(); - - if (!aJsonElement.getAsJsonObject().has(ELEMENT_PLAYLIST)) { - return episodes; - } - - JsonObject playlistObject = - aJsonElement.getAsJsonObject().get(ELEMENT_PLAYLIST).getAsJsonObject(); - if (JsonUtils.hasElements(playlistObject, ELEMENT_GAPLESS_VIDEO)) { - parseGaplessVideo(episodes, playlistObject); - } - - parseVideos(episodes, playlistObject); - - return episodes; - } - - private void parseGaplessVideo(List aEpisodes, JsonObject aPlaylistObject) { - - final Optional title = JsonUtils.getAttributeAsString(aPlaylistObject, ATTRIBUTE_TITLE); - final Optional duration = parseDurationInSeconds(aPlaylistObject); - - final Optional videoInfoOptional = - parseUrls(aPlaylistObject.getAsJsonObject(ELEMENT_GAPLESS_VIDEO)); - - if (videoInfoOptional.isPresent()) { - OrfEpisodeInfoDTO episode = - new OrfEpisodeInfoDTO(videoInfoOptional.get(), title, Optional.empty(), duration); - aEpisodes.add(episode); - } - } - - private void parseVideos(List aEpisodes, JsonObject aPlaylistObject) { - JsonArray videosArray = aPlaylistObject.getAsJsonObject().get(ELEMENT_VIDEOS).getAsJsonArray(); - - for (JsonElement videoElement : videosArray) { - JsonObject videoObject = videoElement.getAsJsonObject(); - final Optional title = JsonUtils.getAttributeAsString(videoObject, ATTRIBUTE_TITLE); - final Optional description = - JsonUtils.getAttributeAsString(videoObject, ATTRIBUTE_DESCRIPTION); - final Optional duration = parseDuration(videoObject); - - final Optional videoInfoOptional = parseUrls(videoObject); - - if (videoInfoOptional.isPresent()) { - OrfEpisodeInfoDTO episode = - new OrfEpisodeInfoDTO(videoInfoOptional.get(), title, description, duration); - aEpisodes.add(episode); - } - } - } - - private Optional parseUrls(final JsonObject aVideoObject) { - - OrfVideoDetailDeserializer deserializer = new OrfVideoDetailDeserializer(); - return deserializer.deserializeVideoObject(aVideoObject); - } - - private static Optional parseDuration(final JsonObject aVideoObject) { - if (aVideoObject.has(ATTRIBUTE_DURATION)) { - Long durationValue = aVideoObject.get(ATTRIBUTE_DURATION).getAsLong(); - - // Duration ist in Millisekunden angegeben, diese interessieren aber nicht - return Optional.of(Duration.ofSeconds(durationValue / 1000)); - } - - return Optional.empty(); - } - - private static Optional parseDurationInSeconds(final JsonObject aVideoObject) { - if (aVideoObject.has(ATTRIBUTE_DURATION_IN_SECONDS)) { - Double durationValue = aVideoObject.get(ATTRIBUTE_DURATION_IN_SECONDS).getAsDouble(); - - return Optional.of(Duration.ofSeconds(durationValue.longValue())); - } - - return Optional.empty(); - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfVideoDetailDeserializer.java b/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfVideoDetailDeserializer.java deleted file mode 100644 index 2a9c70b11..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/parser/OrfVideoDetailDeserializer.java +++ /dev/null @@ -1,163 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.parser; - -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import de.mediathekview.mlib.daten.Resolution; -import de.mediathekview.mserver.crawler.orf.OrfVideoInfoDTO; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.lang.reflect.Type; -import java.util.Optional; - -import static de.mediathekview.mserver.base.HtmlConsts.ATTRIBUTE_SRC; - -public class OrfVideoDetailDeserializer implements JsonDeserializer> { - - private static final Logger LOG = LogManager.getLogger(OrfVideoDetailDeserializer.class); - - private static final String WRONG_HTTPS_URL_PART = ".apa."; - private static final String RIGHT_HTTPS_URL_PART = ".sf.apa."; - - private static final String ELEMENT_PLAYLIST = "playlist"; - private static final String ELEMENT_VIDEOS = "videos"; - private static final String ELEMENT_SUBTITLES = "subtitles"; - private static final String ELEMENT_SOURCES = "sources"; - - private static final String ATTRIBUTE_DELIVERY = "delivery"; - private static final String ATTRIBUTE_PROTOCOL = "protocol"; - private static final String ATTRIBUTE_QUALITY = "quality"; - private static final String ATTRIBUTE_TYPE = "type"; - - private static final String RELEVANT_DELIVERY1 = "progressive"; - private static final String RELEVANT_DELIVERY2 = "hls"; - private static final String RELEVANT_PROTOCOL = "http"; - private static final String RELEVANT_SUBTITLE_TYPE = "ttml"; - private static final String RELEVANT_VIDEO_TYPE1 = "video/mp4"; - private static final String RELEVANT_VIDEO_TYPE2 = "application/x-mpegURL"; - - private static String fixHttpsUrl(final String url) { - if (url.contains(RIGHT_HTTPS_URL_PART)) { - return url; - } - return url.replace(WRONG_HTTPS_URL_PART, RIGHT_HTTPS_URL_PART); - } - - private static void parseVideo(final JsonElement aVideoElement, final OrfVideoInfoDTO dto) { - if (aVideoElement.isJsonArray()) { - aVideoElement - .getAsJsonArray() - .forEach( - videoElement -> { - final JsonObject videoObject = videoElement.getAsJsonObject(); - if (videoObject.has(ATTRIBUTE_PROTOCOL) - && videoObject.has(ATTRIBUTE_QUALITY) - && videoObject.has(ATTRIBUTE_SRC) - && videoObject.has(ATTRIBUTE_TYPE)) { - final String type = videoObject.get(ATTRIBUTE_TYPE).getAsString(); - final String protocol = videoObject.get(ATTRIBUTE_PROTOCOL).getAsString(); - final String delivery = videoObject.get(ATTRIBUTE_DELIVERY).getAsString(); - - if (isVideoRelevant(type, protocol, delivery)) { - final String quality = videoObject.get(ATTRIBUTE_QUALITY).getAsString(); - final String url = fixHttpsUrl(videoObject.get(ATTRIBUTE_SRC).getAsString()); - - final Optional resolution = getQuality(quality); - resolution.ifPresent(resolution1 -> dto.put(resolution1, url)); - } - } - }); - } - } - - public Optional deserializeVideoObject(final JsonObject aVideoObject) { - final OrfVideoInfoDTO dto = new OrfVideoInfoDTO(); - - if (aVideoObject.has(ELEMENT_SOURCES)) { - parseVideo(aVideoObject.get(ELEMENT_SOURCES), dto); - } - - if (aVideoObject.has(ELEMENT_SUBTITLES)) { - parseSubtitles(aVideoObject.get(ELEMENT_SUBTITLES), dto); - } - - if (dto.hasVideoUrls()) { - return Optional.of(dto); - } - - return Optional.empty(); - } - - private static boolean isVideoRelevant( - final String type, final String protocol, final String delivery) { - return (type.equalsIgnoreCase(RELEVANT_VIDEO_TYPE1) - || type.equalsIgnoreCase(RELEVANT_VIDEO_TYPE2)) - && protocol.equalsIgnoreCase(RELEVANT_PROTOCOL) - && (delivery.equalsIgnoreCase(RELEVANT_DELIVERY1) - || delivery.equalsIgnoreCase(RELEVANT_DELIVERY2)); - } - - private static void parseSubtitles( - final JsonElement aSubtitlesElement, final OrfVideoInfoDTO dto) { - if (aSubtitlesElement.isJsonArray()) { - aSubtitlesElement - .getAsJsonArray() - .forEach( - subtitleElement -> { - final JsonObject subtitleObject = subtitleElement.getAsJsonObject(); - if (subtitleObject.has(ATTRIBUTE_SRC) && subtitleObject.has(ATTRIBUTE_TYPE)) { - final String type = subtitleObject.get(ATTRIBUTE_TYPE).getAsString(); - - if (type.equalsIgnoreCase(RELEVANT_SUBTITLE_TYPE)) { - final String url = fixHttpsUrl(subtitleObject.get(ATTRIBUTE_SRC).getAsString()); - dto.setSubtitleUrl(url); - } - } - }); - } - } - - private static Optional getQuality(final String aQuality) { - switch (aQuality) { - case "Q1A": - return Optional.of(Resolution.VERY_SMALL); - case "Q4A": - return Optional.of(Resolution.SMALL); - case "Q6A": - return Optional.of(Resolution.NORMAL); - case "Q8C": - return Optional.of(Resolution.HD); - case "Q0A": - // QXA/QXB(DRM): another m3u8 has to be loaded which is often geoblocked - case "QXA": - case "QXADRM": - case "QXB": - case "QXBDRM": - case "Q8A": - return Optional.empty(); - default: - LOG.debug("ORF: unknown quality: {}", aQuality); - } - return Optional.empty(); - } - - @Override - public Optional deserialize( - final JsonElement aJsonElement, final Type aType, final JsonDeserializationContext aContext) { - - final JsonObject jsonObject = aJsonElement.getAsJsonObject(); - if (jsonObject.has(ELEMENT_PLAYLIST)) { - final JsonObject playlistObject = jsonObject.get(ELEMENT_PLAYLIST).getAsJsonObject(); - if (playlistObject.has(ELEMENT_VIDEOS)) { - final JsonObject videoObject = - playlistObject.get(ELEMENT_VIDEOS).getAsJsonArray().get(0).getAsJsonObject(); - - return deserializeVideoObject(videoObject); - } - } - - return Optional.empty(); - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfDayTask.java b/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfDayTask.java deleted file mode 100644 index b9312c748..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfDayTask.java +++ /dev/null @@ -1,52 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.HtmlConsts; -import de.mediathekview.mserver.crawler.basic.*; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.util.Queue; - -public class OrfDayTask extends AbstractDocumentTask { - - private static final String ITEM_SELECTOR = "article a"; - private static final String TITLE_SELECTOR1 = ".item-title"; - private static final String TITLE_SELECTOR2 = ".teaser-title"; - - public OrfDayTask( - final AbstractCrawler crawler, - final Queue urlToCrawlDTOs) { - super(crawler, urlToCrawlDTOs); - } - - @Override - protected void processDocument(final CrawlerUrlDTO urlDto, final Document document) { - final Elements elements = document.select(ITEM_SELECTOR); - elements.forEach( - item -> { - final Element titleElement = getTitleElement(item); - if (titleElement != null) { - final String theme = OrfHelper.parseTheme(titleElement.text()); - final String url = item.attr(HtmlConsts.ATTRIBUTE_HREF); - - final TopicUrlDTO dto = new TopicUrlDTO(theme, url); - taskResults.add(dto); - } - }); - } - - private Element getTitleElement(final Element item) { - Element titleElement = item.selectFirst(TITLE_SELECTOR1); - if (titleElement == null) { - titleElement = item.selectFirst(TITLE_SELECTOR2); - } - return titleElement; - } - - @Override - protected AbstractUrlTask createNewOwnInstance( - final Queue aUrlsToCrawl) { - return new OrfDayTask(crawler, aUrlsToCrawl); - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTask.java b/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTask.java deleted file mode 100644 index b3544fd9f..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTask.java +++ /dev/null @@ -1,306 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import de.mediathekview.mlib.daten.Film; -import de.mediathekview.mlib.daten.FilmUrl; -import de.mediathekview.mlib.daten.GeoLocations; -import de.mediathekview.mlib.daten.Resolution; -import de.mediathekview.mserver.base.utils.HtmlDocumentUtils; -import de.mediathekview.mserver.crawler.basic.*; -import de.mediathekview.mserver.crawler.orf.OrfEpisodeInfoDTO; -import de.mediathekview.mserver.crawler.orf.OrfVideoInfoDTO; -import de.mediathekview.mserver.crawler.orf.json.OrfMoreEpisodesDeserializer; -import de.mediathekview.mserver.crawler.orf.parser.OrfMoreEpisodesParser; -import de.mediathekview.mserver.crawler.orf.parser.OrfPlaylistDeserializer; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jsoup.nodes.Document; - -import java.io.IOException; -import java.lang.reflect.Type; -import java.net.MalformedURLException; -import java.net.URL; -import java.time.Duration; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class OrfFilmDetailTask extends AbstractDocumentTask { - - private static final Logger LOG = LogManager.getLogger(OrfFilmDetailTask.class); - - private static final String TITLE_SELECTOR = ".description-container .description-title"; - private static final String VIDEO_META_DATA_SELECTOR = ".video-meta-data"; - private static final String TIME_SELECTOR = VIDEO_META_DATA_SELECTOR + " time"; - private static final String DURATION_SELECTOR = VIDEO_META_DATA_SELECTOR + " span.duration"; - private static final String DESCRIPTION_SELECTOR = ".description-container .description-text"; - private static final String VIDEO_SELECTOR = "div.jsb_VideoPlaylist"; - private static final String MORE_EPISODES_SELECTOR = "div.more-episodes"; - - private static final String ATTRIBUTE_DATETIME = "datetime"; - private static final String ATTRIBUTE_DATA_JSB = "data-jsb"; - private static final String PREFIX_AUDIO_DESCRIPTION = "AD |"; - - private static final DateTimeFormatter DATE_TIME_FORMATTER = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - private static final Type CRAWLER_URL_TYPE_TOKEN = new TypeToken() {}.getType(); - private static final Type LIST_EPISODEINFO_TYPE_TOKEN = - new TypeToken>() {}.getType(); - private final boolean processMoreEpisodes; - - public OrfFilmDetailTask( - final AbstractCrawler aCrawler, final Queue aUrlToCrawlDtos, boolean processMoreEpisodes) { - super(aCrawler, aUrlToCrawlDtos); - - this.processMoreEpisodes = processMoreEpisodes; - } - - private static Optional parseDate(final Document aDocument) { - final Optional date = - HtmlDocumentUtils.getElementAttributeString(TIME_SELECTOR, ATTRIBUTE_DATETIME, aDocument); - if (date.isPresent()) { - final String dateValue = date.get().replace("CET", " ").replace("CEST", " "); - try { - final LocalDateTime localDate = LocalDateTime.parse(dateValue, DATE_TIME_FORMATTER); - return Optional.of(localDate); - } catch (final DateTimeParseException e) { - LOG.debug("OrfFilmDetailTask: unknown date format: {}", date.get()); - } - } - - return Optional.empty(); - } - - private static Optional parseDuration(final Document aDocument) { - final Optional duration = - HtmlDocumentUtils.getElementString(DURATION_SELECTOR, aDocument); - if (!duration.isPresent()) { - return Optional.empty(); - } - - final Optional unit = determineChronoUnit(duration.get()); - if (!unit.isPresent()) { - LOG.debug("OrfFilmDetailTask: unknown duration type: {}", duration.get()); - return Optional.empty(); - } - - final String[] parts = duration.get().split(" ")[0].trim().split(":"); - if (parts.length != 2) { - LOG.debug("OrfFilmDetailTask: unknown duration part count: {}", duration.get()); - return Optional.empty(); - } - - final ChronoUnit unitValue = unit.get(); - if (unitValue == ChronoUnit.SECONDS || unitValue == ChronoUnit.MINUTES) { - return Optional.of( - Duration.ofMinutes(Long.parseLong(parts[0])).plusSeconds(Long.parseLong(parts[1]))); - } - if (unitValue == ChronoUnit.HOURS) { - return Optional.of( - Duration.ofHours(Long.parseLong(parts[0])).plusMinutes(Long.parseLong(parts[1]))); - } - - return Optional.empty(); - } - - private static Optional determineChronoUnit(final String aDuration) { - if (aDuration.contains("Min.")) { - return Optional.of(ChronoUnit.MINUTES); - } - if (aDuration.contains("Std.")) { - return Optional.of(ChronoUnit.HOURS); - } - if (aDuration.contains("Sek.")) { - return Optional.of(ChronoUnit.SECONDS); - } - - return Optional.empty(); - } - - @Override - protected void processDocument(final TopicUrlDTO aUrlDto, final Document aDocument) { - final Optional title = HtmlDocumentUtils.getElementString(TITLE_SELECTOR, aDocument); - final Optional time = parseDate(aDocument); - final Optional duration = parseDuration(aDocument); - final Optional description = - HtmlDocumentUtils.getElementString(DESCRIPTION_SELECTOR, aDocument); - - final List episodes = parseEpisodes(aDocument); - if (episodes.size() > 1) { - crawler.incrementMaxCountBySizeAndGetNewSize(episodes.size() - 1L); - crawler.updateProgress(); - } - - for (int i = 0; i < episodes.size(); i++) { - final OrfEpisodeInfoDTO episode = episodes.get(i); - if (i == 0) { - createFilm(aUrlDto, episode.getVideoInfo(), title, description, time, duration); - } else { - createFilm( - aUrlDto, - episode.getVideoInfo(), - episode.getTitle(), - episode.getDescription(), - time, - episode.getDuration()); - } - } - - if (processMoreEpisodes) { - final List topicUrlDTOS = parseMoreEpisodes(aDocument, aUrlDto.getTopic()); - topicUrlDTOS.remove(aUrlDto); - processMoreEpisodes(topicUrlDTOS); - } - } - - @Override - protected AbstractUrlTask createNewOwnInstance( - final Queue aUrlsToCrawl) { - return createNewOwnInstance(aUrlsToCrawl, processMoreEpisodes); - } - - private AbstractUrlTask createNewOwnInstance(final Queue urlsToCrawl, boolean processMoreEpisodes) { - return new OrfFilmDetailTask(crawler, urlsToCrawl, processMoreEpisodes); - } - - private void createFilm( - final TopicUrlDTO aUrlDto, - final OrfVideoInfoDTO aVideoInfo, - final Optional aTitle, - final Optional aDescription, - final Optional aTime, - final Optional aDuration) { - - try { - if (aTitle.isPresent()) { - boolean isAudioDescription = aUrlDto.getTopic().startsWith(PREFIX_AUDIO_DESCRIPTION); - - final Film film = - new Film( - UUID.randomUUID(), - crawler.getSender(), - isAudioDescription - ? trimAudioDescriptionPrefix(aTitle.get()) - : aTitle.get(), - isAudioDescription - ? trimAudioDescriptionPrefix(aUrlDto.getTopic()) - : aUrlDto.getTopic(), - aTime.orElse(LocalDateTime.now()), - aDuration.orElse(Duration.ZERO)); - - film.setWebsite(new URL(aUrlDto.getUrl())); - aDescription.ifPresent(film::setBeschreibung); - - if (StringUtils.isNotBlank(aVideoInfo.getSubtitleUrl())) { - film.addSubtitle(new URL(aVideoInfo.getSubtitleUrl())); - } - - addUrls(film, aVideoInfo.getVideoUrls(), isAudioDescription); - - setGeoLocations(aVideoInfo, film); - - taskResults.add(film); - crawler.incrementAndGetActualCount(); - crawler.updateProgress(); - } else { - LOG.error("OrfFilmDetailTask: no title or video found for url {}", aUrlDto.getUrl()); - crawler.incrementAndGetErrorCount(); - crawler.updateProgress(); - } - } catch (final MalformedURLException ex) { - LOG.fatal("A ORF URL can't be parsed.", ex); - crawler.printErrorMessage(); - crawler.incrementAndGetErrorCount(); - crawler.updateProgress(); - } - } - - private String trimAudioDescriptionPrefix(String text) { - return text.substring(PREFIX_AUDIO_DESCRIPTION.length()); - } - - private void setGeoLocations(final OrfVideoInfoDTO aVideoInfo, final Film film) { - final List geoLocations = new ArrayList<>(); - if (aVideoInfo.getDefaultVideoUrl().contains("cms-austria")) { - geoLocations.add(GeoLocations.GEO_AT); - } else { - geoLocations.add(GeoLocations.GEO_NONE); - } - film.setGeoLocations(geoLocations); - } - - private void addUrls( - final Film aFilm, final Map aVideoUrls, boolean isAudioDescription) - throws MalformedURLException { - - for (final Map.Entry qualitiesEntry : aVideoUrls.entrySet()) { - final String url = qualitiesEntry.getValue(); - final FilmUrl filmUrl = new FilmUrl(url, crawler.determineFileSizeInKB(url)); - final Resolution key = qualitiesEntry.getKey(); - - if (isAudioDescription) { - aFilm.addAudioDescription(key, filmUrl); - } else { - aFilm.addUrl(key, filmUrl); - } - - } - } - - private List parseEpisodes(final Document aDocument) { - final Optional json = - HtmlDocumentUtils.getElementAttributeString(VIDEO_SELECTOR, ATTRIBUTE_DATA_JSB, aDocument); - - if (json.isPresent()) { - - final Gson gson = - new GsonBuilder() - .registerTypeAdapter(LIST_EPISODEINFO_TYPE_TOKEN, new OrfPlaylistDeserializer()) - .create(); - - return gson.fromJson(json.get(), LIST_EPISODEINFO_TYPE_TOKEN); - } - - return new ArrayList<>(); - } - - private List parseMoreEpisodes(final Document document, final String topic) { - final Optional json = HtmlDocumentUtils.getElementAttributeString(MORE_EPISODES_SELECTOR, ATTRIBUTE_DATA_JSB, document); - if (json.isPresent()) { - final Gson gson = - new GsonBuilder() - .registerTypeAdapter(CRAWLER_URL_TYPE_TOKEN, new OrfMoreEpisodesDeserializer()) - .create(); - - CrawlerUrlDTO moreEpisodesUrl = gson.fromJson(json.get(), CRAWLER_URL_TYPE_TOKEN); - if (moreEpisodesUrl != null) { - try { - final Document moreEpisodesDocument = crawler.requestBodyAsHtmlDocument(moreEpisodesUrl.getUrl()); - OrfMoreEpisodesParser parser = new OrfMoreEpisodesParser(); - return parser.parse(moreEpisodesDocument, topic); - } catch (IOException e) { - LOG.error("OrfFilmDetailTask: loading more episodes url {} failed.", moreEpisodesUrl.getUrl()); - crawler.incrementAndGetErrorCount(); - } - } - } - - return new ArrayList<>(); - } - - private void processMoreEpisodes(final List moreFilms) { - if (moreFilms != null && !moreFilms.isEmpty()) { - final Queue queue = new ConcurrentLinkedQueue<>(moreFilms); - final OrfFilmDetailTask task = (OrfFilmDetailTask) createNewOwnInstance(queue, false); - task.fork(); - taskResults.addAll(task.join()); - } - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHelper.java b/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHelper.java deleted file mode 100644 index 900e37f46..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHelper.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.HtmlConsts; -import de.mediathekview.mserver.crawler.orf.OrfConstants; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.util.ArrayList; -import java.util.List; - -/** Helper methods for ORF tasks. */ -class OrfHelper { - - private static final String LETTER_URL_SELECTOR = "li.letter-item > a"; - - private OrfHelper() {} - - static String parseTheme(final Element aItem) { - final String theme = aItem.attr(HtmlConsts.ATTRIBUTE_TITLE); - return parseTheme(theme); - } - - static String parseTheme(final String theme) { - final String result = theme.replaceAll("\\d{1,2}:\\d{2}$", "").trim(); - // Thema steht vor Doppelpunkt - // Ausnahmen - // - ZIB-Sendungen mit Uhrzeit - // - DokEins-Sendungen - // - Ungarisches Magazin - final int index = result.indexOf(':'); - if (index > 0 - && !result.startsWith("ZIB") - && !result.startsWith("DOKeins") - && !result.contains("Ungarisches Magazin")) { - return result.substring(0, index).trim(); - } - return result; - } - - /** - * determines the links to the letter pages. - * - * @param aDocument the html document with letter links - * @return list with urls - */ - static List parseLetterLinks(final Document aDocument) { - final List results = new ArrayList<>(); - - final Elements links = aDocument.select(LETTER_URL_SELECTOR); - links.forEach( - element -> { - if (element.hasAttr(HtmlConsts.ATTRIBUTE_HREF)) { - final String subpage = element.attr(HtmlConsts.ATTRIBUTE_HREF); - results.add(OrfConstants.URL_BASE + subpage); - } - }); - - return results; - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryOverviewTask.java b/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryOverviewTask.java deleted file mode 100644 index 567992534..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryOverviewTask.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.HtmlConsts; -import de.mediathekview.mserver.crawler.basic.AbstractCrawler; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfConstants; -import org.jsoup.nodes.Document; -import org.jsoup.select.Elements; - -import java.util.Queue; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class OrfHistoryOverviewTask implements Callable> { - - private static final String TOPIC_URL_SELECTOR = "section.has-4-in-row article > a"; - - private final AbstractCrawler crawler; - - public OrfHistoryOverviewTask( - final AbstractCrawler aCrawler) { - crawler = aCrawler; - } - - @Override - public Queue call() throws Exception { - final Queue results = new ConcurrentLinkedQueue<>(); - - // URLs für Seiten parsen - final Document document = crawler.requestBodyAsHtmlDocument(OrfConstants.URL_ARCHIVE); - - final Elements topics = document.select(TOPIC_URL_SELECTOR); - topics.forEach( - topicElement -> { - final String url = topicElement.attr(HtmlConsts.ATTRIBUTE_HREF); - final String topic = topicElement.attr(HtmlConsts.ATTRIBUTE_TITLE); - results.add(new TopicUrlDTO(topic, url)); - }); - - return results; - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryTopicTask.java b/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryTopicTask.java deleted file mode 100644 index 546844237..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryTopicTask.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.HtmlConsts; -import de.mediathekview.mserver.crawler.basic.AbstractCrawler; -import de.mediathekview.mserver.crawler.basic.AbstractDocumentTask; -import de.mediathekview.mserver.crawler.basic.AbstractRecursiveConverterTask; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import org.jsoup.nodes.Document; - -import java.util.Queue; - -public class OrfHistoryTopicTask extends AbstractDocumentTask { - - private static final String SHOW_URL_SELECTOR = "article > a"; - - public OrfHistoryTopicTask( - final AbstractCrawler crawler, - final Queue urlToCrawlDTOs - ) { - super(crawler, urlToCrawlDTOs); - } - - @Override - protected AbstractRecursiveConverterTask createNewOwnInstance( - final Queue aElementsToProcess) { - return new OrfHistoryTopicTask(crawler, aElementsToProcess); - } - - @Override - protected void processDocument(final TopicUrlDTO aUrlDto, final Document aDocument) { - aDocument - .select(SHOW_URL_SELECTOR) - .forEach( - showElement -> { - final String url = showElement.attr(HtmlConsts.ATTRIBUTE_HREF); - taskResults.add(new TopicUrlDTO(aUrlDto.getTopic(), url)); - }); - } -} diff --git a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfLetterPageTask.java b/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfLetterPageTask.java deleted file mode 100644 index d4ea67344..000000000 --- a/src/main/java/de/mediathekview/mserver/crawler/orf/tasks/OrfLetterPageTask.java +++ /dev/null @@ -1,70 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.HtmlConsts; -import de.mediathekview.mserver.crawler.basic.AbstractCrawler; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfConstants; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jsoup.nodes.Document; -import org.jsoup.select.Elements; - -import java.io.IOException; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class OrfLetterPageTask implements Callable> { - - private static final Logger LOG = LogManager.getLogger(OrfLetterPageTask.class); - - private static final String SHOW_URL_SELECTOR = "article > a"; - private final AbstractCrawler crawler; - - /** @param aCrawler The crawler which uses this task. */ - public OrfLetterPageTask(final AbstractCrawler aCrawler) { - crawler = aCrawler; - } - - @Override - public Queue call() throws Exception { - final Queue results = new ConcurrentLinkedQueue<>(); - - // URLs für Seiten parsen - final Document document = crawler.getConnection().requestBodyAsHtmlDocument(OrfConstants.URL_SHOW_LETTER_PAGE_A); - final List overviewLinks = OrfHelper.parseLetterLinks(document); - - // Sendungen für die einzelnen Seiten pro Buchstabe ermitteln - overviewLinks.forEach( - url -> { - try { - final Document subpageDocument = crawler.requestBodyAsHtmlDocument(url); - results.addAll(parseOverviewPage(subpageDocument)); - } catch (final IOException ex) { - LOG.fatal("OrfLetterPageTask: error parsing url {}", url, ex); - } catch (final NullPointerException e) { - LOG.fatal(e); - } - }); - - return results; - } - - private Queue parseOverviewPage(final Document aDocument) { - final Queue results = new ConcurrentLinkedQueue<>(); - - final Elements links = aDocument.select(SHOW_URL_SELECTOR); - links.forEach( - element -> { - if (element.hasAttr(HtmlConsts.ATTRIBUTE_HREF)) { - final String link = element.attr(HtmlConsts.ATTRIBUTE_HREF); - final String theme = OrfHelper.parseTheme(element); - - results.add(new TopicUrlDTO(theme, link)); - } - }); - - return results; - } -} 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 3a4622e74..112c7977c 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 @@ -60,7 +60,7 @@ public class OrfOnEpisodeDeserializer implements JsonDeserializer> parseUrl(JsonElement jsonElement) { return Optional.empty(); } // We need to fallback to episode.sources in case there are many elements in the playlist - if (videoPath1.get().getAsJsonArray().size() > 1) { - return parseFallbackVideo(jsonElement); - } - - 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; + if (videoPath1.get().getAsJsonArray().size() == 1) { + 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; + } } } - - return Optional.empty(); + return parseFallbackVideo(jsonElement); } private Optional> parseFallbackVideo(JsonElement root) { @@ -199,7 +196,7 @@ private Optional> parseFallbackVideo(JsonElement root) if (codecs.isPresent() && codecs.get().isJsonArray()) { for (JsonElement singleVideo : codecs.get().getAsJsonArray()) { Optional tgtUrl = JsonUtils.getElementValueAsString(singleVideo, TAG_VIDEO_FALLBACK_URL); - if (tgtUrl.isPresent()) { + if (tgtUrl.isPresent() && !tgtUrl.get().contains("/Jugendschutz") && !tgtUrl.get().contains("/no_drm_support") && !tgtUrl.get().contains("/schwarzung")) { try { urls.put(Resolution.NORMAL, new FilmUrl(tgtUrl.get(), 0L)); } catch (MalformedURLException e) { @@ -221,19 +218,22 @@ private Optional> readVideoForTargetCodec(JsonElement u 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()) && OrfOnEpisodeDeserializer.getQuality(quality.get()).isPresent()) { - try { - 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); + // dummy urls + if (!url.get().contains("/Jugendschutz") && !url.get().contains("/no_drm_support") && !url.get().contains("/schwarzung")) { + try { + 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.isEmpty()) { - Optional.empty(); + return Optional.empty(); } return Optional.of(urls); } diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/json/OrfMoreEpisodesDeserializerTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/json/OrfMoreEpisodesDeserializerTest.java deleted file mode 100644 index b7f536160..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/json/OrfMoreEpisodesDeserializerTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.json; - -import com.google.gson.JsonElement; -import de.mediathekview.mserver.crawler.basic.CrawlerUrlDTO; -import de.mediathekview.mserver.testhelper.JsonFileReader; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class OrfMoreEpisodesDeserializerTest { - - @Test - void testDeserialize() { - final JsonElement jsonElement = JsonFileReader.readJson("/orf/orf_film_more_episodes.json"); - - final OrfMoreEpisodesDeserializer target = new OrfMoreEpisodesDeserializer(); - final CrawlerUrlDTO actual = target.deserialize(jsonElement, null, null); - - assertNotNull(actual); - assertEquals("https://tvthek.orf.at/lane-plus/other_episodes_of_profile?profileId=13895917&profileSlug=Biester", actual.getUrl()); - - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/parser/OrfMoreEpisodesParserTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/parser/OrfMoreEpisodesParserTest.java deleted file mode 100644 index 63893dc77..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/parser/OrfMoreEpisodesParserTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.parser; - -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.testhelper.FileReader; -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; - -class OrfMoreEpisodesParserTest { - @Test - void parseDocumentWithEpisodes() { - TopicUrlDTO[] expectedFilms = new TopicUrlDTO[] { - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-9/14207236"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-8/14207235"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-7/14207234"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-6/14207233"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-5/14207232"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-4/14207231"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-3/14207230"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-2/14207229"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Alle-Folgen-jetzt-Biester-1-10/14207227"), - new TopicUrlDTO("Biester", "https://tvthek.orf.at/profile/Biester/13895917/Biester-Folge-10/14207252"), - }; - - final Document document = Jsoup.parse(FileReader.readFile("/orf/orf_film_more_episodes.html")); - - OrfMoreEpisodesParser target = new OrfMoreEpisodesParser(); - final List actual = target.parse(document, "Biester"); - - assertEquals(10, actual.size()); - MatcherAssert.assertThat(actual, Matchers.containsInAnyOrder(expectedFilms)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/parser/OrfPlaylistDeserializerTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/parser/OrfPlaylistDeserializerTest.java deleted file mode 100644 index 8c6ad8c94..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/parser/OrfPlaylistDeserializerTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.parser; - -import com.google.gson.JsonElement; -import de.mediathekview.mlib.daten.Resolution; -import de.mediathekview.mserver.crawler.orf.OrfEpisodeInfoDTO; -import de.mediathekview.mserver.crawler.orf.OrfVideoInfoDTO; -import de.mediathekview.mserver.testhelper.JsonFileReader; -import org.junit.Test; - -import java.time.Duration; -import java.util.List; -import java.util.Map; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class OrfPlaylistDeserializerTest { - - @Test - public void testDeserializeSingleFilm() { - final JsonElement jsonElement = JsonFileReader.readJson("/orf/orf_playlist_no_episodes.json"); - - final OrfPlaylistDeserializer target = new OrfPlaylistDeserializer(); - final List actual = target.deserialize(jsonElement, null, null); - - assertThat(actual.size(), equalTo(1)); - - final OrfEpisodeInfoDTO actualEpisode = actual.get(0); - assertEpisode( - actualEpisode, - "Rede des Bundespräsidenten", - Duration.ofSeconds(430), - "Bundespräsident Alexander Van der Bellen zeigt sich optimistisch, wünscht sich aber, sich an das österreichische zu erinnern, also das Gemeinsame vor das Trennende zu stellen.", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-26_1947_sd_02_Rede-des-Bundes_____13993313__o__1465128264__s14386692_2__ORF2HD_19461317P_19532320P_Q4A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-26_1947_sd_02_Rede-des-Bundes_____13993313__o__1465128264__s14386692_2__ORF2HD_19461317P_19532320P_Q6A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-26_1947_sd_02_Rede-des-Bundes_____13993313__o__1465128264__s14386692_2__ORF2HD_19461317P_19532320P_Q8C.mp4/playlist.m3u8", - "https://api-tvthek.orf.at/uploads/media/subtitles/0055/75/02ea0c39f7d1f220fbc45284dd13b1d096abd5c8.ttml"); - } - - @Test - public void testDeserializeFilmWithEpisodes() { - final JsonElement jsonElement = JsonFileReader.readJson("/orf/orf_playlist_with_episodes1.json"); - - final OrfPlaylistDeserializer target = new OrfPlaylistDeserializer(); - final List actual = target.deserialize(jsonElement, null, null); - - assertThat(actual.size(), equalTo(3)); - - assertEpisode( - actual.get(0), - "ZIB 1", - Duration.ofSeconds(1094), - "", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/13993106_0016_Q4A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/13993106_0016_Q6A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/13993106_0016_Q8C.mp4/playlist.m3u8", - null); - assertEpisode( - actual.get(1), - "Signation | Themen", - Duration.ofSeconds(42), - "", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-24_1930_tl_02_ZIB-1_Signation---The__13993106__o__1886650622__s14385479_9__ORF2HD_19293322P_19301604P_Q4A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-24_1930_tl_02_ZIB-1_Signation---The__13993106__o__1886650622__s14385479_9__ORF2HD_19293322P_19301604P_Q6A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-24_1930_tl_02_ZIB-1_Signation---The__13993106__o__1886650622__s14385479_9__ORF2HD_19293322P_19301604P_Q8C.mp4/playlist.m3u8", - null); - assertEpisode( - actual.get(2), - "Ministerrat segnet Kassenreform ab", - Duration.ofSeconds(126), - "Die Regierung hat im Ministerrat die Reform der Krankenkassen abgesegnet. Der Gesetzesvorschlag geht ohne große Korrekturen ins Parlament, erste Teile sollen schon ab 1. Jänner 2019 gelten.", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-24_1930_tl_02_ZIB-1_Ministerrat-seg__13993106__o__5309298085__s14385480_0__ORF2HD_19301604P_19322213P_Q4A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-24_1930_tl_02_ZIB-1_Ministerrat-seg__13993106__o__5309298085__s14385480_0__ORF2HD_19301604P_19322213P_Q6A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2018-10-24_1930_tl_02_ZIB-1_Ministerrat-seg__13993106__o__5309298085__s14385480_0__ORF2HD_19301604P_19322213P_Q8C.mp4/playlist.m3u8", - null); - } - - private void assertEpisode( - final OrfEpisodeInfoDTO actualEpisode, - final String expectedTitle, - final Duration expectedDuration, - final String expectedDescription, - final String expectedUrlSmall, - final String expectedUrlNormal, - final String expectedUrlHd, - final String expectedSubtitle) { - assertThat(actualEpisode.getTitle().get(), equalTo(expectedTitle)); - assertThat(actualEpisode.getDuration().get(), equalTo(expectedDuration)); - - if (expectedDescription.isEmpty()) { - assertThat(actualEpisode.getDescription().isPresent(), equalTo(false)); - } else { - assertThat(actualEpisode.getDescription().get(), equalTo(expectedDescription)); - } - - final OrfVideoInfoDTO actualVideoInfo = actualEpisode.getVideoInfo(); - assertThat(actualVideoInfo, notNullValue()); - - final Map actualVideoUrls = actualVideoInfo.getVideoUrls(); - assertThat(actualVideoUrls.get(Resolution.SMALL), equalTo(expectedUrlSmall)); - assertThat(actualVideoUrls.get(Resolution.NORMAL), equalTo(expectedUrlNormal)); - assertThat(actualVideoUrls.containsKey(Resolution.HD), equalTo(!expectedUrlHd.isEmpty())); - if (!expectedUrlHd.isEmpty()) { - assertThat(actualVideoUrls.get(Resolution.HD), equalTo(expectedUrlHd)); - } - - assertThat(actualVideoInfo.getSubtitleUrl(), equalTo(expectedSubtitle)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfDayTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfDayTaskTest.java deleted file mode 100644 index c45f897fe..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfDayTaskTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.basic.CrawlerUrlDTO; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.JsoupMock; -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.io.IOException; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class OrfDayTaskTest extends OrfTaskTestBase { - - @Mock JsoupConnection jsoupConnection; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void test() throws IOException { - final String requestUrl = "http://tvthek.orf.at/schedule/03.02.2018"; - jsoupConnection = JsoupMock.mock(requestUrl, "/orf/orf_day.html"); - OrfCrawler crawler = createCrawler(); - crawler.setConnection(jsoupConnection); - - final TopicUrlDTO[] expected = - new TopicUrlDTO[] { - new TopicUrlDTO( - "Wetter-Panorama", - "https://tvthek.orf.at/profile/Wetter-Panorama/7268748/Wetter-Panorama/14007692"), - new TopicUrlDTO( - "Hallo okidoki", - "https://tvthek.orf.at/profile/Hallo-okidoki/2616615/Hallo-okidoki/14007693"), - new TopicUrlDTO( - "Tolle Tiere", - "https://tvthek.orf.at/profile/Tolle-Tiere/13764575/Tolle-Tiere/14007694"), - new TopicUrlDTO( - "Skiweltcup", - "https://tvthek.orf.at/profile/Ski-alpin-Damen-Herren/13886795/Skiweltcup-Siegerehrungen-inkl-Uebergabe-der-Kristallkugeln/14007719"), - new TopicUrlDTO( - "Was ich glaube", - "https://tvthek.orf.at/profile/Was-ich-glaube/1287/Was-ich-glaube/14007720"), - new TopicUrlDTO( - "ZIB", "https://tvthek.orf.at/profile/ZIB-1700/71284/ZIB-1700/14007722"), - new TopicUrlDTO( - "Vorarlberg heute", - "https://tvthek.orf.at/profile/Vorarlberg-heute/70024/Vorarlberg-heute/14007821"), - new TopicUrlDTO( - "Wien heute", "https://tvthek.orf.at/profile/Wien-heute/70018/Wien-heute/14007816"), - new TopicUrlDTO( - "Fußball", "https://tvthek.orf.at/profile/Fussball/8205855/Fussball/14007727"), - new TopicUrlDTO( - "AD | Fußball", - "https://tvthek.orf.at/profile/AD-Fussball/13886317/AD-Fussball/14007846"), - new TopicUrlDTO("ZIB 1", "https://tvthek.orf.at/profile/ZIB-1/1203/ZIB-1/14007730"), - new TopicUrlDTO( - "ZIB 1 (ÖGS)", "https://tvthek.orf.at/profile/ZIB-1-OeGS/145302/ZIB-1-OeGS/14007848"), - new TopicUrlDTO( - "Embrace - Du bist schön", - "https://tvthek.orf.at/profile/Embrace-Du-bist-schoen/13890275/Embrace-Du-bist-schoen/14007745") - }; - - final Queue queue = new ConcurrentLinkedQueue<>(); - queue.add(new CrawlerUrlDTO(requestUrl)); - - final OrfDayTask target = new OrfDayTask(crawler, queue); - final Set actual = target.invoke(); - - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(expected.length)); - assertThat(actual, Matchers.containsInAnyOrder(expected)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskJugendschutzTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskJugendschutzTest.java deleted file mode 100644 index 95199d540..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskJugendschutzTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mlib.daten.Film; -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.JsoupMock; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.io.IOException; -import java.util.Set; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class OrfFilmDetailTaskJugendschutzTest extends OrfFilmDetailTaskTestBase { - - @Mock JsoupConnection jsoupConnection; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void testJugendschutzNotAdded() throws IOException { - setupHeadRequestForFileSize(); - final String requestUrl = - "https://tvthek.orf.at/profile/Tatort/2713749/Tatort-Hetzjagd/14081980"; - jsoupConnection = JsoupMock.mock(requestUrl, "/orf/orf_film_jugendschutz.html"); - OrfCrawler crawler = createCrawler(); - crawler.setConnection(jsoupConnection); - - final Set actual = executeTask(crawler, "Tatort", requestUrl); - - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(0)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskTest.java deleted file mode 100644 index 555772290..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskTest.java +++ /dev/null @@ -1,237 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -import de.mediathekview.mlib.daten.Film; -import de.mediathekview.mlib.daten.GeoLocations; -import de.mediathekview.mlib.daten.Sender; -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.AssertFilm; -import de.mediathekview.mserver.testhelper.JsoupMock; -import java.io.IOException; -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.Collection; -import java.util.Set; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(Parameterized.class) -public class OrfFilmDetailTaskTest extends OrfFilmDetailTaskTestBase { - - private final String requestUrl; - private final String filmPageFile; - private final String theme; - private final String expectedTheme; - private final String expectedTitle; - private final LocalDateTime expectedDate; - private final Duration expectedDuration; - private final String expectedDescription; - private final String expectedSubtitle; - private final String expectedUrlSmall; - private final String expectedUrlNormal; - private final String expectedUrlHd; - private final String expectedUrlAudioDescriptionSmall; - private final String expectedUrlAudioDescriptionNormal; - private final String expectedUrlAudioDescriptionHd; - private final GeoLocations[] expectedGeoLocations; - @Mock JsoupConnection jsoupConnection; - - public OrfFilmDetailTaskTest( - final String aRequestUrl, - final String aFilmPageFile, - final String aTheme, - final String aExpectedTheme, - final String aExpectedTitle, - final LocalDateTime aExpectedDate, - final Duration aExpectedDuration, - final String aExpectedDescription, - final String aExpectedSubtitle, - final String aExpectedUrlSmall, - final String aExpectedUrlNormal, - final String aExpectedUrlHd, - final String aExpectedUrlAudioDescriptionSmall, - final String aExpectedUrlAudioDescriptionNormal, - final String aExpectedUrlAudioDescriptionHd, - final GeoLocations[] aExpectedGeoLocations) { - requestUrl = aRequestUrl; - filmPageFile = aFilmPageFile; - theme = aTheme; - expectedTheme = aExpectedTheme; - expectedTitle = aExpectedTitle; - expectedDate = aExpectedDate; - expectedDuration = aExpectedDuration; - expectedDescription = aExpectedDescription; - expectedUrlSmall = buildWireMockUrl(aExpectedUrlSmall); - expectedUrlNormal = buildWireMockUrl(aExpectedUrlNormal); - expectedUrlHd = buildWireMockUrl(aExpectedUrlHd); - expectedUrlAudioDescriptionSmall = buildWireMockUrl(aExpectedUrlAudioDescriptionSmall); - expectedUrlAudioDescriptionNormal = buildWireMockUrl(aExpectedUrlAudioDescriptionNormal); - expectedUrlAudioDescriptionHd = buildWireMockUrl(aExpectedUrlAudioDescriptionHd); - expectedSubtitle = aExpectedSubtitle; - expectedGeoLocations = aExpectedGeoLocations; - } - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - { - "https://tvthek.orf.at/profile/Hilfe-ich-hab-meine-Lehrerin-geschrumpft/13889696/Hilfe-ich-hab-meine-Lehrerin-geschrumpft/13993284", - "/orf/orf_film_audiodescription_duration_hour.html", - "AD | Tatort", - "Tatort", - "Tatort: Spieglein, Spieglein", - LocalDateTime.of(2019, 3, 17, 20, 15, 0), - Duration.ofMinutes(87), - "Staatsanwältin Klemm ist fassungslos. Die Frau, die mitten auf der Promenade in Münster erschossen wurde, sieht ihr zum Verwechseln ähnlich. Für Kommissar Thiel gibt es zunächst keinerlei Anhaltspunkte für ein Tatmotiv.", - "", - "", - "", - "", - "/apasfiis.sf.apa.at/ipad/cms-austria/2019-03-17_2015_sd_00_AD---Tatort--Sp_____14007849__o__2088184633__s14465114_4__ORF2ADHD_20144904P_21415115P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-austria/2019-03-17_2015_sd_00_AD---Tatort--Sp_____14007849__o__2088184633__s14465114_4__ORF2ADHD_20144904P_21415115P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-austria/2019-03-17_2015_sd_00_AD---Tatort--Sp_____14007849__o__2088184633__s14465114_4__ORF2ADHD_20144904P_21415115P_Q8C.mp4/playlist.m3u8", - new GeoLocations[] {GeoLocations.GEO_AT} - }, - { - "https://tvthek.orf.at/profile/BUNDESLAND-HEUTE/8461416/Bundesland-heute/13890700", - "/orf/orf_film_date_cest.html", - "Bundesland heute", - "Bundesland heute", - "Bundesland heute", - LocalDateTime.of(2016, 10, 1, 12, 55, 9), - Duration.ofSeconds(30), - "", - "", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/20161011_1040_in_02_Bundesland-heut_____13890700__o__1693823857__s13890997_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/20161011_1040_in_02_Bundesland-heut_____13890700__o__1693823857__s13890997_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/20161011_1040_in_02_Bundesland-heut_____13890700__o__1693823857__s13890997_Q8C.mp4/playlist.m3u8", - "", - "", - "", - new GeoLocations[] {GeoLocations.GEO_NONE} - }, - { - "http://tvthek.orf.at/archive/Die-Geschichte-des-Burgenlands/9236430/Zweisprachige-Ortstafeln/9056913", - "/orf/orf_history_film.html", - "Die Geschichte des Burgenlandes", - "Die Geschichte des Burgenlandes", - "Erste zweisprachige Ortstafel im Burgenland enthüllt", - LocalDateTime.of(2000, 7, 13, 12, 0, 0), - Duration.ofSeconds(174), - "Der Ort Großwarasdorf war die erste burgenländische Gemeinde mit einer offiziellen zweisprachigen Ortstafel. Der damaliger Bundeskanzler Wolfgang Schüssel (ÖVP) war vor Ort, um sie feierlich zu enthüllen. Otkrita prva dvojezična seoska tabla u Gradišću Općina Veliki Borištof je bila prva gradišćanska općina u koj je postavljena oficijelna dvojezična tabla. Tadašnji savezni kancelar Wolfgang Schüss\n.....", - "", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2000-07-13_1200_in_00_Zweisprachige-Ortsta_____9056913__o__0001362620__s9056914___Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2000-07-13_1200_in_00_Zweisprachige-Ortsta_____9056913__o__0001362620__s9056914___Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2000-07-13_1200_in_00_Zweisprachige-Ortsta_____9056913__o__0001362620__s9056914___Q8C.mp4/playlist.m3u8", - "", - "", - "", - new GeoLocations[] {GeoLocations.GEO_NONE} - }, - { - "https://tvthek.orf.at/profile/Soko-Donau/2672809/Soko-Donau-Entfesselt/14007925", - "/orf/orf_film_with_subtitle.html", - "Soko Donau", - "Soko Donau", - "Soko Donau: Entfesselt", - LocalDateTime.of(2019, 3, 19, 20, 15, 0), - Duration.ofMinutes(43).plusSeconds(16), - "Gewalttäter Gerd Weinzierl kommt nach drei Jahren Haft in elektronisch überwachten Hausarrest. Richard Kofler, Vater von Weinzierls damaligen Opfer Daniela, nimmt das mit großer Sorge wahr.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/35/d184eb43cd1d3a3c926810728cb99ee82204c43e.ttml", - "/apasfiis.sf.apa.at/ipad/cms-austria/2019-03-19_2015_in_01_Soko-Donau--Ent_____14007925__o__2552019395__s14465271_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-austria/2019-03-19_2015_in_01_Soko-Donau--Ent_____14007925__o__2552019395__s14465271_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-austria/2019-03-19_2015_in_01_Soko-Donau--Ent_____14007925__o__2552019395__s14465271_Q8C.mp4/playlist.m3u8", - "", - "", - "", - new GeoLocations[] {GeoLocations.GEO_AT} - }, - { - "https://tvthek.orf.at/profile/DENK-mit-KULTUR/8728536/DENK-mit-KULTUR-Gerda-Rogers-und-Schiffkowitz/14034271", - "/orf/orf_film_new_description_block.html", - "DENK mit KULTUR", - "DENK mit KULTUR", - "Gerda Rogers und Schiffkowitz", - LocalDateTime.of(2019, 12, 6, 21, 5, 0), - Duration.ofMinutes(45).plusSeconds(0), - "Birgit Denk hat diesmal Astrologin Gerda Rogers und STS-Star Schiffkowitz zum gemütlichen Late-Night-Talk ins Casino Baden eingeladen.", - "", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2019-12-06_2105_sd_06_DENK-mit-KULTUR_____14034271__o__1025186593__s14603593_3__ORF3HD_21062006P_21511908P_Q4A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2019-12-06_2105_sd_06_DENK-mit-KULTUR_____14034271__o__1025186593__s14603593_3__ORF3HD_21062006P_21511908P_Q6A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2019-12-06_2105_sd_06_DENK-mit-KULTUR_____14034271__o__1025186593__s14603593_3__ORF3HD_21062006P_21511908P_Q8C.mp4/playlist.m3u8", - "", - "", - "", - new GeoLocations[] {GeoLocations.GEO_NONE} - }, - { - "https://tvthek.orf.at/profile/Burgenland-heute-kompakt/13891025/Burgenland-heute-kompakt/14203644", - "/orf/orf_film_with_seconds.html", - "Burgenland heute kompakt", - "Burgenland heute kompakt", - "Burgenland heute kompakt", - LocalDateTime.of(2023, 12, 1, 16, 57, 0), - Duration.ofSeconds(49), - "", - "", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2023-12-01_1657_tl_23_Burgenland-heut_____14203644__o__1338501503__s15520121_1__BLBHD_16570412P_16575304P_Q4A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2023-12-01_1657_tl_23_Burgenland-heut_____14203644__o__1338501503__s15520121_1__BLBHD_16570412P_16575304P_Q6A.mp4/playlist.m3u8", - "https://apasfiis.sf.apa.at/ipad/cms-worldwide/2023-12-01_1657_tl_23_Burgenland-heut_____14203644__o__1338501503__s15520121_1__BLBHD_16570412P_16575304P_Q8C.mp4/playlist.m3u8", - "", - "", - "", - new GeoLocations[] {GeoLocations.GEO_NONE} - } - }); - } - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void test() throws IOException { - setupHeadRequestForFileSize(); - jsoupConnection = JsoupMock.mock(requestUrl, filmPageFile); - OrfCrawler crawler = createCrawler(); - crawler.setConnection(jsoupConnection); - - final Set actual = executeTask(crawler, theme, requestUrl); - - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(1)); - - final Film actualFilm = (Film) actual.toArray()[0]; - AssertFilm.assertEquals( - actualFilm, - Sender.ORF, - expectedTheme, - expectedTitle, - expectedDate, - expectedDuration, - expectedDescription, - requestUrl, - expectedGeoLocations, - expectedUrlSmall, - expectedUrlNormal, - expectedUrlHd, - "", - "", - "", - expectedUrlAudioDescriptionSmall, - expectedUrlAudioDescriptionNormal, - expectedUrlAudioDescriptionHd, - expectedSubtitle); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskTestBase.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskTestBase.java deleted file mode 100644 index 85a0ee3fd..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskTestBase.java +++ /dev/null @@ -1,18 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mlib.daten.Film; - -import de.mediathekview.mserver.crawler.orf.OrfCrawler; - -import java.util.Set; - -public abstract class OrfFilmDetailTaskTestBase extends OrfTaskTestBase { - - public OrfFilmDetailTaskTestBase() { - } - - protected Set executeTask(OrfCrawler crawler, String aTheme, String aRequestUrl) { - return new OrfFilmDetailTask(crawler, createCrawlerUrlDto(aTheme, aRequestUrl), false) - .invoke(); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskWithEpisodesTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskWithEpisodesTest.java deleted file mode 100644 index 1ba587b01..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfFilmDetailTaskWithEpisodesTest.java +++ /dev/null @@ -1,189 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mlib.daten.Film; -import de.mediathekview.mlib.daten.GeoLocations; -import de.mediathekview.mlib.daten.Sender; -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.AssertFilm; -import de.mediathekview.mserver.testhelper.JsoupMock; -import org.junit.Before; -import org.junit.Test; -import org.junit.runners.Parameterized; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.io.IOException; -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.Collection; -import java.util.Set; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class OrfFilmDetailTaskWithEpisodesTest extends OrfFilmDetailTaskTestBase { - - private static final String REQUEST_URL = - "https://tvthek.orf.at/profile/ZIB-900/71256/ZIB-900/14007767"; - private static final String EXPECTED_THEME = "ZIB 9:00"; - private static final LocalDateTime EXPECTED_TIME = LocalDateTime.of(2019, 3, 18, 9, 0, 0); - private static final GeoLocations[] EXPECTED_GEO = new GeoLocations[] {GeoLocations.GEO_NONE}; - - private static final int INDEX_TITLE = 0; - private static final int INDEX_DURATION = 1; - private static final int INDEX_DESCRIPTION = 2; - private static final int INDEX_SUBTITLE = 3; - private static final int INDEX_URL_SMALL = 4; - private static final int INDEX_URL_NORMAL = 5; - private static final int INDEX_URL_HD = 6; - - @Mock JsoupConnection jsoupConnection; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - { - "ZIB 9:00", - Duration.ofMinutes(8).plusSeconds(38), - "Neuseeland: Attentäter will sich selbst verteidigen | Jölli (ORF) über Prozess in Chemnitz | Boeing: USA überprüft Zulassungsverfahren | Fünf Jahre Annexion der Krim | Peter Kraus ist 80 | Thiem auf Platz vier der Weltrangliste | Wetter", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/ab9769266a0be435d2fd5d73cabde0076ef9d55c.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/14007767_0011_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/14007767_0011_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide_episodes/14007767_0011_Q8C.mp4/playlist.m3u8" - }, - { - "Thiem auf Platz vier der Weltrangliste", - Duration.ofSeconds(35), - "Der Tennisspieler Dominic Thiem hat Superstar Roger Federer geschlagen und erstmals einen Masters-1000-Titel gewonnen. Auf der Weltrangliste steht Thiem nun auf Platz vier.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/c10d2fa4eda80c8b90d3d449ada6d68736fa4395.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Thiem-auf-Platz__14007767__o__7185021595__s14465213_3__ORF2HD_09063916P_09071423P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Thiem-auf-Platz__14007767__o__7185021595__s14465213_3__ORF2HD_09063916P_09071423P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Thiem-auf-Platz__14007767__o__7185021595__s14465213_3__ORF2HD_09063916P_09071423P_Q8C.mp4/playlist.m3u8" - }, - { - "Signation | Themen", - Duration.ofSeconds(16), - "Neuseeland: Attentäter will sich selbst verteidigen | Jölli (ORF) über Prozess in Chemnitz | Boeing: USA überprüft Zulassungsverfahren | Fünf Jahre Annexion der Krim | Peter Kraus ist 80 | Thiem auf Platz vier der Weltrangliste | Wetter", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/6d222f74207d1d1dee0d2d4611815951e745e6c3.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Signation---The__14007767__o__1412221432__s14465207_7__ORF2HD_09000021P_09001714P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Signation---The__14007767__o__1412221432__s14465207_7__ORF2HD_09000021P_09001714P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Signation---The__14007767__o__1412221432__s14465207_7__ORF2HD_09000021P_09001714P_Q8C.mp4/playlist.m3u8" - }, - { - "Wetter", - Duration.ofSeconds(85), - "Nach dem sonnigen und milden Sonntag ist über Nacht feuchte Luft von Nordeuropa nach Österreich geströmt. Damit wird es ein unbeständiger und kühler Wochenstart", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/f1488a72dde1d0dbfc892d431503b5d8e005b75b.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Wetter__14007767__o__1404024135__s14465214_4__ORF2HD_09071423P_09084015P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Wetter__14007767__o__1404024135__s14465214_4__ORF2HD_09071423P_09084015P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Wetter__14007767__o__1404024135__s14465214_4__ORF2HD_09071423P_09084015P_Q8C.mp4/playlist.m3u8" - }, - { - "Peter Kraus ist 80", - Duration.ofSeconds(74), - "Peter Kraus feiert am Montag seinen 80. Geburtstag. Der österreichische Sänger und Schauspieler ist seit den 1950er Jahren berühmt und hat den Rock & Roll im deutschsprachigen Raum salonfähig gemacht.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/d5c8eb0e78c1226a38639615ada85592533cf20c.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Peter-Kraus-ist__14007767__o__1330093995__s14465212_2__ORF2HD_09052421P_09063916P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Peter-Kraus-ist__14007767__o__1330093995__s14465212_2__ORF2HD_09052421P_09063916P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Peter-Kraus-ist__14007767__o__1330093995__s14465212_2__ORF2HD_09052421P_09063916P_Q8C.mp4/playlist.m3u8" - }, - { - "Jölli (ORF) über Prozess in Chemnitz", - Duration.ofSeconds(64), - "In Chemnitz in Deutschland beginnt der Prozess um ein Messerangriff. Als Täter gelten zwei Asylwerber und das löst nach der Tat Aufruhr aus. Andreas Jölli (ORF) berichtet.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/e9a6bbc0d3a34adaf677a7845ef923abf46c75e1.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Joelli--ORF--ue__14007767__o__1318216483__s14465209_9__ORF2HD_09013812P_09024309P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Joelli--ORF--ue__14007767__o__1318216483__s14465209_9__ORF2HD_09013812P_09024309P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Joelli--ORF--ue__14007767__o__1318216483__s14465209_9__ORF2HD_09013812P_09024309P_Q8C.mp4/playlist.m3u8" - }, - { - "Fünf Jahre Annexion der Krim", - Duration.ofSeconds(85), - "Vor fünf Jahren hat Russland die ukrainische Halbinsel Krim per Staatsvertrag annektiert. Die Aktion hat viel Kritik ausgelöst, Moskau ist seitdem mit Sanktionen belegt.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/559b2abe436554513bf9b6d7adc5a6c86976390b.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Fuenf-Jahre-Ann__14007767__o__1979729045__s14465211_1__ORF2HD_09035904P_09052421P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Fuenf-Jahre-Ann__14007767__o__1979729045__s14465211_1__ORF2HD_09035904P_09052421P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Fuenf-Jahre-Ann__14007767__o__1979729045__s14465211_1__ORF2HD_09035904P_09052421P_Q8C.mp4/playlist.m3u8" - }, - { - "Boeing: USA überprüft Zulassungsverfahren", - Duration.ofSeconds(75), - "Die Abstürze zweier Boeing-Flugzeuge vom Typ 737 Max 8 haben immer mehr Konsequenzen. Die US-Regierung überprüft das Zulassungsverfahren der amerikanischen Flug-Aufsichtsbehörde.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/39b45f3c67d9db34fa39590756959b78bd036345.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Boeing--USA-ueb__14007767__o__1038723783__s14465210_0__ORF2HD_09024309P_09035904P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Boeing--USA-ueb__14007767__o__1038723783__s14465210_0__ORF2HD_09024309P_09035904P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Boeing--USA-ueb__14007767__o__1038723783__s14465210_0__ORF2HD_09024309P_09035904P_Q8C.mp4/playlist.m3u8" - }, - { - "Attentäter will sich selbst verteidigen", - Duration.ofSeconds(80), - "Nach dem Terroranschlag in Neuseeland mit mindestens 50 Todesopfern will sich der mutmaßliche Attentäter selbst vor Gericht verteidigen. Der 28-jährige Australier ist wegen Mordes angeklagt.", - "https://api-tvthek.orf.at/uploads/media/subtitles/0076/23/86e33a5c356a973fcb78527c822f89b1d4fa5709.ttml", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Neuseeland--Att__14007767__o__1967360405__s14465208_8__ORF2HD_09001810P_09013812P_Q4A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Neuseeland--Att__14007767__o__1967360405__s14465208_8__ORF2HD_09001810P_09013812P_Q6A.mp4/playlist.m3u8", - "/apasfiis.sf.apa.at/ipad/cms-worldwide/2019-03-18_0900_tl_02_ZIB-9-00_Neuseeland--Att__14007767__o__1967360405__s14465208_8__ORF2HD_09001810P_09013812P_Q8C.mp4/playlist.m3u8" - } - }); - } - - @Test - public void test() throws IOException { - setupHeadRequestForFileSize(); - jsoupConnection = JsoupMock.mock(REQUEST_URL, "/orf/orf_film_with_several_parts.html"); - OrfCrawler crawler = createCrawler(); - crawler.setConnection(jsoupConnection); - - final Collection films = data(); - - final Set actual = executeTask(crawler, EXPECTED_THEME, REQUEST_URL); - - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(films.size())); - - actual.forEach( - actualFilm -> { - final Object[] expectedData = getExpectedValues(films, actualFilm.getTitel()); - assertThat(expectedData, notNullValue()); - - AssertFilm.assertEquals( - actualFilm, - Sender.ORF, - EXPECTED_THEME, - expectedData[INDEX_TITLE].toString(), - EXPECTED_TIME, - (Duration) expectedData[INDEX_DURATION], - expectedData[INDEX_DESCRIPTION].toString(), - REQUEST_URL, - EXPECTED_GEO, - expectedData[INDEX_URL_SMALL].toString().isEmpty() - ? "" - : getWireMockBaseUrlSafe() + expectedData[INDEX_URL_SMALL].toString(), - expectedData[INDEX_URL_NORMAL].toString().isEmpty() - ? "" - : getWireMockBaseUrlSafe() + expectedData[INDEX_URL_NORMAL].toString(), - expectedData[INDEX_URL_HD].toString().isEmpty() - ? "" - : getWireMockBaseUrlSafe() + expectedData[INDEX_URL_HD].toString(), - expectedData[INDEX_SUBTITLE].toString()); - }); - } - - private Object[] getExpectedValues(final Collection aExpectedFilms, final String aActualTitle) { - for (final Object[] expected : aExpectedFilms) { - if (expected[INDEX_TITLE].toString().compareToIgnoreCase(aActualTitle) == 0) { - return expected; - } - } - - return new Object[0]; - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHelperTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHelperTest.java deleted file mode 100644 index 075fb4916..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHelperTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Arrays; -import java.util.Collection; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; - -@RunWith(Parameterized.class) -public class OrfHelperTest { - - private final String expectedTheme; - private final String inputTheme; - - public OrfHelperTest(String inputTheme, String expectedTheme) { - this.expectedTheme = expectedTheme; - this.inputTheme = inputTheme; - } - - @Parameterized.Parameters - public static Collection data() { - return Arrays.asList( - new Object[][] { - {"Hallo Österreich", "Hallo Österreich"}, - {"Adj'Isten magyarok", "Adj'Isten magyarok"}, - {"ZIB 1", "ZIB 1"}, - {"ZIB 18", "ZIB 18"}, - {"Sport 20", "Sport 20"}, - {"ZIB Flash 19:55", "ZIB Flash"}, - {"ZIB 17:00", "ZIB"}, - {"ZIB 9:00", "ZIB"}, - {"Guten Morgen Österreich 8:30", "Guten Morgen Österreich"}, - {"Guten Morgen Österreich 08:00", "Guten Morgen Österreich"}, - {"Thema hier : hier kommt was anderes", "Thema hier"} - }); - } - - @Test - public void parseTheme() { - - final String actualTheme = OrfHelper.parseTheme(inputTheme); - assertThat(actualTheme, equalTo(expectedTheme)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryOverviewTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryOverviewTaskTest.java deleted file mode 100644 index 5f3f29a5a..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryOverviewTaskTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mlib.daten.Sender; -import de.mediathekview.mserver.base.config.MServerConfigManager; -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfConstants; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.JsoupMock; -import org.hamcrest.Matchers; -import org.jsoup.nodes.Document; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import java.util.Queue; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -public class OrfHistoryOverviewTaskTest { - - @Mock JsoupConnection jsoupConnection; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - private final TopicUrlDTO[] expectedUrls = - new TopicUrlDTO[] { - new TopicUrlDTO( - "Die Geschichte des Burgenlands", - "https://tvthek.orf.at/history/Die-Geschichte-des-Burgenlands/9236430"), - new TopicUrlDTO( - "Die Geschichte Niederösterreichs", - "https://tvthek.orf.at/history/Die-Geschichte-Niederoesterreichs/8378971"), - new TopicUrlDTO( - "Volksgruppen in Österreich", - "https://tvthek.orf.at/history/Volksgruppen-in-Oesterreich/13557924") - }; - - @Test - public void test() throws Exception { - final OrfCrawler crawler = Mockito.mock(OrfCrawler.class); - when(crawler.getCrawlerConfig()) - .thenReturn( - new MServerConfigManager("MServer-JUnit-Config.yaml").getSenderConfig(Sender.ORF)); - final Document document = JsoupMock.getFileDocument("/orf/orf_history_overview.html"); - when(jsoupConnection.requestBodyAsHtmlDocument(eq(OrfConstants.URL_ARCHIVE))) - .thenReturn(document); - when(crawler.requestBodyAsHtmlDocument(eq(OrfConstants.URL_ARCHIVE))).thenReturn(document); - when(crawler.getConnection()).thenReturn(jsoupConnection); - - final OrfHistoryOverviewTask target = new OrfHistoryOverviewTask(crawler); - - final Queue actual = target.call(); - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(expectedUrls.length)); - assertThat(actual, Matchers.containsInAnyOrder(expectedUrls)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryTopicTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryTopicTaskTest.java deleted file mode 100644 index 3d47033b4..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfHistoryTopicTaskTest.java +++ /dev/null @@ -1,137 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.JsoupMock; -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.io.IOException; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -public class OrfHistoryTopicTaskTest extends OrfTaskTestBase { - - @Mock JsoupConnection jsoupConnection; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - public void test() throws IOException { - final String requestUrl = - "https://tvthek.orf.at/history/Die-Geschichte-Niederoesterreichs/8378971"; - final String topic = "Die Geschichte Niederösterreichs"; - - jsoupConnection = JsoupMock.mock(requestUrl, "/orf/orf_history_topic_overview.html"); - OrfCrawler crawler = createCrawler(); - crawler.setConnection(jsoupConnection); - - final TopicUrlDTO[] expected = - new TopicUrlDTO[] { - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Johanna-Mikl-Leitner-erste-Landeshauptfrau-Niederoesterreichs/13927331"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Letzte-Rede-von-Erwin-Proell-als-Landeshauptmann/13927148"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Landeshauptmann-Erwin-Proell-OeVP-tritt-zurueck/13914863"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Der-Werdegang-des-Julius-Raab/8293346"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Leopold-Figl-Glaubt-an-dieses-Oesterreich/9697062"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Liese-Prokop-erste-Innenministerin-Oesterreichs/13919164"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Niederoesterreich-erhaelt-seine-erste-Landeshymne/8602764"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Ein-Land-sucht-seine-Hauptstadt/8293238"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Protest-gegen-Kraftwerk-in-der-Wachau/8323916"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Siegfried-Ludwig-im-Portraet/8675677"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Der-vorletzte-Kuenringer-Andreas-Maurer/8298065"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Karl-Schloegl-zieht-sich-aus-Politik-zurueck/13988092"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Eroeffnung-des-Josef-Reither-Museums/8764784"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Nachruf-Siegfried-Ludwig/8322787"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Regierungsviertel-Spatenstich-in-St-Poelten/8276763"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Landeshauptleute-und-Politik/8378973/Feierliche-Eroeffnung-des-Regierungsviertels/8276738"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Ein-Tag-im-Stift-Melk/8313371"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Moench-und-Manager-Ein-Blick-in-das-Stift-Altenburg/8313396"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Das-belebte-Stift-Goettweig/8323032"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Die-Schatzkammer-von-Klosterneuburg/8294667"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Doppelkloster-Stift-Geras-Pernegg/8313494"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Bildband-Die-Wienerwaldkloester/8276592"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Kulturerbe-Stift-Lilienfeld/8313407"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/350-Jahre-Basilika-Maria-Taferl/8293327"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/900-Jahre-Stift-Seitenstetten/8302230"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Jubilaeum-im-Stift-Zwettl/8323108"), - new TopicUrlDTO( - topic, - "https://tvthek.orf.at/history/Stifte-und-Kloester/8378976/Pilgerstaette-am-Sonntagberg/8328932") - }; - - final Queue queue = new ConcurrentLinkedQueue<>(); - queue.add(new TopicUrlDTO(topic, requestUrl)); - - final OrfHistoryTopicTask target = - new OrfHistoryTopicTask(crawler, queue); - final Set actual = target.invoke(); - - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(expected.length)); - assertThat(actual, Matchers.containsInAnyOrder(expected)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfLetterPageTaskTest.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfLetterPageTaskTest.java deleted file mode 100644 index 45649d4bd..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfLetterPageTaskTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mlib.daten.Sender; -import de.mediathekview.mserver.base.config.MServerConfigManager; -import de.mediathekview.mserver.base.webaccess.JsoupConnection; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfConstants; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.testhelper.JsoupMock; -import org.hamcrest.Matchers; -import org.jsoup.nodes.Document; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Queue; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.when; - -public class OrfLetterPageTaskTest { - - private static final String ORF_EMPTY_PAGE = "/orf/orf_letter_empty.html"; - - @Mock JsoupConnection jsoupConnection; - - @Before - public void setUp() { - MockitoAnnotations.openMocks(this); - } - - private final TopicUrlDTO[] expectedUrls = - new TopicUrlDTO[] { - new TopicUrlDTO( - "Adj'Isten magyarok", - "https://tvthek.orf.at/profile/AdjIsten-magyarok/13886441/AdjIsten-magyarok/14007007"), - new TopicUrlDTO( - "Aktuell in Österreich", - "https://tvthek.orf.at/profile/Aktuell-in-Oesterreich/13887571/Aktuell-in-Oesterreich/14007906"), - new TopicUrlDTO( - "Alltagsgeschichten", - "https://tvthek.orf.at/profile/Alltagsgeschichten/13887428/Alltagsgeschichte-Am-Wuerstelstand/14007519"), - new TopicUrlDTO( - "Alpine Ski World Cup Magazin", - "https://tvthek.orf.at/profile/Alpine-Ski-World-Cup-Magazin/13889761/FIS-Alpine-SKI-World-Cup-Magazin-2018-2019-Folge-16/14007422"), - new TopicUrlDTO( - "Am Schauplatz Gericht", - "https://tvthek.orf.at/profile/Am-Schauplatz-Gericht/13886290/Am-Schauplatz-Gericht-Der-glaubt-ich-bin-deppert/14007403"), - new TopicUrlDTO( - "Aufgetischt", - "https://tvthek.orf.at/profile/Aufgetischt/13886333/Aufgetischt-am-Sonntag-Dornbirn/14007714"), - new TopicUrlDTO( - "Aus dem Rahmen", - "https://tvthek.orf.at/profile/Aus-dem-Rahmen/3078207/Aus-dem-Rahmen-Kunst-Karl-und-die-Basken-Das-Guggenheim-Museum-in-Bilbao/14007927"), - new TopicUrlDTO( - "Autofocus", - "https://tvthek.orf.at/profile/Autofocus/13886508/Autofocus-LKW-Gas-und-Strom-statt-Diesel/14007294"), - new TopicUrlDTO( - "Yoga-Magazin", - "https://tvthek.orf.at/profile/Yoga-Magazin/7708946/Das-Yoga-Magazin-Folge-110/14007507") - }; - - @Test - public void test() throws Exception { - final OrfCrawler crawler = Mockito.mock(OrfCrawler.class); - - final Map urlMapping = new HashMap<>(); - urlMapping.put( - OrfConstants.URL_SHOW_LETTER_PAGE + "A", - "/orf/orf_letter_multiple_themes_multiple_films.html"); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "B", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "C", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "D", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "E", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "F", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "G", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "H", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "I", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "J", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "K", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "L", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "M", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "N", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "O", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "P", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "Q", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "R", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "S", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "T", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "U", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "V", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "W", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "X", ORF_EMPTY_PAGE); - urlMapping.put( - OrfConstants.URL_SHOW_LETTER_PAGE + "Y", "/orf/orf_letter_single_theme_single_film.html"); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "Z", ORF_EMPTY_PAGE); - urlMapping.put(OrfConstants.URL_SHOW_LETTER_PAGE + "0", ORF_EMPTY_PAGE); - - urlMapping.forEach( - (url, fileName) -> { - try { - final Document document = JsoupMock.getFileDocument(fileName); - when(jsoupConnection.requestBodyAsHtmlDocument(eq(url))).thenReturn(document); - when(crawler.requestBodyAsHtmlDocument(eq(url))).thenReturn(document); - } catch (final IOException iox) { - fail(); - } - }); - - when(crawler.getCrawlerConfig()) - .thenReturn( - new MServerConfigManager("MServer-JUnit-Config.yaml").getSenderConfig(Sender.ORF)); - when(crawler.getConnection()).thenReturn(jsoupConnection); - - final OrfLetterPageTask target = new OrfLetterPageTask(crawler); - - final Queue actual = target.call(); - assertThat(actual, notNullValue()); - assertThat(actual.size(), equalTo(expectedUrls.length)); - assertThat(actual, Matchers.containsInAnyOrder(expectedUrls)); - } -} diff --git a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfTaskTestBase.java b/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfTaskTestBase.java deleted file mode 100644 index 3ab81708f..000000000 --- a/src/test/java/de/mediathekview/mserver/crawler/orf/tasks/OrfTaskTestBase.java +++ /dev/null @@ -1,34 +0,0 @@ -package de.mediathekview.mserver.crawler.orf.tasks; - -import de.mediathekview.mlib.messages.listener.MessageListener; -import de.mediathekview.mserver.base.config.MServerConfigManager; -import de.mediathekview.mserver.crawler.basic.TopicUrlDTO; -import de.mediathekview.mserver.crawler.orf.OrfCrawler; -import de.mediathekview.mserver.progress.listeners.SenderProgressListener; -import de.mediathekview.mserver.testhelper.WireMockTestBase; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ForkJoinPool; - -public abstract class OrfTaskTestBase extends WireMockTestBase { - - protected MServerConfigManager rootConfig = new MServerConfigManager("MServer-JUnit-Config.yaml"); - - public OrfTaskTestBase() {} - - protected OrfCrawler createCrawler() { - final ForkJoinPool forkJoinPool = new ForkJoinPool(); - final Collection nachrichten = new ArrayList<>(); - final Collection fortschritte = new ArrayList<>(); - return new OrfCrawler(forkJoinPool, nachrichten, fortschritte, rootConfig); - } - - protected Queue createCrawlerUrlDto(final String aTheme, final String aUrl) { - final Queue input = new ConcurrentLinkedQueue<>(); - input.add(new TopicUrlDTO(aTheme, aUrl)); - return input; - } -} 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 1064ccdfe..b0efe7fc3 100644 --- a/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodeTaskTest.java +++ b/src/test/java/de/mediathekview/mserver/crawler/orfon/OrfOnEpisodeTaskTest.java @@ -189,6 +189,48 @@ Resolution.VERY_SMALL, new FilmUrl("https://apasfiis.sf.apa.at/ipad/cms-worldwid } } + @Test + public void testDummyUrls() { + setupSuccessfulJsonResponse("/episodeDummyUrl", "/orfOn/episode_noDrm.json"); + setupSuccessfulJsonResponse("/cms-austria/online/6b2d672267c81e196472b564abf8c8fe/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q8C.mp4", "/orfOn/episode_noDrm.json"); + setupSuccessfulJsonResponse("/cms-austria/online/de9bd8775f46ea293a9db4b0711d4de5/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q6A.mp4", "/orfOn/episode_noDrm.json"); + setupSuccessfulJsonResponse("/cms-austria/online/a96476a0eab40b11ef517feefe0d2973/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q4A.mp4", "/orfOn/episode_noDrm.json"); + setupSuccessfulJsonResponse("/cms-austria/online/440102b9f68434fbb577d17114dd9182/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q1A.3gp", "/orfOn/episode_noDrm.json"); + setupHeadRequestForFileSize(); + // + Set result = executeTask("/episodeDummyUrl"); + assertTrue(result.size() == 1); + Film actual = result.toArray(new Film[1])[0]; + // + try { + assertEquals("Spektakuläre Raubüberfälle mit Pierce Brosnan: Bankeinbruch in Kalifornien",actual.getTitel()); + assertEquals("Spektakuläre Raubüberfälle mit Pierce Brosnan",actual.getThema()); + assertEquals(LocalDateTime.of(2024,03,13,23,49,50),actual.getTime()); + assertEquals("Pierce Brosnan präsentiert in der spannenden Krimi-Doku-Reihe die spektakulärsten Raubüberfälle der Geschichte.",actual.getBeschreibung()); + assertEquals(Duration.parse("PT40M46S"),actual.getDuration()); + assertEquals(Optional.of(new URL("https://tvthek.orf.at/profile/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan/13896153/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan-Bankeinbruch-in-Kalifornien/14216629")),actual.getWebsite()); + assertTrue(List.of(GeoLocations.GEO_AT).containsAll(actual.getGeoLocations())); + assertTrue(Set.of( + new URL("https://api-tvthek.orf.at/assets/subtitles/0171/15/e83f6eabbdbcf49e894d1a58d77fcf3a9b951f3c.smi"), + new URL("https://api-tvthek.orf.at/assets/subtitles/0171/15/c95472a931fe3ea8407734f95df242bce2f06b09.ttml"), + new URL("https://api-tvthek.orf.at/assets/subtitles/0171/15/13759cf0d408fe11965ff16d03a564bbabbf5bc1.vtt"), + new URL("https://api-tvthek.orf.at/assets/subtitles/0171/15/e2536ac2b80a5152e54b047073ab327c223579ec.srt"), + new URL("https://api-tvthek.orf.at/assets/subtitles/0171/15/be922c3765a25ec3d7fa13e9265dabad7f986b75.xml") + ).containsAll(actual.getSubtitles())); + assertEquals(Map.of( + Resolution.HD, new FilmUrl(getWireMockBaseUrlSafe()+"/cms-austria/online/6b2d672267c81e196472b564abf8c8fe/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q8C.mp4", 0L), + Resolution.NORMAL, new FilmUrl(getWireMockBaseUrlSafe()+"/cms-austria/online/de9bd8775f46ea293a9db4b0711d4de5/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q6A.mp4", 0L), + Resolution.SMALL, new FilmUrl(getWireMockBaseUrlSafe()+"/cms-austria/online/a96476a0eab40b11ef517feefe0d2973/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q4A.mp4", 0L), + Resolution.VERY_SMALL, new FilmUrl(getWireMockBaseUrlSafe()+"/cms-austria/online/440102b9f68434fbb577d17114dd9182/1713132000/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q1A.3gp", 0L) + ), actual.getUrls()); + } catch (Exception e) { + assertTrue(false); + } + + + + } + private Set executeTask(String... requestUrl) { final Queue input = new ConcurrentLinkedQueue<>(); for (String url : requestUrl) { diff --git a/src/test/resources/orfOn/episode_noDrm.json b/src/test/resources/orfOn/episode_noDrm.json new file mode 100644 index 000000000..0922bd580 --- /dev/null +++ b/src/test/resources/orfOn/episode_noDrm.json @@ -0,0 +1,1558 @@ +{ + "adition_advertising_query_string": "stype:vod,scat:doku-reportage,scatid:1173,spro:spektakulaere-raubueberfaelle-mit-pierce-brosnan,sproid:13896153,episodeid:14216629,duration:2446000,advertisingtags:", + "advertising_mapping": { + "live": { + "web": { + "sb": 4716830, + "tbar": 4420052, + "pre": 4420053, + "post": 4420054 + }, + "mob": { + "par": 4420055, + "pre": 4420220, + "post": 4420057 + }, + "app": { + "par": 4420058, + "pre": 4420059, + "post": 4420060 + }, + "smart": { + "pre": 4420061, + "post": 4420062 + } + }, + "vod": { + "web": { + "sb": 4420426, + "tbar": 4420427, + "pre": 4420428, + "post": 4420429 + }, + "mob": { + "par": 4420430, + "pre": 4420431, + "post": 4420432 + }, + "app": { + "par": 4420433, + "pre": 4420434, + "post": 4420435 + }, + "smart": { + "pre": 4420436, + "post": 4420437 + } + } + }, + "advertising_query_string": "stype=vod&scat=doku-reportage&scatid=1173&spro=spektakulaere-raubueberfaelle-mit-pierce-brosnan&sproid=13896153&episodeid=14216629&duration=2446000&advertisingtags=", + "age_classification": "12+", + "countdown": "1024 Tage", + "date": "2024-03-13T23:49:50+01:00", + "delete_date": "2027-02-07T00:00:00+01:00", + "vod_ressort": null, + "description": "Pierce Brosnan pr\u00e4sentiert in der spannenden Krimi-Doku-Reihe die spektakul\u00e4rsten Raub\u00fcberf\u00e4lle der Geschichte.", + "drm_token": "qaP8q0kHjO6D9w1Nrp2wLaz%2BzbuarITso8dCCeRSRgdkl7VKJpHKnor7tPC9smP7lHZykhEsWJsKTN4EpIEM10T9rqaax%2FR30ChjYqMAiP%2FGIALB3yntBVmGGALs62DKY68T0VDZ3KZpdKur%2BmB0oFTilVbYiKGNF9TA1ikfWqwPJkLFB2xD1w7JuIO%2F1OvYSrQPmn93uYQM355uDcOIBpI%2Fjk8yQrZjgqONjGknxAhvuG6TmqPosadWvRKx3d6B", + "duration_seconds": 2446, + "encrypted_id": "M2RTbGZlazAzbnNMS2RqNEpzZDE0MjE2NjI5", + "exact_duration": 2446000, + "field_descriptor": "Gewalt", + "flimmit_link_text": "", + "flimmit_link": "", + "gapless_sources_austria": { + "hls": [], + "dash": [] + }, + "genre_id": 1173, + "genre_title": "Doku & Reportage", + "right": "austria", + "growing": true, + "growing_type": "chronology", + "has_active_youth_protection": false, + "focus": false, + "show_countdown": true, + "has_subtitle": true, + "has_thumbnail": true, + "has_youth_protection": false, + "headline": "Bankeinbruch in Kalifornien", + "hide_in_new_section": false, + "hide_in_schedule_section": false, + "hide_latest_episodes": false, + "id": 14216629, + "is_archive": false, + "audio_description_service_available": false, + "is_drm_protected": true, + "is_gapless_austria": false, + "is_gapless": true, + "gmf_merged_content": false, + "is_oegs": false, + "two_channel_audio": false, + "uhd": false, + "killdate_extern": "2027-01-31T00:00:00+01:00", + "killdate": "2027-01-31T00:00:00+01:00", + "livedate": "2024-03-13T23:50:00+01:00", + "livedate_extern": "2024-03-13T23:50:00+01:00", + "orf_label": null, + "disable_display_ads_orf_platforms": false, + "disable_instream_ads_orf_platforms": false, + "production_country_is_europe": false, + "production_country": "Vereinigte Staaten", + "production_year": 2023, + "profile_title": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan", + "website": "", + "recommendation_episode": null, + "related_audiodescription_episode_image_url": null, + "related_audiodescription_episode_title": null, + "related_oegs_episode_image_url": null, + "related_oegs_episode_title": null, + "release_date": "2024-03-13T23:50:02+01:00", + "secondary_genres": [], + "segments_complete": true, + "episodes_reference": "", + "share_body": "https:\/\/tvthek.orf.at\/profile\/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan\/13896153\/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan-Bankeinbruch-in-Kalifornien\/14216629", + "share_subject": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien vom 13.03.2024 um 23:49 Uhr", + "show_display_ads": true, + "show_instream_ads": true, + "sources": { + "hls": [ + { + "is_uhd": false, + "quality_key": "QXADRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXA.mp4\/playlist.m3u8", + "is_adaptive_stream": true, + "is_drm_protected": true + }, + { + "is_uhd": false, + "quality_key": "QXBDRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXB.mp4\/playlist.m3u8", + "is_adaptive_stream": true, + "is_drm_protected": true + } + ], + "dash": [ + { + "is_uhd": false, + "quality_key": "QXADRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXA.mp4\/manifest.mpd", + "is_adaptive_stream": true, + "is_drm_protected": true + }, + { + "is_uhd": false, + "quality_key": "QXBDRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXB.mp4\/manifest.mpd", + "is_adaptive_stream": true, + "is_drm_protected": true + } + ] + }, + "sub_headline": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle", + "teaser_text": "In 'Bankeinbruch in Kalifornien' geht es um ein mit der Mafia in Verbindung stehendes Gangsterteam, das vom FBI als das 'beste aller Zeiten' bezeichnet worden ist.", + "teaser_title": "Bankeinbruch in Kalifornien", + "text": null, + "thumbnail_activated": true, + "thumbnail_distributed": false, + "thumbnail_folder": null, + "thumbnail_sources": { + "hls": [ + { + "quality_key": "Q6A", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q6A.mp4\/playlist.m3u8" + }, + { + "quality_key": "Q8C", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q8C.mp4\/playlist.m3u8" + } + ], + "dash": [ + { + "quality_key": "Q6A", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q6A.mp4\/manifest.mpd" + }, + { + "quality_key": "Q8C", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q8C.mp4\/manifest.mpd" + } + ] + }, + "sprite_sources": [], + "title": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien", + "type": "default", + "updated_at": "2024-03-26T12:16:53+01:00", + "video_type": "episode", + "youth_protection_type": "limited-20-06", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629" + }, + "channel": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/channel\/1180" + }, + "profile": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153" + }, + "segments": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629\/segments" + }, + "tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629\/tags" + }, + "advertising_tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629\/advertising\/tags" + }, + "links": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629\/links" + }, + "image": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16997261" + }, + "image16x9_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16997261" + }, + "image2x3_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17003265" + }, + "image2x3": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16596204" + }, + "subtitle": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/subtitle\/914030" + }, + "related_episodes": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629\/related" + }, + "dds_item": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/dds\/ddsitem\/393293" + } + }, + "_embedded": { + "channel": { + "bitmovin_stream_id": "f9a36691-7bd7-4c36-9009-a0b9d7009b29", + "channel_restart_url_hbbtv": "https:\/\/playerapi-restarttv.ors.at\/livestreams\/f9a36691-7bd7-4c36-9009-a0b9d7009b29\/sections\/?state=active&X-Api-Key=66ae5065a94f40f9b00f7de4a9f96ead", + "id": 1180, + "is_drm_protected": true, + "is_main_channel": true, + "name": "ORF 1", + "reel": "orf1", + "updated_at": "2024-02-28T16:06:34+01:00", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/channel\/1180" + }, + "children": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/channel\/1180\/children" + }, + "color_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/13457917" + }, + "black_and_white_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/13457918" + }, + "audio_description_channel": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/channel\/4391789" + } + }, + "_embedded": { + "parent": null, + "color_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "tiny": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/thumb_13457917_channels_tiny.png" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/thumb_13457917_channels_list.png" + }, + "schedule": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/thumb_13457917_channels_schedule.png" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/e88267e73205e46affb97e99d34f715f74bd1f1b.png" + } + } + }, + "black_and_white_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "tiny": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/thumb_13457918_channels_tiny.png" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/thumb_13457918_channels_list.png" + }, + "schedule": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/thumb_13457918_channels_schedule.png" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/channels\/0135\/58\/b1b2c5b46edc8fdb3781957de434fbeeed4e8e44.png" + } + } + } + } + }, + "profile": { + "audio_description": false, + "break_text": null, + "break_title": null, + "dataset_name": "", + "dds_identifier": "", + "description": "Spannende Krimi-Doku-Reihe", + "has_active_youth_protection": false, + "has_youth_protection": false, + "headline": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan", + "hide_in_letter_group": false, + "id": 13896153, + "letter_group": "S", + "livestream_sub_headline": null, + "oegs": false, + "oewa_base_path": "Redcont\/Nachrichten\/Chronik", + "profile_website": null, + "secondary_genres": [], + "sub_headline": null, + "title": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan", + "type": "temporary", + "updated_at": "2024-03-13T09:51:58+01:00", + "youth_protection_type": "limited-20-06", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153" + }, + "image": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16991314" + }, + "image16x9_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16991314" + }, + "image2x3_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17003265" + }, + "image2x3": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16596204" + }, + "genre": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173" + }, + "links": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/links" + }, + "episodes": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/episodes" + }, + "related_profiles": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/related" + }, + "latest_episode": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/episode\/latest" + }, + "tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/tags" + }, + "advertising_tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/advertising\/tags" + } + }, + "_embedded": { + "image": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/c3bbfbb314b936589dd9c5804ac283641a050a83.jpeg" + } + } + }, + "image16x9_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/c3bbfbb314b936589dd9c5804ac283641a050a83.jpeg" + } + } + }, + "image2x3_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/87d0d07cfb0f7cc83377df1a7ce7b28b9af8d976.jpeg" + } + } + }, + "image2x3": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_player.jpeg" + }, + "legacy": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_legacy.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/56745f92b28e3a6f176e66acf9e9d0aea5e0c611.jpeg" + } + } + }, + "theme": null, + "genre": { + "id": 1173, + "advertising_mapping": { + "live": { + "web": { + "sb": 4716830, + "tbar": 4420052, + "pre": 4420053, + "post": 4420054 + }, + "mob": { + "par": 4420055, + "pre": 4420220, + "post": 4420057 + }, + "app": { + "par": 4420058, + "pre": 4420059, + "post": 4420060 + }, + "smart": { + "pre": 4420061, + "post": 4420062 + } + }, + "vod": { + "web": { + "sb": 4420426, + "tbar": 4420427, + "pre": 4420428, + "post": 4420429 + }, + "mob": { + "par": 4420430, + "pre": 4420431, + "post": 4420432 + }, + "app": { + "par": 4420433, + "pre": 4420434, + "post": 4420435 + }, + "smart": { + "pre": 4420436, + "post": 4420437 + } + } + }, + "sorting": 7, + "title": "Doku & Reportage", + "updated_at": "2023-12-31T16:37:59+01:00", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173" + }, + "image": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16596302" + }, + "profiles": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/profiles" + }, + "episodes": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/episodes" + }, + "latest_episode": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/episode\/latest" + }, + "tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/tags" + }, + "advertising_tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/advertising\/tags" + } + }, + "_embedded": { + "image": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/a6885e2f8ea6f778dcac9af57dfea24006218d76.jpeg" + } + } + }, + "tags": [], + "advertising_tags": [] + } + }, + "links": [], + "tags": [], + "advertising_tags": [], + "audio_description_profile": null, + "oegs_profile": null + } + }, + "segments": [ + { + "adition_advertising_query_string": "stype:vod,scat:doku-reportage,scatid:1173,spro:spektakulaere-raubueberfaelle-mit-pierce-brosnan,sproid:13896153,episodeid:14216629,duration:2446000,advertisingtags:", + "advertising_mapping": { + "live": { + "web": { + "sb": 4716830, + "tbar": 4420052, + "pre": 4420053, + "post": 4420054 + }, + "mob": { + "par": 4420055, + "pre": 4420220, + "post": 4420057 + }, + "app": { + "par": 4420058, + "pre": 4420059, + "post": 4420060 + }, + "smart": { + "pre": 4420061, + "post": 4420062 + } + }, + "vod": { + "web": { + "sb": 4420426, + "tbar": 4420427, + "pre": 4420428, + "post": 4420429 + }, + "mob": { + "par": 4420430, + "pre": 4420431, + "post": 4420432 + }, + "app": { + "par": 4420433, + "pre": 4420434, + "post": 4420435 + }, + "smart": { + "pre": 4420436, + "post": 4420437 + } + } + }, + "advertising_query_string": "stype=vod&scat=doku-reportage&scatid=1173&spro=spektakulaere-raubueberfaelle-mit-pierce-brosnan&sproid=13896153&episodeid=14216629&duration=2446000&advertisingtags=", + "blackfades": [], + "episode_date": "2024-03-13T23:49:50+01:00", + "date_as_string": "Mi, 13.3.2024", + "vod_ressort": null, + "description": "Pierce Brosnan pr\u00e4sentiert in der spannenden Krimi-Doku-Reihe die spektakul\u00e4rsten Raub\u00fcberf\u00e4lle der Geschichte.\r\nIn 'Bankeinbruch in Kalifornien' geht es um ein mit der Mafia in Verbindung stehendes Gangsterteam, das vom FBI als das 'beste aller Zeiten' bezeichnet worden ist. 1972 erbeutete die Bande bei dem \u00dcberfall auf eine s\u00fcdkalifornischen Bank, die angeblich Pr\u00e4sident Richard Nixons Wahlkampfgelder eingebunkert hatte, gesch\u00e4tzte 30 Millionen Dollar in bar.\r\nMit Pierce Brosnan\r\nRegie: Brendan Murphy, Kieran Murphy", + "drm_token": "uZH9yZK791mApoQnhaOQPR4H7wCXwjWvlsj2KR7P65Dw6X3SEiO6j376a3lpxNs4HHzLwDx3f5PsLuJmLiifVufJB%2FNCA0k3WpOy%2FbBEBReWp4E3IfVFPVmjbjCAAtB6wpR3K5xQ%2FtNZaRGDUQh%2BQnDkst6PJMzSLg7vpvpu5pnMFCzUPe5OP1ST%2BdrEMVwGC%2Fs%2BpmeM0Vvdd1293uywOu7gdQDh9bl7zxFd4E%2BJYHxO4sX%2FdKYJOIB63rVL3nKG", + "duration_as_string": "40:46 Min.", + "duration_seconds": 2446, + "enabled": true, + "encrypted_id": "ODc4M2hqZDcyOTNrbWQxNTU5NTk5MA==", + "episode_id": 14216629, + "exact_duration": 2446000, + "genre_id": 1173, + "genre_title": "Doku & Reportage", + "right": "austria", + "focus": false, + "show_countdown": true, + "has_thumbnail": true, + "headline": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien", + "id": 15595990, + "is_archive": false, + "is_drm_protected": true, + "jump_mark": false, + "jump_marks": [], + "killdate_extern": "2027-01-31T00:00:00+01:00", + "killdate": "2027-01-31T00:00:00+01:00", + "livedate": "2024-03-13T23:50:00+01:00", + "livedate_extern": "2024-03-13T23:50:00+01:00", + "SSA": { + "cliptype": "Sendung", + "videoid": 15595990, + "videopartid": "1_1", + "videocategory": "Doku-Reportage", + "videotitle": "Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan-Bankeinbruch-in-Kalifornien", + "videoduration": 2446, + "episodeduration": 2446, + "episodeid": 14216629, + "airdate": "2024-03-13T23:50:00+01:00", + "clipreleasetime": "2024-03-13T23:50:02+01:00", + "programname": "Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan", + "channel": "orf1" + }, + "disable_display_ads_orf_platforms": false, + "disable_instream_ads_orf_platforms": false, + "position": 0, + "episodes_reference": "", + "share_body": "https:\/\/tvthek.orf.at\/profile\/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan\/13896153\/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan-Bankeinbruch-in-Kalifornien\/14216629\/Spektakulaere-Raubueberfaelle-mit-Pierce-Brosnan-Bankeinbruch-in-Kalifornien\/15595990", + "share_subject": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien - Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien vom 13.03.2024 um 23:49 Uhr", + "show_display_ads": true, + "show_instream_ads": true, + "sources": { + "hls": [ + { + "is_uhd": false, + "quality_key": "QXADRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXA.mp4\/playlist.m3u8", + "is_adaptive_stream": true, + "is_drm_protected": true + }, + { + "is_uhd": false, + "quality_key": "QXBDRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXB.mp4\/playlist.m3u8", + "is_adaptive_stream": true, + "is_drm_protected": true + } + ], + "dash": [ + { + "is_uhd": false, + "quality_key": "QXADRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXA.mp4\/manifest.mpd", + "is_adaptive_stream": true, + "is_drm_protected": true + }, + { + "is_uhd": false, + "quality_key": "QXBDRM", + "quality_description": "Adaptiv", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-austria\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_QXB.mp4\/manifest.mpd", + "is_adaptive_stream": true, + "is_drm_protected": true + } + ] + }, + "state": "distributed", + "sub_headline": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle", + "teaser_text": null, + "teaser_title": null, + "thumbnail_activated": true, + "thumbnail_distributed": true, + "thumbnail_folder": "cms-preview-clips", + "thumbnail_sources": { + "hls": [ + { + "quality_key": "Q6A", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q6A.mp4\/playlist.m3u8" + }, + { + "quality_key": "Q8C", + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q8C.mp4\/playlist.m3u8" + } + ], + "dash": [ + { + "quality_key": "Q6A", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q6A.mp4\/manifest.mpd" + }, + { + "quality_key": "Q8C", + "src": "https:\/\/apasfiis.sf.apa.at\/dash\/cms-preview-clips\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_clip_Q8C.mp4\/manifest.mpd" + } + ] + }, + "sprite_sources": [], + "title": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien", + "updated_at": "2024-03-14T00:42:13+01:00", + "videobumper": { + "prevideobumper": { + "active": false, + "sources": { + "hls": [], + "progressive_download": [] + } + }, + "postvideobumper": { + "active": false, + "sources": { + "hls": [], + "progressive_download": [] + } + } + }, + "video_file_name": "2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990", + "video_stream_url": null, + "video_type": "segment", + "voez": false, + "voez_ads_allowed": false, + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/segment\/15595990" + }, + "episode": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/episode\/14216629" + }, + "image": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16997261" + }, + "image16x9_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16997261" + }, + "image2x3_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17003265" + }, + "image2x3": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16596204" + }, + "links": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/segment\/15595990\/links" + }, + "subtitle": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/subtitle\/914031" + }, + "playlist": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/segment\/15595990\/playlist" + }, + "tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/segment\/15595990\/tags" + }, + "profile": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153" + } + }, + "_embedded": { + "image": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/2f1988137f18f84c8b23e3ad02f90f94aec642ef.jpeg" + } + } + }, + "image16x9_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/2f1988137f18f84c8b23e3ad02f90f94aec642ef.jpeg" + } + } + }, + "image2x3_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/87d0d07cfb0f7cc83377df1a7ce7b28b9af8d976.jpeg" + } + } + }, + "image2x3": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_player.jpeg" + }, + "legacy": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_legacy.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/56745f92b28e3a6f176e66acf9e9d0aea5e0c611.jpeg" + } + } + }, + "links": [], + "subtitle": { + "id": 914031, + "parsed_at": null, + "sami_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/fe7a33b4649d309b64a8533e0d042d2adcc1b3db.smi", + "srt_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/9cf923418cdda3395e4ab20fa7cab0514b0425a2.srt", + "stl_url": null, + "ttml_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/bae4fee3721136bf92ead4eaea19c2ac368531fe.ttml", + "updated_at": "2024-03-14T00:45:14+01:00", + "vtt_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/6b6430a64f134d6fb118efe6c32310c038b6448f.vtt", + "xml_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/6936fd90f903a4ae5a58ed5380306de0edce8e1e.xml", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/subtitle\/914031" + }, + "xml_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014318" + }, + "srt_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014319" + }, + "vtt_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014320" + }, + "sami_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014322" + }, + "ttml_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014321" + } + }, + "_embedded": { + "xml_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/6936fd90f903a4ae5a58ed5380306de0edce8e1e.xml" + } + } + }, + "stl_file": null, + "srt_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/9cf923418cdda3395e4ab20fa7cab0514b0425a2.srt" + } + } + }, + "vtt_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/6b6430a64f134d6fb118efe6c32310c038b6448f.vtt" + } + } + }, + "sami_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/fe7a33b4649d309b64a8533e0d042d2adcc1b3db.smi" + } + } + }, + "ttml_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/bae4fee3721136bf92ead4eaea19c2ac368531fe.ttml" + } + } + } + } + }, + "playlist": { + "id": 15595990, + "episode_id": 14216629, + "title_prefix": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien", + "title_separator": "|", + "title": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan: Bankeinbruch in Kalifornien", + "description": "Pierce Brosnan pr\u00e4sentiert in der spannenden Krimi-Doku-Reihe die spektakul\u00e4rsten Raub\u00fcberf\u00e4lle der Geschichte.\r\nIn 'Bankeinbruch in Kalifornien' geht es um ein mit der Mafia in Verbindung stehendes Gangsterteam, das vom FBI als das 'beste aller Zeiten' bezeichnet worden ist. 1972 erbeutete die Bande bei dem \u00dcberfall auf eine s\u00fcdkalifornischen Bank, die angeblich Pr\u00e4sident Richard Nixons Wahlkampfgelder eingebunkert hatte, gesch\u00e4tzte 30 Millionen Dollar in bar.\r\nMit Pierce Brosnan\r\nRegie: Brendan Murphy, Kieran Murphy", + "duration": 2446000, + "preview_image_url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_player.jpeg", + "sources": [ + { + "quality": "Q1A", + "quality_string": "Niedrig", + "src": "rtmp:\/\/apasfw.apa.at\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q1A.3gp", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtmp" + }, + { + "quality": "Q4A", + "quality_string": "Mittel", + "src": "rtmp:\/\/apasfw.apa.at\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q4A.mp4", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtmp" + }, + { + "quality": "Q6A", + "quality_string": "Hoch", + "src": "rtmp:\/\/apasfw.apa.at\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q6A.mp4", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtmp" + }, + { + "quality": "Q8C", + "quality_string": "Sehr hoch", + "src": "rtmp:\/\/apasfw.apa.at\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q8C.mp4", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtmp" + }, + { + "quality": "Q1A", + "quality_string": "Niedrig", + "src": "rtsp:\/\/apasfw.apa.at:1935\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q1A.3gp", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtsp" + }, + { + "quality": "SMIL", + "quality_string": "Hoch", + "src": "rtsp:\/\/apasfw.apa.at:1935\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q6A.mp4", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtsp" + }, + { + "quality": "Q4A", + "quality_string": "Mittel", + "src": "rtsp:\/\/apasfw.apa.at:1935\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q4A.mp4", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtsp" + }, + { + "quality": "Q8C", + "quality_string": "Sehr hoch", + "src": "rtsp:\/\/apasfw.apa.at:1935\/cms-austria\/mp4:2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q8C.mp4", + "type": "video\/mp4", + "delivery": "streaming", + "protocol": "rtsp" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "Q0A", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "Q1A", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "Q4A", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "Q6A", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "Q8C", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "QXA", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "src": "https:\/\/apasfiis.sf.apa.at\/ipad\/gp\/no_drm_support_q6a.mp4\/playlist.m3u8", + "is_uhd": false, + "quality": "QXB", + "quality_string": "Kein DRM", + "delivery": "hls", + "type": "video\/mp4", + "protocol": "http" + }, + { + "quality": "Q1A", + "quality_string": "Niedrig", + "src": "https:\/\/localhost:6666\/cms-austria\/online\/440102b9f68434fbb577d17114dd9182\/1713132000\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q1A.3gp", + "type": "video\/mp4", + "delivery": "progressive", + "protocol": "http" + }, + { + "quality": "Q4A", + "quality_string": "Mittel", + "src": "https:\/\/localhost:6666\/cms-austria\/online\/a96476a0eab40b11ef517feefe0d2973\/1713132000\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q4A.mp4", + "type": "video\/mp4", + "delivery": "progressive", + "protocol": "http" + }, + { + "quality": "Q6A", + "quality_string": "Hoch", + "src": "https:\/\/localhost:6666\/cms-austria\/online\/de9bd8775f46ea293a9db4b0711d4de5\/1713132000\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q6A.mp4", + "type": "video\/mp4", + "delivery": "progressive", + "protocol": "http" + }, + { + "quality": "Q8C", + "quality_string": "Sehr hoch", + "src": "https:\/\/localhost:6666\/cms-austria\/online\/6b2d672267c81e196472b564abf8c8fe\/1713132000\/2024-03-13_2349_in_01_Spektakulaere-R_____14216629__o__1333685799__s15595990_Q8C.mp4", + "type": "video\/mp4", + "delivery": "progressive", + "protocol": "http" + } + ], + "position": 0, + "last_segment": true, + "subtitles": [ + { + "src": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/6936fd90f903a4ae5a58ed5380306de0edce8e1e.xml", + "type": "xml", + "lang": "de-AT" + }, + { + "src": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/9cf923418cdda3395e4ab20fa7cab0514b0425a2.srt", + "type": "srt", + "lang": "de-AT" + }, + { + "src": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/6b6430a64f134d6fb118efe6c32310c038b6448f.vtt", + "type": "vtt", + "lang": "de-AT" + }, + { + "src": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/fe7a33b4649d309b64a8533e0d042d2adcc1b3db.smi", + "type": "sami", + "lang": "de-AT" + }, + { + "src": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/bae4fee3721136bf92ead4eaea19c2ac368531fe.ttml", + "type": "ttml", + "lang": "de-AT" + } + ], + "right": "austria", + "is_enabled": true, + "has_active_youthprotection": false, + "pre_bumper": { + "active": false, + "sources": [] + }, + "post_bumper": { + "active": false, + "sources": [] + }, + "hash": "9368c341ed83453303634fbd0f913f90" + }, + "tags": [], + "profile": { + "audio_description": false, + "break_text": null, + "break_title": null, + "dataset_name": "", + "dds_identifier": "", + "description": "Spannende Krimi-Doku-Reihe", + "has_active_youth_protection": false, + "has_youth_protection": false, + "headline": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan", + "hide_in_letter_group": false, + "id": 13896153, + "letter_group": "S", + "livestream_sub_headline": null, + "oegs": false, + "oewa_base_path": "Redcont\/Nachrichten\/Chronik", + "profile_website": null, + "secondary_genres": [], + "sub_headline": null, + "title": "Spektakul\u00e4re Raub\u00fcberf\u00e4lle mit Pierce Brosnan", + "type": "temporary", + "updated_at": "2024-03-13T09:51:58+01:00", + "youth_protection_type": "limited-20-06", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153" + }, + "image": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16991314" + }, + "image16x9_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16991314" + }, + "image2x3_with_logo": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17003265" + }, + "image2x3": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16596204" + }, + "genre": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173" + }, + "links": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/links" + }, + "episodes": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/episodes" + }, + "related_profiles": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/related" + }, + "latest_episode": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/episode\/latest" + }, + "tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/tags" + }, + "advertising_tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/profile\/13896153\/advertising\/tags" + } + }, + "_embedded": { + "image": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/c3bbfbb314b936589dd9c5804ac283641a050a83.jpeg" + } + } + }, + "image16x9_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/thumb_16991314_profiles_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profiles\/0170\/92\/c3bbfbb314b936589dd9c5804ac283641a050a83.jpeg" + } + } + }, + "image2x3_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/87d0d07cfb0f7cc83377df1a7ce7b28b9af8d976.jpeg" + } + } + }, + "image2x3": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_player.jpeg" + }, + "legacy": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_legacy.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/56745f92b28e3a6f176e66acf9e9d0aea5e0c611.jpeg" + } + } + }, + "theme": null, + "genre": { + "id": 1173, + "advertising_mapping": { + "live": { + "web": { + "sb": 4716830, + "tbar": 4420052, + "pre": 4420053, + "post": 4420054 + }, + "mob": { + "par": 4420055, + "pre": 4420220, + "post": 4420057 + }, + "app": { + "par": 4420058, + "pre": 4420059, + "post": 4420060 + }, + "smart": { + "pre": 4420061, + "post": 4420062 + } + }, + "vod": { + "web": { + "sb": 4420426, + "tbar": 4420427, + "pre": 4420428, + "post": 4420429 + }, + "mob": { + "par": 4420430, + "pre": 4420431, + "post": 4420432 + }, + "app": { + "par": 4420433, + "pre": 4420434, + "post": 4420435 + }, + "smart": { + "pre": 4420436, + "post": 4420437 + } + } + }, + "sorting": 7, + "title": "Doku & Reportage", + "updated_at": "2023-12-31T16:37:59+01:00", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173" + }, + "image": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/16596302" + }, + "profiles": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/profiles" + }, + "episodes": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/episodes" + }, + "latest_episode": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/episode\/latest" + }, + "tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/tags" + }, + "advertising_tags": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/genre\/1173\/advertising\/tags" + } + }, + "_embedded": { + "image": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/thumb_16596302_genres_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/genres\/0166\/97\/a6885e2f8ea6f778dcac9af57dfea24006218d76.jpeg" + } + } + }, + "tags": [], + "advertising_tags": [] + } + }, + "links": [], + "tags": [], + "advertising_tags": [], + "audio_description_profile": null, + "oegs_profile": null + } + } + } + } + ], + "tags": [], + "advertising_tags": [], + "links": [], + "audio_description_episode": null, + "oegs_episode": null, + "image": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/2f1988137f18f84c8b23e3ad02f90f94aec642ef.jpeg" + } + } + }, + "image16x9_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/thumb_16997261_segments_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/segments\/0170\/98\/2f1988137f18f84c8b23e3ad02f90f94aec642ef.jpeg" + } + } + }, + "image2x3_with_logo": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_player.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/thumb_17003265_profile_2x3-with-logo_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/profile_2x3-with-logo\/0171\/04\/87d0d07cfb0f7cc83377df1a7ce7b28b9af8d976.jpeg" + } + } + }, + "image2x3": { + "dynamic_color": "#691f11", + "public_urls": { + "highlight_teaser": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_highlight_teaser.jpeg" + }, + "player": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_player.jpeg" + }, + "legacy": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_legacy.jpeg" + }, + "list": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_list.jpeg" + }, + "small": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/thumb_16596204_default_2x3_small.jpeg" + }, + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/default_2x3\/0166\/97\/56745f92b28e3a6f176e66acf9e9d0aea5e0c611.jpeg" + } + } + }, + "subtitle": { + "id": 914030, + "parsed_at": null, + "sami_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/e83f6eabbdbcf49e894d1a58d77fcf3a9b951f3c.smi", + "srt_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/e2536ac2b80a5152e54b047073ab327c223579ec.srt", + "stl_url": null, + "ttml_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/c95472a931fe3ea8407734f95df242bce2f06b09.ttml", + "updated_at": "2024-03-14T00:45:14+01:00", + "vtt_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/13759cf0d408fe11965ff16d03a564bbabbf5bc1.vtt", + "xml_url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/be922c3765a25ec3d7fa13e9265dabad7f986b75.xml", + "_links": { + "self": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/subtitle\/914030" + }, + "xml_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014313" + }, + "srt_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014314" + }, + "vtt_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014315" + }, + "sami_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014317" + }, + "ttml_file": { + "href": "https:\/\/api-tvthek.orf.at\/api\/v4.3\/media\/17014316" + } + }, + "_embedded": { + "xml_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/be922c3765a25ec3d7fa13e9265dabad7f986b75.xml" + } + } + }, + "stl_file": null, + "srt_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/e2536ac2b80a5152e54b047073ab327c223579ec.srt" + } + } + }, + "vtt_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/13759cf0d408fe11965ff16d03a564bbabbf5bc1.vtt" + } + } + }, + "sami_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/e83f6eabbdbcf49e894d1a58d77fcf3a9b951f3c.smi" + } + } + }, + "ttml_file": { + "public_urls": { + "reference": { + "url": "https:\/\/api-tvthek.orf.at\/assets\/subtitles\/0171\/15\/c95472a931fe3ea8407734f95df242bce2f06b09.ttml" + } + } + } + } + } + }, + "accompanying_videos": [] +} \ No newline at end of file