diff --git a/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializer.java b/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializer.java index 8b16c3611..16b34ebe5 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializer.java +++ b/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializer.java @@ -223,19 +223,23 @@ public List deserialize( ArdVideoInfoDto allVideoUrlsOV = new ArdVideoInfoDto(); allVideoUrlsOV.putAll(videoInfo.get().getVideoUrlsOV()); allVideoUrlsOV.setSubtitleUrl(videoInfo.get().getSubtitleUrl()); - final ArdFilmDto filmDtoOV = - new ArdFilmDto( - createFilm( - id.get(), - sender, - topic.get(), - title.get() + " (Originalversion)", - description.orElse(null), - date.orElse(null), - duration.orElse(null), - allVideoUrlsOV, - geoBlocked)); - films.add(filmDtoOV); + allVideoUrlsOV.setOvLanguage(videoInfo.get().getOvLanguage()); + final Film filmOV = + createFilm( + id.get(), + sender, + topic.get(), + title.get() + " (Originalversion)", + description.orElse(null), + date.orElse(null), + duration.orElse(null), + allVideoUrlsOV, + geoBlocked); + // Nur die Originalfassung traegt die Sprache. Die Hauptfassung bleibt leer: sie ist die + // uebliche Fassung des Senders, und ein Wert auf jedem Datensatz wuerde die Filmliste + // unnoetig aufblaehen. + filmOV.setAudioLanguage(videoInfo.get().getOvLanguage()); + films.add(new ArdFilmDto(filmOV)); } return films; @@ -430,15 +434,26 @@ private Optional parseVideos(final JsonObject playerPageObject, if (videoInfoOV.isEmpty() && videoInfoOVAdaptive.isPresent()) { videoInfoOV = getResolutionsFromAdaptiveUrl(videoInfoOVAdaptive); } + // Die Sprache ist hier bekannt - die Streams wurden oben getrennt nach "eng" und "fra" + // eingelesen. Bisher ging sie beim Zusammenfassen zur Originalversion verloren, sodass im + // Ergebnis nur noch der Titelzusatz "(Originalversion)" ohne Sprachangabe stand. + String ovLanguage = null; if (videoInfoOV.isEmpty() && videoInfoEng.isPresent()) { videoInfoOV = videoInfoEng; + ovLanguage = MARKER_VIDEO_ENG; } if (videoInfoOV.isEmpty() && videoInfoFra.isPresent()) { videoInfoOV = videoInfoFra; + ovLanguage = MARKER_VIDEO_FRA; } // flaws - missing proper video marker - mainly tagesschau if ((title.contains(" - (Originalversion)") || title.contains(" (OV)")) && videoInfoOV.isEmpty()) { videoInfoOV = parseVideoUrls(playerPageObject, MARKER_VIDEO_CATEGORY_MAIN, MARKER_VIDEO_STANDARD, MARKER_VIDEO_MP4, "*"); + // Dieser Zweig faengt jede Sprache ab, nicht nur die oben durchprobierten "eng" und "fra". + // Der Code wird deshalb aus den Daten gelesen statt aus dem zutreffenden Filter abgeleitet. + if (videoInfoOV.isPresent()) { + ovLanguage = parseAudioLanguageCode(playerPageObject, MARKER_VIDEO_CATEGORY_MAIN, MARKER_VIDEO_STANDARD, MARKER_VIDEO_MP4, "*").orElse(null); + } } if ((title.contains(" (mit Gebärdensprache)") || title.contains(" mit Gebärdensprache")) && videoInfoStandard.isPresent() && videoInfoDGS.isEmpty()) { videoInfoDGS = videoInfoStandard; @@ -454,6 +469,7 @@ private Optional parseVideos(final JsonObject playerPageObject, videoInfoDGS.ifPresent(allVideoUrls::putAllDGS); videoInfoOVAdaptive.ifPresent(x -> allVideoUrls.setAdaptivUrl(x.entrySet().stream().findFirst().get().getValue())); videoInfoOV.ifPresent(allVideoUrls::putAllOV); + allVideoUrls.setOvLanguage(ovLanguage); subtitles.ifPresent(allVideoUrls::setSubtitleUrl); if (allVideoUrls.getVideoUrls().isEmpty() && allVideoUrls.getVideoUrlsAD().isEmpty() && allVideoUrls.getVideoUrlsDGS().isEmpty() && allVideoUrls.getVideoUrlsOV().isEmpty() ) { @@ -559,4 +575,82 @@ private Optional> parseVideoUrlMap(final JsonObject playerP } return Optional.of(videoInfo); } + + /** + * Liefert den tatsaechlichen Sprachcode ({@code audio[0].languageCode}) des ersten Streams, der + * zum uebergebenen Filter passt. + * + *

Die Auswahl der Streams oben probiert nur die fest verdrahteten Codes "deu", "eng" und "fra" + * durch. Eine Originalversion in einer anderen Sprache - spanisch, polnisch, tuerkisch - landet + * ueber den Platzhalter "*" trotzdem korrekt als Originalversion, ihre Sprache waere aber nicht + * bekannt. Statt sie aus dem zutreffenden Filter zu erraten, wird sie hier aus den Daten gelesen. + * + *

Die Platzhalter "OV" und "*" selbst benennen keine Sprache; ARDs eigener Platzhalter "ov" + * im Feld wird deshalb verworfen. + */ + private Optional parseAudioLanguageCode(final JsonObject playerPageObject, String streamType, String aduioType, String mimeType, String language) { + final Optional mediaCollectionObject = getMediaCollectionObject(playerPageObject); + if (mediaCollectionObject.isEmpty()) { + return Optional.empty(); + } + final Optional streams = JsonUtils.getElement(mediaCollectionObject.get(), ELEMENT_STREAMS); + if (streams.isEmpty() || !streams.get().isJsonArray() || streams.get().getAsJsonArray().isEmpty()) { + return Optional.empty(); + } + for (JsonElement streamsCategory : streams.get().getAsJsonArray()) { + final Optional streamKind = JsonUtils.getElementValueAsString(streamsCategory, ATTRIBUTE_KIND); + final Optional media = JsonUtils.getElement(streamsCategory, ELEMENT_MEDIA); + if (media.isEmpty() || !media.get().isJsonArray() || media.get().getAsJsonArray().isEmpty()) { + continue; + } + if (!streamKind.orElse("").equalsIgnoreCase(streamType)) { + continue; + } + for (JsonElement video : media.get().getAsJsonArray()) { + final Optional mime = JsonUtils.getElementValueAsString(video, ATTRIBUTE_MIME); + if (mime.isEmpty() || !mime.get().equalsIgnoreCase(mimeType)) { + continue; + } + final Optional audios = JsonUtils.getElement(video, ELEMENT_AUDIO); + if (audios.isEmpty() || !audios.get().isJsonArray() || audios.get().getAsJsonArray().isEmpty()) { + continue; + } + final Optional kind = JsonUtils.getElementValueAsString(audios.get().getAsJsonArray().get(0), ATTRIBUTE_KIND); + final Optional languageCode = JsonUtils.getElementValueAsString(audios.get().getAsJsonArray().get(0), ATTRIBUTE_ADUIO_LANG); + if (kind.isEmpty() || !kind.get().equalsIgnoreCase(aduioType)) { + continue; + } + final String code = languageCode.orElse(""); + final boolean matches = code.equalsIgnoreCase(language) + || (language.equalsIgnoreCase("*") && !code.equalsIgnoreCase(MARKER_VIDEO_DE) && !code.equalsIgnoreCase("ov")); + if (matches) { + final Optional normalized = normalizeLanguageCode(code); + if (normalized.isPresent()) { + return normalized; + } + } + } + } + return Optional.empty(); + } + + /** + * Bringt einen Sprachcode aus den Senderdaten in die Form, die das Feld zusichert: dreistelliger + * ISO-639-2/T-Code in Kleinschreibung. + * + *

Eine etwaige Regionsangabe wird abgeschnitten ("spa-ES" wird zu "spa"). Alles, was danach + * kein dreistelliger Buchstabencode ist - ARDs Platzhalter "ov", ein leerer Wert, ein + * zweistelliger Code, den MServer mangels Tabelle nicht zuordnen koennte - ergibt nichts. Lieber + * kein Wert als einer, auf den sich Clients nicht verlassen koennen. + */ + private static Optional normalizeLanguageCode(final String rawCode) { + if (rawCode == null || rawCode.isBlank()) { + return Optional.empty(); + } + final String primary = rawCode.trim().split("-")[0].toLowerCase(Locale.ROOT); + if (primary.length() != 3 || !primary.chars().allMatch(Character::isLetter)) { + return Optional.empty(); + } + return "ov".equals(primary) ? Optional.empty() : Optional.of(primary); + } } diff --git a/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdVideoInfoDto.java b/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdVideoInfoDto.java index 7da7b4d7b..1a8dfde54 100644 --- a/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdVideoInfoDto.java +++ b/src/main/java/de/mediathekview/mserver/crawler/ard/json/ArdVideoInfoDto.java @@ -21,6 +21,13 @@ public class ArdVideoInfoDto { private final Map videoUrlsDGS; private final Map videoUrlsOV; private String adaptivUrl = null; + + /** + * Sprache der Originalversion als ISO-639-2/T-Code, sofern bekannt. Die ARD liefert die Streams + * je Sprache getrennt aus ("eng", "fra"); bisher wurde diese Zuordnung beim Zusammenfassen zur + * Originalversion verworfen. + */ + private String ovLanguage = null; private Set subtitleUrl; @@ -134,6 +141,14 @@ public String getAdaptivUrl() { return adaptivUrl; } + public String getOvLanguage() { + return ovLanguage; + } + + public void setOvLanguage(String ovLanguage) { + this.ovLanguage = ovLanguage; + } + public void setAdaptivUrl(String adaptivUrl) { this.adaptivUrl = adaptivUrl; } diff --git a/src/main/java/de/mediathekview/mserver/daten/Film.java b/src/main/java/de/mediathekview/mserver/daten/Film.java index 911ef6697..37996ee13 100644 --- a/src/main/java/de/mediathekview/mserver/daten/Film.java +++ b/src/main/java/de/mediathekview/mserver/daten/Film.java @@ -14,6 +14,17 @@ public class Film extends Podcast { private Map audioDescriptions; private Map signLanguages; + /** + * Sprache der Tonspur dieses Films als ISO-639-2/T-Code ({@code "deu"}, {@code "eng"}, + * {@code "fra"}), oder {@code null}, wenn der Sender sie nicht benennt. + * + *

Relevant vor allem fuer Originalversionen: die werden bisher nur ueber den Titelzusatz + * "(Originalversion)" kenntlich gemacht, der die Sprache nicht nennt. Sie geht damit verloren, + * obwohl sie beim Crawlen teilweise vorliegt - der ARD-Crawler liest die Streams bereits getrennt + * nach "eng" und "fra" ein. + */ + private String audioLanguage; + public Film( final UUID aUuid, final Sender aSender, @@ -32,6 +43,7 @@ public Film(final Film copyObj) { audioDescriptions = copyObj.audioDescriptions; signLanguages = copyObj.signLanguages; subtitles = copyObj.subtitles; + audioLanguage = copyObj.audioLanguage; } /** DON'T USE! - ONLY FOR GSON! */ @@ -53,9 +65,25 @@ public AbstractMediaResource merge(final AbstractMediaResource || urlEntry.getValue().getFileSize() > getUrls().get(urlEntry.getKey()).getFileSize()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + // Beim Zusammenfuehren zweier Staende - etwa einer importierten aelteren Filmliste ohne das + // Feld und einem frischen Crawl - darf die einmal bekannte Sprache nicht verloren gehen. + if (audioLanguage == null && objToMergeWith instanceof Film filmToMergeWith) { + audioLanguage = filmToMergeWith.getAudioLanguage(); + } return this; } + /** + * @return Sprache der Tonspur als ISO-639-2/T-Code, oder {@code null} wenn unbekannt. + */ + public String getAudioLanguage() { + return audioLanguage; + } + + public void setAudioLanguage(final String aAudioLanguage) { + audioLanguage = aAudioLanguage; + } + public void addAllSubtitleUrls(final Set urlsToAdd) { subtitles.addAll(urlsToAdd); } diff --git a/src/main/java/de/mediathekview/mserver/filmlisten/reader/FilmlistOldFormatReader.java b/src/main/java/de/mediathekview/mserver/filmlisten/reader/FilmlistOldFormatReader.java index e9b457b73..778e7b7fe 100644 --- a/src/main/java/de/mediathekview/mserver/filmlisten/reader/FilmlistOldFormatReader.java +++ b/src/main/java/de/mediathekview/mserver/filmlisten/reader/FilmlistOldFormatReader.java @@ -155,8 +155,19 @@ private void headerColumns(JsonReader jsonReader) throws IOException { jsonReader.nextString(); // Url History jsonReader.nextString(); // Geo jsonReader.nextString(); // neu + readOptionalHeaderColumn(jsonReader); // Sprache jsonReader.endArray(); } + + /** + * Liest eine optionale, hinten angehaengte Spalte. Aeltere Filmlisten fuehren sie nicht, deshalb + * wird nur gelesen, wenn ueberhaupt noch ein Wert vor dem Array-Ende steht. + */ + private void readOptionalHeaderColumn(JsonReader jsonReader) throws IOException { + if (jsonReader.peek() == JsonToken.STRING) { + jsonReader.nextString(); + } + } private Optional readRecord(JsonReader jsonReader) throws IOException { cnt++; @@ -212,6 +223,13 @@ private Optional readRecord(JsonReader jsonReader) throws IOException { f.setGeoLocations(readRecord19Geo(jsonReader.nextString())); // f.setNeu(readRecord20Neu(jsonReader.nextString())); + // Hinten angehaengt und optional: Filmlisten aelterer MServer-Staende haben das Feld nicht. + if (jsonReader.peek() == JsonToken.STRING) { + final String sprache = jsonReader.nextString(); + if (!sprache.isEmpty()) { + f.setAudioLanguage(sprache); + } + } // jsonReader.endArray(); // diff --git a/src/main/java/de/mediathekview/mserver/filmlisten/writer/FilmlistOldFormatWriter.java b/src/main/java/de/mediathekview/mserver/filmlisten/writer/FilmlistOldFormatWriter.java index 192d30f7d..82ba29276 100644 --- a/src/main/java/de/mediathekview/mserver/filmlisten/writer/FilmlistOldFormatWriter.java +++ b/src/main/java/de/mediathekview/mserver/filmlisten/writer/FilmlistOldFormatWriter.java @@ -147,6 +147,10 @@ private void writeColumnHeader(JsonWriter jsonWriter) throws IOException { jsonWriter.value("Url History"); jsonWriter.value("Geo"); jsonWriter.value("neu"); + // Neue Felder werden HINTEN angefuegt: der Desktop-Client liest den Datensatz + // positionsbasiert und ueberspringt die Spaltenkopfzeile vollstaendig + // (FilmListReader.skipFieldDescriptions), ein angehaengtes Feld wird dort daher ignoriert. + jsonWriter.value("Sprache"); jsonWriter.endArray(); } @@ -172,9 +176,24 @@ private void writeRecord(AbstractMediaResource film, JsonWriter jsonWriter) t jsonWriter.value(""); // Url History jsonWriter.value(writeRecord19Geo(film)); jsonWriter.value(writeRecord20Neu(film)); + jsonWriter.value(writeRecord21Sprache(film)); jsonWriter.endArray(); } + /** + * Sprache der Tonspur als ISO-639-2/T-Code, leer wenn der Sender sie nicht benennt. + * + *

Bewusst ein einfacher String und kein Array: der Desktop-Client prueft beim Weiterlesen mit + * {@code isExpectedStartArrayToken()}, ob der naechste Token ein Datensatz ist. Ein angehaengtes + * Array wuerde dort als Filmdatensatz interpretiert. + */ + private String writeRecord21Sprache(AbstractMediaResource in) { + if (in instanceof Film film && film.getAudioLanguage() != null) { + return film.getAudioLanguage(); + } + return ""; + } + private String writeRecord01Sender(AbstractMediaResource in, String aSender) { if (!aSender.equalsIgnoreCase(in.getSenderName())) { this.sender = in.getSenderName(); diff --git a/src/test/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializerAudioLanguageTest.java b/src/test/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializerAudioLanguageTest.java new file mode 100644 index 000000000..838021b07 --- /dev/null +++ b/src/test/java/de/mediathekview/mserver/crawler/ard/json/ArdFilmDeserializerAudioLanguageTest.java @@ -0,0 +1,105 @@ +package de.mediathekview.mserver.crawler.ard.json; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import com.google.gson.JsonElement; +import de.mediathekview.mserver.base.config.MServerConfigManager; +import de.mediathekview.mserver.base.messages.listener.MessageListener; +import de.mediathekview.mserver.crawler.ard.ArdCrawler; +import de.mediathekview.mserver.crawler.ard.ArdFilmDto; +import de.mediathekview.mserver.daten.Film; +import de.mediathekview.mserver.progress.listeners.SenderProgressListener; +import de.mediathekview.mserver.testhelper.JsonFileReader; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ForkJoinPool; +import org.junit.jupiter.api.Test; + +/** + * Prueft, dass die Sprache der Originalversion aus den Daten gelesen wird und nicht nur fuer die + * beiden fest verdrahteten Codes "eng" und "fra" ankommt. + */ +class ArdFilmDeserializerAudioLanguageTest { + + @Test + void originalVersionInAnyLanguageKeepsItsLanguageCode() { + // Dieselbe Sendung wie ard_item_OV.json, aber die Originalversion ist als "spa" ausgezeichnet + // statt mit ARDs Platzhalter "ov". Weder die OV- noch die eng-/fra-Abfrage greift hier; der + // Treffer kommt ueber den Platzhalter "*", und die Sprache wird aus audio[0].languageCode + // gelesen. + final Film originalVersion = findOriginalVersion("/ard/ard_item_OV_spanish.json"); + + assertThat(originalVersion, notNullValue()); + assertThat(originalVersion.getAudioLanguage(), equalTo("spa")); + } + + @Test + void originalVersionWithoutNamedLanguageStaysUnset() { + // Gegenprobe mit dem unveraenderten Fixture: dort meldet die ARD nur ihren eigenen Platzhalter + // "ov", der keine Sprache benennt. Dann darf auch nichts gesetzt werden. + final Film originalVersion = findOriginalVersion("/ard/ard_item_OV.json"); + + assertThat(originalVersion, notNullValue()); + assertThat(originalVersion.getAudioLanguage(), nullValue()); + } + + + @Test + void standardVersionMustNotInheritTheOriginalVersionLanguage() { + // Regression: createFilm hat das Feld frueher unbedingt gesetzt und wird fuer beide Filme mit + // demselben ArdVideoInfoDto aufgerufen. Dadurch bekam die deutsche Hauptfassung die Sprache + // der Originalversion - bei einem Beitrag mit deutscher und englischer Tonspur also "eng". + final List alle = allFilms("/ard/ard_item_OV_eng_plus_deu.json"); + assertThat(alle.size(), equalTo(2)); + + final Film standard = + alle.stream().filter(f -> !f.getTitel().contains("(Originalversion)")).findFirst().orElse(null); + final Film originalVersion = + alle.stream().filter(f -> f.getTitel().contains("(Originalversion)")).findFirst().orElse(null); + + assertThat(standard, notNullValue()); + assertThat(originalVersion, notNullValue()); + assertThat(standard.getAudioLanguage(), nullValue()); + assertThat(originalVersion.getAudioLanguage(), equalTo("eng")); + } + + private List allFilms(final String jsonFile) { + final JsonElement jsonElement = JsonFileReader.readJson(jsonFile); + return new ArdFilmDeserializer(createCrawler()).deserialize(jsonElement, null, null).stream() + .map(ArdFilmDto::getFilm) + .toList(); + } + + @Test + void languageCodeWithRegionIsReducedToTheLanguage() { + // Sollte die ARD den Code je mit Regionsangabe liefern, muss trotzdem der reine + // ISO-639-2/T-Code im Feld stehen - "spa-ES" also als "spa". + final Film originalVersion = findOriginalVersion("/ard/ard_item_OV_spanish_region.json"); + + assertThat(originalVersion, notNullValue()); + assertThat(originalVersion.getAudioLanguage(), equalTo("spa")); + } + + private Film findOriginalVersion(final String jsonFile) { + final JsonElement jsonElement = JsonFileReader.readJson(jsonFile); + final List films = + new ArdFilmDeserializer(createCrawler()).deserialize(jsonElement, null, null); + + return films.stream() + .map(ArdFilmDto::getFilm) + .filter(film -> film.getTitel().contains("(Originalversion)")) + .findFirst() + .orElse(null); + } + + private ArdCrawler createCrawler() { + return new ArdCrawler( + new ForkJoinPool(), + new ArrayList(), + new ArrayList(), + new MServerConfigManager("MServer-JUnit-Config.yaml")); + } +} diff --git a/src/test/java/de/mediathekview/mserver/filmlisten/FilmlistOldFormatWriterTest.java b/src/test/java/de/mediathekview/mserver/filmlisten/FilmlistOldFormatWriterTest.java index 66ae9d558..9fb2edccf 100644 --- a/src/test/java/de/mediathekview/mserver/filmlisten/FilmlistOldFormatWriterTest.java +++ b/src/test/java/de/mediathekview/mserver/filmlisten/FilmlistOldFormatWriterTest.java @@ -1,6 +1,7 @@ package de.mediathekview.mserver.filmlisten; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import de.mediathekview.mserver.daten.Film; @@ -30,6 +31,84 @@ class FilmlistOldFormatWriterTest { @TempDir Path tempDir; + @Test + void audioLanguageSurvivesWriteAndRead() throws IOException { + // Kern des Ganzen: die Sprache muss den Weg durch das alte Format ueberstehen. Ohne das Feld + // bleibt von einer englischen Originalfassung nur der Titelzusatz "(Originalversion)" uebrig, + // der die Sprache nicht nennt. + final Filmlist input = new Filmlist(); + final Film withLanguage = buildMinimalFilm("Mit Sprache (Originalversion)"); + withLanguage.setAudioLanguage("eng"); + final Film withoutLanguage = buildMinimalFilm("Ohne Sprache"); + input.add(withLanguage); + input.add(withoutLanguage); + + final Filmlist afterRoundTrip = writeAndRead(input); + + assertEquals(2, afterRoundTrip.getFilms().size()); + final Film readWithLanguage = findByTitle(afterRoundTrip, "Mit Sprache (Originalversion)"); + final Film readWithoutLanguage = findByTitle(afterRoundTrip, "Ohne Sprache"); + assertEquals("eng", readWithLanguage.getAudioLanguage()); + // Kein Sender-Wert darf nicht als leerer String zurueckkommen, sondern gar nicht gesetzt sein. + assertNull(readWithoutLanguage.getAudioLanguage()); + } + + @Test + void filmlistWithoutLanguageColumnStillReads() throws IOException { + // Rueckwaertskompatibilitaet in die andere Richtung: eine Filmliste eines aelteren + // MServer-Standes fuehrt die Spalte nicht. Der Reader muss sie weiterhin lesen koennen. + final Path testFilePath = + new File( + Thread.currentThread() + .getContextClassLoader() + .getResource("mlib/TestFilmlistOldFormatWriter.json") + .getFile()) + .toPath(); + final String withColumn = Files.readString(testFilePath, StandardCharsets.UTF_8); + final String withoutColumn = withColumn.replace(",\"Sprache\"]", "]").replace(",\"\"]", "]"); + + final Path legacyFile = Files.createTempFile(tempDir, "LegacyFilmlist", ".json"); + Files.writeString(legacyFile, withoutColumn, StandardCharsets.UTF_8); + + final Optional read = + new FilmlistOldFormatReader().read(new FileInputStream(legacyFile.toString())); + + assertTrue(read.isPresent()); + assertTrue(read.get().getFilms().size() > 0); + read.get().getFilms().values().forEach(film -> assertNull(film.getAudioLanguage())); + } + + private Film buildMinimalFilm(final String titel) throws java.net.MalformedURLException { + final Film film = + new Film( + UUID.randomUUID(), + Sender.ARD, + titel, + "Testthema", + LocalDateTime.of(2026, 1, 1, 20, 15), + Duration.ofMinutes(90)); + film.addUrl(Resolution.NORMAL, new FilmUrl("https://example.org/v.mp4", 1L)); + film.addGeolocation(GeoLocations.GEO_NONE); + return film; + } + + private Filmlist writeAndRead(final Filmlist input) throws IOException { + final Path tempFile = Files.createTempFile(tempDir, "AudioLanguageRoundTrip", ".json"); + new FilmlistOldFormatWriter().write(input, tempFile); + final Optional read = + new FilmlistOldFormatReader().read(new FileInputStream(tempFile.toString())); + Files.deleteIfExists(tempFile); + assertTrue(read.isPresent()); + return read.get(); + } + + private Film findByTitle(final Filmlist list, final String titel) { + return list.getFilms().values().stream() + .filter(film -> titel.equals(film.getTitel())) + .findFirst() + .orElseThrow(); + } + @Test void readFilmlistOldFormatIncludingBrokenRecords() throws IOException { @@ -43,8 +122,11 @@ void readFilmlistOldFormatIncludingBrokenRecords() assertTrue( Files.exists(tempFile)); // - String actualData = Files.readString(tempFile, StandardCharsets.UTF_16).substring(100); - String expectedData = Files.readString(testFilePath, StandardCharsets.UTF_16).substring(100); + // FilmlistOldFormatWriter schreibt UTF-8 (OutputStreamWriter mit StandardCharsets.UTF_8). + // Das Einlesen als UTF-16 lief bisher nur deshalb durch, weil die Dateilaenge zufaellig + // gerade war; bei ungerader Byteanzahl wirft readString eine MalformedInputException. + String actualData = Files.readString(tempFile, StandardCharsets.UTF_8).substring(100); + String expectedData = Files.readString(testFilePath, StandardCharsets.UTF_8).substring(100); assertEquals(expectedData, actualData, "Filmlisten stimmen überein."); // Files.deleteIfExists(tempFile); diff --git a/src/test/java/de/mediathekview/mserver/filmlisten/NewFilmlistAudioLanguageTest.java b/src/test/java/de/mediathekview/mserver/filmlisten/NewFilmlistAudioLanguageTest.java new file mode 100644 index 000000000..6d0d34bae --- /dev/null +++ b/src/test/java/de/mediathekview/mserver/filmlisten/NewFilmlistAudioLanguageTest.java @@ -0,0 +1,93 @@ +package de.mediathekview.mserver.filmlisten; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import de.mediathekview.mserver.daten.Film; +import de.mediathekview.mserver.daten.FilmUrl; +import de.mediathekview.mserver.daten.Filmlist; +import de.mediathekview.mserver.daten.Resolution; +import de.mediathekview.mserver.daten.Sender; +import de.mediathekview.mserver.filmlisten.reader.FilmlistReader; +import de.mediathekview.mserver.filmlisten.writer.FilmlistWriter; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +/** Die Sprache muss auch durch das neue Format und ueber merge() hinweg erhalten bleiben. */ +class NewFilmlistAudioLanguageTest { + + @TempDir Path tempDir; + + @Test + void audioLanguageSurvivesTheNewFormat() throws IOException { + final Filmlist input = new Filmlist(); + final Film withLanguage = buildFilm("Mit Sprache (Originalversion)"); + withLanguage.setAudioLanguage("eng"); + input.add(withLanguage); + input.add(buildFilm("Ohne Sprache")); + + final Path tempFile = Files.createTempFile(tempDir, "NewFormatAudioLanguage", ".json"); + new FilmlistWriter().write(input, tempFile); + final Optional read = + new FilmlistReader().read(new FileInputStream(tempFile.toString())); + Files.deleteIfExists(tempFile); + + assertTrue(read.isPresent()); + assertEquals("eng", findByTitle(read.get(), "Mit Sprache (Originalversion)").getAudioLanguage()); + assertNull(findByTitle(read.get(), "Ohne Sprache").getAudioLanguage()); + } + + @Test + void mergeKeepsAKnownLanguage() throws MalformedURLException { + // Eine importierte aeltere Filmliste kennt das Feld nicht. Wird sie mit einem frischen Crawl + // zusammengefuehrt, darf die dort bekannte Sprache nicht verloren gehen. + final Film ausAelteremStand = buildFilm("Folge (Originalversion)"); + final Film ausFrischemCrawl = buildFilm("Folge (Originalversion)"); + ausFrischemCrawl.setAudioLanguage("fra"); + + ausAelteremStand.merge(ausFrischemCrawl); + + assertEquals("fra", ausAelteremStand.getAudioLanguage()); + } + + @Test + void mergeDoesNotOverwriteAnExistingLanguage() throws MalformedURLException { + final Film bekannt = buildFilm("Folge (Originalversion)"); + bekannt.setAudioLanguage("eng"); + final Film ohne = buildFilm("Folge (Originalversion)"); + + bekannt.merge(ohne); + + assertEquals("eng", bekannt.getAudioLanguage()); + } + + private Film buildFilm(final String titel) throws MalformedURLException { + final Film film = + new Film( + UUID.randomUUID(), + Sender.ARD, + titel, + "Testthema", + LocalDateTime.of(2026, 1, 1, 20, 15), + Duration.ofMinutes(90)); + film.addUrl(Resolution.NORMAL, new FilmUrl("https://example.org/v.mp4", 1L)); + return film; + } + + private Film findByTitle(final Filmlist list, final String titel) { + return list.getFilms().values().stream() + .filter(film -> titel.equals(film.getTitel())) + .findFirst() + .orElseThrow(); + } +} diff --git a/src/test/resources/ard/ard_item_OV_eng_plus_deu.json b/src/test/resources/ard/ard_item_OV_eng_plus_deu.json new file mode 100644 index 000000000..d8b8bb5ee --- /dev/null +++ b/src/test/resources/ard/ard_item_OV_eng_plus_deu.json @@ -0,0 +1,500 @@ +{ + "coreAssetType": "EXTRA_BONUS_CONTENT", + "fskRating": "FSK12", + "id": "player_ondemand-page-ard", + "isChildContent": false, + "personalized": false, + "links": { + "self": { + "id": "player_ondemand-page-ard", + "urlId": "player_ondemand-page-ard", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "href": "https://api.ardmediathek.de/page-gateway/pages/ard/item/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?embedded=true&mcV6=true", + "type": "application/vnd.ard.page+json", + "partner": "ard" + } + }, + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "tracking": { + "aggregationLevelId": 38, + "atiCustomVars": { + "clipTitle": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "mediaType": "video", + "lra": "ONE", + "channel": "ONE", + "show": "Murdoch Mysteries", + "contentTypes": "UT", + "mediaDistributionType": 1, + "contentId": 13320735, + "metadataId": "crid://wdr.de/Beitrag-sophora-ce0801f3-6223-4de2-87b3-61522db2d65b", + "clipLength": 2744 + }, + "chapter2": "Player", + "chapter3": "Murdoch Mysteries", + "environmentId": 511893, + "pageTitle": "Mediathek/Player/Murdoch Mysteries/Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)/13320735/20240424_2050", + "szmType": "CP" + }, + "trackingPiano": { + "page_chapter1": "Player", + "page_content_id": "urn:ard:publication:0c1dc4d2e066396c", + "page_content_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "page_id": "player_ondemand-page-ard", + "page_institution": "ONE", + "page_institution_id": "urn:ard:institution:9edd94d68de90140", + "page_publisher": "ONE", + "page_publisher_id": "urn:ard:publisher:892e3c758ca56a9d", + "page_show": "Murdoch Mysteries", + "page_show_id": "urn:ard:show:85088a146d3740b7", + "page_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "site": "634408" + }, + "widgets": [ + { + "availableTo": "2024-05-24T20:50:00Z", + "binaryFeatures": [ + "OV", + "UT" + ], + "blockedByFsk": false, + "broadcastedOn": "2024-04-24T20:50:00Z", + "embeddable": false, + "geoblocked": false, + "id": "Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi", + "image": { + "alt": "Detective Murdoch (Yannick Bisson) und Constable Crabtree (Jonny Harris)", + "producerName": "WDR", + "src": "https://api.ardmediathek.de/image-service/images/urn:ard:image:2a3352f634c1614c?w={width}&ch=ec0aa7bc7271383a", + "title": "Murdoch Mysteries (S04/E12) - OV" + }, + "isChildContent": false, + "maturityContentRating": "FSK12", + "mediaCollection": { + "embedded": { + "isGeoBlocked": true, + "meta": { + "availableToDateTime": "2024-05-24T20:50:00Z", + "broadcastedOnDateTime": "2024-04-24T20:50:00Z", + "clipSourceName": "ONE", + "durationSeconds": 2744, + "images": [ + { + "alt": "Detective Murdoch (Yannick Bisson) und Constable Crabtree (Jonny Harris)", + "aspectRatio": "16x9", + "imageSourceName": "WDR", + "kind": "preview", + "title": "Murdoch Mysteries (S04/E12) - OV", + "url": "https://api.ardmediathek.de/image-service/images/urn:ard:image:2a3352f634c1614c?w=960&ch=ec0aa7bc7271383a" + } + ], + "maturityContentRating": { + "age": 12, + "isBlocked": false, + "kind": "other" + }, + "publicationService": { + "id": "ard", + "name": "ONE", + "partner": "one" + }, + "synopsis": "Während sich Dr. Ogden auf ihre Hochzeit vorbereitet, muss Murdoch versuchen, den 'Küssenden Banditen' aufzuhalten, einen umstrittenen Bankräuber, der schnell zum Volkshelden aufsteigt.", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)" + }, + "pluginData": { + "recommendation@all": { + "isAutoplay": true, + "timerSeconds": 10, + "url": "https://api.ardmediathek.de/page-gateway/compilations/ard/recommendations?contextItemId=Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi" + }, + "trackingAgf@all": { + "appId": "PA02DC09C-B8D3-4098-87D2-2C023682D6D5", + "clipData": { + "assetid": "13320735", + "length": "2744", + "nol_c0": "p0,0", + "nol_c10": "p10,ONE", + "nol_c12": "p12,Content", + "nol_c15": "p15,POC_2002987622", + "nol_c16": "p16,", + "nol_c18": "p18,N", + "nol_c19": "p19,ONE", + "nol_c2": "p2,N", + "nol_c5": "p5,ARD Mediathek", + "nol_c7": "p7,crid://wdr.de/Beitrag-sophora-ce0801f3-6223-4de2-87b3-61522db2d65b", + "nol_c8": "p8,2744", + "nol_c9": "p9,Murdoch Mysteries_Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)_24.04.2024 20:50", + "program": "Murdoch Mysteries", + "title": "ONE_Murdoch Mysteries_Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)_24.04.2024 20:50", + "type": "content" + }, + "tracker": "AGF" + }, + "trackingAti@all": { + "config": { + "site": 511893 + }, + "isEnabled": true, + "richMedia": { + "broadcastMode": "clip", + "duration": "2744", + "mediaLabel": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)__13320735__OV | UT", + "mediaLevel2": "{richMediaLevelTwo}", + "mediaTheme1": "ONE", + "mediaTheme2": "ONE", + "mediaTheme3": "Murdoch Mysteries", + "mediaType": "video", + "playerId": "urn:ard:publication:0c1dc4d2e066396c", + "refreshDuration": { + "0": 5, + "1": 12, + "12": 15, + "18": 30 + } + }, + "tracker": "ATI" + }, + "trackingPiano@all": { + "avContent": { + "av_broadcasting_type": "OnDemand", + "av_content": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "av_content_duration": 2744000, + "av_content_id": "urn:ard:publication:0c1dc4d2e066396c", + "av_content_type": "video", + "av_institution": "ONE", + "av_institution_id": "urn:ard:institution:9edd94d68de90140", + "av_publisher": "ONE", + "av_publisher_id": "urn:ard:publisher:892e3c758ca56a9d", + "av_show": "Murdoch Mysteries", + "av_show_id": "urn:ard:show:85088a146d3740b7" + }, + "config": { + "events": [ + "av.error", + "av.speed", + "av.quality", + "av.jumpmark", + "av.share", + "av.playermode", + "av.subtitle", + "av.language", + "av.audiodescription", + "av.signlanguage", + "av.volume.mute", + "av.recommendation" + ], + "site": 634408 + }, + "isEnabled": true + } + }, + "streams": [ + { + "kind": "main", + "kindName": "Normal", + "media": [ + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "eng" + } + ], + "forcedLabel": "SD", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 640, + "maxVResolutionPx": 360, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016296.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "eng" + } + ], + "forcedLabel": "SD 480p", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 960, + "maxVResolutionPx": 540, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016297.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "eng" + } + ], + "forcedLabel": "Full HD", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1920, + "maxVResolutionPx": 1080, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016294.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "eng" + } + ], + "forcedLabel": "Auto", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1920, + "maxVResolutionPx": 1080, + "mimeType": "application/vnd.apple.mpegurl", + "subtitles": [], + "url": "https://wdradaptiv-vh.akamaihd.net/i/medp/ondemand/de/fsk12/310/3103788/,3103788_57016296,3103788_57016297,3103788_57016295,3103788_57016298,3103788_57016294,.mp4.csmil/master.m3u8", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "eng" + } + ], + "forcedLabel": "HD Ready", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1280, + "maxVResolutionPx": 720, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016298.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "deu" + } + ], + "forcedLabel": "SD", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 640, + "maxVResolutionPx": 360, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016296_deu.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "deu" + } + ], + "forcedLabel": "SD 480p", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 960, + "maxVResolutionPx": 540, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016297_deu.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "deu" + } + ], + "forcedLabel": "Full HD", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1920, + "maxVResolutionPx": 1080, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016294_deu.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "deu" + } + ], + "forcedLabel": "Auto", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1920, + "maxVResolutionPx": 1080, + "mimeType": "application/vnd.apple.mpegurl", + "subtitles": [], + "url": "https://wdradaptiv-vh.akamaihd.net/i/medp/ondemand/de/fsk12/310/3103788/,3103788_57016296,3103788_57016297,3103788_57016295,3103788_57016298,3103788_57016294,_deu.mp4.csmil/master.m3u8", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "deu" + } + ], + "forcedLabel": "HD Ready", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1280, + "maxVResolutionPx": 720, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016298_deu.mp4", + "videoCodec": "H.264" + } + ], + "videoLanguageCode": "" + } + ], + "subtitles": [ + { + "kind": "normal", + "languageCode": "deu", + "sources": [ + { + "kind": "ebutt", + "url": "https://api.ardmediathek.de/player-service/subtitle/ebutt/urn:ard:subtitle:d0e38dd26e6cc85e" + }, + { + "kind": "webvtt", + "url": "https://api.ardmediathek.de/player-service/subtitle/webvtt/urn:ard:subtitle:d0e38dd26e6cc85e.vtt" + } + ] + } + ] + }, + "href": "https://api.ardmediathek.de/page-gateway/mediacollectionv6/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?isTv=false" + }, + "pagination": null, + "personalized": false, + "playerConfig": null, + "publicationService": { + "name": "ONE", + "logo": { + "title": "Logo ONE", + "alt": "Logo ONE", + "producerName": "Logo ONE", + "src": "https://api.ardmediathek.de/image-service/image-collections/urn:ard:image-collection:2213972a8d101de1/16x9?w={width}", + "aspectRatio": "16x9" + }, + "publisherType": "TV", + "partner": "one", + "id": "b3JnYW5pemF0aW9uX09ORQ", + "coreId": "urn:ard:publisher:892e3c758ca56a9d" + }, + "links": { + "self": { + "id": "player_on_demand_widget_ard", + "urlId": "player_on_demand_widget_ard", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "href": "https://api.ardmediathek.de/page-gateway/widgets/ard/editorials/player_on_demand_widget_ard/item/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?pageNumber=0&pageSize=100&embedded=true&mcV6=true", + "type": "application/vnd.ard.widget+json", + "partner": "ard" + } + }, + "show": { + "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "title": "Murdoch Mysteries", + "image": { + "alt": "Sendungslogo \"Murdoch Mysteries\"", + "producerName": "Shaftesbury Murdoch II Inc", + "src": "https://api.ardmediathek.de/image-service/images/urn:ard:image:559937f982bde0f5?w={width}&ch=dc9ee6ab714f2b88", + "title": "Murdoch Mysteries" + }, + "availableSeasons": [ + "1", + "4" + ], + "binaryFeatures": [ + "UT", + "OV" + ], + "coreAssetType": "SEASON_SERIES" + }, + "synopsis": "Während sich Dr. Ogden auf ihre Hochzeit vorbereitet, muss Murdoch versuchen, den 'Küssenden Banditen' aufzuhalten, einen umstrittenen Bankräuber, der schnell zum Volkshelden aufsteigt.", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "trackingPiano": { + "teaser_recommended": false, + "widget_id": "player_on_demand_widget_ard", + "widget_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "widget_typ": "player_ondemand" + }, + "type": "player_ondemand" + }, + { + "aZContent": false, + "compilationType": "itemsOfShow", + "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "isChildContent": false, + "pagination": { + "pageNumber": 0, + "pageSize": 24, + "totalElements": 7 + }, + "personalized": false, + "links": { + "self": { + "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "urlId": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "title": "Murdoch Mysteries", + "href": "https://api.ardmediathek.de/page-gateway/widgets/ard/asset/Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw?excludedAssetIds=Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi&pageNumber=0&pageSize=24&embedded=true&seasoned=false&seasonNumber=&withAudiodescription=false&withOriginalWithSubtitle=false&withOriginalversion=false&single=false", + "type": "application/vnd.ard.widget+json", + "partner": "ard" + } + }, + "size": "m", + "swipeable": true, + "teasers": [], + "title": "Murdoch Mysteries", + "titleVisible": true, + "trackingPiano": { + "teaser_recommended": false, + "widget_id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "widget_title": "Murdoch Mysteries", + "widget_typ": "gridlist" + }, + "type": "gridlist", + "userVisibility": "ALWAYS" + } + ] +} \ No newline at end of file diff --git a/src/test/resources/ard/ard_item_OV_spanish.json b/src/test/resources/ard/ard_item_OV_spanish.json new file mode 100644 index 000000000..50ccda464 --- /dev/null +++ b/src/test/resources/ard/ard_item_OV_spanish.json @@ -0,0 +1,405 @@ +{ + "coreAssetType": "EXTRA_BONUS_CONTENT", + "fskRating": "FSK12", + "id": "player_ondemand-page-ard", + "isChildContent": false, + "personalized": false, + "links": { + "self": { + "id": "player_ondemand-page-ard", + "urlId": "player_ondemand-page-ard", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "href": "https://api.ardmediathek.de/page-gateway/pages/ard/item/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?embedded=true&mcV6=true", + "type": "application/vnd.ard.page+json", + "partner": "ard" + } + }, + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "tracking": { + "aggregationLevelId": 38, + "atiCustomVars": { + "clipTitle": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "mediaType": "video", + "lra": "ONE", + "channel": "ONE", + "show": "Murdoch Mysteries", + "contentTypes": "UT", + "mediaDistributionType": 1, + "contentId": 13320735, + "metadataId": "crid://wdr.de/Beitrag-sophora-ce0801f3-6223-4de2-87b3-61522db2d65b", + "clipLength": 2744 + }, + "chapter2": "Player", + "chapter3": "Murdoch Mysteries", + "environmentId": 511893, + "pageTitle": "Mediathek/Player/Murdoch Mysteries/Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)/13320735/20240424_2050", + "szmType": "CP" + }, + "trackingPiano": { + "page_chapter1": "Player", + "page_content_id": "urn:ard:publication:0c1dc4d2e066396c", + "page_content_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "page_id": "player_ondemand-page-ard", + "page_institution": "ONE", + "page_institution_id": "urn:ard:institution:9edd94d68de90140", + "page_publisher": "ONE", + "page_publisher_id": "urn:ard:publisher:892e3c758ca56a9d", + "page_show": "Murdoch Mysteries", + "page_show_id": "urn:ard:show:85088a146d3740b7", + "page_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "site": "634408" + }, + "widgets": [ + { + "availableTo": "2024-05-24T20:50:00Z", + "binaryFeatures": [ + "OV", + "UT" + ], + "blockedByFsk": false, + "broadcastedOn": "2024-04-24T20:50:00Z", + "embeddable": false, + "geoblocked": false, + "id": "Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi", + "image": { + "alt": "Detective Murdoch (Yannick Bisson) und Constable Crabtree (Jonny Harris)", + "producerName": "WDR", + "src": "https://api.ardmediathek.de/image-service/images/urn:ard:image:2a3352f634c1614c?w={width}&ch=ec0aa7bc7271383a", + "title": "Murdoch Mysteries (S04/E12) - OV" + }, + "isChildContent": false, + "maturityContentRating": "FSK12", + "mediaCollection": { + "embedded": { + "isGeoBlocked": true, + "meta": { + "availableToDateTime": "2024-05-24T20:50:00Z", + "broadcastedOnDateTime": "2024-04-24T20:50:00Z", + "clipSourceName": "ONE", + "durationSeconds": 2744, + "images": [ + { + "alt": "Detective Murdoch (Yannick Bisson) und Constable Crabtree (Jonny Harris)", + "aspectRatio": "16x9", + "imageSourceName": "WDR", + "kind": "preview", + "title": "Murdoch Mysteries (S04/E12) - OV", + "url": "https://api.ardmediathek.de/image-service/images/urn:ard:image:2a3352f634c1614c?w=960&ch=ec0aa7bc7271383a" + } + ], + "maturityContentRating": { + "age": 12, + "isBlocked": false, + "kind": "other" + }, + "publicationService": { + "id": "ard", + "name": "ONE", + "partner": "one" + }, + "synopsis": "Während sich Dr. Ogden auf ihre Hochzeit vorbereitet, muss Murdoch versuchen, den 'Küssenden Banditen' aufzuhalten, einen umstrittenen Bankräuber, der schnell zum Volkshelden aufsteigt.", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)" + }, + "pluginData": { + "recommendation@all": { + "isAutoplay": true, + "timerSeconds": 10, + "url": "https://api.ardmediathek.de/page-gateway/compilations/ard/recommendations?contextItemId=Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi" + }, + "trackingAgf@all": { + "appId": "PA02DC09C-B8D3-4098-87D2-2C023682D6D5", + "clipData": { + "assetid": "13320735", + "length": "2744", + "nol_c0": "p0,0", + "nol_c10": "p10,ONE", + "nol_c12": "p12,Content", + "nol_c15": "p15,POC_2002987622", + "nol_c16": "p16,", + "nol_c18": "p18,N", + "nol_c19": "p19,ONE", + "nol_c2": "p2,N", + "nol_c5": "p5,ARD Mediathek", + "nol_c7": "p7,crid://wdr.de/Beitrag-sophora-ce0801f3-6223-4de2-87b3-61522db2d65b", + "nol_c8": "p8,2744", + "nol_c9": "p9,Murdoch Mysteries_Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)_24.04.2024 20:50", + "program": "Murdoch Mysteries", + "title": "ONE_Murdoch Mysteries_Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)_24.04.2024 20:50", + "type": "content" + }, + "tracker": "AGF" + }, + "trackingAti@all": { + "config": { + "site": 511893 + }, + "isEnabled": true, + "richMedia": { + "broadcastMode": "clip", + "duration": "2744", + "mediaLabel": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)__13320735__OV | UT", + "mediaLevel2": "{richMediaLevelTwo}", + "mediaTheme1": "ONE", + "mediaTheme2": "ONE", + "mediaTheme3": "Murdoch Mysteries", + "mediaType": "video", + "playerId": "urn:ard:publication:0c1dc4d2e066396c", + "refreshDuration": { + "0": 5, + "1": 12, + "12": 15, + "18": 30 + } + }, + "tracker": "ATI" + }, + "trackingPiano@all": { + "avContent": { + "av_broadcasting_type": "OnDemand", + "av_content": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "av_content_duration": 2744000, + "av_content_id": "urn:ard:publication:0c1dc4d2e066396c", + "av_content_type": "video", + "av_institution": "ONE", + "av_institution_id": "urn:ard:institution:9edd94d68de90140", + "av_publisher": "ONE", + "av_publisher_id": "urn:ard:publisher:892e3c758ca56a9d", + "av_show": "Murdoch Mysteries", + "av_show_id": "urn:ard:show:85088a146d3740b7" + }, + "config": { + "events": [ + "av.error", + "av.speed", + "av.quality", + "av.jumpmark", + "av.share", + "av.playermode", + "av.subtitle", + "av.language", + "av.audiodescription", + "av.signlanguage", + "av.volume.mute", + "av.recommendation" + ], + "site": 634408 + }, + "isEnabled": true + } + }, + "streams": [ + { + "kind": "main", + "kindName": "Normal", + "media": [ + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "spa" + } + ], + "forcedLabel": "SD", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 640, + "maxVResolutionPx": 360, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016296.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "spa" + } + ], + "forcedLabel": "SD 480p", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 960, + "maxVResolutionPx": 540, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016297.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "spa" + } + ], + "forcedLabel": "Full HD", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1920, + "maxVResolutionPx": 1080, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016294.mp4", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "spa" + } + ], + "forcedLabel": "Auto", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1920, + "maxVResolutionPx": 1080, + "mimeType": "application/vnd.apple.mpegurl", + "subtitles": [], + "url": "https://wdradaptiv-vh.akamaihd.net/i/medp/ondemand/de/fsk12/310/3103788/,3103788_57016296,3103788_57016297,3103788_57016295,3103788_57016298,3103788_57016294,.mp4.csmil/master.m3u8", + "videoCodec": "H.264" + }, + { + "aspectRatio": "16:9", + "audios": [ + { + "kind": "standard", + "languageCode": "spa" + } + ], + "forcedLabel": "HD Ready", + "hasEmbeddedSubtitles": false, + "isAdaptiveQualitySelectable": false, + "isHighDynamicRange": false, + "maxHResolutionPx": 1280, + "maxVResolutionPx": 720, + "mimeType": "video/mp4", + "subtitles": [], + "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016298.mp4", + "videoCodec": "H.264" + } + ], + "videoLanguageCode": "" + } + ], + "subtitles": [ + { + "kind": "normal", + "languageCode": "deu", + "sources": [ + { + "kind": "ebutt", + "url": "https://api.ardmediathek.de/player-service/subtitle/ebutt/urn:ard:subtitle:d0e38dd26e6cc85e" + }, + { + "kind": "webvtt", + "url": "https://api.ardmediathek.de/player-service/subtitle/webvtt/urn:ard:subtitle:d0e38dd26e6cc85e.vtt" + } + ] + } + ] + }, + "href": "https://api.ardmediathek.de/page-gateway/mediacollectionv6/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?isTv=false" + }, + "pagination": null, + "personalized": false, + "playerConfig": null, + "publicationService": { + "name": "ONE", + "logo": { + "title": "Logo ONE", + "alt": "Logo ONE", + "producerName": "Logo ONE", + "src": "https://api.ardmediathek.de/image-service/image-collections/urn:ard:image-collection:2213972a8d101de1/16x9?w={width}", + "aspectRatio": "16x9" + }, + "publisherType": "TV", + "partner": "one", + "id": "b3JnYW5pemF0aW9uX09ORQ", + "coreId": "urn:ard:publisher:892e3c758ca56a9d" + }, + "links": { + "self": { + "id": "player_on_demand_widget_ard", + "urlId": "player_on_demand_widget_ard", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "href": "https://api.ardmediathek.de/page-gateway/widgets/ard/editorials/player_on_demand_widget_ard/item/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?pageNumber=0&pageSize=100&embedded=true&mcV6=true", + "type": "application/vnd.ard.widget+json", + "partner": "ard" + } + }, + "show": { + "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "title": "Murdoch Mysteries", + "image": { + "alt": "Sendungslogo \"Murdoch Mysteries\"", + "producerName": "Shaftesbury Murdoch II Inc", + "src": "https://api.ardmediathek.de/image-service/images/urn:ard:image:559937f982bde0f5?w={width}&ch=dc9ee6ab714f2b88", + "title": "Murdoch Mysteries" + }, + "availableSeasons": [ + "1", + "4" + ], + "binaryFeatures": [ + "UT", + "OV" + ], + "coreAssetType": "SEASON_SERIES" + }, + "synopsis": "Während sich Dr. Ogden auf ihre Hochzeit vorbereitet, muss Murdoch versuchen, den 'Küssenden Banditen' aufzuhalten, einen umstrittenen Bankräuber, der schnell zum Volkshelden aufsteigt.", + "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "trackingPiano": { + "teaser_recommended": false, + "widget_id": "player_on_demand_widget_ard", + "widget_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", + "widget_typ": "player_ondemand" + }, + "type": "player_ondemand" + }, + { + "aZContent": false, + "compilationType": "itemsOfShow", + "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "isChildContent": false, + "pagination": { + "pageNumber": 0, + "pageSize": 24, + "totalElements": 7 + }, + "personalized": false, + "links": { + "self": { + "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "urlId": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "title": "Murdoch Mysteries", + "href": "https://api.ardmediathek.de/page-gateway/widgets/ard/asset/Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw?excludedAssetIds=Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi&pageNumber=0&pageSize=24&embedded=true&seasoned=false&seasonNumber=&withAudiodescription=false&withOriginalWithSubtitle=false&withOriginalversion=false&single=false", + "type": "application/vnd.ard.widget+json", + "partner": "ard" + } + }, + "size": "m", + "swipeable": true, + "teasers": [], + "title": "Murdoch Mysteries", + "titleVisible": true, + "trackingPiano": { + "teaser_recommended": false, + "widget_id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", + "widget_title": "Murdoch Mysteries", + "widget_typ": "gridlist" + }, + "type": "gridlist", + "userVisibility": "ALWAYS" + } + ] +} \ No newline at end of file diff --git a/src/test/resources/ard/ard_item_OV_spanish_region.json b/src/test/resources/ard/ard_item_OV_spanish_region.json new file mode 100644 index 000000000..ace2817fd --- /dev/null +++ b/src/test/resources/ard/ard_item_OV_spanish_region.json @@ -0,0 +1 @@ +{"coreAssetType": "EXTRA_BONUS_CONTENT", "fskRating": "FSK12", "id": "player_ondemand-page-ard", "isChildContent": false, "personalized": false, "links": {"self": {"id": "player_ondemand-page-ard", "urlId": "player_ondemand-page-ard", "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "href": "https://api.ardmediathek.de/page-gateway/pages/ard/item/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?embedded=true&mcV6=true", "type": "application/vnd.ard.page+json", "partner": "ard"}}, "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "tracking": {"aggregationLevelId": 38, "atiCustomVars": {"clipTitle": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "mediaType": "video", "lra": "ONE", "channel": "ONE", "show": "Murdoch Mysteries", "contentTypes": "UT", "mediaDistributionType": 1, "contentId": 13320735, "metadataId": "crid://wdr.de/Beitrag-sophora-ce0801f3-6223-4de2-87b3-61522db2d65b", "clipLength": 2744}, "chapter2": "Player", "chapter3": "Murdoch Mysteries", "environmentId": 511893, "pageTitle": "Mediathek/Player/Murdoch Mysteries/Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)/13320735/20240424_2050", "szmType": "CP"}, "trackingPiano": {"page_chapter1": "Player", "page_content_id": "urn:ard:publication:0c1dc4d2e066396c", "page_content_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "page_id": "player_ondemand-page-ard", "page_institution": "ONE", "page_institution_id": "urn:ard:institution:9edd94d68de90140", "page_publisher": "ONE", "page_publisher_id": "urn:ard:publisher:892e3c758ca56a9d", "page_show": "Murdoch Mysteries", "page_show_id": "urn:ard:show:85088a146d3740b7", "page_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "site": "634408"}, "widgets": [{"availableTo": "2024-05-24T20:50:00Z", "binaryFeatures": ["OV", "UT"], "blockedByFsk": false, "broadcastedOn": "2024-04-24T20:50:00Z", "embeddable": false, "geoblocked": false, "id": "Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi", "image": {"alt": "Detective Murdoch (Yannick Bisson) und Constable Crabtree (Jonny Harris)", "producerName": "WDR", "src": "https://api.ardmediathek.de/image-service/images/urn:ard:image:2a3352f634c1614c?w={width}&ch=ec0aa7bc7271383a", "title": "Murdoch Mysteries (S04/E12) - OV"}, "isChildContent": false, "maturityContentRating": "FSK12", "mediaCollection": {"embedded": {"isGeoBlocked": true, "meta": {"availableToDateTime": "2024-05-24T20:50:00Z", "broadcastedOnDateTime": "2024-04-24T20:50:00Z", "clipSourceName": "ONE", "durationSeconds": 2744, "images": [{"alt": "Detective Murdoch (Yannick Bisson) und Constable Crabtree (Jonny Harris)", "aspectRatio": "16x9", "imageSourceName": "WDR", "kind": "preview", "title": "Murdoch Mysteries (S04/E12) - OV", "url": "https://api.ardmediathek.de/image-service/images/urn:ard:image:2a3352f634c1614c?w=960&ch=ec0aa7bc7271383a"}], "maturityContentRating": {"age": 12, "isBlocked": false, "kind": "other"}, "publicationService": {"id": "ard", "name": "ONE", "partner": "one"}, "synopsis": "Während sich Dr. Ogden auf ihre Hochzeit vorbereitet, muss Murdoch versuchen, den 'Küssenden Banditen' aufzuhalten, einen umstrittenen Bankräuber, der schnell zum Volkshelden aufsteigt.", "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)"}, "pluginData": {"recommendation@all": {"isAutoplay": true, "timerSeconds": 10, "url": "https://api.ardmediathek.de/page-gateway/compilations/ard/recommendations?contextItemId=Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi"}, "trackingAgf@all": {"appId": "PA02DC09C-B8D3-4098-87D2-2C023682D6D5", "clipData": {"assetid": "13320735", "length": "2744", "nol_c0": "p0,0", "nol_c10": "p10,ONE", "nol_c12": "p12,Content", "nol_c15": "p15,POC_2002987622", "nol_c16": "p16,", "nol_c18": "p18,N", "nol_c19": "p19,ONE", "nol_c2": "p2,N", "nol_c5": "p5,ARD Mediathek", "nol_c7": "p7,crid://wdr.de/Beitrag-sophora-ce0801f3-6223-4de2-87b3-61522db2d65b", "nol_c8": "p8,2744", "nol_c9": "p9,Murdoch Mysteries_Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)_24.04.2024 20:50", "program": "Murdoch Mysteries", "title": "ONE_Murdoch Mysteries_Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)_24.04.2024 20:50", "type": "content"}, "tracker": "AGF"}, "trackingAti@all": {"config": {"site": 511893}, "isEnabled": true, "richMedia": {"broadcastMode": "clip", "duration": "2744", "mediaLabel": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)__13320735__OV | UT", "mediaLevel2": "{richMediaLevelTwo}", "mediaTheme1": "ONE", "mediaTheme2": "ONE", "mediaTheme3": "Murdoch Mysteries", "mediaType": "video", "playerId": "urn:ard:publication:0c1dc4d2e066396c", "refreshDuration": {"0": 5, "1": 12, "12": 15, "18": 30}}, "tracker": "ATI"}, "trackingPiano@all": {"avContent": {"av_broadcasting_type": "OnDemand", "av_content": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "av_content_duration": 2744000, "av_content_id": "urn:ard:publication:0c1dc4d2e066396c", "av_content_type": "video", "av_institution": "ONE", "av_institution_id": "urn:ard:institution:9edd94d68de90140", "av_publisher": "ONE", "av_publisher_id": "urn:ard:publisher:892e3c758ca56a9d", "av_show": "Murdoch Mysteries", "av_show_id": "urn:ard:show:85088a146d3740b7"}, "config": {"events": ["av.error", "av.speed", "av.quality", "av.jumpmark", "av.share", "av.playermode", "av.subtitle", "av.language", "av.audiodescription", "av.signlanguage", "av.volume.mute", "av.recommendation"], "site": 634408}, "isEnabled": true}}, "streams": [{"kind": "main", "kindName": "Normal", "media": [{"aspectRatio": "16:9", "audios": [{"kind": "standard", "languageCode": "spa-ES"}], "forcedLabel": "SD", "hasEmbeddedSubtitles": false, "isAdaptiveQualitySelectable": false, "isHighDynamicRange": false, "maxHResolutionPx": 640, "maxVResolutionPx": 360, "mimeType": "video/mp4", "subtitles": [], "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016296.mp4", "videoCodec": "H.264"}, {"aspectRatio": "16:9", "audios": [{"kind": "standard", "languageCode": "spa-ES"}], "forcedLabel": "SD 480p", "hasEmbeddedSubtitles": false, "isAdaptiveQualitySelectable": false, "isHighDynamicRange": false, "maxHResolutionPx": 960, "maxVResolutionPx": 540, "mimeType": "video/mp4", "subtitles": [], "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016297.mp4", "videoCodec": "H.264"}, {"aspectRatio": "16:9", "audios": [{"kind": "standard", "languageCode": "spa-ES"}], "forcedLabel": "Full HD", "hasEmbeddedSubtitles": false, "isAdaptiveQualitySelectable": false, "isHighDynamicRange": false, "maxHResolutionPx": 1920, "maxVResolutionPx": 1080, "mimeType": "video/mp4", "subtitles": [], "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016294.mp4", "videoCodec": "H.264"}, {"aspectRatio": "16:9", "audios": [{"kind": "standard", "languageCode": "spa-ES"}], "forcedLabel": "Auto", "hasEmbeddedSubtitles": false, "isAdaptiveQualitySelectable": false, "isHighDynamicRange": false, "maxHResolutionPx": 1920, "maxVResolutionPx": 1080, "mimeType": "application/vnd.apple.mpegurl", "subtitles": [], "url": "https://wdradaptiv-vh.akamaihd.net/i/medp/ondemand/de/fsk12/310/3103788/,3103788_57016296,3103788_57016297,3103788_57016295,3103788_57016298,3103788_57016294,.mp4.csmil/master.m3u8", "videoCodec": "H.264"}, {"aspectRatio": "16:9", "audios": [{"kind": "standard", "languageCode": "spa-ES"}], "forcedLabel": "HD Ready", "hasEmbeddedSubtitles": false, "isAdaptiveQualitySelectable": false, "isHighDynamicRange": false, "maxHResolutionPx": 1280, "maxVResolutionPx": 720, "mimeType": "video/mp4", "subtitles": [], "url": "https://wdrmedien-a.akamaihd.net/medp/ondemand/de/fsk12/310/3103788/3103788_57016298.mp4", "videoCodec": "H.264"}], "videoLanguageCode": ""}], "subtitles": [{"kind": "normal", "languageCode": "deu", "sources": [{"kind": "ebutt", "url": "https://api.ardmediathek.de/player-service/subtitle/ebutt/urn:ard:subtitle:d0e38dd26e6cc85e"}, {"kind": "webvtt", "url": "https://api.ardmediathek.de/player-service/subtitle/webvtt/urn:ard:subtitle:d0e38dd26e6cc85e.vtt"}]}]}, "href": "https://api.ardmediathek.de/page-gateway/mediacollectionv6/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?isTv=false"}, "pagination": null, "personalized": false, "playerConfig": null, "publicationService": {"name": "ONE", "logo": {"title": "Logo ONE", "alt": "Logo ONE", "producerName": "Logo ONE", "src": "https://api.ardmediathek.de/image-service/image-collections/urn:ard:image-collection:2213972a8d101de1/16x9?w={width}", "aspectRatio": "16x9"}, "publisherType": "TV", "partner": "one", "id": "b3JnYW5pemF0aW9uX09ORQ", "coreId": "urn:ard:publisher:892e3c758ca56a9d"}, "links": {"self": {"id": "player_on_demand_widget_ard", "urlId": "player_on_demand_widget_ard", "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "href": "https://api.ardmediathek.de/page-gateway/widgets/ard/editorials/player_on_demand_widget_ard/item/Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi?pageNumber=0&pageSize=100&embedded=true&mcV6=true", "type": "application/vnd.ard.widget+json", "partner": "ard"}}, "show": {"id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", "title": "Murdoch Mysteries", "image": {"alt": "Sendungslogo \"Murdoch Mysteries\"", "producerName": "Shaftesbury Murdoch II Inc", "src": "https://api.ardmediathek.de/image-service/images/urn:ard:image:559937f982bde0f5?w={width}&ch=dc9ee6ab714f2b88", "title": "Murdoch Mysteries"}, "availableSeasons": ["1", "4"], "binaryFeatures": ["UT", "OV"], "coreAssetType": "SEASON_SERIES"}, "synopsis": "Während sich Dr. Ogden auf ihre Hochzeit vorbereitet, muss Murdoch versuchen, den 'Küssenden Banditen' aufzuhalten, einen umstrittenen Bankräuber, der schnell zum Volkshelden aufsteigt.", "title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "trackingPiano": {"teaser_recommended": false, "widget_id": "player_on_demand_widget_ard", "widget_title": "Folge 12: Der küssende Bandit (S04/E12) - (Originalversion)", "widget_typ": "player_ondemand"}, "type": "player_ondemand"}, {"aZContent": false, "compilationType": "itemsOfShow", "id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", "isChildContent": false, "pagination": {"pageNumber": 0, "pageSize": 24, "totalElements": 7}, "personalized": false, "links": {"self": {"id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", "urlId": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", "title": "Murdoch Mysteries", "href": "https://api.ardmediathek.de/page-gateway/widgets/ard/asset/Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw?excludedAssetIds=Y3JpZDovL3dkci5kZS9CZWl0cmFnLXNvcGhvcmEtY2UwODAxZjMtNjIyMy00ZGUyLTg3YjMtNjE1MjJkYjJkNjVi&pageNumber=0&pageSize=24&embedded=true&seasoned=false&seasonNumber=&withAudiodescription=false&withOriginalWithSubtitle=false&withOriginalversion=false&single=false", "type": "application/vnd.ard.widget+json", "partner": "ard"}}, "size": "m", "swipeable": true, "teasers": [], "title": "Murdoch Mysteries", "titleVisible": true, "trackingPiano": {"teaser_recommended": false, "widget_id": "Y3JpZDovL3dkci5kZTdvbmUvbXVyZG9jaG15c3Rlcmllcw", "widget_title": "Murdoch Mysteries", "widget_typ": "gridlist"}, "type": "gridlist", "userVisibility": "ALWAYS"}]} \ No newline at end of file diff --git a/src/test/resources/mlib/TestFilmlistOldFormatWriter.json b/src/test/resources/mlib/TestFilmlistOldFormatWriter.json index f9e3a0e37..7dc5178e2 100644 --- a/src/test/resources/mlib/TestFilmlistOldFormatWriter.json +++ b/src/test/resources/mlib/TestFilmlistOldFormatWriter.json @@ -1 +1 @@ -{"Filmliste":["30.05.2023, 19:21","30.05.2023, 17:21","4","MSearch [Vers.: 4.0.1]","7bc3d924-974f-42c4-8994-9d98dde17862"],"Filmliste":["Sender","Thema","Titel","Datum","Zeit","Dauer","Größe [MB]","Beschreibung","Url","Website","Url Untertitel","Url RTMP","Url Klein","Url RTMP Klein","Url HD","Url RTMP HD","DatumL","Url History","Geo","neu"],"X":["3Sat","37 Grad","37° Totgerast (Audiodeskription)","30.05.2023","22:15:00","00:28:45","405","Wer plötzlich Angehörige bei einem Unfall verliert, wacht in einem anderen Leben auf. Antonia verlor ihre Eltern und ihre Schwester, Steffen seine Frau und seinen Sohn.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230530_2215_sendung_37g/2/230530_2215_sendung_37g_a3a4_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad/37-totgerast-102.html","","","101|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230530_2215_sendung_37g/2/230530_2215_sendung_37g_a3a4_6660k_p37v17.mp4","","1685477700","","","false"],"X":["","","37°: Ein Gen verändert unser Leben (Audiodeskription)","16.05.2023","22:15:00","00:28:41","414","Eine Diagnose, die alles verändert: Milo hat einen Gendefekt. Wie wird das Leben werden mit einem Kind, das extrem viel Betreuung braucht? \"37°\" begleitet die Familie.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230502_2215_sendung_37g/4/230502_2215_sendung_37g_a3a4_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad/37-ein-gen-veraendert-unser-leben-100.html","","","101|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230502_2215_sendung_37g/4/230502_2215_sendung_37g_a3a4_6660k_p37v17.mp4","","1684268100","","","false"],"X":["","","37°: Mein Tanz, mein Battle (Audiodeskription)","11.10.2022","22:15:00","00:28:42","416","Joanna und Serhat teilen dieselbe Leidenschaft: Breakdance. 2024 feiert Breaken in Paris olympische Premiere. Eine Herausforderung für die Tänzer, wirklich alles zu geben.","https://rodlzdf-a.akamaihd.net/none/zdf/22/10/221011_2215_sendung_37g/3/221011_2215_sendung_37g_a3a4_2360k_p35v15.mp4","https://www.3sat.de/gesellschaft/37-grad/37-mein-tanz-mein-battle-100.html","","","101|808k_p11v15.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/22/10/221011_2215_sendung_37g/3/221011_2215_sendung_37g_a3a4_3360k_p36v15.mp4","","1665519300","","","false"],"X":["","37 Grad Leben","Stroke Survivor – Ich geb' nicht auf! -","30.05.2023","09:03:00","00:27:07","377","Kaum ins Leben gestartet – und dann die Diagnose Schlaganfall. Wie kommen vor allem junge Betroffene, die sich gesund ernähren und sportlich leben, damit zurecht?","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230507_0903_sendung_sgl/1/230507_0903_sendung_sgl_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad-leben/stroke-survivor-ich-gebe-nicht-auf-102.html","https://utstreaming.zdf.de/mtt/zdf/23/05/230507_0903_sendung_sgl/2/F1039138_hoh_deu_37_Leben_Stroke_Survivors_neu.xml","","96|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230507_0903_sendung_sgl/1/230507_0903_sendung_sgl_6660k_p37v17.mp4","","1685430180","","","false"],"X":["","","Ich lass mich taufen -","28.05.2023","09:03:00","00:27:08","390","Trotz vieler Kirchenaustritte gibt es immer wieder Menschen, die einen Weg in die Kirche finden, sich im Erwachsenenalter taufen lassen. \"37°Leben\" begleitet zwei junge Frauen bei ihrer Taufe.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230528_0903_sendung_sgl/1/230528_0903_sendung_sgl_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad-leben/ich-lass-mich-taufen-102.html","https://utstreaming.zdf.de/mtt/zdf/23/05/230528_0903_sendung_sgl/2/F1039826_hoh_deu_37_Leben_Ich_lass_mich_taufen_280523.xml","","96|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230528_0903_sendung_sgl/1/230528_0903_sendung_sgl_6660k_p37v17.mp4","","1685257380","","","false"],"X":["","","Körperideale: so what? -","14.05.2023","09:03:00","00:26:58","371","Federico ist 1,63 Meter groß. Als kleiner Mann selbstbewusst zu sein und sich begehrenswert zu fühlen, ist sein Weg. Bis heute muss er sich mit verletzenden Kommentaren auseinandersetzen.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230514_0903_sendung_sgl/1/230514_0903_sendung_sgl_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad-leben/koerperideale-so-what-102.html","https://utstreaming.zdf.de/mtt/zdf/23/05/230514_0903_sendung_sgl/2/F1039665_hoh_deu_37_Grad_Leben_Koerperideale_so_what_ap_140523.xml","","96|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230514_0903_sendung_sgl/1/230514_0903_sendung_sgl_6660k_p37v17.mp4","","1684047780","","","false"],"X":["","Besonders normal","Leben in Zeiten von Corona","08.07.2020","11:44:00","00:29:01","499","Menschen mit Behinderungen sind gerade in größter Sorge. Sie haben Angst vor Ansteckung und einem schweren Verlauf, vor der Einsamkeit in Isolation und einem Assistenz- und Pflegekräftemangel.","https://rodlzdf-a.akamaihd.net/none/3sat/20/05/200508__1140_sendung_besondersnormal/2/200508__1140_sendung_besondersnormal_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/besonders-normal/besonders-normal-vom-8-mai-2020-102.html","https://utstreaming.zdf.de/mtt/3sat/20/05/200508__1140_sendung_besondersnormal/2/F1026017_hoh_deu_Besonders_normal_Leben_in_Zeiten_von_Corona_080520.xml","","123|776k_p11v13.mp4","","123|3328k_p36v13.mp4","","1594201440","","","false"],"X":["","","Corona - Zwischen Sorge und Zuversicht","05.06.2020","11:30:00","00:28:56","499","Die Corona-Pandemie wirkt immer noch nach. Auch bei den Menschen mit Behinderungen und sozial Schwachen. Sie können nicht wie gewohnt arbeiten oder bangen um die berufliche Existenz.","https://rodlzdf-a.akamaihd.net/none/3sat/20/06/200605_1130_sendung_besondersnormal/2/200605_1130_sendung_besondersnormal_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/besonders-normal/besonders-normal-vom-5-juni-2020-100.html","https://utstreaming.zdf.de/mtt/3sat/20/06/200605_1130_sendung_besondersnormal/2/F1026188_hoh_deu_Besonders_normal_Corona_Zwischen_Zuversicht_und_Sorge_050620.xml","","121|776k_p11v13.mp4","","121|3328k_p36v13.mp4","","1591349400","","","false"],"X":["","","Beste Freunde","07.06.2019","12:29:00","00:29:27","509","Während die Politik und Gesellschaft über die Möglichkeiten von Inklusion und Teilhabe diskutieren, haben zwei kleine Mädchen, den Traum schon längst umgesetzt.","https://rodlzdf-a.akamaihd.net/none/3sat/19/06/190607_beste_freunde/1/190607_beste_freunde_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/besonders-normal/beste-freunde-102.html","","","91|776k_p11v13.mp4","","91|3296k_p15v13.mp4","","1559903340","","","false"],"X":["","Bier Royal","Bier Royal (1/2) - Familienkomödie, Deutschland 2019","30.01.2019","20:15:00","01:25:05","1467","München. Bier. Society. Und mittendrin eine alteingesessene Bierdynastie, in der zwei Frauen um Macht, Liebe und Anerkennung kämpfen.","https://rodlzdf-a.akamaihd.net/dach/3sat/19/12/191227_bier_royal1_fernsehfilm/2/191227_bier_royal1_fernsehfilm_2328k_p35v13.mp4","https://www.3sat.de/film/bier-royal/bier-royal-1-100.html","","","111|776k_p11v13.mp4","","111|3328k_p36v13.mp4","","1548875700","","DE-AT-CH","false"],"X":["","","Bier Royal (2/2) - Familienkomödie, Deutschland 2019","28.01.2019","20:15:00","01:27:30","1510","Die Münchner Brauerei droht im erbitterten Erbstreit unterzugehen. Gisela und Vicky müssen zusammenarbeiten, um das Unternehmen zu retten.","https://rodlzdf-a.akamaihd.net/dach/3sat/19/12/191227_bier_royal2_fernsehfilm/4/191227_bier_royal2_fernsehfilm_2328k_p35v13.mp4","https://www.3sat.de/film/bier-royal/bier-royal-2-100.html","","","111|776k_p11v13.mp4","","111|3328k_p36v13.mp4","","1548702900","","DE-AT-CH","false"],"X":["","Bilder aus Südtirol","Bilder aus Südtirol vom 20. Mai 2023","20.05.2023","09:35:00","00:23:32","327","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/05/230520_0935_sendung_suedtirol/1/230520_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-20-mai-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/05/230520_0935_sendung_suedtirol/1/230520_0935_sendung_suedtirol_6660k_p37v17.mp4","","1684568100","","","false"],"X":["","","Bilder aus Südtirol vom 13. Mai 2023","13.05.2023","09:37:00","00:22:38","314","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/05/230513_0935_sendung_suedtirol/1/230513_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-13-mai-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/05/230513_0935_sendung_suedtirol/1/230513_0935_sendung_suedtirol_6660k_p37v17.mp4","","1683963420","","","false"],"X":["","","Bilder aus Südtirol vom 6. Mai 2023","06.05.2023","09:39:00","00:24:21","336","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/05/230506_0935_sendung_suedtirol/1/230506_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-6-mai-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/05/230506_0935_sendung_suedtirol/1/230506_0935_sendung_suedtirol_6660k_p37v17.mp4","","1683358740","","","false"],"X":["","","Bilder aus Südtirol vom 22. April 2023","22.04.2023","09:39:00","00:23:52","337","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/04/230422_0935_sendung_suedtirol/1/230422_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-22-april-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/04/230422_0935_sendung_suedtirol/1/230422_0935_sendung_suedtirol_6660k_p37v17.mp4","","1682149140","","","false"],"X":["","","Bilder aus Südtirol vom 15. April 2023","15.04.2023","09:37:00","00:19:42","273","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/04/230415_0935_sendung_suedtirol/1/230415_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-15-april-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/04/230415_0935_sendung_suedtirol/1/230415_0935_sendung_suedtirol_6660k_p37v17.mp4","","1681544220","","","false"],"X":["","","Bilder aus Südtirol vom 8. April 2023","08.04.2023","09:36:00","00:22:56","323","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/04/230408_0935_sendung_suedtirol/1/230408_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-8-april-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/04/230408_0935_sendung_suedtirol/1/230408_0935_sendung_suedtirol_6660k_p37v17.mp4","","1680939360","","","false"],"X":["","","Bilder aus Südtirol vom 11. Dezember 2021","11.12.2021","09:35:00","00:24:35","335","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/21/12/211211_0935_sendung_suedtirol/1/211211_0935_sendung_suedtirol_2360k_p35v15.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-11-dezember-2021-100.html","","","109|808k_p11v15.mp4","","109|3360k_p36v15.mp4","","1639211700","","","false"],"X":["","","Bilder aus Südtirol vom 6. November 2021","06.11.2021","09:35:00","00:23:58","333","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/21/11/211106_0935_sendung_suedtirol/1/211106_0935_sendung_suedtirol_2360k_p35v15.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-6-november-2021-100.html","","","109|808k_p11v15.mp4","","109|3360k_p36v15.mp4","","1636187700","","","false"],"X":["","","Bilder aus Südtirol vom 25. Juli 2020","25.07.2020","09:35:00","00:23:41","407","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/20/07/200725_0935_sendung_suedtirol/1/200725_0935_sendung_suedtirol_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-25-juli-2020-100.html","","","109|776k_p11v13.mp4","","109|3328k_p36v13.mp4","","1595662500","","","false"],"X":["","","Bilder aus Südtirol vom 20. Juni 2020","20.06.2020","09:36:00","00:24:16","416","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/20/06/200620_0935_sendung_suedtirol/1/200620_0935_sendung_suedtirol_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-20-juni-2020-100.html","","","109|776k_p11v13.mp4","","109|3328k_p36v13.mp4","","1592638560","","","false"]} \ No newline at end of file +{"Filmliste":["30.05.2023, 19:21","30.05.2023, 17:21","4","MSearch [Vers.: 4.0.1]","7bc3d924-974f-42c4-8994-9d98dde17862"],"Filmliste":["Sender","Thema","Titel","Datum","Zeit","Dauer","Größe [MB]","Beschreibung","Url","Website","Url Untertitel","Url RTMP","Url Klein","Url RTMP Klein","Url HD","Url RTMP HD","DatumL","Url History","Geo","neu","Sprache"],"X":["3Sat","37 Grad","37° Totgerast (Audiodeskription)","30.05.2023","22:15:00","00:28:45","405","Wer plötzlich Angehörige bei einem Unfall verliert, wacht in einem anderen Leben auf. Antonia verlor ihre Eltern und ihre Schwester, Steffen seine Frau und seinen Sohn.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230530_2215_sendung_37g/2/230530_2215_sendung_37g_a3a4_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad/37-totgerast-102.html","","","101|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230530_2215_sendung_37g/2/230530_2215_sendung_37g_a3a4_6660k_p37v17.mp4","","1685477700","","","false",""],"X":["","","37°: Ein Gen verändert unser Leben (Audiodeskription)","16.05.2023","22:15:00","00:28:41","414","Eine Diagnose, die alles verändert: Milo hat einen Gendefekt. Wie wird das Leben werden mit einem Kind, das extrem viel Betreuung braucht? \"37°\" begleitet die Familie.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230502_2215_sendung_37g/4/230502_2215_sendung_37g_a3a4_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad/37-ein-gen-veraendert-unser-leben-100.html","","","101|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230502_2215_sendung_37g/4/230502_2215_sendung_37g_a3a4_6660k_p37v17.mp4","","1684268100","","","false",""],"X":["","","37°: Mein Tanz, mein Battle (Audiodeskription)","11.10.2022","22:15:00","00:28:42","416","Joanna und Serhat teilen dieselbe Leidenschaft: Breakdance. 2024 feiert Breaken in Paris olympische Premiere. Eine Herausforderung für die Tänzer, wirklich alles zu geben.","https://rodlzdf-a.akamaihd.net/none/zdf/22/10/221011_2215_sendung_37g/3/221011_2215_sendung_37g_a3a4_2360k_p35v15.mp4","https://www.3sat.de/gesellschaft/37-grad/37-mein-tanz-mein-battle-100.html","","","101|808k_p11v15.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/22/10/221011_2215_sendung_37g/3/221011_2215_sendung_37g_a3a4_3360k_p36v15.mp4","","1665519300","","","false",""],"X":["","37 Grad Leben","Stroke Survivor – Ich geb' nicht auf! -","30.05.2023","09:03:00","00:27:07","377","Kaum ins Leben gestartet – und dann die Diagnose Schlaganfall. Wie kommen vor allem junge Betroffene, die sich gesund ernähren und sportlich leben, damit zurecht?","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230507_0903_sendung_sgl/1/230507_0903_sendung_sgl_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad-leben/stroke-survivor-ich-gebe-nicht-auf-102.html","https://utstreaming.zdf.de/mtt/zdf/23/05/230507_0903_sendung_sgl/2/F1039138_hoh_deu_37_Leben_Stroke_Survivors_neu.xml","","96|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230507_0903_sendung_sgl/1/230507_0903_sendung_sgl_6660k_p37v17.mp4","","1685430180","","","false",""],"X":["","","Ich lass mich taufen -","28.05.2023","09:03:00","00:27:08","390","Trotz vieler Kirchenaustritte gibt es immer wieder Menschen, die einen Weg in die Kirche finden, sich im Erwachsenenalter taufen lassen. \"37°Leben\" begleitet zwei junge Frauen bei ihrer Taufe.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230528_0903_sendung_sgl/1/230528_0903_sendung_sgl_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad-leben/ich-lass-mich-taufen-102.html","https://utstreaming.zdf.de/mtt/zdf/23/05/230528_0903_sendung_sgl/2/F1039826_hoh_deu_37_Leben_Ich_lass_mich_taufen_280523.xml","","96|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230528_0903_sendung_sgl/1/230528_0903_sendung_sgl_6660k_p37v17.mp4","","1685257380","","","false",""],"X":["","","Körperideale: so what? -","14.05.2023","09:03:00","00:26:58","371","Federico ist 1,63 Meter groß. Als kleiner Mann selbstbewusst zu sein und sich begehrenswert zu fühlen, ist sein Weg. Bis heute muss er sich mit verletzenden Kommentaren auseinandersetzen.","https://rodlzdf-a.akamaihd.net/none/zdf/23/05/230514_0903_sendung_sgl/1/230514_0903_sendung_sgl_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/37-grad-leben/koerperideale-so-what-102.html","https://utstreaming.zdf.de/mtt/zdf/23/05/230514_0903_sendung_sgl/2/F1039665_hoh_deu_37_Grad_Leben_Koerperideale_so_what_ap_140523.xml","","96|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/zdf/23/05/230514_0903_sendung_sgl/1/230514_0903_sendung_sgl_6660k_p37v17.mp4","","1684047780","","","false",""],"X":["","Besonders normal","Leben in Zeiten von Corona","08.07.2020","11:44:00","00:29:01","499","Menschen mit Behinderungen sind gerade in größter Sorge. Sie haben Angst vor Ansteckung und einem schweren Verlauf, vor der Einsamkeit in Isolation und einem Assistenz- und Pflegekräftemangel.","https://rodlzdf-a.akamaihd.net/none/3sat/20/05/200508__1140_sendung_besondersnormal/2/200508__1140_sendung_besondersnormal_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/besonders-normal/besonders-normal-vom-8-mai-2020-102.html","https://utstreaming.zdf.de/mtt/3sat/20/05/200508__1140_sendung_besondersnormal/2/F1026017_hoh_deu_Besonders_normal_Leben_in_Zeiten_von_Corona_080520.xml","","123|776k_p11v13.mp4","","123|3328k_p36v13.mp4","","1594201440","","","false",""],"X":["","","Corona - Zwischen Sorge und Zuversicht","05.06.2020","11:30:00","00:28:56","499","Die Corona-Pandemie wirkt immer noch nach. Auch bei den Menschen mit Behinderungen und sozial Schwachen. Sie können nicht wie gewohnt arbeiten oder bangen um die berufliche Existenz.","https://rodlzdf-a.akamaihd.net/none/3sat/20/06/200605_1130_sendung_besondersnormal/2/200605_1130_sendung_besondersnormal_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/besonders-normal/besonders-normal-vom-5-juni-2020-100.html","https://utstreaming.zdf.de/mtt/3sat/20/06/200605_1130_sendung_besondersnormal/2/F1026188_hoh_deu_Besonders_normal_Corona_Zwischen_Zuversicht_und_Sorge_050620.xml","","121|776k_p11v13.mp4","","121|3328k_p36v13.mp4","","1591349400","","","false",""],"X":["","","Beste Freunde","07.06.2019","12:29:00","00:29:27","509","Während die Politik und Gesellschaft über die Möglichkeiten von Inklusion und Teilhabe diskutieren, haben zwei kleine Mädchen, den Traum schon längst umgesetzt.","https://rodlzdf-a.akamaihd.net/none/3sat/19/06/190607_beste_freunde/1/190607_beste_freunde_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/besonders-normal/beste-freunde-102.html","","","91|776k_p11v13.mp4","","91|3296k_p15v13.mp4","","1559903340","","","false",""],"X":["","Bier Royal","Bier Royal (1/2) - Familienkomödie, Deutschland 2019","30.01.2019","20:15:00","01:25:05","1467","München. Bier. Society. Und mittendrin eine alteingesessene Bierdynastie, in der zwei Frauen um Macht, Liebe und Anerkennung kämpfen.","https://rodlzdf-a.akamaihd.net/dach/3sat/19/12/191227_bier_royal1_fernsehfilm/2/191227_bier_royal1_fernsehfilm_2328k_p35v13.mp4","https://www.3sat.de/film/bier-royal/bier-royal-1-100.html","","","111|776k_p11v13.mp4","","111|3328k_p36v13.mp4","","1548875700","","DE-AT-CH","false",""],"X":["","","Bier Royal (2/2) - Familienkomödie, Deutschland 2019","28.01.2019","20:15:00","01:27:30","1510","Die Münchner Brauerei droht im erbitterten Erbstreit unterzugehen. Gisela und Vicky müssen zusammenarbeiten, um das Unternehmen zu retten.","https://rodlzdf-a.akamaihd.net/dach/3sat/19/12/191227_bier_royal2_fernsehfilm/4/191227_bier_royal2_fernsehfilm_2328k_p35v13.mp4","https://www.3sat.de/film/bier-royal/bier-royal-2-100.html","","","111|776k_p11v13.mp4","","111|3328k_p36v13.mp4","","1548702900","","DE-AT-CH","false",""],"X":["","Bilder aus Südtirol","Bilder aus Südtirol vom 20. Mai 2023","20.05.2023","09:35:00","00:23:32","327","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/05/230520_0935_sendung_suedtirol/1/230520_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-20-mai-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/05/230520_0935_sendung_suedtirol/1/230520_0935_sendung_suedtirol_6660k_p37v17.mp4","","1684568100","","","false",""],"X":["","","Bilder aus Südtirol vom 13. Mai 2023","13.05.2023","09:37:00","00:22:38","314","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/05/230513_0935_sendung_suedtirol/1/230513_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-13-mai-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/05/230513_0935_sendung_suedtirol/1/230513_0935_sendung_suedtirol_6660k_p37v17.mp4","","1683963420","","","false",""],"X":["","","Bilder aus Südtirol vom 6. Mai 2023","06.05.2023","09:39:00","00:24:21","336","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/05/230506_0935_sendung_suedtirol/1/230506_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-6-mai-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/05/230506_0935_sendung_suedtirol/1/230506_0935_sendung_suedtirol_6660k_p37v17.mp4","","1683358740","","","false",""],"X":["","","Bilder aus Südtirol vom 22. April 2023","22.04.2023","09:39:00","00:23:52","337","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/04/230422_0935_sendung_suedtirol/1/230422_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-22-april-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/04/230422_0935_sendung_suedtirol/1/230422_0935_sendung_suedtirol_6660k_p37v17.mp4","","1682149140","","","false",""],"X":["","","Bilder aus Südtirol vom 15. April 2023","15.04.2023","09:37:00","00:19:42","273","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/04/230415_0935_sendung_suedtirol/1/230415_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-15-april-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/04/230415_0935_sendung_suedtirol/1/230415_0935_sendung_suedtirol_6660k_p37v17.mp4","","1681544220","","","false",""],"X":["","","Bilder aus Südtirol vom 8. April 2023","08.04.2023","09:36:00","00:22:56","323","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/23/04/230408_0935_sendung_suedtirol/1/230408_0935_sendung_suedtirol_2360k_p35v17.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-8-april-2023-100.html","","","109|808k_p11v17.mp4","","8|nrodlzdf-a.akamaihd.net/none/3sat/23/04/230408_0935_sendung_suedtirol/1/230408_0935_sendung_suedtirol_6660k_p37v17.mp4","","1680939360","","","false",""],"X":["","","Bilder aus Südtirol vom 11. Dezember 2021","11.12.2021","09:35:00","00:24:35","335","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/21/12/211211_0935_sendung_suedtirol/1/211211_0935_sendung_suedtirol_2360k_p35v15.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-11-dezember-2021-100.html","","","109|808k_p11v15.mp4","","109|3360k_p36v15.mp4","","1639211700","","","false",""],"X":["","","Bilder aus Südtirol vom 6. November 2021","06.11.2021","09:35:00","00:23:58","333","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/21/11/211106_0935_sendung_suedtirol/1/211106_0935_sendung_suedtirol_2360k_p35v15.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-6-november-2021-100.html","","","109|808k_p11v15.mp4","","109|3360k_p36v15.mp4","","1636187700","","","false",""],"X":["","","Bilder aus Südtirol vom 25. Juli 2020","25.07.2020","09:35:00","00:23:41","407","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/20/07/200725_0935_sendung_suedtirol/1/200725_0935_sendung_suedtirol_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-25-juli-2020-100.html","","","109|776k_p11v13.mp4","","109|3328k_p36v13.mp4","","1595662500","","","false",""],"X":["","","Bilder aus Südtirol vom 20. Juni 2020","20.06.2020","09:36:00","00:24:16","416","\"Bilder aus Südtirol\" ist das Bundesländermagazin des ORF-Landesstudios Tirol.","https://rodlzdf-a.akamaihd.net/none/3sat/20/06/200620_0935_sendung_suedtirol/1/200620_0935_sendung_suedtirol_2328k_p35v13.mp4","https://www.3sat.de/gesellschaft/bilder-aus-suedtirol/bilder-aus-suedtirol-vom-20-juni-2020-100.html","","","109|776k_p11v13.mp4","","109|3328k_p36v13.mp4","","1592638560","","","false",""]} \ No newline at end of file