diff --git a/plextraktsync/pytrakt_extensions.py b/plextraktsync/pytrakt_extensions.py index 7f91a6b4c8..8f2ecf2677 100644 --- a/plextraktsync/pytrakt_extensions.py +++ b/plextraktsync/pytrakt_extensions.py @@ -1,38 +1,4 @@ from trakt.core import get -from trakt.tv import TVEpisode - - -@get -def lookup_table(show): - # returns all seasons and episodes with one single call - data = yield "shows/{}/seasons?extended=episodes".format(show.trakt) - retVal = {} - for season in data: - eps = {} - if "episodes" in season.keys(): - for episode in season["episodes"]: - eps[episode["number"]] = LazyEpisode( - show, season["number"], episode["number"], episode["ids"] - ) - retVal[season["number"]] = eps - yield retVal - - -class LazyEpisode: - def __init__(self, show, season, number, ids): - self.show = show - self.season = season - self.number = number - self.ids = ids - self._instance = None - - @property - def instance(self): - if self._instance is None: - self._instance = TVEpisode( - self.show.title, self.season, number=self.number, **self.ids - ) - return self._instance @get diff --git a/plextraktsync/trakt_api.py b/plextraktsync/trakt_api.py index ab2444a3fe..d363cc9c0f 100644 --- a/plextraktsync/trakt_api.py +++ b/plextraktsync/trakt_api.py @@ -382,17 +382,14 @@ def find_episode_guid(self, guid: PlexGuid, lookup: TraktLookup): """ Find Trakt Episode from Guid of Plex Episode """ - te = lookup.from_number(guid.pm.season_number, guid.pm.episode_number) - if not te or (str(te.ids.get(guid.provider)) != guid.id and not guid.pm.is_legacy_agent): - te = lookup.from_id(guid.provider, guid.id) + te = lookup.from_guid(guid) if te: - return te.instance - else: - # Retry using search for specific Plex Episode - logger.warning(f"Retry using search for specific Plex Episode {guid.guid}") - if not guid.is_episode: - return self.find_by_guid(guid) - return None + return te + + logger.warning(f"Retry using search for specific Plex Episode {guid.guid}") + if not guid.is_episode: + return self.find_by_guid(guid) + return None def flush(self): """ @@ -500,30 +497,43 @@ def remove_empty_values(result): return result +EPISODES_ORDERING_WARNING = "episodes ordering is different in Plex and Trakt. " \ + "Check your Plex media source, TMDB is recommended." + + class TraktLookup: """ Trakt lookup table to find all Trakt episodes of a TVShow """ def __init__(self, tm: TVShow): - self.table = {} self.provider_table = {} self.tm = tm self.same_order = True + @cached_property @nocache - @rate_limit() @retry() - def _lookup(self, tm: TVShow): + def table(self): """ Build a lookup-table accessible via table[season][episode] + + - https://github.com/moogar0880/PyTrakt/pull/185 """ - self.table = pytrakt_extensions.lookup_table(tm) + + seasons = {} + for season in self.tm.seasons: + episodes = {} + for episode in season.episodes: + episodes[episode.number] = episode + seasons[season.season] = episodes + return seasons def _reverse_lookup(self, provider): """ Build a lookup-table accessible via table[provider][id] only if episodes ordering is different between Plex and Trakt """ + # NB: side effect, assumes that from_number() is called first to populate self.table table = {} for season in self.table.keys(): for te in self.table[season].values(): @@ -531,9 +541,17 @@ def _reverse_lookup(self, provider): self.provider_table[provider] = table logger.debug(f"{self.tm.title}: lookup table build with '{provider}' ids") + def from_guid(self, guid: PlexGuid): + """ + Find Trakt Episode from Guid of Plex Episode + """ + te = self.from_number(guid.pm.season_number, guid.pm.episode_number) + if not te or (str(te.ids.get(guid.provider)) != guid.id and not guid.pm.is_legacy_agent): + te = self.from_id(guid.provider, guid.id) + + return te + def from_number(self, season, number): - if not self.table: - self._lookup(self.tm) try: ep = self.table[season][number] except KeyError: @@ -541,8 +559,9 @@ def from_number(self, season, number): return ep def from_id(self, provider, id): + # NB: the code assumes from_id is called only if from_number fails if self.same_order: - logger.debug(f"{self.tm.title} episodes ordering is different in Plex and Trakt. Check your Plex media source, TMDB is recommended.") + logger.warning(f'"{self.tm.title}" {EPISODES_ORDERING_WARNING}') self.same_order = False if provider not in self.provider_table: self._reverse_lookup(provider) diff --git a/tests/test_tv_lookup.py b/tests/test_tv_lookup.py index 742f487929..02db27a99d 100755 --- a/tests/test_tv_lookup.py +++ b/tests/test_tv_lookup.py @@ -2,6 +2,7 @@ from trakt.tv import TVShow from plextraktsync.plex_api import PlexLibraryItem +from plextraktsync.trakt_api import TraktLookup from tests.conftest import factory, make trakt = factory.trakt_api() @@ -13,12 +14,36 @@ def test_tv_lookup(): ) guid = m.guids[0] tm: TVShow = trakt.find_by_guid(guid) - lookup = trakt.lookup(tm) - te = lookup[1][2].instance + lookup = TraktLookup(tm) + te = lookup.from_number(1, 2) assert te.imdb == "tt12057922", f"Unexpected! {te}" +def test_show_episodes_plex(): + m = PlexLibraryItem(make(cls="plexapi.video.Show", guid="imdb://tt10584350", type="show")) + guid = m.guids[0] + show = trakt.find_by_guid(guid) + + assert len(show.seasons) == 1 + episode = show.seasons[0].episodes[1] + assert episode.title == "A Murderer's Beef – Part 2" + assert episode.imdb == "tt12057922", f"Unexpected! {episode}" + + +def test_show_episodes(): + show = TVShow("Game of Thrones") + + assert len(show.seasons) == 9 + seasons = show.seasons + episodes = seasons[1].episodes + assert episodes[0].title == "Winter Is Coming" + + seasons = show.seasons + assert len(seasons) == 9 + assert seasons[1].episodes[0].title == "Winter Is Coming" + + def test_tv_lookup_by_episode_id(): pe = PlexLibraryItem( make( @@ -59,3 +84,7 @@ def test_find_episode(): assert te.season == 1 assert te.episode == 1 assert te.imdb == "tt11909222" + + +if __name__ == '__main__': + test_show_episodes()