diff --git a/plexapi/library.py b/plexapi/library.py index 5afff962e..12ae407f8 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -26,47 +26,61 @@ class Library(PlexObject): def _loadData(self, data): self._data = data - self._sectionsByID = {} # cached Section UUIDs self.identifier = data.attrib.get('identifier') self.mediaTagVersion = data.attrib.get('mediaTagVersion') self.title1 = data.attrib.get('title1') self.title2 = data.attrib.get('title2') + self._sectionsByID = {} # cached sections by key + self._sectionsByTitle = {} # cached sections by title - def sections(self): - """ Returns a list of all media sections in this library. Library sections may be any of - :class:`~plexapi.library.MovieSection`, :class:`~plexapi.library.ShowSection`, - :class:`~plexapi.library.MusicSection`, :class:`~plexapi.library.PhotoSection`. - """ + def _loadSections(self): + """ Loads and caches all the library sections. """ key = '/library/sections' - sections = [] + self._sectionsByID = {} + self._sectionsByTitle = {} for elem in self._server.query(key): for cls in (MovieSection, ShowSection, MusicSection, PhotoSection): if elem.attrib.get('type') == cls.TYPE: section = cls(self._server, elem, key) self._sectionsByID[section.key] = section - sections.append(section) - return sections + self._sectionsByTitle[section.title.lower()] = section + + def sections(self): + """ Returns a list of all media sections in this library. Library sections may be any of + :class:`~plexapi.library.MovieSection`, :class:`~plexapi.library.ShowSection`, + :class:`~plexapi.library.MusicSection`, :class:`~plexapi.library.PhotoSection`. + """ + self._loadSections() + return list(self._sectionsByID.values()) - def section(self, title=None): + def section(self, title): """ Returns the :class:`~plexapi.library.LibrarySection` that matches the specified title. Parameters: title (str): Title of the section to return. """ - for section in self.sections(): - if section.title.lower() == title.lower(): - return section - raise NotFound('Invalid library section: %s' % title) + if not self._sectionsByTitle or title not in self._sectionsByTitle: + self._loadSections() + try: + return self._sectionsByTitle[title.lower()] + except KeyError: + raise NotFound('Invalid library section: %s' % title) from None def sectionByID(self, sectionID): """ Returns the :class:`~plexapi.library.LibrarySection` that matches the specified sectionID. Parameters: sectionID (int): ID of the section to return. + + Raises: + :exc:`~plexapi.exceptions.NotFound`: The library section ID is not found on the server. """ if not self._sectionsByID or sectionID not in self._sectionsByID: - self.sections() - return self._sectionsByID[sectionID] + self._loadSections() + try: + return self._sectionsByID[sectionID] + except KeyError: + raise NotFound('Invalid library sectionID: %s' % sectionID) from None def all(self, **kwargs): """ Returns a list of all media from all library sections. @@ -464,8 +478,12 @@ def delete(self): log.error(msg) raise - def reload(self, key=None): - return self._server.library.section(self.title) + def reload(self): + """ Reload the data for the library section. """ + self._server.library._loadSections() + newLibrary = self._server.library.sectionByID(self.key) + self.__dict__.update(newLibrary.__dict__) + return self def edit(self, agent=None, **kwargs): """ Edit a library (Note: agent is required). See :class:`~plexapi.library.Library` for example usage. @@ -478,11 +496,6 @@ def edit(self, agent=None, **kwargs): part = '/library/sections/%s?agent=%s&%s' % (self.key, agent, urlencode(kwargs)) self._server.query(part, method=self._server._session.put) - # Reload this way since the self.key dont have a full path, but is simply a id. - for s in self._server.library.sections(): - if s.key == self.key: - return s - def get(self, title): """ Returns the media item with the specified title. diff --git a/tests/test_library.py b/tests/test_library.py index da2bb0156..bc79e9aec 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -17,6 +17,8 @@ def test_library_Library_section(plex): assert section_name.title == "TV Shows" with pytest.raises(NotFound): assert plex.library.section("cant-find-me") + with pytest.raises(NotFound): + assert plex.library.sectionByID(-1) def test_library_Library_sectionByID_is_equal_section(plex, movies): @@ -129,12 +131,16 @@ def test_library_add_edit_delete(plex): scanner="Plex Movie Scanner", language="en", ) - assert plex.library.section(section_name) - edited_library = plex.library.section(section_name).edit( - name="a renamed lib", type="movie", agent="com.plexapp.agents.imdb" + section = plex.library.section(section_name) + assert section.title == section_name + new_title = "a renamed lib" + section.edit( + name=new_title, type="movie", agent="com.plexapp.agents.imdb" ) - assert edited_library.title == "a renamed lib" - plex.library.section("a renamed lib").delete() + section.reload() + assert section.title == new_title + section.delete() + assert section not in plex.library.sections() def test_library_Library_cleanBundle(plex): @@ -372,7 +378,6 @@ def test_library_editAdvanced_default(movies): if setting.id == "collectionMode": assert int(setting.value) == 0 - movies.reload() movies.defaultAdvanced() for setting in movies.settings(): assert str(setting.value) == str(setting.default)