diff --git a/README.rst b/README.rst index 9bf34511..eb0ba692 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/plexapi/library.py b/plexapi/library.py index e282a9f7..e27df987 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -167,11 +167,12 @@ class Library(PlexObject): **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) diff --git a/plexapi/media.py b/plexapi/media.py index 8b46b814..00007896 100644 --- a/plexapi/media.py +++ b/plexapi/media.py @@ -681,6 +681,19 @@ class MediaTag(PlexObject): 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: + 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') + + @utils.registerPlexObject class Collection(MediaTag): """ Represents a single Collection media tag. @@ -760,6 +773,16 @@ class Genre(MediaTag): FILTER = 'genre' +@utils.registerPlexObject +class Guid(GuidTag): + """ Represents a single Guid media tag. + + Attributes: + TAG (str): 'Guid' + """ + TAG = "Guid" + + @utils.registerPlexObject class Mood(MediaTag): """ Represents a single Mood media tag. diff --git a/plexapi/video.py b/plexapi/video.py index 0a184b57..508dc5a4 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 @@ class Movie(Playable, Video): 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') diff --git a/tests/test_library.py b/tests/test_library.py index 83404f8f..3958a8e3 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 5eb508a5..e60b2848 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,27 +155,30 @@ 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", - "Comedy", - "Drama", - "Fantasy", - "Musical", - "Romance", - ] - assert movie.guid == "com.plexapp.agents.imdb://tt1172203?lang=en" + 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) assert utils.is_metadata(movie.key) assert utils.is_datetime(movie.lastViewedAt) @@ -186,16 +189,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 +205,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 +322,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 diff --git a/tools/plex-bootstraptest.py b/tools/plex-bootstraptest.py index 5e609a90..1ff4da29 100755 --- a/tools/plex-bootstraptest.py +++ b/tools/plex-bootstraptest.py @@ -520,8 +520,9 @@ if __name__ == "__main__": 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, ) )