Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Library editing updates #837

Merged
merged 48 commits into from
Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ccda840
adding pathExist to utils
blacktwin Sep 27, 2021
75c4886
update to Library.add method to allow for multiple locations
blacktwin Sep 27, 2021
e8711e9
update to Library.edit method to allow editing locations
blacktwin Sep 27, 2021
25fbf6b
adding convenience methods for adding and removing locations from a l…
blacktwin Sep 27, 2021
7e04b9f
Library.edit method docstring update with example
blacktwin Sep 27, 2021
222b8fe
Merge branch 'master' of https://github.com/pkkid/python-plexapi into…
blacktwin Sep 27, 2021
9764ad4
removing example
blacktwin Oct 22, 2021
e46fc1c
remove pathExist method from utils
blacktwin Oct 26, 2021
9213560
create isBrowseable method in server.PlexServer
blacktwin Oct 26, 2021
61d93e7
refactor for new method to check if path exists
blacktwin Oct 26, 2021
b14b48f
check if path exists for list of paths
blacktwin Oct 26, 2021
fbd5d10
update doc to mention list support for paths
blacktwin Oct 26, 2021
cd04cb4
change edit method to use new method for checking path
blacktwin Oct 26, 2021
cb1eebd
change acceptable class for adding and removing locations
blacktwin Oct 26, 2021
84bd515
updating docstring for new acceptable class
blacktwin Oct 26, 2021
617206e
adding browsable checks for adding and removing paths
blacktwin Oct 26, 2021
8cf4f01
refactor removing locations
blacktwin Oct 26, 2021
ba490c7
refactor edit method for correcting location param
blacktwin Dec 19, 2021
7e14d2d
check for valid paths in addLocation and removeLocation methods
blacktwin Dec 19, 2021
d3b0d7b
remove list check in add() method
blacktwin Dec 20, 2021
824be40
remove path check on str in add() method
blacktwin Dec 20, 2021
1aa7043
add paths inside valid path check loop
blacktwin Dec 20, 2021
d04bf03
Use .get() for kwargs location for when not editing library locations
blacktwin Dec 20, 2021
d1b1903
fix up removeLocation method
blacktwin Dec 20, 2021
5cf95e5
we are unable to remove all locations from a library
blacktwin Dec 20, 2021
c2facf0
Merge branch 'master' into libraryEditUpdates
blacktwin Dec 20, 2021
4c519c6
remove underscores
blacktwin Dec 20, 2021
9586d8f
fix up for addLocations, only check paths that are being added not ex…
blacktwin Dec 20, 2021
7390a9b
copy/paste oops
blacktwin Dec 20, 2021
5494c1e
Change test to use Other Videos library type to prevent scanning
blacktwin Dec 20, 2021
ebcadd2
incorrect exception
blacktwin Dec 20, 2021
5527979
docstring indention fixes
blacktwin Dec 20, 2021
f8e2b06
unexpected unindent
blacktwin Dec 20, 2021
54897d2
This reloading was removed in #855.
blacktwin Jan 3, 2022
4f340d0
var renaming for consistency
blacktwin Jan 3, 2022
d2c3fb1
attempt to remove all locations
blacktwin Jan 3, 2022
2f752d2
removeLocations with a Path object
blacktwin Jan 3, 2022
26732f7
fix for movie_path
blacktwin Jan 3, 2022
11ad27b
add edit kwargs test
blacktwin Jan 5, 2022
01ab5bd
add isBrowseable using path object
blacktwin Jan 5, 2022
c19fa9f
removing testing with `Path` object
blacktwin Jan 5, 2022
624af2e
remove use of `Path` objects for adding and removing locations
blacktwin Jan 5, 2022
050572d
remove isBrowseable(Path) check
blacktwin Jan 5, 2022
0f20295
fix section call
blacktwin Jan 5, 2022
0882b8f
minor docstring update
blacktwin Jan 6, 2022
9302f0d
additional edit coverage
blacktwin Jan 6, 2022
0771718
additional edit test with bad path
blacktwin Jan 6, 2022
34f0125
docstring line
blacktwin Jan 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 85 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,88 @@ 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)

# 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 addLocations(self, location):
""" Add a location to a library.

Parameters:
location (str, list, or :class:~plexapi.library.Path)): A single folder path, list of paths,
or :class:`~plexapi.library.Path`.

Example:

.. code-block:: python

LibrarySection.addLocations('/path/1')
LibrarySection.addLocations(['/path/1', 'path/2', '/path/3'])
LibrarySection.addLocations(PlexServer.browse()[0])
"""
locations = self.locations
if isinstance(location, Path):
location = location.path
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, list, or :class:~plexapi.library.Path): A single folder path, list of paths,
or :class:`~plexapi.library.Path`.
Example:

.. code-block:: python

LibrarySection.removeLocations('/path/1')
LibrarySection.removeLocations(['/path/1', 'path/2', '/path/3'])
LibrarySection.removeLocations(PlexServer.browse()[0])
"""
locations = self.locations
if isinstance(location, Path):
location = location.path
if isinstance(location, str):
location = [location]
for _location in location:
if _location in locations:
locations.remove(_location)
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
47 changes: 40 additions & 7 deletions tests/test_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,24 +121,57 @@ 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.delete()
assert section not in plex.library.sections()

Expand Down