Skip to content

Commit 6cacc4a

Browse files
authored
Add playlist title search and sorting (#782)
* Add title and sort arguments to server playlists method * Raise NotFound when retrieving a playlist or collection * Update tests for collection/playlist NotFound
1 parent 3b1dce7 commit 6cacc4a

File tree

4 files changed

+57
-22
lines changed

4 files changed

+57
-22
lines changed

plexapi/library.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,10 +1405,14 @@ def collection(self, title):
14051405
14061406
Parameters:
14071407
title (str): Title of the item to return.
1408+
1409+
Raises:
1410+
:exc:`~plexapi.exceptions.NotFound`: Unable to find collection.
14081411
"""
1409-
results = self.collections(title__iexact=title)
1410-
if results:
1411-
return results[0]
1412+
try:
1413+
return self.collections(title=title, title__iexact=title)[0]
1414+
except IndexError:
1415+
raise NotFound('Unable to find collection with title "%s".' % title) from None
14121416

14131417
def collections(self, **kwargs):
14141418
""" Returns a list of collections from this library section.
@@ -1430,15 +1434,19 @@ def playlist(self, title):
14301434
14311435
Parameters:
14321436
title (str): Title of the item to return.
1437+
1438+
Raises:
1439+
:exc:`~plexapi.exceptions.NotFound`: Unable to find playlist.
14331440
"""
1434-
results = self.playlists(title__iexact=title)
1435-
if results:
1436-
return results[0]
1441+
try:
1442+
return self.playlists(title=title, title__iexact=title)[0]
1443+
except IndexError:
1444+
raise NotFound('Unable to find playlist with title "%s".' % title) from None
14371445

1438-
def playlists(self, **kwargs):
1446+
def playlists(self, sort=None, **kwargs):
14391447
""" Returns a list of playlists from this library section. """
1440-
key = '/playlists?type=15&playlistType=%s&sectionID=%s' % (self.CONTENT_TYPE, self.key)
1441-
return self.fetchItems(key, **kwargs)
1448+
return self._server.playlists(
1449+
playlistType=self.CONTENT_TYPE, sectionId=self.key, sort=sort, **kwargs)
14421450

14431451
@deprecated('use "listFields" instead')
14441452
def filterFields(self, mediaType=None):

plexapi/server.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -575,17 +575,29 @@ def history(self, maxresults=9999999, mindate=None, ratingKey=None, accountID=No
575575
args['X-Plex-Container-Start'] += args['X-Plex-Container-Size']
576576
return results
577577

578-
def playlists(self, playlistType=None):
578+
def playlists(self, playlistType=None, sectionId=None, title=None, sort=None, **kwargs):
579579
""" Returns a list of all :class:`~plexapi.playlist.Playlist` objects on the server.
580580
581581
Parameters:
582582
playlistType (str, optional): The type of playlists to return (audio, video, photo).
583583
Default returns all playlists.
584+
sectionId (int, optional): The section ID (key) of the library to search within.
585+
title (str, optional): General string query to search for. Partial string matches are allowed.
586+
sort (str or list, optional): A string of comma separated sort fields in the format ``column:dir``.
584587
"""
585-
key = '/playlists'
586-
if playlistType:
587-
key = '%s?playlistType=%s' % (key, playlistType)
588-
return self.fetchItems(key)
588+
args = {}
589+
if playlistType is not None:
590+
args['playlistType'] = playlistType
591+
if sectionId is not None:
592+
args['sectionID'] = sectionId
593+
if title is not None:
594+
args['title'] = title
595+
if sort is not None:
596+
# TODO: Automatically retrieve and validate sort field similar to LibrarySection.search()
597+
args['sort'] = sort
598+
599+
key = '/playlists%s' % utils.joinArgs(args)
600+
return self.fetchItems(key, **kwargs)
589601

590602
def playlist(self, title):
591603
""" Returns the :class:`~plexapi.client.Playlist` that matches the specified title.
@@ -594,9 +606,12 @@ def playlist(self, title):
594606
title (str): Title of the playlist to return.
595607
596608
Raises:
597-
:exc:`~plexapi.exceptions.NotFound`: Invalid playlist title.
609+
:exc:`~plexapi.exceptions.NotFound`: Unable to find playlist.
598610
"""
599-
return self.fetchItem('/playlists', title=title)
611+
try:
612+
return self.playlists(title=title, title__iexact=title)[0]
613+
except IndexError:
614+
raise NotFound('Unable to find playlist with title "%s".' % title) from None
600615

601616
def optimizedItems(self, removeAll=None):
602617
""" Returns list of all :class:`~plexapi.media.Optimized` objects connected to server. """

tests/conftest.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,9 @@ def photo(photoalbum):
276276

277277
@pytest.fixture()
278278
def collection(plex, movies, movie):
279-
c = movies.collection("Test Collection")
280-
if c: return c
281-
else:
279+
try:
280+
return movies.collection("Test Collection")
281+
except NotFound:
282282
return plex.createCollection(
283283
title="Test Collection",
284284
section=movies,
@@ -288,9 +288,9 @@ def collection(plex, movies, movie):
288288

289289
@pytest.fixture()
290290
def playlist(plex, tvshows, season):
291-
p = tvshows.playlist("Test Playlist")
292-
if p: return p
293-
else:
291+
try:
292+
return tvshows.playlist("Test Playlist")
293+
except NotFound:
294294
return plex.createPlaylist(
295295
title="Test Playlist",
296296
items=season.episodes()[:3]

tests/test_library.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,11 @@ def test_library_MovieSection_collections(movies, movie):
207207
collection.delete()
208208

209209

210+
def test_library_MovieSection_collection_exception(movies):
211+
with pytest.raises(NotFound):
212+
movies.collection("Does Not Exists")
213+
214+
210215
def test_library_ShowSection_all(tvshows):
211216
assert len(tvshows.all(title__iexact="The 100"))
212217

@@ -241,10 +246,17 @@ def test_library_ShowSection_playlists(tvshows, show):
241246
assert playlist in playlists
242247
p = tvshows.playlist(playlist.title)
243248
assert playlist == p
249+
playlists = tvshows.playlists(title="test_", sort="mediaCount:asc")
250+
assert playlist in playlists
244251
finally:
245252
playlist.delete()
246253

247254

255+
def test_library_ShowSection_playlist_exception(tvshows):
256+
with pytest.raises(NotFound):
257+
tvshows.playlist("Does Not Exists")
258+
259+
248260
def test_library_MusicSection_albums(music):
249261
assert len(music.albums())
250262

0 commit comments

Comments
 (0)