diff --git a/plextraktsync/media.py b/plextraktsync/media.py index 34657e86b0..72c8a9029d 100644 --- a/plextraktsync/media.py +++ b/plextraktsync/media.py @@ -225,9 +225,9 @@ def plex_history(self, **kwargs): def __str__(self): if self.plex: - return str(self.plex) + return f"Media<{str(self.plex).strip('<>')}>" - return str(self.trakt) + return f"Media<{str(self.trakt)}>" class MediaFactory: diff --git a/plextraktsync/plex/PlexLibraryItem.py b/plextraktsync/plex/PlexLibraryItem.py index cbc461ee96..b7d6c2f107 100644 --- a/plextraktsync/plex/PlexLibraryItem.py +++ b/plextraktsync/plex/PlexLibraryItem.py @@ -6,6 +6,7 @@ from trakt.utils import timestamp +from plextraktsync.decorators.flatten import flatten_list from plextraktsync.decorators.retry import retry from plextraktsync.factory import factory from plextraktsync.plex.PlexGuid import PlexGuid @@ -13,20 +14,42 @@ if TYPE_CHECKING: from plexapi.media import MediaPart + from plexapi.video import Episode, Movie, Show from plextraktsync.plex.PlexApi import PlexApi - from plextraktsync.plex.types import PlexMedia class PlexLibraryItem: - def __init__(self, item: PlexMedia, plex: PlexApi = None): + def __init__(self, + item: Movie | Show | Episode, + show: Show | None = None, + plex: PlexApi = None, + ): self.item = item self.plex = plex + if show and self.is_episode: + self._show = show + else: + self._show = None @property def is_legacy_agent(self): return not self.item.guid.startswith("plex://") + @cached_property + def is_episode(self): + return self.type == "episode" + + @property + def show(self): + return self._show + + @show.setter + def show(self, show: Show): + if not self.is_episode: + raise RuntimeError("show property can only be set to episodes") + self._show = show + @cached_property def is_discover(self): # Use __dict__ access to prevent reloads: @@ -278,19 +301,18 @@ def watch_progress(self, view_offset): percent = view_offset / self.item.duration * 100 return percent - def episodes(self): - for ep in self._get_episodes(): - yield PlexLibraryItem(ep, plex=self.plex) - @retry() - def _get_episodes(self): + @flatten_list + def episodes(self): if self.type == "season": show_id = self.item.parentRatingKey season = self.item.seasonNumber + filters = {"show.id": show_id, "season.index": season} + else: + filters = {"show.id": self.item.ratingKey} - return self.library.search(libtype='episode', filters={'show.id': show_id, 'season.index': season}) - - return self.library.search(libtype='episode', filters={'show.id': self.item.ratingKey}) + for ep in self.library.search(libtype="episode", filters=filters): + yield PlexLibraryItem(ep, show=self.item, plex=self.plex) @cached_property def season_number(self): diff --git a/plextraktsync/walker.py b/plextraktsync/walker.py index db5061ffac..520668797b 100644 --- a/plextraktsync/walker.py +++ b/plextraktsync/walker.py @@ -6,7 +6,6 @@ from plextraktsync.decorators.measure_time import measure_time from plextraktsync.mixin.SetWindowTitle import SetWindowTitle -from plextraktsync.plex.PlexGuid import PlexGuid from plextraktsync.plex.PlexLibraryItem import PlexLibraryItem from plextraktsync.trakt.TraktApi import TraktApi from plextraktsync.trakt.TraktItem import TraktItem @@ -310,11 +309,12 @@ def walk_shows(self, shows: set[Media], title="Processing Shows"): def get_plex_episodes(self, episodes: list[Episode]) -> Generator[Media, Any, None]: it = self.progressbar(episodes, desc="Processing episodes") for pe in it: - guid = PlexGuid(pe.grandparentGuid, "show") - show = self.mf.resolve_guid(guid) + ps = self.plex.fetch_item(pe.grandparentKey) + show = self.mf.resolve_any(ps) if not show: continue - me = self.mf.resolve_any(PlexLibraryItem(pe), show) + pm = PlexLibraryItem(pe, show=ps.item, plex=self.plex) + me = self.mf.resolve_any(pm, show) if not me: continue