Skip to content

Commit 020a32f

Browse files
authored
Update PlexAPI to f-strings (#1000)
* Update plexapi to f-strings * Update tests to f-strings
1 parent fbc124a commit 020a32f

30 files changed

+369
-422
lines changed

plexapi/audio.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def sync(self, bitrate, client=None, clientId=None, limit=None, title=None):
120120

121121
section = self._server.library.sectionByID(self.librarySectionID)
122122

123-
sync_item.location = 'library://%s/item/%s' % (section.uuid, quote_plus(self.key))
123+
sync_item.location = f'library://{section.uuid}/item/{quote_plus(self.key)}'
124124
sync_item.policy = Policy.create(limit)
125125
sync_item.mediaSettings = MediaSettings.createMusic(bitrate)
126126

@@ -235,7 +235,7 @@ def download(self, savepath=None, keep_original_name=False, subfolders=False, **
235235

236236
def station(self):
237237
""" Returns a :class:`~plexapi.playlist.Playlist` artist radio station or `None`. """
238-
key = '%s?includeStations=1' % self.key
238+
key = f'{self.key}?includeStations=1'
239239
return next(iter(self.fetchItems(key, cls=Playlist, rtag="Stations")), None)
240240

241241

@@ -356,7 +356,7 @@ def download(self, savepath=None, keep_original_name=False, **kwargs):
356356

357357
def _defaultSyncTitle(self):
358358
""" Returns str, default title for a new syncItem. """
359-
return '%s - %s' % (self.parentTitle, self.title)
359+
return f'{self.parentTitle} - {self.title}'
360360

361361

362362
@utils.registerPlexObject
@@ -435,8 +435,7 @@ def _loadData(self, data):
435435

436436
def _prettyfilename(self):
437437
""" Returns a filename for use in download. """
438-
return '%s - %s - %s - %s' % (
439-
self.grandparentTitle, self.parentTitle, str(self.trackNumber).zfill(2), self.title)
438+
return f'{self.grandparentTitle} - {self.parentTitle} - {str(self.trackNumber).zfill(2)} - {self.title}'
440439

441440
def album(self):
442441
""" Return the track's :class:`~plexapi.audio.Album`. """
@@ -463,7 +462,7 @@ def trackNumber(self):
463462

464463
def _defaultSyncTitle(self):
465464
""" Returns str, default title for a new syncItem. """
466-
return '%s - %s - %s' % (self.grandparentTitle, self.parentTitle, self.title)
465+
return f'{self.grandparentTitle} - {self.parentTitle} - {self.title}'
467466

468467
def _getWebURL(self, base=None):
469468
""" Get the Plex Web URL with the correct parameters. """

plexapi/base.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, server, data, initpath=None, parent=None):
5959
def __repr__(self):
6060
uid = self._clean(self.firstAttr('_baseurl', 'ratingKey', 'id', 'key', 'playQueueID', 'uri'))
6161
name = self._clean(self.firstAttr('title', 'name', 'username', 'product', 'tag', 'value'))
62-
return '<%s>' % ':'.join([p for p in [self.__class__.__name__, uid, name] if p])
62+
return f"<{':'.join([p for p in [self.__class__.__name__, uid, name] if p])}>"
6363

6464
def __setattr__(self, attr, value):
6565
overwriteNone = self.__dict__.get('_overwriteNone')
@@ -84,14 +84,14 @@ def _buildItem(self, elem, cls=None, initpath=None):
8484
return cls(self._server, elem, initpath, parent=self)
8585
# cls is not specified, try looking it up in PLEXOBJECTS
8686
etype = elem.attrib.get('streamType', elem.attrib.get('tagType', elem.attrib.get('type')))
87-
ehash = '%s.%s' % (elem.tag, etype) if etype else elem.tag
87+
ehash = f'{elem.tag}.{etype}' if etype else elem.tag
8888
if initpath == '/status/sessions':
89-
ehash = '%s.%s' % (ehash, 'session')
89+
ehash = f"{ehash}.{'session'}"
9090
ecls = utils.PLEXOBJECTS.get(ehash, utils.PLEXOBJECTS.get(elem.tag))
9191
# log.debug('Building %s as %s', elem.tag, ecls.__name__)
9292
if ecls is not None:
9393
return ecls(self._server, elem, initpath)
94-
raise UnknownType("Unknown library type <%s type='%s'../>" % (elem.tag, etype))
94+
raise UnknownType(f"Unknown library type <{elem.tag} type='{etype}'../>")
9595

9696
def _buildItemOrNone(self, elem, cls=None, initpath=None):
9797
""" Calls :func:`~plexapi.base.PlexObject._buildItem` but returns
@@ -167,7 +167,7 @@ def fetchItem(self, ekey, cls=None, **kwargs):
167167
if ekey is None:
168168
raise BadRequest('ekey was not provided')
169169
if isinstance(ekey, int):
170-
ekey = '/library/metadata/%s' % ekey
170+
ekey = f'/library/metadata/{ekey}'
171171

172172
data = self._server.query(ekey)
173173
item = self.findItem(data, cls, ekey, **kwargs)
@@ -179,7 +179,7 @@ def fetchItem(self, ekey, cls=None, **kwargs):
179179
return item
180180

181181
clsname = cls.__name__ if cls else 'None'
182-
raise NotFound('Unable to find elem: cls=%s, attrs=%s' % (clsname, kwargs))
182+
raise NotFound(f'Unable to find elem: cls={clsname}, attrs={kwargs}')
183183

184184
def fetchItems(self, ekey, cls=None, container_start=None, container_size=None, **kwargs):
185185
""" Load the specified key to find and build all items with the specified tag
@@ -328,7 +328,7 @@ def listAttrs(self, data, attr, rtag=None, **kwargs):
328328
if rtag:
329329
data = next(utils.iterXMLBFS(data, rtag), [])
330330
for elem in data:
331-
kwargs['%s__exists' % attr] = True
331+
kwargs[f'{attr}__exists'] = True
332332
if self._checkAttrs(elem, **kwargs):
333333
results.append(elem.attrib.get(attr))
334334
return results
@@ -399,7 +399,7 @@ def _checkAttrs(self, elem, **kwargs):
399399

400400
def _getAttrOperator(self, attr):
401401
for op, operator in OPERATORS.items():
402-
if attr.endswith('__%s' % op):
402+
if attr.endswith(f'__{op}'):
403403
attr = attr.rsplit('__', 1)[0]
404404
return attr, op, operator
405405
# default to exact match
@@ -496,7 +496,7 @@ def __getattribute__(self, attr):
496496
# Log the reload.
497497
clsname = self.__class__.__name__
498498
title = self.__dict__.get('title', self.__dict__.get('name'))
499-
objname = "%s '%s'" % (clsname, title) if title else clsname
499+
objname = f"{clsname} '{title}'" if title else clsname
500500
log.debug("Reloading %s for attr '%s'", objname, attr)
501501
# Reload and return the value
502502
self._reload(_overwriteNone=False)
@@ -521,7 +521,7 @@ def analyze(self):
521521
* Generate intro video markers: Detects show intros, exposing the
522522
'Skip Intro' button in clients.
523523
"""
524-
key = '/%s/analyze' % self.key.lstrip('/')
524+
key = f"/{self.key.lstrip('/')}/analyze"
525525
self._server.query(key, method=self._server._session.put)
526526

527527
def isFullObject(self):
@@ -547,8 +547,7 @@ def _edit(self, **kwargs):
547547
if 'type' not in kwargs:
548548
kwargs['type'] = utils.searchType(self._searchType)
549549

550-
part = '/library/sections/%s/all%s' % (self.librarySectionID,
551-
utils.joinArgs(kwargs))
550+
part = f'/library/sections/{self.librarySectionID}/all{utils.joinArgs(kwargs)}'
552551
self._server.query(part, method=self._server._session.put)
553552
return self
554553

@@ -627,7 +626,7 @@ def refresh(self):
627626
the refresh process is interrupted (the Server is turned off, internet
628627
connection dies, etc).
629628
"""
630-
key = '%s/refresh' % self.key
629+
key = f'{self.key}/refresh'
631630
self._server.query(key, method=self._server._session.put)
632631

633632
def section(self):
@@ -700,7 +699,7 @@ def getStreamURL(self, **params):
700699
:exc:`~plexapi.exceptions.Unsupported`: When the item doesn't support fetching a stream URL.
701700
"""
702701
if self.TYPE not in ('movie', 'episode', 'track', 'clip'):
703-
raise Unsupported('Fetching stream URL for %s is unsupported.' % self.TYPE)
702+
raise Unsupported(f'Fetching stream URL for {self.TYPE} is unsupported.')
704703
mvb = params.get('maxVideoBitrate')
705704
vr = params.get('videoResolution', '')
706705
params = {
@@ -718,8 +717,10 @@ def getStreamURL(self, **params):
718717
streamtype = 'audio' if self.TYPE in ('track', 'album') else 'video'
719718
# sort the keys since the randomness fucks with my tests..
720719
sorted_params = sorted(params.items(), key=lambda val: val[0])
721-
return self._server.url('/%s/:/transcode/universal/start.m3u8?%s' %
722-
(streamtype, urlencode(sorted_params)), includeToken=True)
720+
return self._server.url(
721+
f'/{streamtype}/:/transcode/universal/start.m3u8?{urlencode(sorted_params)}',
722+
includeToken=True
723+
)
723724

724725
def iterParts(self):
725726
""" Iterates over the parts of this media item. """
@@ -759,15 +760,15 @@ def download(self, savepath=None, keep_original_name=False, **kwargs):
759760

760761
for part in parts:
761762
if not keep_original_name:
762-
filename = utils.cleanFilename('%s.%s' % (self._prettyfilename(), part.container))
763+
filename = utils.cleanFilename(f'{self._prettyfilename()}.{part.container}')
763764
else:
764765
filename = part.file
765766

766767
if kwargs:
767768
# So this seems to be a a lot slower but allows transcode.
768769
download_url = self.getStreamURL(**kwargs)
769770
else:
770-
download_url = self._server.url('%s?download=1' % part.key)
771+
download_url = self._server.url(f'{part.key}?download=1')
771772

772773
filepath = utils.download(
773774
download_url,
@@ -794,8 +795,7 @@ def updateProgress(self, time, state='stopped'):
794795
time (int): milliseconds watched
795796
state (string): state of the video, default 'stopped'
796797
"""
797-
key = '/:/progress?key=%s&identifier=com.plexapp.plugins.library&time=%d&state=%s' % (self.ratingKey,
798-
time, state)
798+
key = f'/:/progress?key={self.ratingKey}&identifier=com.plexapp.plugins.library&time={time}&state={state}'
799799
self._server.query(key)
800800
self._reload(_overwriteNone=False)
801801

plexapi/client.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def connect(self, timeout=None):
9494
self._initpath = self.key
9595
data = self.query(self.key, timeout=timeout)
9696
if not data:
97-
raise NotFound("Client not found at %s" % self._baseurl)
97+
raise NotFound(f"Client not found at {self._baseurl}")
9898
if self._clientIdentifier:
9999
client = next(
100100
(
@@ -106,8 +106,7 @@ def connect(self, timeout=None):
106106
)
107107
if client is None:
108108
raise NotFound(
109-
"Client with identifier %s not found at %s"
110-
% (self._clientIdentifier, self._baseurl)
109+
f"Client with identifier {self._clientIdentifier} not found at {self._baseurl}"
111110
)
112111
else:
113112
client = data[0]
@@ -186,7 +185,7 @@ def query(self, path, method=None, headers=None, timeout=None, **kwargs):
186185
if response.status_code not in (200, 201, 204):
187186
codename = codes.get(response.status_code)[0]
188187
errtext = response.text.replace('\n', ' ')
189-
message = '(%s) %s; %s %s' % (response.status_code, codename, response.url, errtext)
188+
message = f'({response.status_code}) {codename}; {response.url} {errtext}'
190189
if response.status_code == 401:
191190
raise Unauthorized(message)
192191
elif response.status_code == 404:
@@ -213,8 +212,7 @@ def sendCommand(self, command, proxy=None, **params):
213212
controller = command.split('/')[0]
214213
headers = {'X-Plex-Target-Client-Identifier': self.machineIdentifier}
215214
if controller not in self.protocolCapabilities:
216-
log.debug("Client %s doesn't support %s controller."
217-
"What your trying might not work" % (self.title, controller))
215+
log.debug(f"Client {self.title} doesn't support {controller} controller. What your trying might not work")
218216

219217
proxy = self._proxyThroughServer if proxy is None else proxy
220218
query = self._server.query if proxy else self.query
@@ -228,7 +226,7 @@ def sendCommand(self, command, proxy=None, **params):
228226
self.sendCommand(ClientTimeline.key, wait=0)
229227

230228
params['commandID'] = self._nextCommandId()
231-
key = '/player/%s%s' % (command, utils.joinArgs(params))
229+
key = f'/player/{command}{utils.joinArgs(params)}'
232230

233231
try:
234232
return query(key, headers=headers)
@@ -253,8 +251,8 @@ def url(self, key, includeToken=False):
253251
raise BadRequest('PlexClient object missing baseurl.')
254252
if self._token and (includeToken or self._showSecrets):
255253
delim = '&' if '?' in key else '?'
256-
return '%s%s%sX-Plex-Token=%s' % (self._baseurl, key, delim, self._token)
257-
return '%s%s' % (self._baseurl, key)
254+
return f'{self._baseurl}{key}{delim}X-Plex-Token={self._token}'
255+
return f'{self._baseurl}{key}'
258256

259257
# ---------------------
260258
# Navigation Commands
@@ -517,7 +515,7 @@ def playMedia(self, media, offset=0, **params):
517515
'offset': offset,
518516
'key': media.key or playqueue.selectedItem.key,
519517
'type': mediatype,
520-
'containerKey': '/playQueues/%s?window=100&own=1' % playqueue.playQueueID,
518+
'containerKey': f'/playQueues/{playqueue.playQueueID}?window=100&own=1',
521519
**params,
522520
}
523521
token = media._server.createToken()

0 commit comments

Comments
 (0)