From 7298b3c60697346b53b76adfa7e511d3678e3ef2 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 15 Nov 2020 17:54:48 -0800 Subject: [PATCH] Add ability to browse and walk the Plex server system file directories --- plexapi/library.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++ plexapi/server.py | 39 +++++++++++++++++++++++++++++++++++++ plexapi/utils.py | 5 +++++ 3 files changed, 92 insertions(+) diff --git a/plexapi/library.py b/plexapi/library.py index 4a7c4b84..41551295 100644 --- a/plexapi/library.py +++ b/plexapi/library.py @@ -1561,3 +1561,51 @@ 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/) + network (bool): True if path is a network location + path (str): Full path + title (str): Path folder + """ + + 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): + key = '%s?includeFiles=1' % self.key + return self._server.fetchItems(key) + + +@utils.registerPlexObject +class File(PlexObject): + """ Represents a single File. + + Attributes: + TAG (str): 'File' + + key (str): API URL (/services/browse/) + path (str): Full path + title (str): Path folder + """ + + TAG = 'File' + + def _loadData(self, data): + self.key = data.attrib.get('key') + self.path = data.attrib.get('path') + self.title = data.attrib.get('title') diff --git a/plexapi/server.py b/plexapi/server.py index a55582bf..9f366ed4 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -247,6 +247,45 @@ class PlexServer(PlexObject): log.warning('Unable to fetch client ports from myPlex: %s', err) return ports + def browse(self, path=None): + """ Browse the system file path using the Plex API. + Returns list of :class:`~plexapi.library.Path` and :class:`~plexapi.library.File` objects. + + Parameters: + path (str): Path to browse. + """ + if path is not None: + base64path = utils.base64str(path) + key = '/services/browse/%s?includeFiles=1' % base64path + else: + key = '/services/browse?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 (str): Path to walk. + """ + items = self.browse(path) + path = path or '' + paths = [] + files = [] + for item in items: + if item.TAG == 'Path': + paths.append(item) + elif item.TAG == 'File': + files.append(item) + yield path, paths, files + + for _path in paths: + for path, paths, files in self.walk(_path.path): + yield path, paths, files + def clients(self): """ Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. """ items = [] diff --git a/plexapi/utils.py b/plexapi/utils.py index 24a9c7dd..222455c9 100644 --- a/plexapi/utils.py +++ b/plexapi/utils.py @@ -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')