Skip to content

Commit

Permalink
Added AdvancedSettingsMixin (#714)
Browse files Browse the repository at this point in the history
* Added AdvancedSettingsMixin

* forgot import

* shortened line

* remove whitespace

* removed unused import

* reordered mixins

* Add preference method to AdvancedSettingsMixin

* Add tests for AdvancedSettingsMixin

Co-authored-by: JonnyWong16 <[email protected]>
  • Loading branch information
meisnate12 and JonnyWong16 authored Apr 5, 2021
1 parent 2e7ae1f commit 5584ef1
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 62 deletions.
4 changes: 2 additions & 2 deletions plexapi/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from plexapi import library, media, utils
from plexapi.base import Playable, PlexPartialObject
from plexapi.exceptions import BadRequest
from plexapi.mixins import ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin
from plexapi.mixins import AdvancedSettingsMixin, ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin
from plexapi.mixins import SplitMergeMixin, UnmatchMatchMixin
from plexapi.mixins import CollectionMixin, CountryMixin, GenreMixin, LabelMixin, MoodMixin, SimilarArtistMixin, StyleMixin

Expand Down Expand Up @@ -114,7 +114,7 @@ def sync(self, bitrate, client=None, clientId=None, limit=None, title=None):


@utils.registerPlexObject
class Artist(Audio, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
class Artist(Audio, AdvancedSettingsMixin, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
CollectionMixin, CountryMixin, GenreMixin, MoodMixin, SimilarArtistMixin, StyleMixin):
""" Represents a single Artist.
Expand Down
56 changes: 55 additions & 1 deletion plexapi/mixins.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,64 @@
# -*- coding: utf-8 -*-
from urllib.parse import quote_plus, urlencode

from plexapi import media, utils
from plexapi import media, settings, utils
from plexapi.exceptions import NotFound


class AdvancedSettingsMixin(object):
""" Mixin for Plex objects that can have advanced settings. """

def preferences(self):
""" Returns a list of :class:`~plexapi.settings.Preferences` objects. """
items = []
data = self._server.query(self._details_key)
for item in data.iter('Preferences'):
for elem in item:
setting = settings.Preferences(data=elem, server=self._server)
setting._initpath = self.key
items.append(setting)

return items

def preference(self, pref):
""" Returns a :class:`~plexapi.settings.Preferences` object for the specified pref.
Parameters:
pref (str): The id of the preference to return.
"""
prefs = self.preferences()
try:
return next(p for p in prefs if p.id == pref)
except StopIteration:
availablePrefs = [p.id for p in prefs]
raise NotFound('Unknown preference "%s" for %s. '
'Available preferences: %s'
% (pref, self.TYPE, availablePrefs)) from None

def editAdvanced(self, **kwargs):
""" Edit a Plex object's advanced settings. """
data = {}
key = '%s/prefs?' % self.key
preferences = {pref.id: list(pref.enumValues.keys()) for pref in self.preferences()}
for settingID, value in kwargs.items():
enumValues = preferences.get(settingID)
if value in enumValues:
data[settingID] = value
else:
raise NotFound('%s not found in %s' % (value, enumValues))
url = key + urlencode(data)
self._server.query(url, method=self._server._session.put)

def defaultAdvanced(self):
""" Edit all of a Plex object's advanced settings to default. """
data = {}
key = '%s/prefs?' % self.key
for preference in self.preferences():
data[preference.id] = preference.default
url = key + urlencode(data)
self._server.query(url, method=self._server._session.put)


class ArtUrlMixin(object):
""" Mixin for Plex objects that can have a background artwork url. """

Expand Down
45 changes: 5 additions & 40 deletions plexapi/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import os
from urllib.parse import quote_plus, urlencode

from plexapi import library, media, settings, utils
from plexapi import library, media, utils
from plexapi.base import Playable, PlexPartialObject
from plexapi.exceptions import BadRequest, NotFound
from plexapi.mixins import ArtUrlMixin, ArtMixin, BannerMixin, PosterUrlMixin, PosterMixin
from plexapi.exceptions import BadRequest
from plexapi.mixins import AdvancedSettingsMixin, ArtUrlMixin, ArtMixin, BannerMixin, PosterUrlMixin, PosterMixin
from plexapi.mixins import SplitMergeMixin, UnmatchMatchMixin
from plexapi.mixins import CollectionMixin, CountryMixin, DirectorMixin, GenreMixin, LabelMixin, ProducerMixin, WriterMixin

Expand Down Expand Up @@ -248,7 +248,7 @@ def sync(self, videoQuality, client=None, clientId=None, limit=None, unwatched=F


@utils.registerPlexObject
class Movie(Video, Playable, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
class Movie(Video, Playable, AdvancedSettingsMixin, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
CollectionMixin, CountryMixin, DirectorMixin, GenreMixin, LabelMixin, ProducerMixin, WriterMixin):
""" Represents a single Movie.
Expand Down Expand Up @@ -381,7 +381,7 @@ def download(self, savepath=None, keep_original_name=False, **kwargs):


@utils.registerPlexObject
class Show(Video, ArtMixin, BannerMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
class Show(Video, AdvancedSettingsMixin, ArtMixin, BannerMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
CollectionMixin, GenreMixin, LabelMixin):
""" Represents a single Show (including all seasons and episodes).
Expand Down Expand Up @@ -489,41 +489,6 @@ def isWatched(self):
""" Returns True if the show is fully watched. """
return bool(self.viewedLeafCount == self.leafCount)

def preferences(self):
""" Returns a list of :class:`~plexapi.settings.Preferences` objects. """
items = []
data = self._server.query(self._details_key)
for item in data.iter('Preferences'):
for elem in item:
setting = settings.Preferences(data=elem, server=self._server)
setting._initpath = self.key
items.append(setting)

return items

def editAdvanced(self, **kwargs):
""" Edit a show's advanced settings. """
data = {}
key = '%s/prefs?' % self.key
preferences = {pref.id: list(pref.enumValues.keys()) for pref in self.preferences()}
for settingID, value in kwargs.items():
enumValues = preferences.get(settingID)
if value in enumValues:
data[settingID] = value
else:
raise NotFound('%s not found in %s' % (value, enumValues))
url = key + urlencode(data)
self._server.query(url, method=self._server._session.put)

def defaultAdvanced(self):
""" Edit all of show's advanced settings to default. """
data = {}
key = '%s/prefs?' % self.key
for preference in self.preferences():
data[preference.id] = preference.default
url = key + urlencode(data)
self._server.query(url, method=self._server._session.put)

def hubs(self):
""" Returns a list of :class:`~plexapi.library.Hub` objects. """
data = self._server.query(self._details_key)
Expand Down
4 changes: 4 additions & 0 deletions tests/test_audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ def test_audio_Artist_albums(artist):
assert len(albums) == 1 and albums[0].title == "Layers"


def test_audio_Artist_mixins_edit_advanced_settings(artist):
test_mixins.edit_advanced_settings(artist)


def test_audio_Artist_mixins_images(artist):
test_mixins.edit_art(artist)
test_mixins.edit_poster(artist)
Expand Down
31 changes: 31 additions & 0 deletions tests/test_mixins.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from plexapi.exceptions import NotFound
from plexapi.utils import tag_singular
import pytest

from . import conftest as utils

Expand Down Expand Up @@ -146,3 +148,32 @@ def attr_bannerUrl(obj):

def attr_posterUrl(obj):
_test_mixins_imageUrl(obj, 'thumb')


def _test_mixins_editAdvanced(obj):
for pref in obj.preferences():
currentPref = obj.preference(pref.id)
currentValue = currentPref.value
newValue = next(v for v in pref.enumValues if v != currentValue)
obj.editAdvanced(**{pref.id: newValue})
obj.reload()
newPref = obj.preference(pref.id)
assert newPref.value == newValue


def _test_mixins_editAdvanced_bad_pref(obj):
with pytest.raises(NotFound):
assert obj.preference('bad-pref')


def _test_mixins_defaultAdvanced(obj):
obj.defaultAdvanced()
obj.reload()
for pref in obj.preferences():
assert pref.value == pref.default


def edit_advanced_settings(obj):
_test_mixins_editAdvanced(obj)
_test_mixins_editAdvanced_bad_pref(obj)
_test_mixins_defaultAdvanced(obj)
27 changes: 8 additions & 19 deletions tests/test_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ 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)


def test_video_Movie_mixins_images(movie):
test_mixins.edit_art(movie)
test_mixins.edit_poster(movie)
Expand Down Expand Up @@ -647,25 +651,6 @@ def test_video_Show_settings(show):
assert len(preferences) >= 1


def test_video_Show_editAdvanced_default(show):
show.editAdvanced(showOrdering='absolute')
show.reload()
for pref in show.preferences():
if pref.id == 'showOrdering':
assert pref.value == 'absolute'

show.editAdvanced(flattenSeasons=1)
show.reload()
for pref in show.preferences():
if pref.id == 'flattenSeasons':
assert pref.value == 1

show.defaultAdvanced()
show.reload()
for pref in show.preferences():
assert pref.value == pref.default


def test_video_Show_reload(plex):
show = plex.library.section("TV Shows").get("Game of Thrones")
assert utils.is_metadata(show._initpath, prefix="/library/sections/")
Expand Down Expand Up @@ -737,6 +722,10 @@ def test_video_Show_section(show):
assert section.title == "TV Shows"


def test_video_Show_mixins_edit_advanced_settings(show):
test_mixins.edit_advanced_settings(show)


def test_video_Show_mixins_images(show):
test_mixins.edit_art(show)
test_mixins.edit_banner(show)
Expand Down

0 comments on commit 5584ef1

Please sign in to comment.