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';
abstract class MovieApi {
Future<List<MovieData>> getUpcomingMovies([int count]);
Future<List<MovieData>> getUpcomingMovies(DateTime startDate, [int count]);
Future<List<MovieData>> searchForMovies(String searchTerm);
Future<void> addMovieDetails(List<MovieData> movies);
}

View File

@ -1,14 +1,16 @@
import 'dart:convert';
import 'package:http/http.dart';
import 'package:intl/intl.dart';
import 'package:release_schedule/api/api_manager.dart';
import 'package:release_schedule/api/movie_api.dart';
import 'package:release_schedule/model/movie.dart';
class WikidataMovieData extends MovieData {
int entityId;
WikidataMovieData(String title, DateTime releaseDate, this.entityId)
: super(title, releaseDate);
WikidataMovieData(String title, DateTime releaseDate,
DatePrecision releaseDatePrecision, this.entityId)
: super(title, releaseDate, releaseDatePrecision);
WikidataMovieData.fromEncodable(Map encodable)
: 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 """
SELECT
?movie
?movieLabel
(MIN(?releaseDate) as ?minReleaseDate)
(SAMPLE(?precision) as ?datePrecision)
WHERE {
?movie wdt:P31 wd:Q11424; # Q11424 is the item for "film"
wdt:P577 ?releaseDate; # P577 is the "publication date" property
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". }
}
@ -44,6 +51,17 @@ ORDER BY ?minReleaseDate
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 {
ApiManager searchApi = ApiManager("https://www.wikidata.org/w/api.php");
ApiManager queryApi =
@ -56,9 +74,10 @@ class WikidataMovieApi implements MovieApi {
}
@override
Future<List<WikidataMovieData>> getUpcomingMovies([int count = 100]) async {
Response response = await queryApi
.get("&query=${Uri.encodeComponent(createUpcomingMovieQuery(count))}");
Future<List<WikidataMovieData>> getUpcomingMovies(DateTime startDate,
[int count = 100]) async {
Response response = await queryApi.get(
"&query=${Uri.encodeComponent(createUpcomingMovieQuery(startDate, count))}");
if (response.statusCode != 200) {
throw Exception(
"The Wikidata request for upcoming movies failed with status ${response.statusCode} ${response.reasonPhrase}");
@ -72,6 +91,7 @@ class WikidataMovieApi implements MovieApi {
movies.add(WikidataMovieData(
entry["movieLabel"]["value"] as String,
DateTime.parse(entry["minReleaseDate"]["value"] as String),
precisionFromWikidata(int.parse(entry["datePrecision"]["value"])),
int.parse(identifier.substring(1))));
}
return movies;

View File

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

View File

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