From a30b7d6a067055dcb95c5d574c714e62941a1b31 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Fri, 5 Mar 2021 17:49:57 -0800 Subject: [PATCH 1/6] Add new Plex TV agent to library doc string --- plexapi/library.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index 206eb118f..8d3749a80 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -216,12 +216,13 @@ def add(self, name='', type='', agent='', scanner='', location='', language='en' **Show Preferences** - * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.thetvdb, com.plexapp.agents.themoviedb + * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.thetvdb, com.plexapp.agents.themoviedb, + tv.plex.agent.series * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true. * **episodeSort** (int): Episode order. Default -1 Possible options: 0:Oldest first, 1:Newest first. * **flattenSeasons** (int): Seasons. Default value 0 Possible options: 0:Show,1:Hide. * **includeInGlobal** (bool): Include in dashboard. Default value true. - * **scanner** (str): Plex Series Scanner + * **scanner** (str): Plex TV Series, Plex Series Scanner **TheTVDB Show Options** (com.plexapp.agents.thetvdb) From 5227b2dc3b12f6847e259aba3b8d9c2cfeef1922 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Fri, 5 Mar 2021 17:52:58 -0800 Subject: [PATCH 2/6] Update new Plex TV agent show/season/episode attributes --- plexapi/video.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/plexapi/video.py b/plexapi/video.py index e215a2f65..91b82d831 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -382,25 +382,46 @@ class Show(Video, ArtMixin, BannerMixin, PosterMixin, SplitMergeMixin, UnmatchMa Attributes: TAG (str): 'Directory' TYPE (str): 'show' + audienceRating (float): Audience rating (TMDB or TVDB). + audienceRatingImage (str): Key to audience rating image (tmdb://image.rating). + autoDeletionItemPolicyUnwatchedLibrary (int): Setting that indicates the number of unplayed + episodes to keep for the show (0 = All episodes, 5 = 5 latest episodes, 3 = 3 latest episodes, + 1 = 1 latest episode, -3 = Episodes added in the past 3 days, -7 = Episodes added in the + past 7 days, -30 = Episodes added in the past 30 days). + autoDeletionItemPolicyWatchedLibrary (int): Setting that indicates if episodes are deleted + after being watched for the show (0 = Never, 1 = After a day, 7 = After a week, + 100 = On next refresh). banner (str): Key to banner artwork (/library/metadata//banner/). childCount (int): Number of seasons in the show. collections (List<:class:`~plexapi.media.Collection`>): List of collection objects. contentRating (str) Content rating (PG-13; NR; TV-G). duration (int): Typical duration of the show episodes in milliseconds. + episodeSort (int): Setting that indicates how episodes are sorted for the show + (-1 = Library default, 0 = Oldest first, 1 = Newest first). + flattenSeasons (int): Setting that indicates if seasons are set to hidden for the show + (-1 = Library default, 0 = Hide, 1 = Show). genres (List<:class:`~plexapi.media.Genre`>): List of genre objects. + guids (List<:class:`~plexapi.media.Guid`>): List of guid objects. index (int): Plex index number for the show. key (str): API URL (/library/metadata/). labels (List<:class:`~plexapi.media.Label`>): List of label objects. + languageOverride (str): Setting that indicates if a languge is used to override metadata + (eg. en-CA, None = Library default). leafCount (int): Number of items in the show view. locations (List): List of folder paths where the show is found on disk. originallyAvailableAt (datetime): Datetime the show was released. originalTitle (str): The original title of the show. rating (float): Show rating (7.9; 9.8; 8.1). roles (List<:class:`~plexapi.media.Role`>): List of role objects. + showOrdering (str): Setting that indicates the episode ordering for the show + (None = Library default). similar (List<:class:`~plexapi.media.Similar`>): List of Similar objects. studio (str): Studio that created show (Di Bonaventura Pictures; 21 Laps Entertainment). tagline (str): Show tag line. theme (str): URL to theme resource (/library/metadata//theme/). + useOriginalTitle (int): Setting that indicates if the original title is used for the show + (-1 = Library default, 0 = No, 1 = Yes). + userRating (float): User rating (2.0; 8.0). viewedLeafCount (int): Number of items marked as played in the show view. year (int): Year the show was released. """ @@ -411,25 +432,38 @@ class Show(Video, ArtMixin, BannerMixin, PosterMixin, SplitMergeMixin, UnmatchMa def _loadData(self, data): """ Load attribute values from Plex XML response. """ Video._loadData(self, data) + self.audienceRating = utils.cast(float, data.attrib.get('audienceRating')) + self.audienceRatingImage = data.attrib.get('audienceRatingImage') + self.autoDeletionItemPolicyUnwatchedLibrary = utils.cast( + int, data.attrib.get('autoDeletionItemPolicyUnwatchedLibrary', '0')) + self.autoDeletionItemPolicyWatchedLibrary = utils.cast( + int, data.attrib.get('autoDeletionItemPolicyWatchedLibrary', '0')) self.banner = data.attrib.get('banner') self.childCount = utils.cast(int, data.attrib.get('childCount')) self.collections = self.findItems(data, media.Collection) self.contentRating = data.attrib.get('contentRating') self.duration = utils.cast(int, data.attrib.get('duration')) + self.episodeSort = utils.cast(int, data.attrib.get('episodeSort', '-1')) + self.flattenSeasons = utils.cast(int, data.attrib.get('flattenSeasons', '-1')) self.genres = self.findItems(data, media.Genre) + self.guids = self.findItems(data, media.Guid) self.index = utils.cast(int, data.attrib.get('index')) self.key = self.key.replace('/children', '') # FIX_BUG_50 self.labels = self.findItems(data, media.Label) + self.languageOverride = data.attrib.get('languageOverride') self.leafCount = utils.cast(int, data.attrib.get('leafCount')) self.locations = self.listAttrs(data, 'path', etag='Location') self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d') self.originalTitle = data.attrib.get('originalTitle') self.rating = utils.cast(float, data.attrib.get('rating')) self.roles = self.findItems(data, media.Role) + self.showOrdering = data.attrib.get('showOrdering') self.similar = self.findItems(data, media.Similar) self.studio = data.attrib.get('studio') self.tagline = data.attrib.get('tagline') self.theme = data.attrib.get('theme') + self.useOriginalTitle = utils.cast(int, data.attrib.get('useOriginalTitle', '-1')) + self.userRating = utils.cast(float, data.attrib.get('userRating')) self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount')) self.year = utils.cast(int, data.attrib.get('year')) @@ -584,6 +618,7 @@ class Season(Video, ArtMixin, PosterMixin): Attributes: TAG (str): 'Directory' TYPE (str): 'season' + guids (List<:class:`~plexapi.media.Guid`>): List of guid objects. index (int): Season number. key (str): API URL (/library/metadata/). leafCount (int): Number of items in the season view. @@ -603,6 +638,7 @@ class Season(Video, ArtMixin, PosterMixin): def _loadData(self, data): """ Load attribute values from Plex XML response. """ Video._loadData(self, data) + self.guids = self.findItems(data, media.Guid) self.index = utils.cast(int, data.attrib.get('index')) self.key = self.key.replace('/children', '') # FIX_BUG_50 self.leafCount = utils.cast(int, data.attrib.get('leafCount')) @@ -711,6 +747,8 @@ class Episode(Video, Playable, ArtMixin, PosterMixin, Attributes: TAG (str): 'Video' TYPE (str): 'episode' + audienceRating (float): Audience rating (TMDB or TVDB). + audienceRatingImage (str): Key to audience rating image (tmdb://image.rating). chapters (List<:class:`~plexapi.media.Chapter`>): List of Chapter objects. chapterSource (str): Chapter source (agent; media; mixed). contentRating (str) Content rating (PG-13; NR; TV-G). @@ -723,6 +761,7 @@ class Episode(Video, Playable, ArtMixin, PosterMixin, grandparentTheme (str): URL to show theme resource (/library/metadata//theme/). grandparentThumb (str): URL to show thumbnail image (/library/metadata//thumb/). grandparentTitle (str): Name of the show for the episode. + guids (List<:class:`~plexapi.media.Guid`>): List of guid objects. index (int): Episode number. markers (List<:class:`~plexapi.media.Marker`>): List of marker objects. media (List<:class:`~plexapi.media.Media`>): List of media objects. @@ -735,6 +774,7 @@ class Episode(Video, Playable, ArtMixin, PosterMixin, parentTitle (str): Name of the season for the episode. rating (float): Episode rating (7.9; 9.8; 8.1). skipParent (bool): True if the show's seasons are set to hidden. + userRating (float): User rating (2.0; 8.0). viewOffset (int): View offset in milliseconds. writers (List<:class:`~plexapi.media.Writer`>): List of writers objects. year (int): Year episode was released. @@ -748,6 +788,8 @@ def _loadData(self, data): Video._loadData(self, data) Playable._loadData(self, data) self._seasonNumber = None # cached season number + self.audienceRating = utils.cast(float, data.attrib.get('audienceRating')) + self.audienceRatingImage = data.attrib.get('audienceRatingImage') self.chapters = self.findItems(data, media.Chapter) self.chapterSource = data.attrib.get('chapterSource') self.contentRating = data.attrib.get('contentRating') @@ -760,6 +802,7 @@ def _loadData(self, data): self.grandparentTheme = data.attrib.get('grandparentTheme') self.grandparentThumb = data.attrib.get('grandparentThumb') self.grandparentTitle = data.attrib.get('grandparentTitle') + self.guids = self.findItems(data, media.Guid) self.index = utils.cast(int, data.attrib.get('index')) self.markers = self.findItems(data, media.Marker) self.media = self.findItems(data, media.Media) @@ -772,6 +815,7 @@ def _loadData(self, data): self.parentTitle = data.attrib.get('parentTitle') self.rating = utils.cast(float, data.attrib.get('rating')) self.skipParent = utils.cast(bool, data.attrib.get('skipParent', '0')) + self.userRating = utils.cast(float, data.attrib.get('userRating')) self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0)) self.writers = self.findItems(data, media.Writer) self.year = utils.cast(int, data.attrib.get('year')) From e95a32d769588dc544cced1d87932f043e90013e Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Fri, 5 Mar 2021 18:01:20 -0800 Subject: [PATCH 3/6] Update tests for new Plex TV agent show/season/episode attributes --- tests/test_video.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_video.py b/tests/test_video.py index 1573dafcf..d3ff107e6 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -550,20 +550,28 @@ def test_video_Show_attrs(show): assert utils.is_datetime(show.addedAt) if show.art: assert utils.is_art(show.art) + assert show.audienceRating is None # TODO: Change when updating test to the Plex TV agent + assert show.audienceRatingImage is None # TODO: Change when updating test to the Plex TV agent + assert show.autoDeletionItemPolicyUnwatchedLibrary == 0 + assert show.autoDeletionItemPolicyWatchedLibrary == 0 if show.banner: assert utils.is_banner(show.banner) assert utils.is_int(show.childCount) assert show.contentRating in utils.CONTENTRATINGS assert utils.is_int(show.duration, gte=1600000) + assert show.episodeSort == -1 + assert show.flattenSeasons == -1 assert utils.is_section(show._initpath) # Check reloading the show loads the full list of genres assert not {"Adventure", "Drama"} - {i.tag for i in show.genres} show.reload() assert sorted([i.tag for i in show.genres]) == ["Adventure", "Drama", "Fantasy"] + assert show.guids == [] # TODO: Change when updating test to the Plex TV agent # So the initkey should have changed because of the reload assert utils.is_metadata(show._initpath) assert utils.is_int(show.index) assert utils.is_metadata(show.key) + assert show.languageOverride is None assert utils.is_datetime(show.lastViewedAt) assert utils.is_int(show.leafCount) assert show.listType == "video" @@ -586,6 +594,7 @@ def test_video_Show_attrs(show): "Alfie Allen", ] # noqa assert show._server._baseurl == utils.SERVER_BASEURL + assert show.showOrdering is None assert show.studio == "HBO" assert utils.is_string(show.summary, gte=100) assert show.tagline is None @@ -595,6 +604,8 @@ def test_video_Show_attrs(show): assert show.title == "Game of Thrones" assert show.titleSort == "Game of Thrones" assert show.type == "show" + assert show.useOriginalTitle == -1 + assert show.userRating is None assert utils.is_datetime(show.updatedAt) assert utils.is_int(show.viewCount, gte=0) assert utils.is_int(show.viewedLeafCount, gte=0) @@ -790,6 +801,8 @@ def test_video_Episode_attrs(episode): assert utils.is_datetime(episode.addedAt) if episode.art: assert utils.is_art(episode.art) + assert episode.audienceRating is None # TODO: Change when updating test to the Plex TV agent + assert episode.audienceRatingImage is None # TODO: Change when updating test to the Plex TV agent assert episode.contentRating in utils.CONTENTRATINGS if len(episode.directors): assert [i.tag for i in episode.directors] == ["Tim Van Patten"] @@ -799,6 +812,7 @@ def test_video_Episode_attrs(episode): if episode.grandparentThumb: assert utils.is_thumb(episode.grandparentThumb) assert episode.grandparentTitle == "Game of Thrones" + assert episode.guids == [] # TODO: Change when updating test to the Plex TV agent assert episode.index == 1 assert utils.is_metadata(episode._initpath) assert utils.is_metadata(episode.key) @@ -913,6 +927,7 @@ def test_video_Season_attrs(show): assert utils.is_datetime(season.addedAt) if season.art: assert utils.is_art(season.art) + assert season.guids == [] # TODO: Change when updating test to the Plex TV agent assert season.index == 1 assert utils.is_metadata(season._initpath) assert utils.is_metadata(season.key) From 77bebaff94291fb13c68fdb159845936dfeff1b0 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Fri, 5 Mar 2021 18:18:17 -0800 Subject: [PATCH 4/6] Fix test for show attributes --- tests/test_video.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_video.py b/tests/test_video.py index d3ff107e6..3d54a2daa 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -550,21 +550,21 @@ def test_video_Show_attrs(show): assert utils.is_datetime(show.addedAt) if show.art: assert utils.is_art(show.art) - assert show.audienceRating is None # TODO: Change when updating test to the Plex TV agent - assert show.audienceRatingImage is None # TODO: Change when updating test to the Plex TV agent - assert show.autoDeletionItemPolicyUnwatchedLibrary == 0 - assert show.autoDeletionItemPolicyWatchedLibrary == 0 if show.banner: assert utils.is_banner(show.banner) assert utils.is_int(show.childCount) assert show.contentRating in utils.CONTENTRATINGS assert utils.is_int(show.duration, gte=1600000) - assert show.episodeSort == -1 - assert show.flattenSeasons == -1 assert utils.is_section(show._initpath) # Check reloading the show loads the full list of genres assert not {"Adventure", "Drama"} - {i.tag for i in show.genres} show.reload() + assert show.audienceRating is None # TODO: Change when updating test to the Plex TV agent + assert show.audienceRatingImage is None # TODO: Change when updating test to the Plex TV agent + assert show.autoDeletionItemPolicyUnwatchedLibrary == 0 + assert show.autoDeletionItemPolicyWatchedLibrary == 0 + assert show.episodeSort == -1 + assert show.flattenSeasons == -1 assert sorted([i.tag for i in show.genres]) == ["Adventure", "Drama", "Fantasy"] assert show.guids == [] # TODO: Change when updating test to the Plex TV agent # So the initkey should have changed because of the reload @@ -594,7 +594,7 @@ def test_video_Show_attrs(show): "Alfie Allen", ] # noqa assert show._server._baseurl == utils.SERVER_BASEURL - assert show.showOrdering is None + assert show.showOrdering in (None, 'aired') assert show.studio == "HBO" assert utils.is_string(show.summary, gte=100) assert show.tagline is None From 50f03a5d79ceed91a909c544c80a7465de69aef7 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 8 Mar 2021 08:30:40 -0800 Subject: [PATCH 5/6] Add network attribute to show --- plexapi/video.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plexapi/video.py b/plexapi/video.py index 91b82d831..7b0227e78 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -409,6 +409,7 @@ class Show(Video, ArtMixin, BannerMixin, PosterMixin, SplitMergeMixin, UnmatchMa (eg. en-CA, None = Library default). leafCount (int): Number of items in the show view. locations (List): List of folder paths where the show is found on disk. + network (str): The network that distributed the show. originallyAvailableAt (datetime): Datetime the show was released. originalTitle (str): The original title of the show. rating (float): Show rating (7.9; 9.8; 8.1). @@ -453,6 +454,7 @@ def _loadData(self, data): self.languageOverride = data.attrib.get('languageOverride') self.leafCount = utils.cast(int, data.attrib.get('leafCount')) self.locations = self.listAttrs(data, 'path', etag='Location') + self.network = data.attrib.get('network') self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d') self.originalTitle = data.attrib.get('originalTitle') self.rating = utils.cast(float, data.attrib.get('rating')) From 4c2c51fb1fdc6f1c2086e779b5e38d3e31c112f9 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Mon, 8 Mar 2021 20:08:53 +0000 Subject: [PATCH 6/6] Add show network to tests --- tests/test_video.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_video.py b/tests/test_video.py index 3d54a2daa..940c7e52e 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -577,6 +577,7 @@ def test_video_Show_attrs(show): assert show.listType == "video" assert len(show.locations) == 1 assert len(show.locations[0]) >= 10 + assert show.network is None assert utils.is_datetime(show.originallyAvailableAt) assert show.originalTitle is None assert show.rating >= 8.0