From 4487fc1f7ad7f4c028299cc87de2d70fe549b209 Mon Sep 17 00:00:00 2001 From: andyloree Date: Mon, 31 Aug 2020 17:19:06 -0400 Subject: [PATCH 1/7] guids collection to movie and GuidTag PlexObject --- plexapi/media.py | 27 +++++++++++++++++++++++++++ plexapi/video.py | 2 ++ 2 files changed, 29 insertions(+) diff --git a/plexapi/media.py b/plexapi/media.py index 7cacf4644..62835e91b 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -626,6 +626,29 @@ def items(self, *args, **kwargs): raise BadRequest('Key is not defined for this tag: %s' % self.tag) return self.fetchItems(self.key) +class GuidTag(PlexObject): + """ Base class for guid tags used only for Guids, as they contain only a string identifier + + Attributes: + server (:class:`~plexapi.server.PlexServer`): Server this client is connected to. + id (id): Tag ID (Used as a unique id, except for Guid's, used for external systems + to plex identifiers, like imdb and tmdb). + """ + + def _loadData(self, data): + """ Load attribute values from Plex XML response. """ + self._data = data + self.id = data.attrib.get('id') + self.tag = data.attrib.get('tag') + + def items(self, *args, **kwargs): + """ Return the list of items within this tag. This function is only applicable + in search results from PlexServer :func:`~plexapi.server.PlexServer.search()`. + """ + if not self.key: + raise BadRequest('Key is not defined for this tag: %s' % self.tag) + return self.fetchItems(self.key) + @utils.registerPlexObject class Collection(MediaTag): @@ -705,6 +728,10 @@ class Genre(MediaTag): TAG = 'Genre' FILTER = 'genre' +@utils.registerPlexObject +class Guid(GuidTag): + """ Represents a single Guid media tag. """ + TAG = "Guid" @utils.registerPlexObject class Mood(MediaTag): diff --git a/plexapi/video.py b/plexapi/video.py index 0a184b57d..508dc5a4a 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -275,6 +275,7 @@ class Movie(Playable, Video): directors (List<:class:`~plexapi.media.Director`>): List of director objects. duration (int): Duration of the movie in milliseconds. genres (List<:class:`~plexapi.media.Genre`>): List of genre objects. + guids (List<:class:`~plexapi.media.Guid`>): List of guid objects. labels (List<:class:`~plexapi.media.Label`>): List of label objects. media (List<:class:`~plexapi.media.Media`>): List of media objects. originallyAvailableAt (datetime): Datetime the movie was released. @@ -310,6 +311,7 @@ def _loadData(self, data): self.directors = self.findItems(data, media.Director) self.duration = utils.cast(int, data.attrib.get('duration')) self.genres = self.findItems(data, media.Genre) + self.guids = self.findItems(data, media.Guid) self.labels = self.findItems(data, media.Label) self.media = self.findItems(data, media.Media) self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d') From 4ae7e772fb6f64904c47b052aa554539869c8b43 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 15 Dec 2020 13:50:29 -0800 Subject: [PATCH 2/7] Fix flake8 --- plexapi/media.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plexapi/media.py b/plexapi/media.py index 62835e91b..5b474f093 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -626,6 +626,7 @@ def items(self, *args, **kwargs): raise BadRequest('Key is not defined for this tag: %s' % self.tag) return self.fetchItems(self.key) + class GuidTag(PlexObject): """ Base class for guid tags used only for Guids, as they contain only a string identifier @@ -728,11 +729,13 @@ class Genre(MediaTag): TAG = 'Genre' FILTER = 'genre' + @utils.registerPlexObject class Guid(GuidTag): """ Represents a single Guid media tag. """ TAG = "Guid" + @utils.registerPlexObject class Mood(MediaTag): """ Represents a single Mood media tag. From ce43cdbfe4b59381b93d70cdd02d2a711bc7e1a8 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 15 Dec 2020 13:59:20 -0800 Subject: [PATCH 3/7] Clean up GuidTag and Guid --- plexapi/media.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/plexapi/media.py b/plexapi/media.py index 5b474f093..528108fdc 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -631,24 +631,13 @@ class GuidTag(PlexObject): """ Base class for guid tags used only for Guids, as they contain only a string identifier Attributes: - server (:class:`~plexapi.server.PlexServer`): Server this client is connected to. - id (id): Tag ID (Used as a unique id, except for Guid's, used for external systems - to plex identifiers, like imdb and tmdb). + id (id): The guid for external metadata sources (e.g. IMDB, TMDB, TVDB). """ def _loadData(self, data): """ Load attribute values from Plex XML response. """ self._data = data self.id = data.attrib.get('id') - self.tag = data.attrib.get('tag') - - def items(self, *args, **kwargs): - """ Return the list of items within this tag. This function is only applicable - in search results from PlexServer :func:`~plexapi.server.PlexServer.search()`. - """ - if not self.key: - raise BadRequest('Key is not defined for this tag: %s' % self.tag) - return self.fetchItems(self.key) @utils.registerPlexObject @@ -732,7 +721,11 @@ class Genre(MediaTag): @utils.registerPlexObject class Guid(GuidTag): - """ Represents a single Guid media tag. """ + """ Represents a single Guid media tag. + + Attributes: + TAG (str): 'Guid' + """ TAG = "Guid" From dac3efc01a8aedcde861d4043451682f376f995f Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 15 Dec 2020 15:30:00 -0800 Subject: [PATCH 4/7] Add Plex Movie agent to add 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 e282a9f7d..e27df9876 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -167,11 +167,12 @@ def add(self, name='', type='', agent='', scanner='', location='', language='en' **Movie Preferences** - * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.imdb, com.plexapp.agents.themoviedb + * **agent** (str): com.plexapp.agents.none, com.plexapp.agents.imdb, tv.plex.agents.movie, + com.plexapp.agents.themoviedb * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true. * **enableCinemaTrailers** (bool): Enable Cinema Trailers. Default value true. * **includeInGlobal** (bool): Include in dashboard. Default value true. - * **scanner** (str): Plex Movie Scanner, Plex Video Files Scanner + * **scanner** (str): Plex Movie, Plex Movie Scanner, Plex Video Files Scanner, Plex Video Files **IMDB Movie Options** (com.plexapp.agents.imdb) From 02f971d3881e1e5c32eacc08c95f75c3c0b2168e Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 15 Dec 2020 15:30:22 -0800 Subject: [PATCH 5/7] Change test bootstrap server movie library to Plex Movie --- tools/plex-bootstraptest.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/plex-bootstraptest.py b/tools/plex-bootstraptest.py index 5e609a901..1ff4da297 100755 --- a/tools/plex-bootstraptest.py +++ b/tools/plex-bootstraptest.py @@ -520,8 +520,9 @@ def alert_callback(data): name="Movies", type="movie", location="/data/Movies" if opts.no_docker is False else movies_path, - agent="com.plexapp.agents.imdb", - scanner="Plex Movie Scanner", + agent="tv.plex.agents.movie", + scanner="Plex Movie", + language='en-US', expected_media_count=num_movies, ) ) From 78bbc59eedd1fad3a4fbdf7f037edac80c03a99e Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 15 Dec 2020 17:20:35 -0800 Subject: [PATCH 6/7] Update tests for Plex Movie agent --- README.rst | 4 ++-- tests/test_library.py | 12 ++++++------ tests/test_video.py | 40 ++++++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.rst b/README.rst index 9bf345114..eb0ba6928 100644 --- a/README.rst +++ b/README.rst @@ -108,8 +108,8 @@ Usage Examples # Example 6: List all movies directed by the same person as Elephants Dream. movies = plex.library.section('Movies') - die_hard = movies.get('Elephants Dream') - director = die_hard.directors[0] + elephants_dream = movies.get('Elephants Dream') + director = elephants_dream.directors[0] for movie in movies.search(None, director=director): print(movie.title) diff --git a/tests/test_library.py b/tests/test_library.py index 83404f8f3..3958a8e32 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -22,7 +22,7 @@ def test_library_Library_sectionByID_is_equal_section(plex, movies): def test_library_sectionByID_with_attrs(plex, movies): - assert movies.agent == "com.plexapp.agents.imdb" + assert movies.agent == "tv.plex.agents.movie" # This seems to fail for some reason. # my account alloew of sync, didnt find any about settings about the library. # assert movies.allowSync is ('sync' in plex.ownerFeatures) @@ -34,11 +34,11 @@ def test_library_sectionByID_with_attrs(plex, movies): assert movies.filters == "1" assert movies._initpath == "/library/sections" assert utils.is_int(movies.key) - assert movies.language == "en" + assert movies.language == "en-US" assert len(movies.locations) == 1 assert len(movies.locations[0]) >= 10 assert movies.refreshing is False - assert movies.scanner == "Plex Movie Scanner" + assert movies.scanner == "Plex Movie" assert movies._server._baseurl == utils.SERVER_BASEURL assert movies.thumb == "/:/resources/movie.png" assert movies.title == "Movies" @@ -152,8 +152,8 @@ def test_library_MovieSection_refresh(movies, patched_http_call): def test_library_MovieSection_search_genre(movie, movies): - animation = [i for i in movie.genres if i.tag == "Animation"] - assert len(movies.search(genre=animation[0])) > 1 + genre = movie.genres[0] + assert len(movies.search(genre=genre)) >= 1 def test_library_MovieSection_cancelUpdate(movies): @@ -255,7 +255,7 @@ def test_library_editAdvanced_default(movies): movies.reload() movies.defaultAdvanced() for setting in movies.settings(): - assert int(setting.value) == int(setting.default) + assert str(setting.value) == str(setting.default) def test_library_Collection_modeUpdate(collection): diff --git a/tests/test_video.py b/tests/test_video.py index 5eb508a5e..171bb71f7 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -84,7 +84,7 @@ def test_video_Movie_isFullObject_and_reload(plex): movie_via_section_search.reload() assert movie_via_section_search.isFullObject() is True # If the verify that the object has been reloaded. xml from search only returns 3 actors. - assert len(movie_via_section_search.roles) > 3 + assert len(movie_via_section_search.roles) >= 3 def test_video_Movie_isPartialObject(movie): @@ -155,17 +155,26 @@ def test_video_Movie_attrs(movies): assert utils.is_datetime(movie.addedAt) assert utils.is_metadata(movie.art) assert movie.artUrl - assert movie.audienceRating == 8.5 - # Disabled this since it failed on the last run, wasnt in the original xml result. - # assert movie.audienceRatingImage == 'rottentomatoes://image.rating.upright' + assert float(movie.rating) >= 6.4 + assert movie.ratingImage == 'rottentomatoes://image.rating.ripe' + assert movie.audienceRating >= 8.5 + assert movie.audienceRatingImage == 'rottentomatoes://image.rating.upright' movie.reload() # RELOAD assert movie.chapterSource is None - assert movie.collections == [] + assert not movie.collections assert movie.contentRating in utils.CONTENTRATINGS - assert all([i.tag in ["US", "USA"] for i in movie.countries]) - assert [i.tag for i in movie.directors] == ["Nina Paley"] + if movie.countries: + assert "United States of America" in [i.tag for i in movie.countries] + if movie.producers: + assert "Nina Paley" in [i.tag for i in movie.producers] + if movie.directors: + assert "Nina Paley" in [i.tag for i in movie.directors] + if movie.roles: + assert "Reena Shah" in [i.tag for i in movie.roles] + if movie.writers: + assert "Nina Paley" in [i.tag for i in movie.writers] assert movie.duration >= 160000 - assert movie.fields == [] + assert not movie.fields assert movie.posters() assert sorted([i.tag for i in movie.genres]) == [ "Animation", @@ -175,7 +184,8 @@ def test_video_Movie_attrs(movies): "Musical", "Romance", ] - assert movie.guid == "com.plexapp.agents.imdb://tt1172203?lang=en" + assert "imdb://tt1172203" in [i.id for i in movie.guids] + assert movie.guid == "plex://movie/5d776846880197001ec967c6" assert utils.is_metadata(movie._initpath) assert utils.is_metadata(movie.key) assert utils.is_datetime(movie.lastViewedAt) @@ -186,16 +196,7 @@ def test_video_Movie_attrs(movies): assert movie.playlistItemID is None if movie.primaryExtraKey: assert utils.is_metadata(movie.primaryExtraKey) - assert [i.tag for i in movie.producers] == [] - assert float(movie.rating) >= 6.4 - # assert movie.ratingImage == 'rottentomatoes://image.rating.ripe' assert movie.ratingKey >= 1 - assert set(sorted([i.tag for i in movie.roles])) >= { - "Aladdin Ullah", - "Annette Hanshaw", - "Aseem Chhabra", - "Debargo Sanyal", - } # noqa assert movie._server._baseurl == utils.SERVER_BASEURL assert movie.sessionKey is None assert movie.studio == "Nina Paley" @@ -211,7 +212,6 @@ def test_video_Movie_attrs(movies): assert movie.viewCount == 0 assert utils.is_int(movie.viewOffset, gte=0) assert movie.viewedAt is None - assert sorted([i.tag for i in movie.writers][:4]) == ["Nina Paley"] # noqa assert movie.year == 2008 # Audio audio = movie.media[0].parts[0].audioStreams()[0] @@ -329,7 +329,7 @@ def test_video_Movie_attrs(movies): assert part.container in utils.CONTAINERS assert part.decision is None assert part.deepAnalysisVersion is None or utils.is_int(part.deepAnalysisVersion) - assert utils.is_int(part.duration, 160000) + assert utils.is_int(part.duration, gte=160000) assert part.exists assert len(part.file) >= 10 assert part.has64bitOffsets is False From b70ed0320f9a9fc2dfcd9a493774f51293074e78 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 13:00:26 -0800 Subject: [PATCH 7/7] Mix movie genre test --- tests/test_video.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/test_video.py b/tests/test_video.py index 171bb71f7..e60b28484 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -176,14 +176,7 @@ def test_video_Movie_attrs(movies): assert movie.duration >= 160000 assert not movie.fields assert movie.posters() - assert sorted([i.tag for i in movie.genres]) == [ - "Animation", - "Comedy", - "Drama", - "Fantasy", - "Musical", - "Romance", - ] + assert "Animation" in [i.tag for i in movie.genres] assert "imdb://tt1172203" in [i.id for i in movie.guids] assert movie.guid == "plex://movie/5d776846880197001ec967c6" assert utils.is_metadata(movie._initpath)