Skip to content

Commit

Permalink
Merge pull request #729 from JonnyWong16/feature/smart_collections
Browse files Browse the repository at this point in the history
Add new collection attributes
  • Loading branch information
JonnyWong16 authored May 10, 2021
2 parents 0117a84 + e877b00 commit ecd9309
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 8 deletions.
4 changes: 3 additions & 1 deletion plexapi/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,13 +328,14 @@ def _defaultSyncTitle(self):


@utils.registerPlexObject
class Track(Audio, Playable, ArtUrlMixin, PosterUrlMixin, MoodMixin):
class Track(Audio, Playable, ArtUrlMixin, PosterUrlMixin, CollectionMixin, MoodMixin):
""" Represents a single Track.
Attributes:
TAG (str): 'Directory'
TYPE (str): 'track'
chapterSource (str): Unknown
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
duration (int): Length of the track in milliseconds.
grandparentArt (str): URL to album artist artwork (/library/metadata/<grandparentRatingKey>/art/<artid>).
grandparentGuid (str): Plex GUID for the album artist (plex://artist/5d07bcb0403c64029053ac4c).
Expand Down Expand Up @@ -364,6 +365,7 @@ def _loadData(self, data):
Audio._loadData(self, data)
Playable._loadData(self, data)
self.chapterSource = data.attrib.get('chapterSource')
self.collections = self.findItems(data, media.Collection)
self.duration = utils.cast(int, data.attrib.get('duration'))
self.grandparentArt = data.attrib.get('grandparentArt')
self.grandparentGuid = data.attrib.get('grandparentGuid')
Expand Down
14 changes: 11 additions & 3 deletions plexapi/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


@utils.registerPlexObject
class Collections(PlexPartialObject, ArtMixin, PosterMixin, LabelMixin):
class Collection(PlexPartialObject, ArtMixin, PosterMixin, LabelMixin):
""" Represents a single Collection.
Attributes:
Expand All @@ -20,7 +20,9 @@ class Collections(PlexPartialObject, ArtMixin, PosterMixin, LabelMixin):
artBlurHash (str): BlurHash string for artwork image.
childCount (int): Number of items in the collection.
collectionMode (str): How the items in the collection are displayed.
collectionPublished (bool): True if the collection is published to the Plex homepage.
collectionSort (str): How to sort the items in the collection.
content (str): The filter URI string for smart collections.
contentRating (str) Content rating (PG-13; NR; TV-G).
fields (List<:class:`~plexapi.media.Field`>): List of field objects.
guid (str): Plex GUID for the collection (collection://XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX).
Expand All @@ -32,7 +34,9 @@ class Collections(PlexPartialObject, ArtMixin, PosterMixin, LabelMixin):
librarySectionTitle (str): :class:`~plexapi.library.LibrarySection` title.
maxYear (int): Maximum year for the items in the collection.
minYear (int): Minimum year for the items in the collection.
ratingCount (int): The number of ratings.
ratingKey (int): Unique key identifying the collection.
smart (bool): True if the collection is a smart collection.
subtype (str): Media type of the items in the collection (movie, show, artist, or album).
summary (str): Summary of the collection.
thumb (str): URL to thumbnail image (/library/metadata/<ratingKey>/thumb/<thumbid>).
Expand All @@ -52,7 +56,9 @@ def _loadData(self, data):
self.artBlurHash = data.attrib.get('artBlurHash')
self.childCount = utils.cast(int, data.attrib.get('childCount'))
self.collectionMode = utils.cast(int, data.attrib.get('collectionMode', '-1'))
self.collectionPublished = utils.cast(bool, data.attrib.get('collectionPublished', '0'))
self.collectionSort = utils.cast(int, data.attrib.get('collectionSort', '0'))
self.content = data.attrib.get('content')
self.contentRating = data.attrib.get('contentRating')
self.fields = self.findItems(data, media.Field)
self.guid = data.attrib.get('guid')
Expand All @@ -64,7 +70,9 @@ def _loadData(self, data):
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
self.maxYear = utils.cast(int, data.attrib.get('maxYear'))
self.minYear = utils.cast(int, data.attrib.get('minYear'))
self.ratingCount = utils.cast(int, data.attrib.get('ratingCount'))
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
self.smart = utils.cast(bool, data.attrib.get('smart', '0'))
self.subtype = data.attrib.get('subtype')
self.summary = data.attrib.get('summary')
self.thumb = data.attrib.get('thumb')
Expand Down Expand Up @@ -119,7 +127,7 @@ def modeUpdate(self, mode=None):
showItems (Show this Collection and its Items)
Example:
collection = 'plexapi.library.Collections'
collection = 'plexapi.collection.Collection'
collection.updateMode(mode="hide")
"""
mode_dict = {'default': -1,
Expand All @@ -142,7 +150,7 @@ def sortUpdate(self, sort=None):
Example:
colleciton = 'plexapi.library.Collections'
colleciton = 'plexapi.collection.Collection'
collection.updateSort(mode="alpha")
"""
sort_dict = {'release': 0,
Expand Down
9 changes: 6 additions & 3 deletions plexapi/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,12 +585,13 @@ def download(self, savepath=None, keep_original_name=False, **kwargs):


@utils.registerPlexObject
class Season(Video, ArtMixin, PosterMixin):
class Season(Video, ArtMixin, PosterMixin, CollectionMixin):
""" Represents a single Show Season (including all episodes).
Attributes:
TAG (str): 'Directory'
TYPE (str): 'season'
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
guids (List<:class:`~plexapi.media.Guid`>): List of guid objects.
index (int): Season number.
key (str): API URL (/library/metadata/<ratingkey>).
Expand All @@ -611,6 +612,7 @@ class Season(Video, ArtMixin, PosterMixin):
def _loadData(self, data):
""" Load attribute values from Plex XML response. """
Video._loadData(self, data)
self.collections = self.findItems(data, media.Collection)
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
Expand Down Expand Up @@ -713,8 +715,7 @@ def _defaultSyncTitle(self):


@utils.registerPlexObject
class Episode(Video, Playable, ArtMixin, PosterMixin,
DirectorMixin, WriterMixin):
class Episode(Video, Playable, ArtMixin, PosterMixin, CollectionMixin, DirectorMixin, WriterMixin):
""" Represents a single Shows Episode.
Attributes:
Expand All @@ -724,6 +725,7 @@ class Episode(Video, Playable, ArtMixin, PosterMixin,
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).
collections (List<:class:`~plexapi.media.Collection`>): List of collection objects.
contentRating (str) Content rating (PG-13; NR; TV-G).
directors (List<:class:`~plexapi.media.Director`>): List of director objects.
duration (int): Duration of the episode in milliseconds.
Expand Down Expand Up @@ -765,6 +767,7 @@ def _loadData(self, data):
self.audienceRatingImage = data.attrib.get('audienceRatingImage')
self.chapters = self.findItems(data, media.Chapter)
self.chapterSource = data.attrib.get('chapterSource')
self.collections = self.findItems(data, media.Collection)
self.contentRating = data.attrib.get('contentRating')
self.directors = self.findItems(data, media.Director)
self.duration = utils.cast(int, data.attrib.get('duration'))
Expand Down
1 change: 1 addition & 0 deletions tests/test_audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ def test_audio_Track_mixins_images(track):


def test_audio_Track_mixins_tags(track):
test_mixins.edit_collection(track)
test_mixins.edit_mood(track)


Expand Down
4 changes: 4 additions & 0 deletions tests/test_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ def test_Collection_attrs(collection):
assert collection.artBlurHash is None
assert collection.childCount == 1
assert collection.collectionMode == -1
assert collection.collectionPublished is False
assert collection.collectionSort == 0
assert collection.content is None
assert collection.contentRating
assert not collection.fields
assert collection.guid.startswith("collection://")
Expand All @@ -24,7 +26,9 @@ def test_Collection_attrs(collection):
assert collection.librarySectionTitle == "Movies"
assert utils.is_int(collection.maxYear)
assert utils.is_int(collection.minYear)
assert utils.is_int(collection.ratingCount)
assert utils.is_int(collection.ratingKey)
assert collection.smart is False
assert collection.subtype == "movie"
assert collection.summary == ""
assert collection.thumb.startswith("/library/collections/%s/composite" % collection.ratingKey)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def test_server_system_devices(plex):
devices = plex.systemDevices()
assert len(devices)
device = devices[-1]
assert device.clientIdentifier or device.clientIdentifier is None
assert device.clientIdentifier or device.clientIdentifier == ""
assert utils.is_datetime(device.createdAt)
assert utils.is_int(device.id)
assert len(device.key)
Expand Down
6 changes: 6 additions & 0 deletions tests/test_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ def test_video_Episode_mixins_images(episode):


def test_video_Episode_mixins_tags(episode):
test_mixins.edit_collection(episode)
test_mixins.edit_director(episode)
test_mixins.edit_writer(episode)

Expand Down Expand Up @@ -992,6 +993,11 @@ def test_video_Season_mixins_images(show):
test_mixins.attr_posterUrl(season)


def test_video_Season_mixins_tags(show):
season = show.season(season=1)
test_mixins.edit_collection(season)


def test_that_reload_return_the_same_object(plex):
# we want to check this that all the urls are correct
movie_library_search = plex.library.section("Movies").search("Elephants Dream")[0]
Expand Down

0 comments on commit ecd9309

Please sign in to comment.