From 10b291b4aaa85ef7df4fb9405076f135f49909af Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Thu, 23 Mar 2023 20:59:54 +0900 Subject: [PATCH] Add genres and studio objects for the scanner --- .../Repositories/GenreRepository.cs | 8 +++++++ .../Repositories/StudioRepository.cs | 3 +++ .../implementations/themoviedatabase.py | 22 +++++++++++++++++-- scanner/providers/provider.py | 1 + scanner/providers/types/genre.py | 5 ++++- scanner/providers/types/movie.py | 21 ++++++++++++++---- scanner/providers/types/studio.py | 13 +++++++++++ scanner/scanner/scanner.py | 2 +- 8 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 scanner/providers/types/studio.py diff --git a/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs index 2ada5abc..9b9a2843 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs @@ -23,6 +23,7 @@ using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Postgresql; +using Kyoo.Utils; using Microsoft.EntityFrameworkCore; namespace Kyoo.Core.Controllers @@ -61,6 +62,13 @@ namespace Kyoo.Core.Controllers .ToListAsync(); } + /// + protected override async Task Validate(Genre resource) + { + resource.Slug ??= Utility.ToSlug(resource.Name); + await base.Validate(resource); + } + /// public override async Task Create(Genre obj) { diff --git a/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs index 78cccbdb..213d9545 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs @@ -23,6 +23,7 @@ using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Postgresql; +using Kyoo.Utils; using Microsoft.EntityFrameworkCore; namespace Kyoo.Core.Controllers @@ -80,6 +81,8 @@ namespace Kyoo.Core.Controllers /// protected override async Task Validate(Studio resource) { + resource.Slug ??= Utility.ToSlug(resource.Name); + await base.Validate(resource); if (resource.ExternalIDs != null) { diff --git a/scanner/providers/implementations/themoviedatabase.py b/scanner/providers/implementations/themoviedatabase.py index 1e908992..aa35a7d6 100644 --- a/scanner/providers/implementations/themoviedatabase.py +++ b/scanner/providers/implementations/themoviedatabase.py @@ -10,6 +10,7 @@ from providers.types.metadataid import MetadataID from ..provider import Provider from ..types.movie import Movie, MovieTranslation from ..types.status import Status +from ..types.studio import Studio class TheMovieDatabase(Provider): @@ -84,8 +85,25 @@ class TheMovieDatabase(Provider): status=Status.FINISHED if movie["status"] == "Released" else Status.PLANNED, - studios=list(map(lambda x: x["name"], movie["production_companies"])), - genres=[self.genre_map[x["id"]] for x in movie["genres"] if x["id"] in self.genre_map], + studios=[ + Studio( + name=x["name"], + logos=[f"https://image.tmdb.org/t/p/original{x['logo_path']}"] + if "logo_path" in x + else [], + external_id={ + "themoviedatabase": MetadataID( + x["id"], f"https://www.themoviedb.org/company/{x['id']}" + ) + }, + ) + for x in movie["production_companies"] + ], + genres=[ + self.genre_map[x["id"]] + for x in movie["genres"] + if x["id"] in self.genre_map + ], external_id={ "themoviedatabase": MetadataID( movie["id"], f"https://www.themoviedb.org/movie/{movie['id']}" diff --git a/scanner/providers/provider.py b/scanner/providers/provider.py index 20f2ad4d..97f09afa 100644 --- a/scanner/providers/provider.py +++ b/scanner/providers/provider.py @@ -13,6 +13,7 @@ class Provider: @classmethod def get_all(cls: type[Self], client: ClientSession) -> list[Self]: from providers.implementations.themoviedatabase import TheMovieDatabase + providers = [] tmdb = os.environ.get("THEMOVIEDB_APIKEY") diff --git a/scanner/providers/types/genre.py b/scanner/providers/types/genre.py index 1c1d9b18..6eda0b51 100644 --- a/scanner/providers/types/genre.py +++ b/scanner/providers/types/genre.py @@ -1,7 +1,7 @@ from enum import Enum -class Genre(Enum): +class Genre(str, Enum): ACTION = "action" ADVENTURE = "adventure" ANIMATION = "animation" @@ -20,3 +20,6 @@ class Genre(Enum): THRILLER = "thriller" WAR = "war" WESTERN = "western" + + def to_kyoo(self): + return {"name": self} diff --git a/scanner/providers/types/movie.py b/scanner/providers/types/movie.py index 72af578e..de22dfe1 100644 --- a/scanner/providers/types/movie.py +++ b/scanner/providers/types/movie.py @@ -3,8 +3,10 @@ from dataclasses import asdict, dataclass, field from datetime import date from typing import Optional + from .genre import Genre from .status import Status +from .studio import Studio from .metadataid import MetadataID @@ -28,7 +30,7 @@ class Movie: release_date: Optional[date | int] = None status: Status = Status.UNKNOWN path: Optional[str] = None - studios: list[str] = field(default_factory=list) + studios: list[Studio] = field(default_factory=list) genres: list[Genre] = field(default_factory=list) # TODO: handle staff # staff: list[Staff] @@ -36,6 +38,13 @@ class Movie: translations: dict[str, MovieTranslation] = field(default_factory=dict) + def format_date(self, date: date | int | None) -> str | None: + if date is None: + return None + if isinstance(date, int): + return f"{date}-01-01T00:00:00Z" + return date.isoformat() + def to_kyoo(self): # For now, the API of kyoo only support one language so we remove the others. default_language = os.environ["LIBRARY_LANGUAGES"].split(",")[0] @@ -43,11 +52,15 @@ class Movie: **asdict(self), **asdict(self.translations[default_language]), "poster": next(iter(self.translations[default_language].posters), None), - "thumbnail": next(iter(self.translations[default_language].thumbnails), None), + "thumbnail": next( + iter(self.translations[default_language].thumbnails), 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), - "startAir": self.release_date, + "studio": next(iter(x.to_kyoo() for x in self.studios), None), + "release_date": None, + "startAir": self.format_date(self.release_date), "title": self.translations[default_language].name, + "genres": [x.to_kyoo() for x in self.genres], "isMovie": True, } diff --git a/scanner/providers/types/studio.py b/scanner/providers/types/studio.py new file mode 100644 index 00000000..28a608a7 --- /dev/null +++ b/scanner/providers/types/studio.py @@ -0,0 +1,13 @@ +from dataclasses import asdict, dataclass, field + +from .metadataid import MetadataID + + +@dataclass +class Studio: + name: str + logos: list[str] = field(default_factory=list) + external_id: dict[str, MetadataID] = field(default_factory=dict) + + def to_kyoo(self): + return asdict(self) diff --git a/scanner/scanner/scanner.py b/scanner/scanner/scanner.py index c682c0d5..8916b6a0 100644 --- a/scanner/scanner/scanner.py +++ b/scanner/scanner/scanner.py @@ -45,9 +45,9 @@ class Scanner: movie = await self.provider.identify_movie( raw["title"], raw.get("year"), language=self.languages ) + movie.path = str(path) logging.debug("Got movie: %s", movie) await self.post("movies", data=movie.to_kyoo()) - movie.path = str(path) elif raw["type"] == "episode": pass else: