feature: add precision for release dates

also include movies from the last week
main
daniel-michel 2023-11-11 14:50:20 +01:00
parent da366285bb
commit bb356120fa
4 changed files with 59 additions and 12 deletions

View File

@ -1,7 +1,7 @@
import 'package:release_schedule/model/movie.dart'; import 'package:release_schedule/model/movie.dart';
abstract class MovieApi { abstract class MovieApi {
Future<List<MovieData>> getUpcomingMovies([int count]); Future<List<MovieData>> getUpcomingMovies(DateTime startDate, [int count]);
Future<List<MovieData>> searchForMovies(String searchTerm); Future<List<MovieData>> searchForMovies(String searchTerm);
Future<void> addMovieDetails(List<MovieData> movies); Future<void> addMovieDetails(List<MovieData> movies);
} }

View File

@ -1,14 +1,16 @@
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'package:release_schedule/api/api_manager.dart'; import 'package:release_schedule/api/api_manager.dart';
import 'package:release_schedule/api/movie_api.dart'; import 'package:release_schedule/api/movie_api.dart';
import 'package:release_schedule/model/movie.dart'; import 'package:release_schedule/model/movie.dart';
class WikidataMovieData extends MovieData { class WikidataMovieData extends MovieData {
int entityId; int entityId;
WikidataMovieData(String title, DateTime releaseDate, this.entityId) WikidataMovieData(String title, DateTime releaseDate,
: super(title, releaseDate); DatePrecision releaseDatePrecision, this.entityId)
: super(title, releaseDate, releaseDatePrecision);
WikidataMovieData.fromEncodable(Map encodable) WikidataMovieData.fromEncodable(Map encodable)
: entityId = encodable["entityId"], : entityId = encodable["entityId"],
@ -25,17 +27,22 @@ class WikidataMovieData extends MovieData {
} }
} }
String createUpcomingMovieQuery(int limit) { String createUpcomingMovieQuery(DateTime startDate, int limit) {
String date = DateFormat("yyyy-MM-dd").format(startDate);
return """ return """
SELECT SELECT
?movie ?movie
?movieLabel ?movieLabel
(MIN(?releaseDate) as ?minReleaseDate) (MIN(?releaseDate) as ?minReleaseDate)
(SAMPLE(?precision) as ?datePrecision)
WHERE { WHERE {
?movie wdt:P31 wd:Q11424; # Q11424 is the item for "film" ?movie wdt:P31 wd:Q11424; # Q11424 is the item for "film"
wdt:P577 ?releaseDate; # P577 is the "publication date" property wdt:P577 ?releaseDate; # P577 is the "publication date" property
wdt:P1476 ?title. wdt:P1476 ?title.
FILTER (xsd:date(?releaseDate) >= xsd:date(NOW())) OPTIONAL {
?movie p:P577/psv:P577/wikibase:timePrecision ?precision.
}
FILTER (xsd:date(?releaseDate) >= xsd:date("$date"^^xsd:dateTime))
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". } SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
} }
@ -44,6 +51,17 @@ ORDER BY ?minReleaseDate
LIMIT $limit"""; LIMIT $limit""";
} }
DatePrecision precisionFromWikidata(int precision) {
return switch (precision) {
>= 11 => DatePrecision.day,
10 => DatePrecision.month,
9 => DatePrecision.year,
8 => DatePrecision.decade,
< 8 => throw Exception("The precision was too low, value: $precision"),
_ => throw Exception("Unexpected precision value: $precision"),
};
}
class WikidataMovieApi implements MovieApi { class WikidataMovieApi implements MovieApi {
ApiManager searchApi = ApiManager("https://www.wikidata.org/w/api.php"); ApiManager searchApi = ApiManager("https://www.wikidata.org/w/api.php");
ApiManager queryApi = ApiManager queryApi =
@ -56,9 +74,10 @@ class WikidataMovieApi implements MovieApi {
} }
@override @override
Future<List<WikidataMovieData>> getUpcomingMovies([int count = 100]) async { Future<List<WikidataMovieData>> getUpcomingMovies(DateTime startDate,
Response response = await queryApi [int count = 100]) async {
.get("&query=${Uri.encodeComponent(createUpcomingMovieQuery(count))}"); Response response = await queryApi.get(
"&query=${Uri.encodeComponent(createUpcomingMovieQuery(startDate, count))}");
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception( throw Exception(
"The Wikidata request for upcoming movies failed with status ${response.statusCode} ${response.reasonPhrase}"); "The Wikidata request for upcoming movies failed with status ${response.statusCode} ${response.reasonPhrase}");
@ -72,6 +91,7 @@ class WikidataMovieApi implements MovieApi {
movies.add(WikidataMovieData( movies.add(WikidataMovieData(
entry["movieLabel"]["value"] as String, entry["movieLabel"]["value"] as String,
DateTime.parse(entry["minReleaseDate"]["value"] as String), DateTime.parse(entry["minReleaseDate"]["value"] as String),
precisionFromWikidata(int.parse(entry["datePrecision"]["value"])),
int.parse(identifier.substring(1)))); int.parse(identifier.substring(1))));
} }
return movies; return movies;

View File

@ -26,9 +26,13 @@ class Review {
typedef ReleaseDateInCountry = (String country, DateTime date); typedef ReleaseDateInCountry = (String country, DateTime date);
typedef TitleInCountry = (String country, String title); typedef TitleInCountry = (String country, String title);
enum DatePrecision { decade, year, month, day, hour, minute }
class MovieData extends ChangeNotifier { class MovieData extends ChangeNotifier {
String _title; String _title;
DateTime _releaseDate; DateTime _releaseDate;
DatePrecision _releaseDatePrecision;
bool _hasDetails = false; bool _hasDetails = false;
List<ReleaseDateInCountry>? _releaseDates; List<ReleaseDateInCountry>? _releaseDates;
List<String>? _genres; List<String>? _genres;
@ -43,6 +47,10 @@ class MovieData extends ChangeNotifier {
return _releaseDate; return _releaseDate;
} }
DatePrecision get releaseDatePrecision {
return _releaseDatePrecision;
}
List<ReleaseDateInCountry>? get releaseDates { List<ReleaseDateInCountry>? get releaseDates {
return _releaseDates; return _releaseDates;
} }
@ -65,6 +73,9 @@ class MovieData extends ChangeNotifier {
void updateWithNew(MovieData movie) { void updateWithNew(MovieData movie) {
setDetails( setDetails(
title: movie.title,
releaseDate: movie.releaseDate,
releaseDatePrecision: movie.releaseDatePrecision,
releaseDates: movie.releaseDates, releaseDates: movie.releaseDates,
genres: movie.genres, genres: movie.genres,
titles: movie.titles, titles: movie.titles,
@ -72,10 +83,22 @@ class MovieData extends ChangeNotifier {
} }
void setDetails( void setDetails(
{List<ReleaseDateInCountry>? releaseDates, {String? title,
DateTime? releaseDate,
DatePrecision? releaseDatePrecision,
List<ReleaseDateInCountry>? releaseDates,
List<String>? genres, List<String>? genres,
List<TitleInCountry>? titles, List<TitleInCountry>? titles,
List<Review>? reviews}) { List<Review>? reviews}) {
if (title != null) {
_title = title;
}
if (releaseDate != null) {
_releaseDate = releaseDate;
}
if (releaseDatePrecision != null) {
_releaseDatePrecision = releaseDatePrecision;
}
if (releaseDates != null) { if (releaseDates != null) {
_releaseDates = releaseDates; _releaseDates = releaseDates;
} }
@ -104,6 +127,7 @@ class MovieData extends ChangeNotifier {
return { return {
"title": title, "title": title,
"releaseDate": releaseDate.toIso8601String(), "releaseDate": releaseDate.toIso8601String(),
"releaseDatePrecision": _releaseDatePrecision.name,
"releaseDates": releaseDatesByCountry, "releaseDates": releaseDatesByCountry,
"genres": genres, "genres": genres,
"titles": titlesByCountry, "titles": titlesByCountry,
@ -115,11 +139,13 @@ class MovieData extends ChangeNotifier {
return title == other.title && releaseDate == other.releaseDate; return title == other.title && releaseDate == other.releaseDate;
} }
MovieData(this._title, this._releaseDate); MovieData(this._title, this._releaseDate, this._releaseDatePrecision);
MovieData.fromJsonEncodable(Map json) MovieData.fromJsonEncodable(Map json)
: _title = json["title"], : _title = json["title"],
_releaseDate = DateTime.parse(json["releaseDate"]) { _releaseDate = DateTime.parse(json["releaseDate"]),
_releaseDatePrecision = DatePrecision.values.firstWhere(
(element) => element.name == json["releaseDatePrecision"]) {
setDetails( setDetails(
genres: json["genres"], genres: json["genres"],
releaseDates: json["releaseDates"] != null releaseDates: json["releaseDates"] != null

View File

@ -136,7 +136,8 @@ class MovieManager extends ChangeNotifier {
try { try {
loading = true; loading = true;
notifyListeners(); notifyListeners();
List<MovieData> movies = await api.getUpcomingMovies(); List<MovieData> movies = await api
.getUpcomingMovies(DateTime.now().subtract(const Duration(days: 7)));
addMovies(movies); addMovies(movies);
} finally { } finally {
loading = false; loading = false;