From 3de3bcfbc9dc739a7c997f71e24441c127e03f0e Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 12:18:17 -0700 Subject: [PATCH 1/8] Fix more library section ID cast to int --- plexapi/library.py | 2 +- plexapi/myplex.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index 68f962e22..426e25836 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -62,7 +62,7 @@ def sectionByID(self, sectionID): """ Returns the :class:`~plexapi.library.LibrarySection` that matches the specified sectionID. Parameters: - sectionID (str): ID of the section to return. + sectionID (int): ID of the section to return. """ if not self._sectionsByID or sectionID not in self._sectionsByID: self.sections() diff --git a/plexapi/myplex.py b/plexapi/myplex.py index 5d997e365..5e320e147 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -802,28 +802,28 @@ def history(self, maxresults=9999999, mindate=None): class Section(PlexObject): """ This refers to a shared section. The raw xml for the data presented here - can be found at: https://plex.tv/api/servers/{machineId}/shared_servers/{serverId} + can be found at: https://plex.tv/api/servers/{machineId}/shared_servers Attributes: TAG (str): section - id (int): shared section id - sectionKey (str): what key we use for this section + id (int): The shared section ID + key (int): The shared library section key + shared (bool): If this section is shared with the user title (str): Title of the section - sectionId (str): shared section id type (str): movie, tvshow, artist - shared (bool): If this section is shared with the user """ TAG = 'Section' def _loadData(self, data): self._data = data - # self.id = utils.cast(int, data.attrib.get('id')) # Havnt decided if this should be changed. - self.sectionKey = data.attrib.get('key') + self.id = utils.cast(int, data.attrib.get('id')) + self.key = utils.cast(int, data.attrib.get('key')) + self.shared = utils.cast(bool, data.attrib.get('shared', '0')) self.title = data.attrib.get('title') - self.sectionId = data.attrib.get('id') self.type = data.attrib.get('type') - self.shared = utils.cast(bool, data.attrib.get('shared')) + self.sectionId = self.id # For backwards compatibility + self.sectionKey = self.key # For backwards compatibility def history(self, maxresults=9999999, mindate=None): """ Get all Play History for a user for this section in this shared server. From 21f79560cfdbfb0621ebb5e9f69a5fb5d49fe853 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 12:38:53 -0700 Subject: [PATCH 2/8] Add method to return library size for specific libtypes --- plexapi/library.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/plexapi/library.py b/plexapi/library.py index 426e25836..cb068b056 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -394,7 +394,7 @@ def fetchItems(self, ekey, cls=None, container_start=None, container_size=None, @property def totalSize(self): - """ Returns the total number of items in the library. """ + """ Returns the total number of items in the library for the default library type. """ if self._totalSize is None: part = '/library/sections/%s/all?X-Plex-Container-Start=0&X-Plex-Container-Size=0' % self.key data = self._server.query(part) @@ -402,6 +402,27 @@ def totalSize(self): return self._totalSize + def totalViewSize(self, libtype=None, includeCollections=True): + """ Returns the total number of items in the library for a specified libtype. + (e.g. The total number of episodes or albums.) + + Parameters: + libtype (str, optional): The type of items to return the total number for (movie, show, season, episode, + artist, album, track, photoalbum). Default is the main library type. + includeCollections (bool, optional): True or False to include collections in the total number. + Default is True. + """ + args = { + 'includeCollections': int(includeCollections), + 'X-Plex-Container-Start': 0, + 'X-Plex-Container-Size': 0 + } + if libtype is not None: + args['type'] = utils.searchType(libtype) + part = '/library/sections/%s/all%s' % (self.key, utils.joinArgs(args)) + data = self._server.query(part) + return int(data.attrib.get("totalSize")) + def delete(self): """ Delete a library section. """ try: From 00105ab516e71cb6b8779b4a1c26019e1eab3e07 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 12:35:45 -0700 Subject: [PATCH 3/8] Add test for library totalViewSize --- tests/test_library.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_library.py b/tests/test_library.py index 053a3b71b..654683e66 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -58,6 +58,18 @@ def test_library_section_movies_all(movies): assert len(movies.all(container_start=0, container_size=1, maxresults=1)) == 1 +def test_library_section_totalViewSize(tvshows): + assert tvshows.totalViewSize() == 2 + assert tvshows.totalViewSize(libtype="show") == 2 + assert tvshows.totalViewSize(libtype="season") == 4 + assert tvshows.totalViewSize(libtype="episode") == 51 + show = tvshows.get("The 100") + show.addCollection("test_view_size") + assert tvshows.totalViewSize() == 3 + assert tvshows.totalViewSize(includeCollections=False) == 2 + show.removeCollection("test_view_size", locked=False) + + def test_library_section_delete(movies, patched_http_call): movies.delete() From 0ebdd1220974279e1aee545f4a2ce3d79708c445 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 12:51:59 -0700 Subject: [PATCH 4/8] Fix totalViewSize test episode count --- tests/test_library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_library.py b/tests/test_library.py index 654683e66..892c045a3 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -62,7 +62,7 @@ def test_library_section_totalViewSize(tvshows): assert tvshows.totalViewSize() == 2 assert tvshows.totalViewSize(libtype="show") == 2 assert tvshows.totalViewSize(libtype="season") == 4 - assert tvshows.totalViewSize(libtype="episode") == 51 + assert tvshows.totalViewSize(libtype="episode") == 49 show = tvshows.get("The 100") show.addCollection("test_view_size") assert tvshows.totalViewSize() == 3 From d10763b5c47c8bcc69f0148873927201f993d351 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 23:05:47 -0700 Subject: [PATCH 5/8] Don't need to use library _totalSize cache --- plexapi/library.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index cb068b056..2d1cd7755 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -355,7 +355,6 @@ def _loadData(self, data): # Private attrs as we dont want a reload. self._filterTypes = None self._fieldTypes = None - self._totalSize = None self._totalViewSize = None def fetchItems(self, ekey, cls=None, container_start=None, container_size=None, **kwargs): @@ -395,12 +394,7 @@ def fetchItems(self, ekey, cls=None, container_start=None, container_size=None, @property def totalSize(self): """ Returns the total number of items in the library for the default library type. """ - if self._totalSize is None: - part = '/library/sections/%s/all?X-Plex-Container-Start=0&X-Plex-Container-Size=0' % self.key - data = self._server.query(part) - self._totalSize = int(data.attrib.get("totalSize")) - - return self._totalSize + return self.totalViewSize(libtype=self.TYPE, includeCollections=False) def totalViewSize(self, libtype=None, includeCollections=True): """ Returns the total number of items in the library for a specified libtype. From 79f7e80ebbb8f579f185600c13b52b37a61a8d13 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 23:35:12 -0700 Subject: [PATCH 6/8] Validate title search arg as a filter kwarg --- plexapi/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plexapi/library.py b/plexapi/library.py index 2d1cd7755..69d6ea693 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -1097,7 +1097,7 @@ def search(self, title=None, sort=None, maxresults=None, filter_args.append(self._validateFilterField(field, values, libtype)) del kwargs[field] if title is not None: - args['title'] = title + filter_args.append(self._validateFilterField('title', title, libtype)) if sort is not None: args['sort'] = self._validateSortField(sort, libtype) if libtype is not None: From 0cf125d6a7ca565bff86d7708dad0eee7ef60673 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Tue, 23 Mar 2021 23:48:26 -0700 Subject: [PATCH 7/8] Only validate search title if it is a list --- plexapi/library.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plexapi/library.py b/plexapi/library.py index 69d6ea693..e84a44b29 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -1097,7 +1097,10 @@ def search(self, title=None, sort=None, maxresults=None, filter_args.append(self._validateFilterField(field, values, libtype)) del kwargs[field] if title is not None: - filter_args.append(self._validateFilterField('title', title, libtype)) + if isinstance(title, (list, tuple)): + filter_args.append(self._validateFilterField('title', title, libtype)) + else: + args['title'] = title if sort is not None: args['sort'] = self._validateSortField(sort, libtype) if libtype is not None: From b8835a1e2ee3c44541cd890c5701461b3a6b59ce Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Wed, 24 Mar 2021 15:56:56 -0700 Subject: [PATCH 8/8] Update doc string for totalViewSize --- plexapi/library.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plexapi/library.py b/plexapi/library.py index e84a44b29..0bfeb1feb 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -398,7 +398,9 @@ def totalSize(self): def totalViewSize(self, libtype=None, includeCollections=True): """ Returns the total number of items in the library for a specified libtype. - (e.g. The total number of episodes or albums.) + The number of items for the default library type will be returned if no libtype is specified. + (e.g. Specify ``libtype='episode'`` for the total number of episodes + or ``libtype='albums'`` for the total number of albums.) Parameters: libtype (str, optional): The type of items to return the total number for (movie, show, season, episode, @@ -407,7 +409,7 @@ def totalViewSize(self, libtype=None, includeCollections=True): Default is True. """ args = { - 'includeCollections': int(includeCollections), + 'includeCollections': int(bool(includeCollections)), 'X-Plex-Container-Start': 0, 'X-Plex-Container-Size': 0 } @@ -415,7 +417,7 @@ def totalViewSize(self, libtype=None, includeCollections=True): args['type'] = utils.searchType(libtype) part = '/library/sections/%s/all%s' % (self.key, utils.joinArgs(args)) data = self._server.query(part) - return int(data.attrib.get("totalSize")) + return utils.cast(int, data.attrib.get("totalSize")) def delete(self): """ Delete a library section. """