From 7aaf56a62d60e2079347d24d804de772852d838b Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 14:35:13 -0800 Subject: [PATCH 01/10] Move all tag editing to a mixin --- plexapi/audio.py | 7 +- plexapi/base.py | 28 ------ plexapi/library.py | 3 +- plexapi/mixin.py | 221 +++++++++++++++++++++++++++++++++++++++++++++ plexapi/photo.py | 3 +- plexapi/video.py | 7 +- 6 files changed, 233 insertions(+), 36 deletions(-) create mode 100644 plexapi/mixin.py diff --git a/plexapi/audio.py b/plexapi/audio.py index 53f7d9bd..a8052922 100644 --- a/plexapi/audio.py +++ b/plexapi/audio.py @@ -4,6 +4,7 @@ from urllib.parse import quote_plus from plexapi import library, media, utils from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest +from plexapi.mixin import EditCollection, EditCountry, EditGenre, EditLabel, EditMood, EditSimilarArtist, EditStyle class Audio(PlexPartialObject): @@ -123,7 +124,7 @@ class Audio(PlexPartialObject): @utils.registerPlexObject -class Artist(Audio): +class Artist(Audio, EditCollection, EditCountry, EditGenre, EditMood, EditSimilarArtist, EditStyle): """ Represents a single Artist. Attributes: @@ -226,7 +227,7 @@ class Artist(Audio): @utils.registerPlexObject -class Album(Audio): +class Album(Audio, EditCollection, EditGenre, EditLabel, EditMood, EditStyle): """ Represents a single Album. Attributes: @@ -332,7 +333,7 @@ class Album(Audio): @utils.registerPlexObject -class Track(Audio, Playable): +class Track(Audio, Playable, EditMood): """ Represents a single Track. Attributes: diff --git a/plexapi/base.py b/plexapi/base.py index 4d9f397f..814a4d94 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -468,34 +468,6 @@ class PlexPartialObject(PlexObject): self.edit(**d) self.refresh() - def addCollection(self, collections): - """ Add a collection(s). - - Parameters: - collections (list): list of strings - """ - self._edit_tags('collection', collections) - - def removeCollection(self, collections): - """ Remove a collection(s). """ - self._edit_tags('collection', collections, remove=True) - - def addLabel(self, labels): - """ Add a label(s). """ - self._edit_tags('label', labels) - - def removeLabel(self, labels): - """ Remove a label(s). """ - self._edit_tags('label', labels, remove=True) - - def addGenre(self, genres): - """ Add a genre(s). """ - self._edit_tags('genre', genres) - - def removeGenre(self, genres): - """ Remove a genre(s). """ - self._edit_tags('genre', genres, remove=True) - def refresh(self): """ Refreshing a Library or individual item causes the metadata for the item to be refreshed, even if it already has metadata. You can think of refreshing as diff --git a/plexapi/library.py b/plexapi/library.py index e282a9f7..860a7bc8 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -4,6 +4,7 @@ from urllib.parse import quote, quote_plus, unquote, urlencode from plexapi import X_PLEX_CONTAINER_SIZE, log, media, utils from plexapi.base import OPERATORS, PlexObject, PlexPartialObject from plexapi.exceptions import BadRequest, NotFound +from plexapi.mixin import EditLabel from plexapi.settings import Setting from plexapi.utils import deprecated @@ -1525,7 +1526,7 @@ class FirstCharacter(PlexObject): @utils.registerPlexObject -class Collections(PlexPartialObject): +class Collections(PlexPartialObject, EditLabel): """ Represents a single Collection. Attributes: diff --git a/plexapi/mixin.py b/plexapi/mixin.py new file mode 100644 index 00000000..1e887208 --- /dev/null +++ b/plexapi/mixin.py @@ -0,0 +1,221 @@ +# -*- coding: utf-8 -*- + + +class EditCollection(object): + """ Mixin for Plex objects that can have collections. """ + + def addCollection(self, collections): + """ Add a collection tag(s). + + Parameters: + collections (list): List of strings. + """ + self._edit_tags('collection', collections) + + def removeCollection(self, collections): + """ Remove a collection tag(s). + + Parameters: + collections (list): List of strings. + """ + self._edit_tags('collection', collections, remove=True) + + +class EditCountry(object): + """ Mixin for Plex objects that can have countries. """ + + def addCountry(self, countries): + """ Add a country tag(s). + + Parameters: + countries (list): List of strings. + """ + self._edit_tags('country', countries) + + def removeCountry(self, countries): + """ Remove a country tag(s). + + Parameters: + countries (list): List of strings. + """ + self._edit_tags('country', countries, remove=True) + + +class EditDirector(object): + """ Mixin for Plex objects that can have directors. """ + + def addDirector(self, directors): + """ Add a director tag(s). + + Parameters: + directors (list): List of strings. + """ + self._edit_tags('director', directors) + + def removeDirector(self, directors): + """ Remove a director tag(s). + + Parameters: + directors (list): List of strings. + """ + self._edit_tags('director', directors, remove=True) + + +class EditGenre(object): + """ Mixin for Plex objects that can have genres. """ + + def addGenre(self, genres): + """ Add a genre tag(s). + + Parameters: + genres (list): List of strings. + """ + self._edit_tags('genre', genres) + + def removeGenre(self, genres): + """ Remove a genre tag(s). + + Parameters: + genres (list): List of strings. + """ + self._edit_tags('genre', genres, remove=True) + + +class EditLabel(object): + """ Mixin for Plex objects that can have labels. """ + + def addLabel(self, labels): + """ Add a label tag(s). + + Parameters: + labels (list): List of strings. + """ + self._edit_tags('label', labels) + + def removeLabel(self, labels): + """ Remove a label tag(s). + + Parameters: + labels (list): List of strings. + """ + self._edit_tags('label', labels, remove=True) + + +class EditMood(object): + """ Mixin for Plex objects that can have moods. """ + + def addMood(self, moods): + """ Add a mood tag(s). + + Parameters: + moods (list): List of strings. + """ + self._edit_tags('mood', moods) + + def removeMood(self, moods): + """ Remove a mood tag(s). + + Parameters: + moods (list): List of strings. + """ + self._edit_tags('mood', moods, remove=True) + + +class EditProducer(object): + """ Mixin for Plex objects that can have producers. """ + + def addProducer(self, producers): + """ Add a producer tag(s). + + Parameters: + producers (list): List of strings. + """ + self._edit_tags('producer', producers) + + def removeProducer(self, producers): + """ Remove a producer tag(s). + + Parameters: + producers (list): List of strings. + """ + self._edit_tags('producer', producers, remove=True) + + +class EditSimilarArtist(object): + """ Mixin for Plex objects that can have similar artists. """ + + def addSimilarArtist(self, artists): + """ Add a similar artist tag(s). + + Parameters: + artists (list): List of strings. + """ + self._edit_tags('similar', artists) + + def removeSimilarArtist(self, artists): + """ Remove a similar artist tag(s). + + Parameters: + artists (list): List of strings. + """ + self._edit_tags('similar', artists, remove=True) + + +class EditStyle(object): + """ Mixin for Plex objects that can have styles. """ + + def addStyle(self, styles): + """ Add a style tag(s). + + Parameters: + styles (list): List of strings. + """ + self._edit_tags('style', styles) + + def removeStyle(self, styles): + """ Remove a style tag(s). + + Parameters: + styles (list): List of strings. + """ + self._edit_tags('style', styles, remove=True) + + +class EditTag(object): + """ Mixin for Plex objects that can have tags. """ + + def addTag(self, tags): + """ Add a tag(s). + + Parameters: + tags (list): List of strings. + """ + self._edit_tags('tag', tags) + + def removeTag(self, tags): + """ Remove a tag(s). + + Parameters: + tags (list): List of strings. + """ + self._edit_tags('tag', tags, remove=True) + + +class EditWriter(object): + """ Mixin for Plex objects that can have writers. """ + + def addWriter(self, writers): + """ Add a writer tag(s). + + Parameters: + writers (list): List of strings. + """ + self._edit_tags('writer', writers) + + def removeWriter(self, writers): + """ Remove a writer tag(s). + + Parameters: + writers (list): List of strings. + """ + self._edit_tags('writer', writers, remove=True) diff --git a/plexapi/photo.py b/plexapi/photo.py index 49d640bc..cb09ce44 100644 --- a/plexapi/photo.py +++ b/plexapi/photo.py @@ -4,6 +4,7 @@ from urllib.parse import quote_plus from plexapi import media, utils, video from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest +from plexapi.mixin import EditTag @utils.registerPlexObject @@ -136,7 +137,7 @@ class Photoalbum(PlexPartialObject): @utils.registerPlexObject -class Photo(PlexPartialObject, Playable): +class Photo(PlexPartialObject, Playable, EditTag): """ Represents a single Photo. Attributes: diff --git a/plexapi/video.py b/plexapi/video.py index 0a184b57..1055ea3b 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -5,6 +5,7 @@ from urllib.parse import quote_plus, urlencode from plexapi import library, media, settings, utils from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest, NotFound +from plexapi.mixin import EditCollection, EditCountry, EditDirector, EditGenre, EditLabel, EditProducer, EditWriter class Video(PlexPartialObject): @@ -259,7 +260,7 @@ class Video(PlexPartialObject): @utils.registerPlexObject -class Movie(Playable, Video): +class Movie(Playable, Video, EditCollection, EditCountry, EditDirector, EditGenre, EditLabel, EditProducer, EditWriter): """ Represents a single Movie. Attributes: @@ -383,7 +384,7 @@ class Movie(Playable, Video): @utils.registerPlexObject -class Show(Video): +class Show(Video, EditCollection, EditGenre, EditLabel): """ Represents a single Show (including all seasons and episodes). Attributes: @@ -707,7 +708,7 @@ class Season(Video): @utils.registerPlexObject -class Episode(Playable, Video): +class Episode(Playable, Video, EditDirector, EditWriter): """ Represents a single Shows Episode. Attributes: From cfc5bdae26aa5eda801549fa1f05bab302ad95b7 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 14:32:02 -0800 Subject: [PATCH 02/10] Photo plural tags attribute --- plexapi/photo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plexapi/photo.py b/plexapi/photo.py index cb09ce44..86e017df 100644 --- a/plexapi/photo.py +++ b/plexapi/photo.py @@ -164,7 +164,7 @@ class Photo(PlexPartialObject, Playable, EditTag): parentTitle (str): Name of the photo album for the photo. ratingKey (int): Unique key identifying the photo. summary (str): Summary of the photo. - tag (List<:class:`~plexapi.media.Tag`>): List of tag objects. + tags (List<:class:`~plexapi.media.Tag`>): List of tag objects. thumb (str): URL to thumbnail image (/library/metadata//thumb/). title (str): Name of the photo. titleSort (str): Title to use when sorting (defaults to title). @@ -200,7 +200,7 @@ class Photo(PlexPartialObject, Playable, EditTag): self.parentTitle = data.attrib.get('parentTitle') self.ratingKey = utils.cast(int, data.attrib.get('ratingKey')) self.summary = data.attrib.get('summary') - self.tag = self.findItems(data, media.Tag) + self.tags = self.findItems(data, media.Tag) self.thumb = data.attrib.get('thumb') self.title = data.attrib.get('title') self.titleSort = data.attrib.get('titleSort', self.title) From 1b378d3f1c95675745df1f003915609413f48fe3 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 14:36:38 -0800 Subject: [PATCH 03/10] Add helper function to get the plural tag --- plexapi/base.py | 4 ++-- plexapi/utils.py | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/plexapi/base.py b/plexapi/base.py index 814a4d94..295f502d 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -5,7 +5,7 @@ from urllib.parse import quote_plus, urlencode from plexapi import log, utils from plexapi.exceptions import BadRequest, NotFound, UnknownType, Unsupported -from plexapi.utils import tag_helper +from plexapi.utils import get_plural_attr, tag_helper DONT_RELOAD_FOR_KEYS = ['key', 'session'] OPERATORS = { @@ -462,7 +462,7 @@ class PlexPartialObject(PlexObject): """ if not isinstance(items, list): items = [items] - value = getattr(self, tag + 's') + value = getattr(self, get_plural_attr(tag)) existing_cols = [t.tag for t in value if t and remove is False] d = tag_helper(tag, existing_cols + items, locked, remove) self.edit(**d) diff --git a/plexapi/utils.py b/plexapi/utils.py index 8579ca6c..c58dea2b 100644 --- a/plexapi/utils.py +++ b/plexapi/utils.py @@ -335,6 +335,15 @@ def download(url, token, filename=None, savepath=None, session=None, chunksize=4 return fullpath +def get_plural_attr(tag): + if tag == 'country': + return 'countries' + elif tag == 'similar': + return 'similar' + else: + return tag + 's' + + def tag_helper(tag, items, locked=True, remove=False): """ Simple tag helper for editing a object. """ if not isinstance(items, list): From deda4e1b2b4e68652b27a50db5aff1f244fd5223 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 14:40:02 -0800 Subject: [PATCH 04/10] Add mixin tag tests --- tests/test_audio.py | 26 ++++++++++++++++--- tests/test_library.py | 5 ++++ tests/test_mixin.py | 58 +++++++++++++++++++++++++++++++++++++++++++ tests/test_video.py | 30 ++++++++++++++-------- 4 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 tests/test_mixin.py diff --git a/tests/test_audio.py b/tests/test_audio.py index e14bc06b..cba78383 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -2,6 +2,7 @@ from datetime import datetime from . import conftest as utils +from . import test_mixin def test_audio_Artist_attr(artist): @@ -63,6 +64,15 @@ def test_audio_Artist_albums(artist): assert len(albums) == 1 and albums[0].title == "Layers" +def test_audio_Artist_mixin_tags(artist): + test_mixin.edit_collection(artist) + test_mixin.edit_country(artist) + test_mixin.edit_genre(artist) + test_mixin.edit_mood(artist) + test_mixin.edit_similar_artist(artist) + test_mixin.edit_style(artist) + + def test_audio_Album_attrs(album): assert utils.is_datetime(album.addedAt) assert isinstance(album.genres, list) @@ -211,6 +221,14 @@ def test_audio_Album_artist(album): artist.title == "Broke For Free" +def test_audio_Album_mixin_tags(album): + test_mixin.edit_collection(album) + test_mixin.edit_genre(album) + test_mixin.edit_label(album) + test_mixin.edit_mood(album) + test_mixin.edit_style(album) + + def test_audio_Track_attrs(album): track = album.get("As Colourful As Ever").reload() assert utils.is_datetime(track.addedAt) @@ -328,6 +346,10 @@ def test_audio_Track_artist(album, artist): assert tracks[0].artist() == artist +def test_audio_Track_mixin_tags(track): + test_mixin.edit_mood(track) + + def test_audio_Audio_section(artist, album, track): assert artist.section() assert album.section() @@ -348,7 +370,3 @@ def test_audio_album_download(monkeydownload, album, tmpdir): def test_audio_Artist_download(monkeydownload, artist, tmpdir): f = artist.download(savepath=str(tmpdir)) assert len(f) == 1 - - -def test_audio_Album_label(album, patched_http_call): - album.addLabel("YO") diff --git a/tests/test_library.py b/tests/test_library.py index 83404f8f..b6f13ea3 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -4,6 +4,7 @@ import pytest from plexapi.exceptions import NotFound from . import conftest as utils +from . import test_mixin def test_library_Library_section(plex): @@ -313,6 +314,10 @@ def test_library_Collection_items(collection): assert len(items) == 1 +def test_library_Collection_mixin_tags(collection): + test_mixin.edit_label(collection) + + def test_search_with_weird_a(plex): ep_title = "Coup de GrĂ¢ce" result_root = plex.search(ep_title) diff --git a/tests/test_mixin.py b/tests/test_mixin.py new file mode 100644 index 00000000..2fe6a1b6 --- /dev/null +++ b/tests/test_mixin.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +TEST_MIXIN_TAG = "Test Tag" + + +def _mixin_test_tag(obj, attr, tag_method): + add_tag_method = getattr(obj, 'add' + tag_method) + remove_tag_method = getattr(obj, 'remove' + tag_method) + assert TEST_MIXIN_TAG not in [tag.tag for tag in getattr(obj, attr)] + add_tag_method(TEST_MIXIN_TAG) + obj.reload() + assert TEST_MIXIN_TAG in [tag.tag for tag in getattr(obj, attr)] + remove_tag_method(TEST_MIXIN_TAG) + obj.reload() + assert getattr(obj, attr) not in [tag.tag for tag in getattr(obj, attr)] + + +def edit_collection(obj): + _mixin_test_tag(obj, 'collections', 'Collection') + + +def edit_country(obj): + _mixin_test_tag(obj, 'countries', 'Country') + + +def edit_director(obj): + _mixin_test_tag(obj, 'directors', 'Director') + + +def edit_genre(obj): + _mixin_test_tag(obj, 'genres', 'Genre') + + +def edit_label(obj): + _mixin_test_tag(obj, 'labels', 'Label') + + +def edit_mood(obj): + _mixin_test_tag(obj, 'moods', 'Mood') + + +def edit_producer(obj): + _mixin_test_tag(obj, 'producers', 'Producer') + + +def edit_similar_artist(obj): + _mixin_test_tag(obj, 'similar', 'SimilarArtist') + + +def edit_style(obj): + _mixin_test_tag(obj, 'styles', 'Style') + + +def edit_tag(obj): + _mixin_test_tag(obj, 'tags', 'Tag') + + +def edit_writer(obj): + _mixin_test_tag(obj, 'writers', 'Writer') diff --git a/tests/test_video.py b/tests/test_video.py index 5eb508a5..3214e8eb 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -8,6 +8,7 @@ import pytest from plexapi.exceptions import BadRequest, NotFound from . import conftest as utils +from . import test_mixin def test_video_Movie(movies, movie): @@ -39,16 +40,14 @@ def test_video_Movie_merge(movie, patched_http_call): movie.merge(1337) -def test_video_Movie_addCollection(movie): - labelname = "Random_label" - org_collection = [tag.tag for tag in movie.collections if tag] - assert labelname not in org_collection - movie.addCollection(labelname) - movie.reload() - assert labelname in [tag.tag for tag in movie.collections if tag] - movie.removeCollection(labelname) - movie.reload() - assert labelname not in [tag.tag for tag in movie.collections if tag] +def test_video_Movie_mixin_tags(movie): + test_mixin.edit_collection(movie) + test_mixin.edit_country(movie) + test_mixin.edit_director(movie) + test_mixin.edit_genre(movie) + test_mixin.edit_label(movie) + test_mixin.edit_producer(movie) + test_mixin.edit_writer(movie) def test_video_Movie_getStreamURL(movie, account): @@ -730,6 +729,12 @@ def test_video_Show_section(show): assert section.title == "TV Shows" +def test_video_Show_mixin_tags(show): + test_mixin.edit_collection(show) + test_mixin.edit_genre(show) + test_mixin.edit_label(show) + + def test_video_Episode(show): episode = show.episode("Winter Is Coming") assert episode == show.episode(season=1, episode=1) @@ -820,6 +825,11 @@ def test_video_Episode_attrs(episode): assert part.accessible +def test_video_Episode_mixin_tags(episode): + test_mixin.edit_director(episode) + test_mixin.edit_writer(episode) + + def test_video_Season(show): seasons = show.seasons() assert len(seasons) == 2 From dd8373176e4ce083b8ca9f5b08e3bcfc0b50e80d Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 14:40:22 -0800 Subject: [PATCH 05/10] Update test collection fixture --- tests/conftest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 204cf7a1..8db421f7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -222,14 +222,14 @@ def movie(movies): @pytest.fixture() -def collection(plex): +def collection(movies): try: - return plex.library.section("Movies").collections()[0] + return movies.collections()[0] except IndexError: - movie = plex.library.section("Movies").get("Elephants Dream") + movie = movies.get("Elephants Dream") movie.addCollection(["marvel"]) - n = plex.library.section("Movies").reload() + n = movies.reload() return n.collections()[0] From c23d9635f56933f4308fa99ab385f7bf88cd503c Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 15:03:23 -0800 Subject: [PATCH 06/10] Rename to mixins --- plexapi/audio.py | 2 +- plexapi/library.py | 2 +- plexapi/{mixin.py => mixins.py} | 0 plexapi/photo.py | 2 +- plexapi/video.py | 2 +- tests/test_audio.py | 32 ++++++++++++------------- tests/test_library.py | 6 ++--- tests/{test_mixin.py => test_mixins.py} | 24 +++++++++---------- tests/test_video.py | 32 ++++++++++++------------- 9 files changed, 51 insertions(+), 51 deletions(-) rename plexapi/{mixin.py => mixins.py} (100%) rename tests/{test_mixin.py => test_mixins.py} (57%) diff --git a/plexapi/audio.py b/plexapi/audio.py index a8052922..2866426c 100644 --- a/plexapi/audio.py +++ b/plexapi/audio.py @@ -4,7 +4,7 @@ from urllib.parse import quote_plus from plexapi import library, media, utils from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest -from plexapi.mixin import EditCollection, EditCountry, EditGenre, EditLabel, EditMood, EditSimilarArtist, EditStyle +from plexapi.mixins import EditCollection, EditCountry, EditGenre, EditLabel, EditMood, EditSimilarArtist, EditStyle class Audio(PlexPartialObject): diff --git a/plexapi/library.py b/plexapi/library.py index 860a7bc8..36ea426b 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -4,7 +4,7 @@ from urllib.parse import quote, quote_plus, unquote, urlencode from plexapi import X_PLEX_CONTAINER_SIZE, log, media, utils from plexapi.base import OPERATORS, PlexObject, PlexPartialObject from plexapi.exceptions import BadRequest, NotFound -from plexapi.mixin import EditLabel +from plexapi.mixins import EditLabel from plexapi.settings import Setting from plexapi.utils import deprecated diff --git a/plexapi/mixin.py b/plexapi/mixins.py similarity index 100% rename from plexapi/mixin.py rename to plexapi/mixins.py diff --git a/plexapi/photo.py b/plexapi/photo.py index 86e017df..ab88841b 100644 --- a/plexapi/photo.py +++ b/plexapi/photo.py @@ -4,7 +4,7 @@ from urllib.parse import quote_plus from plexapi import media, utils, video from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest -from plexapi.mixin import EditTag +from plexapi.mixins import EditTag @utils.registerPlexObject diff --git a/plexapi/video.py b/plexapi/video.py index 1055ea3b..6972f6fa 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -5,7 +5,7 @@ from urllib.parse import quote_plus, urlencode from plexapi import library, media, settings, utils from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest, NotFound -from plexapi.mixin import EditCollection, EditCountry, EditDirector, EditGenre, EditLabel, EditProducer, EditWriter +from plexapi.mixins import EditCollection, EditCountry, EditDirector, EditGenre, EditLabel, EditProducer, EditWriter class Video(PlexPartialObject): diff --git a/tests/test_audio.py b/tests/test_audio.py index cba78383..13ab8066 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -2,7 +2,7 @@ from datetime import datetime from . import conftest as utils -from . import test_mixin +from . import test_mixins def test_audio_Artist_attr(artist): @@ -64,13 +64,13 @@ def test_audio_Artist_albums(artist): assert len(albums) == 1 and albums[0].title == "Layers" -def test_audio_Artist_mixin_tags(artist): - test_mixin.edit_collection(artist) - test_mixin.edit_country(artist) - test_mixin.edit_genre(artist) - test_mixin.edit_mood(artist) - test_mixin.edit_similar_artist(artist) - test_mixin.edit_style(artist) +def test_audio_Artist_mixins_tags(artist): + test_mixins.edit_collection(artist) + test_mixins.edit_country(artist) + test_mixins.edit_genre(artist) + test_mixins.edit_mood(artist) + test_mixins.edit_similar_artist(artist) + test_mixins.edit_style(artist) def test_audio_Album_attrs(album): @@ -221,12 +221,12 @@ def test_audio_Album_artist(album): artist.title == "Broke For Free" -def test_audio_Album_mixin_tags(album): - test_mixin.edit_collection(album) - test_mixin.edit_genre(album) - test_mixin.edit_label(album) - test_mixin.edit_mood(album) - test_mixin.edit_style(album) +def test_audio_Album_mixins_tags(album): + test_mixins.edit_collection(album) + test_mixins.edit_genre(album) + test_mixins.edit_label(album) + test_mixins.edit_mood(album) + test_mixins.edit_style(album) def test_audio_Track_attrs(album): @@ -346,8 +346,8 @@ def test_audio_Track_artist(album, artist): assert tracks[0].artist() == artist -def test_audio_Track_mixin_tags(track): - test_mixin.edit_mood(track) +def test_audio_Track_mixins_tags(track): + test_mixins.edit_mood(track) def test_audio_Audio_section(artist, album, track): diff --git a/tests/test_library.py b/tests/test_library.py index b6f13ea3..b7949387 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -4,7 +4,7 @@ import pytest from plexapi.exceptions import NotFound from . import conftest as utils -from . import test_mixin +from . import test_mixins def test_library_Library_section(plex): @@ -314,8 +314,8 @@ def test_library_Collection_items(collection): assert len(items) == 1 -def test_library_Collection_mixin_tags(collection): - test_mixin.edit_label(collection) +def test_library_Collection_mixins_tags(collection): + test_mixins.edit_label(collection) def test_search_with_weird_a(plex): diff --git a/tests/test_mixin.py b/tests/test_mixins.py similarity index 57% rename from tests/test_mixin.py rename to tests/test_mixins.py index 2fe6a1b6..2440cacc 100644 --- a/tests/test_mixin.py +++ b/tests/test_mixins.py @@ -2,7 +2,7 @@ TEST_MIXIN_TAG = "Test Tag" -def _mixin_test_tag(obj, attr, tag_method): +def _test_mixins_tag(obj, attr, tag_method): add_tag_method = getattr(obj, 'add' + tag_method) remove_tag_method = getattr(obj, 'remove' + tag_method) assert TEST_MIXIN_TAG not in [tag.tag for tag in getattr(obj, attr)] @@ -15,44 +15,44 @@ def _mixin_test_tag(obj, attr, tag_method): def edit_collection(obj): - _mixin_test_tag(obj, 'collections', 'Collection') + _test_mixins_tag(obj, 'collections', 'Collection') def edit_country(obj): - _mixin_test_tag(obj, 'countries', 'Country') + _test_mixins_tag(obj, 'countries', 'Country') def edit_director(obj): - _mixin_test_tag(obj, 'directors', 'Director') + _test_mixins_tag(obj, 'directors', 'Director') def edit_genre(obj): - _mixin_test_tag(obj, 'genres', 'Genre') + _test_mixins_tag(obj, 'genres', 'Genre') def edit_label(obj): - _mixin_test_tag(obj, 'labels', 'Label') + _test_mixins_tag(obj, 'labels', 'Label') def edit_mood(obj): - _mixin_test_tag(obj, 'moods', 'Mood') + _test_mixins_tag(obj, 'moods', 'Mood') def edit_producer(obj): - _mixin_test_tag(obj, 'producers', 'Producer') + _test_mixins_tag(obj, 'producers', 'Producer') def edit_similar_artist(obj): - _mixin_test_tag(obj, 'similar', 'SimilarArtist') + _test_mixins_tag(obj, 'similar', 'SimilarArtist') def edit_style(obj): - _mixin_test_tag(obj, 'styles', 'Style') + _test_mixins_tag(obj, 'styles', 'Style') def edit_tag(obj): - _mixin_test_tag(obj, 'tags', 'Tag') + _test_mixins_tag(obj, 'tags', 'Tag') def edit_writer(obj): - _mixin_test_tag(obj, 'writers', 'Writer') + _test_mixins_tag(obj, 'writers', 'Writer') diff --git a/tests/test_video.py b/tests/test_video.py index 3214e8eb..26046fe8 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -8,7 +8,7 @@ import pytest from plexapi.exceptions import BadRequest, NotFound from . import conftest as utils -from . import test_mixin +from . import test_mixins def test_video_Movie(movies, movie): @@ -40,14 +40,14 @@ def test_video_Movie_merge(movie, patched_http_call): movie.merge(1337) -def test_video_Movie_mixin_tags(movie): - test_mixin.edit_collection(movie) - test_mixin.edit_country(movie) - test_mixin.edit_director(movie) - test_mixin.edit_genre(movie) - test_mixin.edit_label(movie) - test_mixin.edit_producer(movie) - test_mixin.edit_writer(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_getStreamURL(movie, account): @@ -729,10 +729,10 @@ def test_video_Show_section(show): assert section.title == "TV Shows" -def test_video_Show_mixin_tags(show): - test_mixin.edit_collection(show) - test_mixin.edit_genre(show) - test_mixin.edit_label(show) +def test_video_Show_mixins_tags(show): + test_mixins.edit_collection(show) + test_mixins.edit_genre(show) + test_mixins.edit_label(show) def test_video_Episode(show): @@ -825,9 +825,9 @@ def test_video_Episode_attrs(episode): assert part.accessible -def test_video_Episode_mixin_tags(episode): - test_mixin.edit_director(episode) - test_mixin.edit_writer(episode) +def test_video_Episode_mixins_tags(episode): + test_mixins.edit_director(episode) + test_mixins.edit_writer(episode) def test_video_Season(show): From 22bc55a74e2c9a94ac472ef03793c4f09b1c0e52 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 24 Jan 2021 19:44:36 -0800 Subject: [PATCH 07/10] Rename tag plural helper function --- plexapi/base.py | 4 ++-- plexapi/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plexapi/base.py b/plexapi/base.py index 295f502d..0ff0417b 100644 --- a/plexapi/base.py +++ b/plexapi/base.py @@ -5,7 +5,7 @@ from urllib.parse import quote_plus, urlencode from plexapi import log, utils from plexapi.exceptions import BadRequest, NotFound, UnknownType, Unsupported -from plexapi.utils import get_plural_attr, tag_helper +from plexapi.utils import tag_plural, tag_helper DONT_RELOAD_FOR_KEYS = ['key', 'session'] OPERATORS = { @@ -462,7 +462,7 @@ class PlexPartialObject(PlexObject): """ if not isinstance(items, list): items = [items] - value = getattr(self, get_plural_attr(tag)) + value = getattr(self, tag_plural(tag)) existing_cols = [t.tag for t in value if t and remove is False] d = tag_helper(tag, existing_cols + items, locked, remove) self.edit(**d) diff --git a/plexapi/utils.py b/plexapi/utils.py index c58dea2b..c6021e18 100644 --- a/plexapi/utils.py +++ b/plexapi/utils.py @@ -335,7 +335,7 @@ def download(url, token, filename=None, savepath=None, session=None, chunksize=4 return fullpath -def get_plural_attr(tag): +def tag_plural(tag): if tag == 'country': return 'countries' elif tag == 'similar': From 1bcd3549be05e3f6983887dd11ea87fb786f1604 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sat, 30 Jan 2021 16:25:08 -0800 Subject: [PATCH 08/10] Fix library timeline test queue size --- tests/test_library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_library.py b/tests/test_library.py index b7949387..5ea37f86 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -361,6 +361,6 @@ def test_library_section_timeline(plex): assert tl.mediaTagVersion > 1 assert tl.thumb == "/:/resources/movie.png" assert tl.title1 == "Movies" - assert tl.updateQueueSize == 0 + assert utils.is_int(tl.updateQueueSize, gte=0) assert tl.viewGroup == "secondary" assert tl.viewMode == 65592 From 9c1ac7981df96d52c7ddef74f545d6c3d971f33b Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sat, 6 Feb 2021 20:21:49 -0800 Subject: [PATCH 09/10] Rename mixins --- plexapi/audio.py | 8 ++++---- plexapi/library.py | 4 ++-- plexapi/mixins.py | 20 ++++++++++---------- plexapi/photo.py | 4 ++-- plexapi/video.py | 8 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/plexapi/audio.py b/plexapi/audio.py index 2866426c..1a5b3c21 100644 --- a/plexapi/audio.py +++ b/plexapi/audio.py @@ -4,7 +4,7 @@ from urllib.parse import quote_plus from plexapi import library, media, utils from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest -from plexapi.mixins import EditCollection, EditCountry, EditGenre, EditLabel, EditMood, EditSimilarArtist, EditStyle +from plexapi.mixins import CollectionMixin, CountryMixin, GenreMixin, LabelMixin, MoodMixin, SimilarArtistMixin, StyleMixin class Audio(PlexPartialObject): @@ -124,7 +124,7 @@ class Audio(PlexPartialObject): @utils.registerPlexObject -class Artist(Audio, EditCollection, EditCountry, EditGenre, EditMood, EditSimilarArtist, EditStyle): +class Artist(Audio, CollectionMixin, CountryMixin, GenreMixin, MoodMixin, SimilarArtistMixin, StyleMixin): """ Represents a single Artist. Attributes: @@ -227,7 +227,7 @@ class Artist(Audio, EditCollection, EditCountry, EditGenre, EditMood, EditSimila @utils.registerPlexObject -class Album(Audio, EditCollection, EditGenre, EditLabel, EditMood, EditStyle): +class Album(Audio, CollectionMixin, GenreMixin, LabelMixin, MoodMixin, StyleMixin): """ Represents a single Album. Attributes: @@ -333,7 +333,7 @@ class Album(Audio, EditCollection, EditGenre, EditLabel, EditMood, EditStyle): @utils.registerPlexObject -class Track(Audio, Playable, EditMood): +class Track(Audio, Playable, MoodMixin): """ Represents a single Track. Attributes: diff --git a/plexapi/library.py b/plexapi/library.py index 36ea426b..d972db61 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -4,7 +4,7 @@ from urllib.parse import quote, quote_plus, unquote, urlencode from plexapi import X_PLEX_CONTAINER_SIZE, log, media, utils from plexapi.base import OPERATORS, PlexObject, PlexPartialObject from plexapi.exceptions import BadRequest, NotFound -from plexapi.mixins import EditLabel +from plexapi.mixins import LabelMixin from plexapi.settings import Setting from plexapi.utils import deprecated @@ -1526,7 +1526,7 @@ class FirstCharacter(PlexObject): @utils.registerPlexObject -class Collections(PlexPartialObject, EditLabel): +class Collections(PlexPartialObject, LabelMixin): """ Represents a single Collection. Attributes: diff --git a/plexapi/mixins.py b/plexapi/mixins.py index 1e887208..98eef805 100644 --- a/plexapi/mixins.py +++ b/plexapi/mixins.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -class EditCollection(object): +class CollectionMixin(object): """ Mixin for Plex objects that can have collections. """ def addCollection(self, collections): @@ -21,7 +21,7 @@ class EditCollection(object): self._edit_tags('collection', collections, remove=True) -class EditCountry(object): +class CountryMixin(object): """ Mixin for Plex objects that can have countries. """ def addCountry(self, countries): @@ -41,7 +41,7 @@ class EditCountry(object): self._edit_tags('country', countries, remove=True) -class EditDirector(object): +class DirectorMixin(object): """ Mixin for Plex objects that can have directors. """ def addDirector(self, directors): @@ -61,7 +61,7 @@ class EditDirector(object): self._edit_tags('director', directors, remove=True) -class EditGenre(object): +class GenreMixin(object): """ Mixin for Plex objects that can have genres. """ def addGenre(self, genres): @@ -81,7 +81,7 @@ class EditGenre(object): self._edit_tags('genre', genres, remove=True) -class EditLabel(object): +class LabelMixin(object): """ Mixin for Plex objects that can have labels. """ def addLabel(self, labels): @@ -101,7 +101,7 @@ class EditLabel(object): self._edit_tags('label', labels, remove=True) -class EditMood(object): +class MoodMixin(object): """ Mixin for Plex objects that can have moods. """ def addMood(self, moods): @@ -121,7 +121,7 @@ class EditMood(object): self._edit_tags('mood', moods, remove=True) -class EditProducer(object): +class ProducerMixin(object): """ Mixin for Plex objects that can have producers. """ def addProducer(self, producers): @@ -141,7 +141,7 @@ class EditProducer(object): self._edit_tags('producer', producers, remove=True) -class EditSimilarArtist(object): +class SimilarArtistMixin(object): """ Mixin for Plex objects that can have similar artists. """ def addSimilarArtist(self, artists): @@ -161,7 +161,7 @@ class EditSimilarArtist(object): self._edit_tags('similar', artists, remove=True) -class EditStyle(object): +class StyleMixin(object): """ Mixin for Plex objects that can have styles. """ def addStyle(self, styles): @@ -181,7 +181,7 @@ class EditStyle(object): self._edit_tags('style', styles, remove=True) -class EditTag(object): +class TagMixin(object): """ Mixin for Plex objects that can have tags. """ def addTag(self, tags): diff --git a/plexapi/photo.py b/plexapi/photo.py index ab88841b..40f904e1 100644 --- a/plexapi/photo.py +++ b/plexapi/photo.py @@ -4,7 +4,7 @@ from urllib.parse import quote_plus from plexapi import media, utils, video from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest -from plexapi.mixins import EditTag +from plexapi.mixins import TagMixin @utils.registerPlexObject @@ -137,7 +137,7 @@ class Photoalbum(PlexPartialObject): @utils.registerPlexObject -class Photo(PlexPartialObject, Playable, EditTag): +class Photo(PlexPartialObject, Playable, TagMixin): """ Represents a single Photo. Attributes: diff --git a/plexapi/video.py b/plexapi/video.py index 6972f6fa..5064de21 100644 --- a/plexapi/video.py +++ b/plexapi/video.py @@ -5,7 +5,7 @@ from urllib.parse import quote_plus, urlencode from plexapi import library, media, settings, utils from plexapi.base import Playable, PlexPartialObject from plexapi.exceptions import BadRequest, NotFound -from plexapi.mixins import EditCollection, EditCountry, EditDirector, EditGenre, EditLabel, EditProducer, EditWriter +from plexapi.mixins import CollectionMixin, CountryMixin, DirectorMixin, GenreMixin, LabelMixin, ProducerMixin, EditWriter class Video(PlexPartialObject): @@ -260,7 +260,7 @@ class Video(PlexPartialObject): @utils.registerPlexObject -class Movie(Playable, Video, EditCollection, EditCountry, EditDirector, EditGenre, EditLabel, EditProducer, EditWriter): +class Movie(Playable, Video, CollectionMixin, CountryMixin, DirectorMixin, GenreMixin, LabelMixin, ProducerMixin, EditWriter): """ Represents a single Movie. Attributes: @@ -384,7 +384,7 @@ class Movie(Playable, Video, EditCollection, EditCountry, EditDirector, EditGenr @utils.registerPlexObject -class Show(Video, EditCollection, EditGenre, EditLabel): +class Show(Video, CollectionMixin, GenreMixin, LabelMixin): """ Represents a single Show (including all seasons and episodes). Attributes: @@ -708,7 +708,7 @@ class Season(Video): @utils.registerPlexObject -class Episode(Playable, Video, EditDirector, EditWriter): +class Episode(Playable, Video, DirectorMixin, EditWriter): """ Represents a single Shows Episode. Attributes: From 6842a8d1daf8d0fe8a86a18ab52d882dfecd4fd0 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sat, 6 Feb 2021 20:35:47 -0800 Subject: [PATCH 10/10] Fix mixin tag test --- tests/test_mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_mixins.py b/tests/test_mixins.py index 2440cacc..575cbdc0 100644 --- a/tests/test_mixins.py +++ b/tests/test_mixins.py @@ -11,7 +11,7 @@ def _test_mixins_tag(obj, attr, tag_method): assert TEST_MIXIN_TAG in [tag.tag for tag in getattr(obj, attr)] remove_tag_method(TEST_MIXIN_TAG) obj.reload() - assert getattr(obj, attr) not in [tag.tag for tag in getattr(obj, attr)] + assert TEST_MIXIN_TAG not in [tag.tag for tag in getattr(obj, attr)] def edit_collection(obj):