Add genres and studio objects for the scanner

This commit is contained in:
Zoe Roux 2023-03-23 20:59:54 +09:00
parent c894f33c11
commit 10b291b4aa
8 changed files with 67 additions and 8 deletions

View File

@ -23,6 +23,7 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Postgresql; using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers namespace Kyoo.Core.Controllers
@ -61,6 +62,13 @@ namespace Kyoo.Core.Controllers
.ToListAsync(); .ToListAsync();
} }
/// <inheritdoc />
protected override async Task Validate(Genre resource)
{
resource.Slug ??= Utility.ToSlug(resource.Name);
await base.Validate(resource);
}
/// <inheritdoc /> /// <inheritdoc />
public override async Task<Genre> Create(Genre obj) public override async Task<Genre> Create(Genre obj)
{ {

View File

@ -23,6 +23,7 @@ using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Postgresql; using Kyoo.Postgresql;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Kyoo.Core.Controllers namespace Kyoo.Core.Controllers
@ -80,6 +81,8 @@ namespace Kyoo.Core.Controllers
/// <inheritdoc /> /// <inheritdoc />
protected override async Task Validate(Studio resource) protected override async Task Validate(Studio resource)
{ {
resource.Slug ??= Utility.ToSlug(resource.Name);
await base.Validate(resource); await base.Validate(resource);
if (resource.ExternalIDs != null) if (resource.ExternalIDs != null)
{ {

View File

@ -10,6 +10,7 @@ from providers.types.metadataid import MetadataID
from ..provider import Provider from ..provider import Provider
from ..types.movie import Movie, MovieTranslation from ..types.movie import Movie, MovieTranslation
from ..types.status import Status from ..types.status import Status
from ..types.studio import Studio
class TheMovieDatabase(Provider): class TheMovieDatabase(Provider):
@ -84,8 +85,25 @@ class TheMovieDatabase(Provider):
status=Status.FINISHED status=Status.FINISHED
if movie["status"] == "Released" if movie["status"] == "Released"
else Status.PLANNED, else Status.PLANNED,
studios=list(map(lambda x: x["name"], movie["production_companies"])), studios=[
genres=[self.genre_map[x["id"]] for x in movie["genres"] if x["id"] in self.genre_map], 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={ external_id={
"themoviedatabase": MetadataID( "themoviedatabase": MetadataID(
movie["id"], f"https://www.themoviedb.org/movie/{movie['id']}" movie["id"], f"https://www.themoviedb.org/movie/{movie['id']}"

View File

@ -13,6 +13,7 @@ class Provider:
@classmethod @classmethod
def get_all(cls: type[Self], client: ClientSession) -> list[Self]: def get_all(cls: type[Self], client: ClientSession) -> list[Self]:
from providers.implementations.themoviedatabase import TheMovieDatabase from providers.implementations.themoviedatabase import TheMovieDatabase
providers = [] providers = []
tmdb = os.environ.get("THEMOVIEDB_APIKEY") tmdb = os.environ.get("THEMOVIEDB_APIKEY")

View File

@ -1,7 +1,7 @@
from enum import Enum from enum import Enum
class Genre(Enum): class Genre(str, Enum):
ACTION = "action" ACTION = "action"
ADVENTURE = "adventure" ADVENTURE = "adventure"
ANIMATION = "animation" ANIMATION = "animation"
@ -20,3 +20,6 @@ class Genre(Enum):
THRILLER = "thriller" THRILLER = "thriller"
WAR = "war" WAR = "war"
WESTERN = "western" WESTERN = "western"
def to_kyoo(self):
return {"name": self}

View File

@ -3,8 +3,10 @@ from dataclasses import asdict, dataclass, field
from datetime import date from datetime import date
from typing import Optional from typing import Optional
from .genre import Genre from .genre import Genre
from .status import Status from .status import Status
from .studio import Studio
from .metadataid import MetadataID from .metadataid import MetadataID
@ -28,7 +30,7 @@ class Movie:
release_date: Optional[date | int] = None release_date: Optional[date | int] = None
status: Status = Status.UNKNOWN status: Status = Status.UNKNOWN
path: Optional[str] = None 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) genres: list[Genre] = field(default_factory=list)
# TODO: handle staff # TODO: handle staff
# staff: list[Staff] # staff: list[Staff]
@ -36,6 +38,13 @@ class Movie:
translations: dict[str, MovieTranslation] = field(default_factory=dict) 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): def to_kyoo(self):
# For now, the API of kyoo only support one language so we remove the others. # For now, the API of kyoo only support one language so we remove the others.
default_language = os.environ["LIBRARY_LANGUAGES"].split(",")[0] default_language = os.environ["LIBRARY_LANGUAGES"].split(",")[0]
@ -43,11 +52,15 @@ class Movie:
**asdict(self), **asdict(self),
**asdict(self.translations[default_language]), **asdict(self.translations[default_language]),
"poster": next(iter(self.translations[default_language].posters), None), "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), "logo": next(iter(self.translations[default_language].logos), None),
"trailer": next(iter(self.translations[default_language].trailers), None), "trailer": next(iter(self.translations[default_language].trailers), None),
"studio": next(iter(self.studios), None), "studio": next(iter(x.to_kyoo() for x in self.studios), None),
"startAir": self.release_date, "release_date": None,
"startAir": self.format_date(self.release_date),
"title": self.translations[default_language].name, "title": self.translations[default_language].name,
"genres": [x.to_kyoo() for x in self.genres],
"isMovie": True, "isMovie": True,
} }

View File

@ -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)

View File

@ -45,9 +45,9 @@ class Scanner:
movie = await self.provider.identify_movie( movie = await self.provider.identify_movie(
raw["title"], raw.get("year"), language=self.languages raw["title"], raw.get("year"), language=self.languages
) )
movie.path = str(path)
logging.debug("Got movie: %s", movie) logging.debug("Got movie: %s", movie)
await self.post("movies", data=movie.to_kyoo()) await self.post("movies", data=movie.to_kyoo())
movie.path = str(path)
elif raw["type"] == "episode": elif raw["type"] == "episode":
pass pass
else: else: