diff --git a/scanner/scanner/models/entry.py b/scanner/scanner/models/entry.py index ae5cfe56..cbc0bcd9 100644 --- a/scanner/scanner/models/entry.py +++ b/scanner/scanner/models/entry.py @@ -1,7 +1,9 @@ from __future__ import annotations from datetime import date -from typing import Literal +from typing import Any, Literal + +from pydantic import Field from ..utils import Language, Model from .metadataid import EpisodeId, MetadataId @@ -27,6 +29,7 @@ class Entry(Model): external_id: dict[str, MetadataId | EpisodeId] translations: dict[Language, EntryTranslation] = {} videos: list[str] = [] + extra: dict[str, Any] = Field(exclude=True) class EntryTranslation(Model): diff --git a/scanner/scanner/providers/thetvdb.py b/scanner/scanner/providers/thetvdb.py index 2ce6a219..d4a93dfb 100644 --- a/scanner/scanner/providers/thetvdb.py +++ b/scanner/scanner/providers/thetvdb.py @@ -239,8 +239,8 @@ class TVDB(Provider): data_id=ret["id"], link=f"https://thetvdb.com/series/{ret['slug']}", ), - } - | self._process_remote_id(ret["remoteIds"]), + **self._process_remote_id(ret["remoteIds"]), + }, translations={ Language.get(trans["language"]): SerieTranslation( name=trans["name"], @@ -248,7 +248,7 @@ class TVDB(Provider): description=next( ( x["overview"] - for x in ret["translations"]["overviewTranslations"] + for x in (ret["translations"]["overviewTranslations"] or []) if x["language"] == trans["language"] ), None, @@ -398,8 +398,8 @@ class TVDB(Provider): trans = await asyncio.gather(*[fetch_all(lang) for lang in langs]) entries = trans[0] - # TODO: map multiples `order=0` to their appropriate number using `airsAfterSeason, airsBeforeSeason, airsBeforeEpisode` - return [ + + ret = [ Entry( kind="movie" if entry["isMovie"] @@ -436,6 +436,102 @@ class TVDB(Provider): for lang, tl in zip(langs, trans) if "name" in tl[i] and tl[i]["name"] }, + extra={ + "airs_after_season": entry.get("airsAfterSeason"), + "airs_before_season": entry.get("airsBeforeSeason"), + "airs_before_episode": entry.get("airsBeforeEpisode"), + "linked_movie": entry.get("linkedMovie"), + }, ) for i, entry in enumerate(entries) ] + + for i, entry in enumerate(ret): + if entry.extra["linked_movie"]: + ret[i] = await self.process_movie_entry(entry) + + if entry.order != 0: + continue + + if entry.extra["airs_after_season"] is not None: + before = max( + *( + x.order + for x in ret + if x.season_number == entry.extra["airs_after_season"] + ), + 0.0, + ) + after = min(*(x.order for x in ret if x.order > before), before) + entry.order = (before + after) / 2 + elif entry.extra["airs_before_season"] is not None: + before = ( + next( + ( + x.order + for x in ret + if x.season_number == entry.extra["airs_before_season"] + and x.episode_number == entry.extra["airs_before_episode"] + ), + 0, + ) + if entry.extra["airs_before_episode"] + else min( + *( + x.order + for x in ret + if x.season_number == entry.extra["airs_before_season"] + ), + 0, + ) + ) + after = max(*(x.order for x in ret if x.order < before), 0) + entry.order = (after + before) / 2 + + return ret + + async def process_movie_entry(self, entry: Entry) -> Entry: + ret = ( + await self._get( + f"movies/{entry.extra['linked_movie']}/extended", + params={ + "meta": "translations", + }, + ) + )["data"] + + # keep entry's metadata from series api, it's the same. + entry.slug = ret["slug"] + entry.translations = { + Language.get(trans["language"]): EntryTranslation( + name=trans["name"], + description=next( + ( + x["overview"] + for x in ret["translations"]["overviewTranslations"] + if x["language"] == trans["language"] + ), + None, + ), + tagline=trans.get("tagline") + or next( + ( + x.get("tagline") + for x in ret["translations"]["overviewTranslations"] + if x["language"] == trans["language"] + ), + None, + ), + poster=self._pick_image(ret["artworks"], 14, trans["language"]), + ) + for trans in ret["translations"]["nameTranslations"] + } + entry.external_id = { + self.name: MetadataId( + data_id=ret["id"], + link=f"https://thetvdb.com/movies/{ret['slug']}", + ), + **self._process_remote_id(ret["remoteIds"]), + } + + return entry diff --git a/scanner/scanner/requests.py b/scanner/scanner/requests.py index b32036bb..5436888c 100644 --- a/scanner/scanner/requests.py +++ b/scanner/scanner/requests.py @@ -10,7 +10,7 @@ from pydantic import TypeAdapter from .client import KyooClient from .models.request import Request from .models.videos import Resource -from .providers.provider import Provider +from .providers.provider import Provider, ProviderError logger = getLogger(__name__) tracer = trace.get_tracer("kyoo.scanner") @@ -158,7 +158,10 @@ class RequestProcessor: except Exception as e: span.set_status(trace.Status(trace.StatusCode.ERROR)) span.record_exception(e) - logger.error("Couldn't process request", exc_info=e) + if type(e) == ProviderError: + logger.error(str(e)) + else: + logger.error("Couldn't process request", exc_info=e) cur = await self._database.execute( """ update