mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add episode and show types
This commit is contained in:
parent
8ac5f02d93
commit
a9ce596381
@ -9,7 +9,7 @@ from providers.types.metadataid import MetadataID
|
||||
|
||||
from ..provider import Provider
|
||||
from ..types.movie import Movie, MovieTranslation
|
||||
from ..types.status import Status
|
||||
from ..types.episode import Episode
|
||||
from ..types.studio import Studio
|
||||
|
||||
|
||||
@ -138,3 +138,15 @@ class TheMovieDatabase(Provider):
|
||||
movie = movies[0]
|
||||
movie.translations = {k: v.translations[k] for k, v in zip(language, movies)}
|
||||
return movie
|
||||
|
||||
|
||||
async def identify_episode(
|
||||
self,
|
||||
name: str,
|
||||
season: Optional[int],
|
||||
episode: Optional[int],
|
||||
absolute: Optional[int],
|
||||
*,
|
||||
language: list[str]
|
||||
) -> Episode:
|
||||
raise NotImplementedError
|
||||
|
@ -3,6 +3,7 @@ from aiohttp import ClientSession
|
||||
from abc import abstractmethod
|
||||
from typing import Optional, TypeVar
|
||||
|
||||
from .types.episode import Episode
|
||||
from .types.movie import Movie
|
||||
|
||||
|
||||
@ -27,3 +28,15 @@ class Provider:
|
||||
self, name: str, year: Optional[int], *, language: list[str]
|
||||
) -> Movie:
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
async def identify_episode(
|
||||
self,
|
||||
name: str,
|
||||
season: Optional[int],
|
||||
episode: Optional[int],
|
||||
absolute: Optional[int],
|
||||
*,
|
||||
language: list[str]
|
||||
) -> Episode:
|
||||
raise NotImplementedError
|
||||
|
26
scanner/providers/types/episode.py
Normal file
26
scanner/providers/types/episode.py
Normal file
@ -0,0 +1,26 @@
|
||||
from datetime import date
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from .show import Show
|
||||
from .season import Season
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
@dataclass
|
||||
class EpisodeTranslation:
|
||||
name: str
|
||||
overview: Optional[str]
|
||||
thumbnails: list[str]
|
||||
|
||||
@dataclass
|
||||
class Episode:
|
||||
show: Show | dict[str, MetadataID]
|
||||
season: Optional[Season]
|
||||
episode_number: Optional[int]
|
||||
absolute_number: Optional[int]
|
||||
release_date: Optional[date | int]
|
||||
path: Optional[str]
|
||||
external_id: dict[str, MetadataID]
|
||||
|
||||
translations: dict[str, EpisodeTranslation] = field(default_factory=dict)
|
@ -2,14 +2,19 @@ import os
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from .genre import Genre
|
||||
from .status import Status
|
||||
from .studio import Studio
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
class Status(str, Enum):
|
||||
UNKNOWN = "unknown"
|
||||
FINISHED = "finished"
|
||||
PLANNED = "planned"
|
||||
|
||||
|
||||
@dataclass
|
||||
class MovieTranslation:
|
||||
name: str
|
||||
|
25
scanner/providers/types/season.py
Normal file
25
scanner/providers/types/season.py
Normal file
@ -0,0 +1,25 @@
|
||||
from datetime import date
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
|
||||
from .show import Show
|
||||
from .metadataid import MetadataID
|
||||
|
||||
|
||||
@dataclass
|
||||
class SeasonTranslation:
|
||||
name: Optional[str]
|
||||
overview: Optional[str]
|
||||
poster: list[str]
|
||||
thumbnails: list[str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Season:
|
||||
show: Show | dict[str, MetadataID]
|
||||
season_number: int
|
||||
start_date: Optional[date | int]
|
||||
end_date: Optional[date | int]
|
||||
external_id: dict[str, MetadataID]
|
||||
|
||||
translations: dict[str, SeasonTranslation] = field(default_factory=dict)
|
71
scanner/providers/types/show.py
Normal file
71
scanner/providers/types/show.py
Normal file
@ -0,0 +1,71 @@
|
||||
import os
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
from enum import Enum
|
||||
|
||||
|
||||
from .genre import Genre
|
||||
from .studio import Studio
|
||||
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
|
||||
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)
|
||||
thumbnails: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Show:
|
||||
original_language: Optional[str] = None
|
||||
aliases: list[str] = field(default_factory=list)
|
||||
start_air: Optional[date | int] = None
|
||||
end_air: Optional[date | int] = None
|
||||
status: Status = Status.UNKNOWN
|
||||
studios: list[Studio] = field(default_factory=list)
|
||||
genres: list[Genre] = field(default_factory=list)
|
||||
# TODO: handle staff
|
||||
# staff: list[Staff]
|
||||
external_id: dict[str, MetadataID] = field(default_factory=dict)
|
||||
|
||||
translations: dict[str, ShowTranslation] = 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]
|
||||
return {
|
||||
**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
|
||||
),
|
||||
"logo": next(iter(self.translations[default_language].logos), None),
|
||||
"trailer": next(iter(self.translations[default_language].trailers), None),
|
||||
"studio": next(iter(x.to_kyoo() for x in self.studios), None),
|
||||
"startAir": self.format_date(self.start_air),
|
||||
"endAir": self.format_date(self.end_air),
|
||||
"title": self.translations[default_language].name,
|
||||
"genres": [x.to_kyoo() for x in self.genres],
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class Status(str, Enum):
|
||||
UNKNOWN = "unknown"
|
||||
FINISHED = "finished"
|
||||
AIRING = "airing"
|
||||
PLANNED = "planned"
|
@ -35,12 +35,14 @@ class Scanner:
|
||||
|
||||
@log_errors
|
||||
async def identify(self, path: Path):
|
||||
raw = guessit(path)
|
||||
raw = guessit(path, "--episode-prefer-number")
|
||||
logging.info("Identied %s: %s", path, raw)
|
||||
|
||||
# TODO: check if episode/movie already exists in kyoo and skip if it does.
|
||||
# TODO: keep a list of processing shows to only fetch metadata once even if
|
||||
# multiples identify of the same show run on the same time
|
||||
|
||||
# TODO: Add collections support
|
||||
if raw["type"] == "movie":
|
||||
movie = await self.provider.identify_movie(
|
||||
raw["title"], raw.get("year"), language=self.languages
|
||||
@ -49,7 +51,17 @@ class Scanner:
|
||||
logging.debug("Got movie: %s", movie)
|
||||
await self.post("movies", data=movie.to_kyoo())
|
||||
elif raw["type"] == "episode":
|
||||
pass
|
||||
# TODO: Identify shows & seasons too.
|
||||
episode = await self.provider.identify_episode(
|
||||
raw["title"],
|
||||
season=raw.get("season"),
|
||||
episode=raw.get("episode"),
|
||||
absolute=raw.get("episode") if "season" not in raw else None,
|
||||
language=self.languages,
|
||||
)
|
||||
episode.path = str(path)
|
||||
logging.debug("Got episode: %s", episode)
|
||||
await self.post("episodes", data=episode.to_kyoo())
|
||||
else:
|
||||
logging.warn("Unknown video file type: %s", raw["type"])
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user