Skip to content

Commit 5584ef1

Browse files
Added AdvancedSettingsMixin (#714)
* 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]>
1 parent 2e7ae1f commit 5584ef1

File tree

6 files changed

+105
-62
lines changed

6 files changed

+105
-62
lines changed

plexapi/audio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from plexapi import library, media, utils
55
from plexapi.base import Playable, PlexPartialObject
66
from plexapi.exceptions import BadRequest
7-
from plexapi.mixins import ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin
7+
from plexapi.mixins import AdvancedSettingsMixin, ArtUrlMixin, ArtMixin, PosterUrlMixin, PosterMixin
88
from plexapi.mixins import SplitMergeMixin, UnmatchMatchMixin
99
from plexapi.mixins import CollectionMixin, CountryMixin, GenreMixin, LabelMixin, MoodMixin, SimilarArtistMixin, StyleMixin
1010

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

115115

116116
@utils.registerPlexObject
117-
class Artist(Audio, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
117+
class Artist(Audio, AdvancedSettingsMixin, ArtMixin, PosterMixin, SplitMergeMixin, UnmatchMatchMixin,
118118
CollectionMixin, CountryMixin, GenreMixin, MoodMixin, SimilarArtistMixin, StyleMixin):
119119
""" Represents a single Artist.
120120

plexapi/mixins.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,64 @@
11
# -*- coding: utf-8 -*-
22
from urllib.parse import quote_plus, urlencode
33

4-
from plexapi import media, utils
4+
from plexapi import media, settings, utils
55
from plexapi.exceptions import NotFound
66

77

8+
class AdvancedSettingsMixin(object):
9+
""" Mixin for Plex objects that can have advanced settings. """
10+
11+
def preferences(self):
12+
""" Returns a list of :class:`~plexapi.settings.Preferences` objects. """
13+
items = []
14+
data = self._server.query(self._details_key)
15+
for item in data.iter('Preferences'):
16+
for elem in item:
17+
setting = settings.Preferences(data=elem, server=self._server)
18+
setting._initpath = self.key
19+
items.append(setting)
20+
21+
return items
22+
23+
def preference(self, pref):
24+
""" Returns a :class:`~plexapi.settings.Preferences` object for the specified pref.
25+
26+
Parameters:
27+
pref (str): The id of the preference to return.
28+
"""
29+
prefs = self.preferences()
30+
try:
31+
return next(p for p in prefs if p.id == pref)
32+
except StopIteration:
33+
availablePrefs = [p.id for p in prefs]
34+
raise NotFound('Unknown preference "%s" for %s. '
35+
'Available preferences: %s'
36+
% (pref, self.TYPE, availablePrefs)) from None
37+
38+
def editAdvanced(self, **kwargs):
39+
""" Edit a Plex object's advanced settings. """
40+
data = {}
41+
key = '%s/prefs?' % self.key
42+
preferences = {pref.id: list(pref.enumValues.keys()) for pref in self.preferences()}
43+
for settingID, value in kwargs.items():
44+
enumValues = preferences.get(settingID)
45+
if value in enumValues:
46+
data[settingID] = value
47+
else:
48+
raise NotFound('%s not found in %s' % (value, enumValues))
49+
url = key + urlencode(data)
50+
self._server.query(url, method=self._server._session.put)
51+
52+
def defaultAdvanced(self):
53+
""" Edit all of a Plex object's advanced settings to default. """
54+
data = {}
55+
key = '%s/prefs?' % self.key
56+
for preference in self.preferences():
57+
data[preference.id] = preference.default
58+
url = key + urlencode(data)
59+
self._server.query(url, method=self._server._session.put)
60+
61+
862
class ArtUrlMixin(object):
963
""" Mixin for Plex objects that can have a background artwork url. """
1064

plexapi/video.py

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import os
33
from urllib.parse import quote_plus, urlencode
44

5-
from plexapi import library, media, settings, utils
5+
from plexapi import library, media, utils
66
from plexapi.base import Playable, PlexPartialObject
7-
from plexapi.exceptions import BadRequest, NotFound
8-
from plexapi.mixins import ArtUrlMixin, ArtMixin, BannerMixin, PosterUrlMixin, PosterMixin
7+
from plexapi.exceptions import BadRequest
8+
from plexapi.mixins import AdvancedSettingsMixin, ArtUrlMixin, ArtMixin, BannerMixin, PosterUrlMixin, PosterMixin
99
from plexapi.mixins import SplitMergeMixin, UnmatchMatchMixin
1010
from plexapi.mixins import CollectionMixin, CountryMixin, DirectorMixin, GenreMixin, LabelMixin, ProducerMixin, WriterMixin
1111

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

249249

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

382382

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

492-
def preferences(self):
493-
""" Returns a list of :class:`~plexapi.settings.Preferences` objects. """
494-
items = []
495-
data = self._server.query(self._details_key)
496-
for item in data.iter('Preferences'):
497-
for elem in item:
498-
setting = settings.Preferences(data=elem, server=self._server)
499-
setting._initpath = self.key
500-
items.append(setting)
501-
502-
return items
503-
504-
def editAdvanced(self, **kwargs):
505-
""" Edit a show's advanced settings. """
506-
data = {}
507-
key = '%s/prefs?' % self.key
508-
preferences = {pref.id: list(pref.enumValues.keys()) for pref in self.preferences()}
509-
for settingID, value in kwargs.items():
510-
enumValues = preferences.get(settingID)
511-
if value in enumValues:
512-
data[settingID] = value
513-
else:
514-
raise NotFound('%s not found in %s' % (value, enumValues))
515-
url = key + urlencode(data)
516-
self._server.query(url, method=self._server._session.put)
517-
518-
def defaultAdvanced(self):
519-
""" Edit all of show's advanced settings to default. """
520-
data = {}
521-
key = '%s/prefs?' % self.key
522-
for preference in self.preferences():
523-
data[preference.id] = preference.default
524-
url = key + urlencode(data)
525-
self._server.query(url, method=self._server._session.put)
526-
527492
def hubs(self):
528493
""" Returns a list of :class:`~plexapi.library.Hub` objects. """
529494
data = self._server.query(self._details_key)

tests/test_audio.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ def test_audio_Artist_albums(artist):
6767
assert len(albums) == 1 and albums[0].title == "Layers"
6868

6969

70+
def test_audio_Artist_mixins_edit_advanced_settings(artist):
71+
test_mixins.edit_advanced_settings(artist)
72+
73+
7074
def test_audio_Artist_mixins_images(artist):
7175
test_mixins.edit_art(artist)
7276
test_mixins.edit_poster(artist)

tests/test_mixins.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# -*- coding: utf-8 -*-
2+
from plexapi.exceptions import NotFound
23
from plexapi.utils import tag_singular
4+
import pytest
35

46
from . import conftest as utils
57

@@ -146,3 +148,32 @@ def attr_bannerUrl(obj):
146148

147149
def attr_posterUrl(obj):
148150
_test_mixins_imageUrl(obj, 'thumb')
151+
152+
153+
def _test_mixins_editAdvanced(obj):
154+
for pref in obj.preferences():
155+
currentPref = obj.preference(pref.id)
156+
currentValue = currentPref.value
157+
newValue = next(v for v in pref.enumValues if v != currentValue)
158+
obj.editAdvanced(**{pref.id: newValue})
159+
obj.reload()
160+
newPref = obj.preference(pref.id)
161+
assert newPref.value == newValue
162+
163+
164+
def _test_mixins_editAdvanced_bad_pref(obj):
165+
with pytest.raises(NotFound):
166+
assert obj.preference('bad-pref')
167+
168+
169+
def _test_mixins_defaultAdvanced(obj):
170+
obj.defaultAdvanced()
171+
obj.reload()
172+
for pref in obj.preferences():
173+
assert pref.value == pref.default
174+
175+
176+
def edit_advanced_settings(obj):
177+
_test_mixins_editAdvanced(obj)
178+
_test_mixins_editAdvanced_bad_pref(obj)
179+
_test_mixins_defaultAdvanced(obj)

tests/test_video.py

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ def test_video_Movie_merge(movie, patched_http_call):
4040
movie.merge(1337)
4141

4242

43+
def test_video_Movie_mixins_edit_advanced_settings(movie):
44+
test_mixins.edit_advanced_settings(movie)
45+
46+
4347
def test_video_Movie_mixins_images(movie):
4448
test_mixins.edit_art(movie)
4549
test_mixins.edit_poster(movie)
@@ -647,25 +651,6 @@ def test_video_Show_settings(show):
647651
assert len(preferences) >= 1
648652

649653

650-
def test_video_Show_editAdvanced_default(show):
651-
show.editAdvanced(showOrdering='absolute')
652-
show.reload()
653-
for pref in show.preferences():
654-
if pref.id == 'showOrdering':
655-
assert pref.value == 'absolute'
656-
657-
show.editAdvanced(flattenSeasons=1)
658-
show.reload()
659-
for pref in show.preferences():
660-
if pref.id == 'flattenSeasons':
661-
assert pref.value == 1
662-
663-
show.defaultAdvanced()
664-
show.reload()
665-
for pref in show.preferences():
666-
assert pref.value == pref.default
667-
668-
669654
def test_video_Show_reload(plex):
670655
show = plex.library.section("TV Shows").get("Game of Thrones")
671656
assert utils.is_metadata(show._initpath, prefix="/library/sections/")
@@ -737,6 +722,10 @@ def test_video_Show_section(show):
737722
assert section.title == "TV Shows"
738723

739724

725+
def test_video_Show_mixins_edit_advanced_settings(show):
726+
test_mixins.edit_advanced_settings(show)
727+
728+
740729
def test_video_Show_mixins_images(show):
741730
test_mixins.edit_art(show)
742731
test_mixins.edit_banner(show)

0 commit comments

Comments
 (0)