Merge branch 'develop'

This commit is contained in:
Ruud
2014-09-23 14:54:21 +02:00
19 changed files with 290 additions and 90 deletions
+2 -2
View File
@@ -286,13 +286,13 @@ config = [{
'name': 'permission_folder',
'default': '0755',
'label': 'Folder CHMOD',
'description': 'Can be either decimal (493) or octal (leading zero: 0755)',
'description': 'Can be either decimal (493) or octal (leading zero: 0755). <a target="_blank" href="http://permissions-calculator.org/">Calculate the correct value</a>',
},
{
'name': 'permission_file',
'default': '0755',
'label': 'File CHMOD',
'description': 'Same as Folder CHMOD but for files',
'description': 'See Folder CHMOD description, but for files',
},
],
},
+5 -5
View File
@@ -25,7 +25,7 @@ class Transmission(DownloaderBase):
def connect(self):
# Load host from config and split out port.
host = cleanHost(self.conf('host'), protocol = False).split(':')
host = cleanHost(self.conf('host')).rstrip('/').rsplit(':', 1)
if not isInt(host[1]):
log.error('Config properties are not filled in correctly, port is missing.')
return False
@@ -162,11 +162,11 @@ class Transmission(DownloaderBase):
class TransmissionRPC(object):
"""TransmissionRPC lite library"""
def __init__(self, host = 'localhost', port = 9091, rpc_url = 'transmission', username = None, password = None):
def __init__(self, host = 'http://localhost', port = 9091, rpc_url = 'transmission', username = None, password = None):
super(TransmissionRPC, self).__init__()
self.url = 'http://' + host + ':' + str(port) + '/' + rpc_url + '/rpc'
self.url = host + ':' + str(port) + '/' + rpc_url + '/rpc'
self.tag = 0
self.session_id = 0
self.session = {}
@@ -274,8 +274,8 @@ config = [{
},
{
'name': 'host',
'default': 'localhost:9091',
'description': 'Hostname with port. Usually <strong>localhost:9091</strong>',
'default': 'http://localhost:9091',
'description': 'Hostname with port. Usually <strong>http://localhost:9091</strong>',
},
{
'name': 'rpc_url',
+22
View File
@@ -382,6 +382,28 @@ def getFreeSpace(directories):
return free_space
def getSize(paths):
single = not isinstance(paths, (tuple, list))
if single:
paths = [paths]
total_size = 0
for path in paths:
path = sp(path)
if os.path.isdir(path):
total_size = 0
for dirpath, _, filenames in os.walk(path):
for f in filenames:
total_size += os.path.getsize(sp(os.path.join(dirpath, f)))
elif os.path.isfile(path):
total_size += os.path.getsize(path)
return total_size / 1048576 # MB
def find(func, iterable):
for item in iterable:
if func(item):
@@ -42,6 +42,7 @@ class Base(TorrentProvider):
link = result.find('span', attrs = {'class': 'torrent_name_link'}).parent
url = result.find('td', attrs = {'class': 'torrent_td'}).find('a')
tds = result.find_all('td')
results.append({
'id': link['href'].replace('torrents.php?torrentid=', ''),
@@ -49,8 +50,8 @@ class Base(TorrentProvider):
'url': self.urls['download'] % url['href'],
'detail_url': self.urls['download'] % link['href'],
'size': self.parseSize(result.find_all('td')[5].string),
'seeders': tryInt(result.find_all('td')[7].string),
'leechers': tryInt(result.find_all('td')[8].string),
'seeders': tryInt(tds[len(tds)-2].string),
'leechers': tryInt(tds[len(tds)-1].string),
})
except:
@@ -73,4 +73,24 @@ config = [{
],
},
],
}, {
'name': 'torrent',
'groups': [
{
'tab': 'searcher',
'name': 'searcher',
'wizard': True,
'options': [
{
'name': 'minimum_seeders',
'advanced': True,
'label': 'Minimum seeders',
'description': 'Ignore torrents with seeders below this number',
'default': 1,
'type': 'int',
'unit': 'seeders'
},
],
},
],
}]
+5 -1
View File
@@ -27,6 +27,10 @@ class MovieBase(MovieTypeBase):
addApiView('movie.add', self.addView, docs = {
'desc': 'Add new movie to the wanted list',
'return': {'type': 'object', 'example': """{
'success': True,
'movie': object
}"""},
'params': {
'identifier': {'desc': 'IMDB id of the movie your want to add.'},
'profile_id': {'desc': 'ID of quality profile you want the add the movie in. If empty will use the default profile.'},
@@ -150,7 +154,7 @@ class MovieBase(MovieTypeBase):
for release in fireEvent('release.for_media', m['_id'], single = True):
if release.get('status') in ['downloaded', 'snatched', 'seeding', 'done']:
if params.get('ignore_previous', False):
fireEvent('release.update_status', m['_id'], status = 'ignored')
fireEvent('release.update_status', release['_id'], status = 'ignored')
else:
fireEvent('release.delete', release['_id'], single = True)
@@ -2,7 +2,7 @@ import base64
import time
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import tryUrlencode
from couchpotato.core.helpers.encoding import tryUrlencode, ss
from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie.providers.base import MovieProvider
from couchpotato.environment import Env
@@ -66,7 +66,7 @@ class CouchPotatoApi(MovieProvider):
if not name:
return
name_enc = base64.b64encode(name)
name_enc = base64.b64encode(ss(name))
return self.getJsonData(self.urls['validate'] % name_enc, headers = self.getRequestHeaders())
def isMovie(self, identifier = None):
@@ -25,6 +25,6 @@ class Filmstarts(UserscriptBase):
name = html.find("meta", {"property":"og:title"})['content']
# Year of production is not available in the meta data, so get it from the table
year = table.find("tr", text="Produktionsjahr").parent.parent.parent.td.text
year = table.find(text="Produktionsjahr").parent.parent.next_sibling.text
return self.search(name, year)
return self.search(name, year)
+4 -4
View File
@@ -34,9 +34,9 @@ class Growl(Notification):
self.growl = notifier.GrowlNotifier(
applicationName = Env.get('appname'),
notifications = ["Updates"],
defaultNotifications = ["Updates"],
applicationIcon = '%s/static/images/couch.png' % fireEvent('app.api_url', single = True),
notifications = ['Updates'],
defaultNotifications = ['Updates'],
applicationIcon = self.getNotificationImage('medium'),
hostname = hostname if hostname else 'localhost',
password = password if password else None,
port = port if port else 23053
@@ -56,7 +56,7 @@ class Growl(Notification):
try:
self.growl.notify(
noteType = "Updates",
noteType = 'Updates',
title = self.default_title,
description = message,
sticky = False,
+3 -3
View File
@@ -1,4 +1,4 @@
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.helpers.variable import getTitle, getIdentifier
from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification
@@ -16,7 +16,7 @@ class Trakt(Notification):
'test': 'account/test/%s',
}
listen_to = ['movie.downloaded']
listen_to = ['movie.snatched']
def notify(self, message = '', data = None, listener = None):
if not data: data = {}
@@ -38,7 +38,7 @@ class Trakt(Notification):
'username': self.conf('automation_username'),
'password': self.conf('automation_password'),
'movies': [{
'imdb_id': data['identifier'],
'imdb_id': getIdentifier(data),
'title': getTitle(data),
'year': data['info']['year']
}] if data else []
+35 -22
View File
@@ -121,15 +121,31 @@ class Plugin(object):
if os.path.exists(path):
log.debug('%s already exists, overwriting file with new version', path)
try:
f = open(path, 'w+' if not binary else 'w+b')
f.write(content)
f.close()
os.chmod(path, Env.getPermission('file'))
except:
log.error('Unable writing to file "%s": %s', (path, traceback.format_exc()))
if os.path.isfile(path):
os.remove(path)
write_type = 'w+' if not binary else 'w+b'
# Stream file using response object
if isinstance(content, requests.models.Response):
# Write file to temp
with open('%s.tmp' % path, write_type) as f:
for chunk in content.iter_content(chunk_size = 1048576):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
f.flush()
# Rename to destination
os.rename('%s.tmp' % path, path)
else:
try:
f = open(path, write_type)
f.write(content)
f.close()
os.chmod(path, Env.getPermission('file'))
except:
log.error('Unable writing to file "%s": %s', (path, traceback.format_exc()))
if os.path.isfile(path):
os.remove(path)
def makeDir(self, path):
path = sp(path)
@@ -146,21 +162,17 @@ class Plugin(object):
folder = sp(folder)
for item in os.listdir(folder):
full_folder = os.path.join(folder, item)
full_folder = sp(os.path.join(folder, item))
if not only_clean or (item in only_clean and os.path.isdir(full_folder)):
for root, dirs, files in os.walk(full_folder):
for subfolder, dirs, files in os.walk(full_folder, topdown = False):
for dir_name in dirs:
full_path = os.path.join(root, dir_name)
if len(os.listdir(full_path)) == 0:
try:
os.rmdir(full_path)
except:
if show_error:
log.info2('Couldn\'t remove directory %s: %s', (full_path, traceback.format_exc()))
try:
os.rmdir(subfolder)
except:
if show_error:
log.info2('Couldn\'t remove directory %s: %s', (subfolder, traceback.format_exc()))
try:
os.rmdir(folder)
@@ -169,7 +181,7 @@ class Plugin(object):
log.error('Couldn\'t remove empty directory %s: %s', (folder, traceback.format_exc()))
# http request
def urlopen(self, url, timeout = 30, data = None, headers = None, files = None, show_error = True):
def urlopen(self, url, timeout = 30, data = None, headers = None, files = None, show_error = True, stream = False):
url = quote(ss(url), safe = "%/:=&?~#+!$,;'@()*[]")
if not headers: headers = {}
@@ -210,6 +222,7 @@ class Plugin(object):
'timeout': timeout,
'files': files,
'verify': False, #verify_ssl, Disable for now as to many wrongly implemented certificates..
'stream': stream,
}
method = 'post' if len(data) > 0 or files else 'get'
@@ -218,7 +231,7 @@ class Plugin(object):
status_code = response.status_code
if response.status_code == requests.codes.ok:
data = response.content
data = response if stream else response.content
else:
response.raise_for_status()
+1 -1
View File
@@ -27,7 +27,7 @@ class CategoryPlugin(Plugin):
'desc': 'List all available categories',
'return': {'type': 'object', 'example': """{
'success': True,
'list': array, categories
'categories': array, categories
}"""}
})
+4 -1
View File
@@ -64,6 +64,9 @@ class FileManager(Plugin):
def download(self, url = '', dest = None, overwrite = False, urlopen_kwargs = None):
if not urlopen_kwargs: urlopen_kwargs = {}
# Return response object to stream download
urlopen_kwargs['stream'] = True
if not dest: # to Cache
dest = os.path.join(Env.get('cache_dir'), '%s.%s' % (md5(url), getExt(url)))
@@ -107,4 +110,4 @@ class FileManager(Plugin):
else:
log.info('Subfolder test succeeded')
return failed == 0
return failed == 0
+4 -3
View File
@@ -8,7 +8,7 @@ from couchpotato import md5, get_db
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, addEvent
from couchpotato.core.helpers.encoding import toUnicode, sp
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.helpers.variable import getTitle, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from .index import ReleaseIndex, ReleaseStatusIndex, ReleaseIDIndex, ReleaseDownloadIndex
@@ -380,6 +380,7 @@ class Release(Plugin):
wait_for = False
let_through = False
filtered_results = []
minimum_seeders = tryInt(Env.setting('minimum_seeders', section = 'torrent', default = 1))
# Filter out ignored and other releases we don't want
for rel in results:
@@ -396,8 +397,8 @@ class Release(Plugin):
log.info('Ignored, size "%sMB" to low: %s', (rel['size'], rel['name']))
continue
if 'seeders' in rel and rel.get('seeders') <= 0:
log.info('Ignored, no seeders: %s', (rel['name']))
if 'seeders' in rel and rel.get('seeders') < minimum_seeders:
log.info('Ignored, not enough seeders, has %s needs %s: %s', (rel.get('seeders'), minimum_seeders, rel['name']))
continue
# If a single release comes through the "wait for", let through all
+45 -11
View File
@@ -10,7 +10,8 @@ from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import toUnicode, ss, sp
from couchpotato.core.helpers.variable import getExt, mergeDicts, getTitle, \
getImdb, link, symlink, tryInt, splitString, fnEscape, isSubFolder, getIdentifier
getImdb, link, symlink, tryInt, splitString, fnEscape, isSubFolder, \
getIdentifier, randomString, getFreeSpace, getSize
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.environment import Env
@@ -219,6 +220,12 @@ class Renamer(Plugin):
nfo_name = self.conf('nfo_name')
separator = self.conf('separator')
cd_keys = ['<cd>','<cd_nr>']
if not any(x in folder_name for x in cd_keys) and not any(x in file_name for x in cd_keys):
log.error('Missing `cd` or `cd_nr` in the renamer. This will cause multi-file releases of being renamed to the same file.'
'Force adding it')
file_name = '%s %s' % ('<cd>', file_name)
# Tag release folder as failed_rename in case no groups were found. This prevents check_snatched from removing the release from the downloader.
if not groups and self.statusInfoComplete(release_download):
self.tagRelease(release_download = release_download, tag = 'failed_rename')
@@ -266,13 +273,14 @@ class Renamer(Plugin):
category_label = category['label']
if category['destination'] and len(category['destination']) > 0 and category['destination'] != 'None':
destination = category['destination']
destination = sp(category['destination'])
log.debug('Setting category destination for "%s": %s' % (media_title, destination))
else:
log.debug('No category destination found for "%s"' % media_title)
except:
log.error('Failed getting category label: %s', traceback.format_exc())
# Find subtitle for renaming
group['before_rename'] = []
fireEvent('renamer.before', group)
@@ -369,6 +377,9 @@ class Renamer(Plugin):
if separator:
final_file_name = final_file_name.replace(' ', separator)
final_folder_name = ss(final_folder_name)
final_file_name = ss(final_file_name)
# Move DVD files (no structure renaming)
if group['is_dvd'] and file_type is 'movie':
found = False
@@ -537,6 +548,13 @@ class Renamer(Plugin):
(not keep_original or self.fileIsAdded(current_file, group)):
remove_files.append(current_file)
total_space, available_space = getFreeSpace(destination)
renaming_size = getSize(rename_files.keys())
if renaming_size > available_space:
log.error('Not enough space left, need %s MB but only %s MB available', (renaming_size, available_space))
self.tagRelease(group = group, tag = 'not_enough_space')
continue
# Remove files
delete_folders = []
for src in remove_files:
@@ -552,9 +570,9 @@ class Renamer(Plugin):
os.remove(src)
parent_dir = os.path.dirname(src)
if delete_folders.count(parent_dir) == 0 and os.path.isdir(parent_dir) and \
if parent_dir not in delete_folders and os.path.isdir(parent_dir) and \
not isSubFolder(destination, parent_dir) and not isSubFolder(media_folder, parent_dir) and \
not isSubFolder(parent_dir, base_folder):
isSubFolder(parent_dir, base_folder):
delete_folders.append(parent_dir)
@@ -563,6 +581,7 @@ class Renamer(Plugin):
self.tagRelease(group = group, tag = 'failed_remove')
# Delete leftover folder from older releases
delete_folders = sorted(delete_folders, key = len, reverse = True)
for delete_folder in delete_folders:
try:
self.deleteEmptyFolder(delete_folder, show_error = False)
@@ -575,7 +594,10 @@ class Renamer(Plugin):
for src in rename_files:
if rename_files[src]:
dst = rename_files[src]
log.info('Renaming "%s" to "%s"', (src, dst))
if dst in group['renamed_files']:
log.error('File "%s" already renamed once, adding random string at the end to prevent data loss', dst)
dst = '%s.random-%s' % (dst, randomString())
# Create dir
self.makeDir(os.path.dirname(dst))
@@ -617,8 +639,9 @@ class Renamer(Plugin):
group_folder = sp(os.path.join(base_folder, os.path.relpath(group['parentdir'], base_folder).split(os.path.sep)[0]))
try:
log.info('Deleting folder: %s', group_folder)
self.deleteEmptyFolder(group_folder)
if self.conf('cleanup') or self.conf('move_leftover'):
log.info('Deleting folder: %s', group_folder)
self.deleteEmptyFolder(group_folder)
except:
log.error('Failed removing %s: %s', (group_folder, traceback.format_exc()))
@@ -774,22 +797,32 @@ Remove it if you want it to be renamed (again, or at least let it try again)
dest = sp(dest)
try:
if os.path.exists(dest):
raise Exception('Destination "%s" already exists' % dest)
move_type = self.conf('file_action')
if use_default:
move_type = self.conf('default_file_action')
if move_type not in ['copy', 'link']:
try:
log.info('Moving "%s" to "%s"', (old, dest))
shutil.move(old, dest)
except:
if os.path.exists(dest):
exists = os.path.exists(dest)
if exists and os.path.getsize(old) == os.path.getsize(dest):
log.error('Successfully moved file "%s", but something went wrong: %s', (dest, traceback.format_exc()))
os.unlink(old)
else:
# remove faultly copied file
if exists:
os.unlink(dest)
raise
elif move_type == 'copy':
log.info('Copying "%s" to "%s"', (old, dest))
shutil.copy(old, dest)
else:
log.info('Linking "%s" to "%s"', (old, dest))
# First try to hardlink
try:
log.debug('Hardlinking file "%s" to "%s"...', (old, dest))
@@ -799,9 +832,10 @@ Remove it if you want it to be renamed (again, or at least let it try again)
log.debug('Couldn\'t hardlink file "%s" to "%s". Symlinking instead. Error: %s.', (old, dest, traceback.format_exc()))
shutil.copy(old, dest)
try:
symlink(dest, old + '.link')
old_link = '%s.link' % sp(old)
symlink(dest, old_link)
os.unlink(old)
os.rename(old + '.link', old)
os.rename(old_link, old)
except:
log.error('Couldn\'t symlink file "%s" to "%s". Copied instead. Error: %s. ', (old, dest, traceback.format_exc()))
@@ -1192,7 +1226,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
except Exception as e:
log.error('Failed moving left over file %s to %s: %s %s', (leftoverfile, move_to, e, traceback.format_exc()))
# As we probably tried to overwrite the nfo file, check if it exists and then remove the original
if os.path.isfile(move_to):
if os.path.isfile(move_to) and os.path.getsize(leftoverfile) == os.path.getsize(move_to):
if cleanup:
log.info('Deleting left over file %s instead...', leftoverfile)
os.unlink(leftoverfile)
+17 -8
View File
@@ -9,6 +9,7 @@ import traceback
import warnings
import re
import tarfile
import shutil
from CodernityDB.database_super_thread_safe import SuperThreadSafeDatabase
from argparse import ArgumentParser
@@ -108,14 +109,19 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
if not os.path.isdir(backup_path): os.makedirs(backup_path)
for root, dirs, files in os.walk(backup_path):
for backup_file in sorted(files):
ints = re.findall('\d+', backup_file)
# Only consider files being a direct child of the backup_path
if root == backup_path:
for backup_file in sorted(files):
ints = re.findall('\d+', backup_file)
# Delete non zip files
if len(ints) != 1:
os.remove(os.path.join(backup_path, backup_file))
else:
existing_backups.append((int(ints[0]), backup_file))
# Delete non zip files
if len(ints) != 1:
os.remove(os.path.join(root, backup_file))
else:
existing_backups.append((int(ints[0]), backup_file))
else:
# Delete stray directories.
shutil.rmtree(root)
# Remove all but the last 5
for eb in existing_backups[:-backup_count]:
@@ -145,12 +151,15 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
if not os.path.exists(python_cache):
os.mkdir(python_cache)
session = requests.Session()
session.max_redirects = 5
# Register environment settings
Env.set('app_dir', sp(base_path))
Env.set('data_dir', sp(data_dir))
Env.set('log_path', sp(os.path.join(log_dir, 'CouchPotato.log')))
Env.set('db', db)
Env.set('http_opener', requests.Session())
Env.set('http_opener', session)
Env.set('cache_dir', cache_dir)
Env.set('cache', FileSystemCache(python_cache))
Env.set('console_log', options.console_log)
+101 -21
View File
@@ -634,6 +634,7 @@ Option.Directory = new Class({
browser: null,
save_on_change: false,
use_cache: false,
current_dir: '',
create: function(){
var self = this;
@@ -645,8 +646,17 @@ Option.Directory = new Class({
'click': self.showBrowser.bind(self)
}
}).adopt(
self.input = new Element('span', {
'text': self.getSettingValue()
self.input = new Element('input', {
'value': self.getSettingValue(),
'events': {
'change': self.filterDirectory.bind(self),
'keydown': function(e){
if(e.key == 'enter' || e.key == 'tab')
(e).stop();
},
'keyup': self.filterDirectory.bind(self),
'paste': self.filterDirectory.bind(self)
}
})
)
);
@@ -654,10 +664,55 @@ Option.Directory = new Class({
self.cached = {};
},
filterDirectory: function(e){
var self = this,
value = self.getValue(),
path_sep = Api.getOption('path_sep'),
active_selector = 'li:not(.blur):not(.empty)';
if(e.key == 'enter' || e.key == 'tab'){
(e).stop();
var first = self.dir_list.getElement(active_selector);
if(first){
self.selectDirectory(first.get('data-value'));
}
}
else {
// New folder
if(value.substr(-1) == path_sep){
if(self.current_dir != value)
self.selectDirectory(value)
}
else {
var pd = self.getParentDir(value);
if(self.current_dir != pd)
self.getDirs(pd);
var folder_filter = value.split(path_sep).getLast()
self.dir_list.getElements('li').each(function(li){
var valid = li.get('text').substr(0, folder_filter.length).toLowerCase() != folder_filter.toLowerCase()
li[valid ? 'addClass' : 'removeClass']('blur')
});
var first = self.dir_list.getElement(active_selector);
if(first){
if(!self.dir_list_scroll)
self.dir_list_scroll = new Fx.Scroll(self.dir_list, {
'transition': 'quint:in:out'
});
self.dir_list_scroll.toElement(first);
}
}
}
},
selectDirectory: function(dir){
var self = this;
self.input.set('text', dir);
self.input.set('value', dir);
self.getDirs()
},
@@ -668,9 +723,28 @@ Option.Directory = new Class({
self.selectDirectory(self.getParentDir())
},
caretAtEnd: function(){
var self = this;
self.input.focus();
if (typeof self.input.selectionStart == "number") {
self.input.selectionStart = self.input.selectionEnd = self.input.get('value').length;
} else if (typeof el.createTextRange != "undefined") {
self.input.focus();
var range = self.input.createTextRange();
range.collapse(false);
range.select();
}
},
showBrowser: function(){
var self = this;
// Move caret to back of the input
if(!self.browser || self.browser && !self.browser.isVisible())
self.caretAtEnd()
if(!self.browser){
self.browser = new Element('div.directory_list').adopt(
new Element('div.pointer'),
@@ -686,7 +760,9 @@ Option.Directory = new Class({
}).adopt(
self.show_hidden = new Element('input[type=checkbox].inlay', {
'events': {
'change': self.getDirs.bind(self)
'change': function(){
self.getDirs()
}
}
})
)
@@ -707,7 +783,7 @@ Option.Directory = new Class({
'text': 'Clear',
'events': {
'click': function(e){
self.input.set('text', '');
self.input.set('value', '');
self.hideBrowser(e, true);
}
}
@@ -735,7 +811,7 @@ Option.Directory = new Class({
new Form.Check(self.show_hidden);
}
self.initial_directory = self.input.get('text');
self.initial_directory = self.input.get('value');
self.getDirs();
self.browser.show();
@@ -749,7 +825,7 @@ Option.Directory = new Class({
if(save)
self.save();
else
self.input.set('text', self.initial_directory);
self.input.set('value', self.initial_directory);
self.browser.hide();
self.el.removeEvents('outerClick')
@@ -757,21 +833,21 @@ Option.Directory = new Class({
},
fillBrowser: function(json){
var self = this;
var self = this,
v = self.getValue();
self.data = json;
var v = self.getValue();
var previous_dir = self.getParentDir();
var previous_dir = json.parent;
if(v == '')
self.input.set('text', json.home);
self.input.set('value', json.home);
if(previous_dir != v && previous_dir.length >= 1 && !json.is_root){
if(previous_dir.length >= 1 && !json.is_root){
var prev_dirname = self.getCurrentDirname(previous_dir);
if(previous_dir == json.home)
prev_dirname = 'Home';
prev_dirname = 'Home Folder';
else if(previous_dir == '/' && json.platform == 'nt')
prev_dirname = 'Computer';
@@ -801,12 +877,13 @@ Option.Directory = new Class({
new Element('li.empty', {
'text': 'Selected folder is empty'
}).inject(self.dir_list)
self.caretAtEnd();
},
getDirs: function(){
var self = this;
var c = self.getValue();
getDirs: function(dir){
var self = this,
c = dir || self.getValue();
if(self.cached[c] && self.use_cache){
self.fillBrowser()
@@ -817,7 +894,10 @@ Option.Directory = new Class({
'path': c,
'show_hidden': +self.show_hidden.checked
},
'onComplete': self.fillBrowser.bind(self)
'onComplete': function(json){
self.current_dir = c;
self.fillBrowser(json);
}
})
}
},
@@ -831,8 +911,8 @@ Option.Directory = new Class({
var v = dir || self.getValue();
var sep = Api.getOption('path_sep');
var dirs = v.split(sep);
if(dirs.pop() == '')
dirs.pop();
if(dirs.pop() == '')
dirs.pop();
return dirs.join(sep) + sep
},
@@ -845,7 +925,7 @@ Option.Directory = new Class({
getValue: function(){
var self = this;
return self.input.get('text');
return self.input.get('value');
}
});
+11 -2
View File
@@ -302,15 +302,19 @@
font-family: 'Elusive-Icons';
color: #f5e39c;
}
.page form .directory > span {
.page form .directory > input {
height: 25px;
display: inline-block;
float: right;
text-align: right;
white-space: nowrap;
cursor: pointer;
background: none;
border: 0;
color: #FFF;
width: 100%;
}
.page form .directory span:empty:before {
.page form .directory input:empty:before {
content: 'No folder selected';
font-style: italic;
opacity: .3;
@@ -353,6 +357,11 @@
white-space: nowrap;
text-overflow: ellipsis;
}
.page .directory_list li.blur {
opacity: .3;
}
.page .directory_list li:last-child {
border-bottom: 1px solid rgba(255,255,255,0.1);
}
+4
View File
@@ -532,7 +532,11 @@ class Session(SessionRedirectMixin):
if not isinstance(request, PreparedRequest):
raise ValueError('You can only send PreparedRequests.')
redirect_count = 0
while request.url in self.redirect_cache:
redirect_count += 1
if redirect_count > self.max_redirects:
raise TooManyRedirects
request.url = self.redirect_cache.get(request.url)
# Set up variables needed for resolve_redirects and dispatching of hooks