From 1167cfa3a47cb3cb7a22ff0ef41010253a013977 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 21 Mar 2023 15:43:52 +0900 Subject: [PATCH] Add most metadata information from themoviedb --- .../implementations/themoviedatabase.py | 74 +++++++++++++++---- scanner/providers/types/movie.py | 24 +++--- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/scanner/providers/implementations/themoviedatabase.py b/scanner/providers/implementations/themoviedatabase.py index ec8c4818..abaf5307 100644 --- a/scanner/providers/implementations/themoviedatabase.py +++ b/scanner/providers/implementations/themoviedatabase.py @@ -1,7 +1,10 @@ import asyncio +from datetime import datetime import logging from aiohttp import ClientSession -from typing import Optional, Any +from typing import Callable, Dict, Optional, Any + +from providers.types.genre import Genre from ..provider import Provider from ..types.movie import Movie, MovieTranslation @@ -23,34 +26,75 @@ class TheMovieDatabase(Provider): r.raise_for_status() return await r.json() + def get_image( + self, images: list[Dict[str, Any]], filter: Callable[[Dict[str, Any]], bool] + ) -> list[str]: + return [ + f"https://image.tmdb.org/t/p/original{x['file_path']}" + for x in images + if x["file_path"] and filter(x) + ] + async def identify_movie( self, name: str, year: Optional[int], *, language: list[str] ) -> Movie: - movie_id = ( - await self.get("search/movie", params={"query": name, "year": year}) - )["results"][0]["id"] + search = (await self.get("search/movie", params={"query": name, "year": year}))[ + "results" + ][0] + movie_id = search["id"] async def for_language(lng: str) -> Movie: movie = await self.get( - f"/movie/{movie_id}", params={"language": lng, "append_to_response": ""} + f"/movie/{movie_id}", + params={ + "language": lng, + "append_to_response": "alternative_titles,videos,credits,keywords,images", + "include_image_language": ",".join( + [lng, search["original_language"]] + ), + }, ) logging.debug("TMDb responded: %s", movie) ret = Movie( - aliases=[], - release_date=None, - status=Status.UNKNOWN, - studio=None, - genres=[], - posters=[], - thumbnails=[], - logos=[], - trailers=[], + aliases=list(map(lambda x: x["title"], movie["alternative_titles"])), + release_date=datetime.strptime( + movie["release_date"], "%Y-%m-%d" + ).date(), + status=Status.FINISHED + if movie["Status"] == "Released" + else Status.PLANNED, + studios=list(map(lambda x: x["name"], movie["production_companies"])), + genres=list(map(lambda x: Genre(x["name"]), movie["genres"])), + original_posters=self.get_image( + movie["images"]["posters"], + lambda x: x["iso_639_1"] == search["original_language"], + ), + thumbnails=self.get_image( + movie["images"]["backdrops"], + lambda x: x["iso_639_1"] == lng, + ), + # TODO: Add external IDs. + # TODO: Add cast information ) translation = MovieTranslation( name=movie["title"], - keywords=[], + tagline=movie["tagline"], + keywords=list(map(lambda x: x["name"], movie["keywords"])), overview=movie["overview"], + posters=self.get_image( + movie["images"]["posters"], + lambda x: x["iso_639_1"] == lng, + ), + logos=self.get_image( + movie["images"]["logos"], + lambda x: x["iso_639_1"] == lng, + ), + trailers=[ + f"https://www.youtube.com/watch?v{x['key']}" + for x in movie["videos"]["results"] + if x["type"] == "Trailer" and x["site"] == "YouTube" + ], ) ret.translations = {lng: translation} return ret diff --git a/scanner/providers/types/movie.py b/scanner/providers/types/movie.py index 819a544e..17bf5550 100644 --- a/scanner/providers/types/movie.py +++ b/scanner/providers/types/movie.py @@ -1,6 +1,6 @@ import os from dataclasses import asdict, dataclass, field -from datetime import datetime +from datetime import date from typing import Optional from .genre import Genre @@ -10,22 +10,27 @@ from .status import Status @dataclass class MovieTranslation: name: str + tagline: Optional[str] = None keywords: list[str] = field(default_factory=list) overview: Optional[str] = None + posters: list[str] = field(default_factory=list) + logos: list[str] = field(default_factory=list) + trailers: list[str] = field(default_factory=list) + + @dataclass class Movie: aliases: list[str] = field(default_factory=list) - release_date: Optional[datetime | int] = None + release_date: Optional[date | int] = None status: Status = Status.UNKNOWN - studio: Optional[int | str] = None + studios: list[str] = field(default_factory=list) genres: list[Genre] = field(default_factory=list) - posters: list[str] = field(default_factory=list) thumbnails: list[str] = field(default_factory=list) - logos: list[str] = field(default_factory=list) - trailers: list[str] = field(default_factory=list) + # Original poster in the show's language + original_posters: list[str] = field(default_factory=list) path: Optional[str] = None # TODO: handle staff @@ -39,10 +44,11 @@ class Movie: return { **asdict(self), **asdict(self.translations[default_language]), - "poster": next(iter(self.posters), None), + "poster": next(iter(self.original_posters), None), "thumbnail": next(iter(self.thumbnails), None), - "logo": next(iter(self.logos), None), - "trailer": next(iter(self.trailers), None), + "logo": next(iter(self.translations[default_language].logos), None), + "trailer": next(iter(self.translations[default_language].trailers), None), + "studio": next(iter(self.studios), None), "start_air": self.release_date, "title": self.translations[default_language].name, "isMovie": True,