From f9d6a816b04881d489c895fce2610c3a93730fde Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 7 Jan 2024 20:48:34 +0100 Subject: [PATCH] Compute absolute ordering from normal seasons --- .../implementations/themoviedatabase.py | 41 ++++++++++++------- scanner/providers/types/season.py | 3 ++ scanner/scanner/cache.py | 2 +- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/scanner/providers/implementations/themoviedatabase.py b/scanner/providers/implementations/themoviedatabase.py index 84c86019..99ac4bb0 100644 --- a/scanner/providers/implementations/themoviedatabase.py +++ b/scanner/providers/implementations/themoviedatabase.py @@ -3,9 +3,10 @@ import logging from aiohttp import ClientSession from datetime import datetime, timedelta from typing import Awaitable, Callable, Dict, List, Optional, Any, TypeVar +from itertools import accumulate + from providers.idmapper import IdMapper from providers.implementations.thexem import TheXem - from providers.utils import ProviderError from scanner.cache import cache @@ -134,7 +135,6 @@ class TheMovieDatabase(Provider): }, ) logging.debug("TMDb responded: %s", movie) - # TODO: Use collection data ret = Movie( original_language=movie["original_language"], @@ -350,6 +350,7 @@ class TheMovieDatabase(Provider): ) -> Season: return Season( season_number=season["season_number"], + episodes_count=season["episode_count"], start_air=datetime.strptime(season["air_date"], "%Y-%m-%d").date() if season["air_date"] else None, @@ -458,12 +459,13 @@ class TheMovieDatabase(Provider): ) if season is None or episode_nbr is None: - # Some shows don't have absolute numbering because the default one is absolute on tmdb (for example detetive conan) - season = 1 - episode_nbr = absolute - - if season is None or episode_nbr is None: - raise ProviderError("Could not guess season or episode number of the episode %s %d-%d (%d)", name, season, episode_nbr, absolute) + raise ProviderError( + "Could not guess season or episode number of the episode %s %d-%d (%d)", + name, + season, + episode_nbr, + absolute, + ) if absolute is None: absolute = await self.get_absolute_number(show_id, season, episode_nbr) @@ -575,6 +577,7 @@ class TheMovieDatabase(Provider): logging.exception( "Could not retrieve absolute ordering information", exc_info=e ) + return None async def get_episode_from_absolute(self, show_id: str, absolute: int): absgrp = await self.get_absolute_order(show_id) @@ -584,16 +587,26 @@ class TheMovieDatabase(Provider): season = absgrp[absolute - 1]["season_number"] episode_nbr = absgrp[absolute - 1]["episode_number"] return (season, episode_nbr) - # TODO: if no group exist, simulate one by checking each season ep count and substracting the right amount to get an ep - # This means that we assume that each season should be played in order with no special episodes. - return (None, None) + # We assume that each season should be played in order with no special episodes. + show = await self.identify_show(show_id, original_language=None, language=[]) + seasons = [x.episodes_count for x in show.seasons] + # enumerate(accumulate(season)) return [(0, 12), (1, 24)] if the show has two seasons with 12 eps + # we take the last group that has less total episodes than the absolute number. + (season, total_ep_count) = next( + (snbr, ep_cnt) + for snbr, ep_cnt in reversed(list(enumerate(accumulate(seasons)))) + if ep_cnt <= absolute + ) + return (show.seasons[season].season_number, absolute - total_ep_count) async def get_absolute_number(self, show_id: str, season: int, episode_nbr: int): absgrp = await self.get_absolute_order(show_id) if absgrp is None: - # TODO: if no group exist, simulate one by checking each season ep count and adding the right amount to get an ep - # This means that we assume that each season should be played in order with no special episodes. - return None + # We assume that each season should be played in order with no special episodes. + show = await self.identify_show( + show_id, original_language=None, language=[] + ) + return sum(x.episodes_count for x in show.seasons[:season]) + episode_nbr return next( ( # The + 1 is to go from 0based index to 1based absolute number diff --git a/scanner/providers/types/season.py b/scanner/providers/types/season.py index 0f3682e5..0c224ece 100644 --- a/scanner/providers/types/season.py +++ b/scanner/providers/types/season.py @@ -17,6 +17,9 @@ class SeasonTranslation: @dataclass class Season: 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) diff --git a/scanner/scanner/cache.py b/scanner/scanner/cache.py index ad5d4fe1..b21a9851 100644 --- a/scanner/scanner/cache.py +++ b/scanner/scanner/cache.py @@ -29,7 +29,7 @@ def cache(ttl: timedelta, cache: Cache={}, typed=False): ret = cache.get(key, (None, None, None)) if ret[2] is None: # ret[2] can be None if the cached method failed. if that is the case, run again. - return wrapper(*args, **kwargs) + return await wrapper(*args, **kwargs) return ret[2] # Return the cached result if it exits and is not expired if (