mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Type series & all related types
This commit is contained in:
parent
356b4c0c33
commit
2f00e52857
@ -56,7 +56,7 @@ export type MovieEntry = Prettify<typeof MovieEntry.static>;
|
||||
export const SeedMovieEntry = t.Composite([
|
||||
t.Omit(BaseMovieEntry, ["thumbnail", "nextRefresh"]),
|
||||
t.Object({
|
||||
slug: t.Optional(t.String({ format: "slug" })),
|
||||
slug: t.Optional(t.Nullable(t.String({ format: "slug" }))),
|
||||
thumbnail: t.Nullable(SeedImage),
|
||||
translations: TranslationRecord(
|
||||
t.Intersect([
|
||||
|
@ -41,7 +41,7 @@ async def identify(path: str) -> Video:
|
||||
|
||||
guess = Guess(
|
||||
title=cast(str, title.value),
|
||||
kind=cast(Literal["episode"] | Literal["movie"], kind.value),
|
||||
kind=cast(Literal["episode", "movie"], kind.value),
|
||||
extra_kind=None,
|
||||
years=[cast(int, y.value) for y in years],
|
||||
episodes=[
|
||||
|
@ -25,7 +25,7 @@ class CollectionTranslation(Model):
|
||||
aliases: list[str]
|
||||
tags: list[str]
|
||||
|
||||
posters: list[str]
|
||||
thumbnails: list[str]
|
||||
banner: list[str]
|
||||
logos: list[str]
|
||||
poster: str | None
|
||||
thumbnail: str | None
|
||||
banner: str | None
|
||||
logo: str | None
|
||||
|
36
scanner/scanner/models/entry.py
Normal file
36
scanner/scanner/models/entry.py
Normal file
@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from typing import Literal
|
||||
|
||||
from ..utils import Model
|
||||
from .metadataid import EpisodeId, MetadataId
|
||||
|
||||
|
||||
class Entry(Model):
|
||||
kind: Literal["episode", "movie", "special"]
|
||||
order: float
|
||||
runtime: int | None = None
|
||||
air_date: date | None = None
|
||||
thumbnail: str | None = None
|
||||
|
||||
# Movie-specific fields
|
||||
slug: str | None = None
|
||||
|
||||
# Episode-specific fields
|
||||
season_number: int | None = None
|
||||
episode_number: int | None = None
|
||||
|
||||
# Special-specific fields
|
||||
number: int | None = None
|
||||
|
||||
externalId: dict[str, MetadataId | EpisodeId]
|
||||
translations: dict[str, EntryTranslation] = {}
|
||||
videos: list[str] = []
|
||||
|
||||
|
||||
class EntryTranslation(Model):
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
tagline: str | None = None
|
||||
poster: str | None = None
|
@ -1,54 +0,0 @@
|
||||
from datetime import date
|
||||
from dataclasses import dataclass, field, asdict
|
||||
from typing import Optional
|
||||
|
||||
from providers.utils import select_translation
|
||||
|
||||
from .show import Show
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
@dataclass
|
||||
class PartialShow:
|
||||
name: str
|
||||
original_language: Optional[str]
|
||||
external_id: dict[str, MetadataID]
|
||||
|
||||
|
||||
@dataclass
|
||||
class EpisodeID:
|
||||
show_id: str
|
||||
season: Optional[int]
|
||||
episode: int
|
||||
link: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class EpisodeTranslation:
|
||||
name: Optional[str]
|
||||
overview: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Episode:
|
||||
show: Show | PartialShow
|
||||
season_number: int
|
||||
episode_number: int
|
||||
absolute_number: int
|
||||
runtime: Optional[int]
|
||||
release_date: Optional[date | int]
|
||||
thumbnail: Optional[str]
|
||||
external_id: dict[str, EpisodeID]
|
||||
|
||||
path: Optional[str] = None
|
||||
show_id: Optional[str] = None
|
||||
season_id: Optional[str] = None
|
||||
translations: dict[str, EpisodeTranslation] = field(default_factory=dict)
|
||||
|
||||
def to_kyoo(self):
|
||||
trans = select_translation(self) or EpisodeTranslation("")
|
||||
return {
|
||||
**asdict(self),
|
||||
**asdict(trans),
|
||||
"show": None,
|
||||
}
|
@ -1,10 +1,21 @@
|
||||
from typing import Literal
|
||||
from enum import Enum
|
||||
|
||||
type ExtraKind = (
|
||||
Literal["other"]
|
||||
| Literal["trailer"]
|
||||
| Literal["interview"]
|
||||
| Literal["behind-the-scene"]
|
||||
| Literal["deleted-scene"]
|
||||
| Literal["blooper"]
|
||||
)
|
||||
from ..utils import Model
|
||||
|
||||
|
||||
class ExtraKind(str, Enum):
|
||||
OTHER = "other"
|
||||
TRAILER = "trailer"
|
||||
INTERVIEW = "interview"
|
||||
BEHIND_THE_SCENE = "behind-the-scene"
|
||||
DELETED_SCENE = "deleted-scene"
|
||||
BLOOPER = "blooper"
|
||||
|
||||
|
||||
class Extra(Model):
|
||||
kind: ExtraKind
|
||||
slug: str
|
||||
name: str
|
||||
runtime: int | None
|
||||
thumbnail: str | None
|
||||
video: str
|
||||
|
@ -13,7 +13,7 @@ from .staff import Staff
|
||||
from .studio import Studio
|
||||
|
||||
|
||||
class Status(str, Enum):
|
||||
class MovieStatus(str, Enum):
|
||||
UNKNOWN = "unknown"
|
||||
FINISHED = "finished"
|
||||
PLANNED = "planned"
|
||||
@ -24,7 +24,7 @@ class Movie(Model):
|
||||
original_language: Language | None
|
||||
genres: list[Genre]
|
||||
rating: int | None
|
||||
status: Status
|
||||
status: MovieStatus
|
||||
runtime: int | None
|
||||
air_date: date | None
|
||||
|
||||
@ -44,11 +44,11 @@ class MovieTranslation(Model):
|
||||
aliases: list[str]
|
||||
tags: list[str]
|
||||
|
||||
posters: list[str]
|
||||
thumbnails: list[str]
|
||||
banner: list[str]
|
||||
logos: list[str]
|
||||
trailers: list[str]
|
||||
poster: str | None
|
||||
thumbnail: str | None
|
||||
banner: str | None
|
||||
logo: str | None
|
||||
trailer: str | None
|
||||
|
||||
|
||||
class SearchMovie(Model):
|
||||
|
@ -1,38 +1,22 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from dataclasses import dataclass, field, asdict
|
||||
from typing import Optional
|
||||
|
||||
from providers.utils import select_translation, select_image
|
||||
|
||||
from .metadataid import MetadataID
|
||||
from ..utils import Model
|
||||
from .metadataid import MetadataId
|
||||
|
||||
|
||||
@dataclass
|
||||
class SeasonTranslation:
|
||||
name: Optional[str] = None
|
||||
overview: Optional[str] = None
|
||||
posters: list[str] = field(default_factory=list)
|
||||
thumbnails: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Season:
|
||||
class Season(Model):
|
||||
season_number: int
|
||||
# This is not used by kyoo, this is just used internaly by the TMDB provider.
|
||||
# maybe this should be moved?
|
||||
episodes_count: int
|
||||
start_air: Optional[date | int] = None
|
||||
end_air: Optional[date | int] = None
|
||||
external_id: dict[str, MetadataID] = field(default_factory=dict)
|
||||
start_air: date | None
|
||||
end_air: date | None
|
||||
external_id: dict[str, MetadataId]
|
||||
translations: dict[str, SeasonTranslation] = {}
|
||||
|
||||
show_id: Optional[str] = None
|
||||
translations: dict[str, SeasonTranslation] = field(default_factory=dict)
|
||||
|
||||
def to_kyoo(self):
|
||||
trans = select_translation(self) or SeasonTranslation()
|
||||
return {
|
||||
**asdict(self),
|
||||
**asdict(trans),
|
||||
"poster": select_image(self, "posters"),
|
||||
"thumbnail": select_image(self, "thumbnails"),
|
||||
}
|
||||
class SeasonTranslation(Model):
|
||||
name: str | None
|
||||
description: str | None
|
||||
poster: str | None
|
||||
thumbnail: str | None
|
||||
banner: str | None
|
||||
|
69
scanner/scanner/models/serie.py
Normal file
69
scanner/scanner/models/serie.py
Normal file
@ -0,0 +1,69 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from enum import Enum
|
||||
|
||||
from langcodes import Language
|
||||
|
||||
from ..utils import Model
|
||||
from .collection import Collection
|
||||
from .entry import Entry
|
||||
from .extra import Extra
|
||||
from .genre import Genre
|
||||
from .metadataid import MetadataId
|
||||
from .season import Season
|
||||
from .staff import Staff
|
||||
from .studio import Studio
|
||||
|
||||
|
||||
class SerieStatus(str, Enum):
|
||||
UNKNOWN = "unknown"
|
||||
FINISHED = "finished"
|
||||
AIRING = "airing"
|
||||
PLANNED = "planned"
|
||||
|
||||
|
||||
class Serie(Model):
|
||||
slug: str
|
||||
original_language: Language | None
|
||||
genres: list[Genre]
|
||||
rating: int | None
|
||||
status: SerieStatus
|
||||
runtime: int | None
|
||||
start_air: date | None
|
||||
end_air: date | None
|
||||
|
||||
external_id: dict[str, MetadataId]
|
||||
translations: dict[str, SerieTranslation] = {}
|
||||
seasons: list[Season] = []
|
||||
entries: list[Entry] = []
|
||||
extra: list[Extra] = []
|
||||
collections: list[Collection] = []
|
||||
studios: list[Studio] = []
|
||||
staff: list[Staff] = []
|
||||
|
||||
|
||||
class SerieTranslation(Model):
|
||||
name: str
|
||||
latin_name: str | None
|
||||
description: str | None
|
||||
tagline: str | None
|
||||
aliases: list[str]
|
||||
tags: list[str]
|
||||
|
||||
poster: str | None
|
||||
thumbnail: str | None
|
||||
banner: str | None
|
||||
logo: str | None
|
||||
trailer: str | None
|
||||
|
||||
|
||||
class SearchSerie(Model):
|
||||
slug: str
|
||||
name: str
|
||||
description: str | None
|
||||
start_air: date | None
|
||||
end_air: date | None
|
||||
poster: str
|
||||
original_language: Language | None
|
||||
external_id: dict[str, MetadataId]
|
@ -1,67 +0,0 @@
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
from enum import Enum
|
||||
|
||||
from providers.utils import select_translation, select_image
|
||||
|
||||
from .genre import Genre
|
||||
from .studio import Studio
|
||||
from .season import Season
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
class Status(str, Enum):
|
||||
UNKNOWN = "unknown"
|
||||
FINISHED = "finished"
|
||||
AIRING = "airing"
|
||||
PLANNED = "planned"
|
||||
|
||||
|
||||
@dataclass
|
||||
class ShowTranslation:
|
||||
name: str
|
||||
tagline: Optional[str] = None
|
||||
tags: 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)
|
||||
thumbnails: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Show:
|
||||
original_language: Optional[str]
|
||||
aliases: list[str]
|
||||
start_air: Optional[date | int]
|
||||
end_air: Optional[date | int]
|
||||
status: Status
|
||||
rating: Optional[int]
|
||||
studios: list[Studio]
|
||||
genres: list[Genre]
|
||||
seasons: list[Season]
|
||||
# TODO: handle staff
|
||||
# staff: list[Staff]
|
||||
external_id: dict[str, MetadataID]
|
||||
|
||||
translations: dict[str, ShowTranslation] = field(default_factory=dict)
|
||||
# The title of this show according to it's filename (None only for ease of use in providers)
|
||||
file_title: Optional[str] = None
|
||||
|
||||
def to_kyoo(self):
|
||||
trans = select_translation(self) or ShowTranslation(name=self.file_title or "")
|
||||
return {
|
||||
**asdict(self),
|
||||
**asdict(trans),
|
||||
"rating": self.rating or 0,
|
||||
"studio": next((x.to_kyoo() for x in self.studios), None),
|
||||
"seasons": None,
|
||||
"poster": select_image(self, "posters"),
|
||||
"thumbnail": select_image(self, "thumbnails"),
|
||||
"logo": select_image(self, "logos"),
|
||||
"trailer": select_image(self, "trailers"),
|
||||
"genres": [x.to_kyoo() for x in self.genres],
|
||||
"file_title": None,
|
||||
}
|
@ -38,7 +38,9 @@ class CompositeProvider(Provider):
|
||||
raise ProviderError(
|
||||
f"Couldn't find a movie with title {title}. (year: {year}"
|
||||
)
|
||||
ret = await self.get_movie(search[0].external_id)
|
||||
ret = await self.get_movie(
|
||||
{k: v.data_id for k, v in search[0].external_id.items()}
|
||||
)
|
||||
if not ret:
|
||||
raise ValueError()
|
||||
return ret
|
||||
@ -68,4 +70,9 @@ class CompositeProvider(Provider):
|
||||
raise ProviderError(
|
||||
f"Couldn't find a serie with title {title}. (year: {year}"
|
||||
)
|
||||
return await self.get_serie(search[0].external_id)
|
||||
ret = await self.get_serie(
|
||||
{k: v.data_id for k, v in search[0].external_id.items()}
|
||||
)
|
||||
if not ret:
|
||||
raise ValueError()
|
||||
return ret
|
||||
|
@ -4,12 +4,12 @@ from typing import Literal
|
||||
|
||||
from .client import KyooClient
|
||||
from .models.videos import Guess
|
||||
from .utils import Model
|
||||
from .providers.composite import CompositeProvider
|
||||
from .utils import Model
|
||||
|
||||
|
||||
class Request(Model):
|
||||
kind: Literal["episode"] | Literal["movie"]
|
||||
kind: Literal["episode", "movie"]
|
||||
title: str
|
||||
year: int | None
|
||||
external_id: dict[str, str]
|
||||
@ -39,7 +39,9 @@ class RequestProcessor:
|
||||
request: Request = ...
|
||||
|
||||
if request.kind == "movie":
|
||||
movie = await providers.get_movie(request.title, request.year, request.external_id)
|
||||
movie = await providers.get_movie(
|
||||
request.title, request.year, request.external_id
|
||||
)
|
||||
movie.videos = request.videos
|
||||
await self._client.create_movie(movie)
|
||||
else:
|
||||
|
Loading…
x
Reference in New Issue
Block a user