-
Notifications
You must be signed in to change notification settings - Fork 201
/
Copy pathsettings.py
185 lines (159 loc) · 6.96 KB
/
settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# -*- coding: utf-8 -*-
from collections import defaultdict
from urllib.parse import quote
from plexapi import log, utils
from plexapi.base import PlexObject
from plexapi.exceptions import BadRequest, NotFound
class Settings(PlexObject):
""" Container class for all settings. Allows getting and setting PlexServer settings.
Attributes:
key (str): '/:/prefs'
"""
key = '/:/prefs'
def __init__(self, server, data, initpath=None):
self._settings = {}
super(Settings, self).__init__(server, data, initpath)
def __getattr__(self, attr):
if attr.startswith('_'):
try:
return self.__dict__[attr]
except KeyError:
raise AttributeError
return self.get(attr).value
def __setattr__(self, attr, value):
if not attr.startswith('_'):
return self.get(attr).set(value)
self.__dict__[attr] = value
def _loadData(self, data):
""" Load attribute values from Plex XML response. """
for elem in data:
id = utils.lowerFirst(elem.attrib['id'])
if id in self._settings:
self._settings[id]._loadData(elem)
continue
self._settings[id] = Setting(self._server, elem, self._initpath)
def all(self):
""" Returns a list of all :class:`~plexapi.settings.Setting` objects available. """
return [v for id, v in sorted(self._settings.items())]
def get(self, id):
""" Return the :class:`~plexapi.settings.Setting` object with the specified id. """
id = utils.lowerFirst(id)
if id in self._settings:
return self._settings[id]
raise NotFound(f'Invalid setting id: {id}')
def groups(self):
""" Returns a dict of lists for all :class:`~plexapi.settings.Setting`
objects grouped by setting group.
"""
groups = defaultdict(list)
for setting in self.all():
groups[setting.group].append(setting)
return dict(groups)
def group(self, group):
""" Return a list of all :class:`~plexapi.settings.Setting` objects in the specified group.
Parameters:
group (str): Group to return all settings.
"""
return self.groups().get(group, [])
def save(self):
""" Save any outstanding setting changes to the :class:`~plexapi.server.PlexServer`. This
performs a full reload() of Settings after complete.
"""
params = {}
for setting in self.all():
if setting._setValue:
log.info('Saving PlexServer setting %s = %s', setting.id, setting._setValue)
params[setting.id] = quote(setting._setValue)
if not params:
raise BadRequest('No setting have been modified.')
querystr = '&'.join(f'{k}={v}' for k, v in params.items())
url = f'{self.key}?{querystr}'
self._server.query(url, self._server._session.put)
self.reload()
class Setting(PlexObject):
""" Represents a single Plex setting.
Attributes:
id (str): Setting id (or name).
label (str): Short description of what this setting is.
summary (str): Long description of what this setting is.
type (str): Setting type (text, int, double, bool).
default (str): Default value for this setting.
value (str,bool,int,float): Current value for this setting.
hidden (bool): True if this is a hidden setting.
advanced (bool): True if this is an advanced setting.
group (str): Group name this setting is categorized as.
enumValues (list,dict): List or dictionary of valid values for this setting.
"""
_bool_cast = lambda x: bool(x == 'true' or x == '1')
_bool_str = lambda x: str(x).lower()
TYPES = {
'bool': {'type': bool, 'cast': _bool_cast, 'tostr': _bool_str},
'double': {'type': float, 'cast': float, 'tostr': str},
'int': {'type': int, 'cast': int, 'tostr': str},
'text': {'type': str, 'cast': str, 'tostr': str},
}
def _loadData(self, data):
""" Load attribute values from Plex XML response. """
self.type = data.attrib.get('type')
self.advanced = utils.cast(bool, data.attrib.get('advanced'))
self.default = self._cast(data.attrib.get('default'))
self.enumValues = self._getEnumValues(data)
self.group = data.attrib.get('group')
self.hidden = utils.cast(bool, data.attrib.get('hidden'))
self.id = data.attrib.get('id')
self.label = data.attrib.get('label')
self.option = data.attrib.get('option')
self.secure = utils.cast(bool, data.attrib.get('secure'))
self.summary = data.attrib.get('summary')
self.value = self._cast(data.attrib.get('value'))
self._setValue = None
def _cast(self, value):
""" Cast the specific value to the type of this setting. """
if self.type != 'enum':
value = utils.cast(self.TYPES.get(self.type)['cast'], value)
return value
def _getEnumValues(self, data):
""" Returns a list or dictionary of values for this setting. """
enumstr = data.attrib.get('enumValues') or data.attrib.get('values')
if not enumstr:
return None
if ':' in enumstr:
d = {}
for kv in enumstr.split('|'):
try:
k, v = kv.split(':')
d[self._cast(k)] = v
except ValueError:
d[self._cast(kv)] = kv
return d
return enumstr.split('|')
def set(self, value):
""" Set a new value for this setting. NOTE: You must call plex.settings.save() for before
any changes to setting values are persisted to the :class:`~plexapi.server.PlexServer`.
"""
# check a few things up front
if not isinstance(value, self.TYPES[self.type]['type']):
badtype = type(value).__name__
raise BadRequest(f'Invalid value for {self.id}: a {self.type} is required, not {badtype}')
if self.enumValues and value not in self.enumValues:
raise BadRequest(f'Invalid value for {self.id}: {value} not in {list(self.enumValues)}')
# store value off to the side until we call settings.save()
tostr = self.TYPES[self.type]['tostr']
self._setValue = tostr(value)
def toUrl(self):
"""Helper for urls"""
return f'{self.id}={self._value or self.value}'
@utils.registerPlexObject
class Preferences(Setting):
""" Represents a single Preferences.
Attributes:
TAG (str): 'Setting'
FILTER (str): 'preferences'
"""
TAG = 'Setting'
FILTER = 'preferences'
def _default(self):
""" Set the default value for this setting."""
key = f'{self._initpath}/prefs?'
url = key + f'{self.id}={self.default}'
self._server.query(url, method=self._server._session.put)