mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-28 14:40:31 +00:00
9ede493f4c
* Use generator for string join * Group media type edit mixins * Add UserRatingMixin * Add LibrarySection methods to multi-edit items * Remove deprecated banners * Factor out resource lock/unlock mixins * Update `fetchItems` to accept list of rating keys * Add repr and helper methods to Common object * Update tests
186 lines
7 KiB
Python
186 lines
7 KiB
Python
# -*- 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. """
|
|
self._data = data
|
|
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)
|