From 0520120ccfd39b5e4539ae360b97923abfa3a586 Mon Sep 17 00:00:00 2001 From: daniel-michel <65034538+daniel-michel@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:46:03 +0100 Subject: [PATCH] feature: movie description --- lib/api/wikidata_movie_api.dart | 57 ++++++++++++++++++++++++++++++++- lib/model/movie.dart | 12 +++++++ lib/view/movie_page.dart | 3 +- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/lib/api/wikidata_movie_api.dart b/lib/api/wikidata_movie_api.dart index 13ebf1b..2364144 100644 --- a/lib/api/wikidata_movie_api.dart +++ b/lib/api/wikidata_movie_api.dart @@ -75,7 +75,7 @@ class WikidataMovieApi implements MovieApi { final start = i * batchSize; final end = min((i + 1) * batchSize, movieIds.length); var response = await _wikidataApi.get( - "&action=wbgetentities&format=json&props=labels|claims&ids=${movieIds.sublist(start, end).join("|")}"); + "&action=wbgetentities&format=json&props=labels|claims|sitelinks/urls&ids=${movieIds.sublist(start, end).join("|")}"); Map result = jsonDecode(response.body); Map batchEntities = result["entities"]; entities.addAll(batchEntities); @@ -94,6 +94,12 @@ class WikidataMovieApi implements MovieApi { // they will be retrieved from the cache in fromWikidataEntity await _getLabelsForEntities(allCountryAndGenreIds); + // Get wikipedia explaintexts + Iterable allWikipediaTitles = + selectInJson(entities, "*.sitelinks.enwiki.url") + .map((url) => url.split("/").last); + await _getWikipediaExplainTextForTitles(allWikipediaTitles.toList()); + return movieIds .map((id) => WikidataMovieData.fromWikidataEntity(id, entities[id])) .toList(); @@ -142,6 +148,13 @@ class WikidataMovieData extends MovieData { String title = selectInJson(entity, "labels.en.value").firstOrNull ?? selectInJson(entity, "labels.*.value").first; + String? wikipediaTitle = selectInJson(entity, "sitelinks.enwiki.url") + .firstOrNull + ?.split("/") + .last; + String? description = wikipediaTitle != null + ? _getCachedWikipediaExplainTextFotTitle(wikipediaTitle) + : null; Map claims = entity["claims"]; List? titles = selectInJson( claims, "${WikidataProperties.title}.*.mainsnak.datavalue.value") @@ -167,6 +180,7 @@ class WikidataMovieData extends MovieData { DateTime.now(), DatePrecision.decade, "unknown location"), entityId); movie.setDetails( + description: description, titles: titles, releaseDates: releaseDates, genres: genres, @@ -267,3 +281,44 @@ Future> _getLabelsForEntities( String _getCachedLabelForEntity(String entityId) { return _labelCache[entityId] ?? entityId; } + +ApiManager _wikipediaApi = + ApiManager("https://en.wikipedia.org/w/api.php?format=json&origin=*"); +Map _wikipediaExplainTextCache = {}; +Future> _getWikipediaExplainTextForTitles( + List pageTitles) async { + const batchSize = 50; + Map explainTexts = {}; + for (int i = pageTitles.length - 1; i >= 0; i--) { + if (_labelCache.containsKey(pageTitles[i])) { + explainTexts[pageTitles[i]] = _labelCache[pageTitles[i]]!; + pageTitles.removeAt(i); + } + } + for (int i = 0; i < (pageTitles.length / batchSize).ceil(); i++) { + final start = i * batchSize; + final end = min((i + 1) * batchSize, pageTitles.length); + Response response = await _wikipediaApi.get( + "&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=${pageTitles.sublist(start, end).join("|")}"); + Map result = jsonDecode(response.body); + List normalize = result["query"]["normalized"]; + Map batchPages = result["query"]["pages"]; + for (String pageId in batchPages.keys) { + String pageTitle = batchPages[pageId]["title"]; + String originalTitle = normalize + .where((element) => element["to"] == pageTitle) + .firstOrNull?["from"] ?? + pageTitle; + String? explainText = batchPages[pageId]["extract"]; + if (explainText != null) { + _wikipediaExplainTextCache[originalTitle] = + explainTexts[originalTitle] = explainText; + } + } + } + return explainTexts; +} + +String? _getCachedWikipediaExplainTextFotTitle(String title) { + return _wikipediaExplainTextCache[title]; +} diff --git a/lib/model/movie.dart b/lib/model/movie.dart index e386299..57d518c 100644 --- a/lib/model/movie.dart +++ b/lib/model/movie.dart @@ -7,6 +7,7 @@ class MovieData extends ChangeNotifier { bool _bookmarked = false; bool _hasDetails = false; + String? _description; List? _releaseDates; List? _genres; List? _titles; @@ -25,6 +26,10 @@ class MovieData extends ChangeNotifier { return _bookmarked; } + get description { + return _description; + } + List? get releaseDates { return _releaseDates; } @@ -47,6 +52,7 @@ class MovieData extends ChangeNotifier { setDetails( title: movie.title, releaseDate: movie.releaseDate, + description: movie.description, releaseDates: movie.releaseDates, genres: movie.genres, titles: movie.titles); @@ -56,6 +62,7 @@ class MovieData extends ChangeNotifier { {String? title, DateWithPrecisionAndCountry? releaseDate, bool? bookmarked, + String? description, List? releaseDates, List? genres, List? titles}) { @@ -68,6 +75,9 @@ class MovieData extends ChangeNotifier { if (bookmarked != null) { _bookmarked = bookmarked; } + if (description != null) { + _description = description; + } if (releaseDates != null) { _releaseDates = releaseDates; } @@ -99,6 +109,7 @@ class MovieData extends ChangeNotifier { "title": title, "releaseDate": _releaseDate.toJsonEncodable(), "bookmarked": _bookmarked, + "description": _description, "releaseDates": releaseDatesByCountry, "genres": genres, "titles": titlesByCountry, @@ -111,6 +122,7 @@ class MovieData extends ChangeNotifier { DateWithPrecisionAndCountry.fromJsonEncodable(json["releaseDate"]) { setDetails( bookmarked: json["bookmarked"] as bool, + description: json["description"] as String?, genres: (json["genres"] as List?) ?.map((genre) => genre as String) .toList(), diff --git a/lib/view/movie_page.dart b/lib/view/movie_page.dart index fe9d31e..2b764e2 100644 --- a/lib/view/movie_page.dart +++ b/lib/view/movie_page.dart @@ -51,7 +51,8 @@ class MoviePage extends StatelessWidget { .toList() ?? [], ), - const SizedBox(height: 20), + const Heading("Description"), + Text(movie.description ?? "No description"), const Heading("Titles"), Table( border: TableBorder.symmetric(