diff --git a/scanner/providers/types/collection.py b/scanner/providers/types/collection.py deleted file mode 100644 index c6d01603..00000000 --- a/scanner/providers/types/collection.py +++ /dev/null @@ -1,35 +0,0 @@ -from dataclasses import asdict, dataclass, field -from typing import Optional - -from providers.utils import ProviderError, select_translation, select_image - -from .metadataid import MetadataID - - -@dataclass -class CollectionTranslation: - name: str - overview: Optional[str] = None - posters: list[str] = field(default_factory=list) - logos: list[str] = field(default_factory=list) - thumbnails: list[str] = field(default_factory=list) - - -@dataclass -class Collection: - external_id: dict[str, MetadataID] - translations: dict[str, CollectionTranslation] = field(default_factory=dict) - - def to_kyoo(self): - trans = select_translation(self) - if trans is None: - raise ProviderError( - "Could not find translations for the collection. Aborting" - ) - return { - **asdict(self), - **asdict(trans), - "poster": select_image(self, "posters"), - "thumbnail": select_image(self, "thumbnails"), - "logo": select_image(self, "logos"), - } diff --git a/scanner/providers/types/genre.py b/scanner/providers/types/genre.py deleted file mode 100644 index d596a2f2..00000000 --- a/scanner/providers/types/genre.py +++ /dev/null @@ -1,31 +0,0 @@ -from enum import Enum - - -class Genre(str, Enum): - ACTION = "Action" - ADVENTURE = "Adventure" - ANIMATION = "Animation" - COMEDY = "Comedy" - CRIME = "Crime" - DOCUMENTARY = "Documentary" - DRAMA = "Drama" - FAMILY = "Family" - FANTASY = "Fantasy" - HISTORY = "History" - HORROR = "Horror" - MUSIC = "Music" - MYSTERY = "Mystery" - ROMANCE = "Romance" - SCIENCE_FICTION = "ScienceFiction" - THRILLER = "Thriller" - WAR = "War" - WESTERN = "Western" - KIDS = "Kids" - NEWS = "News" - REALITY = "Reality" - SOAP = "Soap" - TALK = "Talk" - POLITICS = "Politics" - - def to_kyoo(self): - return self.value diff --git a/scanner/providers/utils.py b/scanner/providers/utils.py deleted file mode 100644 index ddcc4ffb..00000000 --- a/scanner/providers/utils.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -import os -from datetime import date -from itertools import chain -from langcodes import Language -from typing import TYPE_CHECKING, Literal, Any, Optional - -if TYPE_CHECKING: - from providers.types.movie import Movie - from providers.types.show import Show - from providers.types.season import Season - from providers.types.episode import Episode - from providers.types.collection import Collection - - -def format_date(date: date | int | None) -> str | None: - if date is None: - return None - if isinstance(date, int): - return f"{date}-01-01" - return date.isoformat() - - -def normalize_lang(lang: str) -> str: - return str(Language.get(lang)) - - -# For now, the API of kyoo only support one language so we remove the others. -default_languages = os.environ.get("LIBRARY_LANGUAGES", "").split(",") -media_prefer_original_language = ( - os.environ.get("MEDIA_PREFER_ORIGINAL_LANGUAGE", "false").lower() == "true" -) - - -def sort_translations( - value: Movie | Show | Season | Episode | Collection, - *, - prefer_orginal=False, -): - from providers.types.movie import Movie - from providers.types.show import Show - - if ( - prefer_orginal - and (isinstance(value, Movie) or isinstance(value, Show)) - and value.original_language - and value.original_language in value.translations - ): - yield value.translations[value.original_language] - for lang in default_languages: - if lang in value.translations: - yield value.translations[lang] - - -def select_translation( - value: Movie | Show | Season | Episode | Collection, *, prefer_orginal=False -) -> Optional[Any]: - return next(sort_translations(value, prefer_orginal=prefer_orginal), None) - - -def select_image( - value: Movie | Show | Season | Collection, - kind: Literal["posters", "thumbnails", "logos", "trailers"], -) -> str | None: - return next( - chain( - *( - getattr(trans, kind) - for trans in sort_translations( - value, prefer_orginal=media_prefer_original_language - ) - ) - ), - None, - ) - - -class ProviderError(RuntimeError): - def __init__(self, *args: object) -> None: - super().__init__(*args) diff --git a/scanner/scanner/models/collection.py b/scanner/scanner/models/collection.py new file mode 100644 index 00000000..58a237c4 --- /dev/null +++ b/scanner/scanner/models/collection.py @@ -0,0 +1,32 @@ +from dataclasses import asdict, dataclass, field +from typing import Optional + +from providers.types.genre import Genre +from .metadataid import MetadataID + + +@dataclass +class CollectionTranslation: + name: str + descrpition: Optional[str] + tagline: Optional[str] + aliases: Optional[str] + tags: Optional[str] + + posters: list[str] + thumbnails: list[str] + banner: list[str] + logos: list[str] + + +@dataclass +class Collection: + slug: str + original_language: str + genres: list[Genre] + rating: Optional[int] + external_id: dict[str, MetadataID] + translations: dict[str, CollectionTranslation] = field(default_factory=dict) + + def to_kyoo(self): + return asdict(self) diff --git a/scanner/providers/types/episode.py b/scanner/scanner/models/episode.py similarity index 100% rename from scanner/providers/types/episode.py rename to scanner/scanner/models/episode.py diff --git a/scanner/scanner/models/genre.py b/scanner/scanner/models/genre.py new file mode 100644 index 00000000..652f702e --- /dev/null +++ b/scanner/scanner/models/genre.py @@ -0,0 +1,30 @@ +from enum import Enum + + +class Genre(str, Enum): + ACTION = "action" + ADVENTURE = "adventure" + ANIMATION = "animation" + COMEDY = "comedy" + CRIME = "crime" + DOCUMENTARY = "documentary" + DRAMA = "drama" + FAMILY = "family" + FANTASY = "fantasy" + HISTORY = "history" + HORROR = "horror" + MUSIC = "music" + MYSTERY = "mystery" + ROMANCE = "romance" + SCIENCE_FICTION = "science-fiction" + THRILLER = "thriller" + WAR = "war" + WESTERN = "western" + KIDS = "kids" + REALITY = "reality" + POLITICS = "politics" + SOAP = "soap" + TALK = "talk" + + def to_kyoo(self): + return self.value diff --git a/scanner/providers/types/metadataid.py b/scanner/scanner/models/metadataid.py similarity index 67% rename from scanner/providers/types/metadataid.py rename to scanner/scanner/models/metadataid.py index a4944400..87bfc915 100644 --- a/scanner/providers/types/metadataid.py +++ b/scanner/scanner/models/metadataid.py @@ -6,6 +6,3 @@ from typing import Optional class MetadataID: data_id: str link: Optional[str] - - def __post_init__(self): - self.data_id = str(self.data_id) diff --git a/scanner/providers/types/movie.py b/scanner/scanner/models/movie.py similarity index 100% rename from scanner/providers/types/movie.py rename to scanner/scanner/models/movie.py diff --git a/scanner/providers/types/season.py b/scanner/scanner/models/season.py similarity index 100% rename from scanner/providers/types/season.py rename to scanner/scanner/models/season.py diff --git a/scanner/providers/types/show.py b/scanner/scanner/models/show.py similarity index 100% rename from scanner/providers/types/show.py rename to scanner/scanner/models/show.py diff --git a/scanner/providers/types/studio.py b/scanner/scanner/models/studio.py similarity index 100% rename from scanner/providers/types/studio.py rename to scanner/scanner/models/studio.py diff --git a/scanner/scanner/utils.py b/scanner/scanner/utils.py new file mode 100644 index 00000000..dc76e680 --- /dev/null +++ b/scanner/scanner/utils.py @@ -0,0 +1,28 @@ +from pydantic import BaseModel, ConfigDict +from pydantic.alias_generators import to_camel +from datetime import date +from langcodes import Language + + +def format_date(date: date | int | None) -> str | None: + if date is None: + return None + if isinstance(date, int): + return f"{date}-01-01" + return date.isoformat() + + +def normalize_lang(lang: str) -> str: + return str(Language.get(lang)) + + +class ProviderError(RuntimeError): + def __init__(self, *args: object) -> None: + super().__init__(*args) + + +class Model(BaseModel): + model_config = ConfigDict( + use_enum_values=True, + alias_generator=to_camel, + )