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) diff --git a/plexapi/video.py b/plexapi/video.py index e215a2f65..7b0227e78 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -382,25 +382,47 @@ 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. + 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). 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 +433,39 @@ 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.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')) 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 +620,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 +640,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 +749,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 +763,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 +776,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 +790,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 +804,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 +817,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')) diff --git a/tests/test_video.py b/tests/test_video.py index 1573dafcf..940c7e52e 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -559,16 +559,25 @@ def test_video_Show_attrs(show): # 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 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" 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 @@ -586,6 +595,7 @@ def test_video_Show_attrs(show): "Alfie Allen", ] # noqa assert show._server._baseurl == utils.SERVER_BASEURL + assert show.showOrdering in (None, 'aired') assert show.studio == "HBO" assert utils.is_string(show.summary, gte=100) assert show.tagline is None @@ -595,6 +605,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 +802,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 +813,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 +928,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)