mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-25 13:10:17 +00:00
Add tests for theme mixin (#897)
* Add lockTheme and unlockTheme methods * Change setTheme to raise NotImplementedError * Add tests for theme mixins
This commit is contained in:
parent
caf3910057
commit
a568819e1e
5 changed files with 241 additions and 152 deletions
|
@ -244,12 +244,18 @@ class ThemeMixin(ThemeUrlMixin):
|
|||
self._server.query(key, method=self._server._session.post, data=data)
|
||||
|
||||
def setTheme(self, theme):
|
||||
""" Set the theme for a Plex object.
|
||||
raise NotImplementedError(
|
||||
'Themes cannot be set through the API. '
|
||||
'Re-upload the theme using "uploadTheme" to set it.'
|
||||
)
|
||||
|
||||
Parameters:
|
||||
theme (:class:`~plexapi.media.Theme`): The theme object to select.
|
||||
"""
|
||||
theme.select()
|
||||
def lockTheme(self):
|
||||
""" Lock the theme for a Plex object. """
|
||||
self._edit(**{'theme.locked': 1})
|
||||
|
||||
def unlockTheme(self):
|
||||
""" Unlock the theme for a Plex object. """
|
||||
self._edit(**{'theme.locked': 0})
|
||||
|
||||
|
||||
class RatingMixin(object):
|
||||
|
|
|
@ -32,6 +32,7 @@ def test_audio_Artist_attr(artist):
|
|||
assert isinstance(artist.similar, list)
|
||||
if artist.summary:
|
||||
assert "Alias" in artist.summary
|
||||
assert artist.theme is None
|
||||
if artist.thumb:
|
||||
assert utils.is_thumb(artist.thumb)
|
||||
assert artist.title == "Broke For Free"
|
||||
|
@ -95,6 +96,10 @@ def test_audio_Artist_mixins_images(artist):
|
|||
test_mixins.attr_posterUrl(artist)
|
||||
|
||||
|
||||
def test_audio_Artist_mixins_themes(artist):
|
||||
test_mixins.edit_theme(artist)
|
||||
|
||||
|
||||
def test_audio_Artist_mixins_rating(artist):
|
||||
test_mixins.edit_rating(artist)
|
||||
|
||||
|
@ -143,6 +148,7 @@ def test_audio_Album_attrs(album):
|
|||
assert utils.is_datetime(album.originallyAvailableAt)
|
||||
assert utils.is_metadata(album.parentKey)
|
||||
assert utils.is_int(album.parentRatingKey)
|
||||
assert album.parentTheme is None or utils.is_metadata(album.parentTheme)
|
||||
if album.parentThumb:
|
||||
assert utils.is_thumb(album.parentThumb)
|
||||
assert album.parentTitle == "Broke For Free"
|
||||
|
@ -206,6 +212,10 @@ def test_audio_Album_mixins_images(album):
|
|||
test_mixins.attr_posterUrl(album)
|
||||
|
||||
|
||||
def test_audio_Album_mixins_themes(album):
|
||||
test_mixins.attr_themeUrl(album)
|
||||
|
||||
|
||||
def test_audio_Album_mixins_rating(album):
|
||||
test_mixins.edit_rating(album)
|
||||
|
||||
|
@ -246,6 +256,7 @@ def test_audio_Track_attrs(album):
|
|||
assert utils.is_art(track.grandparentArt)
|
||||
assert utils.is_metadata(track.grandparentKey)
|
||||
assert utils.is_int(track.grandparentRatingKey)
|
||||
assert track.grandparentTheme is None or utils.is_metadata(track.grandparentTheme)
|
||||
if track.grandparentThumb:
|
||||
assert utils.is_thumb(track.grandparentThumb)
|
||||
assert track.grandparentTitle == "Broke For Free"
|
||||
|
@ -363,6 +374,10 @@ def test_audio_Track_mixins_images(track):
|
|||
test_mixins.attr_posterUrl(track)
|
||||
|
||||
|
||||
def test_audio_Track_mixins_themes(track):
|
||||
test_mixins.attr_themeUrl(track)
|
||||
|
||||
|
||||
def test_audio_Track_mixins_rating(track):
|
||||
test_mixins.edit_rating(track)
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ def test_Collection_attrs(collection):
|
|||
assert collection.smart is False
|
||||
assert collection.subtype == "movie"
|
||||
assert collection.summary == ""
|
||||
assert collection.theme is None
|
||||
assert collection.thumb.startswith("/library/collections/%s/composite" % collection.ratingKey)
|
||||
assert collection.thumbBlurHash is None
|
||||
assert collection.title == "Test Collection"
|
||||
|
@ -282,6 +283,10 @@ def test_Collection_mixins_images(collection):
|
|||
test_mixins.attr_posterUrl(collection)
|
||||
|
||||
|
||||
def test_Collection_mixins_themes(collection):
|
||||
test_mixins.edit_theme(collection)
|
||||
|
||||
|
||||
def test_Collection_mixins_rating(collection):
|
||||
test_mixins.edit_rating(collection)
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ from . import conftest as utils
|
|||
|
||||
TEST_MIXIN_TAG = "Test Tag"
|
||||
CUTE_CAT_SHA1 = "9f7003fc401761d8e0b0364d428b2dab2f789dbb"
|
||||
AUDIO_STUB_SHA1 = "1abc20d5fdc904201bf8988ca6ef30f96bb73617"
|
||||
|
||||
|
||||
def _test_mixins_tag(obj, attr, tag_method):
|
||||
|
@ -180,6 +181,48 @@ def attr_posterUrl(obj):
|
|||
_test_mixins_imageUrl(obj, "thumb")
|
||||
|
||||
|
||||
def _test_mixins_edit_theme(obj):
|
||||
_fields = lambda: [f.name for f in obj.fields]
|
||||
# Test upload theme from file
|
||||
obj.uploadTheme(filepath=utils.STUB_MP3_PATH)
|
||||
themes = obj.themes()
|
||||
file_theme = [
|
||||
t for t in themes
|
||||
if t.ratingKey.startswith("upload://") and t.ratingKey.endswith(AUDIO_STUB_SHA1)
|
||||
]
|
||||
assert file_theme
|
||||
obj.reload()
|
||||
assert "theme" in _fields()
|
||||
# Unlock the theme
|
||||
obj.unlockTheme()
|
||||
obj.reload()
|
||||
assert "theme" not in _fields()
|
||||
# Lock the theme
|
||||
obj.lockTheme()
|
||||
obj.reload()
|
||||
assert "theme" in _fields()
|
||||
with pytest.raises(NotImplementedError):
|
||||
obj.setTheme(themes[0])
|
||||
|
||||
|
||||
def edit_theme(obj):
|
||||
_test_mixins_edit_theme(obj)
|
||||
|
||||
|
||||
def _test_mixins_themeUrl(obj):
|
||||
url = obj.themeUrl
|
||||
if url:
|
||||
assert url.startswith(utils.SERVER_BASEURL)
|
||||
assert "/library/metadata/" in url
|
||||
assert "theme" in url
|
||||
else:
|
||||
assert url is None
|
||||
|
||||
|
||||
def attr_themeUrl(obj):
|
||||
_test_mixins_themeUrl(obj)
|
||||
|
||||
|
||||
def _test_mixins_editAdvanced(obj):
|
||||
for pref in obj.preferences():
|
||||
currentPref = obj.preference(pref.id)
|
||||
|
|
|
@ -40,153 +40,6 @@ def test_video_Movie_merge(movie, patched_http_call):
|
|||
movie.merge(1337)
|
||||
|
||||
|
||||
def test_video_Movie_mixins_edit_advanced_settings(movie):
|
||||
test_mixins.edit_advanced_settings(movie)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Changing images fails randomly")
|
||||
def test_video_Movie_mixins_images(movie):
|
||||
test_mixins.lock_art(movie)
|
||||
test_mixins.lock_poster(movie)
|
||||
test_mixins.edit_art(movie)
|
||||
test_mixins.edit_poster(movie)
|
||||
|
||||
|
||||
def test_video_Movie_mixins_rating(movie):
|
||||
test_mixins.edit_rating(movie)
|
||||
|
||||
|
||||
def test_video_Movie_mixins_tags(movie):
|
||||
test_mixins.edit_collection(movie)
|
||||
test_mixins.edit_country(movie)
|
||||
test_mixins.edit_director(movie)
|
||||
test_mixins.edit_genre(movie)
|
||||
test_mixins.edit_label(movie)
|
||||
test_mixins.edit_producer(movie)
|
||||
test_mixins.edit_writer(movie)
|
||||
|
||||
|
||||
def test_video_Movie_media_tags(movie):
|
||||
movie.reload()
|
||||
test_media.tag_collection(movie)
|
||||
test_media.tag_country(movie)
|
||||
test_media.tag_director(movie)
|
||||
test_media.tag_genre(movie)
|
||||
test_media.tag_label(movie)
|
||||
test_media.tag_producer(movie)
|
||||
test_media.tag_role(movie)
|
||||
test_media.tag_similar(movie)
|
||||
test_media.tag_writer(movie)
|
||||
|
||||
|
||||
def test_video_Movie_media_tags_Exception(movie):
|
||||
with pytest.raises(BadRequest):
|
||||
movie.genres[0].items()
|
||||
|
||||
|
||||
def test_video_Movie_media_tags_collection(movie, collection):
|
||||
movie.reload()
|
||||
collection_tag = next(c for c in movie.collections if c.tag == "Test Collection")
|
||||
assert collection == collection_tag.collection()
|
||||
|
||||
|
||||
def test_video_Movie_getStreamURL(movie, account):
|
||||
key = movie.ratingKey
|
||||
assert movie.getStreamURL() == (
|
||||
"{0}/video/:/transcode/universal/start.m3u8?"
|
||||
"X-Plex-Platform=Chrome©ts=1&mediaIndex=0&"
|
||||
"offset=0&path=%2Flibrary%2Fmetadata%2F{1}&X-Plex-Token={2}").format(
|
||||
utils.SERVER_BASEURL, key, account.authenticationToken
|
||||
) # noqa
|
||||
assert movie.getStreamURL(
|
||||
videoResolution="800x600"
|
||||
) == ("{0}/video/:/transcode/universal/start.m3u8?"
|
||||
"X-Plex-Platform=Chrome©ts=1&mediaIndex=0&"
|
||||
"offset=0&path=%2Flibrary%2Fmetadata%2F{1}&videoResolution=800x600&X-Plex-Token={2}").format(
|
||||
utils.SERVER_BASEURL, key, account.authenticationToken
|
||||
) # noqa
|
||||
|
||||
|
||||
def test_video_Movie_isFullObject_and_reload(plex):
|
||||
movie = plex.library.section("Movies").get("Sita Sings the Blues")
|
||||
assert movie.isFullObject() is False
|
||||
movie.reload(checkFiles=False)
|
||||
assert movie.isFullObject() is False
|
||||
movie.reload()
|
||||
assert movie.isFullObject() is True
|
||||
movie_via_search = plex.library.search(movie.title)[0]
|
||||
assert movie_via_search.isFullObject() is False
|
||||
movie_via_search.reload()
|
||||
assert movie_via_search.isFullObject() is True
|
||||
movie_via_section_search = plex.library.section("Movies").search(movie.title)[0]
|
||||
assert movie_via_section_search.isFullObject() is False
|
||||
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
|
||||
|
||||
|
||||
def test_video_Movie_isPartialObject(movie):
|
||||
assert movie.isPartialObject()
|
||||
|
||||
|
||||
def test_video_Movie_media_delete(movie, patched_http_call):
|
||||
for media in movie.media:
|
||||
media.delete()
|
||||
|
||||
|
||||
def test_video_Movie_iterParts(movie):
|
||||
assert len(list(movie.iterParts())) >= 1
|
||||
|
||||
|
||||
def test_video_Movie_download(monkeydownload, tmpdir, movie):
|
||||
filepaths = movie.download(savepath=str(tmpdir))
|
||||
assert len(filepaths) == 1
|
||||
with_resolution = movie.download(
|
||||
savepath=str(tmpdir), keep_original_filename=True, videoResolution="500x300"
|
||||
)
|
||||
assert len(with_resolution) == 1
|
||||
filename = os.path.basename(movie.media[0].parts[0].file)
|
||||
assert filename in with_resolution[0]
|
||||
|
||||
|
||||
def test_video_Movie_subtitlestreams(movie):
|
||||
assert not movie.subtitleStreams()
|
||||
|
||||
|
||||
def test_video_Episode_subtitlestreams(episode):
|
||||
assert not episode.subtitleStreams()
|
||||
|
||||
|
||||
def test_video_Movie_upload_select_remove_subtitle(movie, subtitle):
|
||||
|
||||
filepath = os.path.realpath(subtitle.name)
|
||||
|
||||
movie.uploadSubtitles(filepath)
|
||||
movie.reload()
|
||||
subtitles = [sub.title for sub in movie.subtitleStreams()]
|
||||
subname = subtitle.name.rsplit(".", 1)[0]
|
||||
assert subname in subtitles
|
||||
|
||||
subtitleSelection = movie.subtitleStreams()[0]
|
||||
parts = list(movie.iterParts())
|
||||
parts[0].setDefaultSubtitleStream(subtitleSelection)
|
||||
movie.reload()
|
||||
|
||||
subtitleSelection = movie.subtitleStreams()[0]
|
||||
assert subtitleSelection.selected
|
||||
|
||||
movie.removeSubtitles(streamTitle=subname)
|
||||
movie.reload()
|
||||
subtitles = [sub.title for sub in movie.subtitleStreams()]
|
||||
assert subname not in subtitles
|
||||
|
||||
try:
|
||||
os.remove(filepath)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def test_video_Movie_attrs(movies):
|
||||
movie = movies.get("Sita Sings the Blues")
|
||||
assert len(movie.locations) == 1
|
||||
|
@ -238,6 +91,7 @@ def test_video_Movie_attrs(movies):
|
|||
assert movie.studio == "Nina Paley"
|
||||
assert utils.is_string(movie.summary, gte=100)
|
||||
assert movie.tagline == "The Greatest Break-Up Story Ever Told"
|
||||
assert movie.theme is None
|
||||
if movie.thumb:
|
||||
assert utils.is_thumb(movie.thumb)
|
||||
assert movie.title == "Sita Sings the Blues"
|
||||
|
@ -436,6 +290,114 @@ def test_video_Movie_attrs(movies):
|
|||
assert stream2.type == 2
|
||||
|
||||
|
||||
def test_video_Movie_media_tags_Exception(movie):
|
||||
with pytest.raises(BadRequest):
|
||||
movie.genres[0].items()
|
||||
|
||||
|
||||
def test_video_Movie_media_tags_collection(movie, collection):
|
||||
movie.reload()
|
||||
collection_tag = next(c for c in movie.collections if c.tag == "Test Collection")
|
||||
assert collection == collection_tag.collection()
|
||||
|
||||
|
||||
def test_video_Movie_getStreamURL(movie, account):
|
||||
key = movie.ratingKey
|
||||
assert movie.getStreamURL() == (
|
||||
"{0}/video/:/transcode/universal/start.m3u8?"
|
||||
"X-Plex-Platform=Chrome©ts=1&mediaIndex=0&"
|
||||
"offset=0&path=%2Flibrary%2Fmetadata%2F{1}&X-Plex-Token={2}").format(
|
||||
utils.SERVER_BASEURL, key, account.authenticationToken
|
||||
) # noqa
|
||||
assert movie.getStreamURL(
|
||||
videoResolution="800x600"
|
||||
) == ("{0}/video/:/transcode/universal/start.m3u8?"
|
||||
"X-Plex-Platform=Chrome©ts=1&mediaIndex=0&"
|
||||
"offset=0&path=%2Flibrary%2Fmetadata%2F{1}&videoResolution=800x600&X-Plex-Token={2}").format(
|
||||
utils.SERVER_BASEURL, key, account.authenticationToken
|
||||
) # noqa
|
||||
|
||||
|
||||
def test_video_Movie_isFullObject_and_reload(plex):
|
||||
movie = plex.library.section("Movies").get("Sita Sings the Blues")
|
||||
assert movie.isFullObject() is False
|
||||
movie.reload(checkFiles=False)
|
||||
assert movie.isFullObject() is False
|
||||
movie.reload()
|
||||
assert movie.isFullObject() is True
|
||||
movie_via_search = plex.library.search(movie.title)[0]
|
||||
assert movie_via_search.isFullObject() is False
|
||||
movie_via_search.reload()
|
||||
assert movie_via_search.isFullObject() is True
|
||||
movie_via_section_search = plex.library.section("Movies").search(movie.title)[0]
|
||||
assert movie_via_section_search.isFullObject() is False
|
||||
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
|
||||
|
||||
|
||||
def test_video_Movie_isPartialObject(movie):
|
||||
assert movie.isPartialObject()
|
||||
|
||||
|
||||
def test_video_Movie_media_delete(movie, patched_http_call):
|
||||
for media in movie.media:
|
||||
media.delete()
|
||||
|
||||
|
||||
def test_video_Movie_iterParts(movie):
|
||||
assert len(list(movie.iterParts())) >= 1
|
||||
|
||||
|
||||
def test_video_Movie_download(monkeydownload, tmpdir, movie):
|
||||
filepaths = movie.download(savepath=str(tmpdir))
|
||||
assert len(filepaths) == 1
|
||||
with_resolution = movie.download(
|
||||
savepath=str(tmpdir), keep_original_filename=True, videoResolution="500x300"
|
||||
)
|
||||
assert len(with_resolution) == 1
|
||||
filename = os.path.basename(movie.media[0].parts[0].file)
|
||||
assert filename in with_resolution[0]
|
||||
|
||||
|
||||
def test_video_Movie_subtitlestreams(movie):
|
||||
assert not movie.subtitleStreams()
|
||||
|
||||
|
||||
def test_video_Episode_subtitlestreams(episode):
|
||||
assert not episode.subtitleStreams()
|
||||
|
||||
|
||||
def test_video_Movie_upload_select_remove_subtitle(movie, subtitle):
|
||||
|
||||
filepath = os.path.realpath(subtitle.name)
|
||||
|
||||
movie.uploadSubtitles(filepath)
|
||||
movie.reload()
|
||||
subtitles = [sub.title for sub in movie.subtitleStreams()]
|
||||
subname = subtitle.name.rsplit(".", 1)[0]
|
||||
assert subname in subtitles
|
||||
|
||||
subtitleSelection = movie.subtitleStreams()[0]
|
||||
parts = list(movie.iterParts())
|
||||
parts[0].setDefaultSubtitleStream(subtitleSelection)
|
||||
movie.reload()
|
||||
|
||||
subtitleSelection = movie.subtitleStreams()[0]
|
||||
assert subtitleSelection.selected
|
||||
|
||||
movie.removeSubtitles(streamTitle=subname)
|
||||
movie.reload()
|
||||
subtitles = [sub.title for sub in movie.subtitleStreams()]
|
||||
assert subname not in subtitles
|
||||
|
||||
try:
|
||||
os.remove(filepath)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def test_video_Movie_history(movie):
|
||||
movie.markWatched()
|
||||
history = movie.history()
|
||||
|
@ -611,6 +573,50 @@ def test_video_Movie_extras(movies):
|
|||
assert extra.type == 'clip'
|
||||
assert extra.section() == movies
|
||||
|
||||
|
||||
def test_video_Movie_mixins_edit_advanced_settings(movie):
|
||||
test_mixins.edit_advanced_settings(movie)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Changing images fails randomly")
|
||||
def test_video_Movie_mixins_images(movie):
|
||||
test_mixins.lock_art(movie)
|
||||
test_mixins.lock_poster(movie)
|
||||
test_mixins.edit_art(movie)
|
||||
test_mixins.edit_poster(movie)
|
||||
|
||||
|
||||
def test_video_Movie_mixins_themes(movie):
|
||||
test_mixins.edit_theme(movie)
|
||||
|
||||
|
||||
def test_video_Movie_mixins_rating(movie):
|
||||
test_mixins.edit_rating(movie)
|
||||
|
||||
|
||||
def test_video_Movie_mixins_tags(movie):
|
||||
test_mixins.edit_collection(movie)
|
||||
test_mixins.edit_country(movie)
|
||||
test_mixins.edit_director(movie)
|
||||
test_mixins.edit_genre(movie)
|
||||
test_mixins.edit_label(movie)
|
||||
test_mixins.edit_producer(movie)
|
||||
test_mixins.edit_writer(movie)
|
||||
|
||||
|
||||
def test_video_Movie_media_tags(movie):
|
||||
movie.reload()
|
||||
test_media.tag_collection(movie)
|
||||
test_media.tag_country(movie)
|
||||
test_media.tag_director(movie)
|
||||
test_media.tag_genre(movie)
|
||||
test_media.tag_label(movie)
|
||||
test_media.tag_producer(movie)
|
||||
test_media.tag_role(movie)
|
||||
test_media.tag_similar(movie)
|
||||
test_media.tag_writer(movie)
|
||||
|
||||
|
||||
def test_video_Movie_PlexWebURL(plex, movie):
|
||||
url = movie.getWebURL()
|
||||
assert url.startswith('https://app.plex.tv/desktop')
|
||||
|
@ -799,6 +805,10 @@ def test_video_Show_mixins_images(show):
|
|||
test_mixins.attr_posterUrl(show)
|
||||
|
||||
|
||||
def test_video_Show_mixins_themes(show):
|
||||
test_mixins.edit_theme(show)
|
||||
|
||||
|
||||
def test_video_Show_mixins_rating(show):
|
||||
test_mixins.edit_rating(show)
|
||||
|
||||
|
@ -860,6 +870,7 @@ def test_video_Season_attrs(show):
|
|||
assert utils.is_metadata(season.parentKey)
|
||||
assert utils.is_int(season.parentRatingKey)
|
||||
assert season.parentStudio == "Revolution Sun Studios"
|
||||
assert utils.is_metadata(season.parentTheme)
|
||||
if season.parentThumb:
|
||||
assert utils.is_thumb(season.parentThumb)
|
||||
assert season.parentTitle == "Game of Thrones"
|
||||
|
@ -930,6 +941,11 @@ def test_video_Season_mixins_images(show):
|
|||
test_mixins.attr_posterUrl(season)
|
||||
|
||||
|
||||
def test_video_Season_mixins_themes(show):
|
||||
season = show.season(season=1)
|
||||
test_mixins.attr_themeUrl(season)
|
||||
|
||||
|
||||
def test_video_Season_mixins_rating(show):
|
||||
season = show.season(season=1)
|
||||
test_mixins.edit_rating(season)
|
||||
|
@ -1142,6 +1158,10 @@ def test_video_Episode_mixins_images(episode):
|
|||
test_mixins.attr_posterUrl(episode)
|
||||
|
||||
|
||||
def test_video_Episode_mixins_themes(episode):
|
||||
test_mixins.attr_themeUrl(episode)
|
||||
|
||||
|
||||
def test_video_Episode_mixins_rating(episode):
|
||||
test_mixins.edit_rating(episode)
|
||||
|
||||
|
|
Loading…
Reference in a new issue