Add support for the new Plex Movie agent (#628)

* guids collection to movie and GuidTag PlexObject

* Fix flake8

* Clean up GuidTag and Guid

* Add Plex Movie agent to add library doc string

* Change test bootstrap server movie library to Plex Movie

* Update tests for Plex Movie agent

* Mix movie genre test

Co-authored-by: andyloree <andy@andyloree.com>
This commit is contained in:
JonnyWong16 2021-01-24 18:03:58 -08:00 committed by GitHub
parent fee5261aaf
commit ee28bef80f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 40 deletions

View file

@ -108,8 +108,8 @@ Usage Examples
# Example 6: List all movies directed by the same person as Elephants Dream. # Example 6: List all movies directed by the same person as Elephants Dream.
movies = plex.library.section('Movies') movies = plex.library.section('Movies')
die_hard = movies.get('Elephants Dream') elephants_dream = movies.get('Elephants Dream')
director = die_hard.directors[0] director = elephants_dream.directors[0]
for movie in movies.search(None, director=director): for movie in movies.search(None, director=director):
print(movie.title) print(movie.title)

View file

@ -167,11 +167,12 @@ class Library(PlexObject):
**Movie Preferences** **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. * **enableBIFGeneration** (bool): Enable video preview thumbnails. Default value true.
* **enableCinemaTrailers** (bool): Enable Cinema Trailers. Default value true. * **enableCinemaTrailers** (bool): Enable Cinema Trailers. Default value true.
* **includeInGlobal** (bool): Include in dashboard. 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) **IMDB Movie Options** (com.plexapp.agents.imdb)

View file

@ -681,6 +681,19 @@ class MediaTag(PlexObject):
return self.fetchItems(self.key) 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 @utils.registerPlexObject
class Collection(MediaTag): class Collection(MediaTag):
""" Represents a single Collection media tag. """ Represents a single Collection media tag.
@ -760,6 +773,16 @@ class Genre(MediaTag):
FILTER = 'genre' FILTER = 'genre'
@utils.registerPlexObject
class Guid(GuidTag):
""" Represents a single Guid media tag.
Attributes:
TAG (str): 'Guid'
"""
TAG = "Guid"
@utils.registerPlexObject @utils.registerPlexObject
class Mood(MediaTag): class Mood(MediaTag):
""" Represents a single Mood media tag. """ Represents a single Mood media tag.

View file

@ -275,6 +275,7 @@ class Movie(Playable, Video):
directors (List<:class:`~plexapi.media.Director`>): List of director objects. directors (List<:class:`~plexapi.media.Director`>): List of director objects.
duration (int): Duration of the movie in milliseconds. duration (int): Duration of the movie in milliseconds.
genres (List<:class:`~plexapi.media.Genre`>): List of genre objects. 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. labels (List<:class:`~plexapi.media.Label`>): List of label objects.
media (List<:class:`~plexapi.media.Media`>): List of media objects. media (List<:class:`~plexapi.media.Media`>): List of media objects.
originallyAvailableAt (datetime): Datetime the movie was released. originallyAvailableAt (datetime): Datetime the movie was released.
@ -310,6 +311,7 @@ class Movie(Playable, Video):
self.directors = self.findItems(data, media.Director) self.directors = self.findItems(data, media.Director)
self.duration = utils.cast(int, data.attrib.get('duration')) self.duration = utils.cast(int, data.attrib.get('duration'))
self.genres = self.findItems(data, media.Genre) self.genres = self.findItems(data, media.Genre)
self.guids = self.findItems(data, media.Guid)
self.labels = self.findItems(data, media.Label) self.labels = self.findItems(data, media.Label)
self.media = self.findItems(data, media.Media) self.media = self.findItems(data, media.Media)
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d') self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')

View file

@ -22,7 +22,7 @@ def test_library_Library_sectionByID_is_equal_section(plex, movies):
def test_library_sectionByID_with_attrs(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. # This seems to fail for some reason.
# my account alloew of sync, didnt find any about settings about the library. # my account alloew of sync, didnt find any about settings about the library.
# assert movies.allowSync is ('sync' in plex.ownerFeatures) # 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.filters == "1"
assert movies._initpath == "/library/sections" assert movies._initpath == "/library/sections"
assert utils.is_int(movies.key) assert utils.is_int(movies.key)
assert movies.language == "en" assert movies.language == "en-US"
assert len(movies.locations) == 1 assert len(movies.locations) == 1
assert len(movies.locations[0]) >= 10 assert len(movies.locations[0]) >= 10
assert movies.refreshing is False 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._server._baseurl == utils.SERVER_BASEURL
assert movies.thumb == "/:/resources/movie.png" assert movies.thumb == "/:/resources/movie.png"
assert movies.title == "Movies" 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): def test_library_MovieSection_search_genre(movie, movies):
animation = [i for i in movie.genres if i.tag == "Animation"] genre = movie.genres[0]
assert len(movies.search(genre=animation[0])) > 1 assert len(movies.search(genre=genre)) >= 1
def test_library_MovieSection_cancelUpdate(movies): def test_library_MovieSection_cancelUpdate(movies):
@ -255,7 +255,7 @@ def test_library_editAdvanced_default(movies):
movies.reload() movies.reload()
movies.defaultAdvanced() movies.defaultAdvanced()
for setting in movies.settings(): 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): def test_library_Collection_modeUpdate(collection):

