feature: movie description

main
daniel-michel 2024-01-10 14:46:03 +01:00
parent 9aa0278ab0
commit 0520120ccf
3 changed files with 70 additions and 2 deletions

View File

@ -75,7 +75,7 @@ class WikidataMovieApi implements MovieApi {
final start = i * batchSize; final start = i * batchSize;
final end = min((i + 1) * batchSize, movieIds.length); final end = min((i + 1) * batchSize, movieIds.length);
var response = await _wikidataApi.get( 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<String, dynamic> result = jsonDecode(response.body); Map<String, dynamic> result = jsonDecode(response.body);
Map<String, dynamic> batchEntities = result["entities"]; Map<String, dynamic> batchEntities = result["entities"];
entities.addAll(batchEntities); entities.addAll(batchEntities);
@ -94,6 +94,12 @@ class WikidataMovieApi implements MovieApi {
// they will be retrieved from the cache in fromWikidataEntity // they will be retrieved from the cache in fromWikidataEntity
await _getLabelsForEntities(allCountryAndGenreIds); await _getLabelsForEntities(allCountryAndGenreIds);
// Get wikipedia explaintexts
Iterable<String> allWikipediaTitles =
selectInJson<String>(entities, "*.sitelinks.enwiki.url")
.map((url) => url.split("/").last);
await _getWikipediaExplainTextForTitles(allWikipediaTitles.toList());
return movieIds return movieIds
.map((id) => WikidataMovieData.fromWikidataEntity(id, entities[id])) .map((id) => WikidataMovieData.fromWikidataEntity(id, entities[id]))
.toList(); .toList();
@ -142,6 +148,13 @@ class WikidataMovieData extends MovieData {
String title = String title =
selectInJson<String>(entity, "labels.en.value").firstOrNull ?? selectInJson<String>(entity, "labels.en.value").firstOrNull ??
selectInJson<String>(entity, "labels.*.value").first; selectInJson<String>(entity, "labels.*.value").first;
String? wikipediaTitle = selectInJson(entity, "sitelinks.enwiki.url")
.firstOrNull
?.split("/")
.last;
String? description = wikipediaTitle != null
? _getCachedWikipediaExplainTextFotTitle(wikipediaTitle)
: null;
Map<String, dynamic> claims = entity["claims"]; Map<String, dynamic> claims = entity["claims"];
List<TitleInLanguage>? titles = selectInJson( List<TitleInLanguage>? titles = selectInJson(
claims, "${WikidataProperties.title}.*.mainsnak.datavalue.value") claims, "${WikidataProperties.title}.*.mainsnak.datavalue.value")
@ -167,6 +180,7 @@ class WikidataMovieData extends MovieData {
DateTime.now(), DatePrecision.decade, "unknown location"), DateTime.now(), DatePrecision.decade, "unknown location"),
entityId); entityId);
movie.setDetails( movie.setDetails(
description: description,
titles: titles, titles: titles,
releaseDates: releaseDates, releaseDates: releaseDates,
genres: genres, genres: genres,
@ -267,3 +281,44 @@ Future<Map<String, String>> _getLabelsForEntities(
String _getCachedLabelForEntity(String entityId) { String _getCachedLabelForEntity(String entityId) {
return _labelCache[entityId] ?? entityId; return _labelCache[entityId] ?? entityId;
} }
ApiManager _wikipediaApi =
ApiManager("https://en.wikipedia.org/w/api.php?format=json&origin=*");
Map<String, String> _wikipediaExplainTextCache = {};
Future<Map<String, String>> _getWikipediaExplainTextForTitles(
List<String> pageTitles) async {
const batchSize = 50;
Map<String, String> 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<String, dynamic> result = jsonDecode(response.body);
List<dynamic> normalize = result["query"]["normalized"];
Map<String, dynamic> 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];
}

View File

@ -7,6 +7,7 @@ class MovieData extends ChangeNotifier {
bool _bookmarked = false; bool _bookmarked = false;
bool _hasDetails = false; bool _hasDetails = false;
String? _description;
List<DateWithPrecisionAndCountry>? _releaseDates; List<DateWithPrecisionAndCountry>? _releaseDates;
List<String>? _genres; List<String>? _genres;
List<TitleInLanguage>? _titles; List<TitleInLanguage>? _titles;
@ -25,6 +26,10 @@ class MovieData extends ChangeNotifier {
return _bookmarked; return _bookmarked;
} }
get description {
return _description;
}
List<DateWithPrecisionAndCountry>? get releaseDates { List<DateWithPrecisionAndCountry>? get releaseDates {
return _releaseDates; return _releaseDates;
} }
@ -47,6 +52,7 @@ class MovieData extends ChangeNotifier {
setDetails( setDetails(
title: movie.title, title: movie.title,
releaseDate: movie.releaseDate, releaseDate: movie.releaseDate,
description: movie.description,
releaseDates: movie.releaseDates, releaseDates: movie.releaseDates,
genres: movie.genres, genres: movie.genres,
titles: movie.titles); titles: movie.titles);
@ -56,6 +62,7 @@ class MovieData extends ChangeNotifier {
{String? title, {String? title,
DateWithPrecisionAndCountry? releaseDate, DateWithPrecisionAndCountry? releaseDate,
bool? bookmarked, bool? bookmarked,
String? description,
List<DateWithPrecisionAndCountry>? releaseDates, List<DateWithPrecisionAndCountry>? releaseDates,
List<String>? genres, List<String>? genres,
List<TitleInLanguage>? titles}) { List<TitleInLanguage>? titles}) {
@ -68,6 +75,9 @@ class MovieData extends ChangeNotifier {
if (bookmarked != null) { if (bookmarked != null) {
_bookmarked = bookmarked; _bookmarked = bookmarked;
} }
if (description != null) {
_description = description;
}
if (releaseDates != null) { if (releaseDates != null) {
_releaseDates = releaseDates; _releaseDates = releaseDates;
} }
@ -99,6 +109,7 @@ class MovieData extends ChangeNotifier {
"title": title, "title": title,
"releaseDate": _releaseDate.toJsonEncodable(), "releaseDate": _releaseDate.toJsonEncodable(),
"bookmarked": _bookmarked, "bookmarked": _bookmarked,
"description": _description,
"releaseDates": releaseDatesByCountry, "releaseDates": releaseDatesByCountry,
"genres": genres, "genres": genres,
"titles": titlesByCountry, "titles": titlesByCountry,
@ -111,6 +122,7 @@ class MovieData extends ChangeNotifier {
DateWithPrecisionAndCountry.fromJsonEncodable(json["releaseDate"]) { DateWithPrecisionAndCountry.fromJsonEncodable(json["releaseDate"]) {
setDetails( setDetails(
bookmarked: json["bookmarked"] as bool, bookmarked: json["bookmarked"] as bool,
description: json["description"] as String?,
genres: (json["genres"] as List<dynamic>?) genres: (json["genres"] as List<dynamic>?)
?.map((genre) => genre as String) ?.map((genre) => genre as String)
.toList(), .toList(),

View File

@ -51,7 +51,8 @@ class MoviePage extends StatelessWidget {
.toList() ?? .toList() ??
[], [],
), ),
const SizedBox(height: 20), const Heading("Description"),
Text(movie.description ?? "No description"),
const Heading("Titles"), const Heading("Titles"),
Table( Table(
border: TableBorder.symmetric( border: TableBorder.symmetric(