diff --git a/sabnzbd/api.py b/sabnzbd/api.py index 0c9e6e5..61ef4cd 100644 --- a/sabnzbd/api.py +++ b/sabnzbd/api.py @@ -43,6 +43,7 @@ from sabnzbd.skintext import SKIN_TEXT from sabnzbd.utils.rsslib import RSS, Item from sabnzbd.utils.json import JsonWriter +from sabnzbd.utils.pathbrowser import folders_at_path from sabnzbd.misc import loadavg, to_units, diskfree, disktotal, get_ext, \ get_filename, int_conv, globber, time_format from sabnzbd.encoding import xml_name, unicoder, special_fixer, platform_encode @@ -597,6 +598,19 @@ def _api_undefined(name, output, kwargs): #------------------------------------------------------------------------------ +def _api_browse(name, output, kwargs): + """ Return tree of local path """ + compact = kwargs.get('compact') + if compact and compact == '1': + limit = int_conv(kwargs.get('limit', 30)) + paths = [entry['path'] for entry in folders_at_path(os.path.dirname(name)) if 'path' in entry] + paths = '\n'.join(paths[0:limit]) + else: + paths = folders_at_path(name, True) + return report(output, keyword='paths', data=paths) + + +#------------------------------------------------------------------------------ def _api_config(name, output, kwargs): """ API: Dispather for "config" """ return _api_config_table.get(name, _api_config_undefined)(output, kwargs) @@ -710,7 +724,8 @@ _api_table = { 'rescan' : _api_rescan, 'eval_sort' : _api_eval_sort, 'watched_now' : _api_watched_now, - 'rss_now' : _api_rss_now + 'rss_now' : _api_rss_now, + 'browse' : _api_browse } _api_queue_table = { diff --git a/sabnzbd/utils/pathbrowser.py b/sabnzbd/utils/pathbrowser.py new file mode 100644 index 0000000..f3039d3 --- /dev/null +++ b/sabnzbd/utils/pathbrowser.py @@ -0,0 +1,81 @@ +#------------------------------------------------------------------------------------------------ +# This file is an excerpt from Sick Beard's browser.py +# Modified and improved to fit SABnzbd. +# +# Author: Nic Wolfe +# URL: http://code.google.com/p/sickbeard/ +# +# Sick Beard is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sick Beard is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sick Beard. If not, see . + +import os + +# this is for the drive letter code, it only works on windows +if os.name == 'nt': + from ctypes import windll + +# adapted from http://stackoverflow.com/questions/827371/is-there-a-way-to-list-all-the-available-drive-letters-in-python/827490 +def get_win_drives(): + """ Return list of detected drives """ + assert os.name == 'nt' + drives = [] + bitmask = windll.kernel32.GetLogicalDrives() #@UndefinedVariable + for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': + if bitmask & 1: + drives.append(letter) + bitmask >>= 1 + return drives + +def folders_at_path(path, include_parent = False): + """ Returns a list of dictionaries with the folders contained at the given path + Give the empty string as the path to list the contents of the root path + under Unix this means "/", on Windows this will be a list of drive letters) + from sabnzbd.encoding import unicoder + assert os.path.isabs(path) or path == "" + """ + from sabnzbd.encoding import unicoder + + # walk up the tree until we find a valid path + while path and not os.path.isdir(path): + if path == os.path.dirname(path): + path = '' + break + else: + path = os.path.dirname(path) + + if path == "": + if os.name == 'nt': + entries = [{'name': letter + ':\\', 'path': letter + ':\\'} for letter in get_win_drives()] + entries.insert(0, {'current_path': 'Root'}) + return entries + else: + path = '/' + + # fix up the path and find the parent + path = os.path.abspath(os.path.normpath(path)) + parent_path = os.path.dirname(path) + + # if we're at the root then the next step is the meta-node showing our drive letters + if path == parent_path and os.name == 'nt': + parent_path = "" + + file_list = [{ 'name': unicoder(filename), 'path': unicoder(os.path.join(path, filename)) } for filename in os.listdir(path)] + file_list = filter(lambda entry: os.path.isdir(entry['path']), file_list) + file_list = sorted(file_list, lambda x, y: cmp(os.path.basename(x['name']).lower(), os.path.basename(y['path']).lower())) + + file_list.insert(0, {'current_path': path}) + if include_parent and parent_path != path: + file_list.append({ 'name': "..", 'path': parent_path }) + + return file_list +