From 951076294dedcee216b400078cc6666b143990e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 10 Jan 2022 17:55:35 +0200 Subject: [PATCH 1/6] Add LabelMixin to Episode class --- plexapi/video.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plexapi/video.py b/plexapi/video.py index 4049d6c53..a8f56300b 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -710,7 +710,7 @@ def _defaultSyncTitle(self): @utils.registerPlexObject class Episode(Video, Playable, ArtMixin, PosterMixin, RatingMixin, - CollectionMixin, DirectorMixin, WriterMixin): + CollectionMixin, DirectorMixin, LabelMixin, WriterMixin): """ Represents a single Shows Episode. Attributes: @@ -733,6 +733,7 @@ class Episode(Video, Playable, ArtMixin, PosterMixin, RatingMixin, grandparentTitle (str): Name of the show for the episode. guids (List<:class:`~plexapi.media.Guid`>): List of guid objects. index (int): Episode number. + labels (List<:class:`~plexapi.media.Label`>): List of label objects. markers (List<:class:`~plexapi.media.Marker`>): List of marker objects. media (List<:class:`~plexapi.media.Media`>): List of media objects. originallyAvailableAt (datetime): Datetime the episode was released. @@ -777,6 +778,7 @@ def _loadData(self, data): self.grandparentTitle = data.attrib.get('grandparentTitle') self.guids = self.findItems(data, media.Guid) self.index = utils.cast(int, data.attrib.get('index')) + self.labels = self.findItems(data, media.Label) self.markers = self.findItems(data, media.Marker) self.media = self.findItems(data, media.Media) self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d') From 874d6e22e92e61a292c66c50c2d6d3f926a048a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 13:19:39 +0200 Subject: [PATCH 2/6] Add test_mixins.edit_label(episode) test --- tests/test_video.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_video.py b/tests/test_video.py index 02dec0d6c..3091217b9 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -1149,6 +1149,7 @@ def test_video_Episode_mixins_tags(episode): test_mixins.edit_collection(episode) test_mixins.edit_director(episode) test_mixins.edit_writer(episode) + test_mixins.edit_label(episode) def test_video_Episode_media_tags(episode): From 4ee94924726c61131a5d82e72c61301633bfe95a Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Thu, 13 Jan 2022 10:47:11 -0500 Subject: [PATCH 3/6] Add Label Mixin to Season, Artist,and Track --- plexapi/audio.py | 8 ++++++-- plexapi/video.py | 4 +++- tests/test_audio.py | 2 ++ tests/test_video.py | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/plexapi/audio.py b/plexapi/audio.py index 656b9250a..94a34bdc6 100644 --- a/plexapi/audio.py +++ b/plexapi/audio.py @@ -125,7 +125,7 @@ def sync(self, bitrate, client=None, clientId=None, limit=None, title=None): @utils.registerPlexObject class Artist(Audio, AdvancedSettingsMixin, ArtMixin, PosterMixin, RatingMixin, SplitMergeMixin, UnmatchMatchMixin, - CollectionMixin, CountryMixin, GenreMixin, MoodMixin, SimilarArtistMixin, StyleMixin): + CollectionMixin, CountryMixin, GenreMixin, LabelMixin, MoodMixin, SimilarArtistMixin, StyleMixin): """ Represents a single Artist. Attributes: @@ -137,6 +137,7 @@ class Artist(Audio, AdvancedSettingsMixin, ArtMixin, PosterMixin, RatingMixin, S countries (List<:class:`~plexapi.media.Country`>): List country objects. genres (List<:class:`~plexapi.media.Genre`>): List of genre objects. key (str): API URL (/library/metadata/). + labels (List<:class:`~plexapi.media.Label`>): List of label objects. locations (List): List of folder paths where the artist is found on disk. similar (List<:class:`~plexapi.media.Similar`>): List of similar objects. styles (List<:class:`~plexapi.media.Style`>): List of style objects. @@ -152,6 +153,7 @@ def _loadData(self, data): self.countries = self.findItems(data, media.Country) self.genres = self.findItems(data, media.Genre) self.key = self.key.replace('/children', '') # FIX_BUG_50 + self.labels = self.findItems(data, media.Label) self.locations = self.listAttrs(data, 'path', etag='Location') self.similar = self.findItems(data, media.Similar) self.styles = self.findItems(data, media.Style) @@ -332,7 +334,7 @@ def _defaultSyncTitle(self): @utils.registerPlexObject class Track(Audio, Playable, ArtUrlMixin, PosterUrlMixin, RatingMixin, - CollectionMixin, MoodMixin): + CollectionMixin, LabelMixin, MoodMixin): """ Represents a single Track. Attributes: @@ -348,6 +350,7 @@ class Track(Audio, Playable, ArtUrlMixin, PosterUrlMixin, RatingMixin, grandparentThumb (str): URL to album artist thumbnail image (/library/metadata//thumb/). grandparentTitle (str): Name of the album artist for the track. + labels (List<:class:`~plexapi.media.Label`>): List of label objects. media (List<:class:`~plexapi.media.Media`>): List of media objects. originalTitle (str): The artist for the track. parentGuid (str): Plex GUID for the album (plex://album/5d07cd8e403c640290f180f9). @@ -377,6 +380,7 @@ def _loadData(self, data): self.grandparentRatingKey = utils.cast(int, data.attrib.get('grandparentRatingKey')) self.grandparentThumb = data.attrib.get('grandparentThumb') self.grandparentTitle = data.attrib.get('grandparentTitle') + self.labels = self.findItems(data, media.Label) self.media = self.findItems(data, media.Media) self.originalTitle = data.attrib.get('originalTitle') self.parentGuid = data.attrib.get('parentGuid') diff --git a/plexapi/video.py b/plexapi/video.py index 4049d6c53..cdcb747a0 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -574,7 +574,7 @@ def download(self, savepath=None, keep_original_name=False, subfolders=False, ** @utils.registerPlexObject -class Season(Video, ArtMixin, PosterMixin, RatingMixin, CollectionMixin): +class Season(Video, ArtMixin, PosterMixin, RatingMixin, CollectionMixin, LabelMixin): """ Represents a single Show Season (including all episodes). Attributes: @@ -584,6 +584,7 @@ class Season(Video, ArtMixin, PosterMixin, RatingMixin, CollectionMixin): guids (List<:class:`~plexapi.media.Guid`>): List of guid objects. index (int): Season number. key (str): API URL (/library/metadata/). + labels (List<:class:`~plexapi.media.Label`>): List of label objects. leafCount (int): Number of items in the season view. parentGuid (str): Plex GUID for the show (plex://show/5d9c086fe9d5a1001f4d9fe6). parentIndex (int): Plex index number for the show. @@ -607,6 +608,7 @@ def _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.labels = self.findItems(data, media.Label) self.leafCount = utils.cast(int, data.attrib.get('leafCount')) self.parentGuid = data.attrib.get('parentGuid') self.parentIndex = utils.cast(int, data.attrib.get('parentIndex')) diff --git a/tests/test_audio.py b/tests/test_audio.py index 41363ddb0..a5921df1f 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -103,6 +103,7 @@ def test_audio_Artist_mixins_tags(artist): test_mixins.edit_collection(artist) test_mixins.edit_country(artist) test_mixins.edit_genre(artist) + test_mixins.edit_label(episode) test_mixins.edit_mood(artist) test_mixins.edit_similar_artist(artist) test_mixins.edit_style(artist) @@ -368,6 +369,7 @@ def test_audio_Track_mixins_rating(track): def test_audio_Track_mixins_tags(track): test_mixins.edit_collection(track) + test_mixins.edit_label(episode) test_mixins.edit_mood(track) diff --git a/tests/test_video.py b/tests/test_video.py index 02dec0d6c..e9c62425b 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -938,6 +938,7 @@ def test_video_Season_mixins_rating(show): def test_video_Season_mixins_tags(show): season = show.season(season=1) test_mixins.edit_collection(season) + test_mixins.edit_label(episode) def test_video_Season_PlexWebURL(plex, season): From abdf42098eb81929e1e618adacb94e148559701f Mon Sep 17 00:00:00 2001 From: meisnate12 Date: Thu, 13 Jan 2022 10:56:32 -0500 Subject: [PATCH 4/6] fix tests --- tests/test_audio.py | 4 ++-- tests/test_video.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_audio.py b/tests/test_audio.py index a5921df1f..2a262392d 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -103,7 +103,7 @@ def test_audio_Artist_mixins_tags(artist): test_mixins.edit_collection(artist) test_mixins.edit_country(artist) test_mixins.edit_genre(artist) - test_mixins.edit_label(episode) + test_mixins.edit_label(artist) test_mixins.edit_mood(artist) test_mixins.edit_similar_artist(artist) test_mixins.edit_style(artist) @@ -369,7 +369,7 @@ def test_audio_Track_mixins_rating(track): def test_audio_Track_mixins_tags(track): test_mixins.edit_collection(track) - test_mixins.edit_label(episode) + test_mixins.edit_label(track) test_mixins.edit_mood(track) diff --git a/tests/test_video.py b/tests/test_video.py index e9c62425b..d72bc4349 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -938,7 +938,7 @@ def test_video_Season_mixins_rating(show): def test_video_Season_mixins_tags(show): season = show.season(season=1) test_mixins.edit_collection(season) - test_mixins.edit_label(episode) + test_mixins.edit_label(season) def test_video_Season_PlexWebURL(plex, season): From 01d6d12b6953f487553985b2b7c9aa5ba6c7c230 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 23 Jan 2022 20:34:08 -0800 Subject: [PATCH 5/6] Load manual FilteringFields for labels --- plexapi/library.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index 5abb55e66..551262c33 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -2225,7 +2225,7 @@ def _manualSorts(self): """ Manually add additional sorts which are available but not exposed on the Plex server. """ - # Sorts: key, dir, title + # Sorts: (key, dir, title) additionalSorts = [ ('guid', 'asc', 'Guid'), ('id', 'asc', 'Rating Key'), @@ -2255,8 +2255,10 @@ def _manualSorts(self): manualSorts = [] for sortField, sortDir, sortTitle in additionalSorts: - sortXML = ('' - % (sortDir, sortField, sortField, sortTitle)) + sortXML = ( + '' + % (sortDir, sortField, sortField, sortTitle) + ) manualSorts.append(self._manuallyLoadXML(sortXML, FilteringSort)) return manualSorts @@ -2265,7 +2267,7 @@ def _manualFields(self): """ Manually add additional fields which are available but not exposed on the Plex server. """ - # Fields: key, type, title + # Fields: (key, type, title) additionalFields = [ ('guid', 'string', 'Guid'), ('id', 'integer', 'Rating Key'), @@ -2291,19 +2293,26 @@ def _manualFields(self): additionalFields.extend([ ('addedAt', 'date', 'Date Season Added'), ('unviewedLeafCount', 'integer', 'Episode Unplayed Count'), - ('year', 'integer', 'Season Year') + ('year', 'integer', 'Season Year'), + ('label', 'tag', 'Label') ]) elif self.type == 'episode': additionalFields.extend([ ('audienceRating', 'integer', 'Audience Rating'), ('duration', 'integer', 'Duration'), ('rating', 'integer', 'Critic Rating'), - ('viewOffset', 'integer', 'View Offset') + ('viewOffset', 'integer', 'View Offset'), + ('label', 'tag', 'Label') + ]) + elif self.type == 'artist': + additionalFields.extend([ + ('label', 'tag', 'Label') ]) elif self.type == 'track': additionalFields.extend([ ('duration', 'integer', 'Duration'), - ('viewOffset', 'integer', 'View Offset') + ('viewOffset', 'integer', 'View Offset'), + ('label', 'tag', 'Label') ]) elif self.type == 'collection': additionalFields.extend([ @@ -2314,8 +2323,10 @@ def _manualFields(self): manualFields = [] for field, fieldType, fieldTitle in additionalFields: - fieldXML = ('' - % (prefix, field, fieldTitle, fieldType)) + fieldXML = ( + '' + % (prefix, field, fieldTitle, fieldType) + ) manualFields.append(self._manuallyLoadXML(fieldXML, FilteringField)) return manualFields From a6ad3d110bab313faac414466d78251265f5f8df Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 23 Jan 2022 20:34:40 -0800 Subject: [PATCH 6/6] Load manual FilteringFilters for labels --- plexapi/library.py | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/plexapi/library.py b/plexapi/library.py index 551262c33..6225b869b 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -2216,11 +2216,52 @@ def _loadData(self, data): self.title = data.attrib.get('title') self.type = data.attrib.get('type') - # Add additional manual sorts and fields which are available + self._librarySectionID = self._parent().key + + # Add additional manual filters, sorts, and fields which are available # but not exposed on the Plex server + self.filters += self._manualFilters() self.sorts += self._manualSorts() self.fields += self._manualFields() + def _manualFilters(self): + """ Manually add additional filters which are available + but not exposed on the Plex server. + """ + # Filters: (filter, type, title) + additionalFilters = [ + ] + + if self.type == 'season': + additionalFilters.extend([ + ('label', 'string', 'Labels') + ]) + elif self.type == 'episode': + additionalFilters.extend([ + ('label', 'string', 'Labels') + ]) + elif self.type == 'artist': + additionalFilters.extend([ + ('label', 'string', 'Labels') + ]) + elif self.type == 'track': + additionalFilters.extend([ + ('label', 'string', 'Labels') + ]) + + manualFilters = [] + for filterTag, filterType, filterTitle in additionalFilters: + filterKey = '/library/sections/%s/%s?type=%s' % ( + self._librarySectionID, filterTag, utils.searchType(self.type) + ) + filterXML = ( + '' + % (filterTag, filterType, filterKey, filterTitle) + ) + manualFilters.append(self._manuallyLoadXML(filterXML, FilteringFilter)) + + return manualFilters + def _manualSorts(self): """ Manually add additional sorts which are available but not exposed on the Plex server.