mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-25 05:00:22 +00:00
Merge pull request #601 from JonnyWong16/server_browse
Add ability to browse and walk the Plex server system file directories
This commit is contained in:
commit
ae59620e9a
5 changed files with 125 additions and 1 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -26,3 +26,7 @@ lib/
|
|||
pip-selfcheck.json
|
||||
pyvenv.cfg
|
||||
MANIFEST
|
||||
|
||||
|
||||
# path for the test lib.
|
||||
tools/plex
|
|
@ -1570,3 +1570,54 @@ class Collections(PlexPartialObject):
|
|||
|
||||
# def edit(self, **kwargs):
|
||||
# TODO
|
||||
|
||||
|
||||
@utils.registerPlexObject
|
||||
class Path(PlexObject):
|
||||
""" Represents a single directory Path.
|
||||
|
||||
Attributes:
|
||||
TAG (str): 'Path'
|
||||
|
||||
home (bool): True if the path is the home directory
|
||||
key (str): API URL (/services/browse/<base64path>)
|
||||
network (bool): True if path is a network location
|
||||
path (str): Full path to folder
|
||||
title (str): Folder name
|
||||
"""
|
||||
TAG = 'Path'
|
||||
|
||||
def _loadData(self, data):
|
||||
self.home = utils.cast(bool, data.attrib.get('home'))
|
||||
self.key = data.attrib.get('key')
|
||||
self.network = utils.cast(bool, data.attrib.get('network'))
|
||||
self.path = data.attrib.get('path')
|
||||
self.title = data.attrib.get('title')
|
||||
|
||||
def browse(self, includeFiles=True):
|
||||
""" Alias for :func:`~plexapi.server.PlexServer.browse`. """
|
||||
return self._server.browse(self, includeFiles)
|
||||
|
||||
def walk(self):
|
||||
""" Alias for :func:`~plexapi.server.PlexServer.walk`. """
|
||||
for path, paths, files in self._server.walk(self):
|
||||
yield path, paths, files
|
||||
|
||||
|
||||
@utils.registerPlexObject
|
||||
class File(PlexObject):
|
||||
""" Represents a single File.
|
||||
|
||||
Attributes:
|
||||
TAG (str): 'File'
|
||||
|
||||
key (str): API URL (/services/browse/<base64path>)
|
||||
path (str): Full path to file
|
||||
title (str): File name
|
||||
"""
|
||||
TAG = 'File'
|
||||
|
||||
def _loadData(self, data):
|
||||
self.key = data.attrib.get('key')
|
||||
self.path = data.attrib.get('path')
|
||||
self.title = data.attrib.get('title')
|
||||
|
|
|
@ -15,7 +15,7 @@ from plexapi.alert import AlertListener
|
|||
from plexapi.base import PlexObject
|
||||
from plexapi.client import PlexClient
|
||||
from plexapi.exceptions import BadRequest, NotFound, Unauthorized
|
||||
from plexapi.library import Hub, Library
|
||||
from plexapi.library import Hub, Library, Path, File
|
||||
from plexapi.media import Conversion, Optimized
|
||||
from plexapi.playlist import Playlist
|
||||
from plexapi.playqueue import PlayQueue
|
||||
|
@ -247,6 +247,53 @@ class PlexServer(PlexObject):
|
|||
log.warning('Unable to fetch client ports from myPlex: %s', err)
|
||||
return ports
|
||||
|
||||
def browse(self, path=None, includeFiles=True):
|
||||
""" Browse the system file path using the Plex API.
|
||||
Returns list of :class:`~plexapi.library.Path` and :class:`~plexapi.library.File` objects.
|
||||
|
||||
Parameters:
|
||||
path (:class:`~plexapi.library.Path` or str, optional): Full path to browse.
|
||||
includeFiles (bool): True to include files when browsing (Default).
|
||||
False to only return folders.
|
||||
"""
|
||||
if isinstance(path, Path):
|
||||
key = path.key
|
||||
elif path is not None:
|
||||
base64path = utils.base64str(path)
|
||||
key = '/services/browse/%s' % base64path
|
||||
else:
|
||||
key = '/services/browse'
|
||||
if includeFiles:
|
||||
key += '?includeFiles=1'
|
||||
return self.fetchItems(key)
|
||||
|
||||
def walk(self, path=None):
|
||||
""" Walk the system file tree using the Plex API similar to `os.walk`.
|
||||
Yields a 3-tuple `(path, paths, files)` where
|
||||
`path` is a string of the directory path,
|
||||
`paths` is a list of :class:`~plexapi.library.Path` objects, and
|
||||
`files` is a list of :class:`~plexapi.library.File` objects.
|
||||
|
||||
Parameters:
|
||||
path (:class:`~plexapi.library.Path` or str, optional): Full path to walk.
|
||||
"""
|
||||
paths = []
|
||||
files = []
|
||||
for item in self.browse(path):
|
||||
if isinstance(item, Path):
|
||||
paths.append(item)
|
||||
elif isinstance(item, File):
|
||||
files.append(item)
|
||||
|
||||
if isinstance(path, Path):
|
||||
path = path.path
|
||||
|
||||
yield path or '', paths, files
|
||||
|
||||
for _path in paths:
|
||||
for path, paths, files in self.walk(_path):
|
||||
yield path, paths, files
|
||||
|
||||
def clients(self):
|
||||
""" Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. """
|
||||
items = []
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
@ -411,3 +412,7 @@ def getAgentIdentifier(section, agent):
|
|||
agents += identifiers
|
||||
raise NotFound('Couldnt find "%s" in agents list (%s)' %
|
||||
(agent, ', '.join(agents)))
|
||||
|
||||
|
||||
def base64str(text):
|
||||
return base64.b64encode(text.encode('utf-8')).decode('utf-8')
|
||||
|
|
|
@ -287,6 +287,23 @@ def test_server_downloadDatabases(tmpdir, plex):
|
|||
assert len(tmpdir.listdir()) > 1
|
||||
|
||||
|
||||
def test_server_browse(plex, movies):
|
||||
movies_path = movies.locations[0]
|
||||
# browse root
|
||||
paths = plex.browse()
|
||||
assert len(paths)
|
||||
# browse the path of the movie library
|
||||
paths = plex.browse(movies_path)
|
||||
assert len(paths)
|
||||
# browse the path of the movie library without files
|
||||
paths = plex.browse(movies_path, includeFiles=False)
|
||||
assert not len([f for f in paths if f.TAG == 'File'])
|
||||
# walk the path of the movie library
|
||||
for path, paths, files in plex.walk(movies_path):
|
||||
assert path.startswith(movies_path)
|
||||
assert len(paths) or len(files)
|
||||
|
||||
|
||||
def test_server_allowMediaDeletion(account):
|
||||
plex = PlexServer(utils.SERVER_BASEURL, account.authenticationToken)
|
||||
# Check server current allowMediaDeletion setting
|
||||
|
|
Loading…
Reference in a new issue