Skip to content

Commit

Permalink
Merge pull request #837 from pkkid/libraryEditUpdates
Browse files Browse the repository at this point in the history
Library editing updates
  • Loading branch information
blacktwin authored Jan 6, 2022
2 parents a497613 + 34f0125 commit 1d77f32
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 12 deletions.
78 changes: 73 additions & 5 deletions plexapi/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def add(self, name='', type='', agent='', scanner='', location='', language='en'
name (str): Name of the library
agent (str): Example com.plexapp.agents.imdb
type (str): movie, show, # check me
location (str): /path/to/files
location (str or list): /path/to/files, ["/path/to/files", "/path/to/morefiles"]
language (str): Two letter language fx en
kwargs (dict): Advanced options should be passed as a dict. where the id is the key.
Expand Down Expand Up @@ -308,8 +308,16 @@ def add(self, name='', type='', agent='', scanner='', location='', language='en'
40:South Africa, 41:Spain, 42:Sweden, 43:Switzerland, 44:Taiwan, 45:Trinidad,
46:United Kingdom, 47:United States, 48:Uruguay, 49:Venezuela.
"""
part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=%s&location=%s' % (
quote_plus(name), type, agent, quote_plus(scanner), language, quote_plus(location)) # noqa E126
if isinstance(location, str):
location = [location]
locations = []
for path in location:
if not self._server.isBrowsable(path):
raise BadRequest('Path: %s does not exist.' % path)
locations.append(('location', path))

part = '/library/sections?name=%s&type=%s&agent=%s&scanner=%s&language=%s&%s' % (
quote_plus(name), type, agent, quote_plus(scanner), language, urlencode(locations, doseq=True)) # noqa E126
if kwargs:
part += urlencode(kwargs)
return self._server.query(part, method=self._server._session.post)
Expand Down Expand Up @@ -486,16 +494,76 @@ def reload(self):
return self

def edit(self, agent=None, **kwargs):
""" Edit a library (Note: agent is required). See :class:`~plexapi.library.Library` for example usage.
""" Edit a library. See :class:`~plexapi.library.Library` for example usage.
Parameters:
agent (str, optional): The library agent.
kwargs (dict): Dict of settings to edit.
"""
if not agent:
agent = self.agent
part = '/library/sections/%s?agent=%s&%s' % (self.key, agent, urlencode(kwargs))

locations = []
if kwargs.get('location'):
if isinstance(kwargs['location'], str):
kwargs['location'] = [kwargs['location']]
for path in kwargs.pop('location'):
if not self._server.isBrowsable(path):
raise BadRequest('Path: %s does not exist.' % path)
locations.append(('location', path))

params = list(kwargs.items()) + locations

part = '/library/sections/%s?agent=%s&%s' % (self.key, agent, urlencode(params, doseq=True))
self._server.query(part, method=self._server._session.put)

def addLocations(self, location):
""" Add a location to a library.
Parameters:
location (str or list): A single folder path, list of paths.
Example:
.. code-block:: python
LibrarySection.addLocations('/path/1')
LibrarySection.addLocations(['/path/1', 'path/2', '/path/3'])
"""
locations = self.locations
if isinstance(location, str):
location = [location]
for path in location:
if not self._server.isBrowsable(path):
raise BadRequest('Path: %s does not exist.' % path)
locations.append(path)
self.edit(location=locations)

def removeLocations(self, location):
""" Remove a location from a library.
Parameters:
location (str or list): A single folder path, list of paths.
Example:
.. code-block:: python
LibrarySection.removeLocations('/path/1')
LibrarySection.removeLocations(['/path/1', 'path/2', '/path/3'])
"""
locations = self.locations
if isinstance(location, str):
location = [location]
for path in location:
if path in locations:
locations.remove(path)
else:
raise BadRequest('Path: %s does not exist in the library.' % location)
if len(locations) == 0:
raise BadRequest('You are unable to remove all locations from a library.')
self.edit(location=locations)

def get(self, title):
""" Returns the media item with the specified title.
Expand Down
13 changes: 13 additions & 0 deletions plexapi/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from xml.etree import ElementTree

import requests
import os
from plexapi import (BASE_HEADERS, CONFIG, TIMEOUT, X_PLEX_CONTAINER_SIZE, log,
logfilter)
from plexapi import utils
Expand Down Expand Up @@ -384,6 +385,18 @@ def walk(self, path=None):
for path, paths, files in self.walk(_path):
yield path, paths, files

def isBrowsable(self, path):
""" Returns True if the Plex server can browse the given path.
Parameters:
path (:class:`~plexapi.library.Path` or str): Full path to browse.
"""
if isinstance(path, Path):
path = path.path
path = os.path.normpath(path)
paths = [p.path for p in self.browse(os.path.dirname(path), includeFiles=False)]
return path in paths

def clients(self):
""" Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. """
items = []
Expand Down
55 changes: 48 additions & 7 deletions tests/test_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,65 @@ def test_library_recentlyAdded(plex):
assert len(list(plex.library.recentlyAdded()))


def test_library_add_edit_delete(plex):
# Dont add a location to prevent scanning scanning
def test_library_add_edit_delete(plex, movies, photos):
# Create Other Videos library = No external metadata scanning
section_name = "plexapi_test_section"
movie_location = movies.locations[0]
photo_location = photos.locations[0]
plex.library.add(
name=section_name,
type="movie",
agent="com.plexapp.agents.imdb",
scanner="Plex Movie Scanner",
agent="com.plexapp.agents.none",
scanner="Plex Video Files Scanner",
language="en",
location=[movie_location, photo_location]
)
section = plex.library.section(section_name)
assert section.title == section_name
# Create library with an invalid path
error_section_name = "plexapi_error_section"
with pytest.raises(BadRequest):
plex.library.add(
name=error_section_name,
type="movie",
agent="com.plexapp.agents.none",
scanner="Plex Video Files Scanner",
language="en",
location=[movie_location, photo_location[:-1]]
)
# Create library with no path
with pytest.raises(BadRequest):
plex.library.add(
name=error_section_name,
type="movie",
agent="com.plexapp.agents.none",
scanner="Plex Video Files Scanner",
language="en",
)
with pytest.raises(NotFound):
plex.library.section(error_section_name)
new_title = "a renamed lib"
section.edit(
name=new_title, type="movie", agent="com.plexapp.agents.imdb"
)
section.edit(name=new_title)
section.reload()
assert section.title == new_title
with pytest.raises(BadRequest):
section.addLocations(movie_location[:-1])
with pytest.raises(BadRequest):
section.removeLocations(movie_location[:-1])
section.removeLocations(photo_location)
section.reload()
assert len(section.locations) == 1
section.addLocations(photo_location)
section.reload()
assert len(section.locations) == 2
section.edit(**{'location': movie_location})
section.reload()
assert len(section.locations) == 1
with pytest.raises(BadRequest):
section.edit(**{'location': movie_location[:-1]})
# Attempt to remove all locations
with pytest.raises(BadRequest):
section.removeLocations(section.locations)
section.delete()
assert section not in plex.library.sections()

Expand Down

0 comments on commit 1d77f32

Please sign in to comment.