diff --git a/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmListDeserializer.java b/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmListDeserializer.java index 95e3b4052..b04bc4d58 100644 --- a/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmListDeserializer.java +++ b/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmListDeserializer.java @@ -5,6 +5,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import de.mediathekview.mlib.tool.Log; + import java.lang.reflect.Type; /** @@ -25,7 +27,17 @@ public ArteCategoryFilmsDTO deserialize(JsonElement aJsonElement, Type aType, Js for (JsonElement jsonElement : aJsonElement.getAsJsonObject().get(JSON_ELEMENT_DATA).getAsJsonArray()) { String programId = jsonElement.getAsJsonObject().get(JSON_ELEMENT_PROGRAMID).getAsString(); if (programId != null) { - dto.addProgramId(programId); + if (programId.startsWith("RC-")) { + // add 1 to collection id to get list of episodes + try { + long collectionId = Long.parseLong(programId.replace("RC-", "")) + 1; + dto.addCollection(String.format("RC-%06d", collectionId)); + } catch (NumberFormatException e) { + Log.errorLog(12834939, "Invalid collection id: " + programId); + } + } else { + dto.addProgramId(programId); + } } } diff --git a/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmsDTO.java b/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmsDTO.java index 3394f56d2..3d85200de 100644 --- a/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmsDTO.java +++ b/src/main/java/mServer/crawler/sender/arte/ArteCategoryFilmsDTO.java @@ -5,15 +5,23 @@ public class ArteCategoryFilmsDTO { private final ArrayList programIds = new ArrayList<>(); + private final ArrayList collectionIds = new ArrayList<>(); + private boolean hasNextPage; public void addProgramId(String aProgramId) { programIds.add(aProgramId); } + public void addCollection(String aCollectionId) { + collectionIds.add(aCollectionId); + } public ArrayList getProgramIds() { return programIds; } + public ArrayList getCollectionIds() { + return collectionIds; + } public boolean hasNextPage() { return hasNextPage; diff --git a/src/main/java/mServer/crawler/sender/arte/ArteCollectionDeserializer.java b/src/main/java/mServer/crawler/sender/arte/ArteCollectionDeserializer.java new file mode 100644 index 000000000..f1302c848 --- /dev/null +++ b/src/main/java/mServer/crawler/sender/arte/ArteCollectionDeserializer.java @@ -0,0 +1,42 @@ +package mServer.crawler.sender.arte; + +import com.google.gson.*; +import mServer.crawler.sender.base.JsonUtils; + +import java.lang.reflect.Type; + +public class ArteCollectionDeserializer implements JsonDeserializer { + private static final String ATTRIBUTE_PROGRAM_ID = "programId"; + private static final String ELEMENT_PROGRAMS = "programs"; + private static final String ELEMENT_VIDEOS = "videos"; + + public ArteCategoryFilmsDTO deserialize( + final JsonElement aJsonElement, + final Type aType, + final JsonDeserializationContext aJsonDeserializationContext) + throws JsonParseException { + final ArteCategoryFilmsDTO result = new ArteCategoryFilmsDTO(); + if (aJsonElement.isJsonObject()) { + final JsonObject mainObj = aJsonElement.getAsJsonObject(); + + if (JsonUtils.checkTreePath(mainObj, ELEMENT_PROGRAMS)) { + final JsonArray programs = mainObj.get(ELEMENT_PROGRAMS).getAsJsonArray(); + programs.forEach( + program -> { + final JsonObject programObject = program.getAsJsonObject(); + if (JsonUtils.checkTreePath(programObject, ELEMENT_VIDEOS)) { + programObject + .get(ELEMENT_VIDEOS) + .getAsJsonArray() + .forEach( + filmElement -> + JsonUtils.getAttributeAsString(filmElement.getAsJsonObject(), ATTRIBUTE_PROGRAM_ID) + .ifPresent(result::addProgramId)); + } + }); + } + } + return result; + } + +} diff --git a/src/main/java/mServer/crawler/sender/arte/MediathekArte.java b/src/main/java/mServer/crawler/sender/arte/MediathekArte.java index ca206a5c6..ef98ebc09 100644 --- a/src/main/java/mServer/crawler/sender/arte/MediathekArte.java +++ b/src/main/java/mServer/crawler/sender/arte/MediathekArte.java @@ -7,46 +7,40 @@ import de.mediathekview.mlib.daten.DatenFilm; import de.mediathekview.mlib.daten.ListeFilme; import de.mediathekview.mlib.tool.Log; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - import mServer.crawler.CrawlerTool; import mServer.crawler.FilmeSuchen; import mServer.crawler.sender.MediathekReader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + public class MediathekArte extends MediathekReader { /* - * Informationen zu den ARTE-URLs: - * {} sind nur Makierungen, dass es Platzhalter sind, sie gehören nicht zur URL. - * - * Allgemeine URL eines Films: (050169-002-A = ID des Films); (die-spur-der-steine = Titel) - * http://www.arte.tv/de/videos/{050169-002-A}/{die-spur-der-steine} - * - * Alle Sendungen: (Deutsch = DE; Französisch = FR) - * https://api.arte.tv/api/opa/v3/videos?channel={DE} - * - * Informationen zum Film: (050169-002-A = ID des Films); (de für deutsch / fr für französisch) - * https://api.arte.tv/api/player/v1/config/{de}/{050169-002-A}?platform=ARTE_NEXT - * - * Zweite Quelle für Informationen zum Film: (050169-002-A = ID des Films); (de für deutsch / fr für französisch) - * https://api.arte.tv/api/opa/v3/programs/{de}/{050169-002-A} - * - * Hintergrundinfos zum Laden der Filme nach Kategorien im langen Lauf: - * 1. statische Informationen über verfügbare Kategorien laden: URL_STATIC_CONTENT - * 2. für jede Kategorie die Unterkategorien ermitteln: URL_CATEGORY - * 3. für jede Unterkategorie die enthaltenen ProgramId ermitteln: URL_SUBCATEGORY - * 4. für alle ProgramIds die Videoinformationen laden (wie kurze Variante) + * Informationen zu den ARTE-URLs: + * {} sind nur Makierungen, dass es Platzhalter sind, sie gehören nicht zur URL. + * + * Allgemeine URL eines Films: (050169-002-A = ID des Films); (die-spur-der-steine = Titel) + * http://www.arte.tv/de/videos/{050169-002-A}/{die-spur-der-steine} + * + * Alle Sendungen: (Deutsch = DE; Französisch = FR) + * https://api.arte.tv/api/opa/v3/videos?channel={DE} + * + * Informationen zum Film: (050169-002-A = ID des Films); (de für deutsch / fr für französisch) + * https://api.arte.tv/api/player/v1/config/{de}/{050169-002-A}?platform=ARTE_NEXT + * + * Zweite Quelle für Informationen zum Film: (050169-002-A = ID des Films); (de für deutsch / fr für französisch) + * https://api.arte.tv/api/opa/v3/programs/{de}/{050169-002-A} + * + * Hintergrundinfos zum Laden der Filme nach Kategorien im langen Lauf: + * 1. statische Informationen über verfügbare Kategorien laden: URL_STATIC_CONTENT + * 2. für jede Kategorie die Unterkategorien ermitteln: URL_CATEGORY + * 3. für jede Unterkategorie die enthaltenen ProgramId ermitteln: URL_SUBCATEGORY + * 4. für alle ProgramIds die Videoinformationen laden (wie kurze Variante) */ private static final Logger LOG = LogManager.getLogger(MediathekArte.class); private static final String ARTE_API_TAG_URL_PATTERN = "https://api.arte.tv/api/opa/v3/videos?channel=%s&arteSchedulingDay=%s"; @@ -66,6 +60,8 @@ public class MediathekArte extends MediathekReader { "CIV", "LGP", "XXE" }; + private static final String COLLECTION_URL = "https://api.arte.tv/api/opa/v3/programs/%s/%s"; + private static final DateTimeFormatter ARTE_API_DATEFORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final boolean PARSE_SUBCATEGORY_SUB_PAGES = false; // Flag, ob Unterseiten der Unterkategorien verarbeitet werden soll @@ -152,7 +148,7 @@ private void addCategories() { senderLanguages.forEach((sender, langCode) -> { for (String subCategory : SUBCATEGORIES) { String subCategoryUrl = String.format(URL_SUBCATEGORY, langCode.toLowerCase(), subCategory, 1); - listeThemen.add(new String[]{sender, langCode, subCategory, subCategoryUrl}); + listeThemen.add(new String[]{sender, langCode, subCategory, subCategoryUrl}); } }); } @@ -209,6 +205,7 @@ private void addFilmeForTag(String sender, String aUrl) { */ class CategoryLoader extends Thread { + @Override public void run() { try { @@ -225,12 +222,19 @@ public void run() { } private void loadSubCategory(String sender, String langCode, String aCategory, String aUrl) { - Gson gson = new GsonBuilder().registerTypeAdapter(ArteCategoryFilmsDTO.class, new ArteCategoryFilmListDeserializer()).create(); + Gson gson = new GsonBuilder() + .registerTypeAdapter(ArteCategoryFilmsDTO.class, new ArteCategoryFilmListDeserializer()) + .create(); + Gson gsonCollection = new GsonBuilder() + .registerTypeAdapter(ArteCategoryFilmsDTO.class, new ArteCollectionDeserializer()) + .create(); // erste Seite laden int i = 2; ArteCategoryFilmsDTO dto = loadSubCategoryPage(gson, sender, aUrl); if (dto != null) { + loadCollections(sender, langCode, gsonCollection, dto); + ArteCategoryFilmsDTO nextDto = dto; while (PARSE_SUBCATEGORY_SUB_PAGES && nextDto != null && nextDto.hasNextPage()) { @@ -238,6 +242,7 @@ private void loadSubCategory(String sender, String langCode, String aCategory, S String url = String.format(URL_SUBCATEGORY, langCode.toLowerCase(), aCategory, i); nextDto = loadSubCategoryPage(gson, sender, url); if (nextDto != null) { + loadCollections(sender, langCode, gsonCollection, nextDto); nextDto.getProgramIds().forEach(programId -> dto.addProgramId(programId)); } @@ -251,6 +256,20 @@ private void loadSubCategory(String sender, String langCode, String aCategory, S } } + private void loadCollections(String sender, String langCode, Gson gson, ArteCategoryFilmsDTO dto) { + dto.getCollectionIds().forEach(collectionId -> { + final String url = String.format(COLLECTION_URL, langCode, collectionId); + try { + final ArteCategoryFilmsDTO collectionDto = ArteHttpClient.executeRequest(sender, LOG, gson, url, ArteCategoryFilmsDTO.class); + if (collectionDto != null) { + collectionDto.getProgramIds().forEach(dto::addProgramId); + } + } catch (Exception e) { + Log.errorLog(894330855, e, url); + } + }); + } + private ListeFilme loadPrograms(String sender, String langCode, ArteCategoryFilmsDTO dto) { ListeFilme listeFilme = new ListeFilme();