View file

@ -84,7 +84,7 @@ def test_video_Movie_isFullObject_and_reload(plex):
movie_via_section_search.reload() movie_via_section_search.reload()
assert movie_via_section_search.isFullObject() is True assert movie_via_section_search.isFullObject() is True
# If the verify that the object has been reloaded. xml from search only returns 3 actors. # 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): 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_datetime(movie.addedAt)
assert utils.is_metadata(movie.art) assert utils.is_metadata(movie.art)
assert movie.artUrl assert movie.artUrl
assert movie.audienceRating == 8.5 assert float(movie.rating) >= 6.4
# Disabled this since it failed on the last run, wasnt in the original xml result. assert movie.ratingImage == 'rottentomatoes://image.rating.ripe'
# assert movie.audienceRatingImage == 'rottentomatoes://image.rating.upright' assert movie.audienceRating >= 8.5
assert movie.audienceRatingImage == 'rottentomatoes://image.rating.upright'
movie.reload() # RELOAD movie.reload() # RELOAD
assert movie.chapterSource is None assert movie.chapterSource is None
assert movie.collections == [] assert not movie.collections
assert movie.contentRating in utils.CONTENTRATINGS assert movie.contentRating in utils.CONTENTRATINGS
assert all([i.tag in ["US", "USA"] for i in movie.countries]) if movie.countries:
assert [i.tag for i in movie.directors] == ["Nina Paley"] 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.duration >= 160000
assert movie.fields == [] assert not movie.fields
assert movie.posters() assert movie.posters()
assert sorted([i.tag for i in movie.genres]) == [ assert "Animation" in [i.tag for i in movie.genres]
"Animation", assert "imdb://tt1172203" in [i.id for i in movie.guids]
"Comedy", assert movie.guid == "plex://movie/5d776846880197001ec967c6"
"Drama",
"Fantasy",
"Musical",
"Romance",
]
assert movie.guid == "com.plexapp.agents.imdb://tt1172203?lang=en"
assert utils.is_metadata(movie._initpath) assert utils.is_metadata(movie._initpath)
assert utils.is_metadata(movie.key) assert utils.is_metadata(movie.key)
assert utils.is_datetime(movie.lastViewedAt) assert utils.is_datetime(movie.lastViewedAt)
@ -186,16 +189,7 @@ def test_video_Movie_attrs(movies):
assert movie.playlistItemID is None assert movie.playlistItemID is None
if movie.primaryExtraKey: if movie.primaryExtraKey:
assert utils.is_metadata(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 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._server._baseurl == utils.SERVER_BASEURL
assert movie.sessionKey is None assert movie.sessionKey is None
assert movie.studio == "Nina Paley" assert movie.studio == "Nina Paley"
@ -211,7 +205,6 @@ def test_video_Movie_attrs(movies):
assert movie.viewCount == 0 assert movie.viewCount == 0
assert utils.is_int(movie.viewOffset, gte=0) assert utils.is_int(movie.viewOffset, gte=0)
assert movie.viewedAt is None assert movie.viewedAt is None
assert sorted([i.tag for i in movie.writers][:4]) == ["Nina Paley"] # noqa
assert movie.year == 2008 assert movie.year == 2008
# Audio # Audio
audio = movie.media[0].parts[0].audioStreams()[0] 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.container in utils.CONTAINERS
assert part.decision is None assert part.decision is None
assert part.deepAnalysisVersion is None or utils.is_int(part.deepAnalysisVersion) 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 part.exists
assert len(part.file) >= 10 assert len(part.file) >= 10
assert part.has64bitOffsets is False assert part.has64bitOffsets is False

View file

@ -520,8 +520,9 @@ if __name__ == "__main__":
name="Movies", name="Movies",
type="movie", type="movie",
location="/data/Movies" if opts.no_docker is False else movies_path, location="/data/Movies" if opts.no_docker is False else movies_path,
agent="com.plexapp.agents.imdb", agent="tv.plex.agents.movie",
scanner="Plex Movie Scanner", scanner="Plex Movie",
language='en-US',
expected_media_count=num_movies, expected_media_count=num_movies,
) )
) )