mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 05:01:14 -07:00
Bump plexapi from 4.12.1 to 4.13.1 (#1888)
Bumps [plexapi](https://github.com/pkkid/python-plexapi) from 4.12.1 to 4.13.1. - [Release notes](https://github.com/pkkid/python-plexapi/releases) - [Commits](https://github.com/pkkid/python-plexapi/compare/4.12.1...4.13.1) --- updated-dependencies: - dependency-name: plexapi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
3af08f0d07
commit
e79da07973
20 changed files with 1791 additions and 724 deletions
|
@ -171,7 +171,7 @@ class PlexServer(PlexObject):
|
|||
return headers
|
||||
|
||||
def _uriRoot(self):
|
||||
return 'server://%s/com.plexapp.plugins.library' % self.machineIdentifier
|
||||
return f'server://{self.machineIdentifier}/com.plexapp.plugins.library'
|
||||
|
||||
@property
|
||||
def library(self):
|
||||
|
@ -232,7 +232,7 @@ class PlexServer(PlexObject):
|
|||
""" Returns a list of :class:`~plexapi.media.Agent` objects this server has available. """
|
||||
key = '/system/agents'
|
||||
if mediaType:
|
||||
key += '?mediaType=%s' % utils.searchType(mediaType)
|
||||
key += f'?mediaType={utils.searchType(mediaType)}'
|
||||
return self.fetchItems(key)
|
||||
|
||||
def createToken(self, type='delegation', scope='all'):
|
||||
|
@ -240,7 +240,7 @@ class PlexServer(PlexObject):
|
|||
if not self._token:
|
||||
# Handle unclaimed servers
|
||||
return None
|
||||
q = self.query('/security/token?type=%s&scope=%s' % (type, scope))
|
||||
q = self.query(f'/security/token?type={type}&scope={scope}')
|
||||
return q.attrib.get('token')
|
||||
|
||||
def switchUser(self, username, session=None, timeout=None):
|
||||
|
@ -291,7 +291,7 @@ class PlexServer(PlexObject):
|
|||
try:
|
||||
return next(account for account in self.systemAccounts() if account.id == accountID)
|
||||
except StopIteration:
|
||||
raise NotFound('Unknown account with accountID=%s' % accountID) from None
|
||||
raise NotFound(f'Unknown account with accountID={accountID}') from None
|
||||
|
||||
def systemDevices(self):
|
||||
""" Returns a list of :class:`~plexapi.server.SystemDevice` objects this server contains. """
|
||||
|
@ -309,7 +309,7 @@ class PlexServer(PlexObject):
|
|||
try:
|
||||
return next(device for device in self.systemDevices() if device.id == deviceID)
|
||||
except StopIteration:
|
||||
raise NotFound('Unknown device with deviceID=%s' % deviceID) from None
|
||||
raise NotFound(f'Unknown device with deviceID={deviceID}') from None
|
||||
|
||||
def myPlexAccount(self):
|
||||
""" Returns a :class:`~plexapi.myplex.MyPlexAccount` object using the same
|
||||
|
@ -351,7 +351,7 @@ class PlexServer(PlexObject):
|
|||
key = path.key
|
||||
elif path is not None:
|
||||
base64path = utils.base64str(path)
|
||||
key = '/services/browse/%s' % base64path
|
||||
key = f'/services/browse/{base64path}'
|
||||
else:
|
||||
key = '/services/browse'
|
||||
if includeFiles:
|
||||
|
@ -406,7 +406,7 @@ class PlexServer(PlexObject):
|
|||
log.warning('%s did not advertise a port, checking plex.tv.', elem.attrib.get('name'))
|
||||
ports = self._myPlexClientPorts() if ports is None else ports
|
||||
port = ports.get(elem.attrib.get('machineIdentifier'))
|
||||
baseurl = 'http://%s:%s' % (elem.attrib['host'], port)
|
||||
baseurl = f"http://{elem.attrib['host']}:{port}"
|
||||
items.append(PlexClient(baseurl=baseurl, server=self,
|
||||
token=self._token, data=elem, connect=False))
|
||||
|
||||
|
@ -425,7 +425,7 @@ class PlexServer(PlexObject):
|
|||
if client and client.title == name:
|
||||
return client
|
||||
|
||||
raise NotFound('Unknown client name: %s' % name)
|
||||
raise NotFound(f'Unknown client name: {name}')
|
||||
|
||||
def createCollection(self, title, section, items=None, smart=False, limit=None,
|
||||
libtype=None, sort=None, filters=None, **kwargs):
|
||||
|
@ -547,6 +547,7 @@ class PlexServer(PlexObject):
|
|||
f'Invalid butler task: {task}. Available tasks are: {validTasks}'
|
||||
)
|
||||
self.query(f'/butler/{task}', method=self._session.post)
|
||||
return self
|
||||
|
||||
@deprecated('use "checkForUpdate" instead')
|
||||
def check_for_update(self, force=True, download=False):
|
||||
|
@ -559,7 +560,7 @@ class PlexServer(PlexObject):
|
|||
force (bool): Force server to check for new releases
|
||||
download (bool): Download if a update is available.
|
||||
"""
|
||||
part = '/updater/check?download=%s' % (1 if download else 0)
|
||||
part = f'/updater/check?download={1 if download else 0}'
|
||||
if force:
|
||||
self.query(part, method=self._session.put)
|
||||
releases = self.fetchItems('/updater/status')
|
||||
|
@ -608,7 +609,7 @@ class PlexServer(PlexObject):
|
|||
args['X-Plex-Container-Start'] = 0
|
||||
args['X-Plex-Container-Size'] = min(X_PLEX_CONTAINER_SIZE, maxresults)
|
||||
while subresults and maxresults > len(results):
|
||||
key = '/status/sessions/history/all%s' % utils.joinArgs(args)
|
||||
key = f'/status/sessions/history/all{utils.joinArgs(args)}'
|
||||
subresults = self.fetchItems(key)
|
||||
results += subresults[:maxresults - len(results)]
|
||||
args['X-Plex-Container-Start'] += args['X-Plex-Container-Size']
|
||||
|
@ -635,7 +636,7 @@ class PlexServer(PlexObject):
|
|||
# TODO: Automatically retrieve and validate sort field similar to LibrarySection.search()
|
||||
args['sort'] = sort
|
||||
|
||||
key = '/playlists%s' % utils.joinArgs(args)
|
||||
key = f'/playlists{utils.joinArgs(args)}'
|
||||
return self.fetchItems(key, **kwargs)
|
||||
|
||||
def playlist(self, title):
|
||||
|
@ -650,7 +651,7 @@ class PlexServer(PlexObject):
|
|||
try:
|
||||
return self.playlists(title=title, title__iexact=title)[0]
|
||||
except IndexError:
|
||||
raise NotFound('Unable to find playlist with title "%s".' % title) from None
|
||||
raise NotFound(f'Unable to find playlist with title "{title}".') from None
|
||||
|
||||
def optimizedItems(self, removeAll=None):
|
||||
""" Returns list of all :class:`~plexapi.media.Optimized` objects connected to server. """
|
||||
|
@ -659,7 +660,7 @@ class PlexServer(PlexObject):
|
|||
self.query(key, method=self._server._session.delete)
|
||||
else:
|
||||
backgroundProcessing = self.fetchItem('/playlists?type=42')
|
||||
return self.fetchItems('%s/items' % backgroundProcessing.key, cls=Optimized)
|
||||
return self.fetchItems(f'{backgroundProcessing.key}/items', cls=Optimized)
|
||||
|
||||
@deprecated('use "plexapi.media.Optimized.items()" instead')
|
||||
def optimizedItem(self, optimizedID):
|
||||
|
@ -668,7 +669,7 @@ class PlexServer(PlexObject):
|
|||
"""
|
||||
|
||||
backgroundProcessing = self.fetchItem('/playlists?type=42')
|
||||
return self.fetchItem('%s/items/%s/items' % (backgroundProcessing.key, optimizedID))
|
||||
return self.fetchItem(f'{backgroundProcessing.key}/items/{optimizedID}/items')
|
||||
|
||||
def conversions(self, pause=None):
|
||||
""" Returns list of all :class:`~plexapi.media.Conversion` objects connected to server. """
|
||||
|
@ -697,7 +698,7 @@ class PlexServer(PlexObject):
|
|||
if response.status_code not in (200, 201, 204):
|
||||
codename = codes.get(response.status_code)[0]
|
||||
errtext = response.text.replace('\n', ' ')
|
||||
message = '(%s) %s; %s %s' % (response.status_code, codename, response.url, errtext)
|
||||
message = f'({response.status_code}) {codename}; {response.url} {errtext}'
|
||||
if response.status_code == 401:
|
||||
raise Unauthorized(message)
|
||||
elif response.status_code == 404:
|
||||
|
@ -736,7 +737,7 @@ class PlexServer(PlexObject):
|
|||
params['limit'] = limit
|
||||
if sectionId:
|
||||
params['sectionId'] = sectionId
|
||||
key = '/hubs/search?%s' % urlencode(params)
|
||||
key = f'/hubs/search?{urlencode(params)}'
|
||||
for hub in self.fetchItems(key, Hub):
|
||||
if mediatype:
|
||||
if hub.type == mediatype:
|
||||
|
@ -753,21 +754,27 @@ class PlexServer(PlexObject):
|
|||
""" Returns a list of all active :class:`~plexapi.media.TranscodeSession` objects. """
|
||||
return self.fetchItems('/transcode/sessions')
|
||||
|
||||
def startAlertListener(self, callback=None):
|
||||
def startAlertListener(self, callback=None, callbackError=None):
|
||||
""" Creates a websocket connection to the Plex Server to optionally receive
|
||||
notifications. These often include messages from Plex about media scans
|
||||
as well as updates to currently running Transcode Sessions.
|
||||
|
||||
NOTE: You need websocket-client installed in order to use this feature.
|
||||
>> pip install websocket-client
|
||||
Returns a new :class:`~plexapi.alert.AlertListener` object.
|
||||
|
||||
Note: ``websocket-client`` must be installed in order to use this feature.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>> pip install websocket-client
|
||||
|
||||
Parameters:
|
||||
callback (func): Callback function to call on received messages.
|
||||
callbackError (func): Callback function to call on errors.
|
||||
|
||||
Raises:
|
||||
:exc:`~plexapi.exception.Unsupported`: Websocket-client not installed.
|
||||
"""
|
||||
notifier = AlertListener(self, callback)
|
||||
notifier = AlertListener(self, callback, callbackError)
|
||||
notifier.start()
|
||||
return notifier
|
||||
|
||||
|
@ -809,7 +816,7 @@ class PlexServer(PlexObject):
|
|||
if imageFormat is not None:
|
||||
params['format'] = imageFormat.lower()
|
||||
|
||||
key = '/photo/:/transcode%s' % utils.joinArgs(params)
|
||||
key = f'/photo/:/transcode{utils.joinArgs(params)}'
|
||||
return self.url(key, includeToken=True)
|
||||
|
||||
def url(self, key, includeToken=None):
|
||||
|
@ -818,8 +825,8 @@ class PlexServer(PlexObject):
|
|||
"""
|
||||
if self._token and (includeToken or self._showSecrets):
|
||||
delim = '&' if '?' in key else '?'
|
||||
return '%s%s%sX-Plex-Token=%s' % (self._baseurl, key, delim, self._token)
|
||||
return '%s%s' % (self._baseurl, key)
|
||||
return f'{self._baseurl}{key}{delim}X-Plex-Token={self._token}'
|
||||
return f'{self._baseurl}{key}'
|
||||
|
||||
def refreshSynclist(self):
|
||||
""" Force PMS to download new SyncList from Plex.tv. """
|
||||
|
@ -853,7 +860,7 @@ class PlexServer(PlexObject):
|
|||
log.debug('Plex is currently not allowed to delete media. Toggle set to not allow, exiting.')
|
||||
raise BadRequest('Plex is currently not allowed to delete media. Toggle set to not allow, exiting.')
|
||||
value = 1 if toggle is True else 0
|
||||
return self.query('/:/prefs?allowMediaDeletion=%s' % value, self._session.put)
|
||||
return self.query(f'/:/prefs?allowMediaDeletion={value}', self._session.put)
|
||||
|
||||
def bandwidth(self, timespan=None, **kwargs):
|
||||
""" Returns a list of :class:`~plexapi.server.StatisticsBandwidth` objects
|
||||
|
@ -904,8 +911,7 @@ class PlexServer(PlexObject):
|
|||
gigabytes = round(bandwidth.bytes / 1024**3, 3)
|
||||
local = 'local' if bandwidth.lan else 'remote'
|
||||
date = bandwidth.at.strftime('%Y-%m-%d')
|
||||
print('%s used %s GB of %s bandwidth on %s from %s'
|
||||
% (account.name, gigabytes, local, date, device.name))
|
||||
print(f'{account.name} used {gigabytes} GB of {local} bandwidth on {date} from {device.name}')
|
||||
|
||||
"""
|
||||
params = {}
|
||||
|
@ -923,19 +929,19 @@ class PlexServer(PlexObject):
|
|||
try:
|
||||
params['timespan'] = timespans[timespan]
|
||||
except KeyError:
|
||||
raise BadRequest('Invalid timespan specified: %s. '
|
||||
'Available timespans: %s' % (timespan, ', '.join(timespans.keys())))
|
||||
raise BadRequest(f"Invalid timespan specified: {timespan}. "
|
||||
f"Available timespans: {', '.join(timespans.keys())}")
|
||||
|
||||
filters = {'accountID', 'at', 'at<', 'at>', 'bytes', 'bytes<', 'bytes>', 'deviceID', 'lan'}
|
||||
|
||||
for key, value in kwargs.items():
|
||||
if key not in filters:
|
||||
raise BadRequest('Unknown filter: %s=%s' % (key, value))
|
||||
raise BadRequest(f'Unknown filter: {key}={value}')
|
||||
if key.startswith('at'):
|
||||
try:
|
||||
value = utils.cast(int, value.timestamp())
|
||||
except AttributeError:
|
||||
raise BadRequest('Time frame filter must be a datetime object: %s=%s' % (key, value))
|
||||
raise BadRequest(f'Time frame filter must be a datetime object: {key}={value}')
|
||||
elif key.startswith('bytes') or key == 'lan':
|
||||
value = utils.cast(int, value)
|
||||
elif key == 'accountID':
|
||||
|
@ -943,7 +949,7 @@ class PlexServer(PlexObject):
|
|||
value = 1 # The admin account is accountID=1
|
||||
params[key] = value
|
||||
|
||||
key = '/statistics/bandwidth?%s' % urlencode(params)
|
||||
key = f'/statistics/bandwidth?{urlencode(params)}'
|
||||
return self.fetchItems(key, StatisticsBandwidth)
|
||||
|
||||
def resources(self):
|
||||
|
@ -966,13 +972,9 @@ class PlexServer(PlexObject):
|
|||
base = 'https://app.plex.tv/desktop/'
|
||||
|
||||
if endpoint:
|
||||
return '%s#!/server/%s/%s%s' % (
|
||||
base, self.machineIdentifier, endpoint, utils.joinArgs(kwargs)
|
||||
)
|
||||
return f'{base}#!/server/{self.machineIdentifier}/{endpoint}{utils.joinArgs(kwargs)}'
|
||||
else:
|
||||
return '%s#!/media/%s/com.plexapp.plugins.library%s' % (
|
||||
base, self.machineIdentifier, utils.joinArgs(kwargs)
|
||||
)
|
||||
return f'{base}#!/media/{self.machineIdentifier}/com.plexapp.plugins.library{utils.joinArgs(kwargs)}'
|
||||
|
||||
def getWebURL(self, base=None, playlistTab=None):
|
||||
""" Returns the Plex Web URL for the server.
|
||||
|
@ -983,7 +985,7 @@ class PlexServer(PlexObject):
|
|||
playlistTab (str): The playlist tab (audio, video, photo). Only used for the playlist URL.
|
||||
"""
|
||||
if playlistTab is not None:
|
||||
params = {'source': 'playlists', 'pivot': 'playlists.%s' % playlistTab}
|
||||
params = {'source': 'playlists', 'pivot': f'playlists.{playlistTab}'}
|
||||
else:
|
||||
params = {'key': '/hubs', 'pageType': 'hub'}
|
||||
return self._buildWebURL(base=base, **params)
|
||||
|
@ -1115,7 +1117,7 @@ class SystemDevice(PlexObject):
|
|||
self.clientIdentifier = data.attrib.get('clientIdentifier')
|
||||
self.createdAt = utils.toDatetime(data.attrib.get('createdAt'))
|
||||
self.id = utils.cast(int, data.attrib.get('id'))
|
||||
self.key = '/devices/%s' % self.id
|
||||
self.key = f'/devices/{self.id}'
|
||||
self.name = data.attrib.get('name')
|
||||
self.platform = data.attrib.get('platform')
|
||||
|
||||
|
@ -1146,12 +1148,14 @@ class StatisticsBandwidth(PlexObject):
|
|||
self.timespan = utils.cast(int, data.attrib.get('timespan'))
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s>' % ':'.join([p for p in [
|
||||
self.__class__.__name__,
|
||||
self._clean(self.accountID),
|
||||
self._clean(self.deviceID),
|
||||
self._clean(int(self.at.timestamp()))
|
||||
] if p])
|
||||
return '<{}>'.format(
|
||||
':'.join([p for p in [
|
||||
self.__class__.__name__,
|
||||
self._clean(self.accountID),
|
||||
self._clean(self.deviceID),
|
||||
self._clean(int(self.at.timestamp()))
|
||||
] if p])
|
||||
)
|
||||
|
||||
def account(self):
|
||||
""" Returns the :class:`~plexapi.server.SystemAccount` associated with the bandwidth data. """
|
||||
|
@ -1186,10 +1190,7 @@ class StatisticsResources(PlexObject):
|
|||
self.timespan = utils.cast(int, data.attrib.get('timespan'))
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s>' % ':'.join([p for p in [
|
||||
self.__class__.__name__,
|
||||
self._clean(int(self.at.timestamp()))
|
||||
] if p])
|
||||
return f"<{':'.join([p for p in [self.__class__.__name__, self._clean(int(self.at.timestamp()))] if p])}>"
|
||||
|
||||
|
||||
@utils.registerPlexObject
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue