[Lint] Convert all python double quotes to single quotes
* A rather disruptive change but for a few reasons such as easier to read,
easier type, keep consistent and javascript code uses single quotes.
* There are a few exceptions for the automated process:
* Any double quotes in comments
* Triple double quotes for docstrings
* Strings containing single quotes are left e.g. "they're"
* To deal with merge conflicts from feature branches it is best to follow
these steps for each commit:
* Create a patch: `git format-patch -1 <sha1>`
* Edit the patch and replace double quotes with single except those in
comments or strings containing an unescaped apostrophe.
* Check the patch `git apply --check <patchfile>` and fix any remaining
issues if it outputs an error.
* Apply the patch `git am < <patchfile>`
This commit is contained in:
parent
d4a8a38586
commit
3a2ff0c188
@ -23,7 +23,7 @@ try:
|
||||
except ImportError:
|
||||
import libtorrent as lt
|
||||
|
||||
REQUIRED_VERSION = "1.0.7.0"
|
||||
REQUIRED_VERSION = '1.0.7.0'
|
||||
|
||||
if VersionSplit(lt.__version__) < VersionSplit(REQUIRED_VERSION):
|
||||
raise ImportError("Deluge %s requires libtorrent >= %s" % (get_version(), REQUIRED_VERSION))
|
||||
raise ImportError('Deluge %s requires libtorrent >= %s' % (get_version(), REQUIRED_VERSION))
|
||||
|
||||
@ -75,7 +75,7 @@ def bdecode(x):
|
||||
try:
|
||||
r, l = decode_func[x[0]](x, 0)
|
||||
except (IndexError, KeyError, ValueError):
|
||||
raise BTFailure("not a valid bencoded string")
|
||||
raise BTFailure('not a valid bencoded string')
|
||||
|
||||
return r
|
||||
|
||||
|
||||
222
deluge/common.py
222
deluge/common.py
@ -32,7 +32,7 @@ from deluge.error import InvalidPathError
|
||||
try:
|
||||
import dbus
|
||||
bus = dbus.SessionBus()
|
||||
dbus_fileman = bus.get_object("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1")
|
||||
dbus_fileman = bus.get_object('org.freedesktop.FileManager1', '/org/freedesktop/FileManager1')
|
||||
except Exception:
|
||||
dbus_fileman = None
|
||||
|
||||
@ -40,29 +40,29 @@ except Exception:
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
TORRENT_STATE = [
|
||||
"Allocating",
|
||||
"Checking",
|
||||
"Downloading",
|
||||
"Seeding",
|
||||
"Paused",
|
||||
"Error",
|
||||
"Queued",
|
||||
"Moving"
|
||||
'Allocating',
|
||||
'Checking',
|
||||
'Downloading',
|
||||
'Seeding',
|
||||
'Paused',
|
||||
'Error',
|
||||
'Queued',
|
||||
'Moving'
|
||||
]
|
||||
|
||||
FILE_PRIORITY = {
|
||||
0: "Do Not Download",
|
||||
1: "Normal Priority",
|
||||
2: "High Priority",
|
||||
3: "High Priority",
|
||||
4: "High Priority",
|
||||
5: "High Priority",
|
||||
6: "High Priority",
|
||||
7: "Highest Priority",
|
||||
"Do Not Download": 0,
|
||||
"Normal Priority": 1,
|
||||
"High Priority": 5,
|
||||
"Highest Priority": 7
|
||||
0: 'Do Not Download',
|
||||
1: 'Normal Priority',
|
||||
2: 'High Priority',
|
||||
3: 'High Priority',
|
||||
4: 'High Priority',
|
||||
5: 'High Priority',
|
||||
6: 'High Priority',
|
||||
7: 'Highest Priority',
|
||||
'Do Not Download': 0,
|
||||
'Normal Priority': 1,
|
||||
'High Priority': 5,
|
||||
'Highest Priority': 7
|
||||
}
|
||||
|
||||
|
||||
@ -74,7 +74,7 @@ def get_version():
|
||||
:rtype: string
|
||||
|
||||
"""
|
||||
return pkg_resources.require("Deluge")[0].version
|
||||
return pkg_resources.require('Deluge')[0].version
|
||||
|
||||
|
||||
def get_default_config_dir(filename=None):
|
||||
@ -89,12 +89,12 @@ def get_default_config_dir(filename=None):
|
||||
|
||||
if windows_check():
|
||||
def save_config_path(resource):
|
||||
app_data_path = os.environ.get("APPDATA")
|
||||
app_data_path = os.environ.get('APPDATA')
|
||||
if not app_data_path:
|
||||
import _winreg
|
||||
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
|
||||
app_data_reg = _winreg.QueryValueEx(hkey, "AppData")
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders')
|
||||
app_data_reg = _winreg.QueryValueEx(hkey, 'AppData')
|
||||
app_data_path = app_data_reg[0]
|
||||
_winreg.CloseKey(hkey)
|
||||
return os.path.join(app_data_path, resource)
|
||||
@ -103,9 +103,9 @@ def get_default_config_dir(filename=None):
|
||||
if not filename:
|
||||
filename = ''
|
||||
try:
|
||||
return os.path.join(save_config_path("deluge"), filename)
|
||||
return os.path.join(save_config_path('deluge'), filename)
|
||||
except OSError as ex:
|
||||
log.error("Unable to use default config directory, exiting... (%s)", ex)
|
||||
log.error('Unable to use default config directory, exiting... (%s)', ex)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -115,20 +115,20 @@ def get_default_download_dir():
|
||||
:rtype: string
|
||||
|
||||
"""
|
||||
download_dir = ""
|
||||
download_dir = ''
|
||||
if not windows_check():
|
||||
from xdg.BaseDirectory import xdg_config_home
|
||||
try:
|
||||
with open(os.path.join(xdg_config_home, 'user-dirs.dirs'), 'r') as _file:
|
||||
for line in _file:
|
||||
if not line.startswith('#') and line.startswith('XDG_DOWNLOAD_DIR'):
|
||||
download_dir = os.path.expandvars(line.partition("=")[2].rstrip().strip('"'))
|
||||
download_dir = os.path.expandvars(line.partition('=')[2].rstrip().strip('"'))
|
||||
break
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
if not download_dir:
|
||||
download_dir = os.path.join(os.path.expanduser("~"), 'Downloads')
|
||||
download_dir = os.path.join(os.path.expanduser('~'), 'Downloads')
|
||||
return download_dir
|
||||
|
||||
|
||||
@ -151,7 +151,7 @@ def vista_check():
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
return platform.release() == "Vista"
|
||||
return platform.release() == 'Vista'
|
||||
|
||||
|
||||
def osx_check():
|
||||
@ -162,7 +162,7 @@ def osx_check():
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
return platform.system() == "Darwin"
|
||||
return platform.system() == 'Darwin'
|
||||
|
||||
|
||||
def linux_check():
|
||||
@ -173,7 +173,7 @@ def linux_check():
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
return platform.system() == "Linux"
|
||||
return platform.system() == 'Linux'
|
||||
|
||||
|
||||
def get_os_version():
|
||||
@ -197,7 +197,7 @@ def get_pixmap(fname):
|
||||
:rtype: string
|
||||
|
||||
"""
|
||||
return resource_filename("deluge", os.path.join("ui", "data", "pixmaps", fname))
|
||||
return resource_filename('deluge', os.path.join('ui', 'data', 'pixmaps', fname))
|
||||
|
||||
|
||||
def resource_filename(module, path):
|
||||
@ -207,8 +207,8 @@ def resource_filename(module, path):
|
||||
# not, it returns the first found on the python path, which is not good
|
||||
# enough.
|
||||
# This is a work-around that.
|
||||
return pkg_resources.require("Deluge>=%s" % get_version())[0].get_resource_filename(
|
||||
pkg_resources._manager, os.path.join(*(module.split(".") + [path]))
|
||||
return pkg_resources.require('Deluge>=%s' % get_version())[0].get_resource_filename(
|
||||
pkg_resources._manager, os.path.join(*(module.split('.') + [path]))
|
||||
)
|
||||
|
||||
|
||||
@ -223,14 +223,14 @@ def open_file(path, timestamp=None):
|
||||
if windows_check():
|
||||
os.startfile(path)
|
||||
elif osx_check():
|
||||
subprocess.Popen(["open", path])
|
||||
subprocess.Popen(['open', path])
|
||||
else:
|
||||
if timestamp is None:
|
||||
timestamp = int(time.time())
|
||||
env = os.environ.copy()
|
||||
env["DESKTOP_STARTUP_ID"] = "%s-%u-%s-xdg_open_TIME%d" % \
|
||||
env['DESKTOP_STARTUP_ID'] = '%s-%u-%s-xdg_open_TIME%d' % \
|
||||
(os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
|
||||
subprocess.Popen(["xdg-open", "%s" % path], env=env)
|
||||
subprocess.Popen(['xdg-open', '%s' % path], env=env)
|
||||
|
||||
|
||||
def show_file(path, timestamp=None):
|
||||
@ -242,21 +242,21 @@ def show_file(path, timestamp=None):
|
||||
|
||||
"""
|
||||
if windows_check():
|
||||
subprocess.Popen(["explorer", "/select,", path])
|
||||
subprocess.Popen(['explorer', '/select,', path])
|
||||
elif osx_check():
|
||||
subprocess.Popen(["open", "-R", path])
|
||||
subprocess.Popen(['open', '-R', path])
|
||||
else:
|
||||
if timestamp is None:
|
||||
timestamp = int(time.time())
|
||||
startup_id = "%s_%u_%s-dbus_TIME%d" % (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
|
||||
startup_id = '%s_%u_%s-dbus_TIME%d' % (os.path.basename(sys.argv[0]), os.getpid(), os.uname()[1], timestamp)
|
||||
if dbus_fileman:
|
||||
paths = [urlparse.urljoin("file:", urllib.pathname2url(utf8_encoded(path)))]
|
||||
dbus_fileman.ShowItems(paths, startup_id, dbus_interface="org.freedesktop.FileManager1")
|
||||
paths = [urlparse.urljoin('file:', urllib.pathname2url(utf8_encoded(path)))]
|
||||
dbus_fileman.ShowItems(paths, startup_id, dbus_interface='org.freedesktop.FileManager1')
|
||||
else:
|
||||
env = os.environ.copy()
|
||||
env["DESKTOP_STARTUP_ID"] = startup_id.replace("dbus", "xdg-open")
|
||||
env['DESKTOP_STARTUP_ID'] = startup_id.replace('dbus', 'xdg-open')
|
||||
# No option in xdg to highlight a file so just open parent folder.
|
||||
subprocess.Popen(["xdg-open", os.path.dirname(path.rstrip("/"))], env=env)
|
||||
subprocess.Popen(['xdg-open', os.path.dirname(path.rstrip('/'))], env=env)
|
||||
|
||||
|
||||
def open_url_in_browser(url):
|
||||
@ -272,15 +272,15 @@ def open_url_in_browser(url):
|
||||
|
||||
# Formatting text functions
|
||||
|
||||
byte_txt = "B"
|
||||
kib_txt = "KiB"
|
||||
mib_txt = "MiB"
|
||||
gib_txt = "GiB"
|
||||
tib_txt = "TiB"
|
||||
kib_txt_short = "K"
|
||||
mib_txt_short = "M"
|
||||
gib_txt_short = "G"
|
||||
tib_txt_short = "T"
|
||||
byte_txt = 'B'
|
||||
kib_txt = 'KiB'
|
||||
mib_txt = 'MiB'
|
||||
gib_txt = 'GiB'
|
||||
tib_txt = 'TiB'
|
||||
kib_txt_short = 'K'
|
||||
mib_txt_short = 'M'
|
||||
gib_txt_short = 'G'
|
||||
tib_txt_short = 'T'
|
||||
|
||||
|
||||
def translate_size_units():
|
||||
@ -289,15 +289,15 @@ def translate_size_units():
|
||||
global byte_txt, kib_txt, mib_txt, gib_txt, tib_txt
|
||||
global kib_txt_short, mib_txt_short, gib_txt_short, tib_txt_short
|
||||
|
||||
byte_txt = _("B")
|
||||
kib_txt = _("KiB")
|
||||
mib_txt = _("MiB")
|
||||
gib_txt = _("GiB")
|
||||
tib_txt = _("TiB")
|
||||
kib_txt_short = _("K")
|
||||
mib_txt_short = _("M")
|
||||
gib_txt_short = _("G")
|
||||
tib_txt_short = _("T")
|
||||
byte_txt = _('B')
|
||||
kib_txt = _('KiB')
|
||||
mib_txt = _('MiB')
|
||||
gib_txt = _('GiB')
|
||||
tib_txt = _('TiB')
|
||||
kib_txt_short = _('K')
|
||||
mib_txt_short = _('M')
|
||||
gib_txt_short = _('G')
|
||||
tib_txt_short = _('T')
|
||||
|
||||
|
||||
def fsize(fsize_b, precision=1, shortform=False):
|
||||
@ -324,15 +324,15 @@ def fsize(fsize_b, precision=1, shortform=False):
|
||||
"""
|
||||
|
||||
if fsize_b >= 1024 ** 4:
|
||||
return "%.*f %s" % (precision, fsize_b / 1024 ** 4, tib_txt_short if shortform else tib_txt)
|
||||
return '%.*f %s' % (precision, fsize_b / 1024 ** 4, tib_txt_short if shortform else tib_txt)
|
||||
elif fsize_b >= 1024 ** 3:
|
||||
return "%.*f %s" % (precision, fsize_b / 1024 ** 3, gib_txt_short if shortform else gib_txt)
|
||||
return '%.*f %s' % (precision, fsize_b / 1024 ** 3, gib_txt_short if shortform else gib_txt)
|
||||
elif fsize_b >= 1024 ** 2:
|
||||
return "%.*f %s" % (precision, fsize_b / 1024 ** 2, mib_txt_short if shortform else mib_txt)
|
||||
return '%.*f %s' % (precision, fsize_b / 1024 ** 2, mib_txt_short if shortform else mib_txt)
|
||||
elif fsize_b >= 1024:
|
||||
return "%.*f %s" % (precision, fsize_b / 1024, kib_txt_short if shortform else kib_txt)
|
||||
return '%.*f %s' % (precision, fsize_b / 1024, kib_txt_short if shortform else kib_txt)
|
||||
else:
|
||||
return "%d %s" % (fsize_b, byte_txt)
|
||||
return '%d %s' % (fsize_b, byte_txt)
|
||||
|
||||
|
||||
def fpcnt(dec, precision=2):
|
||||
@ -375,13 +375,13 @@ def fspeed(bps, precision=1, shortform=False):
|
||||
"""
|
||||
|
||||
if bps < 1024 ** 2:
|
||||
return "%.*f %s" % (precision, bps / 1024, _("K/s") if shortform else _("KiB/s"))
|
||||
return '%.*f %s' % (precision, bps / 1024, _('K/s') if shortform else _('KiB/s'))
|
||||
elif bps < 1024 ** 3:
|
||||
return "%.*f %s" % (precision, bps / 1024 ** 2, _("M/s") if shortform else _("MiB/s"))
|
||||
return '%.*f %s' % (precision, bps / 1024 ** 2, _('M/s') if shortform else _('MiB/s'))
|
||||
elif bps < 1024 ** 4:
|
||||
return "%.*f %s" % (precision, bps / 1024 ** 3, _("G/s") if shortform else _("GiB/s"))
|
||||
return '%.*f %s' % (precision, bps / 1024 ** 3, _('G/s') if shortform else _('GiB/s'))
|
||||
else:
|
||||
return "%.*f %s" % (precision, bps / 1024 ** 4, _("T/s") if shortform else _("TiB/s"))
|
||||
return '%.*f %s' % (precision, bps / 1024 ** 4, _('T/s') if shortform else _('TiB/s'))
|
||||
|
||||
|
||||
def fpeer(num_peers, total_peers):
|
||||
@ -402,9 +402,9 @@ def fpeer(num_peers, total_peers):
|
||||
|
||||
"""
|
||||
if total_peers > -1:
|
||||
return "{:d} ({:d})".format(num_peers, total_peers)
|
||||
return '{:d} ({:d})'.format(num_peers, total_peers)
|
||||
else:
|
||||
return "{:d}".format(num_peers)
|
||||
return '{:d}'.format(num_peers)
|
||||
|
||||
|
||||
def ftime(secs):
|
||||
@ -456,8 +456,8 @@ def fdate(seconds, date_only=False, precision_secs=False):
|
||||
"""
|
||||
|
||||
if seconds < 0:
|
||||
return ""
|
||||
time_format = "%x %X" if precision_secs else "%x %H:%M"
|
||||
return ''
|
||||
time_format = '%x %X' if precision_secs else '%x %H:%M'
|
||||
if date_only:
|
||||
time_format = time_format.split()[0]
|
||||
return time.strftime(time_format, time.localtime(seconds))
|
||||
@ -535,7 +535,7 @@ def parse_human_size(size):
|
||||
if normalized_unit.startswith(unit['prefix'].lower()):
|
||||
return int(tokens[0] * unit['divider'])
|
||||
# We failed to parse the size specification.
|
||||
msg = "Failed to parse size! (input %r was tokenized as %r)"
|
||||
msg = 'Failed to parse size! (input %r was tokenized as %r)'
|
||||
raise InvalidSize(msg % (size, tokens))
|
||||
|
||||
|
||||
@ -554,7 +554,7 @@ def is_url(url):
|
||||
True
|
||||
|
||||
"""
|
||||
return url.partition('://')[0] in ("http", "https", "ftp", "udp")
|
||||
return url.partition('://')[0] in ('http', 'https', 'ftp', 'udp')
|
||||
|
||||
|
||||
def is_infohash(infohash):
|
||||
@ -623,9 +623,9 @@ def get_magnet_info(uri):
|
||||
xt_hash = param[len(xt_param):]
|
||||
if len(xt_hash) == 32:
|
||||
try:
|
||||
info_hash = base64.b32decode(xt_hash.upper()).encode("hex")
|
||||
info_hash = base64.b32decode(xt_hash.upper()).encode('hex')
|
||||
except TypeError as ex:
|
||||
log.debug("Invalid base32 magnet hash: %s, %s", xt_hash, ex)
|
||||
log.debug('Invalid base32 magnet hash: %s, %s', xt_hash, ex)
|
||||
break
|
||||
elif is_infohash(xt_hash):
|
||||
info_hash = xt_hash.lower()
|
||||
@ -637,7 +637,7 @@ def get_magnet_info(uri):
|
||||
if info_hash:
|
||||
if not name:
|
||||
name = info_hash
|
||||
return {"name": name, "info_hash": info_hash, "files_tree": ''}
|
||||
return {'name': name, 'info_hash': info_hash, 'files_tree': ''}
|
||||
return False
|
||||
|
||||
|
||||
@ -657,12 +657,12 @@ def create_magnet_uri(infohash, name=None, trackers=None):
|
||||
|
||||
"""
|
||||
from base64 import b32encode
|
||||
uri = "magnet:?xt=urn:btih:" + b32encode(infohash.decode("hex"))
|
||||
uri = 'magnet:?xt=urn:btih:' + b32encode(infohash.decode('hex'))
|
||||
if name:
|
||||
uri = uri + "&dn=" + name
|
||||
uri = uri + '&dn=' + name
|
||||
if trackers:
|
||||
for t in trackers:
|
||||
uri = uri + "&tr=" + t
|
||||
uri = uri + '&tr=' + t
|
||||
|
||||
return uri
|
||||
|
||||
@ -704,13 +704,13 @@ def free_space(path):
|
||||
|
||||
"""
|
||||
if not path or not os.path.exists(path):
|
||||
raise InvalidPathError("%s is not a valid path" % path)
|
||||
raise InvalidPathError('%s is not a valid path' % path)
|
||||
|
||||
if windows_check():
|
||||
from win32file import GetDiskFreeSpaceEx
|
||||
return GetDiskFreeSpaceEx(path)[0]
|
||||
else:
|
||||
disk_data = os.statvfs(path.encode("utf8"))
|
||||
disk_data = os.statvfs(path.encode('utf8'))
|
||||
block_size = disk_data.f_frsize
|
||||
return disk_data.f_bavail * block_size
|
||||
|
||||
@ -745,7 +745,7 @@ def is_ip(ip):
|
||||
# now test ipv6
|
||||
try:
|
||||
if windows_check():
|
||||
log.warning("ipv6 check unavailable on windows")
|
||||
log.warning('ipv6 check unavailable on windows')
|
||||
return True
|
||||
else:
|
||||
if socket.inet_pton(socket.AF_INET6, ip):
|
||||
@ -754,7 +754,7 @@ def is_ip(ip):
|
||||
return False
|
||||
|
||||
|
||||
def decode_string(s, encoding="utf8"):
|
||||
def decode_string(s, encoding='utf8'):
|
||||
"""
|
||||
Decodes a string and return unicode. If it cannot decode using
|
||||
`:param:encoding` then it will try latin1, and if that fails,
|
||||
@ -774,12 +774,12 @@ def decode_string(s, encoding="utf8"):
|
||||
elif isinstance(s, unicode):
|
||||
return s
|
||||
|
||||
encodings = [lambda: ("utf8", 'strict'),
|
||||
lambda: ("iso-8859-1", 'strict'),
|
||||
lambda: (chardet.detect(s)["encoding"], 'strict'),
|
||||
encodings = [lambda: ('utf8', 'strict'),
|
||||
lambda: ('iso-8859-1', 'strict'),
|
||||
lambda: (chardet.detect(s)['encoding'], 'strict'),
|
||||
lambda: (encoding, 'ignore')]
|
||||
|
||||
if encoding is not "utf8":
|
||||
if encoding is not 'utf8':
|
||||
encodings.insert(0, lambda: (encoding, 'strict'))
|
||||
|
||||
for l in encodings:
|
||||
@ -790,7 +790,7 @@ def decode_string(s, encoding="utf8"):
|
||||
return u''
|
||||
|
||||
|
||||
def utf8_encoded(s, encoding="utf8"):
|
||||
def utf8_encoded(s, encoding='utf8'):
|
||||
"""
|
||||
Returns a utf8 encoded string of s
|
||||
|
||||
@ -803,9 +803,9 @@ def utf8_encoded(s, encoding="utf8"):
|
||||
|
||||
"""
|
||||
if isinstance(s, str):
|
||||
s = decode_string(s, encoding).encode("utf8")
|
||||
s = decode_string(s, encoding).encode('utf8')
|
||||
elif isinstance(s, unicode):
|
||||
s = s.encode("utf8")
|
||||
s = s.encode('utf8')
|
||||
return s
|
||||
|
||||
|
||||
@ -838,13 +838,13 @@ class VersionSplit(object):
|
||||
vs = [''.join(group[0:2]), ''.join(group[2:4]), group[4].lstrip('.')]
|
||||
else:
|
||||
ver = ver.lower()
|
||||
vs = ver.replace("_", "-").split("-")
|
||||
vs = ver.replace('_', '-').split('-')
|
||||
|
||||
self.version = [int(x) for x in vs[0].split(".") if x.isdigit()]
|
||||
self.version = [int(x) for x in vs[0].split('.') if x.isdigit()]
|
||||
self.suffix = None
|
||||
self.dev = False
|
||||
if len(vs) > 1:
|
||||
if vs[1].startswith(("rc", "a", "b", "c")):
|
||||
if vs[1].startswith(('rc', 'a', 'b', 'c')):
|
||||
self.suffix = vs[1]
|
||||
if vs[-1].startswith('dev'):
|
||||
self.dev = vs[-1]
|
||||
@ -889,10 +889,10 @@ def create_auth_file():
|
||||
import stat
|
||||
import deluge.configmanager
|
||||
|
||||
auth_file = deluge.configmanager.get_config_dir("auth")
|
||||
auth_file = deluge.configmanager.get_config_dir('auth')
|
||||
# Check for auth file and create if necessary
|
||||
if not os.path.exists(auth_file):
|
||||
with open(auth_file, "w") as _file:
|
||||
with open(auth_file, 'w') as _file:
|
||||
_file.flush()
|
||||
os.fsync(_file.fileno())
|
||||
# Change the permissions on the file so only this user can read/write it
|
||||
@ -904,13 +904,13 @@ def create_localclient_account(append=False):
|
||||
from hashlib import sha1 as sha
|
||||
import deluge.configmanager
|
||||
|
||||
auth_file = deluge.configmanager.get_config_dir("auth")
|
||||
auth_file = deluge.configmanager.get_config_dir('auth')
|
||||
if not os.path.exists(auth_file):
|
||||
create_auth_file()
|
||||
|
||||
with open(auth_file, "a" if append else "w") as _file:
|
||||
_file.write(":".join([
|
||||
"localclient",
|
||||
with open(auth_file, 'a' if append else 'w') as _file:
|
||||
_file.write(':'.join([
|
||||
'localclient',
|
||||
sha(str(random.random())).hexdigest(),
|
||||
str(AUTH_LEVEL_ADMIN)
|
||||
]) + '\n')
|
||||
@ -1008,11 +1008,11 @@ def unicode_argv():
|
||||
else:
|
||||
# On other platforms, we have to find the likely encoding of the args and decode
|
||||
# First check if sys.stdout or stdin have encoding set
|
||||
encoding = getattr(sys.stdout, "encoding") or getattr(sys.stdin, "encoding")
|
||||
encoding = getattr(sys.stdout, 'encoding') or getattr(sys.stdin, 'encoding')
|
||||
# If that fails, check what the locale is set to
|
||||
encoding = encoding or locale.getpreferredencoding()
|
||||
# As a last resort, just default to utf-8
|
||||
encoding = encoding or "utf-8"
|
||||
encoding = encoding or 'utf-8'
|
||||
|
||||
return [arg.decode(encoding) for arg in sys.argv]
|
||||
|
||||
@ -1028,16 +1028,16 @@ def run_profiled(func, *args, **kwargs):
|
||||
output_file (str, optional): Filename to save profile results. If None, print to stdout.
|
||||
Defaults to None.
|
||||
"""
|
||||
if kwargs.get("do_profile", True) is not False:
|
||||
if kwargs.get('do_profile', True) is not False:
|
||||
import cProfile
|
||||
profiler = cProfile.Profile()
|
||||
|
||||
def on_shutdown():
|
||||
output_file = kwargs.get("output_file", None)
|
||||
output_file = kwargs.get('output_file', None)
|
||||
if output_file:
|
||||
profiler.dump_stats(output_file)
|
||||
log.info("Profile stats saved to %s", output_file)
|
||||
print("Profile stats saved to %s" % output_file)
|
||||
log.info('Profile stats saved to %s', output_file)
|
||||
print('Profile stats saved to %s' % output_file)
|
||||
else:
|
||||
import pstats
|
||||
import StringIO
|
||||
|
||||
@ -31,7 +31,7 @@ class ComponentException(Exception):
|
||||
|
||||
def __str__(self):
|
||||
s = super(ComponentException, self).__str__()
|
||||
return "%s\n%s" % (s, "".join(self.tb))
|
||||
return '%s\n%s' % (s, ''.join(self.tb))
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, self.__class__):
|
||||
@ -101,7 +101,7 @@ class Component(object):
|
||||
self._component_name = name
|
||||
self._component_interval = interval
|
||||
self._component_depend = depend
|
||||
self._component_state = "Stopped"
|
||||
self._component_state = 'Stopped'
|
||||
self._component_timer = None
|
||||
self._component_starting_deferred = None
|
||||
self._component_stopping_deferred = None
|
||||
@ -112,34 +112,34 @@ class Component(object):
|
||||
_ComponentRegistry.deregister(self)
|
||||
|
||||
def _component_start_timer(self):
|
||||
if hasattr(self, "update"):
|
||||
if hasattr(self, 'update'):
|
||||
self._component_timer = LoopingCall(self.update)
|
||||
self._component_timer.start(self._component_interval)
|
||||
|
||||
def _component_start(self):
|
||||
def on_start(result):
|
||||
self._component_state = "Started"
|
||||
self._component_state = 'Started'
|
||||
self._component_starting_deferred = None
|
||||
self._component_start_timer()
|
||||
return True
|
||||
|
||||
def on_start_fail(result):
|
||||
self._component_state = "Stopped"
|
||||
self._component_state = 'Stopped'
|
||||
self._component_starting_deferred = None
|
||||
log.error(result)
|
||||
return fail(result)
|
||||
|
||||
if self._component_state == "Stopped":
|
||||
if hasattr(self, "start"):
|
||||
self._component_state = "Starting"
|
||||
if self._component_state == 'Stopped':
|
||||
if hasattr(self, 'start'):
|
||||
self._component_state = 'Starting'
|
||||
d = deferLater(reactor, 0, self.start)
|
||||
d.addCallbacks(on_start, on_start_fail)
|
||||
self._component_starting_deferred = d
|
||||
else:
|
||||
d = maybeDeferred(on_start, None)
|
||||
elif self._component_state == "Starting":
|
||||
elif self._component_state == 'Starting':
|
||||
return self._component_starting_deferred
|
||||
elif self._component_state == "Started":
|
||||
elif self._component_state == 'Started':
|
||||
d = succeed(True)
|
||||
else:
|
||||
d = fail(ComponentException("Trying to start a component ('%s') not in stopped state. Current state: '%s'" %
|
||||
@ -148,20 +148,20 @@ class Component(object):
|
||||
|
||||
def _component_stop(self):
|
||||
def on_stop(result):
|
||||
self._component_state = "Stopped"
|
||||
self._component_state = 'Stopped'
|
||||
if self._component_timer and self._component_timer.running:
|
||||
self._component_timer.stop()
|
||||
return True
|
||||
|
||||
def on_stop_fail(result):
|
||||
self._component_state = "Started"
|
||||
self._component_state = 'Started'
|
||||
self._component_stopping_deferred = None
|
||||
log.error(result)
|
||||
return result
|
||||
|
||||
if self._component_state != "Stopped" and self._component_state != "Stopping":
|
||||
if hasattr(self, "stop"):
|
||||
self._component_state = "Stopping"
|
||||
if self._component_state != 'Stopped' and self._component_state != 'Stopping':
|
||||
if hasattr(self, 'stop'):
|
||||
self._component_state = 'Stopping'
|
||||
d = maybeDeferred(self.stop)
|
||||
d.addCallback(on_stop)
|
||||
d.addErrback(on_stop_fail)
|
||||
@ -169,22 +169,22 @@ class Component(object):
|
||||
else:
|
||||
d = maybeDeferred(on_stop, None)
|
||||
|
||||
if self._component_state == "Stopping":
|
||||
if self._component_state == 'Stopping':
|
||||
return self._component_stopping_deferred
|
||||
|
||||
return succeed(None)
|
||||
|
||||
def _component_pause(self):
|
||||
def on_pause(result):
|
||||
self._component_state = "Paused"
|
||||
self._component_state = 'Paused'
|
||||
|
||||
if self._component_state == "Started":
|
||||
if self._component_state == 'Started':
|
||||
if self._component_timer and self._component_timer.running:
|
||||
d = maybeDeferred(self._component_timer.stop)
|
||||
d.addCallback(on_pause)
|
||||
else:
|
||||
d = succeed(None)
|
||||
elif self._component_state == "Paused":
|
||||
elif self._component_state == 'Paused':
|
||||
d = succeed(None)
|
||||
else:
|
||||
d = fail(ComponentException("Trying to pause a component ('%s') not in started state. Current state: '%s'" %
|
||||
@ -193,9 +193,9 @@ class Component(object):
|
||||
|
||||
def _component_resume(self):
|
||||
def on_resume(result):
|
||||
self._component_state = "Started"
|
||||
self._component_state = 'Started'
|
||||
|
||||
if self._component_state == "Paused":
|
||||
if self._component_state == 'Paused':
|
||||
d = maybeDeferred(self._component_start_timer)
|
||||
d.addCallback(on_resume)
|
||||
else:
|
||||
@ -205,7 +205,7 @@ class Component(object):
|
||||
|
||||
def _component_shutdown(self):
|
||||
def on_stop(result):
|
||||
if hasattr(self, "shutdown"):
|
||||
if hasattr(self, 'shutdown'):
|
||||
return maybeDeferred(self.shutdown)
|
||||
return succeed(None)
|
||||
|
||||
@ -254,7 +254,7 @@ class ComponentRegistry(object):
|
||||
"""
|
||||
name = obj._component_name
|
||||
if name in self.components:
|
||||
raise ComponentAlreadyRegistered("Component already registered with name %s" % name)
|
||||
raise ComponentAlreadyRegistered('Component already registered with name %s' % name)
|
||||
|
||||
self.components[obj._component_name] = obj
|
||||
if obj._component_depend:
|
||||
@ -273,7 +273,7 @@ class ComponentRegistry(object):
|
||||
|
||||
"""
|
||||
if obj in self.components.values():
|
||||
log.debug("Deregistering Component: %s", obj._component_name)
|
||||
log.debug('Deregistering Component: %s', obj._component_name)
|
||||
d = self.stop([obj._component_name])
|
||||
|
||||
def on_stop(result, name):
|
||||
@ -377,7 +377,7 @@ class ComponentRegistry(object):
|
||||
deferreds = []
|
||||
|
||||
for name in names:
|
||||
if self.components[name]._component_state == "Started":
|
||||
if self.components[name]._component_state == 'Started':
|
||||
deferreds.append(self.components[name]._component_pause())
|
||||
|
||||
return DeferredList(deferreds)
|
||||
@ -403,7 +403,7 @@ class ComponentRegistry(object):
|
||||
deferreds = []
|
||||
|
||||
for name in names:
|
||||
if self.components[name]._component_state == "Paused":
|
||||
if self.components[name]._component_state == 'Paused':
|
||||
deferreds.append(self.components[name]._component_resume())
|
||||
|
||||
return DeferredList(deferreds)
|
||||
|
||||
@ -82,16 +82,16 @@ def find_json_objects(s):
|
||||
"""
|
||||
objects = []
|
||||
opens = 0
|
||||
start = s.find("{")
|
||||
start = s.find('{')
|
||||
offset = start
|
||||
|
||||
if start < 0:
|
||||
return []
|
||||
|
||||
for index, c in enumerate(s[offset:]):
|
||||
if c == "{":
|
||||
if c == '{':
|
||||
opens += 1
|
||||
elif c == "}":
|
||||
elif c == '}':
|
||||
opens -= 1
|
||||
if opens == 0:
|
||||
objects.append((start, index + offset + 1))
|
||||
@ -119,8 +119,8 @@ class Config(object):
|
||||
|
||||
# These hold the version numbers and they will be set when loaded
|
||||
self.__version = {
|
||||
"format": 1,
|
||||
"file": file_version
|
||||
'format': 1,
|
||||
'file': file_version
|
||||
}
|
||||
|
||||
# This will get set with a reactor.callLater whenever a config option
|
||||
@ -186,7 +186,7 @@ class Config(object):
|
||||
try:
|
||||
oldtype = type(self.__config[key])
|
||||
if isinstance(self.__config[key], unicode):
|
||||
value = oldtype(value, "utf8")
|
||||
value = oldtype(value, 'utf8')
|
||||
else:
|
||||
value = oldtype(value)
|
||||
except ValueError:
|
||||
@ -244,7 +244,7 @@ class Config(object):
|
||||
"""
|
||||
if isinstance(self.__config[key], str):
|
||||
try:
|
||||
return self.__config[key].decode("utf8")
|
||||
return self.__config[key].decode('utf8')
|
||||
except UnicodeDecodeError:
|
||||
return self.__config[key]
|
||||
else:
|
||||
@ -342,7 +342,7 @@ class Config(object):
|
||||
test 5
|
||||
|
||||
"""
|
||||
log.debug("Registering function for %s key..", key)
|
||||
log.debug('Registering function for %s key..', key)
|
||||
if key not in self.__set_functions:
|
||||
self.__set_functions[key] = []
|
||||
|
||||
@ -367,7 +367,7 @@ class Config(object):
|
||||
test 5
|
||||
|
||||
"""
|
||||
log.debug("Calling all set functions..")
|
||||
log.debug('Calling all set functions..')
|
||||
for key, value in self.__set_functions.iteritems():
|
||||
for func in value:
|
||||
func(key, self.__config[key])
|
||||
@ -379,7 +379,7 @@ class Config(object):
|
||||
key (str): the config key
|
||||
|
||||
"""
|
||||
log.debug("Calling set functions for key %s..", key)
|
||||
log.debug('Calling set functions for key %s..', key)
|
||||
if key in self.__set_functions:
|
||||
for func in self.__set_functions[key]:
|
||||
func(key, self.__config[key])
|
||||
@ -395,10 +395,10 @@ class Config(object):
|
||||
filename = self.__config_file
|
||||
|
||||
try:
|
||||
with open(filename, "rb") as _file:
|
||||
with open(filename, 'rb') as _file:
|
||||
data = _file.read()
|
||||
except IOError as ex:
|
||||
log.warning("Unable to open config file %s: %s", filename, ex)
|
||||
log.warning('Unable to open config file %s: %s', filename, ex)
|
||||
return
|
||||
|
||||
objects = find_json_objects(data)
|
||||
@ -409,14 +409,14 @@ class Config(object):
|
||||
self.__config.update(pickle.loads(data))
|
||||
except Exception as ex:
|
||||
log.exception(ex)
|
||||
log.warning("Unable to load config file: %s", filename)
|
||||
log.warning('Unable to load config file: %s', filename)
|
||||
elif len(objects) == 1:
|
||||
start, end = objects[0]
|
||||
try:
|
||||
self.__config.update(json.loads(data[start:end]))
|
||||
except Exception as ex:
|
||||
log.exception(ex)
|
||||
log.warning("Unable to load config file: %s", filename)
|
||||
log.warning('Unable to load config file: %s', filename)
|
||||
elif len(objects) == 2:
|
||||
try:
|
||||
start, end = objects[0]
|
||||
@ -425,10 +425,10 @@ class Config(object):
|
||||
self.__config.update(json.loads(data[start:end]))
|
||||
except Exception as ex:
|
||||
log.exception(ex)
|
||||
log.warning("Unable to load config file: %s", filename)
|
||||
log.warning('Unable to load config file: %s', filename)
|
||||
|
||||
log.debug("Config %s version: %s.%s loaded: %s", filename,
|
||||
self.__version["format"], self.__version["file"], self.__config)
|
||||
log.debug('Config %s version: %s.%s loaded: %s', filename,
|
||||
self.__version['format'], self.__version['file'], self.__config)
|
||||
|
||||
def save(self, filename=None):
|
||||
"""Save configuration to disk
|
||||
@ -445,7 +445,7 @@ class Config(object):
|
||||
# Check to see if the current config differs from the one on disk
|
||||
# We will only write a new config file if there is a difference
|
||||
try:
|
||||
with open(filename, "rb") as _file:
|
||||
with open(filename, 'rb') as _file:
|
||||
data = _file.read()
|
||||
objects = find_json_objects(data)
|
||||
start, end = objects[0]
|
||||
@ -458,34 +458,34 @@ class Config(object):
|
||||
self._save_timer.cancel()
|
||||
return True
|
||||
except (IOError, IndexError) as ex:
|
||||
log.warning("Unable to open config file: %s because: %s", filename, ex)
|
||||
log.warning('Unable to open config file: %s because: %s', filename, ex)
|
||||
|
||||
# Save the new config and make sure it's written to disk
|
||||
try:
|
||||
log.debug("Saving new config file %s", filename + ".new")
|
||||
with open(filename + ".new", "wb") as _file:
|
||||
log.debug('Saving new config file %s', filename + '.new')
|
||||
with open(filename + '.new', 'wb') as _file:
|
||||
json.dump(self.__version, _file, indent=2)
|
||||
json.dump(self.__config, _file, indent=2, sort_keys=True)
|
||||
_file.flush()
|
||||
os.fsync(_file.fileno())
|
||||
except IOError as ex:
|
||||
log.error("Error writing new config file: %s", ex)
|
||||
log.error('Error writing new config file: %s', ex)
|
||||
return False
|
||||
|
||||
# Make a backup of the old config
|
||||
try:
|
||||
log.debug("Backing up old config file to %s.bak", filename)
|
||||
shutil.move(filename, filename + ".bak")
|
||||
log.debug('Backing up old config file to %s.bak', filename)
|
||||
shutil.move(filename, filename + '.bak')
|
||||
except IOError as ex:
|
||||
log.warning("Unable to backup old config: %s", ex)
|
||||
log.warning('Unable to backup old config: %s', ex)
|
||||
|
||||
# The new config file has been written successfully, so let's move it over
|
||||
# the existing one.
|
||||
try:
|
||||
log.debug("Moving new config file %s to %s..", filename + ".new", filename)
|
||||
shutil.move(filename + ".new", filename)
|
||||
log.debug('Moving new config file %s to %s..', filename + '.new', filename)
|
||||
shutil.move(filename + '.new', filename)
|
||||
except IOError as ex:
|
||||
log.error("Error moving new config file: %s", ex)
|
||||
log.error('Error moving new config file: %s', ex)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
@ -508,22 +508,22 @@ class Config(object):
|
||||
|
||||
"""
|
||||
if output_version in input_range or output_version <= max(input_range):
|
||||
raise ValueError("output_version needs to be greater than input_range")
|
||||
raise ValueError('output_version needs to be greater than input_range')
|
||||
|
||||
if self.__version["file"] not in input_range:
|
||||
log.debug("File version %s is not in input_range %s, ignoring converter function..",
|
||||
self.__version["file"], input_range)
|
||||
if self.__version['file'] not in input_range:
|
||||
log.debug('File version %s is not in input_range %s, ignoring converter function..',
|
||||
self.__version['file'], input_range)
|
||||
return
|
||||
|
||||
try:
|
||||
self.__config = func(self.__config)
|
||||
except Exception as ex:
|
||||
log.exception(ex)
|
||||
log.error("There was an exception try to convert config file %s %s to %s",
|
||||
self.__config_file, self.__version["file"], output_version)
|
||||
log.error('There was an exception try to convert config file %s %s to %s',
|
||||
self.__config_file, self.__version['file'], output_version)
|
||||
raise ex
|
||||
else:
|
||||
self.__version["file"] = output_version
|
||||
self.__version['file'] = output_version
|
||||
self.save()
|
||||
|
||||
@property
|
||||
|
||||
@ -19,7 +19,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class _ConfigManager(object):
|
||||
def __init__(self):
|
||||
log.debug("ConfigManager started..")
|
||||
log.debug('ConfigManager started..')
|
||||
self.config_files = {}
|
||||
self.__config_directory = None
|
||||
|
||||
@ -44,16 +44,16 @@ class _ConfigManager(object):
|
||||
if not directory:
|
||||
return False
|
||||
|
||||
log.info("Setting config directory to: %s", directory)
|
||||
log.info('Setting config directory to: %s', directory)
|
||||
if not os.path.exists(directory):
|
||||
# Try to create the config folder if it doesn't exist
|
||||
try:
|
||||
os.makedirs(directory)
|
||||
except OSError as ex:
|
||||
log.error("Unable to make config directory: %s", ex)
|
||||
log.error('Unable to make config directory: %s', ex)
|
||||
return False
|
||||
elif not os.path.isdir(directory):
|
||||
log.error("Config directory needs to be a directory!")
|
||||
log.error('Config directory needs to be a directory!')
|
||||
return False
|
||||
|
||||
self.__config_directory = directory
|
||||
|
||||
@ -30,9 +30,9 @@ log = logging.getLogger(__name__)
|
||||
class AlertManager(component.Component):
|
||||
"""AlertManager fetches and processes libtorrent alerts"""
|
||||
def __init__(self):
|
||||
log.debug("AlertManager init...")
|
||||
component.Component.__init__(self, "AlertManager", interval=0.3)
|
||||
self.session = component.get("Core").session
|
||||
log.debug('AlertManager init...')
|
||||
component.Component.__init__(self, 'AlertManager', interval=0.3)
|
||||
self.session = component.get('Core').session
|
||||
|
||||
# Increase the alert queue size so that alerts don't get lost.
|
||||
self.alert_queue_size = 10000
|
||||
@ -47,7 +47,7 @@ class AlertManager(component.Component):
|
||||
lt.alert.category_t.performance_warning)
|
||||
|
||||
try:
|
||||
self.session.apply_settings("alert_mask", alert_mask)
|
||||
self.session.apply_settings('alert_mask', alert_mask)
|
||||
except AttributeError:
|
||||
self.session.set_alert_mask(alert_mask)
|
||||
|
||||
@ -81,7 +81,7 @@ class AlertManager(component.Component):
|
||||
|
||||
# Append the handler to the list in the handlers dictionary
|
||||
self.handlers[alert_type].append(handler)
|
||||
log.debug("Registered handler for alert %s", alert_type)
|
||||
log.debug('Registered handler for alert %s', alert_type)
|
||||
|
||||
def deregister_handler(self, handler):
|
||||
"""
|
||||
@ -105,16 +105,16 @@ class AlertManager(component.Component):
|
||||
|
||||
num_alerts = len(alerts)
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Alerts queued: %s", num_alerts)
|
||||
log.debug('Alerts queued: %s', num_alerts)
|
||||
if num_alerts > 0.9 * self.alert_queue_size:
|
||||
log.warning("Warning total alerts queued, %s, passes 90%% of queue size.", num_alerts)
|
||||
log.warning('Warning total alerts queued, %s, passes 90%% of queue size.', num_alerts)
|
||||
|
||||
# Loop through all alerts in the queue
|
||||
for alert in alerts:
|
||||
alert_type = type(alert).__name__
|
||||
# Display the alert message
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("%s: %s", alert_type, decode_string(alert.message()))
|
||||
log.debug('%s: %s', alert_type, decode_string(alert.message()))
|
||||
# Call any handlers for this alert type
|
||||
if alert_type in self.handlers:
|
||||
for handler in self.handlers[alert_type]:
|
||||
@ -122,6 +122,6 @@ class AlertManager(component.Component):
|
||||
|
||||
def set_alert_queue_size(self, queue_size):
|
||||
"""Sets the maximum size of the libtorrent alert queue"""
|
||||
log.info("Alert Queue Size set to %s", queue_size)
|
||||
log.info('Alert Queue Size set to %s', queue_size)
|
||||
self.alert_queue_size = queue_size
|
||||
component.get("Core").apply_session_setting("alert_queue_size", self.alert_queue_size)
|
||||
component.get('Core').apply_session_setting('alert_queue_size', self.alert_queue_size)
|
||||
|
||||
@ -51,12 +51,12 @@ class Account(object):
|
||||
|
||||
def __repr__(self):
|
||||
return ('<Account username="%(username)s" authlevel=%(authlevel)s>' %
|
||||
{"username": self.username, "authlevel": self.authlevel})
|
||||
{'username': self.username, 'authlevel': self.authlevel})
|
||||
|
||||
|
||||
class AuthManager(component.Component):
|
||||
def __init__(self):
|
||||
component.Component.__init__(self, "AuthManager", interval=10)
|
||||
component.Component.__init__(self, 'AuthManager', interval=10)
|
||||
self.__auth = {}
|
||||
self.__auth_modification_time = None
|
||||
|
||||
@ -70,16 +70,16 @@ class AuthManager(component.Component):
|
||||
pass
|
||||
|
||||
def update(self):
|
||||
auth_file = configmanager.get_config_dir("auth")
|
||||
auth_file = configmanager.get_config_dir('auth')
|
||||
# Check for auth file and create if necessary
|
||||
if not os.path.isfile(auth_file):
|
||||
log.info("Authfile not found, recreating it.")
|
||||
log.info('Authfile not found, recreating it.')
|
||||
self.__load_auth_file()
|
||||
return
|
||||
|
||||
auth_file_modification_time = os.stat(auth_file).st_mtime
|
||||
if self.__auth_modification_time != auth_file_modification_time:
|
||||
log.info("Auth file changed, reloading it!")
|
||||
log.info('Auth file changed, reloading it!')
|
||||
self.__load_auth_file()
|
||||
|
||||
def authorize(self, username, password):
|
||||
@ -99,22 +99,22 @@ class AuthManager(component.Component):
|
||||
"""
|
||||
if not username:
|
||||
raise AuthenticationRequired(
|
||||
"Username and Password are required.", username
|
||||
'Username and Password are required.', username
|
||||
)
|
||||
|
||||
if username not in self.__auth:
|
||||
# Let's try to re-load the file.. Maybe it's been updated
|
||||
self.__load_auth_file()
|
||||
if username not in self.__auth:
|
||||
raise BadLoginError("Username does not exist", username)
|
||||
raise BadLoginError('Username does not exist', username)
|
||||
|
||||
if self.__auth[username].password == password:
|
||||
# Return the users auth level
|
||||
return self.__auth[username].authlevel
|
||||
elif not password and self.__auth[username].password:
|
||||
raise AuthenticationRequired("Password is required", username)
|
||||
raise AuthenticationRequired('Password is required', username)
|
||||
else:
|
||||
raise BadLoginError("Password does not match", username)
|
||||
raise BadLoginError('Password does not match', username)
|
||||
|
||||
def has_account(self, username):
|
||||
return username in self.__auth
|
||||
@ -126,7 +126,7 @@ class AuthManager(component.Component):
|
||||
|
||||
def create_account(self, username, password, authlevel):
|
||||
if username in self.__auth:
|
||||
raise AuthManagerError("Username in use.", username)
|
||||
raise AuthManagerError('Username in use.', username)
|
||||
if authlevel not in AUTH_LEVELS_MAPPING:
|
||||
raise AuthManagerError("Invalid auth level: '%s'" % authlevel)
|
||||
try:
|
||||
@ -140,7 +140,7 @@ class AuthManager(component.Component):
|
||||
|
||||
def update_account(self, username, password, authlevel):
|
||||
if username not in self.__auth:
|
||||
raise AuthManagerError("Username not known", username)
|
||||
raise AuthManagerError('Username not known', username)
|
||||
if authlevel not in AUTH_LEVELS_MAPPING:
|
||||
raise AuthManagerError("Invalid auth level: '%s'" % authlevel)
|
||||
try:
|
||||
@ -155,10 +155,10 @@ class AuthManager(component.Component):
|
||||
|
||||
def remove_account(self, username):
|
||||
if username not in self.__auth:
|
||||
raise AuthManagerError("Username not known", username)
|
||||
elif username == component.get("RPCServer").get_session_user():
|
||||
raise AuthManagerError('Username not known', username)
|
||||
elif username == component.get('RPCServer').get_session_user():
|
||||
raise AuthManagerError(
|
||||
"You cannot delete your own account while logged in!", username
|
||||
'You cannot delete your own account while logged in!', username
|
||||
)
|
||||
|
||||
del self.__auth[username]
|
||||
@ -166,39 +166,39 @@ class AuthManager(component.Component):
|
||||
return True
|
||||
|
||||
def write_auth_file(self):
|
||||
filename = "auth"
|
||||
filename = 'auth'
|
||||
filepath = os.path.join(configmanager.get_config_dir(), filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
filepath_tmp = filepath + ".tmp"
|
||||
filepath_bak = filepath + '.bak'
|
||||
filepath_tmp = filepath + '.tmp'
|
||||
|
||||
try:
|
||||
if os.path.isfile(filepath):
|
||||
log.debug("Creating backup of %s at: %s", filename, filepath_bak)
|
||||
log.debug('Creating backup of %s at: %s', filename, filepath_bak)
|
||||
shutil.copy2(filepath, filepath_bak)
|
||||
except IOError as ex:
|
||||
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
|
||||
log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
|
||||
else:
|
||||
log.info("Saving the %s at: %s", filename, filepath)
|
||||
log.info('Saving the %s at: %s', filename, filepath)
|
||||
try:
|
||||
with open(filepath_tmp, "wb") as _file:
|
||||
with open(filepath_tmp, 'wb') as _file:
|
||||
for account in self.__auth.values():
|
||||
_file.write("%(username)s:%(password)s:%(authlevel_int)s\n" % account.data())
|
||||
_file.write('%(username)s:%(password)s:%(authlevel_int)s\n' % account.data())
|
||||
_file.flush()
|
||||
os.fsync(_file.fileno())
|
||||
shutil.move(filepath_tmp, filepath)
|
||||
except IOError as ex:
|
||||
log.error("Unable to save %s: %s", filename, ex)
|
||||
log.error('Unable to save %s: %s', filename, ex)
|
||||
if os.path.isfile(filepath_bak):
|
||||
log.info("Restoring backup of %s from: %s", filename, filepath_bak)
|
||||
log.info('Restoring backup of %s from: %s', filename, filepath_bak)
|
||||
shutil.move(filepath_bak, filepath)
|
||||
|
||||
self.__load_auth_file()
|
||||
|
||||
def __load_auth_file(self):
|
||||
save_and_reload = False
|
||||
filename = "auth"
|
||||
filename = 'auth'
|
||||
auth_file = configmanager.get_config_dir(filename)
|
||||
auth_file_bak = auth_file + ".bak"
|
||||
auth_file_bak = auth_file + '.bak'
|
||||
|
||||
# Check for auth file and create if necessary
|
||||
if not os.path.isfile(auth_file):
|
||||
@ -213,28 +213,28 @@ class AuthManager(component.Component):
|
||||
return
|
||||
|
||||
for _filepath in (auth_file, auth_file_bak):
|
||||
log.info("Opening %s for load: %s", filename, _filepath)
|
||||
log.info('Opening %s for load: %s', filename, _filepath)
|
||||
try:
|
||||
with open(_filepath, "rb") as _file:
|
||||
with open(_filepath, 'rb') as _file:
|
||||
file_data = _file.readlines()
|
||||
except IOError as ex:
|
||||
log.warning("Unable to load %s: %s", _filepath, ex)
|
||||
log.warning('Unable to load %s: %s', _filepath, ex)
|
||||
file_data = []
|
||||
else:
|
||||
log.info("Successfully loaded %s: %s", filename, _filepath)
|
||||
log.info('Successfully loaded %s: %s', filename, _filepath)
|
||||
break
|
||||
|
||||
# Load the auth file into a dictionary: {username: Account(...)}
|
||||
for line in file_data:
|
||||
line = line.strip()
|
||||
if line.startswith("#") or not line:
|
||||
if line.startswith('#') or not line:
|
||||
# This line is a comment or empty
|
||||
continue
|
||||
lsplit = line.split(":")
|
||||
lsplit = line.split(':')
|
||||
if len(lsplit) == 2:
|
||||
username, password = lsplit
|
||||
log.warning("Your auth entry for %s contains no auth level, "
|
||||
"using AUTH_LEVEL_DEFAULT(%s)..", username, AUTH_LEVEL_DEFAULT)
|
||||
log.warning('Your auth entry for %s contains no auth level, '
|
||||
'using AUTH_LEVEL_DEFAULT(%s)..', username, AUTH_LEVEL_DEFAULT)
|
||||
if username == 'localclient':
|
||||
authlevel = AUTH_LEVEL_ADMIN
|
||||
else:
|
||||
@ -244,7 +244,7 @@ class AuthManager(component.Component):
|
||||
elif len(lsplit) == 3:
|
||||
username, password, authlevel = lsplit
|
||||
else:
|
||||
log.error("Your auth file is malformed: Incorrect number of fields!")
|
||||
log.error('Your auth file is malformed: Incorrect number of fields!')
|
||||
continue
|
||||
|
||||
username = username.strip()
|
||||
@ -255,16 +255,16 @@ class AuthManager(component.Component):
|
||||
try:
|
||||
authlevel = AUTH_LEVELS_MAPPING[authlevel]
|
||||
except KeyError:
|
||||
log.error("Your auth file is malformed: %r is not a valid auth level", authlevel)
|
||||
log.error('Your auth file is malformed: %r is not a valid auth level', authlevel)
|
||||
continue
|
||||
|
||||
self.__auth[username] = Account(username, password, authlevel)
|
||||
|
||||
if "localclient" not in self.__auth:
|
||||
if 'localclient' not in self.__auth:
|
||||
create_localclient_account(True)
|
||||
return self.__load_auth_file()
|
||||
|
||||
if save_and_reload:
|
||||
log.info("Re-writing auth file (upgrade)")
|
||||
log.info('Re-writing auth file (upgrade)')
|
||||
self.write_auth_file()
|
||||
self.__auth_modification_time = auth_file_modification_time
|
||||
|
||||
@ -44,22 +44,22 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class Core(component.Component):
|
||||
def __init__(self, listen_interface=None, read_only_config_keys=None):
|
||||
log.debug("Core init...")
|
||||
component.Component.__init__(self, "Core")
|
||||
log.debug('Core init...')
|
||||
component.Component.__init__(self, 'Core')
|
||||
|
||||
# These keys will be dropped from the set_config() RPC and are
|
||||
# configurable from the command-line.
|
||||
self.read_only_config_keys = read_only_config_keys
|
||||
log.debug("read_only_config_keys: %s", read_only_config_keys)
|
||||
log.debug('read_only_config_keys: %s', read_only_config_keys)
|
||||
|
||||
# Create the client fingerprint
|
||||
client_id = "DE"
|
||||
client_id = 'DE'
|
||||
client_version = deluge.common.VersionSplit(deluge.common.get_version()).version
|
||||
while len(client_version) < 4:
|
||||
client_version.append(0)
|
||||
|
||||
# Start the libtorrent session
|
||||
log.info("Starting libtorrent %s (%s, %s) session...", lt.__version__, client_id, client_version)
|
||||
log.info('Starting libtorrent %s (%s, %s) session...', lt.__version__, client_id, client_version)
|
||||
self.session = lt.session(lt.fingerprint(client_id, *client_version), flags=0)
|
||||
|
||||
# Load the session state if available
|
||||
@ -67,20 +67,20 @@ class Core(component.Component):
|
||||
|
||||
# Apply session settings
|
||||
self.apply_session_setting(
|
||||
"user_agent",
|
||||
"Deluge/%(deluge_version)s libtorrent/%(lt_version)s" % {
|
||||
'user_agent',
|
||||
'Deluge/%(deluge_version)s libtorrent/%(lt_version)s' % {
|
||||
'deluge_version': deluge.common.get_version(),
|
||||
'lt_version': self.get_libtorrent_version().rpartition(".")[0]}
|
||||
'lt_version': self.get_libtorrent_version().rpartition('.')[0]}
|
||||
)
|
||||
|
||||
# No SSL torrent support in code so disable the listen port.
|
||||
self.apply_session_setting("ssl_listen", 0)
|
||||
self.apply_session_setting('ssl_listen', 0)
|
||||
|
||||
# Enable libtorrent extensions
|
||||
# Allows peers to download the metadata from the swarm directly
|
||||
self.session.add_extension("ut_metadata")
|
||||
self.session.add_extension('ut_metadata')
|
||||
# Ban peers that sends bad data
|
||||
self.session.add_extension("smart_ban")
|
||||
self.session.add_extension('smart_ban')
|
||||
|
||||
# Create the components
|
||||
self.eventmanager = EventManager()
|
||||
@ -96,13 +96,13 @@ class Core(component.Component):
|
||||
|
||||
# External IP Address from libtorrent
|
||||
self.external_ip = None
|
||||
self.eventmanager.register_event_handler("ExternalIPEvent", self._on_external_ip_event)
|
||||
self.eventmanager.register_event_handler('ExternalIPEvent', self._on_external_ip_event)
|
||||
|
||||
# GeoIP instance with db loaded
|
||||
self.geoip_instance = None
|
||||
|
||||
# Get the core config
|
||||
self.config = ConfigManager("core.conf")
|
||||
self.config = ConfigManager('core.conf')
|
||||
self.config.save()
|
||||
|
||||
# If there was an interface value from the command line, use it, but
|
||||
@ -110,10 +110,10 @@ class Core(component.Component):
|
||||
self.__old_interface = None
|
||||
if listen_interface:
|
||||
if deluge.common.is_ip(listen_interface):
|
||||
self.__old_interface = self.config["listen_interface"]
|
||||
self.config["listen_interface"] = listen_interface
|
||||
self.__old_interface = self.config['listen_interface']
|
||||
self.config['listen_interface'] = listen_interface
|
||||
else:
|
||||
log.error("Invalid listen interface (must be IP Address): %s", listen_interface)
|
||||
log.error('Invalid listen interface (must be IP Address): %s', listen_interface)
|
||||
|
||||
# New release check information
|
||||
self.__new_release = None
|
||||
@ -123,14 +123,14 @@ class Core(component.Component):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
log.debug("Core stopping...")
|
||||
log.debug('Core stopping...')
|
||||
|
||||
# Save the libtorrent session state
|
||||
self.__save_session_state()
|
||||
|
||||
# We stored a copy of the old interface value
|
||||
if self.__old_interface:
|
||||
self.config["listen_interface"] = self.__old_interface
|
||||
self.config['listen_interface'] = self.__old_interface
|
||||
|
||||
# Make sure the config file has been saved
|
||||
self.config.save()
|
||||
@ -156,64 +156,64 @@ class Core(component.Component):
|
||||
|
||||
def __save_session_state(self):
|
||||
"""Saves the libtorrent session state"""
|
||||
filename = "session.state"
|
||||
filename = 'session.state'
|
||||
filepath = get_config_dir(filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
filepath_tmp = filepath + ".tmp"
|
||||
filepath_bak = filepath + '.bak'
|
||||
filepath_tmp = filepath + '.tmp'
|
||||
|
||||
try:
|
||||
if os.path.isfile(filepath):
|
||||
log.debug("Creating backup of %s at: %s", filename, filepath_bak)
|
||||
log.debug('Creating backup of %s at: %s', filename, filepath_bak)
|
||||
shutil.copy2(filepath, filepath_bak)
|
||||
except IOError as ex:
|
||||
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
|
||||
log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
|
||||
else:
|
||||
log.info("Saving the %s at: %s", filename, filepath)
|
||||
log.info('Saving the %s at: %s', filename, filepath)
|
||||
try:
|
||||
with open(filepath_tmp, "wb") as _file:
|
||||
with open(filepath_tmp, 'wb') as _file:
|
||||
_file.write(lt.bencode(self.session.save_state()))
|
||||
_file.flush()
|
||||
os.fsync(_file.fileno())
|
||||
shutil.move(filepath_tmp, filepath)
|
||||
except (IOError, EOFError) as ex:
|
||||
log.error("Unable to save %s: %s", filename, ex)
|
||||
log.error('Unable to save %s: %s', filename, ex)
|
||||
if os.path.isfile(filepath_bak):
|
||||
log.info("Restoring backup of %s from: %s", filename, filepath_bak)
|
||||
log.info('Restoring backup of %s from: %s', filename, filepath_bak)
|
||||
shutil.move(filepath_bak, filepath)
|
||||
|
||||
def __load_session_state(self):
|
||||
"""Loads the libtorrent session state"""
|
||||
filename = "session.state"
|
||||
filename = 'session.state'
|
||||
filepath = get_config_dir(filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
filepath_bak = filepath + '.bak'
|
||||
|
||||
for _filepath in (filepath, filepath_bak):
|
||||
log.info("Opening %s for load: %s", filename, _filepath)
|
||||
log.info('Opening %s for load: %s', filename, _filepath)
|
||||
try:
|
||||
with open(_filepath, "rb") as _file:
|
||||
with open(_filepath, 'rb') as _file:
|
||||
state = lt.bdecode(_file.read())
|
||||
except (IOError, EOFError, RuntimeError) as ex:
|
||||
log.warning("Unable to load %s: %s", _filepath, ex)
|
||||
log.warning('Unable to load %s: %s', _filepath, ex)
|
||||
else:
|
||||
log.info("Successfully loaded %s: %s", filename, _filepath)
|
||||
log.info('Successfully loaded %s: %s', filename, _filepath)
|
||||
self.session.load_state(state)
|
||||
return
|
||||
|
||||
def get_new_release(self):
|
||||
log.debug("get_new_release")
|
||||
log.debug('get_new_release')
|
||||
from urllib2 import urlopen, URLError
|
||||
try:
|
||||
self.new_release = urlopen("http://download.deluge-torrent.org/version-1.0").read().strip()
|
||||
self.new_release = urlopen('http://download.deluge-torrent.org/version-1.0').read().strip()
|
||||
except URLError as ex:
|
||||
log.debug("Unable to get release info from website: %s", ex)
|
||||
log.debug('Unable to get release info from website: %s', ex)
|
||||
return
|
||||
self.check_new_release()
|
||||
|
||||
def check_new_release(self):
|
||||
if self.new_release:
|
||||
log.debug("new_release: %s", self.new_release)
|
||||
log.debug('new_release: %s', self.new_release)
|
||||
if deluge.common.VersionSplit(self.new_release) > deluge.common.VersionSplit(deluge.common.get_version()):
|
||||
component.get("EventManager").emit(NewVersionAvailableEvent(self.new_release))
|
||||
component.get('EventManager').emit(NewVersionAvailableEvent(self.new_release))
|
||||
return self.new_release
|
||||
return False
|
||||
|
||||
@ -233,14 +233,14 @@ class Core(component.Component):
|
||||
try:
|
||||
filedump = base64.decodestring(filedump)
|
||||
except Exception as ex:
|
||||
log.error("There was an error decoding the filedump string: %s", ex)
|
||||
log.error('There was an error decoding the filedump string: %s', ex)
|
||||
|
||||
try:
|
||||
d = self.torrentmanager.add(
|
||||
filedump=filedump, options=options, filename=filename, save_state=save_state
|
||||
)
|
||||
except RuntimeError as ex:
|
||||
log.error("There was an error adding the torrent file %s: %s", filename, ex)
|
||||
log.error('There was an error adding the torrent file %s: %s', filename, ex)
|
||||
raise
|
||||
else:
|
||||
return d
|
||||
@ -301,11 +301,11 @@ class Core(component.Component):
|
||||
|
||||
:returns: a Deferred which returns the torrent_id as a str or None
|
||||
"""
|
||||
log.info("Attempting to add url %s", url)
|
||||
log.info('Attempting to add url %s', url)
|
||||
|
||||
def on_download_success(filename):
|
||||
# We got the file, so add it to the session
|
||||
with open(filename, "rb") as _file:
|
||||
with open(filename, 'rb') as _file:
|
||||
data = _file.read()
|
||||
try:
|
||||
os.remove(filename)
|
||||
@ -315,7 +315,7 @@ class Core(component.Component):
|
||||
|
||||
def on_download_fail(failure):
|
||||
# Log the error and pass the failure onto the client
|
||||
log.error("Failed to add torrent from url %s", url)
|
||||
log.error('Failed to add torrent from url %s', url)
|
||||
return failure
|
||||
|
||||
tmp_fd, tmp_file = tempfile.mkstemp(prefix='deluge_url.', suffix='.torrent')
|
||||
@ -338,7 +338,7 @@ class Core(component.Component):
|
||||
:rtype: string
|
||||
|
||||
"""
|
||||
log.debug("Attempting to add by magnet uri: %s", uri)
|
||||
log.debug('Attempting to add by magnet uri: %s', uri)
|
||||
|
||||
return self.torrentmanager.add(magnet=uri, options=options)
|
||||
|
||||
@ -357,7 +357,7 @@ class Core(component.Component):
|
||||
InvalidTorrentError: If the torrent ID does not exist in the session.
|
||||
|
||||
"""
|
||||
log.debug("Removing torrent %s from the core.", torrent_id)
|
||||
log.debug('Removing torrent %s from the core.', torrent_id)
|
||||
return self.torrentmanager.remove(torrent_id, remove_data)
|
||||
|
||||
@export
|
||||
@ -375,7 +375,7 @@ class Core(component.Component):
|
||||
[("<torrent_id>", "Error removing torrent")]
|
||||
|
||||
"""
|
||||
log.info("Removing %d torrents from core.", len(torrent_ids))
|
||||
log.info('Removing %d torrents from core.', len(torrent_ids))
|
||||
|
||||
def do_remove_torrents():
|
||||
errors = []
|
||||
@ -387,7 +387,7 @@ class Core(component.Component):
|
||||
# Save the session state
|
||||
self.torrentmanager.save_state()
|
||||
if errors:
|
||||
log.warn("Failed to remove %d of %d torrents.", len(errors), len(torrent_ids))
|
||||
log.warn('Failed to remove %d of %d torrents.', len(errors), len(torrent_ids))
|
||||
return errors
|
||||
return task.deferLater(reactor, 0, do_remove_torrents)
|
||||
|
||||
@ -426,55 +426,55 @@ class Core(component.Component):
|
||||
status = self.session.get_cache_status()
|
||||
cache = {}
|
||||
for attr in dir(status):
|
||||
if attr.startswith("_"):
|
||||
if attr.startswith('_'):
|
||||
continue
|
||||
cache[attr] = getattr(status, attr)
|
||||
|
||||
# Add in a couple ratios
|
||||
try:
|
||||
cache["write_hit_ratio"] = (cache["blocks_written"] - cache["writes"]) / cache["blocks_written"]
|
||||
cache['write_hit_ratio'] = (cache['blocks_written'] - cache['writes']) / cache['blocks_written']
|
||||
except ZeroDivisionError:
|
||||
cache["write_hit_ratio"] = 0.0
|
||||
cache['write_hit_ratio'] = 0.0
|
||||
|
||||
try:
|
||||
cache["read_hit_ratio"] = cache["blocks_read_hit"] / cache["blocks_read"]
|
||||
cache['read_hit_ratio'] = cache['blocks_read_hit'] / cache['blocks_read']
|
||||
except ZeroDivisionError:
|
||||
cache["read_hit_ratio"] = 0.0
|
||||
cache['read_hit_ratio'] = 0.0
|
||||
|
||||
return cache
|
||||
|
||||
@export
|
||||
def force_reannounce(self, torrent_ids):
|
||||
log.debug("Forcing reannouncment to: %s", torrent_ids)
|
||||
log.debug('Forcing reannouncment to: %s', torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
self.torrentmanager[torrent_id].force_reannounce()
|
||||
|
||||
@export
|
||||
def pause_torrent(self, torrent_ids):
|
||||
log.debug("Pausing: %s", torrent_ids)
|
||||
log.debug('Pausing: %s', torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
if not self.torrentmanager[torrent_id].pause():
|
||||
log.warning("Error pausing torrent %s", torrent_id)
|
||||
log.warning('Error pausing torrent %s', torrent_id)
|
||||
|
||||
@export
|
||||
def connect_peer(self, torrent_id, ip, port):
|
||||
log.debug("adding peer %s to %s", ip, torrent_id)
|
||||
log.debug('adding peer %s to %s', ip, torrent_id)
|
||||
if not self.torrentmanager[torrent_id].connect_peer(ip, port):
|
||||
log.warning("Error adding peer %s:%s to %s", ip, port, torrent_id)
|
||||
log.warning('Error adding peer %s:%s to %s', ip, port, torrent_id)
|
||||
|
||||
@export
|
||||
def move_storage(self, torrent_ids, dest):
|
||||
log.debug("Moving storage %s to %s", torrent_ids, dest)
|
||||
log.debug('Moving storage %s to %s', torrent_ids, dest)
|
||||
for torrent_id in torrent_ids:
|
||||
if not self.torrentmanager[torrent_id].move_storage(dest):
|
||||
log.warning("Error moving torrent %s to %s", torrent_id, dest)
|
||||
log.warning('Error moving torrent %s to %s', torrent_id, dest)
|
||||
|
||||
@export
|
||||
def pause_session(self):
|
||||
"""Pause all torrents in the session"""
|
||||
if not self.session.is_paused():
|
||||
self.session.pause()
|
||||
component.get("EventManager").emit(SessionPausedEvent())
|
||||
component.get('EventManager').emit(SessionPausedEvent())
|
||||
|
||||
@export
|
||||
def resume_session(self):
|
||||
@ -483,11 +483,11 @@ class Core(component.Component):
|
||||
self.session.resume()
|
||||
for torrent_id in self.torrentmanager.torrents:
|
||||
self.torrentmanager[torrent_id].update_state()
|
||||
component.get("EventManager").emit(SessionResumedEvent())
|
||||
component.get('EventManager').emit(SessionResumedEvent())
|
||||
|
||||
@export
|
||||
def resume_torrent(self, torrent_ids):
|
||||
log.debug("Resuming: %s", torrent_ids)
|
||||
log.debug('Resuming: %s', torrent_ids)
|
||||
for torrent_id in torrent_ids:
|
||||
self.torrentmanager[torrent_id].resume()
|
||||
|
||||
@ -566,7 +566,7 @@ class Core(component.Component):
|
||||
if self.read_only_config_keys and key in self.read_only_config_keys:
|
||||
continue
|
||||
if isinstance(config[key], basestring):
|
||||
config[key] = config[key].encode("utf8")
|
||||
config[key] = config[key].encode('utf8')
|
||||
self.config[key] = config[key]
|
||||
|
||||
@export
|
||||
@ -578,7 +578,7 @@ class Core(component.Component):
|
||||
def get_i2p_proxy(self):
|
||||
"""Returns the active listen port"""
|
||||
i2p_settings = self.session.i2p_proxy() # Deprecated, moved to proxy types
|
||||
i2p_dict = {"hostname": i2p_settings.hostname, "port": i2p_settings.port}
|
||||
i2p_dict = {'hostname': i2p_settings.hostname, 'port': i2p_settings.port}
|
||||
return i2p_dict
|
||||
|
||||
@export
|
||||
@ -586,13 +586,13 @@ class Core(component.Component):
|
||||
"""Returns the active listen port"""
|
||||
proxy_settings = self.session.proxy()
|
||||
proxy_dict = {
|
||||
"type": int(proxy_settings.type),
|
||||
"hostname": proxy_settings.hostname,
|
||||
"username": proxy_settings.username,
|
||||
"password": proxy_settings.password,
|
||||
"port": proxy_settings.port,
|
||||
"proxy_hostnames": proxy_settings.proxy_hostnames,
|
||||
"proxy_peer_connections": proxy_settings.proxy_peer_connections
|
||||
'type': int(proxy_settings.type),
|
||||
'hostname': proxy_settings.hostname,
|
||||
'username': proxy_settings.username,
|
||||
'password': proxy_settings.password,
|
||||
'port': proxy_settings.port,
|
||||
'proxy_hostnames': proxy_settings.proxy_hostnames,
|
||||
'proxy_peer_connections': proxy_settings.proxy_peer_connections
|
||||
}
|
||||
return proxy_dict
|
||||
|
||||
@ -733,7 +733,7 @@ class Core(component.Component):
|
||||
def create_torrent(self, path, tracker, piece_length, comment, target,
|
||||
webseeds, private, created_by, trackers, add_to_session):
|
||||
|
||||
log.debug("creating torrent..")
|
||||
log.debug('creating torrent..')
|
||||
threading.Thread(target=self._create_torrent_thread,
|
||||
args=(
|
||||
path,
|
||||
@ -760,11 +760,11 @@ class Core(component.Component):
|
||||
private=private,
|
||||
created_by=created_by,
|
||||
trackers=trackers)
|
||||
log.debug("torrent created!")
|
||||
log.debug('torrent created!')
|
||||
if add_to_session:
|
||||
options = {}
|
||||
options["download_location"] = os.path.split(path)[0]
|
||||
with open(target, "rb") as _file:
|
||||
options['download_location'] = os.path.split(path)[0]
|
||||
with open(target, 'rb') as _file:
|
||||
self.add_torrent_file(os.path.split(target)[1], _file.read(), options)
|
||||
|
||||
@export
|
||||
@ -777,20 +777,20 @@ class Core(component.Component):
|
||||
try:
|
||||
filedump = base64.decodestring(filedump)
|
||||
except Exception as ex:
|
||||
log.error("There was an error decoding the filedump string!")
|
||||
log.error('There was an error decoding the filedump string!')
|
||||
log.exception(ex)
|
||||
return
|
||||
|
||||
with open(os.path.join(get_config_dir(), "plugins", filename), "wb") as _file:
|
||||
with open(os.path.join(get_config_dir(), 'plugins', filename), 'wb') as _file:
|
||||
_file.write(filedump)
|
||||
component.get("CorePluginManager").scan_for_plugins()
|
||||
component.get('CorePluginManager').scan_for_plugins()
|
||||
|
||||
@export
|
||||
def rescan_plugins(self):
|
||||
"""
|
||||
Rescans the plugin folders for new plugins
|
||||
"""
|
||||
component.get("CorePluginManager").scan_for_plugins()
|
||||
component.get('CorePluginManager').scan_for_plugins()
|
||||
|
||||
@export
|
||||
def rename_files(self, torrent_id, filenames):
|
||||
@ -808,7 +808,7 @@ class Core(component.Component):
|
||||
|
||||
"""
|
||||
if torrent_id not in self.torrentmanager.torrents:
|
||||
raise InvalidTorrentError("torrent_id is not in session")
|
||||
raise InvalidTorrentError('torrent_id is not in session')
|
||||
|
||||
def rename():
|
||||
self.torrentmanager[torrent_id].rename_files(filenames)
|
||||
@ -833,25 +833,25 @@ class Core(component.Component):
|
||||
|
||||
"""
|
||||
if torrent_id not in self.torrentmanager.torrents:
|
||||
raise InvalidTorrentError("torrent_id is not in session")
|
||||
raise InvalidTorrentError('torrent_id is not in session')
|
||||
|
||||
return self.torrentmanager[torrent_id].rename_folder(folder, new_folder)
|
||||
|
||||
@export
|
||||
def queue_top(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to top", torrent_ids)
|
||||
log.debug('Attempting to queue %s to top', torrent_ids)
|
||||
# torrent_ids must be sorted in reverse before moving to preserve order
|
||||
for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position, reverse=True):
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrentmanager.queue_top(torrent_id):
|
||||
component.get("EventManager").emit(TorrentQueueChangedEvent())
|
||||
component.get('EventManager').emit(TorrentQueueChangedEvent())
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
log.warning('torrent_id: %s does not exist in the queue', torrent_id)
|
||||
|
||||
@export
|
||||
def queue_up(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to up", torrent_ids)
|
||||
log.debug('Attempting to queue %s to up', torrent_ids)
|
||||
torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids)
|
||||
torrent_moved = True
|
||||
prev_queue_position = None
|
||||
@ -862,16 +862,16 @@ class Core(component.Component):
|
||||
try:
|
||||
torrent_moved = self.torrentmanager.queue_up(torrent_id)
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
log.warning('torrent_id: %s does not exist in the queue', torrent_id)
|
||||
# If the torrent moved, then we should emit a signal
|
||||
if torrent_moved:
|
||||
component.get("EventManager").emit(TorrentQueueChangedEvent())
|
||||
component.get('EventManager').emit(TorrentQueueChangedEvent())
|
||||
else:
|
||||
prev_queue_position = queue_position
|
||||
|
||||
@export
|
||||
def queue_down(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to down", torrent_ids)
|
||||
log.debug('Attempting to queue %s to down', torrent_ids)
|
||||
torrents = ((self.torrentmanager.get_queue_position(torrent_id), torrent_id) for torrent_id in torrent_ids)
|
||||
torrent_moved = True
|
||||
prev_queue_position = None
|
||||
@ -882,24 +882,24 @@ class Core(component.Component):
|
||||
try:
|
||||
torrent_moved = self.torrentmanager.queue_down(torrent_id)
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
log.warning('torrent_id: %s does not exist in the queue', torrent_id)
|
||||
# If the torrent moved, then we should emit a signal
|
||||
if torrent_moved:
|
||||
component.get("EventManager").emit(TorrentQueueChangedEvent())
|
||||
component.get('EventManager').emit(TorrentQueueChangedEvent())
|
||||
else:
|
||||
prev_queue_position = queue_position
|
||||
|
||||
@export
|
||||
def queue_bottom(self, torrent_ids):
|
||||
log.debug("Attempting to queue %s to bottom", torrent_ids)
|
||||
log.debug('Attempting to queue %s to bottom', torrent_ids)
|
||||
# torrent_ids must be sorted before moving to preserve order
|
||||
for torrent_id in sorted(torrent_ids, key=self.torrentmanager.get_queue_position):
|
||||
try:
|
||||
# If the queue method returns True, then we should emit a signal
|
||||
if self.torrentmanager.queue_bottom(torrent_id):
|
||||
component.get("EventManager").emit(TorrentQueueChangedEvent())
|
||||
component.get('EventManager').emit(TorrentQueueChangedEvent())
|
||||
except KeyError:
|
||||
log.warning("torrent_id: %s does not exist in the queue", torrent_id)
|
||||
log.warning('torrent_id: %s does not exist in the queue', torrent_id)
|
||||
|
||||
@export
|
||||
def glob(self, path):
|
||||
@ -914,14 +914,14 @@ class Core(component.Component):
|
||||
:rtype: bool
|
||||
|
||||
"""
|
||||
d = getPage("http://deluge-torrent.org/test_port.php?port=%s" %
|
||||
d = getPage('http://deluge-torrent.org/test_port.php?port=%s' %
|
||||
self.get_listen_port(), timeout=30)
|
||||
|
||||
def on_get_page(result):
|
||||
return bool(int(result))
|
||||
|
||||
def on_error(failure):
|
||||
log.warning("Error testing listen port: %s", failure)
|
||||
log.warning('Error testing listen port: %s', failure)
|
||||
|
||||
d.addCallback(on_get_page)
|
||||
d.addErrback(on_error)
|
||||
@ -943,7 +943,7 @@ class Core(component.Component):
|
||||
|
||||
"""
|
||||
if not path:
|
||||
path = self.config["download_location"]
|
||||
path = self.config['download_location']
|
||||
try:
|
||||
return deluge.common.free_space(path)
|
||||
except InvalidPathError:
|
||||
|
||||
@ -43,7 +43,7 @@ def is_daemon_running(pid_file):
|
||||
|
||||
try:
|
||||
with open(pid_file) as _file:
|
||||
pid, port = [int(x) for x in _file.readline().strip().split(";")]
|
||||
pid, port = [int(x) for x in _file.readline().strip().split(';')]
|
||||
except EnvironmentError:
|
||||
return False
|
||||
|
||||
@ -51,7 +51,7 @@ def is_daemon_running(pid_file):
|
||||
# Ensure it's a deluged process by trying to open a socket to it's port.
|
||||
_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
_socket.connect(("127.0.0.1", port))
|
||||
_socket.connect(('127.0.0.1', port))
|
||||
except socket.error:
|
||||
# Can't connect, so pid is not a deluged process.
|
||||
return False
|
||||
@ -77,19 +77,19 @@ class Daemon(object):
|
||||
altered by core.set_config() RPC method.
|
||||
"""
|
||||
self.standalone = standalone
|
||||
self.pid_file = get_config_dir("deluged.pid")
|
||||
log.info("Deluge daemon %s", get_version())
|
||||
self.pid_file = get_config_dir('deluged.pid')
|
||||
log.info('Deluge daemon %s', get_version())
|
||||
if is_daemon_running(self.pid_file):
|
||||
raise DaemonRunningError("Deluge daemon already running with this config directory!")
|
||||
raise DaemonRunningError('Deluge daemon already running with this config directory!')
|
||||
|
||||
# Twisted catches signals to terminate, so just have it call the shutdown method.
|
||||
reactor.addSystemEventTrigger("before", "shutdown", self._shutdown)
|
||||
reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
|
||||
|
||||
# Catch some Windows specific signals
|
||||
if windows_check():
|
||||
def win_handler(ctrl_type):
|
||||
"""Handle the Windows shutdown or close events."""
|
||||
log.debug("windows handler ctrl_type: %s", ctrl_type)
|
||||
log.debug('windows handler ctrl_type: %s', ctrl_type)
|
||||
if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT:
|
||||
self._shutdown()
|
||||
return 1
|
||||
@ -100,21 +100,21 @@ class Daemon(object):
|
||||
read_only_config_keys=read_only_config_keys)
|
||||
|
||||
if port is None:
|
||||
port = self.core.config["daemon_port"]
|
||||
port = self.core.config['daemon_port']
|
||||
self.port = port
|
||||
|
||||
if interface and not is_ip(interface):
|
||||
log.error("Invalid UI interface (must be IP Address): %s", interface)
|
||||
log.error('Invalid UI interface (must be IP Address): %s', interface)
|
||||
interface = None
|
||||
|
||||
self.rpcserver = RPCServer(
|
||||
port=port,
|
||||
allow_remote=self.core.config["allow_remote"],
|
||||
allow_remote=self.core.config['allow_remote'],
|
||||
listen=not standalone,
|
||||
interface=interface
|
||||
)
|
||||
|
||||
log.debug("Listening to UI on: %s:%s and bittorrent on: %s", interface, port, listen_interface)
|
||||
log.debug('Listening to UI on: %s:%s and bittorrent on: %s', interface, port, listen_interface)
|
||||
|
||||
def start(self):
|
||||
# Register the daemon and the core RPCs
|
||||
@ -122,32 +122,32 @@ class Daemon(object):
|
||||
self.rpcserver.register_object(self)
|
||||
|
||||
# Make sure we start the PreferencesManager first
|
||||
component.start("PreferencesManager")
|
||||
component.start('PreferencesManager')
|
||||
|
||||
if not self.standalone:
|
||||
log.info("Deluge daemon starting...")
|
||||
log.info('Deluge daemon starting...')
|
||||
# Create pid file to track if deluged is running, also includes the port number.
|
||||
pid = os.getpid()
|
||||
log.debug("Storing pid %s & port %s in: %s", pid, self.port, self.pid_file)
|
||||
with open(self.pid_file, "wb") as _file:
|
||||
_file.write("%s;%s\n" % (pid, self.port))
|
||||
log.debug('Storing pid %s & port %s in: %s', pid, self.port, self.pid_file)
|
||||
with open(self.pid_file, 'wb') as _file:
|
||||
_file.write('%s;%s\n' % (pid, self.port))
|
||||
|
||||
component.start()
|
||||
|
||||
try:
|
||||
reactor.run()
|
||||
finally:
|
||||
log.debug("Remove pid file: %s", self.pid_file)
|
||||
log.debug('Remove pid file: %s', self.pid_file)
|
||||
os.remove(self.pid_file)
|
||||
log.info("Deluge daemon shutdown successfully")
|
||||
log.info('Deluge daemon shutdown successfully')
|
||||
|
||||
@export()
|
||||
def shutdown(self, *args, **kwargs):
|
||||
log.debug("Deluge daemon shutdown requested...")
|
||||
log.debug('Deluge daemon shutdown requested...')
|
||||
reactor.callLater(0, reactor.stop)
|
||||
|
||||
def _shutdown(self, *args, **kwargs):
|
||||
log.info("Deluge daemon shutting down, waiting for components to shutdown...")
|
||||
log.info('Deluge daemon shutting down, waiting for components to shutdown...')
|
||||
if not self.standalone:
|
||||
return component.shutdown()
|
||||
|
||||
|
||||
@ -20,15 +20,15 @@ from deluge.ui.util import lang
|
||||
|
||||
|
||||
def add_daemon_options(parser):
|
||||
group = parser.add_argument_group(_("Daemon Options"))
|
||||
group.add_argument("-u", "--ui-interface", metavar="<ip-addr>", action="store",
|
||||
help=_("IP address to listen for UI connections"))
|
||||
group.add_argument("-p", "--port", metavar="<port>", action="store", type=int,
|
||||
help=_("Port to listen for UI connections on"))
|
||||
group.add_argument("-i", "--interface", metavar="<ip-addr>", dest="listen_interface", action="store",
|
||||
help=_("IP address to listen for BitTorrent connections"))
|
||||
group.add_argument("--read-only-config-keys", metavar="<comma-separated-keys>", action="store",
|
||||
help=_("Config keys to be unmodified by `set_config` RPC"), type=str, default="")
|
||||
group = parser.add_argument_group(_('Daemon Options'))
|
||||
group.add_argument('-u', '--ui-interface', metavar='<ip-addr>', action='store',
|
||||
help=_('IP address to listen for UI connections'))
|
||||
group.add_argument('-p', '--port', metavar='<port>', action='store', type=int,
|
||||
help=_('Port to listen for UI connections on'))
|
||||
group.add_argument('-i', '--interface', metavar='<ip-addr>', dest='listen_interface', action='store',
|
||||
help=_('IP address to listen for BitTorrent connections'))
|
||||
group.add_argument('--read-only-config-keys', metavar='<comma-separated-keys>', action='store',
|
||||
help=_('Config keys to be unmodified by `set_config` RPC'), type=str, default='')
|
||||
parser.add_process_arg_group()
|
||||
|
||||
|
||||
@ -53,17 +53,17 @@ def start_daemon(skip_start=False):
|
||||
|
||||
# Check for any daemons running with this same config
|
||||
from deluge.core.daemon import is_daemon_running
|
||||
pid_file = get_config_dir("deluged.pid")
|
||||
pid_file = get_config_dir('deluged.pid')
|
||||
if is_daemon_running(pid_file):
|
||||
print("Cannot run multiple daemons using the same config directory.\n"
|
||||
"If you believe this is an error, you can force a start by deleting: %s" % pid_file)
|
||||
print('Cannot run multiple daemons using the same config directory.\n'
|
||||
'If you believe this is an error, you can force a start by deleting: %s' % pid_file)
|
||||
sys.exit(1)
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
# If no logfile specified add logging to default location (as well as stdout)
|
||||
if not options.logfile:
|
||||
options.logfile = get_config_dir("deluged.log")
|
||||
options.logfile = get_config_dir('deluged.log')
|
||||
file_handler = FileHandler(options.logfile)
|
||||
log.addHandler(file_handler)
|
||||
|
||||
@ -73,7 +73,7 @@ def start_daemon(skip_start=False):
|
||||
daemon = Daemon(listen_interface=options.listen_interface,
|
||||
interface=options.ui_interface,
|
||||
port=options.port,
|
||||
read_only_config_keys=options.read_only_config_keys.split(","))
|
||||
read_only_config_keys=options.read_only_config_keys.split(','))
|
||||
if skip_start:
|
||||
return daemon
|
||||
else:
|
||||
|
||||
@ -16,7 +16,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class EventManager(component.Component):
|
||||
def __init__(self):
|
||||
component.Component.__init__(self, "EventManager")
|
||||
component.Component.__init__(self, 'EventManager')
|
||||
self.handlers = {}
|
||||
|
||||
def emit(self, event):
|
||||
@ -26,7 +26,7 @@ class EventManager(component.Component):
|
||||
:param event: DelugeEvent
|
||||
"""
|
||||
# Emit the event to the interested clients
|
||||
component.get("RPCServer").emit_event(event)
|
||||
component.get('RPCServer').emit_event(event)
|
||||
# Call any handlers for the event
|
||||
if event.name in self.handlers:
|
||||
for handler in self.handlers[event.name]:
|
||||
@ -34,7 +34,7 @@ class EventManager(component.Component):
|
||||
try:
|
||||
handler(*event.args)
|
||||
except Exception as ex:
|
||||
log.error("Event handler %s failed in %s with exception %s", event.name, handler, ex)
|
||||
log.error('Event handler %s failed in %s with exception %s', event.name, handler, ex)
|
||||
|
||||
def register_event_handler(self, event, handler):
|
||||
"""
|
||||
|
||||
@ -14,14 +14,14 @@ from deluge.common import TORRENT_STATE
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
STATE_SORT = ["All", "Active"] + TORRENT_STATE
|
||||
STATE_SORT = ['All', 'Active'] + TORRENT_STATE
|
||||
|
||||
|
||||
# Special purpose filters:
|
||||
def filter_keywords(torrent_ids, values):
|
||||
# Cleanup
|
||||
keywords = ",".join([v.lower() for v in values])
|
||||
keywords = keywords.split(",")
|
||||
keywords = ','.join([v.lower() for v in values])
|
||||
keywords = keywords.split(',')
|
||||
|
||||
for keyword in keywords:
|
||||
torrent_ids = filter_one_keyword(torrent_ids, keyword)
|
||||
@ -33,7 +33,7 @@ def filter_one_keyword(torrent_ids, keyword):
|
||||
search torrent on keyword.
|
||||
searches title,state,tracker-status,tracker,files
|
||||
"""
|
||||
all_torrents = component.get("TorrentManager").torrents
|
||||
all_torrents = component.get('TorrentManager').torrents
|
||||
|
||||
for torrent_id in torrent_ids:
|
||||
torrent = all_torrents[torrent_id]
|
||||
@ -41,7 +41,7 @@ def filter_one_keyword(torrent_ids, keyword):
|
||||
yield torrent_id
|
||||
elif keyword in torrent.state.lower():
|
||||
yield torrent_id
|
||||
elif torrent.trackers and keyword in torrent.trackers[0]["url"]:
|
||||
elif torrent.trackers and keyword in torrent.trackers[0]['url']:
|
||||
yield torrent_id
|
||||
elif keyword in torrent_id:
|
||||
yield torrent_id
|
||||
@ -50,13 +50,13 @@ def filter_one_keyword(torrent_ids, keyword):
|
||||
yield torrent_id
|
||||
else:
|
||||
for t_file in torrent.get_files():
|
||||
if keyword in t_file["path"].lower():
|
||||
if keyword in t_file['path'].lower():
|
||||
yield torrent_id
|
||||
break
|
||||
|
||||
|
||||
def filter_by_name(torrent_ids, search_string):
|
||||
all_torrents = component.get("TorrentManager").torrents
|
||||
all_torrents = component.get('TorrentManager').torrents
|
||||
try:
|
||||
search_string, match_case = search_string[0].split('::match')
|
||||
except ValueError:
|
||||
@ -79,18 +79,18 @@ def filter_by_name(torrent_ids, search_string):
|
||||
|
||||
def tracker_error_filter(torrent_ids, values):
|
||||
filtered_torrent_ids = []
|
||||
tm = component.get("TorrentManager")
|
||||
tm = component.get('TorrentManager')
|
||||
|
||||
# If this is a tracker_host, then we need to filter on it
|
||||
if values[0] != "Error":
|
||||
if values[0] != 'Error':
|
||||
for torrent_id in torrent_ids:
|
||||
if values[0] == tm[torrent_id].get_status(["tracker_host"])["tracker_host"]:
|
||||
if values[0] == tm[torrent_id].get_status(['tracker_host'])['tracker_host']:
|
||||
filtered_torrent_ids.append(torrent_id)
|
||||
return filtered_torrent_ids
|
||||
|
||||
# Check torrent's tracker_status for 'Error:' and return those torrent_ids
|
||||
for torrent_id in torrent_ids:
|
||||
if "Error:" in tm[torrent_id].get_status(["tracker_status"])["tracker_status"]:
|
||||
if 'Error:' in tm[torrent_id].get_status(['tracker_status'])['tracker_status']:
|
||||
filtered_torrent_ids.append(torrent_id)
|
||||
return filtered_torrent_ids
|
||||
|
||||
@ -100,26 +100,26 @@ class FilterManager(component.Component):
|
||||
|
||||
"""
|
||||
def __init__(self, core):
|
||||
component.Component.__init__(self, "FilterManager")
|
||||
log.debug("FilterManager init..")
|
||||
component.Component.__init__(self, 'FilterManager')
|
||||
log.debug('FilterManager init..')
|
||||
self.core = core
|
||||
self.torrents = core.torrentmanager
|
||||
self.registered_filters = {}
|
||||
self.register_filter("keyword", filter_keywords)
|
||||
self.register_filter("name", filter_by_name)
|
||||
self.register_filter('keyword', filter_keywords)
|
||||
self.register_filter('name', filter_by_name)
|
||||
self.tree_fields = {}
|
||||
|
||||
self.register_tree_field("state", self._init_state_tree)
|
||||
self.register_tree_field('state', self._init_state_tree)
|
||||
|
||||
def _init_tracker_tree():
|
||||
return {"Error": 0}
|
||||
self.register_tree_field("tracker_host", _init_tracker_tree)
|
||||
return {'Error': 0}
|
||||
self.register_tree_field('tracker_host', _init_tracker_tree)
|
||||
|
||||
self.register_filter("tracker_host", tracker_error_filter)
|
||||
self.register_filter('tracker_host', tracker_error_filter)
|
||||
|
||||
def _init_users_tree():
|
||||
return {"": 0}
|
||||
self.register_tree_field("owner", _init_users_tree)
|
||||
return {'': 0}
|
||||
self.register_tree_field('owner', _init_users_tree)
|
||||
|
||||
def filter_torrent_ids(self, filter_dict):
|
||||
"""
|
||||
@ -135,9 +135,9 @@ class FilterManager(component.Component):
|
||||
filter_dict[key] = [value]
|
||||
|
||||
# Optimized filter for id
|
||||
if "id" in filter_dict:
|
||||
torrent_ids = list(filter_dict["id"])
|
||||
del filter_dict["id"]
|
||||
if 'id' in filter_dict:
|
||||
torrent_ids = list(filter_dict['id'])
|
||||
del filter_dict['id']
|
||||
else:
|
||||
torrent_ids = self.torrents.get_torrent_list()
|
||||
|
||||
@ -146,14 +146,14 @@ class FilterManager(component.Component):
|
||||
return torrent_ids
|
||||
|
||||
# Special purpose, state=Active.
|
||||
if "state" in filter_dict:
|
||||
if 'state' in filter_dict:
|
||||
# We need to make sure this is a list for the logic below
|
||||
filter_dict["state"] = list(filter_dict["state"])
|
||||
filter_dict['state'] = list(filter_dict['state'])
|
||||
|
||||
if "state" in filter_dict and "Active" in filter_dict["state"]:
|
||||
filter_dict["state"].remove("Active")
|
||||
if not filter_dict["state"]:
|
||||
del filter_dict["state"]
|
||||
if 'state' in filter_dict and 'Active' in filter_dict['state']:
|
||||
filter_dict['state'].remove('Active')
|
||||
if not filter_dict['state']:
|
||||
del filter_dict['state']
|
||||
torrent_ids = self.filter_state_active(torrent_ids)
|
||||
|
||||
if not filter_dict:
|
||||
@ -200,12 +200,12 @@ class FilterManager(component.Component):
|
||||
value = status[field]
|
||||
items[field][value] = items[field].get(value, 0) + 1
|
||||
|
||||
if "tracker_host" in items:
|
||||
items["tracker_host"]["All"] = len(torrent_ids)
|
||||
items["tracker_host"]["Error"] = len(tracker_error_filter(torrent_ids, ("Error",)))
|
||||
if 'tracker_host' in items:
|
||||
items['tracker_host']['All'] = len(torrent_ids)
|
||||
items['tracker_host']['Error'] = len(tracker_error_filter(torrent_ids, ('Error',)))
|
||||
|
||||
if not show_zero_hits:
|
||||
for cat in ["state", "owner", "tracker_host"]:
|
||||
for cat in ['state', 'owner', 'tracker_host']:
|
||||
if cat in tree_keys:
|
||||
self._hide_state_items(items[cat])
|
||||
|
||||
@ -214,17 +214,17 @@ class FilterManager(component.Component):
|
||||
for field in tree_keys:
|
||||
sorted_items[field] = sorted(items[field].iteritems())
|
||||
|
||||
if "state" in tree_keys:
|
||||
sorted_items["state"].sort(self._sort_state_items)
|
||||
if 'state' in tree_keys:
|
||||
sorted_items['state'].sort(self._sort_state_items)
|
||||
|
||||
return sorted_items
|
||||
|
||||
def _init_state_tree(self):
|
||||
init_state = {}
|
||||
init_state["All"] = len(self.torrents.get_torrent_list())
|
||||
init_state['All'] = len(self.torrents.get_torrent_list())
|
||||
for state in TORRENT_STATE:
|
||||
init_state[state] = 0
|
||||
init_state["Active"] = len(self.filter_state_active(self.torrents.get_torrent_list()))
|
||||
init_state['Active'] = len(self.filter_state_active(self.torrents.get_torrent_list()))
|
||||
return init_state
|
||||
|
||||
def register_filter(self, filter_id, filter_func, filter_value=None):
|
||||
@ -242,8 +242,8 @@ class FilterManager(component.Component):
|
||||
|
||||
def filter_state_active(self, torrent_ids):
|
||||
for torrent_id in list(torrent_ids):
|
||||
status = self.torrents[torrent_id].get_status(["download_payload_rate", "upload_payload_rate"])
|
||||
if status["download_payload_rate"] or status["upload_payload_rate"]:
|
||||
status = self.torrents[torrent_id].get_status(['download_payload_rate', 'upload_payload_rate'])
|
||||
if status['download_payload_rate'] or status['upload_payload_rate']:
|
||||
pass
|
||||
else:
|
||||
torrent_ids.remove(torrent_id)
|
||||
@ -252,7 +252,7 @@ class FilterManager(component.Component):
|
||||
def _hide_state_items(self, state_items):
|
||||
"""For hide(show)-zero hits"""
|
||||
for (value, count) in state_items.items():
|
||||
if value != "All" and count == 0:
|
||||
if value != 'All' and count == 0:
|
||||
del state_items[value]
|
||||
|
||||
def _sort_state_items(self, x, y):
|
||||
|
||||
@ -26,13 +26,13 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
|
||||
functions to access parts of the core."""
|
||||
|
||||
def __init__(self, core):
|
||||
component.Component.__init__(self, "CorePluginManager")
|
||||
component.Component.__init__(self, 'CorePluginManager')
|
||||
|
||||
self.status_fields = {}
|
||||
|
||||
# Call the PluginManagerBase constructor
|
||||
deluge.pluginmanagerbase.PluginManagerBase.__init__(
|
||||
self, "core.conf", "deluge.plugin.core")
|
||||
self, 'core.conf', 'deluge.plugin.core')
|
||||
|
||||
def start(self):
|
||||
# Enable plugins that are enabled in the config
|
||||
@ -47,7 +47,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
|
||||
|
||||
def update_plugins(self):
|
||||
for plugin in self.plugins:
|
||||
if hasattr(self.plugins[plugin], "update"):
|
||||
if hasattr(self.plugins[plugin], 'update'):
|
||||
try:
|
||||
self.plugins[plugin].update()
|
||||
except Exception as ex:
|
||||
@ -60,7 +60,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
|
||||
|
||||
def on_enable_plugin(result):
|
||||
if result is True and name in self.plugins:
|
||||
component.get("EventManager").emit(PluginEnabledEvent(name))
|
||||
component.get('EventManager').emit(PluginEnabledEvent(name))
|
||||
return result
|
||||
|
||||
d.addBoth(on_enable_plugin)
|
||||
@ -73,7 +73,7 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
|
||||
|
||||
def on_disable_plugin(result):
|
||||
if name not in self.plugins:
|
||||
component.get("EventManager").emit(PluginDisabledEvent(name))
|
||||
component.get('EventManager').emit(PluginDisabledEvent(name))
|
||||
return result
|
||||
d.addBoth(on_disable_plugin)
|
||||
return d
|
||||
@ -93,13 +93,13 @@ class PluginManager(deluge.pluginmanagerbase.PluginManagerBase, component.Compon
|
||||
def register_status_field(self, field, function):
|
||||
"""Register a new status field. This can be used in the same way the
|
||||
client requests other status information from core."""
|
||||
log.debug("Registering status field %s with PluginManager", field)
|
||||
log.debug('Registering status field %s with PluginManager', field)
|
||||
self.status_fields[field] = function
|
||||
|
||||
def deregister_status_field(self, field):
|
||||
"""Deregisters a status field"""
|
||||
log.debug("Deregistering status field %s with PluginManager", field)
|
||||
log.debug('Deregistering status field %s with PluginManager', field)
|
||||
try:
|
||||
del self.status_fields[field]
|
||||
except Exception:
|
||||
log.warning("Unable to deregister status field %s", field)
|
||||
log.warning('Unable to deregister status field %s', field)
|
||||
|
||||
@ -29,119 +29,119 @@ except ImportError:
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"send_info": False,
|
||||
"info_sent": 0.0,
|
||||
"daemon_port": 58846,
|
||||
"allow_remote": False,
|
||||
"pre_allocate_storage": False,
|
||||
"download_location": deluge.common.get_default_download_dir(),
|
||||
"listen_ports": [6881, 6891],
|
||||
"listen_interface": "",
|
||||
"random_port": True,
|
||||
"listen_random_port": None,
|
||||
"listen_use_sys_port": False,
|
||||
"listen_reuse_port": True,
|
||||
"outgoing_ports": [0, 0],
|
||||
"random_outgoing_ports": True,
|
||||
"copy_torrent_file": False,
|
||||
"del_copy_torrent_file": False,
|
||||
"torrentfiles_location": deluge.common.get_default_download_dir(),
|
||||
"plugins_location": os.path.join(deluge.configmanager.get_config_dir(), "plugins"),
|
||||
"prioritize_first_last_pieces": False,
|
||||
"sequential_download": False,
|
||||
"dht": True,
|
||||
"upnp": True,
|
||||
"natpmp": True,
|
||||
"utpex": True,
|
||||
"lsd": True,
|
||||
"enc_in_policy": 1,
|
||||
"enc_out_policy": 1,
|
||||
"enc_level": 2,
|
||||
"max_connections_global": 200,
|
||||
"max_upload_speed": -1.0,
|
||||
"max_download_speed": -1.0,
|
||||
"max_upload_slots_global": 4,
|
||||
"max_half_open_connections": (lambda: deluge.common.windows_check() and
|
||||
'send_info': False,
|
||||
'info_sent': 0.0,
|
||||
'daemon_port': 58846,
|
||||
'allow_remote': False,
|
||||
'pre_allocate_storage': False,
|
||||
'download_location': deluge.common.get_default_download_dir(),
|
||||
'listen_ports': [6881, 6891],
|
||||
'listen_interface': '',
|
||||
'random_port': True,
|
||||
'listen_random_port': None,
|
||||
'listen_use_sys_port': False,
|
||||
'listen_reuse_port': True,
|
||||
'outgoing_ports': [0, 0],
|
||||
'random_outgoing_ports': True,
|
||||
'copy_torrent_file': False,
|
||||
'del_copy_torrent_file': False,
|
||||
'torrentfiles_location': deluge.common.get_default_download_dir(),
|
||||
'plugins_location': os.path.join(deluge.configmanager.get_config_dir(), 'plugins'),
|
||||
'prioritize_first_last_pieces': False,
|
||||
'sequential_download': False,
|
||||
'dht': True,
|
||||
'upnp': True,
|
||||
'natpmp': True,
|
||||
'utpex': True,
|
||||
'lsd': True,
|
||||
'enc_in_policy': 1,
|
||||
'enc_out_policy': 1,
|
||||
'enc_level': 2,
|
||||
'max_connections_global': 200,
|
||||
'max_upload_speed': -1.0,
|
||||
'max_download_speed': -1.0,
|
||||
'max_upload_slots_global': 4,
|
||||
'max_half_open_connections': (lambda: deluge.common.windows_check() and
|
||||
(lambda: deluge.common.vista_check() and 4 or 8)() or 50)(),
|
||||
"max_connections_per_second": 20,
|
||||
"ignore_limits_on_local_network": True,
|
||||
"max_connections_per_torrent": -1,
|
||||
"max_upload_slots_per_torrent": -1,
|
||||
"max_upload_speed_per_torrent": -1,
|
||||
"max_download_speed_per_torrent": -1,
|
||||
"enabled_plugins": [],
|
||||
"add_paused": False,
|
||||
"max_active_seeding": 5,
|
||||
"max_active_downloading": 3,
|
||||
"max_active_limit": 8,
|
||||
"dont_count_slow_torrents": False,
|
||||
"queue_new_to_top": False,
|
||||
"stop_seed_at_ratio": False,
|
||||
"remove_seed_at_ratio": False,
|
||||
"stop_seed_ratio": 2.00,
|
||||
"share_ratio_limit": 2.00,
|
||||
"seed_time_ratio_limit": 7.00,
|
||||
"seed_time_limit": 180,
|
||||
"auto_managed": True,
|
||||
"move_completed": False,
|
||||
"move_completed_path": deluge.common.get_default_download_dir(),
|
||||
"move_completed_paths_list": [],
|
||||
"download_location_paths_list": [],
|
||||
"path_chooser_show_chooser_button_on_localhost": True,
|
||||
"path_chooser_auto_complete_enabled": True,
|
||||
"path_chooser_accelerator_string": "Tab",
|
||||
"path_chooser_max_popup_rows": 20,
|
||||
"path_chooser_show_hidden_files": False,
|
||||
"new_release_check": True,
|
||||
"proxy": {
|
||||
"type": 0,
|
||||
"hostname": "",
|
||||
"username": "",
|
||||
"password": "",
|
||||
"port": 8080,
|
||||
"proxy_hostnames": True,
|
||||
"proxy_peer_connections": True,
|
||||
'max_connections_per_second': 20,
|
||||
'ignore_limits_on_local_network': True,
|
||||
'max_connections_per_torrent': -1,
|
||||
'max_upload_slots_per_torrent': -1,
|
||||
'max_upload_speed_per_torrent': -1,
|
||||
'max_download_speed_per_torrent': -1,
|
||||
'enabled_plugins': [],
|
||||
'add_paused': False,
|
||||
'max_active_seeding': 5,
|
||||
'max_active_downloading': 3,
|
||||
'max_active_limit': 8,
|
||||
'dont_count_slow_torrents': False,
|
||||
'queue_new_to_top': False,
|
||||
'stop_seed_at_ratio': False,
|
||||
'remove_seed_at_ratio': False,
|
||||
'stop_seed_ratio': 2.00,
|
||||
'share_ratio_limit': 2.00,
|
||||
'seed_time_ratio_limit': 7.00,
|
||||
'seed_time_limit': 180,
|
||||
'auto_managed': True,
|
||||
'move_completed': False,
|
||||
'move_completed_path': deluge.common.get_default_download_dir(),
|
||||
'move_completed_paths_list': [],
|
||||
'download_location_paths_list': [],
|
||||
'path_chooser_show_chooser_button_on_localhost': True,
|
||||
'path_chooser_auto_complete_enabled': True,
|
||||
'path_chooser_accelerator_string': 'Tab',
|
||||
'path_chooser_max_popup_rows': 20,
|
||||
'path_chooser_show_hidden_files': False,
|
||||
'new_release_check': True,
|
||||
'proxy': {
|
||||
'type': 0,
|
||||
'hostname': '',
|
||||
'username': '',
|
||||
'password': '',
|
||||
'port': 8080,
|
||||
'proxy_hostnames': True,
|
||||
'proxy_peer_connections': True,
|
||||
},
|
||||
"i2p_proxy": {
|
||||
"hostname": "",
|
||||
"port": 0
|
||||
'i2p_proxy': {
|
||||
'hostname': '',
|
||||
'port': 0
|
||||
},
|
||||
"peer_tos": "0x00",
|
||||
"rate_limit_ip_overhead": True,
|
||||
"anonymous_mode": False,
|
||||
"geoip_db_location": "/usr/share/GeoIP/GeoIP.dat",
|
||||
"cache_size": 512,
|
||||
"cache_expiry": 60,
|
||||
"auto_manage_prefer_seeds": False,
|
||||
"shared": False,
|
||||
"super_seeding": False,
|
||||
"priority": 0
|
||||
'peer_tos': '0x00',
|
||||
'rate_limit_ip_overhead': True,
|
||||
'anonymous_mode': False,
|
||||
'geoip_db_location': '/usr/share/GeoIP/GeoIP.dat',
|
||||
'cache_size': 512,
|
||||
'cache_expiry': 60,
|
||||
'auto_manage_prefer_seeds': False,
|
||||
'shared': False,
|
||||
'super_seeding': False,
|
||||
'priority': 0
|
||||
}
|
||||
|
||||
|
||||
class PreferencesManager(component.Component):
|
||||
def __init__(self):
|
||||
component.Component.__init__(self, "PreferencesManager")
|
||||
self.config = deluge.configmanager.ConfigManager("core.conf", DEFAULT_PREFS)
|
||||
if "proxies" in self.config:
|
||||
component.Component.__init__(self, 'PreferencesManager')
|
||||
self.config = deluge.configmanager.ConfigManager('core.conf', DEFAULT_PREFS)
|
||||
if 'proxies' in self.config:
|
||||
log.warning("Updating config file for proxy, using 'peer' values to fill new 'proxy' setting")
|
||||
self.config["proxy"].update(self.config["proxies"]['peer'])
|
||||
log.warning("New proxy config is: %s", self.config["proxy"])
|
||||
del self.config["proxies"]
|
||||
self.config['proxy'].update(self.config['proxies']['peer'])
|
||||
log.warning('New proxy config is: %s', self.config['proxy'])
|
||||
del self.config['proxies']
|
||||
|
||||
self.core = component.get("Core")
|
||||
self.session = component.get("Core").session
|
||||
self.core = component.get('Core')
|
||||
self.session = component.get('Core').session
|
||||
self.new_release_timer = None
|
||||
|
||||
def start(self):
|
||||
# Setup listen port followed by dht to ensure both use same port.
|
||||
self.__set_listen_on()
|
||||
self._on_set_dht("dht", self.config["dht"])
|
||||
self._on_set_dht('dht', self.config['dht'])
|
||||
|
||||
# Set the initial preferences on start-up
|
||||
for key in DEFAULT_PREFS:
|
||||
# Listen port and dht already setup in correct order so skip running again.
|
||||
if key in ("dht", "random_port") or key.startswith("listen_"):
|
||||
if key in ('dht', 'random_port') or key.startswith('listen_'):
|
||||
continue
|
||||
self.do_config_set_func(key, self.config[key])
|
||||
|
||||
@ -153,10 +153,10 @@ class PreferencesManager(component.Component):
|
||||
|
||||
# Config set functions
|
||||
def do_config_set_func(self, key, value):
|
||||
on_set_func = getattr(self, "_on_set_" + key, None)
|
||||
on_set_func = getattr(self, '_on_set_' + key, None)
|
||||
if on_set_func:
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Config key: %s set to %s..", key, value)
|
||||
log.debug('Config key: %s set to %s..', key, value)
|
||||
on_set_func(key, value)
|
||||
|
||||
def session_set_setting(self, key, value):
|
||||
@ -164,27 +164,27 @@ class PreferencesManager(component.Component):
|
||||
self.session.apply_settings({key: value})
|
||||
except AttributeError:
|
||||
# Deprecated in libtorrent 1.1
|
||||
if key in ("enable_lsd", "enable_upnp", "enable_natpmp", "enable_dht"):
|
||||
start_stop = key.replace("enable", "start") if value else key.replace("enable", "stop")
|
||||
if key in ('enable_lsd', 'enable_upnp', 'enable_natpmp', 'enable_dht'):
|
||||
start_stop = key.replace('enable', 'start') if value else key.replace('enable', 'stop')
|
||||
getattr(self.session, start_stop)()
|
||||
elif key == "dht_bootstrap_nodes":
|
||||
self.session.add_dht_router("router.bittorrent.com", 6881)
|
||||
self.session.add_dht_router("router.utorrent.com", 6881)
|
||||
self.session.add_dht_router("router.bitcomet.com", 6881)
|
||||
elif key == 'dht_bootstrap_nodes':
|
||||
self.session.add_dht_router('router.bittorrent.com', 6881)
|
||||
self.session.add_dht_router('router.utorrent.com', 6881)
|
||||
self.session.add_dht_router('router.bitcomet.com', 6881)
|
||||
else:
|
||||
self.session.set_settings({key: value})
|
||||
|
||||
def _on_config_value_change(self, key, value):
|
||||
if self.get_state() == "Started":
|
||||
if self.get_state() == 'Started':
|
||||
self.do_config_set_func(key, value)
|
||||
component.get("EventManager").emit(ConfigValueChangedEvent(key, value))
|
||||
component.get('EventManager').emit(ConfigValueChangedEvent(key, value))
|
||||
|
||||
def _on_set_torrentfiles_location(self, key, value):
|
||||
if self.config["copy_torrent_file"]:
|
||||
if self.config['copy_torrent_file']:
|
||||
try:
|
||||
os.makedirs(value)
|
||||
except OSError as ex:
|
||||
log.debug("Unable to make directory: %s", ex)
|
||||
log.debug('Unable to make directory: %s', ex)
|
||||
|
||||
def _on_set_listen_ports(self, key, value):
|
||||
self.__set_listen_on()
|
||||
@ -197,35 +197,35 @@ class PreferencesManager(component.Component):
|
||||
|
||||
def __set_listen_on(self):
|
||||
""" Set the ports and interface address to listen for incoming connections on."""
|
||||
if self.config["random_port"]:
|
||||
if not self.config["listen_random_port"]:
|
||||
self.config["listen_random_port"] = random.randrange(49152, 65525)
|
||||
listen_ports = [self.config["listen_random_port"]] * 2 # use single port range
|
||||
if self.config['random_port']:
|
||||
if not self.config['listen_random_port']:
|
||||
self.config['listen_random_port'] = random.randrange(49152, 65525)
|
||||
listen_ports = [self.config['listen_random_port']] * 2 # use single port range
|
||||
else:
|
||||
self.config["listen_random_port"] = None
|
||||
listen_ports = self.config["listen_ports"]
|
||||
self.config['listen_random_port'] = None
|
||||
listen_ports = self.config['listen_ports']
|
||||
|
||||
interface = str(self.config["listen_interface"].strip())
|
||||
interface = str(self.config['listen_interface'].strip())
|
||||
|
||||
log.debug("Listen Interface: %s, Ports: %s with use_sys_port: %s",
|
||||
interface, listen_ports, self.config["listen_use_sys_port"])
|
||||
log.debug('Listen Interface: %s, Ports: %s with use_sys_port: %s',
|
||||
interface, listen_ports, self.config['listen_use_sys_port'])
|
||||
try:
|
||||
interfaces = ["%s:%s" % (interface, port) for port in range(listen_ports[0], listen_ports[1]+1)]
|
||||
self.session.apply_setting({"listen_system_port_fallback", self.config["listen_use_sys_port"]})
|
||||
self.session.apply_setting({"listen_interfaces", interfaces})
|
||||
interfaces = ['%s:%s' % (interface, port) for port in range(listen_ports[0], listen_ports[1]+1)]
|
||||
self.session.apply_setting({'listen_system_port_fallback', self.config['listen_use_sys_port']})
|
||||
self.session.apply_setting({'listen_interfaces', interfaces})
|
||||
except AttributeError:
|
||||
# Deprecated in libtorrent 1.1
|
||||
# If a single port range then always enable re-use port flag.
|
||||
reuse_port = True if listen_ports[0] == listen_ports[1] else self.config["listen_reuse_port"]
|
||||
reuse_port = True if listen_ports[0] == listen_ports[1] else self.config['listen_reuse_port']
|
||||
flags = ((lt.listen_on_flags_t.listen_no_system_port
|
||||
if not self.config["listen_use_sys_port"] else 0) |
|
||||
if not self.config['listen_use_sys_port'] else 0) |
|
||||
(lt.listen_on_flags_t.listen_reuse_address
|
||||
if reuse_port else 0))
|
||||
try:
|
||||
self.session.listen_on(listen_ports[0], listen_ports[1], interface, flags)
|
||||
except RuntimeError as ex:
|
||||
if ex.message == "Invalid Argument":
|
||||
log.error("Error setting listen interface (must be IP Address): %s %s-%s",
|
||||
if ex.message == 'Invalid Argument':
|
||||
log.error('Error setting listen interface (must be IP Address): %s %s-%s',
|
||||
interface, listen_ports[0], listen_ports[1])
|
||||
|
||||
def _on_set_outgoing_ports(self, key, value):
|
||||
@ -235,34 +235,34 @@ class PreferencesManager(component.Component):
|
||||
self.__set_outgoing_ports()
|
||||
|
||||
def __set_outgoing_ports(self):
|
||||
ports = [0, 0] if self.config["random_outgoing_ports"] else self.config["outgoing_ports"]
|
||||
log.debug("Outgoing ports set to %s", ports)
|
||||
self.session_set_setting("outgoing_ports", (ports[0], ports[1]))
|
||||
ports = [0, 0] if self.config['random_outgoing_ports'] else self.config['outgoing_ports']
|
||||
log.debug('Outgoing ports set to %s', ports)
|
||||
self.session_set_setting('outgoing_ports', (ports[0], ports[1]))
|
||||
|
||||
def _on_set_peer_tos(self, key, value):
|
||||
try:
|
||||
self.session_set_setting("peer_tos", chr(int(value, 16)))
|
||||
self.session_set_setting('peer_tos', chr(int(value, 16)))
|
||||
except ValueError as ex:
|
||||
log.debug("Invalid tos byte: %s", ex)
|
||||
log.debug('Invalid tos byte: %s', ex)
|
||||
return
|
||||
|
||||
def _on_set_dht(self, key, value):
|
||||
dht_bootstraps = "router.bittorrent.com:6881,router.utorrent.com:6881,router.bitcomet.com:6881"
|
||||
self.session_set_setting("dht_bootstrap_nodes", dht_bootstraps)
|
||||
self.session_set_setting("enable_dht", value)
|
||||
dht_bootstraps = 'router.bittorrent.com:6881,router.utorrent.com:6881,router.bitcomet.com:6881'
|
||||
self.session_set_setting('dht_bootstrap_nodes', dht_bootstraps)
|
||||
self.session_set_setting('enable_dht', value)
|
||||
|
||||
def _on_set_upnp(self, key, value):
|
||||
self.session_set_setting("enable_upnp", value)
|
||||
self.session_set_setting('enable_upnp', value)
|
||||
|
||||
def _on_set_natpmp(self, key, value):
|
||||
self.session_set_setting("enable_natpmp", value)
|
||||
self.session_set_setting('enable_natpmp', value)
|
||||
|
||||
def _on_set_lsd(self, key, value):
|
||||
self.session_set_setting("enable_lsd", value)
|
||||
self.session_set_setting('enable_lsd', value)
|
||||
|
||||
def _on_set_utpex(self, key, value):
|
||||
if value:
|
||||
self.session.add_extension("ut_pex")
|
||||
self.session.add_extension('ut_pex')
|
||||
|
||||
def _on_set_enc_in_policy(self, key, value):
|
||||
self._on_set_encryption(key, value)
|
||||
@ -277,76 +277,76 @@ class PreferencesManager(component.Component):
|
||||
# Convert Deluge enc_level values to libtorrent enc_level values.
|
||||
pe_enc_level = {0: lt.enc_level.plaintext, 1: lt.enc_level.rc4, 2: lt.enc_level.both}
|
||||
try:
|
||||
self.session.apply_setting("out_enc_policy", lt.enc_policy(self.config["enc_out_policy"]))
|
||||
self.session.apply_setting("in_enc_policy", lt.enc_policy(self.config["enc_in_policy"]))
|
||||
self.session.apply_setting("allowed_enc_level", lt.enc_level(pe_enc_level[self.config["enc_level"]]))
|
||||
self.session.apply_setting("prefer_rc4", True)
|
||||
self.session.apply_setting('out_enc_policy', lt.enc_policy(self.config['enc_out_policy']))
|
||||
self.session.apply_setting('in_enc_policy', lt.enc_policy(self.config['enc_in_policy']))
|
||||
self.session.apply_setting('allowed_enc_level', lt.enc_level(pe_enc_level[self.config['enc_level']]))
|
||||
self.session.apply_setting('prefer_rc4', True)
|
||||
except AttributeError:
|
||||
# Deprecated in libtorrent 1.1
|
||||
pe_settings = lt.pe_settings()
|
||||
pe_settings.out_enc_policy = lt.enc_policy(self.config["enc_out_policy"])
|
||||
pe_settings.in_enc_policy = lt.enc_policy(self.config["enc_in_policy"])
|
||||
pe_settings.allowed_enc_level = lt.enc_level(pe_enc_level[self.config["enc_level"]])
|
||||
pe_settings.out_enc_policy = lt.enc_policy(self.config['enc_out_policy'])
|
||||
pe_settings.in_enc_policy = lt.enc_policy(self.config['enc_in_policy'])
|
||||
pe_settings.allowed_enc_level = lt.enc_level(pe_enc_level[self.config['enc_level']])
|
||||
pe_settings.prefer_rc4 = True
|
||||
self.session.set_pe_settings(pe_settings)
|
||||
pe_sess_settings = self.session.get_pe_settings()
|
||||
log.debug("encryption settings:\n\t\t\tout_policy: %s\n\t\t\
|
||||
in_policy: %s\n\t\t\tlevel: %s\n\t\t\tprefer_rc4: %s",
|
||||
log.debug('encryption settings:\n\t\t\tout_policy: %s\n\t\t\
|
||||
in_policy: %s\n\t\t\tlevel: %s\n\t\t\tprefer_rc4: %s',
|
||||
pe_sess_settings.out_enc_policy,
|
||||
pe_sess_settings.in_enc_policy,
|
||||
pe_sess_settings.allowed_enc_level,
|
||||
pe_sess_settings.prefer_rc4)
|
||||
|
||||
def _on_set_max_connections_global(self, key, value):
|
||||
self.session_set_setting("connections_limit", value)
|
||||
self.session_set_setting('connections_limit', value)
|
||||
|
||||
def _on_set_max_upload_speed(self, key, value):
|
||||
# We need to convert Kb/s to B/s
|
||||
value = -1 if value < 0 else int(value * 1024)
|
||||
self.session_set_setting("upload_rate_limit", value)
|
||||
self.session_set_setting('upload_rate_limit', value)
|
||||
|
||||
def _on_set_max_download_speed(self, key, value):
|
||||
# We need to convert Kb/s to B/s
|
||||
value = -1 if value < 0 else int(value * 1024)
|
||||
self.session_set_setting("download_rate_limit", value)
|
||||
self.session_set_setting('download_rate_limit', value)
|
||||
|
||||
def _on_set_max_upload_slots_global(self, key, value):
|
||||
self.session_set_setting("unchoke_slots_limit", value)
|
||||
self.session_set_setting('unchoke_slots_limit', value)
|
||||
|
||||
def _on_set_max_half_open_connections(self, key, value):
|
||||
self.session_set_setting("half_open_limit", value)
|
||||
self.session_set_setting('half_open_limit', value)
|
||||
|
||||
def _on_set_max_connections_per_second(self, key, value):
|
||||
self.session_set_setting("connection_speed", value)
|
||||
self.session_set_setting('connection_speed', value)
|
||||
|
||||
def _on_set_ignore_limits_on_local_network(self, key, value):
|
||||
self.session_set_setting("ignore_limits_on_local_network", value)
|
||||
self.session_set_setting('ignore_limits_on_local_network', value)
|
||||
|
||||
def _on_set_share_ratio_limit(self, key, value):
|
||||
self.session_set_setting("share_ratio_limit", value)
|
||||
self.session_set_setting('share_ratio_limit', value)
|
||||
|
||||
def _on_set_seed_time_ratio_limit(self, key, value):
|
||||
self.session_set_setting("seed_time_ratio_limit", value)
|
||||
self.session_set_setting('seed_time_ratio_limit', value)
|
||||
|
||||
def _on_set_seed_time_limit(self, key, value):
|
||||
# This value is stored in minutes in deluge, but libtorrent wants seconds
|
||||
self.session_set_setting("seed_time_limit", int(value * 60))
|
||||
self.session_set_setting('seed_time_limit', int(value * 60))
|
||||
|
||||
def _on_set_max_active_downloading(self, key, value):
|
||||
self.session_set_setting("active_downloads", value)
|
||||
self.session_set_setting('active_downloads', value)
|
||||
|
||||
def _on_set_max_active_seeding(self, key, value):
|
||||
self.session_set_setting("active_seeds", value)
|
||||
self.session_set_setting('active_seeds', value)
|
||||
|
||||
def _on_set_max_active_limit(self, key, value):
|
||||
self.session_set_setting("active_limit", value)
|
||||
self.session_set_setting('active_limit', value)
|
||||
|
||||
def _on_set_dont_count_slow_torrents(self, key, value):
|
||||
self.session_set_setting("dont_count_slow_torrents", value)
|
||||
self.session_set_setting('dont_count_slow_torrents', value)
|
||||
|
||||
def _on_set_send_info(self, key, value):
|
||||
"""sends anonymous stats home"""
|
||||
log.debug("Sending anonymous stats..")
|
||||
log.debug('Sending anonymous stats..')
|
||||
|
||||
class SendInfoThread(threading.Thread):
|
||||
def __init__(self, config):
|
||||
@ -357,33 +357,33 @@ class PreferencesManager(component.Component):
|
||||
import time
|
||||
now = time.time()
|
||||
# check if we've done this within the last week or never
|
||||
if (now - self.config["info_sent"]) >= (60 * 60 * 24 * 7):
|
||||
if (now - self.config['info_sent']) >= (60 * 60 * 24 * 7):
|
||||
from urllib import quote_plus
|
||||
from urllib2 import urlopen
|
||||
import platform
|
||||
try:
|
||||
url = "http://deluge-torrent.org/stats_get.php?processor=" + \
|
||||
platform.machine() + "&python=" + platform.python_version() \
|
||||
+ "&deluge=" + deluge.common.get_version() \
|
||||
+ "&os=" + platform.system() \
|
||||
+ "&plugins=" + quote_plus(":".join(self.config["enabled_plugins"]))
|
||||
url = 'http://deluge-torrent.org/stats_get.php?processor=' + \
|
||||
platform.machine() + '&python=' + platform.python_version() \
|
||||
+ '&deluge=' + deluge.common.get_version() \
|
||||
+ '&os=' + platform.system() \
|
||||
+ '&plugins=' + quote_plus(':'.join(self.config['enabled_plugins']))
|
||||
urlopen(url)
|
||||
except IOError as ex:
|
||||
log.debug("Network error while trying to send info: %s", ex)
|
||||
log.debug('Network error while trying to send info: %s', ex)
|
||||
else:
|
||||
self.config["info_sent"] = now
|
||||
self.config['info_sent'] = now
|
||||
if value:
|
||||
SendInfoThread(self.config).start()
|
||||
|
||||
def _on_set_new_release_check(self, key, value):
|
||||
if value:
|
||||
log.debug("Checking for new release..")
|
||||
log.debug('Checking for new release..')
|
||||
threading.Thread(target=self.core.get_new_release).start()
|
||||
if self.new_release_timer and self.new_release_timer.running:
|
||||
self.new_release_timer.stop()
|
||||
# Set a timer to check for a new release every 3 days
|
||||
self.new_release_timer = LoopingCall(
|
||||
self._on_set_new_release_check, "new_release_check", True)
|
||||
self._on_set_new_release_check, 'new_release_check', True)
|
||||
self.new_release_timer.start(72 * 60 * 60, False)
|
||||
else:
|
||||
if self.new_release_timer and self.new_release_timer.running:
|
||||
@ -391,46 +391,46 @@ class PreferencesManager(component.Component):
|
||||
|
||||
def _on_set_proxy(self, key, value):
|
||||
try:
|
||||
if key == "i2p_proxy":
|
||||
self.session.apply_settings("proxy_type", lt.proxy_type("i2p_proxy"))
|
||||
self.session.apply_settings("i2p_hostname", value["hostname"])
|
||||
self.session.apply_settings("i2p_port", value["port"])
|
||||
if key == 'i2p_proxy':
|
||||
self.session.apply_settings('proxy_type', lt.proxy_type('i2p_proxy'))
|
||||
self.session.apply_settings('i2p_hostname', value['hostname'])
|
||||
self.session.apply_settings('i2p_port', value['port'])
|
||||
else:
|
||||
self.session.apply_settings("proxy_type", lt.proxy_type(value["type"]))
|
||||
self.session.apply_settings("proxy_hostname", value["hostname"])
|
||||
self.session.apply_settings("proxy_port", value["port"])
|
||||
self.session.apply_settings("proxy_username", value["username"])
|
||||
self.session.apply_settings("proxy_password", value["password"])
|
||||
self.session.apply_settings("proxy_hostnames", value["proxy_hostnames"])
|
||||
self.session.apply_settings("proxy_peer_connections", value["proxy_peer_connections"])
|
||||
self.session.apply_settings("proxy_tracker_connections", value["proxy_tracker_connections"])
|
||||
self.session.apply_settings('proxy_type', lt.proxy_type(value['type']))
|
||||
self.session.apply_settings('proxy_hostname', value['hostname'])
|
||||
self.session.apply_settings('proxy_port', value['port'])
|
||||
self.session.apply_settings('proxy_username', value['username'])
|
||||
self.session.apply_settings('proxy_password', value['password'])
|
||||
self.session.apply_settings('proxy_hostnames', value['proxy_hostnames'])
|
||||
self.session.apply_settings('proxy_peer_connections', value['proxy_peer_connections'])
|
||||
self.session.apply_settings('proxy_tracker_connections', value['proxy_tracker_connections'])
|
||||
except AttributeError:
|
||||
proxy_settings = lt.proxy_settings()
|
||||
proxy_settings.hostname = value["hostname"]
|
||||
proxy_settings.port = value["port"]
|
||||
if key == "i2p_proxy":
|
||||
proxy_settings.hostname = value['hostname']
|
||||
proxy_settings.port = value['port']
|
||||
if key == 'i2p_proxy':
|
||||
try:
|
||||
self.session.set_i2p_proxy(proxy_settings)
|
||||
except RuntimeError as ex:
|
||||
log.error("Unable to set I2P Proxy: %s", ex)
|
||||
log.error('Unable to set I2P Proxy: %s', ex)
|
||||
else:
|
||||
proxy_settings.type = lt.proxy_type(value["type"])
|
||||
proxy_settings.username = value["username"]
|
||||
proxy_settings.password = value["password"]
|
||||
proxy_settings.hostname = value["hostname"]
|
||||
proxy_settings.port = value["port"]
|
||||
proxy_settings.proxy_hostnames = value["proxy_hostnames"]
|
||||
proxy_settings.proxy_peer_connections = value["proxy_peer_connections"]
|
||||
proxy_settings.type = lt.proxy_type(value['type'])
|
||||
proxy_settings.username = value['username']
|
||||
proxy_settings.password = value['password']
|
||||
proxy_settings.hostname = value['hostname']
|
||||
proxy_settings.port = value['port']
|
||||
proxy_settings.proxy_hostnames = value['proxy_hostnames']
|
||||
proxy_settings.proxy_peer_connections = value['proxy_peer_connections']
|
||||
self.session.set_proxy(proxy_settings)
|
||||
|
||||
def _on_set_i2p_proxy(self, key, value):
|
||||
self._on_set_proxy(key, value)
|
||||
|
||||
def _on_set_rate_limit_ip_overhead(self, key, value):
|
||||
self.session_set_setting("rate_limit_ip_overhead", value)
|
||||
self.session_set_setting('rate_limit_ip_overhead', value)
|
||||
|
||||
def _on_set_anonymous_mode(self, key, value):
|
||||
self.session_set_setting("anonymous_mode", value)
|
||||
self.session_set_setting('anonymous_mode', value)
|
||||
|
||||
def _on_set_geoip_db_location(self, key, geoipdb_path):
|
||||
# Load the GeoIP DB for country look-ups if available
|
||||
@ -438,15 +438,15 @@ class PreferencesManager(component.Component):
|
||||
try:
|
||||
self.core.geoip_instance = GeoIP.open(geoipdb_path, GeoIP.GEOIP_STANDARD)
|
||||
except AttributeError:
|
||||
log.warning("GeoIP Unavailable")
|
||||
log.warning('GeoIP Unavailable')
|
||||
else:
|
||||
log.warning("Unable to find GeoIP database file: %s", geoipdb_path)
|
||||
log.warning('Unable to find GeoIP database file: %s', geoipdb_path)
|
||||
|
||||
def _on_set_cache_size(self, key, value):
|
||||
self.session_set_setting("cache_size", value)
|
||||
self.session_set_setting('cache_size', value)
|
||||
|
||||
def _on_set_cache_expiry(self, key, value):
|
||||
self.session_set_setting("cache_expiry", value)
|
||||
self.session_set_setting('cache_expiry', value)
|
||||
|
||||
def _on_auto_manage_prefer_seeds(self, key, value):
|
||||
self.session_set_setting("auto_manage_prefer_seeds", value)
|
||||
self.session_set_setting('auto_manage_prefer_seeds', value)
|
||||
|
||||
@ -49,7 +49,7 @@ def export(auth_level=AUTH_LEVEL_DEFAULT):
|
||||
func._rpcserver_export = True
|
||||
func._rpcserver_auth_level = auth_level
|
||||
doc = func.__doc__
|
||||
func.__doc__ = "**RPC Exported Function** (*Auth Level: %s*)\n\n" % auth_level
|
||||
func.__doc__ = '**RPC Exported Function** (*Auth Level: %s*)\n\n' % auth_level
|
||||
if doc:
|
||||
func.__doc__ += doc
|
||||
|
||||
@ -75,16 +75,16 @@ def format_request(call):
|
||||
|
||||
"""
|
||||
try:
|
||||
s = call[1] + "("
|
||||
s = call[1] + '('
|
||||
if call[2]:
|
||||
s += ", ".join([str(x) for x in call[2]])
|
||||
s += ', '.join([str(x) for x in call[2]])
|
||||
if call[3]:
|
||||
if call[2]:
|
||||
s += ", "
|
||||
s += ", ".join([key + "=" + str(value) for key, value in call[3].items()])
|
||||
s += ")"
|
||||
s += ', '
|
||||
s += ', '.join([key + '=' + str(value) for key, value in call[3].items()])
|
||||
s += ')'
|
||||
except UnicodeEncodeError:
|
||||
return "UnicodeEncodeError, call: %s" % call
|
||||
return 'UnicodeEncodeError, call: %s' % call
|
||||
else:
|
||||
return s
|
||||
|
||||
@ -97,11 +97,11 @@ class ServerContextFactory(object):
|
||||
This loads the servers cert/private key SSL files for use with the
|
||||
SSL transport.
|
||||
"""
|
||||
ssl_dir = deluge.configmanager.get_config_dir("ssl")
|
||||
ssl_dir = deluge.configmanager.get_config_dir('ssl')
|
||||
ctx = SSL.Context(SSL.SSLv23_METHOD)
|
||||
ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3)
|
||||
ctx.use_certificate_file(os.path.join(ssl_dir, "daemon.cert"))
|
||||
ctx.use_privatekey_file(os.path.join(ssl_dir, "daemon.pkey"))
|
||||
ctx.use_certificate_file(os.path.join(ssl_dir, 'daemon.cert'))
|
||||
ctx.use_privatekey_file(os.path.join(ssl_dir, 'daemon.pkey'))
|
||||
return ctx
|
||||
|
||||
|
||||
@ -118,17 +118,17 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
|
||||
"""
|
||||
if not isinstance(request, tuple):
|
||||
log.debug("Received invalid message: type is not tuple")
|
||||
log.debug('Received invalid message: type is not tuple')
|
||||
return
|
||||
|
||||
if len(request) < 1:
|
||||
log.debug("Received invalid message: there are no items")
|
||||
log.debug('Received invalid message: there are no items')
|
||||
return
|
||||
|
||||
for call in request:
|
||||
if len(call) != 4:
|
||||
log.debug("Received invalid rpc request: number of items "
|
||||
"in request is %s", len(call))
|
||||
log.debug('Received invalid rpc request: number of items '
|
||||
'in request is %s', len(call))
|
||||
continue
|
||||
# log.debug("RPCRequest: %s", format_request(call))
|
||||
reactor.callLater(0, self.dispatch, *call)
|
||||
@ -145,7 +145,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
try:
|
||||
self.transfer_message(data)
|
||||
except Exception as ex:
|
||||
log.warn("Error occurred when sending message: %s.", ex)
|
||||
log.warn('Error occurred when sending message: %s.', ex)
|
||||
log.exception(ex)
|
||||
raise
|
||||
|
||||
@ -154,7 +154,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
This method is called when a new client connects.
|
||||
"""
|
||||
peer = self.transport.getPeer()
|
||||
log.info("Deluge Client connection made from: %s:%s",
|
||||
log.info('Deluge Client connection made from: %s:%s',
|
||||
peer.host, peer.port)
|
||||
# Set the initial auth level of this session to AUTH_LEVEL_NONE
|
||||
self.factory.authorized_sessions[self.transport.sessionno] = AUTH_LEVEL_NONE
|
||||
@ -175,9 +175,9 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
if self.transport.sessionno in self.factory.interested_events:
|
||||
del self.factory.interested_events[self.transport.sessionno]
|
||||
|
||||
if self.factory.state == "running":
|
||||
component.get("EventManager").emit(ClientDisconnectedEvent(self.factory.session_id))
|
||||
log.info("Deluge client disconnected: %s", reason.value)
|
||||
if self.factory.state == 'running':
|
||||
component.get('EventManager').emit(ClientDisconnectedEvent(self.factory.session_id))
|
||||
log.info('Deluge client disconnected: %s', reason.value)
|
||||
|
||||
def valid_session(self):
|
||||
return self.transport.sessionno in self.factory.authorized_sessions
|
||||
@ -215,29 +215,29 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
))
|
||||
except AttributeError:
|
||||
# This is not a deluge exception (object has no attribute '_args), let's wrap it
|
||||
log.warning("An exception occurred while sending RPC_ERROR to "
|
||||
"client. Wrapping it and resending. Error to "
|
||||
"send(causing exception goes next):\n%s", formated_tb)
|
||||
log.warning('An exception occurred while sending RPC_ERROR to '
|
||||
'client. Wrapping it and resending. Error to '
|
||||
'send(causing exception goes next):\n%s', formated_tb)
|
||||
try:
|
||||
raise WrappedException(str(exceptionValue), exceptionType.__name__, formated_tb)
|
||||
except WrappedException:
|
||||
send_error()
|
||||
except Exception as ex:
|
||||
log.error("An exception occurred while sending RPC_ERROR to client: %s", ex)
|
||||
log.error('An exception occurred while sending RPC_ERROR to client: %s', ex)
|
||||
|
||||
if method == "daemon.info":
|
||||
if method == 'daemon.info':
|
||||
# This is a special case and used in the initial connection process
|
||||
self.sendData((RPC_RESPONSE, request_id, deluge.common.get_version()))
|
||||
return
|
||||
elif method == "daemon.login":
|
||||
elif method == 'daemon.login':
|
||||
# This is a special case and used in the initial connection process
|
||||
# We need to authenticate the user here
|
||||
log.debug("RPC dispatch daemon.login")
|
||||
log.debug('RPC dispatch daemon.login')
|
||||
try:
|
||||
client_version = kwargs.pop('client_version', None)
|
||||
if client_version is None:
|
||||
raise IncompatibleClient(deluge.common.get_version())
|
||||
ret = component.get("AuthManager").authorize(*args, **kwargs)
|
||||
ret = component.get('AuthManager').authorize(*args, **kwargs)
|
||||
if ret:
|
||||
self.factory.authorized_sessions[self.transport.sessionno] = (ret, args[0])
|
||||
self.factory.session_protocols[self.transport.sessionno] = self
|
||||
@ -255,8 +255,8 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
if not self.valid_session():
|
||||
return
|
||||
|
||||
if method == "daemon.set_event_interest":
|
||||
log.debug("RPC dispatch daemon.set_event_interest")
|
||||
if method == 'daemon.set_event_interest':
|
||||
log.debug('RPC dispatch daemon.set_event_interest')
|
||||
# This special case is to allow clients to set which events they are
|
||||
# interested in receiving.
|
||||
# We are expecting a sequence from the client.
|
||||
@ -278,13 +278,13 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
send_error()
|
||||
return
|
||||
|
||||
log.debug("RPC dispatch %s", method)
|
||||
log.debug('RPC dispatch %s', method)
|
||||
try:
|
||||
method_auth_requirement = self.factory.methods[method]._rpcserver_auth_level
|
||||
auth_level = self.factory.authorized_sessions[self.transport.sessionno][0]
|
||||
if auth_level < method_auth_requirement:
|
||||
# This session is not allowed to call this method
|
||||
log.debug("Session %s is attempting an unauthorized method call!",
|
||||
log.debug('Session %s is attempting an unauthorized method call!',
|
||||
self.transport.sessionno)
|
||||
raise NotAuthorizedError(auth_level, method_auth_requirement)
|
||||
# Set the session_id in the factory so that methods can know
|
||||
@ -296,7 +296,7 @@ class DelugeRPCProtocol(DelugeTransferProtocol):
|
||||
# Don't bother printing out DelugeErrors, because they are just
|
||||
# for the client
|
||||
if not isinstance(ex, DelugeError):
|
||||
log.exception("Exception calling RPC request: %s", ex)
|
||||
log.exception('Exception calling RPC request: %s', ex)
|
||||
else:
|
||||
# Check if the return value is a deferred, since we'll need to
|
||||
# wait for it to fire before sending the RPC_RESPONSE
|
||||
@ -336,13 +336,13 @@ class RPCServer(component.Component):
|
||||
:type listen: bool
|
||||
"""
|
||||
|
||||
def __init__(self, port=58846, interface="", allow_remote=False, listen=True):
|
||||
component.Component.__init__(self, "RPCServer")
|
||||
def __init__(self, port=58846, interface='', allow_remote=False, listen=True):
|
||||
component.Component.__init__(self, 'RPCServer')
|
||||
|
||||
self.factory = Factory()
|
||||
self.factory.protocol = DelugeRPCProtocol
|
||||
self.factory.session_id = -1
|
||||
self.factory.state = "running"
|
||||
self.factory.state = 'running'
|
||||
|
||||
# Holds the registered methods
|
||||
self.factory.methods = {}
|
||||
@ -358,14 +358,14 @@ class RPCServer(component.Component):
|
||||
return
|
||||
|
||||
if allow_remote:
|
||||
hostname = ""
|
||||
hostname = ''
|
||||
else:
|
||||
hostname = "localhost"
|
||||
hostname = 'localhost'
|
||||
|
||||
if interface:
|
||||
hostname = interface
|
||||
|
||||
log.info("Starting DelugeRPC server %s:%s", hostname, port)
|
||||
log.info('Starting DelugeRPC server %s:%s', hostname, port)
|
||||
|
||||
# Check for SSL keys and generate some if needed
|
||||
check_ssl_keys()
|
||||
@ -373,7 +373,7 @@ class RPCServer(component.Component):
|
||||
try:
|
||||
reactor.listenSSL(port, self.factory, ServerContextFactory(), interface=hostname)
|
||||
except Exception as ex:
|
||||
log.info("Daemon already running or port not available.")
|
||||
log.info('Daemon already running or port not available.')
|
||||
log.error(ex)
|
||||
raise
|
||||
|
||||
@ -391,11 +391,11 @@ class RPCServer(component.Component):
|
||||
name = obj.__class__.__name__.lower()
|
||||
|
||||
for d in dir(obj):
|
||||
if d[0] == "_":
|
||||
if d[0] == '_':
|
||||
continue
|
||||
if getattr(getattr(obj, d), '_rpcserver_export', False):
|
||||
log.debug("Registering method: %s", name + "." + d)
|
||||
self.factory.methods[name + "." + d] = getattr(obj, d)
|
||||
log.debug('Registering method: %s', name + '.' + d)
|
||||
self.factory.methods[name + '.' + d] = getattr(obj, d)
|
||||
|
||||
def deregister_object(self, obj):
|
||||
"""
|
||||
@ -450,13 +450,13 @@ class RPCServer(component.Component):
|
||||
|
||||
"""
|
||||
if not self.listen:
|
||||
return "localclient"
|
||||
return 'localclient'
|
||||
session_id = self.get_session_id()
|
||||
if session_id > -1 and session_id in self.factory.authorized_sessions:
|
||||
return self.factory.authorized_sessions[session_id][1]
|
||||
else:
|
||||
# No connections made yet
|
||||
return ""
|
||||
return ''
|
||||
|
||||
def get_session_auth_level(self):
|
||||
"""
|
||||
@ -498,11 +498,11 @@ class RPCServer(component.Component):
|
||||
:param event: the event to emit
|
||||
:type event: :class:`deluge.event.DelugeEvent`
|
||||
"""
|
||||
log.debug("intevents: %s", self.factory.interested_events)
|
||||
log.debug('intevents: %s', self.factory.interested_events)
|
||||
# Find sessions interested in this event
|
||||
for session_id, interest in self.factory.interested_events.items():
|
||||
if event.name in interest:
|
||||
log.debug("Emit Event: %s %s", event.name, event.args)
|
||||
log.debug('Emit Event: %s %s', event.name, event.args)
|
||||
# This session is interested so send a RPC_EVENT
|
||||
self.factory.session_protocols[session_id].sendData(
|
||||
(RPC_EVENT, event.name, event.args)
|
||||
@ -532,20 +532,20 @@ class RPCServer(component.Component):
|
||||
self.factory.session_protocols[session_id].sendData((RPC_EVENT, event.name, event.args))
|
||||
|
||||
def stop(self):
|
||||
self.factory.state = "stopping"
|
||||
self.factory.state = 'stopping'
|
||||
|
||||
|
||||
def check_ssl_keys():
|
||||
"""
|
||||
Check for SSL cert/key and create them if necessary
|
||||
"""
|
||||
ssl_dir = deluge.configmanager.get_config_dir("ssl")
|
||||
ssl_dir = deluge.configmanager.get_config_dir('ssl')
|
||||
if not os.path.exists(ssl_dir):
|
||||
# The ssl folder doesn't exist so we need to create it
|
||||
os.makedirs(ssl_dir)
|
||||
generate_ssl_keys()
|
||||
else:
|
||||
for f in ("daemon.pkey", "daemon.cert"):
|
||||
for f in ('daemon.pkey', 'daemon.cert'):
|
||||
if not os.path.exists(os.path.join(ssl_dir, f)):
|
||||
generate_ssl_keys()
|
||||
break
|
||||
@ -555,7 +555,7 @@ def generate_ssl_keys():
|
||||
"""
|
||||
This method generates a new SSL key/cert.
|
||||
"""
|
||||
digest = "sha256"
|
||||
digest = 'sha256'
|
||||
# Generate key pair
|
||||
pkey = crypto.PKey()
|
||||
pkey.generate_key(crypto.TYPE_RSA, 2048)
|
||||
@ -563,7 +563,7 @@ def generate_ssl_keys():
|
||||
# Generate cert request
|
||||
req = crypto.X509Req()
|
||||
subj = req.get_subject()
|
||||
setattr(subj, "CN", "Deluge Daemon")
|
||||
setattr(subj, 'CN', 'Deluge Daemon')
|
||||
req.set_pubkey(pkey)
|
||||
req.sign(pkey, digest)
|
||||
|
||||
@ -578,11 +578,11 @@ def generate_ssl_keys():
|
||||
cert.sign(pkey, digest)
|
||||
|
||||
# Write out files
|
||||
ssl_dir = deluge.configmanager.get_config_dir("ssl")
|
||||
with open(os.path.join(ssl_dir, "daemon.pkey"), "w") as _file:
|
||||
ssl_dir = deluge.configmanager.get_config_dir('ssl')
|
||||
with open(os.path.join(ssl_dir, 'daemon.pkey'), 'w') as _file:
|
||||
_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
|
||||
with open(os.path.join(ssl_dir, "daemon.cert"), "w") as _file:
|
||||
with open(os.path.join(ssl_dir, 'daemon.cert'), 'w') as _file:
|
||||
_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
|
||||
# Make the files only readable by this user
|
||||
for f in ("daemon.pkey", "daemon.cert"):
|
||||
for f in ('daemon.pkey', 'daemon.cert'):
|
||||
os.chmod(os.path.join(ssl_dir, f), stat.S_IREAD | stat.S_IWRITE)
|
||||
|
||||
@ -34,14 +34,14 @@ from deluge.event import TorrentFolderRenamedEvent, TorrentStateChangedEvent, To
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
LT_TORRENT_STATE_MAP = {
|
||||
"queued_for_checking": "Checking",
|
||||
"checking_files": "Checking",
|
||||
"downloading_metadata": "Downloading",
|
||||
"downloading": "Downloading",
|
||||
"finished": "Seeding",
|
||||
"seeding": "Seeding",
|
||||
"allocating": "Allocating",
|
||||
"checking_resume_data": "Checking"
|
||||
'queued_for_checking': 'Checking',
|
||||
'checking_files': 'Checking',
|
||||
'downloading_metadata': 'Downloading',
|
||||
'downloading': 'Downloading',
|
||||
'finished': 'Seeding',
|
||||
'seeding': 'Seeding',
|
||||
'allocating': 'Allocating',
|
||||
'checking_resume_data': 'Checking'
|
||||
}
|
||||
|
||||
|
||||
@ -57,19 +57,19 @@ def sanitize_filepath(filepath, folder=False):
|
||||
def clean_filename(filename):
|
||||
"""Strips whitespace and discards dotted filenames"""
|
||||
filename = filename.strip()
|
||||
if filename.replace(".", "") == "":
|
||||
return ""
|
||||
if filename.replace('.', '') == '':
|
||||
return ''
|
||||
return filename
|
||||
|
||||
if "\\" in filepath or "/" in filepath:
|
||||
folderpath = filepath.replace("\\", "/").split("/")
|
||||
if '\\' in filepath or '/' in filepath:
|
||||
folderpath = filepath.replace('\\', '/').split('/')
|
||||
folderpath = [clean_filename(x) for x in folderpath]
|
||||
newfilepath = "/".join([path for path in folderpath if path])
|
||||
newfilepath = '/'.join([path for path in folderpath if path])
|
||||
else:
|
||||
newfilepath = clean_filename(filepath)
|
||||
|
||||
if folder is True:
|
||||
newfilepath += "/"
|
||||
newfilepath += '/'
|
||||
|
||||
return newfilepath
|
||||
|
||||
@ -95,10 +95,10 @@ def convert_lt_files(files):
|
||||
filelist = []
|
||||
for index, _file in enumerate(files):
|
||||
filelist.append({
|
||||
"index": index,
|
||||
"path": _file.path.decode("utf8").replace("\\", "/"),
|
||||
"size": _file.size,
|
||||
"offset": _file.offset
|
||||
'index': index,
|
||||
'path': _file.path.decode('utf8').replace('\\', '/'),
|
||||
'size': _file.size,
|
||||
'offset': _file.offset
|
||||
})
|
||||
|
||||
return filelist
|
||||
@ -139,34 +139,34 @@ class TorrentOptions(dict):
|
||||
"""
|
||||
def __init__(self):
|
||||
super(TorrentOptions, self).__init__()
|
||||
config = ConfigManager("core.conf").config
|
||||
config = ConfigManager('core.conf').config
|
||||
options_conf_map = {
|
||||
"max_connections": "max_connections_per_torrent",
|
||||
"max_upload_slots": "max_upload_slots_per_torrent",
|
||||
"max_upload_speed": "max_upload_speed_per_torrent",
|
||||
"max_download_speed": "max_download_speed_per_torrent",
|
||||
"prioritize_first_last_pieces": "prioritize_first_last_pieces",
|
||||
"sequential_download": "sequential_download",
|
||||
"pre_allocate_storage": "pre_allocate_storage",
|
||||
"download_location": "download_location",
|
||||
"auto_managed": "auto_managed",
|
||||
"stop_at_ratio": "stop_seed_at_ratio",
|
||||
"stop_ratio": "stop_seed_ratio",
|
||||
"remove_at_ratio": "remove_seed_at_ratio",
|
||||
"move_completed": "move_completed",
|
||||
"move_completed_path": "move_completed_path",
|
||||
"add_paused": "add_paused",
|
||||
"shared": "shared",
|
||||
"super_seeding": "super_seeding",
|
||||
"priority": "priority",
|
||||
'max_connections': 'max_connections_per_torrent',
|
||||
'max_upload_slots': 'max_upload_slots_per_torrent',
|
||||
'max_upload_speed': 'max_upload_speed_per_torrent',
|
||||
'max_download_speed': 'max_download_speed_per_torrent',
|
||||
'prioritize_first_last_pieces': 'prioritize_first_last_pieces',
|
||||
'sequential_download': 'sequential_download',
|
||||
'pre_allocate_storage': 'pre_allocate_storage',
|
||||
'download_location': 'download_location',
|
||||
'auto_managed': 'auto_managed',
|
||||
'stop_at_ratio': 'stop_seed_at_ratio',
|
||||
'stop_ratio': 'stop_seed_ratio',
|
||||
'remove_at_ratio': 'remove_seed_at_ratio',
|
||||
'move_completed': 'move_completed',
|
||||
'move_completed_path': 'move_completed_path',
|
||||
'add_paused': 'add_paused',
|
||||
'shared': 'shared',
|
||||
'super_seeding': 'super_seeding',
|
||||
'priority': 'priority',
|
||||
}
|
||||
for opt_k, conf_k in options_conf_map.iteritems():
|
||||
self[opt_k] = config[conf_k]
|
||||
self["file_priorities"] = []
|
||||
self["mapped_files"] = {}
|
||||
self["owner"] = ""
|
||||
self["name"] = ""
|
||||
self["seed_mode"] = False
|
||||
self['file_priorities'] = []
|
||||
self['mapped_files'] = {}
|
||||
self['owner'] = ''
|
||||
self['name'] = ''
|
||||
self['seed_mode'] = False
|
||||
|
||||
|
||||
class TorrentError(object):
|
||||
@ -216,11 +216,11 @@ class Torrent(object):
|
||||
def __init__(self, handle, options, state=None, filename=None, magnet=None):
|
||||
self.torrent_id = str(handle.info_hash())
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Creating torrent object %s", self.torrent_id)
|
||||
log.debug('Creating torrent object %s', self.torrent_id)
|
||||
|
||||
# Get the core config
|
||||
self.config = ConfigManager("core.conf")
|
||||
self.rpcserver = component.get("RPCServer")
|
||||
self.config = ConfigManager('core.conf')
|
||||
self.rpcserver = component.get('RPCServer')
|
||||
|
||||
self.handle = handle
|
||||
self.handle.resolve_countries(True)
|
||||
@ -253,7 +253,7 @@ class Torrent(object):
|
||||
self.state = None
|
||||
self.moving_storage = False
|
||||
self.moving_storage_dest_path = None
|
||||
self.tracker_status = ""
|
||||
self.tracker_status = ''
|
||||
self.tracker_host = None
|
||||
self.forcing_recheck = False
|
||||
self.forcing_recheck_paused = False
|
||||
@ -267,13 +267,13 @@ class Torrent(object):
|
||||
self.update_state()
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Torrent object created.")
|
||||
log.debug('Torrent object created.')
|
||||
|
||||
def on_metadata_received(self):
|
||||
"""Process the metadata received alert for this torrent"""
|
||||
self.has_metadata = True
|
||||
self.torrent_info = self.handle.get_torrent_info()
|
||||
if self.options["prioritize_first_last_pieces"]:
|
||||
if self.options['prioritize_first_last_pieces']:
|
||||
self.set_prioritize_first_last_pieces(True)
|
||||
self.write_torrentfile()
|
||||
|
||||
@ -286,13 +286,13 @@ class Torrent(object):
|
||||
"""
|
||||
# set_prioritize_first_last is called by set_file_priorities so only run if not in options
|
||||
skip_func = []
|
||||
if "file_priorities" in options:
|
||||
self.options["prioritize_first_last_pieces"] = options["prioritize_first_last_pieces"]
|
||||
skip_func.append("prioritize_first_last_pieces")
|
||||
if 'file_priorities' in options:
|
||||
self.options['prioritize_first_last_pieces'] = options['prioritize_first_last_pieces']
|
||||
skip_func.append('prioritize_first_last_pieces')
|
||||
|
||||
for key, value in options.items():
|
||||
if key in self.options:
|
||||
options_set_func = getattr(self, "set_" + key, None)
|
||||
options_set_func = getattr(self, 'set_' + key, None)
|
||||
if options_set_func and key not in skip_func:
|
||||
options_set_func(value)
|
||||
else:
|
||||
@ -323,7 +323,7 @@ class Torrent(object):
|
||||
elif max_connections == 1:
|
||||
max_connections = 2
|
||||
|
||||
self.options["max_connections"] = max_connections
|
||||
self.options['max_connections'] = max_connections
|
||||
self.handle.set_max_connections(max_connections)
|
||||
|
||||
def set_max_upload_slots(self, max_slots):
|
||||
@ -332,7 +332,7 @@ class Torrent(object):
|
||||
Args:
|
||||
max_slots (int): Maximum upload slots
|
||||
"""
|
||||
self.options["max_upload_slots"] = max_slots
|
||||
self.options['max_upload_slots'] = max_slots
|
||||
self.handle.set_max_uploads(max_slots)
|
||||
|
||||
def set_max_upload_speed(self, m_up_speed):
|
||||
@ -341,7 +341,7 @@ class Torrent(object):
|
||||
Args:
|
||||
m_up_speed (float): Maximum upload speed in KiB/s.
|
||||
"""
|
||||
self.options["max_upload_speed"] = m_up_speed
|
||||
self.options['max_upload_speed'] = m_up_speed
|
||||
if m_up_speed < 0:
|
||||
value = -1
|
||||
else:
|
||||
@ -354,7 +354,7 @@ class Torrent(object):
|
||||
Args:
|
||||
m_up_speed (float): Maximum download speed in KiB/s.
|
||||
"""
|
||||
self.options["max_download_speed"] = m_down_speed
|
||||
self.options['max_download_speed'] = m_down_speed
|
||||
if m_down_speed < 0:
|
||||
value = -1
|
||||
else:
|
||||
@ -374,11 +374,11 @@ class Torrent(object):
|
||||
Returns:
|
||||
tuple of lists: The prioritized pieces and the torrent piece priorities.
|
||||
"""
|
||||
self.options["prioritize_first_last_pieces"] = prioritize
|
||||
self.options['prioritize_first_last_pieces'] = prioritize
|
||||
if not prioritize:
|
||||
# If we are turning off this option, call set_file_priorities to
|
||||
# reset all the piece priorities
|
||||
self.set_file_priorities(self.options["file_priorities"])
|
||||
self.set_file_priorities(self.options['file_priorities'])
|
||||
return None, None
|
||||
if not self.has_metadata:
|
||||
return None, None
|
||||
@ -414,7 +414,7 @@ class Torrent(object):
|
||||
Args:
|
||||
set_sequencial (bool): Enable sequencial downloading.
|
||||
"""
|
||||
self.options["sequential_download"] = set_sequencial
|
||||
self.options['sequential_download'] = set_sequencial
|
||||
self.handle.set_sequential_download(set_sequencial)
|
||||
|
||||
def set_auto_managed(self, auto_managed):
|
||||
@ -423,7 +423,7 @@ class Torrent(object):
|
||||
Args:
|
||||
auto_managed (bool): Enable auto managed.
|
||||
"""
|
||||
self.options["auto_managed"] = auto_managed
|
||||
self.options['auto_managed'] = auto_managed
|
||||
if not (self.status.paused and not self.status.auto_managed):
|
||||
self.handle.auto_managed(auto_managed)
|
||||
self.update_state()
|
||||
@ -435,10 +435,10 @@ class Torrent(object):
|
||||
super_seeding (bool): Enable super seeding.
|
||||
"""
|
||||
if self.status.is_seeding:
|
||||
self.options["super_seeding"] = super_seeding
|
||||
self.options['super_seeding'] = super_seeding
|
||||
self.handle.super_seeding(super_seeding)
|
||||
else:
|
||||
self.options["super_seeding"] = False
|
||||
self.options['super_seeding'] = False
|
||||
|
||||
def set_stop_ratio(self, stop_ratio):
|
||||
"""The seeding ratio to stop (or remove) the torrent at.
|
||||
@ -446,7 +446,7 @@ class Torrent(object):
|
||||
Args:
|
||||
stop_ratio (float): The seeding ratio.
|
||||
"""
|
||||
self.options["stop_ratio"] = stop_ratio
|
||||
self.options['stop_ratio'] = stop_ratio
|
||||
|
||||
def set_stop_at_ratio(self, stop_at_ratio):
|
||||
"""Stop the torrent when it has reached stop_ratio.
|
||||
@ -454,7 +454,7 @@ class Torrent(object):
|
||||
Args:
|
||||
stop_at_ratio (bool): Stop the torrent.
|
||||
"""
|
||||
self.options["stop_at_ratio"] = stop_at_ratio
|
||||
self.options['stop_at_ratio'] = stop_at_ratio
|
||||
|
||||
def set_remove_at_ratio(self, remove_at_ratio):
|
||||
"""Remove the torrent when it has reached the stop_ratio.
|
||||
@ -462,7 +462,7 @@ class Torrent(object):
|
||||
Args:
|
||||
remove_at_ratio (bool): Remove the torrent.
|
||||
"""
|
||||
self.options["remove_at_ratio"] = remove_at_ratio
|
||||
self.options['remove_at_ratio'] = remove_at_ratio
|
||||
|
||||
def set_move_completed(self, move_completed):
|
||||
"""Set whether to move the torrent when downloading has finished.
|
||||
@ -471,7 +471,7 @@ class Torrent(object):
|
||||
move_completed (bool): Move the torrent.
|
||||
|
||||
"""
|
||||
self.options["move_completed"] = move_completed
|
||||
self.options['move_completed'] = move_completed
|
||||
|
||||
def set_move_completed_path(self, move_completed_path):
|
||||
"""Set the path to move torrent to when downloading has finished.
|
||||
@ -479,7 +479,7 @@ class Torrent(object):
|
||||
Args:
|
||||
move_completed_path (str): The move path.
|
||||
"""
|
||||
self.options["move_completed_path"] = move_completed_path
|
||||
self.options['move_completed_path'] = move_completed_path
|
||||
|
||||
def set_file_priorities(self, file_priorities):
|
||||
"""Sets the file priotities.
|
||||
@ -490,8 +490,8 @@ class Torrent(object):
|
||||
if not self.has_metadata:
|
||||
return
|
||||
if len(file_priorities) != self.torrent_info.num_files():
|
||||
log.debug("file_priorities len != num_files")
|
||||
self.options["file_priorities"] = self.handle.file_priorities()
|
||||
log.debug('file_priorities len != num_files')
|
||||
self.options['file_priorities'] = self.handle.file_priorities()
|
||||
return
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
@ -499,10 +499,10 @@ class Torrent(object):
|
||||
|
||||
self.handle.prioritize_files(file_priorities)
|
||||
|
||||
if 0 in self.options["file_priorities"]:
|
||||
if 0 in self.options['file_priorities']:
|
||||
# We have previously marked a file 'Do Not Download'
|
||||
# Check to see if we have changed any 0's to >0 and change state accordingly
|
||||
for index, priority in enumerate(self.options["file_priorities"]):
|
||||
for index, priority in enumerate(self.options['file_priorities']):
|
||||
if priority == 0 and file_priorities[index] > 0:
|
||||
# We have a changed 'Do Not Download' to a download priority
|
||||
self.is_finished = False
|
||||
@ -511,11 +511,11 @@ class Torrent(object):
|
||||
|
||||
# In case values in file_priorities were faulty (old state?)
|
||||
# we make sure the stored options are in sync
|
||||
self.options["file_priorities"] = self.handle.file_priorities()
|
||||
self.options['file_priorities'] = self.handle.file_priorities()
|
||||
|
||||
# Set the first/last priorities if needed
|
||||
if self.options["prioritize_first_last_pieces"]:
|
||||
self.set_prioritize_first_last_pieces(self.options["prioritize_first_last_pieces"])
|
||||
if self.options['prioritize_first_last_pieces']:
|
||||
self.set_prioritize_first_last_pieces(self.options['prioritize_first_last_pieces'])
|
||||
|
||||
def set_save_path(self, download_location):
|
||||
"""Deprecated, use set_download_location."""
|
||||
@ -523,7 +523,7 @@ class Torrent(object):
|
||||
|
||||
def set_download_location(self, download_location):
|
||||
"""The location for downloading torrent data."""
|
||||
self.options["download_location"] = download_location
|
||||
self.options['download_location'] = download_location
|
||||
|
||||
def set_priority(self, priority):
|
||||
"""Sets the bandwidth priority of this torrent.
|
||||
@ -537,10 +537,10 @@ class Torrent(object):
|
||||
ValueError: If value of priority is not in range [0..255]
|
||||
"""
|
||||
if 0 <= priority <= 255:
|
||||
self.options["priority"] = priority
|
||||
self.options['priority'] = priority
|
||||
return self.handle.set_priority(priority)
|
||||
else:
|
||||
raise ValueError("Torrent priority, %s, is invalid, should be [0..255]", priority)
|
||||
raise ValueError('Torrent priority, %s, is invalid, should be [0..255]', priority)
|
||||
|
||||
def set_owner(self, account):
|
||||
"""Sets the owner of this torrent.
|
||||
@ -548,7 +548,7 @@ class Torrent(object):
|
||||
Only a user with admin level auth can change this value.
|
||||
"""
|
||||
if self.rpcserver.get_session_auth_level() == AUTH_LEVEL_ADMIN:
|
||||
self.options["owner"] = account
|
||||
self.options['owner'] = account
|
||||
|
||||
# End Options methods #
|
||||
|
||||
@ -564,21 +564,21 @@ class Torrent(object):
|
||||
return
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Setting trackers for %s: %s", self.torrent_id, trackers)
|
||||
log.debug('Setting trackers for %s: %s', self.torrent_id, trackers)
|
||||
|
||||
tracker_list = []
|
||||
|
||||
for tracker in trackers:
|
||||
new_entry = lt.announce_entry(str(tracker["url"]))
|
||||
new_entry.tier = tracker["tier"]
|
||||
new_entry = lt.announce_entry(str(tracker['url']))
|
||||
new_entry.tier = tracker['tier']
|
||||
tracker_list.append(new_entry)
|
||||
self.handle.replace_trackers(tracker_list)
|
||||
|
||||
# Print out the trackers
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Trackers set for %s:", self.torrent_id)
|
||||
log.debug('Trackers set for %s:', self.torrent_id)
|
||||
for tracker in self.handle.trackers():
|
||||
log.debug(" [tier %s]: %s", tracker["tier"], tracker["url"])
|
||||
log.debug(' [tier %s]: %s', tracker['tier'], tracker['url'])
|
||||
# Set the tracker list in the torrent object
|
||||
self.trackers = trackers
|
||||
if len(trackers) > 0:
|
||||
@ -601,26 +601,26 @@ class Torrent(object):
|
||||
|
||||
if self.tracker_status != status:
|
||||
self.tracker_status = status
|
||||
component.get("EventManager").emit(TorrentTrackerStatusEvent(self.torrent_id, self.tracker_status))
|
||||
component.get('EventManager').emit(TorrentTrackerStatusEvent(self.torrent_id, self.tracker_status))
|
||||
|
||||
def merge_trackers(self, torrent_info):
|
||||
"""Merges new trackers in torrent_info into torrent"""
|
||||
log.info("Adding any new trackers to torrent (%s) already in session...", self.torrent_id)
|
||||
log.info('Adding any new trackers to torrent (%s) already in session...', self.torrent_id)
|
||||
if not torrent_info:
|
||||
return
|
||||
# Don't merge trackers if either torrent has private flag set.
|
||||
if torrent_info.priv() or self.get_status(["private"])["private"]:
|
||||
log.info("Adding trackers aborted: Torrent has private flag set.")
|
||||
if torrent_info.priv() or self.get_status(['private'])['private']:
|
||||
log.info('Adding trackers aborted: Torrent has private flag set.')
|
||||
else:
|
||||
for tracker in torrent_info.trackers():
|
||||
self.handle.add_tracker({"url": tracker.url, "tier": tracker.tier})
|
||||
self.handle.add_tracker({'url': tracker.url, 'tier': tracker.tier})
|
||||
# Update torrent.trackers from libtorrent handle.
|
||||
self.set_trackers()
|
||||
|
||||
def update_state(self):
|
||||
"""Updates the state, based on libtorrent's torrent state"""
|
||||
status = self.handle.status()
|
||||
session_paused = component.get("Core").session.is_paused()
|
||||
session_paused = component.get('Core').session.is_paused()
|
||||
old_state = self.state
|
||||
self.set_status_message()
|
||||
try:
|
||||
@ -630,30 +630,30 @@ class Torrent(object):
|
||||
status_error = status.error
|
||||
|
||||
if self.forced_error:
|
||||
self.state = "Error"
|
||||
self.state = 'Error'
|
||||
self.set_status_message(self.forced_error.error_message)
|
||||
elif status_error:
|
||||
self.state = "Error"
|
||||
self.state = 'Error'
|
||||
# auto-manage status will be reverted upon resuming.
|
||||
self.handle.auto_managed(False)
|
||||
self.set_status_message(decode_string(status_error))
|
||||
elif self.moving_storage:
|
||||
self.state = "Moving"
|
||||
self.state = 'Moving'
|
||||
elif not session_paused and status.paused and status.auto_managed:
|
||||
self.state = "Queued"
|
||||
self.state = 'Queued'
|
||||
elif session_paused or status.paused:
|
||||
self.state = "Paused"
|
||||
self.state = 'Paused'
|
||||
else:
|
||||
self.state = LT_TORRENT_STATE_MAP.get(str(status.state), str(status.state))
|
||||
|
||||
if self.state != old_state:
|
||||
component.get("EventManager").emit(TorrentStateChangedEvent(self.torrent_id, self.state))
|
||||
component.get('EventManager').emit(TorrentStateChangedEvent(self.torrent_id, self.state))
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("State from lt was: %s | Session is paused: %s\nTorrent state set from '%s' to '%s' (%s)",
|
||||
"error" if status_error else status.state, session_paused, old_state, self.state, self.torrent_id)
|
||||
'error' if status_error else status.state, session_paused, old_state, self.state, self.torrent_id)
|
||||
if self.forced_error:
|
||||
log.debug("Torrent Error state message: %s", self.forced_error.error_message)
|
||||
log.debug('Torrent Error state message: %s', self.forced_error.error_message)
|
||||
|
||||
def set_status_message(self, message=None):
|
||||
"""Sets the torrent status message.
|
||||
@ -665,7 +665,7 @@ class Torrent(object):
|
||||
|
||||
"""
|
||||
if not message:
|
||||
message = "OK"
|
||||
message = 'OK'
|
||||
self.statusmsg = message
|
||||
|
||||
def force_error_state(self, message, restart_to_resume=True):
|
||||
@ -690,12 +690,12 @@ class Torrent(object):
|
||||
return
|
||||
|
||||
if self.forced_error.restart_to_resume:
|
||||
log.error("Restart deluge to clear this torrent error")
|
||||
log.error('Restart deluge to clear this torrent error')
|
||||
|
||||
if not self.forced_error.was_paused and self.options["auto_managed"]:
|
||||
if not self.forced_error.was_paused and self.options['auto_managed']:
|
||||
self.handle.auto_managed(True)
|
||||
self.forced_error = None
|
||||
self.set_status_message("OK")
|
||||
self.set_status_message('OK')
|
||||
if update_state:
|
||||
self.update_state()
|
||||
|
||||
@ -708,9 +708,9 @@ class Torrent(object):
|
||||
"""
|
||||
status = self.status
|
||||
eta = 0
|
||||
if self.is_finished and self.options["stop_at_ratio"] and status.upload_payload_rate:
|
||||
if self.is_finished and self.options['stop_at_ratio'] and status.upload_payload_rate:
|
||||
# We're a seed, so calculate the time to the 'stop_share_ratio'
|
||||
eta = ((status.all_time_download * self.options["stop_ratio"]) -
|
||||
eta = ((status.all_time_download * self.options['stop_ratio']) -
|
||||
status.all_time_upload) // status.upload_payload_rate
|
||||
elif status.download_payload_rate:
|
||||
left = status.total_wanted - status.total_wanted_done
|
||||
@ -788,20 +788,20 @@ class Torrent(object):
|
||||
client = decode_string(peer.client)
|
||||
|
||||
try:
|
||||
country = component.get("Core").geoip_instance.country_code_by_addr(peer.ip[0])
|
||||
country = component.get('Core').geoip_instance.country_code_by_addr(peer.ip[0])
|
||||
except AttributeError:
|
||||
country = ""
|
||||
country = ''
|
||||
else:
|
||||
country = "".join([char if char.isalpha() else " " for char in country])
|
||||
country = ''.join([char if char.isalpha() else ' ' for char in country])
|
||||
|
||||
ret.append({
|
||||
"client": client,
|
||||
"country": country,
|
||||
"down_speed": peer.payload_down_speed,
|
||||
"ip": "%s:%s" % (peer.ip[0], peer.ip[1]),
|
||||
"progress": peer.progress,
|
||||
"seed": peer.flags & peer.seed,
|
||||
"up_speed": peer.payload_up_speed,
|
||||
'client': client,
|
||||
'country': country,
|
||||
'down_speed': peer.payload_down_speed,
|
||||
'ip': '%s:%s' % (peer.ip[0], peer.ip[1]),
|
||||
'progress': peer.progress,
|
||||
'seed': peer.flags & peer.seed,
|
||||
'up_speed': peer.payload_up_speed,
|
||||
})
|
||||
|
||||
return ret
|
||||
@ -838,12 +838,12 @@ class Torrent(object):
|
||||
|
||||
tracker = self.status.current_tracker
|
||||
if not tracker and self.trackers:
|
||||
tracker = self.trackers[0]["url"]
|
||||
tracker = self.trackers[0]['url']
|
||||
|
||||
if tracker:
|
||||
url = urlparse(tracker.replace("udp://", "http://"))
|
||||
if hasattr(url, "hostname"):
|
||||
host = (url.hostname or "DHT")
|
||||
url = urlparse(tracker.replace('udp://', 'http://'))
|
||||
if hasattr(url, 'hostname'):
|
||||
host = (url.hostname or 'DHT')
|
||||
# Check if hostname is an IP address and just return it if that's the case
|
||||
try:
|
||||
socket.inet_aton(host)
|
||||
@ -853,15 +853,15 @@ class Torrent(object):
|
||||
# This is an IP address because an exception wasn't raised
|
||||
return url.hostname
|
||||
|
||||
parts = host.split(".")
|
||||
parts = host.split('.')
|
||||
if len(parts) > 2:
|
||||
if parts[-2] in ("co", "com", "net", "org") or parts[-1] == "uk":
|
||||
host = ".".join(parts[-3:])
|
||||
if parts[-2] in ('co', 'com', 'net', 'org') or parts[-1] == 'uk':
|
||||
host = '.'.join(parts[-3:])
|
||||
else:
|
||||
host = ".".join(parts[-2:])
|
||||
host = '.'.join(parts[-2:])
|
||||
self.tracker_host = host
|
||||
return host
|
||||
return ""
|
||||
return ''
|
||||
|
||||
def get_magnet_uri(self):
|
||||
"""Returns a magnet uri for this torrent"""
|
||||
@ -878,14 +878,14 @@ class Torrent(object):
|
||||
str: the name of the torrent.
|
||||
|
||||
"""
|
||||
if not self.options["name"]:
|
||||
if not self.options['name']:
|
||||
handle_name = self.handle.name()
|
||||
if handle_name:
|
||||
name = decode_string(handle_name)
|
||||
else:
|
||||
name = self.torrent_id
|
||||
else:
|
||||
name = self.options["name"]
|
||||
name = self.options['name']
|
||||
|
||||
return name
|
||||
|
||||
@ -902,12 +902,12 @@ class Torrent(object):
|
||||
files = [os.path.join(path, f) for f in files]
|
||||
return sum(os.stat(f).st_size for f in files if os.path.exists(f))
|
||||
|
||||
if self.state == "Error":
|
||||
if self.state == 'Error':
|
||||
progress = 100.0
|
||||
elif self.moving_storage:
|
||||
# Check if torrent has downloaded any data yet.
|
||||
if self.status.total_done:
|
||||
torrent_files = [f["path"] for f in self.get_files()]
|
||||
torrent_files = [f['path'] for f in self.get_files()]
|
||||
dest_path_size = get_size(torrent_files, self.moving_storage_dest_path)
|
||||
progress = dest_path_size / self.status.total_done * 100
|
||||
else:
|
||||
@ -972,81 +972,81 @@ class Torrent(object):
|
||||
def _create_status_funcs(self):
|
||||
"""Creates the functions for getting torrent status"""
|
||||
self.status_funcs = {
|
||||
"active_time": lambda: self.status.active_time,
|
||||
"seeding_time": lambda: self.status.seeding_time,
|
||||
"finished_time": lambda: self.status.finished_time,
|
||||
"all_time_download": lambda: self.status.all_time_download,
|
||||
"storage_mode": lambda: self.status.storage_mode.name.split("_")[2], # sparse or allocate
|
||||
"distributed_copies": lambda: max(0.0, self.status.distributed_copies),
|
||||
"download_payload_rate": lambda: self.status.download_payload_rate,
|
||||
"file_priorities": lambda: self.options["file_priorities"],
|
||||
"hash": lambda: self.torrent_id,
|
||||
"is_auto_managed": lambda: self.options["auto_managed"],
|
||||
"is_finished": lambda: self.is_finished,
|
||||
"max_connections": lambda: self.options["max_connections"],
|
||||
"max_download_speed": lambda: self.options["max_download_speed"],
|
||||
"max_upload_slots": lambda: self.options["max_upload_slots"],
|
||||
"max_upload_speed": lambda: self.options["max_upload_speed"],
|
||||
"message": lambda: self.statusmsg,
|
||||
"move_on_completed_path": lambda: self.options["move_completed_path"], # Depr, use move_completed_path
|
||||
"move_on_completed": lambda: self.options["move_completed"], # Deprecated, use move_completed
|
||||
"move_completed_path": lambda: self.options["move_completed_path"],
|
||||
"move_completed": lambda: self.options["move_completed"],
|
||||
"next_announce": lambda: self.status.next_announce.seconds,
|
||||
"num_peers": lambda: self.status.num_peers - self.status.num_seeds,
|
||||
"num_seeds": lambda: self.status.num_seeds,
|
||||
"owner": lambda: self.options["owner"],
|
||||
"paused": lambda: self.status.paused,
|
||||
"prioritize_first_last": lambda: self.options["prioritize_first_last_pieces"],
|
||||
"sequential_download": lambda: self.options["sequential_download"],
|
||||
"progress": self.get_progress,
|
||||
"shared": lambda: self.options["shared"],
|
||||
"remove_at_ratio": lambda: self.options["remove_at_ratio"],
|
||||
"save_path": lambda: self.options["download_location"], # Deprecated, use download_location
|
||||
"download_location": lambda: self.options["download_location"],
|
||||
"seeds_peers_ratio": lambda: -1.0 if self.status.num_incomplete == 0 else ( # Use -1.0 to signify infinity
|
||||
'active_time': lambda: self.status.active_time,
|
||||
'seeding_time': lambda: self.status.seeding_time,
|
||||
'finished_time': lambda: self.status.finished_time,
|
||||
'all_time_download': lambda: self.status.all_time_download,
|
||||
'storage_mode': lambda: self.status.storage_mode.name.split('_')[2], # sparse or allocate
|
||||
'distributed_copies': lambda: max(0.0, self.status.distributed_copies),
|
||||
'download_payload_rate': lambda: self.status.download_payload_rate,
|
||||
'file_priorities': lambda: self.options['file_priorities'],
|
||||
'hash': lambda: self.torrent_id,
|
||||
'is_auto_managed': lambda: self.options['auto_managed'],
|
||||
'is_finished': lambda: self.is_finished,
|
||||
'max_connections': lambda: self.options['max_connections'],
|
||||
'max_download_speed': lambda: self.options['max_download_speed'],
|
||||
'max_upload_slots': lambda: self.options['max_upload_slots'],
|
||||
'max_upload_speed': lambda: self.options['max_upload_speed'],
|
||||
'message': lambda: self.statusmsg,
|
||||
'move_on_completed_path': lambda: self.options['move_completed_path'], # Depr, use move_completed_path
|
||||
'move_on_completed': lambda: self.options['move_completed'], # Deprecated, use move_completed
|
||||
'move_completed_path': lambda: self.options['move_completed_path'],
|
||||
'move_completed': lambda: self.options['move_completed'],
|
||||
'next_announce': lambda: self.status.next_announce.seconds,
|
||||
'num_peers': lambda: self.status.num_peers - self.status.num_seeds,
|
||||
'num_seeds': lambda: self.status.num_seeds,
|
||||
'owner': lambda: self.options['owner'],
|
||||
'paused': lambda: self.status.paused,
|
||||
'prioritize_first_last': lambda: self.options['prioritize_first_last_pieces'],
|
||||
'sequential_download': lambda: self.options['sequential_download'],
|
||||
'progress': self.get_progress,
|
||||
'shared': lambda: self.options['shared'],
|
||||
'remove_at_ratio': lambda: self.options['remove_at_ratio'],
|
||||
'save_path': lambda: self.options['download_location'], # Deprecated, use download_location
|
||||
'download_location': lambda: self.options['download_location'],
|
||||
'seeds_peers_ratio': lambda: -1.0 if self.status.num_incomplete == 0 else ( # Use -1.0 to signify infinity
|
||||
self.status.num_complete / self.status.num_incomplete),
|
||||
"seed_rank": lambda: self.status.seed_rank,
|
||||
"state": lambda: self.state,
|
||||
"stop_at_ratio": lambda: self.options["stop_at_ratio"],
|
||||
"stop_ratio": lambda: self.options["stop_ratio"],
|
||||
"time_added": lambda: self.status.added_time,
|
||||
"total_done": lambda: self.status.total_done,
|
||||
"total_payload_download": lambda: self.status.total_payload_download,
|
||||
"total_payload_upload": lambda: self.status.total_payload_upload,
|
||||
"total_peers": lambda: self.status.num_incomplete,
|
||||
"total_seeds": lambda: self.status.num_complete,
|
||||
"total_uploaded": lambda: self.status.all_time_upload,
|
||||
"total_wanted": lambda: self.status.total_wanted,
|
||||
"total_remaining": lambda: self.status.total_wanted - self.status.total_wanted_done,
|
||||
"tracker": lambda: self.status.current_tracker,
|
||||
"tracker_host": self.get_tracker_host,
|
||||
"trackers": lambda: self.trackers,
|
||||
"tracker_status": lambda: self.tracker_status,
|
||||
"upload_payload_rate": lambda: self.status.upload_payload_rate,
|
||||
"comment": lambda: decode_string(self.torrent_info.comment()) if self.has_metadata else "",
|
||||
"num_files": lambda: self.torrent_info.num_files() if self.has_metadata else 0,
|
||||
"num_pieces": lambda: self.torrent_info.num_pieces() if self.has_metadata else 0,
|
||||
"piece_length": lambda: self.torrent_info.piece_length() if self.has_metadata else 0,
|
||||
"private": lambda: self.torrent_info.priv() if self.has_metadata else False,
|
||||
"total_size": lambda: self.torrent_info.total_size() if self.has_metadata else 0,
|
||||
"eta": self.get_eta,
|
||||
"file_progress": self.get_file_progress,
|
||||
"files": self.get_files,
|
||||
"orig_files": self.get_orig_files,
|
||||
"is_seed": lambda: self.status.is_seeding,
|
||||
"peers": self.get_peers,
|
||||
"queue": lambda: self.status.queue_position,
|
||||
"ratio": self.get_ratio,
|
||||
"completed_time": lambda: self.status.completed_time,
|
||||
"last_seen_complete": lambda: self.status.last_seen_complete,
|
||||
"name": self.get_name,
|
||||
"pieces": self._get_pieces_info,
|
||||
"seed_mode": lambda: self.status.seed_mode,
|
||||
"super_seeding": lambda: self.status.super_seeding,
|
||||
"time_since_download": lambda: self.status.time_since_download,
|
||||
"time_since_upload": lambda: self.status.time_since_upload,
|
||||
"priority": lambda: self.status.priority,
|
||||
'seed_rank': lambda: self.status.seed_rank,
|
||||
'state': lambda: self.state,
|
||||
'stop_at_ratio': lambda: self.options['stop_at_ratio'],
|
||||
'stop_ratio': lambda: self.options['stop_ratio'],
|
||||
'time_added': lambda: self.status.added_time,
|
||||
'total_done': lambda: self.status.total_done,
|
||||
'total_payload_download': lambda: self.status.total_payload_download,
|
||||
'total_payload_upload': lambda: self.status.total_payload_upload,
|
||||
'total_peers': lambda: self.status.num_incomplete,
|
||||
'total_seeds': lambda: self.status.num_complete,
|
||||
'total_uploaded': lambda: self.status.all_time_upload,
|
||||
'total_wanted': lambda: self.status.total_wanted,
|
||||
'total_remaining': lambda: self.status.total_wanted - self.status.total_wanted_done,
|
||||
'tracker': lambda: self.status.current_tracker,
|
||||
'tracker_host': self.get_tracker_host,
|
||||
'trackers': lambda: self.trackers,
|
||||
'tracker_status': lambda: self.tracker_status,
|
||||
'upload_payload_rate': lambda: self.status.upload_payload_rate,
|
||||
'comment': lambda: decode_string(self.torrent_info.comment()) if self.has_metadata else '',
|
||||
'num_files': lambda: self.torrent_info.num_files() if self.has_metadata else 0,
|
||||
'num_pieces': lambda: self.torrent_info.num_pieces() if self.has_metadata else 0,
|
||||
'piece_length': lambda: self.torrent_info.piece_length() if self.has_metadata else 0,
|
||||
'private': lambda: self.torrent_info.priv() if self.has_metadata else False,
|
||||
'total_size': lambda: self.torrent_info.total_size() if self.has_metadata else 0,
|
||||
'eta': self.get_eta,
|
||||
'file_progress': self.get_file_progress,
|
||||
'files': self.get_files,
|
||||
'orig_files': self.get_orig_files,
|
||||
'is_seed': lambda: self.status.is_seeding,
|
||||
'peers': self.get_peers,
|
||||
'queue': lambda: self.status.queue_position,
|
||||
'ratio': self.get_ratio,
|
||||
'completed_time': lambda: self.status.completed_time,
|
||||
'last_seen_complete': lambda: self.status.last_seen_complete,
|
||||
'name': self.get_name,
|
||||
'pieces': self._get_pieces_info,
|
||||
'seed_mode': lambda: self.status.seed_mode,
|
||||
'super_seeding': lambda: self.status.super_seeding,
|
||||
'time_since_download': lambda: self.status.time_since_download,
|
||||
'time_since_upload': lambda: self.status.time_since_upload,
|
||||
'priority': lambda: self.status.priority,
|
||||
}
|
||||
|
||||
def pause(self):
|
||||
@ -1058,7 +1058,7 @@ class Torrent(object):
|
||||
"""
|
||||
# Turn off auto-management so the torrent will not be unpaused by lt queueing
|
||||
self.handle.auto_managed(False)
|
||||
if self.state == "Error":
|
||||
if self.state == 'Error':
|
||||
return False
|
||||
elif self.status.paused:
|
||||
# This torrent was probably paused due to being auto managed by lt
|
||||
@ -1066,37 +1066,37 @@ class Torrent(object):
|
||||
# show it as 'Paused'. We need to emit a torrent_paused signal because
|
||||
# the torrent_paused alert from libtorrent will not be generated.
|
||||
self.update_state()
|
||||
component.get("EventManager").emit(TorrentStateChangedEvent(self.torrent_id, "Paused"))
|
||||
component.get('EventManager').emit(TorrentStateChangedEvent(self.torrent_id, 'Paused'))
|
||||
else:
|
||||
try:
|
||||
self.handle.pause()
|
||||
except RuntimeError as ex:
|
||||
log.debug("Unable to pause torrent: %s", ex)
|
||||
log.debug('Unable to pause torrent: %s', ex)
|
||||
return False
|
||||
return True
|
||||
|
||||
def resume(self):
|
||||
"""Resumes this torrent."""
|
||||
if self.status.paused and self.status.auto_managed:
|
||||
log.debug("Resume not possible for auto-managed torrent!")
|
||||
log.debug('Resume not possible for auto-managed torrent!')
|
||||
elif self.forced_error and self.forced_error.was_paused:
|
||||
log.debug("Resume skipped for error'd torrent as it was originally paused.")
|
||||
elif (self.status.is_finished and self.options["stop_at_ratio"] and
|
||||
self.get_ratio() >= self.options["stop_ratio"]):
|
||||
elif (self.status.is_finished and self.options['stop_at_ratio'] and
|
||||
self.get_ratio() >= self.options['stop_ratio']):
|
||||
log.debug("Resume skipped for torrent as it has reached 'stop_seed_ratio'.")
|
||||
else:
|
||||
# Check if torrent was originally being auto-managed.
|
||||
if self.options["auto_managed"]:
|
||||
if self.options['auto_managed']:
|
||||
self.handle.auto_managed(True)
|
||||
try:
|
||||
self.handle.resume()
|
||||
except RuntimeError as ex:
|
||||
log.debug("Unable to resume torrent: %s", ex)
|
||||
log.debug('Unable to resume torrent: %s', ex)
|
||||
|
||||
# Clear torrent error state.
|
||||
if self.forced_error and not self.forced_error.restart_to_resume:
|
||||
self.clear_forced_error_state()
|
||||
elif self.state == "Error" and not self.forced_error:
|
||||
elif self.state == 'Error' and not self.forced_error:
|
||||
self.handle.clear_error()
|
||||
|
||||
def connect_peer(self, peer_ip, peer_port):
|
||||
@ -1112,7 +1112,7 @@ class Torrent(object):
|
||||
try:
|
||||
self.handle.connect_peer((peer_ip, peer_port), 0)
|
||||
except RuntimeError as ex:
|
||||
log.debug("Unable to connect to peer: %s", ex)
|
||||
log.debug('Unable to connect to peer: %s', ex)
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -1132,8 +1132,8 @@ class Torrent(object):
|
||||
try:
|
||||
os.makedirs(dest)
|
||||
except OSError as ex:
|
||||
log.error("Could not move storage for torrent %s since %s does "
|
||||
"not exist and could not create the directory: %s",
|
||||
log.error('Could not move storage for torrent %s since %s does '
|
||||
'not exist and could not create the directory: %s',
|
||||
self.torrent_id, dest, ex)
|
||||
return False
|
||||
|
||||
@ -1145,7 +1145,7 @@ class Torrent(object):
|
||||
except TypeError:
|
||||
self.handle.move_storage(utf8_encoded(dest), flags=1)
|
||||
except RuntimeError as ex:
|
||||
log.error("Error calling libtorrent move_storage: %s", ex)
|
||||
log.error('Error calling libtorrent move_storage: %s', ex)
|
||||
return False
|
||||
self.moving_storage = True
|
||||
self.moving_storage_dest_path = dest
|
||||
@ -1164,12 +1164,12 @@ class Torrent(object):
|
||||
|
||||
"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Requesting save_resume_data for torrent: %s", self.torrent_id)
|
||||
log.debug('Requesting save_resume_data for torrent: %s', self.torrent_id)
|
||||
flags = lt.save_resume_flags_t.flush_disk_cache if flush_disk_cache else 0
|
||||
# Don't generate fastresume data if torrent is in a Deluge Error state.
|
||||
if self.forced_error:
|
||||
component.get("TorrentManager").waiting_on_resume_data[self.torrent_id].errback(
|
||||
UserWarning("Skipped creating resume_data while in Error state"))
|
||||
component.get('TorrentManager').waiting_on_resume_data[self.torrent_id].errback(
|
||||
UserWarning('Skipped creating resume_data while in Error state'))
|
||||
else:
|
||||
self.handle.save_resume_data(flags)
|
||||
|
||||
@ -1183,48 +1183,48 @@ class Torrent(object):
|
||||
|
||||
def write_file(filepath, filedump):
|
||||
"""Write out the torrent file"""
|
||||
log.debug("Writing torrent file to: %s", filepath)
|
||||
log.debug('Writing torrent file to: %s', filepath)
|
||||
try:
|
||||
with open(filepath, "wb") as save_file:
|
||||
with open(filepath, 'wb') as save_file:
|
||||
save_file.write(filedump)
|
||||
except IOError as ex:
|
||||
log.error("Unable to save torrent file to: %s", ex)
|
||||
log.error('Unable to save torrent file to: %s', ex)
|
||||
|
||||
filepath = os.path.join(get_config_dir(), "state", self.torrent_id + ".torrent")
|
||||
filepath = os.path.join(get_config_dir(), 'state', self.torrent_id + '.torrent')
|
||||
# Regenerate the file priorities
|
||||
self.set_file_priorities([])
|
||||
if filedump is None:
|
||||
metadata = lt.bdecode(self.torrent_info.metadata())
|
||||
torrent_file = {"info": metadata}
|
||||
torrent_file = {'info': metadata}
|
||||
filedump = lt.bencode(torrent_file)
|
||||
write_file(filepath, filedump)
|
||||
|
||||
# If the user has requested a copy of the torrent be saved elsewhere we need to do that.
|
||||
if self.config["copy_torrent_file"]:
|
||||
if self.config['copy_torrent_file']:
|
||||
if not self.filename:
|
||||
self.filename = self.get_name() + ".torrent"
|
||||
filepath = os.path.join(self.config["torrentfiles_location"], self.filename)
|
||||
self.filename = self.get_name() + '.torrent'
|
||||
filepath = os.path.join(self.config['torrentfiles_location'], self.filename)
|
||||
write_file(filepath, filedump)
|
||||
|
||||
def delete_torrentfile(self, delete_copies=False):
|
||||
"""Deletes the .torrent file in the state directory in config"""
|
||||
torrent_files = [os.path.join(get_config_dir(), "state", self.torrent_id + ".torrent")]
|
||||
torrent_files = [os.path.join(get_config_dir(), 'state', self.torrent_id + '.torrent')]
|
||||
if delete_copies:
|
||||
torrent_files.append(os.path.join(self.config["torrentfiles_location"], self.filename))
|
||||
torrent_files.append(os.path.join(self.config['torrentfiles_location'], self.filename))
|
||||
|
||||
for torrent_file in torrent_files:
|
||||
log.debug("Deleting torrent file: %s", torrent_file)
|
||||
log.debug('Deleting torrent file: %s', torrent_file)
|
||||
try:
|
||||
os.remove(torrent_file)
|
||||
except OSError as ex:
|
||||
log.warning("Unable to delete the torrent file: %s", ex)
|
||||
log.warning('Unable to delete the torrent file: %s', ex)
|
||||
|
||||
def force_reannounce(self):
|
||||
"""Force a tracker reannounce"""
|
||||
try:
|
||||
self.handle.force_reannounce()
|
||||
except RuntimeError as ex:
|
||||
log.debug("Unable to force reannounce: %s", ex)
|
||||
log.debug('Unable to force reannounce: %s', ex)
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -1237,7 +1237,7 @@ class Torrent(object):
|
||||
try:
|
||||
self.handle.scrape_tracker()
|
||||
except RuntimeError as ex:
|
||||
log.debug("Unable to scrape tracker: %s", ex)
|
||||
log.debug('Unable to scrape tracker: %s', ex)
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -1254,7 +1254,7 @@ class Torrent(object):
|
||||
self.handle.resume()
|
||||
self.forcing_recheck = True
|
||||
except RuntimeError as ex:
|
||||
log.debug("Unable to force recheck: %s", ex)
|
||||
log.debug('Unable to force recheck: %s', ex)
|
||||
self.forcing_recheck = False
|
||||
return self.forcing_recheck
|
||||
|
||||
@ -1285,7 +1285,7 @@ class Torrent(object):
|
||||
Returns:
|
||||
twisted.internet.defer.Deferred: A deferred which fires when the rename is complete
|
||||
"""
|
||||
log.debug("Attempting to rename folder: %s to %s", folder, new_folder)
|
||||
log.debug('Attempting to rename folder: %s to %s', folder, new_folder)
|
||||
|
||||
# Empty string means remove the dir and move its content to the parent
|
||||
if len(new_folder) > 0:
|
||||
@ -1298,24 +1298,24 @@ class Torrent(object):
|
||||
wait_on_folder = {}
|
||||
self.waiting_on_folder_rename.append(wait_on_folder)
|
||||
for _file in self.get_files():
|
||||
if _file["path"].startswith(folder):
|
||||
if _file['path'].startswith(folder):
|
||||
# Keep track of filerenames we're waiting on
|
||||
wait_on_folder[_file["index"]] = Deferred().addBoth(
|
||||
on_file_rename_complete, wait_on_folder, _file["index"]
|
||||
wait_on_folder[_file['index']] = Deferred().addBoth(
|
||||
on_file_rename_complete, wait_on_folder, _file['index']
|
||||
)
|
||||
new_path = _file["path"].replace(folder, new_folder, 1)
|
||||
new_path = _file['path'].replace(folder, new_folder, 1)
|
||||
try:
|
||||
self.handle.rename_file(_file["index"], new_path)
|
||||
self.handle.rename_file(_file['index'], new_path)
|
||||
except TypeError:
|
||||
self.handle.rename_file(_file["index"], utf8_encoded(new_path))
|
||||
self.handle.rename_file(_file['index'], utf8_encoded(new_path))
|
||||
|
||||
def on_folder_rename_complete(dummy_result, torrent, folder, new_folder):
|
||||
"""Folder rename complete"""
|
||||
component.get("EventManager").emit(TorrentFolderRenamedEvent(torrent.torrent_id, folder, new_folder))
|
||||
component.get('EventManager').emit(TorrentFolderRenamedEvent(torrent.torrent_id, folder, new_folder))
|
||||
# Empty folders are removed after libtorrent folder renames
|
||||
self.remove_empty_folders(folder)
|
||||
torrent.waiting_on_folder_rename = [_dir for _dir in torrent.waiting_on_folder_rename if _dir]
|
||||
component.get("TorrentManager").save_resume_data((self.torrent_id,))
|
||||
component.get('TorrentManager').save_resume_data((self.torrent_id,))
|
||||
|
||||
d = DeferredList(wait_on_folder.values())
|
||||
d.addBoth(on_folder_rename_complete, self, folder, new_folder)
|
||||
@ -1330,24 +1330,24 @@ class Torrent(object):
|
||||
folder (str): The folder to recursively check
|
||||
"""
|
||||
# Removes leading slashes that can cause join to ignore download_location
|
||||
download_location = self.options["download_location"]
|
||||
folder_full_path = os.path.normpath(os.path.join(download_location, folder.lstrip("\\/")))
|
||||
download_location = self.options['download_location']
|
||||
folder_full_path = os.path.normpath(os.path.join(download_location, folder.lstrip('\\/')))
|
||||
|
||||
try:
|
||||
if not os.listdir(folder_full_path):
|
||||
os.removedirs(folder_full_path)
|
||||
log.debug("Removed Empty Folder %s", folder_full_path)
|
||||
log.debug('Removed Empty Folder %s', folder_full_path)
|
||||
else:
|
||||
for root, dirs, dummy_files in os.walk(folder_full_path, topdown=False):
|
||||
for name in dirs:
|
||||
try:
|
||||
os.removedirs(os.path.join(root, name))
|
||||
log.debug("Removed Empty Folder %s", os.path.join(root, name))
|
||||
log.debug('Removed Empty Folder %s', os.path.join(root, name))
|
||||
except OSError as ex:
|
||||
log.debug(ex)
|
||||
|
||||
except OSError as ex:
|
||||
log.debug("Cannot Remove Folder: %s", ex)
|
||||
log.debug('Cannot Remove Folder: %s', ex)
|
||||
|
||||
def cleanup_prev_status(self):
|
||||
"""Checks the validity of the keys in the prev_status dict.
|
||||
|
||||
@ -46,7 +46,7 @@ class TorrentState: # pylint: disable=old-style-class
|
||||
torrent_id=None,
|
||||
filename=None,
|
||||
trackers=None,
|
||||
storage_mode="sparse",
|
||||
storage_mode='sparse',
|
||||
paused=False,
|
||||
save_path=None,
|
||||
max_connections=-1,
|
||||
@ -72,7 +72,7 @@ class TorrentState: # pylint: disable=old-style-class
|
||||
name=None):
|
||||
# Build the class atrribute list from args
|
||||
for key, value in locals().items():
|
||||
if key == "self":
|
||||
if key == 'self':
|
||||
continue
|
||||
setattr(self, key, value)
|
||||
|
||||
@ -96,21 +96,21 @@ class TorrentManager(component.Component):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
component.Component.__init__(self, "TorrentManager", interval=5,
|
||||
depend=["CorePluginManager", "AlertManager"])
|
||||
log.debug("TorrentManager init...")
|
||||
component.Component.__init__(self, 'TorrentManager', interval=5,
|
||||
depend=['CorePluginManager', 'AlertManager'])
|
||||
log.debug('TorrentManager init...')
|
||||
# Set the libtorrent session
|
||||
self.session = component.get("Core").session
|
||||
self.session = component.get('Core').session
|
||||
# Set the alertmanager
|
||||
self.alerts = component.get("AlertManager")
|
||||
self.alerts = component.get('AlertManager')
|
||||
# Get the core config
|
||||
self.config = ConfigManager("core.conf")
|
||||
self.config = ConfigManager('core.conf')
|
||||
|
||||
# Make sure the state folder has been created
|
||||
self.state_dir = os.path.join(get_config_dir(), "state")
|
||||
self.state_dir = os.path.join(get_config_dir(), 'state')
|
||||
if not os.path.exists(self.state_dir):
|
||||
os.makedirs(self.state_dir)
|
||||
self.temp_file = os.path.join(self.state_dir, ".safe_state_check")
|
||||
self.temp_file = os.path.join(self.state_dir, '.safe_state_check')
|
||||
|
||||
# Create the torrents dict { torrent_id: Torrent }
|
||||
self.torrents = {}
|
||||
@ -134,38 +134,38 @@ class TorrentManager(component.Component):
|
||||
self.last_state_update_alert_ts = 0
|
||||
|
||||
# Register set functions
|
||||
self.config.register_set_function("max_connections_per_torrent",
|
||||
self.config.register_set_function('max_connections_per_torrent',
|
||||
self.on_set_max_connections_per_torrent)
|
||||
self.config.register_set_function("max_upload_slots_per_torrent",
|
||||
self.config.register_set_function('max_upload_slots_per_torrent',
|
||||
self.on_set_max_upload_slots_per_torrent)
|
||||
self.config.register_set_function("max_upload_speed_per_torrent",
|
||||
self.config.register_set_function('max_upload_speed_per_torrent',
|
||||
self.on_set_max_upload_speed_per_torrent)
|
||||
self.config.register_set_function("max_download_speed_per_torrent",
|
||||
self.config.register_set_function('max_download_speed_per_torrent',
|
||||
self.on_set_max_download_speed_per_torrent)
|
||||
|
||||
# Register alert functions
|
||||
self.alerts.register_handler("torrent_finished_alert", self.on_alert_torrent_finished)
|
||||
self.alerts.register_handler("torrent_paused_alert", self.on_alert_torrent_paused)
|
||||
self.alerts.register_handler("torrent_checked_alert", self.on_alert_torrent_checked)
|
||||
self.alerts.register_handler("tracker_reply_alert", self.on_alert_tracker_reply)
|
||||
self.alerts.register_handler("tracker_announce_alert", self.on_alert_tracker_announce)
|
||||
self.alerts.register_handler("tracker_warning_alert", self.on_alert_tracker_warning)
|
||||
self.alerts.register_handler("tracker_error_alert", self.on_alert_tracker_error)
|
||||
self.alerts.register_handler("storage_moved_alert", self.on_alert_storage_moved)
|
||||
self.alerts.register_handler("storage_moved_failed_alert", self.on_alert_storage_moved_failed)
|
||||
self.alerts.register_handler("torrent_resumed_alert", self.on_alert_torrent_resumed)
|
||||
self.alerts.register_handler("state_changed_alert", self.on_alert_state_changed)
|
||||
self.alerts.register_handler("save_resume_data_alert", self.on_alert_save_resume_data)
|
||||
self.alerts.register_handler("save_resume_data_failed_alert", self.on_alert_save_resume_data_failed)
|
||||
self.alerts.register_handler("file_renamed_alert", self.on_alert_file_renamed)
|
||||
self.alerts.register_handler("metadata_received_alert", self.on_alert_metadata_received)
|
||||
self.alerts.register_handler("file_error_alert", self.on_alert_file_error)
|
||||
self.alerts.register_handler("file_completed_alert", self.on_alert_file_completed)
|
||||
self.alerts.register_handler("state_update_alert", self.on_alert_state_update)
|
||||
self.alerts.register_handler("external_ip_alert", self.on_alert_external_ip)
|
||||
self.alerts.register_handler("performance_alert", self.on_alert_performance)
|
||||
self.alerts.register_handler("fastresume_rejected_alert", self.on_alert_fastresume_rejected)
|
||||
self.alerts.register_handler("add_torrent_alert", self.on_add_torrent_alert)
|
||||
self.alerts.register_handler('torrent_finished_alert', self.on_alert_torrent_finished)
|
||||
self.alerts.register_handler('torrent_paused_alert', self.on_alert_torrent_paused)
|
||||
self.alerts.register_handler('torrent_checked_alert', self.on_alert_torrent_checked)
|
||||
self.alerts.register_handler('tracker_reply_alert', self.on_alert_tracker_reply)
|
||||
self.alerts.register_handler('tracker_announce_alert', self.on_alert_tracker_announce)
|
||||
self.alerts.register_handler('tracker_warning_alert', self.on_alert_tracker_warning)
|
||||
self.alerts.register_handler('tracker_error_alert', self.on_alert_tracker_error)
|
||||
self.alerts.register_handler('storage_moved_alert', self.on_alert_storage_moved)
|
||||
self.alerts.register_handler('storage_moved_failed_alert', self.on_alert_storage_moved_failed)
|
||||
self.alerts.register_handler('torrent_resumed_alert', self.on_alert_torrent_resumed)
|
||||
self.alerts.register_handler('state_changed_alert', self.on_alert_state_changed)
|
||||
self.alerts.register_handler('save_resume_data_alert', self.on_alert_save_resume_data)
|
||||
self.alerts.register_handler('save_resume_data_failed_alert', self.on_alert_save_resume_data_failed)
|
||||
self.alerts.register_handler('file_renamed_alert', self.on_alert_file_renamed)
|
||||
self.alerts.register_handler('metadata_received_alert', self.on_alert_metadata_received)
|
||||
self.alerts.register_handler('file_error_alert', self.on_alert_file_error)
|
||||
self.alerts.register_handler('file_completed_alert', self.on_alert_file_completed)
|
||||
self.alerts.register_handler('state_update_alert', self.on_alert_state_update)
|
||||
self.alerts.register_handler('external_ip_alert', self.on_alert_external_ip)
|
||||
self.alerts.register_handler('performance_alert', self.on_alert_performance)
|
||||
self.alerts.register_handler('fastresume_rejected_alert', self.on_alert_fastresume_rejected)
|
||||
self.alerts.register_handler('add_torrent_alert', self.on_add_torrent_alert)
|
||||
|
||||
# Define timers
|
||||
self.save_state_timer = LoopingCall(self.save_state)
|
||||
@ -178,24 +178,24 @@ class TorrentManager(component.Component):
|
||||
def archive_file(filename):
|
||||
"""Archives the file in 'archive' sub-directory with timestamp appended"""
|
||||
filepath = os.path.join(self.state_dir, filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
archive_dir = os.path.join(get_config_dir(), "archive")
|
||||
filepath_bak = filepath + '.bak'
|
||||
archive_dir = os.path.join(get_config_dir(), 'archive')
|
||||
if not os.path.exists(archive_dir):
|
||||
os.makedirs(archive_dir)
|
||||
|
||||
for _filepath in (filepath, filepath_bak):
|
||||
timestamp = datetime.datetime.now().replace(microsecond=0).isoformat().replace(':', '-')
|
||||
archive_filepath = os.path.join(archive_dir, filename + "-" + timestamp)
|
||||
archive_filepath = os.path.join(archive_dir, filename + '-' + timestamp)
|
||||
try:
|
||||
shutil.copy2(_filepath, archive_filepath)
|
||||
except IOError:
|
||||
log.error("Unable to archive: %s", filename)
|
||||
log.error('Unable to archive: %s', filename)
|
||||
else:
|
||||
log.info("Archive of %s successful: %s", filename, archive_filepath)
|
||||
log.info('Archive of %s successful: %s', filename, archive_filepath)
|
||||
|
||||
log.warning("Potential bad shutdown of Deluge detected, archiving torrent state files...")
|
||||
archive_file("torrents.state")
|
||||
archive_file("torrents.fastresume")
|
||||
log.warning('Potential bad shutdown of Deluge detected, archiving torrent state files...')
|
||||
archive_file('torrents.state')
|
||||
archive_file('torrents.fastresume')
|
||||
else:
|
||||
with open(self.temp_file, 'a'):
|
||||
os.utime(self.temp_file, None)
|
||||
@ -233,15 +233,15 @@ class TorrentManager(component.Component):
|
||||
def update(self):
|
||||
for torrent_id, torrent in self.torrents.items():
|
||||
# XXX: Should the state check be those that _can_ be stopped at ratio
|
||||
if torrent.options["stop_at_ratio"] and torrent.state not in (
|
||||
"Checking", "Allocating", "Paused", "Queued"):
|
||||
if torrent.options['stop_at_ratio'] and torrent.state not in (
|
||||
'Checking', 'Allocating', 'Paused', 'Queued'):
|
||||
# If the global setting is set, but the per-torrent isn't...
|
||||
# Just skip to the next torrent.
|
||||
# This is so that a user can turn-off the stop at ratio option on a per-torrent basis
|
||||
if not torrent.options["stop_at_ratio"]:
|
||||
if not torrent.options['stop_at_ratio']:
|
||||
continue
|
||||
if torrent.get_ratio() >= torrent.options["stop_ratio"] and torrent.is_finished:
|
||||
if torrent.options["remove_at_ratio"]:
|
||||
if torrent.get_ratio() >= torrent.options['stop_ratio'] and torrent.is_finished:
|
||||
if torrent.options['remove_at_ratio']:
|
||||
self.remove(torrent_id)
|
||||
break
|
||||
if not torrent.handle.status().paused:
|
||||
@ -267,13 +267,13 @@ class TorrentManager(component.Component):
|
||||
|
||||
"""
|
||||
torrent_ids = self.torrents.keys()
|
||||
if component.get("RPCServer").get_session_auth_level() == AUTH_LEVEL_ADMIN:
|
||||
if component.get('RPCServer').get_session_auth_level() == AUTH_LEVEL_ADMIN:
|
||||
return torrent_ids
|
||||
|
||||
current_user = component.get("RPCServer").get_session_user()
|
||||
current_user = component.get('RPCServer').get_session_user()
|
||||
for torrent_id in torrent_ids[:]:
|
||||
torrent_status = self.torrents[torrent_id].get_status(["owner", "shared"])
|
||||
if torrent_status["owner"] != current_user and not torrent_status["shared"]:
|
||||
torrent_status = self.torrents[torrent_id].get_status(['owner', 'shared'])
|
||||
if torrent_status['owner'] != current_user and not torrent_status['shared']:
|
||||
torrent_ids.pop(torrent_ids.index(torrent_id))
|
||||
return torrent_ids
|
||||
|
||||
@ -289,11 +289,11 @@ class TorrentManager(component.Component):
|
||||
"""
|
||||
# Get the torrent data from the torrent file
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Attempting to extract torrent_info from %s", filepath)
|
||||
log.debug('Attempting to extract torrent_info from %s', filepath)
|
||||
try:
|
||||
torrent_info = lt.torrent_info(filepath)
|
||||
except RuntimeError as ex:
|
||||
log.warning("Unable to open torrent file %s: %s", filepath, ex)
|
||||
log.warning('Unable to open torrent file %s: %s', filepath, ex)
|
||||
else:
|
||||
return torrent_info
|
||||
|
||||
@ -319,39 +319,39 @@ class TorrentManager(component.Component):
|
||||
|
||||
"""
|
||||
if not torrent_info and not filedump and not magnet:
|
||||
raise AddTorrentError("You must specify a valid torrent_info, torrent state or magnet.")
|
||||
raise AddTorrentError('You must specify a valid torrent_info, torrent state or magnet.')
|
||||
|
||||
if filedump:
|
||||
try:
|
||||
torrent_info = lt.torrent_info(lt.bdecode(filedump))
|
||||
except RuntimeError as ex:
|
||||
raise AddTorrentError("Unable to add torrent, decoding filedump failed: %s" % ex)
|
||||
raise AddTorrentError('Unable to add torrent, decoding filedump failed: %s' % ex)
|
||||
|
||||
add_torrent_params = {}
|
||||
if torrent_info:
|
||||
add_torrent_params["ti"] = torrent_info
|
||||
add_torrent_params['ti'] = torrent_info
|
||||
name = torrent_info.name()
|
||||
if not name:
|
||||
name = torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0]
|
||||
add_torrent_params["name"] = name
|
||||
name = torrent_info.file_at(0).path.replace('\\', '/', 1).split('/', 1)[0]
|
||||
add_torrent_params['name'] = name
|
||||
torrent_id = str(torrent_info.info_hash())
|
||||
elif magnet:
|
||||
magnet = utf8_encoded(magnet)
|
||||
magnet_info = get_magnet_info(magnet)
|
||||
if magnet_info:
|
||||
add_torrent_params["url"] = magnet
|
||||
add_torrent_params["name"] = magnet_info["name"]
|
||||
torrent_id = magnet_info["info_hash"]
|
||||
add_torrent_params['url'] = magnet
|
||||
add_torrent_params['name'] = magnet_info['name']
|
||||
torrent_id = magnet_info['info_hash']
|
||||
else:
|
||||
raise AddTorrentError("Unable to add magnet, invalid magnet info: %s" % magnet)
|
||||
raise AddTorrentError('Unable to add magnet, invalid magnet info: %s' % magnet)
|
||||
|
||||
# Check for existing torrent in session.
|
||||
if torrent_id in self.get_torrent_list():
|
||||
# Attempt merge trackers before returning.
|
||||
self.torrents[torrent_id].merge_trackers(torrent_info)
|
||||
raise AddTorrentError("Torrent already in session (%s)." % torrent_id)
|
||||
raise AddTorrentError('Torrent already in session (%s).' % torrent_id)
|
||||
elif torrent_id in self.torrents_loading:
|
||||
raise AddTorrentError("Torrent already being added (%s)." % torrent_id)
|
||||
raise AddTorrentError('Torrent already being added (%s).' % torrent_id)
|
||||
|
||||
# Load default options and update if needed.
|
||||
_options = TorrentOptions()
|
||||
@ -360,63 +360,63 @@ class TorrentManager(component.Component):
|
||||
options = _options
|
||||
|
||||
# Check for renamed files and if so, rename them in the torrent_info before adding.
|
||||
if options["mapped_files"] and torrent_info:
|
||||
for index, fname in options["mapped_files"].items():
|
||||
if options['mapped_files'] and torrent_info:
|
||||
for index, fname in options['mapped_files'].items():
|
||||
fname = sanitize_filepath(decode_string(fname))
|
||||
log.debug("renaming file index %s to %s", index, fname)
|
||||
log.debug('renaming file index %s to %s', index, fname)
|
||||
try:
|
||||
torrent_info.rename_file(index, fname)
|
||||
except TypeError:
|
||||
torrent_info.rename_file(index, utf8_encoded(fname))
|
||||
add_torrent_params["ti"] = torrent_info
|
||||
add_torrent_params['ti'] = torrent_info
|
||||
|
||||
if not options["owner"]:
|
||||
options["owner"] = component.get("RPCServer").get_session_user()
|
||||
if not component.get("AuthManager").has_account(options["owner"]):
|
||||
options["owner"] = "localclient"
|
||||
if not options['owner']:
|
||||
options['owner'] = component.get('RPCServer').get_session_user()
|
||||
if not component.get('AuthManager').has_account(options['owner']):
|
||||
options['owner'] = 'localclient'
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("options: %s", options)
|
||||
log.debug('options: %s', options)
|
||||
|
||||
# Fill in the rest of the add_torrent_params dictionary.
|
||||
add_torrent_params["save_path"] = utf8_encoded(options["download_location"])
|
||||
if options["name"]:
|
||||
add_torrent_params["name"] = options["name"]
|
||||
if options["pre_allocate_storage"]:
|
||||
add_torrent_params["storage_mode"] = lt.storage_mode_t.storage_mode_allocate
|
||||
add_torrent_params['save_path'] = utf8_encoded(options['download_location'])
|
||||
if options['name']:
|
||||
add_torrent_params['name'] = options['name']
|
||||
if options['pre_allocate_storage']:
|
||||
add_torrent_params['storage_mode'] = lt.storage_mode_t.storage_mode_allocate
|
||||
if resume_data:
|
||||
add_torrent_params["resume_data"] = resume_data
|
||||
add_torrent_params['resume_data'] = resume_data
|
||||
|
||||
default_flags = (lt.add_torrent_params_flags_t.flag_paused |
|
||||
lt.add_torrent_params_flags_t.flag_auto_managed |
|
||||
lt.add_torrent_params_flags_t.flag_update_subscribe |
|
||||
lt.add_torrent_params_flags_t.flag_apply_ip_filter)
|
||||
# Set flags: enable duplicate_is_error & override_resume_data, disable auto_managed.
|
||||
add_torrent_params["flags"] = ((default_flags |
|
||||
add_torrent_params['flags'] = ((default_flags |
|
||||
lt.add_torrent_params_flags_t.flag_duplicate_is_error |
|
||||
lt.add_torrent_params_flags_t.flag_override_resume_data) ^
|
||||
lt.add_torrent_params_flags_t.flag_auto_managed)
|
||||
if options["seed_mode"]:
|
||||
add_torrent_params["flags"] |= lt.add_torrent_params_flags_t.flag_seed_mode
|
||||
if options['seed_mode']:
|
||||
add_torrent_params['flags'] |= lt.add_torrent_params_flags_t.flag_seed_mode
|
||||
|
||||
d = Deferred()
|
||||
try:
|
||||
self.torrents_loading[torrent_id] = (d, options, state, filename, magnet, resume_data, filedump, save_state)
|
||||
self.session.async_add_torrent(add_torrent_params)
|
||||
except RuntimeError as ex:
|
||||
raise AddTorrentError("Unable to add torrent to session: %s" % ex)
|
||||
raise AddTorrentError('Unable to add torrent to session: %s' % ex)
|
||||
return d
|
||||
|
||||
def on_add_torrent_alert(self, alert):
|
||||
"""Alert handler for libtorrent add_torrent_alert"""
|
||||
if not alert.handle.is_valid():
|
||||
log.warn("Torrent handle is invalid!")
|
||||
log.warn('Torrent handle is invalid!')
|
||||
return
|
||||
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
except RuntimeError as ex:
|
||||
log.warn("Failed to get torrent id from handle: %s", ex)
|
||||
log.warn('Failed to get torrent id from handle: %s', ex)
|
||||
return
|
||||
|
||||
d, options, state, filename, magnet, resume_data, filedump, save_state = self.torrents_loading.pop(torrent_id)
|
||||
@ -431,25 +431,25 @@ class TorrentManager(component.Component):
|
||||
|
||||
# Add to queued torrents set.
|
||||
self.queued_torrents.add(torrent.torrent_id)
|
||||
if self.config["queue_new_to_top"]:
|
||||
if self.config['queue_new_to_top']:
|
||||
self.queue_top(torrent.torrent_id)
|
||||
|
||||
# Resume the torrent if needed.
|
||||
if not options["add_paused"]:
|
||||
if not options['add_paused']:
|
||||
torrent.resume()
|
||||
|
||||
# Emit torrent_added signal.
|
||||
from_state = state is not None
|
||||
component.get("EventManager").emit(TorrentAddedEvent(torrent.torrent_id, from_state))
|
||||
component.get('EventManager').emit(TorrentAddedEvent(torrent.torrent_id, from_state))
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Torrent added: %s", str(alert.handle.info_hash()))
|
||||
log.debug('Torrent added: %s', str(alert.handle.info_hash()))
|
||||
if log.isEnabledFor(logging.INFO):
|
||||
name_and_owner = torrent.get_status(["name", "owner"])
|
||||
name_and_owner = torrent.get_status(['name', 'owner'])
|
||||
log.info("Torrent %s from user \"%s\" %s",
|
||||
name_and_owner["name"],
|
||||
name_and_owner["owner"],
|
||||
from_state and "loaded" or "added")
|
||||
name_and_owner['name'],
|
||||
name_and_owner['owner'],
|
||||
from_state and 'loaded' or 'added')
|
||||
|
||||
# Write the .torrent file to the state directory.
|
||||
if filedump:
|
||||
@ -485,22 +485,22 @@ class TorrentManager(component.Component):
|
||||
except KeyError:
|
||||
raise InvalidTorrentError("torrent_id '%s' not in session." % torrent_id)
|
||||
|
||||
torrent_name = torrent.get_status(["name"])["name"]
|
||||
torrent_name = torrent.get_status(['name'])['name']
|
||||
|
||||
# Emit the signal to the clients
|
||||
component.get("EventManager").emit(PreTorrentRemovedEvent(torrent_id))
|
||||
component.get('EventManager').emit(PreTorrentRemovedEvent(torrent_id))
|
||||
|
||||
try:
|
||||
self.session.remove_torrent(torrent.handle, 1 if remove_data else 0)
|
||||
except RuntimeError as ex:
|
||||
log.warning("Error removing torrent: %s", ex)
|
||||
log.warning('Error removing torrent: %s', ex)
|
||||
return False
|
||||
|
||||
# Remove fastresume data if it is exists
|
||||
self.resume_data.pop(torrent_id, None)
|
||||
|
||||
# Remove the .torrent file in the state and copy location, if user requested.
|
||||
delete_copies = self.config["copy_torrent_file"] and self.config["del_copy_torrent_file"]
|
||||
delete_copies = self.config['copy_torrent_file'] and self.config['del_copy_torrent_file']
|
||||
torrent.delete_torrentfile(delete_copies)
|
||||
|
||||
# Remove from set if it wasn't finished
|
||||
@ -518,8 +518,8 @@ class TorrentManager(component.Component):
|
||||
self.save_state()
|
||||
|
||||
# Emit the signal to the clients
|
||||
component.get("EventManager").emit(TorrentRemovedEvent(torrent_id))
|
||||
log.info("Torrent %s removed by user: %s", torrent_name, component.get("RPCServer").get_session_user())
|
||||
component.get('EventManager').emit(TorrentRemovedEvent(torrent_id))
|
||||
log.info('Torrent %s removed by user: %s', torrent_name, component.get('RPCServer').get_session_user())
|
||||
return True
|
||||
|
||||
def fixup_state(self, state):
|
||||
@ -540,7 +540,7 @@ class TorrentManager(component.Component):
|
||||
for t_state in state.torrents:
|
||||
setattr(t_state, attr, getattr(t_state_tmp, attr, None))
|
||||
except AttributeError as ex:
|
||||
log.error("Unable to update state file to a compatible version: %s", ex)
|
||||
log.error('Unable to update state file to a compatible version: %s', ex)
|
||||
return state
|
||||
|
||||
def open_state(self):
|
||||
@ -550,17 +550,17 @@ class TorrentManager(component.Component):
|
||||
TorrentManagerState: The TorrentManager state.
|
||||
|
||||
"""
|
||||
torrents_state = os.path.join(self.state_dir, "torrents.state")
|
||||
for filepath in (torrents_state, torrents_state + ".bak"):
|
||||
log.info("Loading torrent state: %s", filepath)
|
||||
torrents_state = os.path.join(self.state_dir, 'torrents.state')
|
||||
for filepath in (torrents_state, torrents_state + '.bak'):
|
||||
log.info('Loading torrent state: %s', filepath)
|
||||
try:
|
||||
with open(filepath, "rb") as _file:
|
||||
with open(filepath, 'rb') as _file:
|
||||
state = cPickle.load(_file)
|
||||
except (IOError, EOFError, cPickle.UnpicklingError) as ex:
|
||||
log.warning("Unable to load %s: %s", filepath, ex)
|
||||
log.warning('Unable to load %s: %s', filepath, ex)
|
||||
state = None
|
||||
else:
|
||||
log.info("Successfully loaded %s", filepath)
|
||||
log.info('Successfully loaded %s', filepath)
|
||||
break
|
||||
|
||||
if state is None:
|
||||
@ -579,7 +579,7 @@ class TorrentManager(component.Component):
|
||||
state = self.fixup_state(state)
|
||||
|
||||
# Reorder the state.torrents list to add torrents in the correct queue order.
|
||||
state.torrents.sort(key=operator.attrgetter("queue"), reverse=self.config["queue_new_to_top"])
|
||||
state.torrents.sort(key=operator.attrgetter('queue'), reverse=self.config['queue_new_to_top'])
|
||||
resume_data = self.load_resume_data_file()
|
||||
|
||||
deferreds = []
|
||||
@ -592,14 +592,14 @@ class TorrentManager(component.Component):
|
||||
except AttributeError:
|
||||
pass
|
||||
# Manually update unmatched attributes
|
||||
options["download_location"] = t_state.save_path
|
||||
options["pre_allocate_storage"] = t_state.storage_mode == "allocate"
|
||||
options["prioritize_first_last_pieces"] = t_state.prioritize_first_last
|
||||
options["add_paused"] = t_state.paused
|
||||
options['download_location'] = t_state.save_path
|
||||
options['pre_allocate_storage'] = t_state.storage_mode == 'allocate'
|
||||
options['prioritize_first_last_pieces'] = t_state.prioritize_first_last
|
||||
options['add_paused'] = t_state.paused
|
||||
|
||||
magnet = t_state.magnet
|
||||
torrent_info = self.get_torrent_info_from_file(
|
||||
os.path.join(self.state_dir, t_state.torrent_id + ".torrent"))
|
||||
os.path.join(self.state_dir, t_state.torrent_id + '.torrent'))
|
||||
if torrent_info:
|
||||
magnet = None
|
||||
|
||||
@ -614,8 +614,8 @@ class TorrentManager(component.Component):
|
||||
deferred_list = DeferredList(deferreds, consumeErrors=False)
|
||||
|
||||
def on_complete(result):
|
||||
log.info("Finished loading %d torrents in %s", len(state.torrents), str(datetime.datetime.now() - start))
|
||||
component.get("EventManager").emit(SessionStartedEvent())
|
||||
log.info('Finished loading %d torrents in %s', len(state.torrents), str(datetime.datetime.now() - start))
|
||||
component.get('EventManager').emit(SessionStartedEvent())
|
||||
deferred_list.addCallback(on_complete)
|
||||
|
||||
def create_state(self):
|
||||
@ -632,7 +632,7 @@ class TorrentManager(component.Component):
|
||||
paused = torrent.handle.is_paused()
|
||||
elif torrent.forced_error:
|
||||
paused = torrent.forced_error.was_paused
|
||||
elif torrent.state == "Paused":
|
||||
elif torrent.state == 'Paused':
|
||||
paused = True
|
||||
else:
|
||||
paused = False
|
||||
@ -641,30 +641,30 @@ class TorrentManager(component.Component):
|
||||
torrent.torrent_id,
|
||||
torrent.filename,
|
||||
torrent.trackers,
|
||||
torrent.get_status(["storage_mode"])["storage_mode"],
|
||||
torrent.get_status(['storage_mode'])['storage_mode'],
|
||||
paused,
|
||||
torrent.options["download_location"],
|
||||
torrent.options["max_connections"],
|
||||
torrent.options["max_upload_slots"],
|
||||
torrent.options["max_upload_speed"],
|
||||
torrent.options["max_download_speed"],
|
||||
torrent.options["prioritize_first_last_pieces"],
|
||||
torrent.options["sequential_download"],
|
||||
torrent.options["file_priorities"],
|
||||
torrent.options['download_location'],
|
||||
torrent.options['max_connections'],
|
||||
torrent.options['max_upload_slots'],
|
||||
torrent.options['max_upload_speed'],
|
||||
torrent.options['max_download_speed'],
|
||||
torrent.options['prioritize_first_last_pieces'],
|
||||
torrent.options['sequential_download'],
|
||||
torrent.options['file_priorities'],
|
||||
torrent.get_queue_position(),
|
||||
torrent.options["auto_managed"],
|
||||
torrent.options['auto_managed'],
|
||||
torrent.is_finished,
|
||||
torrent.options["stop_ratio"],
|
||||
torrent.options["stop_at_ratio"],
|
||||
torrent.options["remove_at_ratio"],
|
||||
torrent.options["move_completed"],
|
||||
torrent.options["move_completed_path"],
|
||||
torrent.options['stop_ratio'],
|
||||
torrent.options['stop_at_ratio'],
|
||||
torrent.options['remove_at_ratio'],
|
||||
torrent.options['move_completed'],
|
||||
torrent.options['move_completed_path'],
|
||||
torrent.magnet,
|
||||
torrent.options["owner"],
|
||||
torrent.options["shared"],
|
||||
torrent.options["super_seeding"],
|
||||
torrent.options["priority"],
|
||||
torrent.options["name"]
|
||||
torrent.options['owner'],
|
||||
torrent.options['shared'],
|
||||
torrent.options['super_seeding'],
|
||||
torrent.options['priority'],
|
||||
torrent.options['name']
|
||||
)
|
||||
state.torrents.append(torrent_state)
|
||||
return state
|
||||
@ -692,41 +692,41 @@ class TorrentManager(component.Component):
|
||||
"""Save the state of the TorrentManager to the torrents.state file."""
|
||||
state = self.create_state()
|
||||
if not state.torrents:
|
||||
log.debug("Skipping saving state with no torrents loaded")
|
||||
log.debug('Skipping saving state with no torrents loaded')
|
||||
return
|
||||
|
||||
filename = "torrents.state"
|
||||
filename = 'torrents.state'
|
||||
filepath = os.path.join(self.state_dir, filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
filepath_tmp = filepath + ".tmp"
|
||||
filepath_bak = filepath + '.bak'
|
||||
filepath_tmp = filepath + '.tmp'
|
||||
|
||||
try:
|
||||
log.debug("Creating the temporary file: %s", filepath_tmp)
|
||||
with open(filepath_tmp, "wb", 0) as _file:
|
||||
log.debug('Creating the temporary file: %s', filepath_tmp)
|
||||
with open(filepath_tmp, 'wb', 0) as _file:
|
||||
cPickle.dump(state, _file)
|
||||
_file.flush()
|
||||
os.fsync(_file.fileno())
|
||||
except (OSError, cPickle.PicklingError) as ex:
|
||||
log.error("Unable to save %s: %s", filename, ex)
|
||||
log.error('Unable to save %s: %s', filename, ex)
|
||||
return
|
||||
|
||||
try:
|
||||
log.debug("Creating backup of %s at: %s", filename, filepath_bak)
|
||||
log.debug('Creating backup of %s at: %s', filename, filepath_bak)
|
||||
if os.path.isfile(filepath_bak):
|
||||
os.remove(filepath_bak)
|
||||
if os.path.isfile(filepath):
|
||||
os.rename(filepath, filepath_bak)
|
||||
except OSError as ex:
|
||||
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
|
||||
log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
|
||||
return
|
||||
|
||||
try:
|
||||
log.debug("Saving %s to: %s", filename, filepath)
|
||||
log.debug('Saving %s to: %s', filename, filepath)
|
||||
os.rename(filepath_tmp, filepath)
|
||||
except OSError as ex:
|
||||
log.error("Failed to set new state file %s: %s", filepath, ex)
|
||||
log.error('Failed to set new state file %s: %s', filepath, ex)
|
||||
if os.path.isfile(filepath_bak):
|
||||
log.info("Restoring backup of state from: %s", filepath_bak)
|
||||
log.info('Restoring backup of state from: %s', filepath_bak)
|
||||
os.rename(filepath_bak, filepath)
|
||||
|
||||
def save_resume_data(self, torrent_ids=None, flush_disk_cache=False):
|
||||
@ -781,22 +781,22 @@ class TorrentManager(component.Component):
|
||||
dict: A dict of torrents and their resume_data.
|
||||
|
||||
"""
|
||||
filename = "torrents.fastresume"
|
||||
filename = 'torrents.fastresume'
|
||||
filepath = os.path.join(self.state_dir, filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
filepath_bak = filepath + '.bak'
|
||||
old_data_filepath = os.path.join(get_config_dir(), filename)
|
||||
|
||||
for _filepath in (filepath, filepath_bak, old_data_filepath):
|
||||
log.info("Opening %s for load: %s", filename, _filepath)
|
||||
log.info('Opening %s for load: %s', filename, _filepath)
|
||||
try:
|
||||
with open(_filepath, "rb") as _file:
|
||||
with open(_filepath, 'rb') as _file:
|
||||
resume_data = lt.bdecode(_file.read())
|
||||
except (IOError, EOFError, RuntimeError) as ex:
|
||||
if self.torrents:
|
||||
log.warning("Unable to load %s: %s", _filepath, ex)
|
||||
log.warning('Unable to load %s: %s', _filepath, ex)
|
||||
resume_data = None
|
||||
else:
|
||||
log.info("Successfully loaded %s: %s", filename, _filepath)
|
||||
log.info('Successfully loaded %s: %s', filename, _filepath)
|
||||
break
|
||||
# If the libtorrent bdecode doesn't happen properly, it will return None
|
||||
# so we need to make sure we return a {}
|
||||
@ -836,38 +836,38 @@ class TorrentManager(component.Component):
|
||||
if not self.resume_data:
|
||||
return True
|
||||
|
||||
filename = "torrents.fastresume"
|
||||
filename = 'torrents.fastresume'
|
||||
filepath = os.path.join(self.state_dir, filename)
|
||||
filepath_bak = filepath + ".bak"
|
||||
filepath_tmp = filepath + ".tmp"
|
||||
filepath_bak = filepath + '.bak'
|
||||
filepath_tmp = filepath + '.tmp'
|
||||
|
||||
try:
|
||||
log.debug("Creating the temporary file: %s", filepath_tmp)
|
||||
with open(filepath_tmp, "wb", 0) as _file:
|
||||
log.debug('Creating the temporary file: %s', filepath_tmp)
|
||||
with open(filepath_tmp, 'wb', 0) as _file:
|
||||
_file.write(lt.bencode(self.resume_data))
|
||||
_file.flush()
|
||||
os.fsync(_file.fileno())
|
||||
except (OSError, EOFError) as ex:
|
||||
log.error("Unable to save %s: %s", filename, ex)
|
||||
log.error('Unable to save %s: %s', filename, ex)
|
||||
return False
|
||||
|
||||
try:
|
||||
log.debug("Creating backup of %s at: %s", filename, filepath_bak)
|
||||
log.debug('Creating backup of %s at: %s', filename, filepath_bak)
|
||||
if os.path.isfile(filepath_bak):
|
||||
os.remove(filepath_bak)
|
||||
if os.path.isfile(filepath):
|
||||
os.rename(filepath, filepath_bak)
|
||||
except OSError as ex:
|
||||
log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
|
||||
log.error('Unable to backup %s to %s: %s', filepath, filepath_bak, ex)
|
||||
return False
|
||||
|
||||
try:
|
||||
log.debug("Saving %s to: %s", filename, filepath)
|
||||
log.debug('Saving %s to: %s', filename, filepath)
|
||||
os.rename(filepath_tmp, filepath)
|
||||
except OSError as ex:
|
||||
log.error("Failed to set new file %s: %s", filepath, ex)
|
||||
log.error('Failed to set new file %s: %s', filepath, ex)
|
||||
if os.path.isfile(filepath_bak):
|
||||
log.info("Restoring backup from: %s", filepath_bak)
|
||||
log.info('Restoring backup from: %s', filepath_bak)
|
||||
os.rename(filepath_bak, filepath)
|
||||
else:
|
||||
# Sync the rename operations for the directory
|
||||
@ -920,58 +920,58 @@ class TorrentManager(component.Component):
|
||||
|
||||
def on_set_max_connections_per_torrent(self, key, value):
|
||||
"""Sets the per-torrent connection limit"""
|
||||
log.debug("max_connections_per_torrent set to %s...", value)
|
||||
log.debug('max_connections_per_torrent set to %s...', value)
|
||||
for key in self.torrents:
|
||||
self.torrents[key].set_max_connections(value)
|
||||
|
||||
def on_set_max_upload_slots_per_torrent(self, key, value):
|
||||
"""Sets the per-torrent upload slot limit"""
|
||||
log.debug("max_upload_slots_per_torrent set to %s...", value)
|
||||
log.debug('max_upload_slots_per_torrent set to %s...', value)
|
||||
for key in self.torrents:
|
||||
self.torrents[key].set_max_upload_slots(value)
|
||||
|
||||
def on_set_max_upload_speed_per_torrent(self, key, value):
|
||||
"""Sets the per-torrent upload speed limit"""
|
||||
log.debug("max_upload_speed_per_torrent set to %s...", value)
|
||||
log.debug('max_upload_speed_per_torrent set to %s...', value)
|
||||
for key in self.torrents:
|
||||
self.torrents[key].set_max_upload_speed(value)
|
||||
|
||||
def on_set_max_download_speed_per_torrent(self, key, value):
|
||||
"""Sets the per-torrent download speed limit"""
|
||||
log.debug("max_download_speed_per_torrent set to %s...", value)
|
||||
log.debug('max_download_speed_per_torrent set to %s...', value)
|
||||
for key in self.torrents:
|
||||
self.torrents[key].set_max_download_speed(value)
|
||||
|
||||
# --- Alert handlers ---
|
||||
def on_alert_torrent_finished(self, alert):
|
||||
"""Alert handler for libtorrent torrent_finished_alert"""
|
||||
log.debug("on_alert_torrent_finished")
|
||||
log.debug('on_alert_torrent_finished')
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
except (RuntimeError, KeyError):
|
||||
return
|
||||
log.debug("Finished %s ", torrent_id)
|
||||
log.debug('Finished %s ', torrent_id)
|
||||
|
||||
# If total_download is 0, do not move, it's likely the torrent wasn't downloaded, but just added.
|
||||
# Get fresh data from libtorrent, the cache isn't always up to date
|
||||
total_download = torrent.get_status(["total_payload_download"], update=True)["total_payload_download"]
|
||||
total_download = torrent.get_status(['total_payload_download'], update=True)['total_payload_download']
|
||||
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("Torrent settings: is_finished: %s, total_download: %s, move_completed: %s, move_path: %s",
|
||||
torrent.is_finished, total_download, torrent.options["move_completed"],
|
||||
torrent.options["move_completed_path"])
|
||||
log.debug('Torrent settings: is_finished: %s, total_download: %s, move_completed: %s, move_path: %s',
|
||||
torrent.is_finished, total_download, torrent.options['move_completed'],
|
||||
torrent.options['move_completed_path'])
|
||||
|
||||
torrent.update_state()
|
||||
if not torrent.is_finished and total_download:
|
||||
# Move completed download to completed folder if needed
|
||||
if torrent.options["move_completed"] and \
|
||||
torrent.options["download_location"] != torrent.options["move_completed_path"]:
|
||||
if torrent.options['move_completed'] and \
|
||||
torrent.options['download_location'] != torrent.options['move_completed_path']:
|
||||
self.waiting_on_finish_moving.append(torrent_id)
|
||||
torrent.move_storage(torrent.options["move_completed_path"])
|
||||
torrent.move_storage(torrent.options['move_completed_path'])
|
||||
else:
|
||||
torrent.is_finished = True
|
||||
component.get("EventManager").emit(TorrentFinishedEvent(torrent_id))
|
||||
component.get('EventManager').emit(TorrentFinishedEvent(torrent_id))
|
||||
else:
|
||||
torrent.is_finished = True
|
||||
|
||||
@ -994,7 +994,7 @@ class TorrentManager(component.Component):
|
||||
def on_alert_torrent_paused(self, alert):
|
||||
"""Alert handler for libtorrent torrent_paused_alert"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_torrent_paused")
|
||||
log.debug('on_alert_torrent_paused')
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
@ -1008,7 +1008,7 @@ class TorrentManager(component.Component):
|
||||
def on_alert_torrent_checked(self, alert):
|
||||
"""Alert handler for libtorrent torrent_checked_alert"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_torrent_checked")
|
||||
log.debug('on_alert_torrent_checked')
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
@ -1025,14 +1025,14 @@ class TorrentManager(component.Component):
|
||||
def on_alert_tracker_reply(self, alert):
|
||||
"""Alert handler for libtorrent tracker_reply_alert"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_tracker_reply: %s", decode_string(alert.message()))
|
||||
log.debug('on_alert_tracker_reply: %s', decode_string(alert.message()))
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
return
|
||||
|
||||
# Set the tracker status for the torrent
|
||||
torrent.set_tracker_status("Announce OK")
|
||||
torrent.set_tracker_status('Announce OK')
|
||||
|
||||
# Check for peer information from the tracker, if none then send a scrape request.
|
||||
if alert.handle.status().num_complete == -1 or alert.handle.status().num_incomplete == -1:
|
||||
@ -1041,24 +1041,24 @@ class TorrentManager(component.Component):
|
||||
def on_alert_tracker_announce(self, alert):
|
||||
"""Alert handler for libtorrent tracker_announce_alert"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_tracker_announce")
|
||||
log.debug('on_alert_tracker_announce')
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
return
|
||||
|
||||
# Set the tracker status for the torrent
|
||||
torrent.set_tracker_status("Announce Sent")
|
||||
torrent.set_tracker_status('Announce Sent')
|
||||
|
||||
def on_alert_tracker_warning(self, alert):
|
||||
"""Alert handler for libtorrent tracker_warning_alert"""
|
||||
log.debug("on_alert_tracker_warning")
|
||||
log.debug('on_alert_tracker_warning')
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
return
|
||||
# Set the tracker status for the torrent
|
||||
torrent.set_tracker_status("Warning: %s" % decode_string(alert.message()))
|
||||
torrent.set_tracker_status('Warning: %s' % decode_string(alert.message()))
|
||||
|
||||
def on_alert_tracker_error(self, alert):
|
||||
"""Alert handler for libtorrent tracker_error_alert"""
|
||||
@ -1071,17 +1071,17 @@ class TorrentManager(component.Component):
|
||||
# cannot be replaced by a.e.message because the code is included in the string (for non-'-1').
|
||||
if not error_message:
|
||||
error_message = decode_string(alert.error.message())
|
||||
log.debug("Tracker Error Alert: %s [%s]", decode_string(alert.message()), error_message)
|
||||
log.debug('Tracker Error Alert: %s [%s]', decode_string(alert.message()), error_message)
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
return
|
||||
|
||||
torrent.set_tracker_status("Error: " + error_message)
|
||||
torrent.set_tracker_status('Error: ' + error_message)
|
||||
|
||||
def on_alert_storage_moved(self, alert):
|
||||
"""Alert handler for libtorrent storage_moved_alert"""
|
||||
log.debug("on_alert_storage_moved")
|
||||
log.debug('on_alert_storage_moved')
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
@ -1100,11 +1100,11 @@ class TorrentManager(component.Component):
|
||||
if torrent_id in self.waiting_on_finish_moving:
|
||||
self.waiting_on_finish_moving.remove(torrent_id)
|
||||
torrent.is_finished = True
|
||||
component.get("EventManager").emit(TorrentFinishedEvent(torrent_id))
|
||||
component.get('EventManager').emit(TorrentFinishedEvent(torrent_id))
|
||||
|
||||
def on_alert_storage_moved_failed(self, alert):
|
||||
"""Alert handler for libtorrent storage_moved_failed_alert"""
|
||||
log.warning("on_alert_storage_moved_failed: %s", decode_string(alert.message()))
|
||||
log.warning('on_alert_storage_moved_failed: %s', decode_string(alert.message()))
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
@ -1113,23 +1113,23 @@ class TorrentManager(component.Component):
|
||||
# Set an Error message and pause the torrent
|
||||
alert_msg = decode_string(alert.message()).split(':', 1)[1].strip()
|
||||
torrent.moving_storage = False
|
||||
torrent.force_error_state("Failed to move download folder: %s" % alert_msg)
|
||||
torrent.force_error_state('Failed to move download folder: %s' % alert_msg)
|
||||
|
||||
if torrent_id in self.waiting_on_finish_moving:
|
||||
self.waiting_on_finish_moving.remove(torrent_id)
|
||||
torrent.is_finished = True
|
||||
component.get("EventManager").emit(TorrentFinishedEvent(torrent_id))
|
||||
component.get('EventManager').emit(TorrentFinishedEvent(torrent_id))
|
||||
|
||||
def on_alert_torrent_resumed(self, alert):
|
||||
"""Alert handler for libtorrent torrent_resumed_alert"""
|
||||
log.debug("on_alert_torrent_resumed")
|
||||
log.debug('on_alert_torrent_resumed')
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
except (RuntimeError, KeyError):
|
||||
return
|
||||
torrent.update_state()
|
||||
component.get("EventManager").emit(TorrentResumedEvent(torrent_id))
|
||||
component.get('EventManager').emit(TorrentResumedEvent(torrent_id))
|
||||
|
||||
def on_alert_state_changed(self, alert):
|
||||
"""Alert handler for libtorrent state_changed_alert.
|
||||
@ -1139,7 +1139,7 @@ class TorrentManager(component.Component):
|
||||
|
||||
"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_state_changed")
|
||||
log.debug('on_alert_state_changed')
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
@ -1155,7 +1155,7 @@ class TorrentManager(component.Component):
|
||||
def on_alert_save_resume_data(self, alert):
|
||||
"""Alert handler for libtorrent save_resume_data_alert"""
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
log.debug("on_alert_save_resume_data")
|
||||
log.debug('on_alert_save_resume_data')
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
except RuntimeError:
|
||||
@ -1169,7 +1169,7 @@ class TorrentManager(component.Component):
|
||||
|
||||
def on_alert_save_resume_data_failed(self, alert):
|
||||
"""Alert handler for libtorrent save_resume_data_failed_alert"""
|
||||
log.debug("on_alert_save_resume_data_failed: %s", decode_string(alert.message()))
|
||||
log.debug('on_alert_save_resume_data_failed: %s', decode_string(alert.message()))
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
except RuntimeError:
|
||||
@ -1181,7 +1181,7 @@ class TorrentManager(component.Component):
|
||||
def on_alert_fastresume_rejected(self, alert):
|
||||
"""Alert handler for libtorrent fastresume_rejected_alert"""
|
||||
alert_msg = decode_string(alert.message())
|
||||
log.error("on_alert_fastresume_rejected: %s", alert_msg)
|
||||
log.error('on_alert_fastresume_rejected: %s', alert_msg)
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
@ -1189,12 +1189,12 @@ class TorrentManager(component.Component):
|
||||
return
|
||||
|
||||
if alert.error.value() == 134:
|
||||
if not os.path.isdir(torrent.options["download_location"]):
|
||||
error_msg = "Unable to locate Download Folder!"
|
||||
if not os.path.isdir(torrent.options['download_location']):
|
||||
error_msg = 'Unable to locate Download Folder!'
|
||||
else:
|
||||
error_msg = "Missing or invalid torrent data!"
|
||||
error_msg = 'Missing or invalid torrent data!'
|
||||
else:
|
||||
error_msg = "Problem with resume data: %s" % alert_msg.split(":", 1)[1].strip()
|
||||
error_msg = 'Problem with resume data: %s' % alert_msg.split(':', 1)[1].strip()
|
||||
torrent.force_error_state(error_msg, restart_to_resume=True)
|
||||
|
||||
def on_alert_file_renamed(self, alert):
|
||||
@ -1204,13 +1204,13 @@ class TorrentManager(component.Component):
|
||||
TorrentFileRenamedEvent: Files in the torrent have been renamed.
|
||||
|
||||
"""
|
||||
log.debug("on_alert_file_renamed")
|
||||
log.debug('on_alert_file_renamed')
|
||||
try:
|
||||
new_name = decode_string(alert.new_name)
|
||||
except AttributeError:
|
||||
# Deprecated in libtorrent 1.1
|
||||
new_name = decode_string(alert.name)
|
||||
log.debug("index: %s name: %s", alert.index, new_name)
|
||||
log.debug('index: %s name: %s', alert.index, new_name)
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
torrent = self.torrents[torrent_id]
|
||||
@ -1224,12 +1224,12 @@ class TorrentManager(component.Component):
|
||||
break
|
||||
else:
|
||||
# This is just a regular file rename so send the signal
|
||||
component.get("EventManager").emit(TorrentFileRenamedEvent(torrent_id, alert.index, new_name))
|
||||
component.get('EventManager').emit(TorrentFileRenamedEvent(torrent_id, alert.index, new_name))
|
||||
self.save_resume_data((torrent_id,))
|
||||
|
||||
def on_alert_metadata_received(self, alert):
|
||||
"""Alert handler for libtorrent metadata_received_alert"""
|
||||
log.debug("on_alert_metadata_received")
|
||||
log.debug('on_alert_metadata_received')
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
@ -1238,7 +1238,7 @@ class TorrentManager(component.Component):
|
||||
|
||||
def on_alert_file_error(self, alert):
|
||||
"""Alert handler for libtorrent file_error_alert"""
|
||||
log.debug("on_alert_file_error: %s", decode_string(alert.message()))
|
||||
log.debug('on_alert_file_error: %s', decode_string(alert.message()))
|
||||
try:
|
||||
torrent = self.torrents[str(alert.handle.info_hash())]
|
||||
except (RuntimeError, KeyError):
|
||||
@ -1252,13 +1252,13 @@ class TorrentManager(component.Component):
|
||||
TorrentFileCompletedEvent: When an individual file completes downloading.
|
||||
|
||||
"""
|
||||
log.debug("file_completed_alert: %s", decode_string(alert.message()))
|
||||
log.debug('file_completed_alert: %s', decode_string(alert.message()))
|
||||
try:
|
||||
torrent_id = str(alert.handle.info_hash())
|
||||
except RuntimeError:
|
||||
return
|
||||
if torrent_id in self.torrents:
|
||||
component.get("EventManager").emit(TorrentFileCompletedEvent(torrent_id, alert.index))
|
||||
component.get('EventManager').emit(TorrentFileCompletedEvent(torrent_id, alert.index))
|
||||
|
||||
def on_alert_state_update(self, alert):
|
||||
"""Alert handler for libtorrent state_update_alert
|
||||
@ -1267,7 +1267,7 @@ class TorrentManager(component.Component):
|
||||
of all torrents that changed since last time this was posted.
|
||||
|
||||
"""
|
||||
log.debug("on_status_notification: %s", decode_string(alert.message()))
|
||||
log.debug('on_status_notification: %s', decode_string(alert.message()))
|
||||
self.last_state_update_alert_ts = time.time()
|
||||
|
||||
for t_status in alert.status:
|
||||
@ -1291,24 +1291,24 @@ class TorrentManager(component.Component):
|
||||
"""
|
||||
|
||||
external_ip = decode_string(alert.message()).split(' ')[-1]
|
||||
log.info("on_alert_external_ip: %s", external_ip)
|
||||
component.get("EventManager").emit(ExternalIPEvent(external_ip))
|
||||
log.info('on_alert_external_ip: %s', external_ip)
|
||||
component.get('EventManager').emit(ExternalIPEvent(external_ip))
|
||||
|
||||
def on_alert_performance(self, alert):
|
||||
"""Alert handler for libtorrent performance_alert"""
|
||||
log.warning("on_alert_performance: %s, %s", decode_string(alert.message()), alert.warning_code)
|
||||
log.warning('on_alert_performance: %s, %s', decode_string(alert.message()), alert.warning_code)
|
||||
if alert.warning_code == lt.performance_warning_t.send_buffer_watermark_too_low:
|
||||
max_send_buffer_watermark = 3 * 1024 * 1024 # 3MiB
|
||||
settings = self.session.get_settings()
|
||||
send_buffer_watermark = settings["send_buffer_watermark"]
|
||||
send_buffer_watermark = settings['send_buffer_watermark']
|
||||
|
||||
# If send buffer is too small, try increasing its size by 512KiB (up to max_send_buffer_watermark)
|
||||
if send_buffer_watermark < max_send_buffer_watermark:
|
||||
value = send_buffer_watermark + (500 * 1024)
|
||||
log.info("Increasing send_buffer_watermark from %s to %s Bytes", send_buffer_watermark, value)
|
||||
component.get("Core").apply_session_setting("send_buffer_watermark", value)
|
||||
log.info('Increasing send_buffer_watermark from %s to %s Bytes', send_buffer_watermark, value)
|
||||
component.get('Core').apply_session_setting('send_buffer_watermark', value)
|
||||
else:
|
||||
log.warning("send_buffer_watermark reached maximum value: %s Bytes", max_send_buffer_watermark)
|
||||
log.warning('send_buffer_watermark reached maximum value: %s Bytes', max_send_buffer_watermark)
|
||||
|
||||
def separate_keys(self, keys, torrent_ids):
|
||||
"""Separates the input keys into torrent class keys and plugins keys"""
|
||||
|
||||
@ -89,7 +89,7 @@ def _overrides(stack, method, explicit_base_classes=None):
|
||||
if explicit_base_classes:
|
||||
# One or more base classes are explicitly given, check only those classes
|
||||
override_classes = re.search(r'\s*@overrides\((.+)\)\s*', stack[1][4][0]).group(1)
|
||||
override_classes = [c.strip() for c in override_classes.split(",")]
|
||||
override_classes = [c.strip() for c in override_classes.split(',')]
|
||||
check_classes = override_classes
|
||||
|
||||
for c in base_classes + check_classes:
|
||||
@ -108,9 +108,9 @@ def _overrides(stack, method, explicit_base_classes=None):
|
||||
for cls in check_classes:
|
||||
if not hasattr(classes[cls], method.__name__):
|
||||
raise Exception("Function override '%s' not found in superclass: '%s'\n%s"
|
||||
% (method.__name__, cls, "File: %s:%s" % (stack[1][1], stack[1][2])))
|
||||
% (method.__name__, cls, 'File: %s:%s' % (stack[1][1], stack[1][2])))
|
||||
|
||||
if not any(hasattr(classes[cls], method.__name__) for cls in check_classes):
|
||||
raise Exception("Function override '%s' not found in any superclass: '%s'\n%s"
|
||||
% (method.__name__, check_classes, "File: %s:%s" % (stack[1][1], stack[1][2])))
|
||||
% (method.__name__, check_classes, 'File: %s:%s' % (stack[1][1], stack[1][2])))
|
||||
return method
|
||||
|
||||
@ -49,7 +49,7 @@ class WrappedException(DelugeError):
|
||||
self.traceback = traceback
|
||||
|
||||
def __str__(self):
|
||||
return "%s\n%s" % (self.message, self.traceback)
|
||||
return '%s\n%s' % (self.message, self.traceback)
|
||||
|
||||
|
||||
class _ClientSideRecreateError(DelugeError):
|
||||
@ -60,8 +60,8 @@ class IncompatibleClient(_ClientSideRecreateError):
|
||||
|
||||
def __init__(self, daemon_version):
|
||||
self.daemon_version = daemon_version
|
||||
msg = "Your deluge client is not compatible with the daemon. "\
|
||||
"Please upgrade your client to %(daemon_version)s" % \
|
||||
msg = 'Your deluge client is not compatible with the daemon. '\
|
||||
'Please upgrade your client to %(daemon_version)s' % \
|
||||
dict(daemon_version=self.daemon_version)
|
||||
super(IncompatibleClient, self).__init__(message=msg)
|
||||
|
||||
@ -69,7 +69,7 @@ class IncompatibleClient(_ClientSideRecreateError):
|
||||
class NotAuthorizedError(_ClientSideRecreateError):
|
||||
|
||||
def __init__(self, current_level, required_level):
|
||||
msg = "Auth level too low: %(current_level)s < %(required_level)s" % \
|
||||
msg = 'Auth level too low: %(current_level)s < %(required_level)s' % \
|
||||
dict(current_level=current_level, required_level=required_level)
|
||||
super(NotAuthorizedError, self).__init__(message=msg)
|
||||
self.current_level = current_level
|
||||
|
||||
@ -24,7 +24,7 @@ class DelugeEventMetaClass(type):
|
||||
"""
|
||||
def __init__(self, name, bases, dct): # pylint: disable=bad-mcs-method-argument
|
||||
super(DelugeEventMetaClass, self).__init__(name, bases, dct)
|
||||
if name != "DelugeEvent":
|
||||
if name != 'DelugeEvent':
|
||||
known_events[name] = self
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ class DelugeEvent(object):
|
||||
return self.__class__.__name__
|
||||
|
||||
def _get_args(self):
|
||||
if not hasattr(self, "_args"):
|
||||
if not hasattr(self, '_args'):
|
||||
return []
|
||||
return self._args
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ class HTTPDownloader(client.HTTPDownloader):
|
||||
self.force_filename = force_filename
|
||||
self.allow_compression = allow_compression
|
||||
self.code = None
|
||||
agent = "Deluge/%s (http://deluge-torrent.org)" % get_version()
|
||||
agent = 'Deluge/%s (http://deluge-torrent.org)' % get_version()
|
||||
client.HTTPDownloader.__init__(self, url, filename, headers=headers, agent=agent)
|
||||
|
||||
def gotStatus(self, version, status, message): # NOQA
|
||||
@ -58,19 +58,19 @@ class HTTPDownloader(client.HTTPDownloader):
|
||||
|
||||
def gotHeaders(self, headers): # NOQA
|
||||
if self.code == http.OK:
|
||||
if "content-length" in headers:
|
||||
self.total_length = int(headers["content-length"][0])
|
||||
if 'content-length' in headers:
|
||||
self.total_length = int(headers['content-length'][0])
|
||||
else:
|
||||
self.total_length = 0
|
||||
|
||||
if self.allow_compression and "content-encoding" in headers and \
|
||||
headers["content-encoding"][0] in ("gzip", "x-gzip", "deflate"):
|
||||
if self.allow_compression and 'content-encoding' in headers and \
|
||||
headers['content-encoding'][0] in ('gzip', 'x-gzip', 'deflate'):
|
||||
# Adding 32 to the wbits enables gzip & zlib decoding (with automatic header detection)
|
||||
# Adding 16 just enables gzip decoding (no zlib)
|
||||
self.decoder = zlib.decompressobj(zlib.MAX_WBITS + 32)
|
||||
|
||||
if "content-disposition" in headers and not self.force_filename:
|
||||
new_file_name = str(headers["content-disposition"][0]).split(";")[1].split("=")[1]
|
||||
if 'content-disposition' in headers and not self.force_filename:
|
||||
new_file_name = str(headers['content-disposition'][0]).split(';')[1].split('=')[1]
|
||||
new_file_name = sanitise_filename(new_file_name)
|
||||
new_file_name = os.path.join(os.path.split(self.value)[0], new_file_name)
|
||||
|
||||
@ -79,14 +79,14 @@ class HTTPDownloader(client.HTTPDownloader):
|
||||
fileext = os.path.splitext(new_file_name)[1]
|
||||
while os.path.isfile(new_file_name):
|
||||
# Increment filename if already exists
|
||||
new_file_name = "%s-%s%s" % (fileroot, count, fileext)
|
||||
new_file_name = '%s-%s%s' % (fileroot, count, fileext)
|
||||
count += 1
|
||||
|
||||
self.fileName = new_file_name
|
||||
self.value = new_file_name
|
||||
|
||||
elif self.code in (http.MOVED_PERMANENTLY, http.FOUND, http.SEE_OTHER, http.TEMPORARY_REDIRECT):
|
||||
location = headers["location"][0]
|
||||
location = headers['location'][0]
|
||||
error = PageRedirect(self.code, location=location)
|
||||
self.noPage(Failure(error))
|
||||
|
||||
@ -133,7 +133,7 @@ def sanitise_filename(filename):
|
||||
filename = os.path.basename(filename)
|
||||
|
||||
filename = filename.strip()
|
||||
if filename.startswith(".") or ";" in filename or "|" in filename:
|
||||
if filename.startswith('.') or ';' in filename or '|' in filename:
|
||||
# Dodgy server, log it
|
||||
log.warning("Potentially malicious server: trying to write to file '%s'", filename)
|
||||
|
||||
@ -172,11 +172,11 @@ def _download_file(url, filename, callback=None, headers=None, force_filename=Fa
|
||||
if allow_compression:
|
||||
if not headers:
|
||||
headers = {}
|
||||
headers["accept-encoding"] = "deflate, gzip, x-gzip"
|
||||
headers['accept-encoding'] = 'deflate, gzip, x-gzip'
|
||||
|
||||
# In Twisted 13.1.0 _parse() function replaced by _URI class.
|
||||
# In Twisted 15.0.0 _URI class renamed to URI.
|
||||
if hasattr(client, "_parse"):
|
||||
if hasattr(client, '_parse'):
|
||||
scheme, host, port, dummy_path = client._parse(url)
|
||||
else:
|
||||
try:
|
||||
@ -190,7 +190,7 @@ def _download_file(url, filename, callback=None, headers=None, force_filename=Fa
|
||||
port = uri.port
|
||||
|
||||
factory = HTTPDownloader(url, filename, callback, headers, force_filename, allow_compression)
|
||||
if scheme == "https":
|
||||
if scheme == 'https':
|
||||
from twisted.internet import ssl
|
||||
# ClientTLSOptions in Twisted >= 14, see ticket #2765 for details on this addition.
|
||||
try:
|
||||
@ -241,12 +241,12 @@ def download_file(url, filename, callback=None, headers=None, force_filename=Fal
|
||||
|
||||
"""
|
||||
def on_download_success(result):
|
||||
log.debug("Download success!")
|
||||
log.debug('Download success!')
|
||||
return result
|
||||
|
||||
def on_download_fail(failure):
|
||||
if failure.check(PageRedirect) and handle_redirects:
|
||||
new_url = urljoin(url, failure.getErrorMessage().split(" to ")[1])
|
||||
new_url = urljoin(url, failure.getErrorMessage().split(' to ')[1])
|
||||
result = _download_file(new_url, filename, callback=callback, headers=headers,
|
||||
force_filename=force_filename,
|
||||
allow_compression=allow_compression)
|
||||
|
||||
@ -21,14 +21,14 @@ from twisted.python.log import PythonLoggingObserver
|
||||
|
||||
from deluge import common
|
||||
|
||||
__all__ = ("setup_logger", "set_logger_level", "get_plugin_logger", "LOG")
|
||||
__all__ = ('setup_logger', 'set_logger_level', 'get_plugin_logger', 'LOG')
|
||||
|
||||
LoggingLoggerClass = logging.getLoggerClass()
|
||||
|
||||
if "dev" in common.get_version():
|
||||
DEFAULT_LOGGING_FORMAT = "%%(asctime)s.%%(msecs)03.0f [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s"
|
||||
if 'dev' in common.get_version():
|
||||
DEFAULT_LOGGING_FORMAT = '%%(asctime)s.%%(msecs)03.0f [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s'
|
||||
else:
|
||||
DEFAULT_LOGGING_FORMAT = "%%(asctime)s [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s"
|
||||
DEFAULT_LOGGING_FORMAT = '%%(asctime)s [%%(levelname)-8s][%%(name)-%ds:%%(lineno)-4d] %%(message)s'
|
||||
MAX_LOGGER_NAME_LENGTH = 10
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ class Logging(LoggingLoggerClass):
|
||||
for handler in logging.getLogger().handlers:
|
||||
handler.setFormatter(logging.Formatter(
|
||||
DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH,
|
||||
datefmt="%H:%M:%S"
|
||||
datefmt='%H:%M:%S'
|
||||
))
|
||||
|
||||
@defer.inlineCallbacks
|
||||
@ -83,12 +83,12 @@ class Logging(LoggingLoggerClass):
|
||||
|
||||
def findCaller(self): # NOQA
|
||||
f = logging.currentframe().f_back
|
||||
rv = "(unknown file)", 0, "(unknown function)"
|
||||
while hasattr(f, "f_code"):
|
||||
rv = '(unknown file)', 0, '(unknown function)'
|
||||
while hasattr(f, 'f_code'):
|
||||
co = f.f_code
|
||||
filename = os.path.normcase(co.co_filename)
|
||||
if filename in (__file__.replace(".pyc", ".py"),
|
||||
defer.__file__.replace(".pyc", ".py")):
|
||||
if filename in (__file__.replace('.pyc', '.py'),
|
||||
defer.__file__.replace('.pyc', '.py')):
|
||||
f = f.f_back
|
||||
continue
|
||||
rv = (filename, f.f_lineno, co.co_name)
|
||||
@ -96,18 +96,18 @@ class Logging(LoggingLoggerClass):
|
||||
return rv
|
||||
|
||||
levels = {
|
||||
"info": logging.INFO,
|
||||
"warn": logging.WARNING,
|
||||
"warning": logging.WARNING,
|
||||
"error": logging.ERROR,
|
||||
"none": logging.CRITICAL,
|
||||
"debug": logging.DEBUG,
|
||||
"trace": 5,
|
||||
"garbage": 1
|
||||
'info': logging.INFO,
|
||||
'warn': logging.WARNING,
|
||||
'warning': logging.WARNING,
|
||||
'error': logging.ERROR,
|
||||
'none': logging.CRITICAL,
|
||||
'debug': logging.DEBUG,
|
||||
'trace': 5,
|
||||
'garbage': 1
|
||||
}
|
||||
|
||||
|
||||
def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
|
||||
def setup_logger(level='error', filename=None, filemode='w', logrotate=None,
|
||||
output_stream=sys.stdout, twisted_observer=True):
|
||||
"""
|
||||
Sets up the basic logger and if `:param:filename` is set, then it will log
|
||||
@ -125,8 +125,8 @@ def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
|
||||
"""
|
||||
if logging.getLoggerClass() is not Logging:
|
||||
logging.setLoggerClass(Logging)
|
||||
logging.addLevelName(5, "TRACE")
|
||||
logging.addLevelName(1, "GARBAGE")
|
||||
logging.addLevelName(5, 'TRACE')
|
||||
logging.addLevelName(1, 'GARBAGE')
|
||||
|
||||
level = levels.get(level, logging.ERROR)
|
||||
|
||||
@ -135,13 +135,13 @@ def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
|
||||
if filename and logrotate:
|
||||
handler = logging.handlers.RotatingFileHandler(
|
||||
filename, maxBytes=logrotate,
|
||||
backupCount=5, encoding="utf-8"
|
||||
backupCount=5, encoding='utf-8'
|
||||
)
|
||||
elif filename and filemode == "w":
|
||||
elif filename and filemode == 'w':
|
||||
handler_cls = logging.FileHandler
|
||||
if not common.windows_check():
|
||||
handler_cls = getattr(logging.handlers, "WatchedFileHandler", logging.FileHandler)
|
||||
handler = handler_cls(filename, mode=filemode, encoding="utf-8")
|
||||
handler_cls = getattr(logging.handlers, 'WatchedFileHandler', logging.FileHandler)
|
||||
handler = handler_cls(filename, mode=filemode, encoding='utf-8')
|
||||
else:
|
||||
handler = logging.StreamHandler(stream=output_stream)
|
||||
|
||||
@ -149,7 +149,7 @@ def setup_logger(level="error", filename=None, filemode="w", logrotate=None,
|
||||
|
||||
formatter = logging.Formatter(
|
||||
DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH,
|
||||
datefmt="%H:%M:%S"
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
|
||||
handler.setFormatter(formatter)
|
||||
@ -182,9 +182,9 @@ class TwistedLoggingObserver(PythonLoggingObserver):
|
||||
|
||||
def emit(self, event_dict):
|
||||
log = logging.getLogger(__name__)
|
||||
if "log_failure" in event_dict:
|
||||
fmt = "%(log_namespace)s \n%(log_failure)s"
|
||||
getattr(LoggingLoggerClass, event_dict["log_level"].name)(log, fmt % (event_dict))
|
||||
if 'log_failure' in event_dict:
|
||||
fmt = '%(log_namespace)s \n%(log_failure)s'
|
||||
getattr(LoggingLoggerClass, event_dict['log_level'].name)(log, fmt % (event_dict))
|
||||
else:
|
||||
PythonLoggingObserver.emit(self, event_dict)
|
||||
|
||||
@ -208,17 +208,17 @@ def tweak_logging_levels():
|
||||
the command line.
|
||||
"""
|
||||
from deluge import configmanager
|
||||
logging_config_file = os.path.join(configmanager.get_config_dir(), "logging.conf")
|
||||
logging_config_file = os.path.join(configmanager.get_config_dir(), 'logging.conf')
|
||||
if not os.path.isfile(logging_config_file):
|
||||
return
|
||||
log = logging.getLogger(__name__)
|
||||
log.warn("logging.conf found! tweaking logging levels from %s",
|
||||
log.warn('logging.conf found! tweaking logging levels from %s',
|
||||
logging_config_file)
|
||||
with open(logging_config_file, "r") as _file:
|
||||
with open(logging_config_file, 'r') as _file:
|
||||
for line in _file:
|
||||
if line.strip().startswith("#"):
|
||||
if line.strip().startswith('#'):
|
||||
continue
|
||||
name, level = line.strip().split(":")
|
||||
name, level = line.strip().split(':')
|
||||
if level not in levels:
|
||||
continue
|
||||
|
||||
@ -236,7 +236,7 @@ def set_logger_level(level, logger_name=None):
|
||||
tweak the root logger level.
|
||||
|
||||
"""
|
||||
logging.getLogger(logger_name).setLevel(levels.get(level, "error"))
|
||||
logging.getLogger(logger_name).setLevel(levels.get(level, 'error'))
|
||||
|
||||
|
||||
def get_plugin_logger(logger_name):
|
||||
@ -246,14 +246,14 @@ def get_plugin_logger(logger_name):
|
||||
module_stack = stack.pop(0) # The module that called the log function
|
||||
caller_module = inspect.getmodule(module_stack[0])
|
||||
# In some weird cases caller_module might be None, try to continue
|
||||
caller_module_name = getattr(caller_module, "__name__", "")
|
||||
caller_module_name = getattr(caller_module, '__name__', '')
|
||||
warnings.warn_explicit(DEPRECATION_WARNING, DeprecationWarning,
|
||||
module_stack[1], module_stack[2],
|
||||
caller_module_name)
|
||||
|
||||
if "deluge.plugins." in logger_name:
|
||||
if 'deluge.plugins.' in logger_name:
|
||||
return logging.getLogger(logger_name)
|
||||
return logging.getLogger("deluge.plugin.%s" % logger_name)
|
||||
return logging.getLogger('deluge.plugin.%s' % logger_name)
|
||||
|
||||
|
||||
DEPRECATION_WARNING = """You seem to be using old style logging on your code, ie:
|
||||
@ -282,13 +282,13 @@ Triggering code:"""
|
||||
class _BackwardsCompatibleLOG(object):
|
||||
def __getattribute__(self, name):
|
||||
import warnings
|
||||
logger_name = "deluge"
|
||||
logger_name = 'deluge'
|
||||
stack = inspect.stack()
|
||||
stack.pop(0) # The logging call from this module
|
||||
module_stack = stack.pop(0) # The module that called the log function
|
||||
caller_module = inspect.getmodule(module_stack[0])
|
||||
# In some weird cases caller_module might be None, try to continue
|
||||
caller_module_name = getattr(caller_module, "__name__", "")
|
||||
caller_module_name = getattr(caller_module, '__name__', '')
|
||||
warnings.warn_explicit(DEPRECATION_WARNING, DeprecationWarning,
|
||||
module_stack[1], module_stack[2],
|
||||
caller_module_name)
|
||||
@ -297,16 +297,16 @@ class _BackwardsCompatibleLOG(object):
|
||||
module = inspect.getmodule(member[0])
|
||||
if not module:
|
||||
continue
|
||||
if module.__name__ in ("deluge.plugins.pluginbase",
|
||||
"deluge.plugins.init"):
|
||||
logger_name += ".plugin.%s" % caller_module_name
|
||||
if module.__name__ in ('deluge.plugins.pluginbase',
|
||||
'deluge.plugins.init'):
|
||||
logger_name += '.plugin.%s' % caller_module_name
|
||||
# Monkey Patch The Plugin Module
|
||||
caller_module.log = logging.getLogger(logger_name)
|
||||
break
|
||||
else:
|
||||
logging.getLogger(logger_name).warning(
|
||||
"Unable to monkey-patch the calling module's `log` attribute! "
|
||||
"You should really update and rebuild your plugins..."
|
||||
'You should really update and rebuild your plugins...'
|
||||
)
|
||||
return getattr(logging.getLogger(logger_name), name)
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ class TorrentMetadata(object):
|
||||
def __init__(self):
|
||||
self.__data_path = None
|
||||
self.__piece_size = 0
|
||||
self.__comment = ""
|
||||
self.__comment = ''
|
||||
self.__private = False
|
||||
self.__trackers = []
|
||||
self.__webseeds = []
|
||||
@ -65,37 +65,37 @@ class TorrentMetadata(object):
|
||||
|
||||
"""
|
||||
if not self.data_path:
|
||||
raise InvalidPath("Need to set a data_path!")
|
||||
raise InvalidPath('Need to set a data_path!')
|
||||
|
||||
torrent = {
|
||||
"info": {}
|
||||
'info': {}
|
||||
}
|
||||
|
||||
if self.comment:
|
||||
torrent["comment"] = self.comment.encode("UTF-8")
|
||||
torrent['comment'] = self.comment.encode('UTF-8')
|
||||
|
||||
if self.private:
|
||||
torrent["info"]["private"] = True
|
||||
torrent['info']['private'] = True
|
||||
|
||||
if self.trackers:
|
||||
torrent["announce"] = self.trackers[0][0]
|
||||
torrent["announce-list"] = self.trackers
|
||||
torrent['announce'] = self.trackers[0][0]
|
||||
torrent['announce-list'] = self.trackers
|
||||
else:
|
||||
torrent["announce"] = ""
|
||||
torrent['announce'] = ''
|
||||
|
||||
if self.webseeds:
|
||||
httpseeds = []
|
||||
webseeds = []
|
||||
for w in self.webseeds:
|
||||
if w.endswith(".php"):
|
||||
if w.endswith('.php'):
|
||||
httpseeds.append(w)
|
||||
else:
|
||||
webseeds.append(w)
|
||||
|
||||
if httpseeds:
|
||||
torrent["httpseeds"] = httpseeds
|
||||
torrent['httpseeds'] = httpseeds
|
||||
if webseeds:
|
||||
torrent["url-list"] = webseeds
|
||||
torrent['url-list'] = webseeds
|
||||
|
||||
datasize = get_path_size(self.data_path)
|
||||
|
||||
@ -112,11 +112,11 @@ class TorrentMetadata(object):
|
||||
if datasize % piece_size:
|
||||
num_pieces += 1
|
||||
|
||||
torrent["info"]["piece length"] = piece_size
|
||||
torrent['info']['piece length'] = piece_size
|
||||
|
||||
# Create the info
|
||||
if os.path.isdir(self.data_path):
|
||||
torrent["info"]["name"] = os.path.split(self.data_path)[1]
|
||||
torrent['info']['name'] = os.path.split(self.data_path)[1]
|
||||
files = []
|
||||
padding_count = 0
|
||||
# Collect a list of file paths and add padding files if necessary
|
||||
@ -124,8 +124,8 @@ class TorrentMetadata(object):
|
||||
for index, filename in enumerate(filenames):
|
||||
size = get_path_size(os.path.join(self.data_path, dirpath, filename))
|
||||
p = dirpath[len(self.data_path):]
|
||||
p = p.lstrip("/")
|
||||
p = p.split("/")
|
||||
p = p.lstrip('/')
|
||||
p = p.split('/')
|
||||
if p[0]:
|
||||
p += [filename]
|
||||
else:
|
||||
@ -136,7 +136,7 @@ class TorrentMetadata(object):
|
||||
left = size % piece_size
|
||||
if left:
|
||||
p = list(p)
|
||||
p[-1] = "_____padding_file_" + str(padding_count)
|
||||
p[-1] = '_____padding_file_' + str(padding_count)
|
||||
files.append((piece_size - left, p))
|
||||
padding_count += 1
|
||||
|
||||
@ -147,17 +147,17 @@ class TorrentMetadata(object):
|
||||
fs = []
|
||||
pieces = []
|
||||
# Create the piece hashes
|
||||
buf = ""
|
||||
buf = ''
|
||||
for size, path in files:
|
||||
path = [s.decode(sys.getfilesystemencoding()).encode("UTF-8") for s in path]
|
||||
fs.append({"length": size, "path": path})
|
||||
if path[-1].startswith("_____padding_file_"):
|
||||
buf += "\0" * size
|
||||
path = [s.decode(sys.getfilesystemencoding()).encode('UTF-8') for s in path]
|
||||
fs.append({'length': size, 'path': path})
|
||||
if path[-1].startswith('_____padding_file_'):
|
||||
buf += '\0' * size
|
||||
pieces.append(sha(buf).digest())
|
||||
buf = ""
|
||||
fs[-1]["attr"] = "p"
|
||||
buf = ''
|
||||
fs[-1]['attr'] = 'p'
|
||||
else:
|
||||
with open(os.path.join(self.data_path, *path), "rb") as _file:
|
||||
with open(os.path.join(self.data_path, *path), 'rb') as _file:
|
||||
r = _file.read(piece_size - len(buf))
|
||||
while r:
|
||||
buf += r
|
||||
@ -166,7 +166,7 @@ class TorrentMetadata(object):
|
||||
# Run the progress function if necessary
|
||||
if progress:
|
||||
progress(len(pieces), num_pieces)
|
||||
buf = ""
|
||||
buf = ''
|
||||
else:
|
||||
break
|
||||
r = _file.read(piece_size - len(buf))
|
||||
@ -175,17 +175,17 @@ class TorrentMetadata(object):
|
||||
pieces.append(sha(buf).digest())
|
||||
if progress:
|
||||
progress(len(pieces), num_pieces)
|
||||
buf = ""
|
||||
buf = ''
|
||||
|
||||
torrent["info"]["pieces"] = "".join(pieces)
|
||||
torrent["info"]["files"] = fs
|
||||
torrent['info']['pieces'] = ''.join(pieces)
|
||||
torrent['info']['files'] = fs
|
||||
|
||||
elif os.path.isfile(self.data_path):
|
||||
torrent["info"]["name"] = os.path.split(self.data_path)[1]
|
||||
torrent["info"]["length"] = get_path_size(self.data_path)
|
||||
torrent['info']['name'] = os.path.split(self.data_path)[1]
|
||||
torrent['info']['length'] = get_path_size(self.data_path)
|
||||
pieces = []
|
||||
|
||||
with open(self.data_path, "rb") as _file:
|
||||
with open(self.data_path, 'rb') as _file:
|
||||
r = _file.read(piece_size)
|
||||
while r:
|
||||
pieces.append(sha(r).digest())
|
||||
@ -194,10 +194,10 @@ class TorrentMetadata(object):
|
||||
|
||||
r = _file.read(piece_size)
|
||||
|
||||
torrent["info"]["pieces"] = "".join(pieces)
|
||||
torrent['info']['pieces'] = ''.join(pieces)
|
||||
|
||||
# Write out the torrent file
|
||||
with open(torrent_path, "wb") as _file:
|
||||
with open(torrent_path, 'wb') as _file:
|
||||
_file.write(bencode(torrent))
|
||||
|
||||
def get_data_path(self):
|
||||
@ -228,7 +228,7 @@ class TorrentMetadata(object):
|
||||
if os.path.exists(path) and (os.path.isdir(path) or os.path.isfile(path)):
|
||||
self.__data_path = os.path.abspath(path)
|
||||
else:
|
||||
raise InvalidPath("No such file or directory: %s" % path)
|
||||
raise InvalidPath('No such file or directory: %s' % path)
|
||||
|
||||
def get_piece_size(self):
|
||||
"""The size of the pieces.
|
||||
@ -254,7 +254,7 @@ class TorrentMetadata(object):
|
||||
|
||||
"""
|
||||
if size % 16 and size:
|
||||
raise InvalidPieceSize("Piece size must be a multiple of 16 KiB")
|
||||
raise InvalidPieceSize('Piece size must be a multiple of 16 KiB')
|
||||
self.__piece_size = size
|
||||
|
||||
def get_comment(self):
|
||||
|
||||
@ -47,10 +47,10 @@ def get_filesystem_encoding():
|
||||
def decode_from_filesystem(path):
|
||||
encoding = get_filesystem_encoding()
|
||||
if encoding is None:
|
||||
assert isinstance(path, unicode), "Path should be unicode not %s" % type(path)
|
||||
assert isinstance(path, unicode), 'Path should be unicode not %s' % type(path)
|
||||
decoded_path = path
|
||||
else:
|
||||
assert isinstance(path, str), "Path should be str not %s" % type(path)
|
||||
assert isinstance(path, str), 'Path should be str not %s' % type(path)
|
||||
decoded_path = path.decode(encoding)
|
||||
|
||||
return decoded_path
|
||||
@ -65,7 +65,7 @@ class RemoteFileProgress(object):
|
||||
self.session_id = session_id
|
||||
|
||||
def __call__(self, piece_count, num_pieces):
|
||||
component.get("RPCServer").emit_event_for_session_id(
|
||||
component.get('RPCServer').emit_event_for_session_id(
|
||||
self.session_id, CreateTorrentProgressEvent(piece_count, num_pieces)
|
||||
)
|
||||
|
||||
@ -86,11 +86,11 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
|
||||
f = target
|
||||
|
||||
if progress is None:
|
||||
session_id = component.get("RPCServer").get_session_id()
|
||||
session_id = component.get('RPCServer').get_session_id()
|
||||
if not session_id:
|
||||
progress = dummy
|
||||
else:
|
||||
progress = RemoteFileProgress(component.get("RPCServer").get_session_id())
|
||||
progress = RemoteFileProgress(component.get('RPCServer').get_session_id())
|
||||
|
||||
info = makeinfo(path, piece_length, progress, name, content_type, private)
|
||||
|
||||
@ -99,18 +99,18 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
|
||||
|
||||
data['info'] = info
|
||||
if title:
|
||||
data['title'] = title.encode("utf8")
|
||||
data['title'] = title.encode('utf8')
|
||||
if comment:
|
||||
data['comment'] = comment.encode("utf8")
|
||||
data['comment'] = comment.encode('utf8')
|
||||
if safe:
|
||||
data['safe'] = safe.encode("utf8")
|
||||
data['safe'] = safe.encode('utf8')
|
||||
|
||||
httpseeds = []
|
||||
url_list = []
|
||||
|
||||
if webseeds:
|
||||
for webseed in webseeds:
|
||||
if webseed.endswith(".php"):
|
||||
if webseed.endswith('.php'):
|
||||
httpseeds.append(webseed)
|
||||
else:
|
||||
url_list.append(webseed)
|
||||
@ -120,12 +120,12 @@ def make_meta_file(path, url, piece_length, progress=None, title=None, comment=N
|
||||
if httpseeds:
|
||||
data['httpseeds'] = httpseeds
|
||||
if created_by:
|
||||
data['created by'] = created_by.encode("utf8")
|
||||
data['created by'] = created_by.encode('utf8')
|
||||
|
||||
if trackers and (len(trackers[0]) > 1 or len(trackers) > 1):
|
||||
data['announce-list'] = trackers
|
||||
|
||||
data["encoding"] = "UTF-8"
|
||||
data['encoding'] = 'UTF-8'
|
||||
|
||||
h.write(bencode(data))
|
||||
h.close()
|
||||
|
||||
@ -41,9 +41,9 @@ def get_completion_paths(args):
|
||||
:rtype: list
|
||||
|
||||
"""
|
||||
args["paths"] = []
|
||||
path_value = args["completion_text"]
|
||||
hidden_files = args["show_hidden_files"]
|
||||
args['paths'] = []
|
||||
path_value = args['completion_text']
|
||||
hidden_files = args['show_hidden_files']
|
||||
|
||||
def get_subdirs(dirname):
|
||||
try:
|
||||
@ -78,5 +78,5 @@ def get_completion_paths(args):
|
||||
p += os.path.sep
|
||||
matching_dirs.append(p)
|
||||
|
||||
args["paths"] = sorted(matching_dirs)
|
||||
args['paths'] = sorted(matching_dirs)
|
||||
return args
|
||||
|
||||
@ -24,15 +24,15 @@ import deluge.configmanager
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
METADATA_KEYS = [
|
||||
"Name",
|
||||
"License",
|
||||
"Author",
|
||||
"Home-page",
|
||||
"Summary",
|
||||
"Platform",
|
||||
"Version",
|
||||
"Author-email",
|
||||
"Description",
|
||||
'Name',
|
||||
'License',
|
||||
'Author',
|
||||
'Home-page',
|
||||
'Summary',
|
||||
'Platform',
|
||||
'Version',
|
||||
'Author-email',
|
||||
'Description',
|
||||
]
|
||||
|
||||
DEPRECATION_WARNING = """
|
||||
@ -50,13 +50,13 @@ class PluginManagerBase(object):
|
||||
"""PluginManagerBase is a base class for PluginManagers to inherit"""
|
||||
|
||||
def __init__(self, config_file, entry_name):
|
||||
log.debug("Plugin manager init..")
|
||||
log.debug('Plugin manager init..')
|
||||
|
||||
self.config = deluge.configmanager.ConfigManager(config_file)
|
||||
|
||||
# Create the plugins folder if it doesn't exist
|
||||
if not os.path.exists(os.path.join(deluge.configmanager.get_config_dir(), "plugins")):
|
||||
os.mkdir(os.path.join(deluge.configmanager.get_config_dir(), "plugins"))
|
||||
if not os.path.exists(os.path.join(deluge.configmanager.get_config_dir(), 'plugins')):
|
||||
os.mkdir(os.path.join(deluge.configmanager.get_config_dir(), 'plugins'))
|
||||
|
||||
# This is the entry we want to load..
|
||||
self.entry_name = entry_name
|
||||
@ -69,7 +69,7 @@ class PluginManagerBase(object):
|
||||
|
||||
def enable_plugins(self):
|
||||
# Load plugins that are enabled in the config.
|
||||
for name in self.config["enabled_plugins"]:
|
||||
for name in self.config['enabled_plugins']:
|
||||
self.enable_plugin(name)
|
||||
|
||||
def disable_plugins(self):
|
||||
@ -91,9 +91,9 @@ class PluginManagerBase(object):
|
||||
|
||||
def scan_for_plugins(self):
|
||||
"""Scans for available plugins"""
|
||||
base_plugin_dir = deluge.common.resource_filename("deluge", "plugins")
|
||||
base_plugin_dir = deluge.common.resource_filename('deluge', 'plugins')
|
||||
pkg_resources.working_set.add_entry(base_plugin_dir)
|
||||
user_plugin_dir = os.path.join(deluge.configmanager.get_config_dir(), "plugins")
|
||||
user_plugin_dir = os.path.join(deluge.configmanager.get_config_dir(), 'plugins')
|
||||
|
||||
plugins_dirs = [base_plugin_dir]
|
||||
for dirname in os.listdir(base_plugin_dir):
|
||||
@ -107,7 +107,7 @@ class PluginManagerBase(object):
|
||||
|
||||
self.available_plugins = []
|
||||
for name in self.pkg_env:
|
||||
log.debug("Found plugin: %s %s at %s",
|
||||
log.debug('Found plugin: %s %s at %s',
|
||||
self.pkg_env[name][0].project_name,
|
||||
self.pkg_env[name][0].version,
|
||||
self.pkg_env[name][0].location)
|
||||
@ -125,14 +125,14 @@ class PluginManagerBase(object):
|
||||
|
||||
"""
|
||||
if plugin_name not in self.available_plugins:
|
||||
log.warning("Cannot enable non-existant plugin %s", plugin_name)
|
||||
log.warning('Cannot enable non-existant plugin %s', plugin_name)
|
||||
return defer.succeed(False)
|
||||
|
||||
if plugin_name in self.plugins:
|
||||
log.warning("Cannot enable already enabled plugin %s", plugin_name)
|
||||
log.warning('Cannot enable already enabled plugin %s', plugin_name)
|
||||
return defer.succeed(True)
|
||||
|
||||
plugin_name = plugin_name.replace(" ", "-")
|
||||
plugin_name = plugin_name.replace(' ', '-')
|
||||
egg = self.pkg_env[plugin_name][0]
|
||||
egg.activate()
|
||||
return_d = defer.succeed(True)
|
||||
@ -141,12 +141,12 @@ class PluginManagerBase(object):
|
||||
entry_point = egg.get_entry_info(self.entry_name, name)
|
||||
try:
|
||||
cls = entry_point.load()
|
||||
instance = cls(plugin_name.replace("-", "_"))
|
||||
instance = cls(plugin_name.replace('-', '_'))
|
||||
except component.ComponentAlreadyRegistered as ex:
|
||||
log.error(ex)
|
||||
return defer.succeed(False)
|
||||
except Exception as ex:
|
||||
log.error("Unable to instantiate plugin %r from %r!", name, egg.location)
|
||||
log.error('Unable to instantiate plugin %r from %r!', name, egg.location)
|
||||
log.exception(ex)
|
||||
continue
|
||||
try:
|
||||
@ -156,25 +156,25 @@ class PluginManagerBase(object):
|
||||
log.exception(ex)
|
||||
return_d = defer.fail(False)
|
||||
|
||||
if not instance.__module__.startswith("deluge.plugins."):
|
||||
if not instance.__module__.startswith('deluge.plugins.'):
|
||||
import warnings
|
||||
warnings.warn_explicit(
|
||||
DEPRECATION_WARNING % name,
|
||||
DeprecationWarning,
|
||||
instance.__module__, 0
|
||||
)
|
||||
if self._component_state == "Started":
|
||||
if self._component_state == 'Started':
|
||||
def on_enabled(result, instance):
|
||||
return component.start([instance.plugin._component_name])
|
||||
return_d.addCallback(on_enabled, instance)
|
||||
|
||||
def on_started(result, instance):
|
||||
plugin_name_space = plugin_name.replace("-", " ")
|
||||
plugin_name_space = plugin_name.replace('-', ' ')
|
||||
self.plugins[plugin_name_space] = instance
|
||||
if plugin_name_space not in self.config["enabled_plugins"]:
|
||||
log.debug("Adding %s to enabled_plugins list in config", plugin_name_space)
|
||||
self.config["enabled_plugins"].append(plugin_name_space)
|
||||
log.info("Plugin %s enabled..", plugin_name_space)
|
||||
if plugin_name_space not in self.config['enabled_plugins']:
|
||||
log.debug('Adding %s to enabled_plugins list in config', plugin_name_space)
|
||||
self.config['enabled_plugins'].append(plugin_name_space)
|
||||
log.info('Plugin %s enabled..', plugin_name_space)
|
||||
return True
|
||||
|
||||
def on_started_error(result, instance):
|
||||
@ -218,13 +218,13 @@ class PluginManagerBase(object):
|
||||
try:
|
||||
component.deregister(self.plugins[name].plugin)
|
||||
del self.plugins[name]
|
||||
self.config["enabled_plugins"].remove(name)
|
||||
self.config['enabled_plugins'].remove(name)
|
||||
except Exception as ex:
|
||||
log.error("Unable to disable plugin '%s'!", name)
|
||||
log.exception(ex)
|
||||
ret = False
|
||||
else:
|
||||
log.info("Plugin %s disabled..", name)
|
||||
log.info('Plugin %s disabled..', name)
|
||||
return ret
|
||||
|
||||
d.addBoth(on_disabled)
|
||||
@ -233,25 +233,25 @@ class PluginManagerBase(object):
|
||||
def get_plugin_info(self, name):
|
||||
"""Returns a dictionary of plugin info from the metadata"""
|
||||
info = {}.fromkeys(METADATA_KEYS)
|
||||
last_header = ""
|
||||
last_header = ''
|
||||
cont_lines = []
|
||||
# Missing plugin info
|
||||
if not self.pkg_env[name]:
|
||||
log.warn("Failed to retrive info for plugin '%s'", name)
|
||||
for k in info:
|
||||
info[k] = "not available"
|
||||
info[k] = 'not available'
|
||||
return info
|
||||
for line in self.pkg_env[name][0].get_metadata("PKG-INFO").splitlines():
|
||||
for line in self.pkg_env[name][0].get_metadata('PKG-INFO').splitlines():
|
||||
if not line:
|
||||
continue
|
||||
if line[0] in ' \t' and (len(line.split(":", 1)) == 1 or line.split(":", 1)[0] not in info.keys()):
|
||||
if line[0] in ' \t' and (len(line.split(':', 1)) == 1 or line.split(':', 1)[0] not in info.keys()):
|
||||
# This is a continuation
|
||||
cont_lines.append(line.strip())
|
||||
else:
|
||||
if cont_lines:
|
||||
info[last_header] = "\n".join(cont_lines).strip()
|
||||
info[last_header] = '\n'.join(cont_lines).strip()
|
||||
cont_lines = []
|
||||
if line.split(":", 1)[0] in info.keys():
|
||||
last_header = line.split(":", 1)[0]
|
||||
info[last_header] = line.split(":", 1)[1].strip()
|
||||
if line.split(':', 1)[0] in info.keys():
|
||||
last_header = line.split(':', 1)[0]
|
||||
info[last_header] = line.split(':', 1)[1].strip()
|
||||
return info
|
||||
|
||||
@ -18,4 +18,4 @@ import pkg_resources
|
||||
|
||||
|
||||
def get_resource(filename):
|
||||
return pkg_resources.resource_filename("deluge.plugins.autoadd", os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.autoadd', os.path.join('data', filename))
|
||||
|
||||
@ -33,35 +33,35 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"watchdirs": {},
|
||||
"next_id": 1
|
||||
'watchdirs': {},
|
||||
'next_id': 1
|
||||
}
|
||||
|
||||
|
||||
OPTIONS_AVAILABLE = { # option: builtin
|
||||
"enabled": False,
|
||||
"path": False,
|
||||
"append_extension": False,
|
||||
"copy_torrent": False,
|
||||
"delete_copy_torrent_toggle": False,
|
||||
"abspath": False,
|
||||
"download_location": True,
|
||||
"max_download_speed": True,
|
||||
"max_upload_speed": True,
|
||||
"max_connections": True,
|
||||
"max_upload_slots": True,
|
||||
"prioritize_first_last": True,
|
||||
"auto_managed": True,
|
||||
"stop_at_ratio": True,
|
||||
"stop_ratio": True,
|
||||
"remove_at_ratio": True,
|
||||
"move_completed": True,
|
||||
"move_completed_path": True,
|
||||
"label": False,
|
||||
"add_paused": True,
|
||||
"queue_to_top": False,
|
||||
"owner": True,
|
||||
"seed_mode": True
|
||||
'enabled': False,
|
||||
'path': False,
|
||||
'append_extension': False,
|
||||
'copy_torrent': False,
|
||||
'delete_copy_torrent_toggle': False,
|
||||
'abspath': False,
|
||||
'download_location': True,
|
||||
'max_download_speed': True,
|
||||
'max_upload_speed': True,
|
||||
'max_connections': True,
|
||||
'max_upload_slots': True,
|
||||
'prioritize_first_last': True,
|
||||
'auto_managed': True,
|
||||
'stop_at_ratio': True,
|
||||
'stop_ratio': True,
|
||||
'remove_at_ratio': True,
|
||||
'move_completed': True,
|
||||
'move_completed_path': True,
|
||||
'label': False,
|
||||
'add_paused': True,
|
||||
'queue_to_top': False,
|
||||
'owner': True,
|
||||
'seed_mode': True
|
||||
}
|
||||
|
||||
MAX_NUM_ATTEMPTS = 10
|
||||
@ -82,13 +82,13 @@ class Core(CorePluginBase):
|
||||
def enable(self):
|
||||
|
||||
# reduce typing, assigning some values to self...
|
||||
self.config = deluge.configmanager.ConfigManager("autoadd.conf", DEFAULT_PREFS)
|
||||
self.config = deluge.configmanager.ConfigManager('autoadd.conf', DEFAULT_PREFS)
|
||||
self.config.run_converter((0, 1), 2, self.__migrate_config_1_to_2)
|
||||
self.config.save()
|
||||
self.watchdirs = self.config["watchdirs"]
|
||||
self.watchdirs = self.config['watchdirs']
|
||||
|
||||
component.get("EventManager").register_event_handler(
|
||||
"PreTorrentRemovedEvent", self.__on_pre_torrent_removed
|
||||
component.get('EventManager').register_event_handler(
|
||||
'PreTorrentRemovedEvent', self.__on_pre_torrent_removed
|
||||
)
|
||||
|
||||
# Dict of Filename:Attempts
|
||||
@ -100,13 +100,13 @@ class Core(CorePluginBase):
|
||||
def enable_looping(self):
|
||||
# Enable all looping calls for enabled watchdirs here
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
if watchdir["enabled"]:
|
||||
if watchdir['enabled']:
|
||||
self.enable_watchdir(watchdir_id)
|
||||
|
||||
def disable(self):
|
||||
# disable all running looping calls
|
||||
component.get("EventManager").deregister_event_handler(
|
||||
"PreTorrentRemovedEvent", self.__on_pre_torrent_removed
|
||||
component.get('EventManager').deregister_event_handler(
|
||||
'PreTorrentRemovedEvent', self.__on_pre_torrent_removed
|
||||
)
|
||||
for loopingcall in self.update_timers.itervalues():
|
||||
loopingcall.stop()
|
||||
@ -121,45 +121,45 @@ class Core(CorePluginBase):
|
||||
watchdir_id = str(watchdir_id)
|
||||
options = self._make_unicode(options)
|
||||
check_input(
|
||||
watchdir_id in self.watchdirs, _("Watch folder does not exist.")
|
||||
watchdir_id in self.watchdirs, _('Watch folder does not exist.')
|
||||
)
|
||||
if "path" in options:
|
||||
options["abspath"] = os.path.abspath(options["path"])
|
||||
if 'path' in options:
|
||||
options['abspath'] = os.path.abspath(options['path'])
|
||||
check_input(
|
||||
os.path.isdir(options["abspath"]), _("Path does not exist.")
|
||||
os.path.isdir(options['abspath']), _('Path does not exist.')
|
||||
)
|
||||
for w_id, w in self.watchdirs.iteritems():
|
||||
if options["abspath"] == w["abspath"] and watchdir_id != w_id:
|
||||
raise Exception("Path is already being watched.")
|
||||
if options['abspath'] == w['abspath'] and watchdir_id != w_id:
|
||||
raise Exception('Path is already being watched.')
|
||||
for key in options:
|
||||
if key not in OPTIONS_AVAILABLE:
|
||||
if key not in [key2 + "_toggle" for key2 in OPTIONS_AVAILABLE.iterkeys()]:
|
||||
raise Exception("autoadd: Invalid options key:%s" % key)
|
||||
if key not in [key2 + '_toggle' for key2 in OPTIONS_AVAILABLE.iterkeys()]:
|
||||
raise Exception('autoadd: Invalid options key:%s' % key)
|
||||
# disable the watch loop if it was active
|
||||
if watchdir_id in self.update_timers:
|
||||
self.disable_watchdir(watchdir_id)
|
||||
|
||||
self.watchdirs[watchdir_id].update(options)
|
||||
# re-enable watch loop if appropriate
|
||||
if self.watchdirs[watchdir_id]["enabled"]:
|
||||
if self.watchdirs[watchdir_id]['enabled']:
|
||||
self.enable_watchdir(watchdir_id)
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
|
||||
component.get('EventManager').emit(AutoaddOptionsChangedEvent())
|
||||
|
||||
def load_torrent(self, filename, magnet):
|
||||
try:
|
||||
log.debug("Attempting to open %s for add.", filename)
|
||||
log.debug('Attempting to open %s for add.', filename)
|
||||
if magnet:
|
||||
with open(filename, "r") as _file:
|
||||
with open(filename, 'r') as _file:
|
||||
filedump = _file.read()
|
||||
else:
|
||||
with open(filename, "rb") as _file:
|
||||
with open(filename, 'rb') as _file:
|
||||
filedump = _file.read()
|
||||
|
||||
if not filedump:
|
||||
raise RuntimeError("Torrent is 0 bytes!")
|
||||
raise RuntimeError('Torrent is 0 bytes!')
|
||||
except IOError as ex:
|
||||
log.warning("Unable to open %s: %s", filename, ex)
|
||||
log.warning('Unable to open %s: %s', filename, ex)
|
||||
raise ex
|
||||
|
||||
# Get the info to see if any exceptions are raised
|
||||
@ -169,16 +169,16 @@ class Core(CorePluginBase):
|
||||
return base64.encodestring(filedump)
|
||||
|
||||
def split_magnets(self, filename):
|
||||
log.debug("Attempting to open %s for splitting magnets.", filename)
|
||||
log.debug('Attempting to open %s for splitting magnets.', filename)
|
||||
magnets = []
|
||||
try:
|
||||
with open(filename, "r") as _file:
|
||||
with open(filename, 'r') as _file:
|
||||
for line in _file:
|
||||
line = line.strip()
|
||||
if line:
|
||||
magnets.append(line)
|
||||
except IOError as ex:
|
||||
log.warning("Unable to open %s: %s", filename, ex)
|
||||
log.warning('Unable to open %s: %s', filename, ex)
|
||||
|
||||
if len(magnets) < 2:
|
||||
return []
|
||||
@ -186,79 +186,79 @@ class Core(CorePluginBase):
|
||||
n = 0
|
||||
path = filename.rsplit(os.sep, 1)[0]
|
||||
for magnet in magnets:
|
||||
for part in magnet.split("&"):
|
||||
if part.startswith("dn="):
|
||||
mname = os.sep.join([path, part[3:] + ".magnet"])
|
||||
for part in magnet.split('&'):
|
||||
if part.startswith('dn='):
|
||||
mname = os.sep.join([path, part[3:] + '.magnet'])
|
||||
break
|
||||
else:
|
||||
mname = ".".join([filename, str(n), "magnet"])
|
||||
mname = '.'.join([filename, str(n), 'magnet'])
|
||||
n += 1
|
||||
try:
|
||||
with open(mname, "w") as _mfile:
|
||||
with open(mname, 'w') as _mfile:
|
||||
_mfile.write(magnet)
|
||||
except IOError as ex:
|
||||
log.warning("Unable to open %s: %s", mname, ex)
|
||||
log.warning('Unable to open %s: %s', mname, ex)
|
||||
return magnets
|
||||
|
||||
def update_watchdir(self, watchdir_id):
|
||||
"""Check the watch folder for new torrents to add."""
|
||||
log.trace("Updating watchdir id: %s", watchdir_id)
|
||||
log.trace('Updating watchdir id: %s', watchdir_id)
|
||||
watchdir_id = str(watchdir_id)
|
||||
watchdir = self.watchdirs[watchdir_id]
|
||||
if not watchdir["enabled"]:
|
||||
if not watchdir['enabled']:
|
||||
# We shouldn't be updating because this watchdir is not enabled
|
||||
log.debug("Watchdir id %s is not enabled. Disabling it.",
|
||||
log.debug('Watchdir id %s is not enabled. Disabling it.',
|
||||
watchdir_id)
|
||||
self.disable_watchdir(watchdir_id)
|
||||
return
|
||||
|
||||
if not os.path.isdir(watchdir["abspath"]):
|
||||
log.warning("Invalid AutoAdd folder: %s", watchdir["abspath"])
|
||||
if not os.path.isdir(watchdir['abspath']):
|
||||
log.warning('Invalid AutoAdd folder: %s', watchdir['abspath'])
|
||||
self.disable_watchdir(watchdir_id)
|
||||
return
|
||||
|
||||
# Generate options dict for watchdir
|
||||
opts = {}
|
||||
if "stop_at_ratio_toggle" in watchdir:
|
||||
watchdir["stop_ratio_toggle"] = watchdir["stop_at_ratio_toggle"]
|
||||
if 'stop_at_ratio_toggle' in watchdir:
|
||||
watchdir['stop_ratio_toggle'] = watchdir['stop_at_ratio_toggle']
|
||||
# We default to True when reading _toggle values, so a config
|
||||
# without them is valid, and applies all its settings.
|
||||
for option, value in watchdir.iteritems():
|
||||
if OPTIONS_AVAILABLE.get(option):
|
||||
if watchdir.get(option + "_toggle", True) or option in ["owner", "seed_mode"]:
|
||||
if watchdir.get(option + '_toggle', True) or option in ['owner', 'seed_mode']:
|
||||
opts[option] = value
|
||||
|
||||
# Check for .magnet files containing multiple magnet links and
|
||||
# create a new .magnet file for each of them.
|
||||
for filename in os.listdir(watchdir["abspath"]):
|
||||
for filename in os.listdir(watchdir['abspath']):
|
||||
try:
|
||||
filepath = os.path.join(watchdir["abspath"], filename)
|
||||
filepath = os.path.join(watchdir['abspath'], filename)
|
||||
except UnicodeDecodeError as ex:
|
||||
log.error("Unable to auto add torrent due to improper filename encoding: %s", ex)
|
||||
log.error('Unable to auto add torrent due to improper filename encoding: %s', ex)
|
||||
continue
|
||||
if os.path.isdir(filepath):
|
||||
# Skip directories
|
||||
continue
|
||||
elif os.path.splitext(filename)[1] == ".magnet" and self.split_magnets(filepath):
|
||||
elif os.path.splitext(filename)[1] == '.magnet' and self.split_magnets(filepath):
|
||||
os.remove(filepath)
|
||||
|
||||
for filename in os.listdir(watchdir["abspath"]):
|
||||
for filename in os.listdir(watchdir['abspath']):
|
||||
try:
|
||||
filepath = os.path.join(watchdir["abspath"], filename)
|
||||
filepath = os.path.join(watchdir['abspath'], filename)
|
||||
except UnicodeDecodeError as ex:
|
||||
log.error("Unable to auto add torrent due to improper filename encoding: %s", ex)
|
||||
log.error('Unable to auto add torrent due to improper filename encoding: %s', ex)
|
||||
continue
|
||||
if os.path.isdir(filepath):
|
||||
# Skip directories
|
||||
continue
|
||||
else:
|
||||
ext = os.path.splitext(filename)[1].lower()
|
||||
if ext == ".torrent":
|
||||
if ext == '.torrent':
|
||||
magnet = False
|
||||
elif ext == ".magnet":
|
||||
elif ext == '.magnet':
|
||||
magnet = True
|
||||
else:
|
||||
log.debug("File checked for auto-loading is invalid: %s", filename)
|
||||
log.debug('File checked for auto-loading is invalid: %s', filename)
|
||||
continue
|
||||
try:
|
||||
filedump = self.load_torrent(filepath, magnet)
|
||||
@ -266,15 +266,15 @@ class Core(CorePluginBase):
|
||||
# If the torrent is invalid, we keep track of it so that we
|
||||
# can try again on the next pass. This is because some
|
||||
# torrents may not be fully saved during the pass.
|
||||
log.debug("Torrent is invalid: %s", ex)
|
||||
log.debug('Torrent is invalid: %s', ex)
|
||||
if filename in self.invalid_torrents:
|
||||
self.invalid_torrents[filename] += 1
|
||||
if self.invalid_torrents[filename] >= MAX_NUM_ATTEMPTS:
|
||||
log.warning(
|
||||
"Maximum attempts reached while trying to add the "
|
||||
"torrent file with the path %s", filepath
|
||||
'Maximum attempts reached while trying to add the '
|
||||
'torrent file with the path %s', filepath
|
||||
)
|
||||
os.rename(filepath, filepath + ".invalid")
|
||||
os.rename(filepath, filepath + '.invalid')
|
||||
del self.invalid_torrents[filename]
|
||||
else:
|
||||
self.invalid_torrents[filename] = 1
|
||||
@ -282,37 +282,37 @@ class Core(CorePluginBase):
|
||||
|
||||
# The torrent looks good, so lets add it to the session.
|
||||
if magnet:
|
||||
torrent_id = component.get("Core").add_torrent_magnet(filedump, opts)
|
||||
torrent_id = component.get('Core').add_torrent_magnet(filedump, opts)
|
||||
else:
|
||||
torrent_id = component.get("Core").add_torrent_file(filename, filedump, opts)
|
||||
torrent_id = component.get('Core').add_torrent_file(filename, filedump, opts)
|
||||
|
||||
# If the torrent added successfully, set the extra options.
|
||||
if torrent_id:
|
||||
if "Label" in component.get("CorePluginManager").get_enabled_plugins():
|
||||
if watchdir.get("label_toggle", True) and watchdir.get("label"):
|
||||
label = component.get("CorePlugin.Label")
|
||||
if not watchdir["label"] in label.get_labels():
|
||||
label.add(watchdir["label"])
|
||||
label.set_torrent(torrent_id, watchdir["label"])
|
||||
if watchdir.get("queue_to_top_toggle", True) and "queue_to_top" in watchdir:
|
||||
if watchdir["queue_to_top"]:
|
||||
component.get("TorrentManager").queue_top(torrent_id)
|
||||
if 'Label' in component.get('CorePluginManager').get_enabled_plugins():
|
||||
if watchdir.get('label_toggle', True) and watchdir.get('label'):
|
||||
label = component.get('CorePlugin.Label')
|
||||
if not watchdir['label'] in label.get_labels():
|
||||
label.add(watchdir['label'])
|
||||
label.set_torrent(torrent_id, watchdir['label'])
|
||||
if watchdir.get('queue_to_top_toggle', True) and 'queue_to_top' in watchdir:
|
||||
if watchdir['queue_to_top']:
|
||||
component.get('TorrentManager').queue_top(torrent_id)
|
||||
else:
|
||||
component.get("TorrentManager").queue_bottom(torrent_id)
|
||||
component.get('TorrentManager').queue_bottom(torrent_id)
|
||||
else:
|
||||
# torrent handle is invalid and so is the magnet link
|
||||
if magnet:
|
||||
log.debug("invalid magnet link")
|
||||
os.rename(filepath, filepath + ".invalid")
|
||||
log.debug('invalid magnet link')
|
||||
os.rename(filepath, filepath + '.invalid')
|
||||
continue
|
||||
|
||||
# Rename, copy or delete the torrent once added to deluge.
|
||||
if watchdir.get("append_extension_toggle"):
|
||||
if not watchdir.get("append_extension"):
|
||||
watchdir["append_extension"] = ".added"
|
||||
os.rename(filepath, filepath + watchdir["append_extension"])
|
||||
elif watchdir.get("copy_torrent_toggle"):
|
||||
copy_torrent_path = watchdir["copy_torrent"]
|
||||
if watchdir.get('append_extension_toggle'):
|
||||
if not watchdir.get('append_extension'):
|
||||
watchdir['append_extension'] = '.added'
|
||||
os.rename(filepath, filepath + watchdir['append_extension'])
|
||||
elif watchdir.get('copy_torrent_toggle'):
|
||||
copy_torrent_path = watchdir['copy_torrent']
|
||||
copy_torrent_file = os.path.join(copy_torrent_path, filename)
|
||||
log.debug("Moving added torrent file \"%s\" to \"%s\"",
|
||||
os.path.basename(filepath), copy_torrent_path)
|
||||
@ -325,7 +325,7 @@ class Core(CorePluginBase):
|
||||
"""Disables any watch folders with un-handled exceptions."""
|
||||
self.disable_watchdir(watchdir_id)
|
||||
log.error("Disabling '%s', error during update: %s",
|
||||
self.watchdirs[watchdir_id]["path"], failure)
|
||||
self.watchdirs[watchdir_id]['path'], failure)
|
||||
|
||||
@export
|
||||
def enable_watchdir(self, watchdir_id):
|
||||
@ -337,10 +337,10 @@ class Core(CorePluginBase):
|
||||
self.on_update_watchdir_error, w_id
|
||||
)
|
||||
# Update the config
|
||||
if not self.watchdirs[w_id]["enabled"]:
|
||||
self.watchdirs[w_id]["enabled"] = True
|
||||
if not self.watchdirs[w_id]['enabled']:
|
||||
self.watchdirs[w_id]['enabled'] = True
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
|
||||
component.get('EventManager').emit(AutoaddOptionsChangedEvent())
|
||||
|
||||
@export
|
||||
def disable_watchdir(self, watchdir_id):
|
||||
@ -351,10 +351,10 @@ class Core(CorePluginBase):
|
||||
self.update_timers[w_id].stop()
|
||||
del self.update_timers[w_id]
|
||||
# Update the config
|
||||
if self.watchdirs[w_id]["enabled"]:
|
||||
self.watchdirs[w_id]["enabled"] = False
|
||||
if self.watchdirs[w_id]['enabled']:
|
||||
self.watchdirs[w_id]['enabled'] = False
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
|
||||
component.get('EventManager').emit(AutoaddOptionsChangedEvent())
|
||||
|
||||
@export
|
||||
def set_config(self, config):
|
||||
@ -363,7 +363,7 @@ class Core(CorePluginBase):
|
||||
for key in config:
|
||||
self.config[key] = config[key]
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
|
||||
component.get('EventManager').emit(AutoaddOptionsChangedEvent())
|
||||
|
||||
@export
|
||||
def get_config(self):
|
||||
@ -372,28 +372,28 @@ class Core(CorePluginBase):
|
||||
|
||||
@export
|
||||
def get_watchdirs(self):
|
||||
rpcserver = component.get("RPCServer")
|
||||
rpcserver = component.get('RPCServer')
|
||||
session_user = rpcserver.get_session_user()
|
||||
session_auth_level = rpcserver.get_session_auth_level()
|
||||
if session_auth_level == AUTH_LEVEL_ADMIN:
|
||||
log.debug("Current logged in user %s is an ADMIN, send all "
|
||||
"watchdirs", session_user)
|
||||
log.debug('Current logged in user %s is an ADMIN, send all '
|
||||
'watchdirs', session_user)
|
||||
return self.watchdirs
|
||||
|
||||
watchdirs = {}
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
if watchdir.get("owner", "localclient") == session_user:
|
||||
if watchdir.get('owner', 'localclient') == session_user:
|
||||
watchdirs[watchdir_id] = watchdir
|
||||
|
||||
log.debug("Current logged in user %s is not an ADMIN, send only "
|
||||
"his watchdirs: %s", session_user, watchdirs.keys())
|
||||
log.debug('Current logged in user %s is not an ADMIN, send only '
|
||||
'his watchdirs: %s', session_user, watchdirs.keys())
|
||||
return watchdirs
|
||||
|
||||
def _make_unicode(self, options):
|
||||
opts = {}
|
||||
for key in options:
|
||||
if isinstance(options[key], str):
|
||||
options[key] = unicode(options[key], "utf8")
|
||||
options[key] = unicode(options[key], 'utf8')
|
||||
opts[key] = options[key]
|
||||
return opts
|
||||
|
||||
@ -403,58 +403,58 @@ class Core(CorePluginBase):
|
||||
if options is None:
|
||||
options = {}
|
||||
options = self._make_unicode(options)
|
||||
abswatchdir = os.path.abspath(options["path"])
|
||||
check_input(os.path.isdir(abswatchdir), _("Path does not exist."))
|
||||
abswatchdir = os.path.abspath(options['path'])
|
||||
check_input(os.path.isdir(abswatchdir), _('Path does not exist.'))
|
||||
check_input(
|
||||
os.access(abswatchdir, os.R_OK | os.W_OK),
|
||||
"You must have read and write access to watch folder."
|
||||
'You must have read and write access to watch folder.'
|
||||
)
|
||||
if abswatchdir in [wd["abspath"] for wd in self.watchdirs.itervalues()]:
|
||||
raise Exception("Path is already being watched.")
|
||||
options.setdefault("enabled", False)
|
||||
options["abspath"] = abswatchdir
|
||||
watchdir_id = self.config["next_id"]
|
||||
if abswatchdir in [wd['abspath'] for wd in self.watchdirs.itervalues()]:
|
||||
raise Exception('Path is already being watched.')
|
||||
options.setdefault('enabled', False)
|
||||
options['abspath'] = abswatchdir
|
||||
watchdir_id = self.config['next_id']
|
||||
self.watchdirs[str(watchdir_id)] = options
|
||||
if options.get("enabled"):
|
||||
if options.get('enabled'):
|
||||
self.enable_watchdir(watchdir_id)
|
||||
self.config["next_id"] = watchdir_id + 1
|
||||
self.config['next_id'] = watchdir_id + 1
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
|
||||
component.get('EventManager').emit(AutoaddOptionsChangedEvent())
|
||||
return watchdir_id
|
||||
|
||||
@export
|
||||
def remove(self, watchdir_id):
|
||||
"""Remove a watch folder."""
|
||||
watchdir_id = str(watchdir_id)
|
||||
check_input(watchdir_id in self.watchdirs, "Unknown Watchdir: %s" % self.watchdirs)
|
||||
if self.watchdirs[watchdir_id]["enabled"]:
|
||||
check_input(watchdir_id in self.watchdirs, 'Unknown Watchdir: %s' % self.watchdirs)
|
||||
if self.watchdirs[watchdir_id]['enabled']:
|
||||
self.disable_watchdir(watchdir_id)
|
||||
del self.watchdirs[watchdir_id]
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(AutoaddOptionsChangedEvent())
|
||||
component.get('EventManager').emit(AutoaddOptionsChangedEvent())
|
||||
|
||||
def __migrate_config_1_to_2(self, config):
|
||||
for watchdir_id in config["watchdirs"].iterkeys():
|
||||
config["watchdirs"][watchdir_id]["owner"] = "localclient"
|
||||
for watchdir_id in config['watchdirs'].iterkeys():
|
||||
config['watchdirs'][watchdir_id]['owner'] = 'localclient'
|
||||
return config
|
||||
|
||||
def __on_pre_torrent_removed(self, torrent_id):
|
||||
try:
|
||||
torrent = component.get("TorrentManager")[torrent_id]
|
||||
torrent = component.get('TorrentManager')[torrent_id]
|
||||
except KeyError:
|
||||
log.warning("Unable to remove torrent file for torrent id %s. It"
|
||||
"was already deleted from the TorrentManager",
|
||||
log.warning('Unable to remove torrent file for torrent id %s. It'
|
||||
'was already deleted from the TorrentManager',
|
||||
torrent_id)
|
||||
return
|
||||
torrent_fname = torrent.filename
|
||||
for watchdir in self.watchdirs.itervalues():
|
||||
if not watchdir.get("copy_torrent_toggle", False):
|
||||
if not watchdir.get('copy_torrent_toggle', False):
|
||||
# This watchlist does copy torrents
|
||||
continue
|
||||
elif not watchdir.get("delete_copy_torrent_toggle", False):
|
||||
elif not watchdir.get('delete_copy_torrent_toggle', False):
|
||||
# This watchlist is not set to delete finished torrents
|
||||
continue
|
||||
copy_torrent_path = watchdir["copy_torrent"]
|
||||
copy_torrent_path = watchdir['copy_torrent']
|
||||
torrent_fname_path = os.path.join(copy_torrent_path, torrent_fname)
|
||||
if os.path.isfile(torrent_fname_path):
|
||||
try:
|
||||
|
||||
@ -34,10 +34,10 @@ class IncompatibleOption(Exception):
|
||||
|
||||
|
||||
class OptionsDialog(object):
|
||||
spin_ids = ["max_download_speed", "max_upload_speed", "stop_ratio"]
|
||||
spin_int_ids = ["max_upload_slots", "max_connections"]
|
||||
chk_ids = ["stop_at_ratio", "remove_at_ratio", "move_completed",
|
||||
"add_paused", "auto_managed", "queue_to_top"]
|
||||
spin_ids = ['max_download_speed', 'max_upload_speed', 'stop_ratio']
|
||||
spin_int_ids = ['max_upload_slots', 'max_connections']
|
||||
chk_ids = ['stop_at_ratio', 'remove_at_ratio', 'move_completed',
|
||||
'add_paused', 'auto_managed', 'queue_to_top']
|
||||
|
||||
def __init__(self):
|
||||
self.accounts = gtk.ListStore(str)
|
||||
@ -47,16 +47,16 @@ class OptionsDialog(object):
|
||||
def show(self, options=None, watchdir_id=None):
|
||||
if options is None:
|
||||
options = {}
|
||||
self.glade = gtk.glade.XML(get_resource("autoadd_options.glade"))
|
||||
self.glade = gtk.glade.XML(get_resource('autoadd_options.glade'))
|
||||
self.glade.signal_autoconnect({
|
||||
"on_opts_add": self.on_add,
|
||||
"on_opts_apply": self.on_apply,
|
||||
"on_opts_cancel": self.on_cancel,
|
||||
"on_options_dialog_close": self.on_cancel,
|
||||
"on_toggle_toggled": self.on_toggle_toggled
|
||||
'on_opts_add': self.on_add,
|
||||
'on_opts_apply': self.on_apply,
|
||||
'on_opts_cancel': self.on_cancel,
|
||||
'on_options_dialog_close': self.on_cancel,
|
||||
'on_toggle_toggled': self.on_toggle_toggled
|
||||
})
|
||||
self.dialog = self.glade.get_widget("options_dialog")
|
||||
self.dialog.set_transient_for(component.get("Preferences").pref_dialog)
|
||||
self.dialog = self.glade.get_widget('options_dialog')
|
||||
self.dialog.set_transient_for(component.get('Preferences').pref_dialog)
|
||||
|
||||
if watchdir_id:
|
||||
# We have an existing watchdir_id, we are editing
|
||||
@ -108,10 +108,10 @@ class OptionsDialog(object):
|
||||
|
||||
for spin_id in self.spin_ids + self.spin_int_ids:
|
||||
self.glade.get_widget(spin_id).set_value(options.get(spin_id, 0))
|
||||
self.glade.get_widget(spin_id + "_toggle").set_active(options.get(spin_id + "_toggle", False))
|
||||
self.glade.get_widget(spin_id + '_toggle').set_active(options.get(spin_id + '_toggle', False))
|
||||
for chk_id in self.chk_ids:
|
||||
self.glade.get_widget(chk_id).set_active(bool(options.get(chk_id, True)))
|
||||
self.glade.get_widget(chk_id + "_toggle").set_active(options.get(chk_id + "_toggle", False))
|
||||
self.glade.get_widget(chk_id + '_toggle').set_active(options.get(chk_id + '_toggle', False))
|
||||
if not options.get('add_paused', True):
|
||||
self.glade.get_widget('isnt_add_paused').set_active(True)
|
||||
if not options.get('queue_to_top', True):
|
||||
@ -121,59 +121,59 @@ class OptionsDialog(object):
|
||||
for field in ['move_completed_path', 'path', 'download_location',
|
||||
'copy_torrent']:
|
||||
if client.is_localhost():
|
||||
self.glade.get_widget(field + "_chooser").set_current_folder(
|
||||
options.get(field, os.path.expanduser("~"))
|
||||
self.glade.get_widget(field + '_chooser').set_current_folder(
|
||||
options.get(field, os.path.expanduser('~'))
|
||||
)
|
||||
self.glade.get_widget(field + "_chooser").show()
|
||||
self.glade.get_widget(field + "_entry").hide()
|
||||
self.glade.get_widget(field + '_chooser').show()
|
||||
self.glade.get_widget(field + '_entry').hide()
|
||||
else:
|
||||
self.glade.get_widget(field + "_entry").set_text(
|
||||
options.get(field, "")
|
||||
self.glade.get_widget(field + '_entry').set_text(
|
||||
options.get(field, '')
|
||||
)
|
||||
self.glade.get_widget(field + "_entry").show()
|
||||
self.glade.get_widget(field + "_chooser").hide()
|
||||
self.glade.get_widget(field + '_entry').show()
|
||||
self.glade.get_widget(field + '_chooser').hide()
|
||||
self.set_sensitive()
|
||||
|
||||
def on_core_config(config):
|
||||
if client.is_localhost():
|
||||
self.glade.get_widget('download_location_chooser').set_current_folder(
|
||||
options.get('download_location', config["download_location"])
|
||||
options.get('download_location', config['download_location'])
|
||||
)
|
||||
if options.get('move_completed_toggle', config["move_completed"]):
|
||||
if options.get('move_completed_toggle', config['move_completed']):
|
||||
self.glade.get_widget('move_completed_toggle').set_active(True)
|
||||
self.glade.get_widget('move_completed_path_chooser').set_current_folder(
|
||||
options.get('move_completed_path', config["move_completed_path"])
|
||||
options.get('move_completed_path', config['move_completed_path'])
|
||||
)
|
||||
if options.get('copy_torrent_toggle', config["copy_torrent_file"]):
|
||||
if options.get('copy_torrent_toggle', config['copy_torrent_file']):
|
||||
self.glade.get_widget('copy_torrent_toggle').set_active(True)
|
||||
self.glade.get_widget('copy_torrent_chooser').set_current_folder(
|
||||
options.get('copy_torrent', config["torrentfiles_location"])
|
||||
options.get('copy_torrent', config['torrentfiles_location'])
|
||||
)
|
||||
else:
|
||||
self.glade.get_widget('download_location_entry').set_text(
|
||||
options.get('download_location', config["download_location"])
|
||||
options.get('download_location', config['download_location'])
|
||||
)
|
||||
if options.get('move_completed_toggle', config["move_completed"]):
|
||||
if options.get('move_completed_toggle', config['move_completed']):
|
||||
self.glade.get_widget('move_completed_toggle').set_active(
|
||||
options.get('move_completed_toggle', False)
|
||||
)
|
||||
self.glade.get_widget('move_completed_path_entry').set_text(
|
||||
options.get('move_completed_path', config["move_completed_path"])
|
||||
options.get('move_completed_path', config['move_completed_path'])
|
||||
)
|
||||
if options.get('copy_torrent_toggle', config["copy_torrent_file"]):
|
||||
if options.get('copy_torrent_toggle', config['copy_torrent_file']):
|
||||
self.glade.get_widget('copy_torrent_toggle').set_active(True)
|
||||
self.glade.get_widget('copy_torrent_entry').set_text(
|
||||
options.get('copy_torrent', config["torrentfiles_location"])
|
||||
options.get('copy_torrent', config['torrentfiles_location'])
|
||||
)
|
||||
|
||||
if options.get('delete_copy_torrent_toggle', config["del_copy_torrent_file"]):
|
||||
if options.get('delete_copy_torrent_toggle', config['del_copy_torrent_file']):
|
||||
self.glade.get_widget('delete_copy_torrent_toggle').set_active(True)
|
||||
|
||||
if not options:
|
||||
client.core.get_config().addCallback(on_core_config)
|
||||
|
||||
def on_accounts(accounts, owner):
|
||||
log.debug("Got Accounts")
|
||||
log.debug('Got Accounts')
|
||||
selected_iter = None
|
||||
for account in accounts:
|
||||
acc_iter = self.accounts.append()
|
||||
@ -185,14 +185,14 @@ class OptionsDialog(object):
|
||||
self.glade.get_widget('OwnerCombobox').set_active_iter(selected_iter)
|
||||
|
||||
def on_accounts_failure(failure):
|
||||
log.debug("Failed to get accounts!!! %s", failure)
|
||||
log.debug('Failed to get accounts!!! %s', failure)
|
||||
acc_iter = self.accounts.append()
|
||||
self.accounts.set_value(acc_iter, 0, client.get_auth_user())
|
||||
self.glade.get_widget('OwnerCombobox').set_active(0)
|
||||
self.glade.get_widget('OwnerCombobox').set_sensitive(False)
|
||||
|
||||
def on_labels(labels):
|
||||
log.debug("Got Labels: %s", labels)
|
||||
log.debug('Got Labels: %s', labels)
|
||||
for label in labels:
|
||||
self.labels.set_value(self.labels.append(), 0, label)
|
||||
label_widget = self.glade.get_widget('label')
|
||||
@ -228,10 +228,10 @@ class OptionsDialog(object):
|
||||
'max_upload_slots', 'add_paused', 'auto_managed',
|
||||
'stop_at_ratio', 'queue_to_top', 'copy_torrent']
|
||||
for maintoggle in maintoggles:
|
||||
self.on_toggle_toggled(self.glade.get_widget(maintoggle + "_toggle"))
|
||||
self.on_toggle_toggled(self.glade.get_widget(maintoggle + '_toggle'))
|
||||
|
||||
def on_toggle_toggled(self, tb):
|
||||
toggle = str(tb.name).replace("_toggle", "")
|
||||
toggle = str(tb.name).replace('_toggle', '')
|
||||
isactive = tb.get_active()
|
||||
if toggle == 'download_location':
|
||||
self.glade.get_widget('download_location_chooser').set_sensitive(isactive)
|
||||
@ -279,10 +279,10 @@ class OptionsDialog(object):
|
||||
str(self.watchdir_id), options
|
||||
).addCallbacks(self.on_added, self.on_error_show)
|
||||
except IncompatibleOption as ex:
|
||||
dialogs.ErrorDialog(_("Incompatible Option"), str(ex), self.dialog).run()
|
||||
dialogs.ErrorDialog(_('Incompatible Option'), str(ex), self.dialog).run()
|
||||
|
||||
def on_error_show(self, result):
|
||||
d = dialogs.ErrorDialog(_("Error"), result.value.exception_msg, self.dialog)
|
||||
d = dialogs.ErrorDialog(_('Error'), result.value.exception_msg, self.dialog)
|
||||
result.cleanFailure()
|
||||
d.run()
|
||||
|
||||
@ -294,7 +294,7 @@ class OptionsDialog(object):
|
||||
options = self.generate_opts()
|
||||
client.autoadd.add(options).addCallbacks(self.on_added, self.on_error_show)
|
||||
except IncompatibleOption as ex:
|
||||
dialogs.ErrorDialog(_("Incompatible Option"), str(ex), self.dialog).run()
|
||||
dialogs.ErrorDialog(_('Incompatible Option'), str(ex), self.dialog).run()
|
||||
|
||||
def on_cancel(self, event=None):
|
||||
self.dialog.destroy()
|
||||
@ -332,13 +332,13 @@ class OptionsDialog(object):
|
||||
|
||||
for spin_id in self.spin_ids:
|
||||
options[spin_id] = self.glade.get_widget(spin_id).get_value()
|
||||
options[spin_id + "_toggle"] = self.glade.get_widget(spin_id + "_toggle").get_active()
|
||||
options[spin_id + '_toggle'] = self.glade.get_widget(spin_id + '_toggle').get_active()
|
||||
for spin_int_id in self.spin_int_ids:
|
||||
options[spin_int_id] = self.glade.get_widget(spin_int_id).get_value_as_int()
|
||||
options[spin_int_id + "_toggle"] = self.glade.get_widget(spin_int_id + "_toggle").get_active()
|
||||
options[spin_int_id + '_toggle'] = self.glade.get_widget(spin_int_id + '_toggle').get_active()
|
||||
for chk_id in self.chk_ids:
|
||||
options[chk_id] = self.glade.get_widget(chk_id).get_active()
|
||||
options[chk_id + "_toggle"] = self.glade.get_widget(chk_id + "_toggle").get_active()
|
||||
options[chk_id + '_toggle'] = self.glade.get_widget(chk_id + '_toggle').get_active()
|
||||
|
||||
if options['copy_torrent_toggle'] and options['path'] == options['copy_torrent']:
|
||||
raise IncompatibleOption(_("\"Watch Folder\" directory and \"Copy of .torrent"
|
||||
@ -349,27 +349,27 @@ class OptionsDialog(object):
|
||||
class GtkUI(GtkPluginBase):
|
||||
def enable(self):
|
||||
|
||||
self.glade = gtk.glade.XML(get_resource("config.glade"))
|
||||
self.glade = gtk.glade.XML(get_resource('config.glade'))
|
||||
self.glade.signal_autoconnect({
|
||||
"on_add_button_clicked": self.on_add_button_clicked,
|
||||
"on_edit_button_clicked": self.on_edit_button_clicked,
|
||||
"on_remove_button_clicked": self.on_remove_button_clicked
|
||||
'on_add_button_clicked': self.on_add_button_clicked,
|
||||
'on_edit_button_clicked': self.on_edit_button_clicked,
|
||||
'on_remove_button_clicked': self.on_remove_button_clicked
|
||||
})
|
||||
self.opts_dialog = OptionsDialog()
|
||||
|
||||
component.get("PluginManager").register_hook(
|
||||
"on_apply_prefs", self.on_apply_prefs
|
||||
component.get('PluginManager').register_hook(
|
||||
'on_apply_prefs', self.on_apply_prefs
|
||||
)
|
||||
component.get("PluginManager").register_hook(
|
||||
"on_show_prefs", self.on_show_prefs
|
||||
component.get('PluginManager').register_hook(
|
||||
'on_show_prefs', self.on_show_prefs
|
||||
)
|
||||
client.register_event_handler(
|
||||
"AutoaddOptionsChangedEvent", self.on_options_changed_event
|
||||
'AutoaddOptionsChangedEvent', self.on_options_changed_event
|
||||
)
|
||||
|
||||
self.watchdirs = {}
|
||||
|
||||
vbox = self.glade.get_widget("watchdirs_vbox")
|
||||
vbox = self.glade.get_widget('watchdirs_vbox')
|
||||
sw = gtk.ScrolledWindow()
|
||||
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
|
||||
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
@ -379,24 +379,24 @@ class GtkUI(GtkPluginBase):
|
||||
self.store = self.create_model()
|
||||
|
||||
self.treeView = gtk.TreeView(self.store)
|
||||
self.treeView.connect("cursor-changed", self.on_listitem_activated)
|
||||
self.treeView.connect("row-activated", self.on_edit_button_clicked)
|
||||
self.treeView.connect('cursor-changed', self.on_listitem_activated)
|
||||
self.treeView.connect('row-activated', self.on_edit_button_clicked)
|
||||
self.treeView.set_rules_hint(True)
|
||||
|
||||
self.create_columns(self.treeView)
|
||||
sw.add(self.treeView)
|
||||
sw.show_all()
|
||||
component.get("Preferences").add_page(
|
||||
_("AutoAdd"), self.glade.get_widget("prefs_box")
|
||||
component.get('Preferences').add_page(
|
||||
_('AutoAdd'), self.glade.get_widget('prefs_box')
|
||||
)
|
||||
|
||||
def disable(self):
|
||||
component.get("Preferences").remove_page(_("AutoAdd"))
|
||||
component.get("PluginManager").deregister_hook(
|
||||
"on_apply_prefs", self.on_apply_prefs
|
||||
component.get('Preferences').remove_page(_('AutoAdd'))
|
||||
component.get('PluginManager').deregister_hook(
|
||||
'on_apply_prefs', self.on_apply_prefs
|
||||
)
|
||||
component.get("PluginManager").deregister_hook(
|
||||
"on_show_prefs", self.on_show_prefs
|
||||
component.get('PluginManager').deregister_hook(
|
||||
'on_show_prefs', self.on_show_prefs
|
||||
)
|
||||
|
||||
def create_model(self):
|
||||
@ -411,7 +411,7 @@ class GtkUI(GtkPluginBase):
|
||||
def create_columns(self, treeview):
|
||||
renderer_toggle = gtk.CellRendererToggle()
|
||||
column = gtk.TreeViewColumn(
|
||||
_("Active"), renderer_toggle, activatable=1, active=1
|
||||
_('Active'), renderer_toggle, activatable=1, active=1
|
||||
)
|
||||
column.set_sort_column_id(1)
|
||||
treeview.append_column(column)
|
||||
@ -420,7 +420,7 @@ class GtkUI(GtkPluginBase):
|
||||
treeview.set_tooltip_cell(tt, None, None, renderer_toggle)
|
||||
|
||||
renderertext = gtk.CellRendererText()
|
||||
column = gtk.TreeViewColumn(_("Owner"), renderertext, text=2)
|
||||
column = gtk.TreeViewColumn(_('Owner'), renderertext, text=2)
|
||||
column.set_sort_column_id(2)
|
||||
treeview.append_column(column)
|
||||
tt2 = gtk.Tooltip()
|
||||
@ -428,7 +428,7 @@ class GtkUI(GtkPluginBase):
|
||||
treeview.set_has_tooltip(True)
|
||||
|
||||
renderertext = gtk.CellRendererText()
|
||||
column = gtk.TreeViewColumn(_("Path"), renderertext, text=3)
|
||||
column = gtk.TreeViewColumn(_('Path'), renderertext, text=3)
|
||||
column.set_sort_column_id(3)
|
||||
treeview.append_column(column)
|
||||
tt2 = gtk.Tooltip()
|
||||
@ -455,7 +455,7 @@ class GtkUI(GtkPluginBase):
|
||||
tree, tree_id = self.treeView.get_selection().get_selected()
|
||||
watchdir_id = str(self.store.get_value(tree_id, 0))
|
||||
if watchdir_id:
|
||||
if col and col.get_title() == _("Active"):
|
||||
if col and col.get_title() == _('Active'):
|
||||
if self.watchdirs[watchdir_id]['enabled']:
|
||||
client.autoadd.disable_watchdir(watchdir_id)
|
||||
else:
|
||||
@ -473,7 +473,7 @@ class GtkUI(GtkPluginBase):
|
||||
self.glade.get_widget('remove_button').set_sensitive(False)
|
||||
|
||||
def on_apply_prefs(self):
|
||||
log.debug("applying prefs for AutoAdd")
|
||||
log.debug('applying prefs for AutoAdd')
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
client.autoadd.set_options(watchdir_id, watchdir)
|
||||
|
||||
@ -485,7 +485,7 @@ class GtkUI(GtkPluginBase):
|
||||
|
||||
def cb_get_config(self, watchdirs):
|
||||
"""callback for on show_prefs"""
|
||||
log.trace("Got whatchdirs from core: %s", watchdirs)
|
||||
log.trace('Got whatchdirs from core: %s', watchdirs)
|
||||
self.watchdirs = watchdirs or {}
|
||||
self.store.clear()
|
||||
for watchdir_id, watchdir in self.watchdirs.iteritems():
|
||||
|
||||
@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("autoadd.js")]
|
||||
scripts = [get_resource('autoadd.js')]
|
||||
|
||||
def enable(self):
|
||||
pass
|
||||
|
||||
@ -15,15 +15,15 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "AutoAdd"
|
||||
__author__ = "Chase Sterling, Pedro Algarvio"
|
||||
__author_email__ = "chase.sterling@gmail.com, pedro@algarvio.me"
|
||||
__version__ = "1.05"
|
||||
__url__ = "http://dev.deluge-torrent.org/wiki/Plugins/AutoAdd"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Monitors folders for .torrent files."
|
||||
__plugin_name__ = 'AutoAdd'
|
||||
__author__ = 'Chase Sterling, Pedro Algarvio'
|
||||
__author_email__ = 'chase.sterling@gmail.com, pedro@algarvio.me'
|
||||
__version__ = '1.05'
|
||||
__url__ = 'http://dev.deluge-torrent.org/wiki/Plugins/AutoAdd'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Monitors folders for .torrent files.'
|
||||
__long_description__ = """"""
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -35,7 +35,7 @@ setup(
|
||||
license=__license__,
|
||||
long_description=__long_description__ if __long_description__ else __description__,
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -15,8 +15,8 @@ import pkg_resources
|
||||
|
||||
|
||||
def get_resource(filename):
|
||||
return pkg_resources.resource_filename("deluge.plugins.blocklist",
|
||||
os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.blocklist',
|
||||
os.path.join('data', filename))
|
||||
|
||||
|
||||
def raises_errors_as(error):
|
||||
@ -56,7 +56,7 @@ def remove_zeros(ip):
|
||||
000.000.000.003 -> 0.0.0.3
|
||||
|
||||
"""
|
||||
return ".".join([part.lstrip("0").zfill(1) for part in ip.split(".")])
|
||||
return '.'.join([part.lstrip('0').zfill(1) for part in ip.split('.')])
|
||||
|
||||
|
||||
class BadIP(Exception):
|
||||
|
||||
@ -39,16 +39,16 @@ from .readers import ReaderParseError
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"url": "",
|
||||
"load_on_start": False,
|
||||
"check_after_days": 4,
|
||||
"list_compression": "",
|
||||
"list_type": "",
|
||||
"last_update": 0.0,
|
||||
"list_size": 0,
|
||||
"timeout": 180,
|
||||
"try_times": 3,
|
||||
"whitelisted": [],
|
||||
'url': '',
|
||||
'load_on_start': False,
|
||||
'check_after_days': 4,
|
||||
'list_compression': '',
|
||||
'list_type': '',
|
||||
'last_update': 0.0,
|
||||
'list_size': 0,
|
||||
'timeout': 180,
|
||||
'try_times': 3,
|
||||
'whitelisted': [],
|
||||
}
|
||||
|
||||
# Constants
|
||||
@ -70,26 +70,26 @@ class Core(CorePluginBase):
|
||||
self.num_blocked = 0
|
||||
self.file_progress = 0.0
|
||||
|
||||
self.core = component.get("Core")
|
||||
self.config = deluge.configmanager.ConfigManager("blocklist.conf", DEFAULT_PREFS)
|
||||
if "whitelisted" not in self.config:
|
||||
self.config["whitelisted"] = []
|
||||
self.core = component.get('Core')
|
||||
self.config = deluge.configmanager.ConfigManager('blocklist.conf', DEFAULT_PREFS)
|
||||
if 'whitelisted' not in self.config:
|
||||
self.config['whitelisted'] = []
|
||||
|
||||
self.reader = create_reader(self.config["list_type"], self.config["list_compression"])
|
||||
self.reader = create_reader(self.config['list_type'], self.config['list_compression'])
|
||||
|
||||
if not isinstance(self.config["last_update"], float):
|
||||
self.config.config["last_update"] = 0.0
|
||||
if not isinstance(self.config['last_update'], float):
|
||||
self.config.config['last_update'] = 0.0
|
||||
|
||||
update_now = False
|
||||
if self.config["load_on_start"]:
|
||||
if self.config['load_on_start']:
|
||||
self.pause_session()
|
||||
if self.config["last_update"]:
|
||||
last_update = datetime.fromtimestamp(self.config["last_update"])
|
||||
check_period = timedelta(days=self.config["check_after_days"])
|
||||
if not self.config["last_update"] or last_update + check_period < datetime.now():
|
||||
if self.config['last_update']:
|
||||
last_update = datetime.fromtimestamp(self.config['last_update'])
|
||||
check_period = timedelta(days=self.config['check_after_days'])
|
||||
if not self.config['last_update'] or last_update + check_period < datetime.now():
|
||||
update_now = True
|
||||
else:
|
||||
d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache"))
|
||||
d = self.import_list(deluge.configmanager.get_config_dir('blocklist.cache'))
|
||||
d.addCallbacks(self.on_import_complete, self.on_import_error)
|
||||
if self.need_to_resume_session:
|
||||
d.addBoth(self.resume_session)
|
||||
@ -97,16 +97,16 @@ class Core(CorePluginBase):
|
||||
# This function is called every 'check_after_days' days, to download
|
||||
# and import a new list if needed.
|
||||
self.update_timer = LoopingCall(self.check_import)
|
||||
if self.config["check_after_days"] > 0:
|
||||
if self.config['check_after_days'] > 0:
|
||||
self.update_timer.start(
|
||||
self.config["check_after_days"] * 24 * 60 * 60, update_now
|
||||
self.config['check_after_days'] * 24 * 60 * 60, update_now
|
||||
)
|
||||
|
||||
def disable(self):
|
||||
self.config.save()
|
||||
log.debug("Reset IP filter")
|
||||
log.debug('Reset IP filter')
|
||||
self.core.session.get_ip_filter().add_rule(
|
||||
"0.0.0.0", "255.255.255.255", ALLOW_RANGE
|
||||
'0.0.0.0', '255.255.255.255', ALLOW_RANGE
|
||||
)
|
||||
log.debug('Blocklist: Plugin disabled')
|
||||
|
||||
@ -125,7 +125,7 @@ class Core(CorePluginBase):
|
||||
Deferred: A Deferred which fires when the blocklist has been imported.
|
||||
|
||||
"""
|
||||
if not self.config["url"]:
|
||||
if not self.config['url']:
|
||||
return
|
||||
|
||||
# Reset variables
|
||||
@ -136,7 +136,7 @@ class Core(CorePluginBase):
|
||||
self.up_to_date = False
|
||||
if force:
|
||||
self.reader = None
|
||||
self.is_url = is_url(self.config["url"])
|
||||
self.is_url = is_url(self.config['url'])
|
||||
|
||||
# Start callback chain
|
||||
if self.is_url:
|
||||
@ -144,7 +144,7 @@ class Core(CorePluginBase):
|
||||
d.addCallbacks(self.on_download_complete, self.on_download_error)
|
||||
d.addCallback(self.import_list)
|
||||
else:
|
||||
d = self.import_list(self.config["url"])
|
||||
d = self.import_list(self.config['url'])
|
||||
d.addCallbacks(self.on_import_complete, self.on_import_error)
|
||||
if self.need_to_resume_session:
|
||||
d.addBoth(self.resume_session)
|
||||
@ -176,7 +176,7 @@ class Core(CorePluginBase):
|
||||
update = set(config[key])
|
||||
diff = saved.symmetric_difference(update)
|
||||
if diff:
|
||||
log.debug("Whitelist changed. Updating...")
|
||||
log.debug('Whitelist changed. Updating...')
|
||||
added = update.intersection(diff)
|
||||
removed = saved.intersection(diff)
|
||||
if added:
|
||||
@ -187,10 +187,10 @@ class Core(CorePluginBase):
|
||||
ip.address, ip.address, ALLOW_RANGE
|
||||
)
|
||||
saved.add(ip.address)
|
||||
log.debug("Added %s to whitelisted", ip)
|
||||
log.debug('Added %s to whitelisted', ip)
|
||||
self.num_whited += 1
|
||||
except BadIP as ex:
|
||||
log.error("Bad IP: %s", ex)
|
||||
log.error('Bad IP: %s', ex)
|
||||
continue
|
||||
if removed:
|
||||
needs_blocklist_import = True
|
||||
@ -198,37 +198,37 @@ class Core(CorePluginBase):
|
||||
try:
|
||||
ip = IP.parse(ip)
|
||||
saved.remove(ip.address)
|
||||
log.debug("Removed %s from whitelisted", ip)
|
||||
log.debug('Removed %s from whitelisted', ip)
|
||||
except BadIP as ex:
|
||||
log.error("Bad IP: %s", ex)
|
||||
log.error('Bad IP: %s', ex)
|
||||
continue
|
||||
|
||||
self.config[key] = list(saved)
|
||||
continue
|
||||
elif key == "check_after_days":
|
||||
elif key == 'check_after_days':
|
||||
if self.config[key] != config[key]:
|
||||
self.config[key] = config[key]
|
||||
update_now = False
|
||||
if self.config["last_update"]:
|
||||
last_update = datetime.fromtimestamp(self.config["last_update"])
|
||||
check_period = timedelta(days=self.config["check_after_days"])
|
||||
if not self.config["last_update"] or last_update + check_period < datetime.now():
|
||||
if self.config['last_update']:
|
||||
last_update = datetime.fromtimestamp(self.config['last_update'])
|
||||
check_period = timedelta(days=self.config['check_after_days'])
|
||||
if not self.config['last_update'] or last_update + check_period < datetime.now():
|
||||
update_now = True
|
||||
if self.update_timer.running:
|
||||
self.update_timer.stop()
|
||||
if self.config["check_after_days"] > 0:
|
||||
if self.config['check_after_days'] > 0:
|
||||
self.update_timer.start(
|
||||
self.config["check_after_days"] * 24 * 60 * 60, update_now
|
||||
self.config['check_after_days'] * 24 * 60 * 60, update_now
|
||||
)
|
||||
continue
|
||||
self.config[key] = config[key]
|
||||
|
||||
if needs_blocklist_import:
|
||||
log.debug("IP addresses were removed from the whitelist. Since we "
|
||||
log.debug('IP addresses were removed from the whitelist. Since we '
|
||||
"don't know if they were blocked before. Re-import "
|
||||
"current blocklist and re-add whitelisted.")
|
||||
'current blocklist and re-add whitelisted.')
|
||||
self.has_imported = False
|
||||
d = self.import_list(deluge.configmanager.get_config_dir("blocklist.cache"))
|
||||
d = self.import_list(deluge.configmanager.get_config_dir('blocklist.cache'))
|
||||
d.addCallbacks(self.on_import_complete, self.on_import_error)
|
||||
|
||||
@export
|
||||
@ -241,23 +241,23 @@ class Core(CorePluginBase):
|
||||
"""
|
||||
status = {}
|
||||
if self.is_downloading:
|
||||
status["state"] = "Downloading"
|
||||
status['state'] = 'Downloading'
|
||||
elif self.is_importing:
|
||||
status["state"] = "Importing"
|
||||
status['state'] = 'Importing'
|
||||
else:
|
||||
status["state"] = "Idle"
|
||||
status['state'] = 'Idle'
|
||||
|
||||
status["up_to_date"] = self.up_to_date
|
||||
status["num_whited"] = self.num_whited
|
||||
status["num_blocked"] = self.num_blocked
|
||||
status["file_progress"] = self.file_progress
|
||||
status["file_url"] = self.config["url"]
|
||||
status["file_size"] = self.config["list_size"]
|
||||
status["file_date"] = self.config["last_update"]
|
||||
status["file_type"] = self.config["list_type"]
|
||||
status["whitelisted"] = self.config["whitelisted"]
|
||||
if self.config["list_compression"]:
|
||||
status["file_type"] += " (%s)" % self.config["list_compression"]
|
||||
status['up_to_date'] = self.up_to_date
|
||||
status['num_whited'] = self.num_whited
|
||||
status['num_blocked'] = self.num_blocked
|
||||
status['file_progress'] = self.file_progress
|
||||
status['file_url'] = self.config['url']
|
||||
status['file_size'] = self.config['list_size']
|
||||
status['file_date'] = self.config['last_update']
|
||||
status['file_type'] = self.config['list_type']
|
||||
status['whitelisted'] = self.config['whitelisted']
|
||||
if self.config['list_compression']:
|
||||
status['file_type'] += ' (%s)' % self.config['list_compression']
|
||||
return status
|
||||
|
||||
####
|
||||
@ -272,9 +272,9 @@ class Core(CorePluginBase):
|
||||
str: Path of blocklist.
|
||||
|
||||
"""
|
||||
log.debug("Updating blocklist info: %s", blocklist)
|
||||
self.config["last_update"] = time.time()
|
||||
self.config["list_size"] = os.path.getsize(blocklist)
|
||||
log.debug('Updating blocklist info: %s', blocklist)
|
||||
self.config['last_update'] = time.time()
|
||||
self.config['list_size'] = os.path.getsize(blocklist)
|
||||
self.filename = blocklist
|
||||
return blocklist
|
||||
|
||||
@ -299,20 +299,20 @@ class Core(CorePluginBase):
|
||||
self.file_progress = fp
|
||||
|
||||
import socket
|
||||
socket.setdefaulttimeout(self.config["timeout"])
|
||||
socket.setdefaulttimeout(self.config['timeout'])
|
||||
|
||||
if not url:
|
||||
url = self.config["url"]
|
||||
url = self.config['url']
|
||||
|
||||
headers = {}
|
||||
if self.config["last_update"] and not self.force_download:
|
||||
headers['If-Modified-Since'] = formatdate(self.config["last_update"], usegmt=True)
|
||||
if self.config['last_update'] and not self.force_download:
|
||||
headers['If-Modified-Since'] = formatdate(self.config['last_update'], usegmt=True)
|
||||
|
||||
log.debug("Attempting to download blocklist %s", url)
|
||||
log.debug("Sending headers: %s", headers)
|
||||
log.debug('Attempting to download blocklist %s', url)
|
||||
log.debug('Sending headers: %s', headers)
|
||||
self.is_downloading = True
|
||||
return download_file(
|
||||
url, deluge.configmanager.get_config_dir("blocklist.download"),
|
||||
url, deluge.configmanager.get_config_dir('blocklist.download'),
|
||||
on_retrieve_data, headers
|
||||
)
|
||||
|
||||
@ -326,7 +326,7 @@ class Core(CorePluginBase):
|
||||
Deferred: a Deferred which fires when clean up is done.
|
||||
|
||||
"""
|
||||
log.debug("Blocklist download complete: %s", blocklist)
|
||||
log.debug('Blocklist download complete: %s', blocklist)
|
||||
self.is_downloading = False
|
||||
return threads.deferToThread(self.update_info, blocklist)
|
||||
|
||||
@ -345,21 +345,21 @@ class Core(CorePluginBase):
|
||||
d = f
|
||||
if f.check(error.PageRedirect):
|
||||
# Handle redirect errors
|
||||
location = urljoin(self.config["url"], error_msg.split(" to ")[1])
|
||||
if "Moved Permanently" in error_msg:
|
||||
log.debug("Setting blocklist url to %s", location)
|
||||
self.config["url"] = location
|
||||
location = urljoin(self.config['url'], error_msg.split(' to ')[1])
|
||||
if 'Moved Permanently' in error_msg:
|
||||
log.debug('Setting blocklist url to %s', location)
|
||||
self.config['url'] = location
|
||||
d = self.download_list(location)
|
||||
d.addCallbacks(self.on_download_complete, self.on_download_error)
|
||||
else:
|
||||
if "Not Modified" in error_msg:
|
||||
log.debug("Blocklist is up-to-date!")
|
||||
if 'Not Modified' in error_msg:
|
||||
log.debug('Blocklist is up-to-date!')
|
||||
self.up_to_date = True
|
||||
blocklist = deluge.configmanager.get_config_dir("blocklist.cache")
|
||||
blocklist = deluge.configmanager.get_config_dir('blocklist.cache')
|
||||
d = threads.deferToThread(self.update_info, blocklist)
|
||||
else:
|
||||
log.warning("Blocklist download failed: %s", error_msg)
|
||||
if self.failed_attempts < self.config["try_times"]:
|
||||
log.warning('Blocklist download failed: %s', error_msg)
|
||||
if self.failed_attempts < self.config['try_times']:
|
||||
log.debug("Let's try again")
|
||||
self.failed_attempts += 1
|
||||
d = self.download_list()
|
||||
@ -376,7 +376,7 @@ class Core(CorePluginBase):
|
||||
Deferred: A Deferred that fires when the blocklist has been imported.
|
||||
|
||||
"""
|
||||
log.trace("on import_list")
|
||||
log.trace('on import_list')
|
||||
|
||||
def on_read_ip_range(start, end):
|
||||
"""Add ip range to blocklist"""
|
||||
@ -388,19 +388,19 @@ class Core(CorePluginBase):
|
||||
"""Add any whitelisted IP's and add the blocklist to session"""
|
||||
# White listing happens last because the last rules added have
|
||||
# priority
|
||||
log.info("Added %d ranges to ipfilter as blocked", self.num_blocked)
|
||||
for ip in self.config["whitelisted"]:
|
||||
log.info('Added %d ranges to ipfilter as blocked', self.num_blocked)
|
||||
for ip in self.config['whitelisted']:
|
||||
ip = IP.parse(ip)
|
||||
self.blocklist.add_rule(ip.address, ip.address, ALLOW_RANGE)
|
||||
self.num_whited += 1
|
||||
log.trace("Added %s to the ipfiler as white-listed", ip.address)
|
||||
log.info("Added %d ranges to ipfilter as white-listed", self.num_whited)
|
||||
log.trace('Added %s to the ipfiler as white-listed', ip.address)
|
||||
log.info('Added %d ranges to ipfilter as white-listed', self.num_whited)
|
||||
self.core.session.set_ip_filter(self.blocklist)
|
||||
return result
|
||||
|
||||
# TODO: double check logic
|
||||
if self.up_to_date and self.has_imported:
|
||||
log.debug("Latest blocklist is already imported")
|
||||
log.debug('Latest blocklist is already imported')
|
||||
return defer.succeed(blocklist)
|
||||
|
||||
self.is_importing = True
|
||||
@ -416,12 +416,12 @@ class Core(CorePluginBase):
|
||||
self.auto_detected = True
|
||||
|
||||
def on_reader_failure(failure):
|
||||
log.error("Failed to read!!!!!!")
|
||||
log.error('Failed to read!!!!!!')
|
||||
log.exception(failure)
|
||||
|
||||
log.debug("Importing using reader: %s", self.reader)
|
||||
log.debug("Reader type: %s compression: %s", self.config["list_type"], self.config["list_compression"])
|
||||
log.debug("Clearing current ip filtering")
|
||||
log.debug('Importing using reader: %s', self.reader)
|
||||
log.debug('Reader type: %s compression: %s', self.config['list_type'], self.config['list_compression'])
|
||||
log.debug('Clearing current ip filtering')
|
||||
# self.blocklist.add_rule("0.0.0.0", "255.255.255.255", ALLOW_RANGE)
|
||||
d = threads.deferToThread(self.reader(blocklist).read, on_read_ip_range)
|
||||
d.addCallback(on_finish_read).addErrback(on_reader_failure)
|
||||
@ -438,18 +438,18 @@ class Core(CorePluginBase):
|
||||
Deferred: A Deferred that fires when clean up is done.
|
||||
|
||||
"""
|
||||
log.trace("on_import_list_complete")
|
||||
log.trace('on_import_list_complete')
|
||||
d = blocklist
|
||||
self.is_importing = False
|
||||
self.has_imported = True
|
||||
log.debug("Blocklist import complete!")
|
||||
cache = deluge.configmanager.get_config_dir("blocklist.cache")
|
||||
log.debug('Blocklist import complete!')
|
||||
cache = deluge.configmanager.get_config_dir('blocklist.cache')
|
||||
if blocklist != cache:
|
||||
if self.is_url:
|
||||
log.debug("Moving %s to %s", blocklist, cache)
|
||||
log.debug('Moving %s to %s', blocklist, cache)
|
||||
d = threads.deferToThread(shutil.move, blocklist, cache)
|
||||
else:
|
||||
log.debug("Copying %s to %s", blocklist, cache)
|
||||
log.debug('Copying %s to %s', blocklist, cache)
|
||||
d = threads.deferToThread(shutil.copy, blocklist, cache)
|
||||
return d
|
||||
|
||||
@ -463,21 +463,21 @@ class Core(CorePluginBase):
|
||||
Deferred or Failure: A Deferred if recovery was possible else original Failure.
|
||||
|
||||
"""
|
||||
log.trace("on_import_error: %s", f)
|
||||
log.trace('on_import_error: %s', f)
|
||||
d = f
|
||||
self.is_importing = False
|
||||
try_again = False
|
||||
cache = deluge.configmanager.get_config_dir("blocklist.cache")
|
||||
cache = deluge.configmanager.get_config_dir('blocklist.cache')
|
||||
|
||||
if f.check(ReaderParseError) and not self.auto_detected:
|
||||
# Invalid / corrupt list, let's detect it
|
||||
log.warning("Invalid / corrupt blocklist")
|
||||
log.warning('Invalid / corrupt blocklist')
|
||||
self.reader = None
|
||||
blocklist = None
|
||||
try_again = True
|
||||
elif self.filename != cache and os.path.exists(cache):
|
||||
# If we have a backup and we haven't already used it
|
||||
log.warning("Error reading blocklist: %s", f.getErrorMessage())
|
||||
log.warning('Error reading blocklist: %s', f.getErrorMessage())
|
||||
blocklist = cache
|
||||
try_again = True
|
||||
|
||||
@ -497,14 +497,14 @@ class Core(CorePluginBase):
|
||||
UnknownFormatError: If the format cannot be detected.
|
||||
|
||||
"""
|
||||
self.config["list_compression"] = detect_compression(blocklist)
|
||||
self.config["list_type"] = detect_format(blocklist, self.config["list_compression"])
|
||||
log.debug("Auto-detected type: %s compression: %s", self.config["list_type"], self.config["list_compression"])
|
||||
if not self.config["list_type"]:
|
||||
self.config["list_compression"] = ""
|
||||
self.config['list_compression'] = detect_compression(blocklist)
|
||||
self.config['list_type'] = detect_format(blocklist, self.config['list_compression'])
|
||||
log.debug('Auto-detected type: %s compression: %s', self.config['list_type'], self.config['list_compression'])
|
||||
if not self.config['list_type']:
|
||||
self.config['list_compression'] = ''
|
||||
raise UnknownFormatError
|
||||
else:
|
||||
self.reader = create_reader(self.config["list_type"], self.config["list_compression"])
|
||||
self.reader = create_reader(self.config['list_type'], self.config['list_compression'])
|
||||
|
||||
def pause_session(self):
|
||||
self.need_to_resume_session = not self.core.session.is_paused()
|
||||
|
||||
@ -11,21 +11,21 @@ from .decompressers import BZipped2, GZipped, Zipped
|
||||
from .readers import EmuleReader, PeerGuardianReader, SafePeerReader
|
||||
|
||||
COMPRESSION_TYPES = {
|
||||
"PK": "Zip",
|
||||
"\x1f\x8b": "GZip",
|
||||
"BZ": "BZip2"
|
||||
'PK': 'Zip',
|
||||
'\x1f\x8b': 'GZip',
|
||||
'BZ': 'BZip2'
|
||||
}
|
||||
|
||||
DECOMPRESSERS = {
|
||||
"Zip": Zipped,
|
||||
"GZip": GZipped,
|
||||
"BZip2": BZipped2
|
||||
'Zip': Zipped,
|
||||
'GZip': GZipped,
|
||||
'BZip2': BZipped2
|
||||
}
|
||||
|
||||
READERS = {
|
||||
"Emule": EmuleReader,
|
||||
"SafePeer": SafePeerReader,
|
||||
"PeerGuardian": PeerGuardianReader
|
||||
'Emule': EmuleReader,
|
||||
'SafePeer': SafePeerReader,
|
||||
'PeerGuardian': PeerGuardianReader
|
||||
}
|
||||
|
||||
|
||||
@ -34,13 +34,13 @@ class UnknownFormatError(Exception):
|
||||
|
||||
|
||||
def detect_compression(filename):
|
||||
with open(filename, "rb") as _file:
|
||||
with open(filename, 'rb') as _file:
|
||||
magic_number = _file.read(2)
|
||||
return COMPRESSION_TYPES.get(magic_number, "")
|
||||
return COMPRESSION_TYPES.get(magic_number, '')
|
||||
|
||||
|
||||
def detect_format(filename, compression=""):
|
||||
file_format = ""
|
||||
def detect_format(filename, compression=''):
|
||||
file_format = ''
|
||||
for reader in READERS:
|
||||
if create_reader(reader, compression)(filename).is_valid():
|
||||
file_format = reader
|
||||
@ -48,7 +48,7 @@ def detect_format(filename, compression=""):
|
||||
return file_format
|
||||
|
||||
|
||||
def create_reader(file_format, compression=""):
|
||||
def create_reader(file_format, compression=''):
|
||||
reader = READERS.get(file_format)
|
||||
if reader and compression:
|
||||
decompressor = DECOMPRESSERS.get(compression)
|
||||
|
||||
@ -25,102 +25,102 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class GtkUI(GtkPluginBase):
|
||||
def enable(self):
|
||||
log.debug("Blocklist GtkUI enable..")
|
||||
self.plugin = component.get("PluginManager")
|
||||
log.debug('Blocklist GtkUI enable..')
|
||||
self.plugin = component.get('PluginManager')
|
||||
|
||||
self.load_preferences_page()
|
||||
|
||||
self.status_item = component.get("StatusBar").add_item(
|
||||
image=common.get_resource("blocklist16.png"),
|
||||
text="",
|
||||
self.status_item = component.get('StatusBar').add_item(
|
||||
image=common.get_resource('blocklist16.png'),
|
||||
text='',
|
||||
callback=self._on_status_item_clicked,
|
||||
tooltip=_("Blocked IP Ranges /Whitelisted IP Ranges")
|
||||
tooltip=_('Blocked IP Ranges /Whitelisted IP Ranges')
|
||||
)
|
||||
|
||||
# Register some hooks
|
||||
self.plugin.register_hook("on_apply_prefs", self._on_apply_prefs)
|
||||
self.plugin.register_hook("on_show_prefs", self._on_show_prefs)
|
||||
self.plugin.register_hook('on_apply_prefs', self._on_apply_prefs)
|
||||
self.plugin.register_hook('on_show_prefs', self._on_show_prefs)
|
||||
|
||||
def disable(self):
|
||||
log.debug("Blocklist GtkUI disable..")
|
||||
log.debug('Blocklist GtkUI disable..')
|
||||
|
||||
# Remove the preferences page
|
||||
self.plugin.remove_preferences_page(_("Blocklist"))
|
||||
self.plugin.remove_preferences_page(_('Blocklist'))
|
||||
|
||||
# Remove status item
|
||||
component.get("StatusBar").remove_item(self.status_item)
|
||||
component.get('StatusBar').remove_item(self.status_item)
|
||||
del self.status_item
|
||||
|
||||
# Deregister the hooks
|
||||
self.plugin.deregister_hook("on_apply_prefs", self._on_apply_prefs)
|
||||
self.plugin.deregister_hook("on_show_prefs", self._on_show_prefs)
|
||||
self.plugin.deregister_hook('on_apply_prefs', self._on_apply_prefs)
|
||||
self.plugin.deregister_hook('on_show_prefs', self._on_show_prefs)
|
||||
|
||||
del self.glade
|
||||
|
||||
def update(self):
|
||||
def _on_get_status(status):
|
||||
if status["state"] == "Downloading":
|
||||
if status['state'] == 'Downloading':
|
||||
self.table_info.hide()
|
||||
self.glade.get_widget("button_check_download").set_sensitive(False)
|
||||
self.glade.get_widget("button_force_download").set_sensitive(False)
|
||||
self.glade.get_widget("image_up_to_date").hide()
|
||||
self.glade.get_widget('button_check_download').set_sensitive(False)
|
||||
self.glade.get_widget('button_force_download').set_sensitive(False)
|
||||
self.glade.get_widget('image_up_to_date').hide()
|
||||
|
||||
self.status_item.set_text(
|
||||
"Downloading %.2f%%" % (status["file_progress"] * 100))
|
||||
self.progress_bar.set_text("Downloading %.2f%%" % (status["file_progress"] * 100))
|
||||
self.progress_bar.set_fraction(status["file_progress"])
|
||||
'Downloading %.2f%%' % (status['file_progress'] * 100))
|
||||
self.progress_bar.set_text('Downloading %.2f%%' % (status['file_progress'] * 100))
|
||||
self.progress_bar.set_fraction(status['file_progress'])
|
||||
self.progress_bar.show()
|
||||
|
||||
elif status["state"] == "Importing":
|
||||
elif status['state'] == 'Importing':
|
||||
self.table_info.hide()
|
||||
self.glade.get_widget("button_check_download").set_sensitive(False)
|
||||
self.glade.get_widget("button_force_download").set_sensitive(False)
|
||||
self.glade.get_widget("image_up_to_date").hide()
|
||||
self.glade.get_widget('button_check_download').set_sensitive(False)
|
||||
self.glade.get_widget('button_force_download').set_sensitive(False)
|
||||
self.glade.get_widget('image_up_to_date').hide()
|
||||
|
||||
self.status_item.set_text(
|
||||
"Importing " + str(status["num_blocked"]))
|
||||
self.progress_bar.set_text("Importing %s" % (status["num_blocked"]))
|
||||
'Importing ' + str(status['num_blocked']))
|
||||
self.progress_bar.set_text('Importing %s' % (status['num_blocked']))
|
||||
self.progress_bar.pulse()
|
||||
self.progress_bar.show()
|
||||
|
||||
elif status["state"] == "Idle":
|
||||
elif status['state'] == 'Idle':
|
||||
self.progress_bar.hide()
|
||||
self.glade.get_widget("button_check_download").set_sensitive(True)
|
||||
self.glade.get_widget("button_force_download").set_sensitive(True)
|
||||
if status["up_to_date"]:
|
||||
self.glade.get_widget("image_up_to_date").show()
|
||||
self.glade.get_widget('button_check_download').set_sensitive(True)
|
||||
self.glade.get_widget('button_force_download').set_sensitive(True)
|
||||
if status['up_to_date']:
|
||||
self.glade.get_widget('image_up_to_date').show()
|
||||
else:
|
||||
self.glade.get_widget("image_up_to_date").hide()
|
||||
self.glade.get_widget('image_up_to_date').hide()
|
||||
|
||||
self.table_info.show()
|
||||
self.status_item.set_text("%(num_blocked)s/%(num_whited)s" % status)
|
||||
self.status_item.set_text('%(num_blocked)s/%(num_whited)s' % status)
|
||||
|
||||
self.glade.get_widget("label_filesize").set_text(
|
||||
deluge.common.fsize(status["file_size"]))
|
||||
self.glade.get_widget("label_modified").set_text(
|
||||
datetime.fromtimestamp(status["file_date"]).strftime("%c"))
|
||||
self.glade.get_widget("label_type").set_text(status["file_type"])
|
||||
self.glade.get_widget("label_url").set_text(
|
||||
status["file_url"])
|
||||
self.glade.get_widget('label_filesize').set_text(
|
||||
deluge.common.fsize(status['file_size']))
|
||||
self.glade.get_widget('label_modified').set_text(
|
||||
datetime.fromtimestamp(status['file_date']).strftime('%c'))
|
||||
self.glade.get_widget('label_type').set_text(status['file_type'])
|
||||
self.glade.get_widget('label_url').set_text(
|
||||
status['file_url'])
|
||||
|
||||
client.blocklist.get_status().addCallback(_on_get_status)
|
||||
|
||||
def _on_show_prefs(self):
|
||||
def _on_get_config(config):
|
||||
log.trace("Loaded config: %s", config)
|
||||
self.glade.get_widget("entry_url").set_text(config["url"])
|
||||
self.glade.get_widget("spin_check_days").set_value(config["check_after_days"])
|
||||
self.glade.get_widget("chk_import_on_start").set_active(config["load_on_start"])
|
||||
self.populate_whitelist(config["whitelisted"])
|
||||
log.trace('Loaded config: %s', config)
|
||||
self.glade.get_widget('entry_url').set_text(config['url'])
|
||||
self.glade.get_widget('spin_check_days').set_value(config['check_after_days'])
|
||||
self.glade.get_widget('chk_import_on_start').set_active(config['load_on_start'])
|
||||
self.populate_whitelist(config['whitelisted'])
|
||||
|
||||
client.blocklist.get_config().addCallback(_on_get_config)
|
||||
|
||||
def _on_apply_prefs(self):
|
||||
config = {}
|
||||
config["url"] = self.glade.get_widget("entry_url").get_text().strip()
|
||||
config["check_after_days"] = self.glade.get_widget("spin_check_days").get_value_as_int()
|
||||
config["load_on_start"] = self.glade.get_widget("chk_import_on_start").get_active()
|
||||
config["whitelisted"] = [ip[0] for ip in self.whitelist_model if ip[0] != 'IP HERE']
|
||||
config['url'] = self.glade.get_widget('entry_url').get_text().strip()
|
||||
config['check_after_days'] = self.glade.get_widget('spin_check_days').get_value_as_int()
|
||||
config['load_on_start'] = self.glade.get_widget('chk_import_on_start').get_active()
|
||||
config['whitelisted'] = [ip[0] for ip in self.whitelist_model if ip[0] != 'IP HERE']
|
||||
client.blocklist.set_config(config)
|
||||
|
||||
def _on_button_check_download_clicked(self, widget):
|
||||
@ -132,16 +132,16 @@ class GtkUI(GtkPluginBase):
|
||||
client.blocklist.check_import(force=True)
|
||||
|
||||
def _on_status_item_clicked(self, widget, event):
|
||||
component.get("Preferences").show(_("Blocklist"))
|
||||
component.get('Preferences').show(_('Blocklist'))
|
||||
|
||||
def load_preferences_page(self):
|
||||
"""Initializes the preferences page and adds it to the preferences dialog"""
|
||||
# Load the preferences page
|
||||
self.glade = gtk.glade.XML(common.get_resource("blocklist_pref.glade"))
|
||||
self.glade = gtk.glade.XML(common.get_resource('blocklist_pref.glade'))
|
||||
|
||||
self.whitelist_frame = self.glade.get_widget("whitelist_frame")
|
||||
self.progress_bar = self.glade.get_widget("progressbar")
|
||||
self.table_info = self.glade.get_widget("table_info")
|
||||
self.whitelist_frame = self.glade.get_widget('whitelist_frame')
|
||||
self.progress_bar = self.glade.get_widget('progressbar')
|
||||
self.table_info = self.glade.get_widget('table_info')
|
||||
|
||||
# Hide the progress bar initially
|
||||
self.progress_bar.hide()
|
||||
@ -151,8 +151,8 @@ class GtkUI(GtkPluginBase):
|
||||
self.build_whitelist_model_treeview()
|
||||
|
||||
self.glade.signal_autoconnect({
|
||||
"on_button_check_download_clicked": self._on_button_check_download_clicked,
|
||||
"on_button_force_download_clicked": self._on_button_force_download_clicked,
|
||||
'on_button_check_download_clicked': self._on_button_check_download_clicked,
|
||||
'on_button_force_download_clicked': self._on_button_force_download_clicked,
|
||||
'on_whitelist_add_clicked': (self.on_add_button_clicked,
|
||||
self.whitelist_treeview),
|
||||
'on_whitelist_remove_clicked': (self.on_delete_button_clicked,
|
||||
@ -160,32 +160,32 @@ class GtkUI(GtkPluginBase):
|
||||
})
|
||||
|
||||
# Set button icons
|
||||
self.glade.get_widget("image_download").set_from_file(
|
||||
common.get_resource("blocklist_download24.png"))
|
||||
self.glade.get_widget('image_download').set_from_file(
|
||||
common.get_resource('blocklist_download24.png'))
|
||||
|
||||
self.glade.get_widget("image_import").set_from_file(
|
||||
common.get_resource("blocklist_import24.png"))
|
||||
self.glade.get_widget('image_import').set_from_file(
|
||||
common.get_resource('blocklist_import24.png'))
|
||||
|
||||
# Update the preferences page with config values from the core
|
||||
self._on_show_prefs()
|
||||
|
||||
# Add the page to the preferences dialog
|
||||
self.plugin.add_preferences_page(
|
||||
_("Blocklist"),
|
||||
self.glade.get_widget("blocklist_prefs_box"))
|
||||
_('Blocklist'),
|
||||
self.glade.get_widget('blocklist_prefs_box'))
|
||||
|
||||
def build_whitelist_model_treeview(self):
|
||||
self.whitelist_treeview = self.glade.get_widget("whitelist_treeview")
|
||||
self.whitelist_treeview = self.glade.get_widget('whitelist_treeview')
|
||||
treeview_selection = self.whitelist_treeview.get_selection()
|
||||
treeview_selection.connect(
|
||||
"changed", self.on_whitelist_treeview_selection_changed
|
||||
'changed', self.on_whitelist_treeview_selection_changed
|
||||
)
|
||||
self.whitelist_model = gtk.ListStore(str, bool)
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.connect("edited", self.on_cell_edited, self.whitelist_model)
|
||||
renderer.set_data("ip", 0)
|
||||
renderer.connect('edited', self.on_cell_edited, self.whitelist_model)
|
||||
renderer.set_data('ip', 0)
|
||||
|
||||
column = gtk.TreeViewColumn("IPs", renderer, text=0, editable=1)
|
||||
column = gtk.TreeViewColumn('IPs', renderer, text=0, editable=1)
|
||||
column.set_expand(True)
|
||||
self.whitelist_treeview.append_column(column)
|
||||
self.whitelist_treeview.set_model(self.whitelist_model)
|
||||
@ -199,21 +199,21 @@ class GtkUI(GtkPluginBase):
|
||||
except common.BadIP as ex:
|
||||
model.remove(model.get_iter_from_string(path_string))
|
||||
from deluge.ui.gtkui import dialogs
|
||||
d = dialogs.ErrorDialog(_("Bad IP address"), ex.message)
|
||||
d = dialogs.ErrorDialog(_('Bad IP address'), ex.message)
|
||||
d.run()
|
||||
|
||||
def on_whitelist_treeview_selection_changed(self, selection):
|
||||
model, selected_connection_iter = selection.get_selected()
|
||||
if selected_connection_iter:
|
||||
self.glade.get_widget("whitelist_delete").set_property('sensitive',
|
||||
self.glade.get_widget('whitelist_delete').set_property('sensitive',
|
||||
True)
|
||||
else:
|
||||
self.glade.get_widget("whitelist_delete").set_property('sensitive',
|
||||
self.glade.get_widget('whitelist_delete').set_property('sensitive',
|
||||
False)
|
||||
|
||||
def on_add_button_clicked(self, widget, treeview):
|
||||
model = treeview.get_model()
|
||||
model.set(model.append(), 0, "IP HERE", 1, True)
|
||||
model.set(model.append(), 0, 'IP HERE', 1, True)
|
||||
|
||||
def on_delete_button_clicked(self, widget, treeview):
|
||||
selection = treeview.get_selection()
|
||||
|
||||
@ -24,35 +24,35 @@ class PGException(Exception):
|
||||
class PGReader(object):
|
||||
|
||||
def __init__(self, filename):
|
||||
log.debug("PGReader loading: %s", filename)
|
||||
log.debug('PGReader loading: %s', filename)
|
||||
|
||||
try:
|
||||
with gzip.open(filename, "rb") as _file:
|
||||
with gzip.open(filename, 'rb') as _file:
|
||||
self.fd = _file
|
||||
except IOError:
|
||||
log.debug("Blocklist: PGReader: Incorrect file type or list is corrupt")
|
||||
log.debug('Blocklist: PGReader: Incorrect file type or list is corrupt')
|
||||
|
||||
# 4 bytes, should be 0xffffffff
|
||||
buf = self.fd.read(4)
|
||||
hdr = unpack("l", buf)[0]
|
||||
hdr = unpack('l', buf)[0]
|
||||
if hdr != -1:
|
||||
raise PGException(_("Invalid leader") + " %d" % hdr)
|
||||
raise PGException(_('Invalid leader') + ' %d' % hdr)
|
||||
|
||||
magic = self.fd.read(3)
|
||||
if magic != "P2B":
|
||||
raise PGException(_("Invalid magic code"))
|
||||
if magic != 'P2B':
|
||||
raise PGException(_('Invalid magic code'))
|
||||
|
||||
buf = self.fd.read(1)
|
||||
ver = ord(buf)
|
||||
if ver != 1 and ver != 2:
|
||||
raise PGException(_("Invalid version") + " %d" % ver)
|
||||
raise PGException(_('Invalid version') + ' %d' % ver)
|
||||
|
||||
def __next__(self):
|
||||
# Skip over the string
|
||||
buf = -1
|
||||
while buf != 0:
|
||||
buf = self.fd.read(1)
|
||||
if buf == "": # EOF
|
||||
if buf == '': # EOF
|
||||
return False
|
||||
buf = ord(buf)
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ class BaseReader(object):
|
||||
try:
|
||||
callback(IP.parse(start), IP.parse(end))
|
||||
except BadIP as ex:
|
||||
log.error("Failed to parse IP: %s", ex)
|
||||
log.error('Failed to parse IP: %s', ex)
|
||||
return self.file
|
||||
|
||||
def is_ignored(self, line):
|
||||
@ -55,8 +55,8 @@ class BaseReader(object):
|
||||
if not self.is_ignored(line):
|
||||
try:
|
||||
(start, end) = self.parse(line)
|
||||
if not re.match(r"^(\d{1,3}\.){4}$", start + ".") or \
|
||||
not re.match(r"^(\d{1,3}\.){4}$", end + "."):
|
||||
if not re.match(r'^(\d{1,3}\.){4}$', start + '.') or \
|
||||
not re.match(r'^(\d{1,3}\.){4}$', end + '.'):
|
||||
valid = False
|
||||
except Exception:
|
||||
valid = False
|
||||
@ -77,13 +77,13 @@ class BaseReader(object):
|
||||
class EmuleReader(BaseReader):
|
||||
"""Blocklist reader for emule style blocklists"""
|
||||
def parse(self, line):
|
||||
return line.strip().split(" , ")[0].split(" - ")
|
||||
return line.strip().split(' , ')[0].split(' - ')
|
||||
|
||||
|
||||
class SafePeerReader(BaseReader):
|
||||
"""Blocklist reader for SafePeer style blocklists"""
|
||||
def parse(self, line):
|
||||
return line.strip().split(":")[-1].split("-")
|
||||
return line.strip().split(':')[-1].split('-')
|
||||
|
||||
|
||||
class PeerGuardianReader(SafePeerReader):
|
||||
|
||||
@ -16,14 +16,14 @@ from .common import get_resource
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
FORMAT_LIST = [
|
||||
('gzmule', _("Emule IP list (GZip)")),
|
||||
('spzip', _("SafePeer Text (Zipped)")),
|
||||
('pgtext', _("PeerGuardian Text (Uncompressed)")),
|
||||
('p2bgz', _("PeerGuardian P2B (GZip)"))
|
||||
('gzmule', _('Emule IP list (GZip)')),
|
||||
('spzip', _('SafePeer Text (Zipped)')),
|
||||
('pgtext', _('PeerGuardian Text (Uncompressed)')),
|
||||
('p2bgz', _('PeerGuardian P2B (GZip)'))
|
||||
]
|
||||
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("blocklist.js")]
|
||||
scripts = [get_resource('blocklist.js')]
|
||||
debug_scripts = scripts
|
||||
|
||||
@ -9,15 +9,15 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Blocklist"
|
||||
__author__ = "John Garland"
|
||||
__author_email__ = "johnnybg+deluge@gmail.com"
|
||||
__version__ = "1.3"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Download and import IP blocklists"
|
||||
__plugin_name__ = 'Blocklist'
|
||||
__author__ = 'John Garland'
|
||||
__author_email__ = 'johnnybg+deluge@gmail.com'
|
||||
__version__ = '1.3'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Download and import IP blocklists'
|
||||
__long_description__ = __description__
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ["data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -30,7 +30,7 @@ setup(
|
||||
zip_safe=False,
|
||||
long_description=__long_description__,
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
entry_points="""
|
||||
[deluge.plugin.core]
|
||||
|
||||
@ -13,5 +13,5 @@ import pkg_resources
|
||||
|
||||
|
||||
def get_resource(filename):
|
||||
return pkg_resources.resource_filename("deluge.plugins.execute",
|
||||
os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.execute',
|
||||
os.path.join('data', filename))
|
||||
|
||||
@ -24,7 +24,7 @@ from deluge.plugins.pluginbase import CorePluginBase
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
"commands": []
|
||||
'commands': []
|
||||
}
|
||||
|
||||
EXECUTE_ID = 0
|
||||
@ -32,9 +32,9 @@ EXECUTE_EVENT = 1
|
||||
EXECUTE_COMMAND = 2
|
||||
|
||||
EVENT_MAP = {
|
||||
"complete": "TorrentFinishedEvent",
|
||||
"added": "TorrentAddedEvent",
|
||||
"removed": "TorrentRemovedEvent"
|
||||
'complete': 'TorrentFinishedEvent',
|
||||
'added': 'TorrentAddedEvent',
|
||||
'removed': 'TorrentRemovedEvent'
|
||||
}
|
||||
|
||||
|
||||
@ -56,13 +56,13 @@ class ExecuteCommandRemovedEvent(DelugeEvent):
|
||||
|
||||
class Core(CorePluginBase):
|
||||
def enable(self):
|
||||
self.config = ConfigManager("execute.conf", DEFAULT_CONFIG)
|
||||
event_manager = component.get("EventManager")
|
||||
self.config = ConfigManager('execute.conf', DEFAULT_CONFIG)
|
||||
event_manager = component.get('EventManager')
|
||||
self.registered_events = {}
|
||||
self.preremoved_cache = {}
|
||||
|
||||
# Go through the commands list and register event handlers
|
||||
for command in self.config["commands"]:
|
||||
for command in self.config['commands']:
|
||||
event = command[EXECUTE_EVENT]
|
||||
if event in self.registered_events:
|
||||
continue
|
||||
@ -73,47 +73,47 @@ class Core(CorePluginBase):
|
||||
return event_handler
|
||||
event_handler = create_event_handler(event)
|
||||
event_manager.register_event_handler(EVENT_MAP[event], event_handler)
|
||||
if event == "removed":
|
||||
event_manager.register_event_handler("PreTorrentRemovedEvent", self.on_preremoved)
|
||||
if event == 'removed':
|
||||
event_manager.register_event_handler('PreTorrentRemovedEvent', self.on_preremoved)
|
||||
self.registered_events[event] = event_handler
|
||||
|
||||
log.debug("Execute core plugin enabled!")
|
||||
log.debug('Execute core plugin enabled!')
|
||||
|
||||
def on_preremoved(self, torrent_id):
|
||||
# Get and store the torrent info before it is removed
|
||||
torrent = component.get("TorrentManager").torrents[torrent_id]
|
||||
info = torrent.get_status(["name", "download_location"])
|
||||
self.preremoved_cache[torrent_id] = [utf8_encoded(torrent_id), utf8_encoded(info["name"]),
|
||||
utf8_encoded(info["download_location"])]
|
||||
torrent = component.get('TorrentManager').torrents[torrent_id]
|
||||
info = torrent.get_status(['name', 'download_location'])
|
||||
self.preremoved_cache[torrent_id] = [utf8_encoded(torrent_id), utf8_encoded(info['name']),
|
||||
utf8_encoded(info['download_location'])]
|
||||
|
||||
def execute_commands(self, torrent_id, event, *arg):
|
||||
if event == "added" and arg[0]:
|
||||
if event == 'added' and arg[0]:
|
||||
# No futher action as from_state (arg[0]) is True
|
||||
return
|
||||
elif event == "removed":
|
||||
elif event == 'removed':
|
||||
torrent_id, torrent_name, download_location = self.preremoved_cache.pop(torrent_id)
|
||||
else:
|
||||
torrent = component.get("TorrentManager").torrents[torrent_id]
|
||||
info = torrent.get_status(["name", "download_location"])
|
||||
torrent = component.get('TorrentManager').torrents[torrent_id]
|
||||
info = torrent.get_status(['name', 'download_location'])
|
||||
# Grab the torrent name and download location
|
||||
# getProcessOutputAndValue requires args to be str
|
||||
torrent_id = utf8_encoded(torrent_id)
|
||||
torrent_name = utf8_encoded(info["name"])
|
||||
download_location = utf8_encoded(info["download_location"])
|
||||
torrent_name = utf8_encoded(info['name'])
|
||||
download_location = utf8_encoded(info['download_location'])
|
||||
|
||||
log.debug("Running commands for %s", event)
|
||||
log.debug('Running commands for %s', event)
|
||||
|
||||
def log_error(result, command):
|
||||
(stdout, stderr, exit_code) = result
|
||||
if exit_code:
|
||||
log.warn("Command '%s' failed with exit code %d", command, exit_code)
|
||||
if stdout:
|
||||
log.warn("stdout: %s", stdout)
|
||||
log.warn('stdout: %s', stdout)
|
||||
if stderr:
|
||||
log.warn("stderr: %s", stderr)
|
||||
log.warn('stderr: %s', stderr)
|
||||
|
||||
# Go through and execute all the commands
|
||||
for command in self.config["commands"]:
|
||||
for command in self.config['commands']:
|
||||
if command[EXECUTE_EVENT] == event:
|
||||
command = os.path.expandvars(command[EXECUTE_COMMAND])
|
||||
command = os.path.expanduser(command)
|
||||
@ -121,47 +121,47 @@ class Core(CorePluginBase):
|
||||
cmd_args = [torrent_id, torrent_name, download_location]
|
||||
if windows_check():
|
||||
# Escape ampersand on windows (see #2784)
|
||||
cmd_args = [cmd_arg.replace("&", "^^^&") for cmd_arg in cmd_args]
|
||||
cmd_args = [cmd_arg.replace('&', '^^^&') for cmd_arg in cmd_args]
|
||||
|
||||
if os.path.isfile(command) and os.access(command, os.X_OK):
|
||||
log.debug("Running %s with args: %s", command, cmd_args)
|
||||
log.debug('Running %s with args: %s', command, cmd_args)
|
||||
d = getProcessOutputAndValue(command, cmd_args, env=os.environ)
|
||||
d.addCallback(log_error, command)
|
||||
else:
|
||||
log.error("Execute script not found or not executable")
|
||||
log.error('Execute script not found or not executable')
|
||||
|
||||
def disable(self):
|
||||
self.config.save()
|
||||
event_manager = component.get("EventManager")
|
||||
event_manager = component.get('EventManager')
|
||||
for event, handler in self.registered_events.iteritems():
|
||||
event_manager.deregister_event_handler(event, handler)
|
||||
log.debug("Execute core plugin disabled!")
|
||||
log.debug('Execute core plugin disabled!')
|
||||
|
||||
# Exported RPC methods #
|
||||
@export
|
||||
def add_command(self, event, command):
|
||||
command_id = hashlib.sha1(str(time.time())).hexdigest()
|
||||
self.config["commands"].append((command_id, event, command))
|
||||
self.config['commands'].append((command_id, event, command))
|
||||
self.config.save()
|
||||
component.get("EventManager").emit(ExecuteCommandAddedEvent(command_id, event, command))
|
||||
component.get('EventManager').emit(ExecuteCommandAddedEvent(command_id, event, command))
|
||||
|
||||
@export
|
||||
def get_commands(self):
|
||||
return self.config["commands"]
|
||||
return self.config['commands']
|
||||
|
||||
@export
|
||||
def remove_command(self, command_id):
|
||||
for command in self.config["commands"]:
|
||||
for command in self.config['commands']:
|
||||
if command[EXECUTE_ID] == command_id:
|
||||
self.config["commands"].remove(command)
|
||||
component.get("EventManager").emit(ExecuteCommandRemovedEvent(command_id))
|
||||
self.config['commands'].remove(command)
|
||||
component.get('EventManager').emit(ExecuteCommandRemovedEvent(command_id))
|
||||
break
|
||||
self.config.save()
|
||||
|
||||
@export
|
||||
def save_command(self, command_id, event, cmd):
|
||||
for i, command in enumerate(self.config["commands"]):
|
||||
for i, command in enumerate(self.config['commands']):
|
||||
if command[EXECUTE_ID] == command_id:
|
||||
self.config["commands"][i] = (command_id, event, cmd)
|
||||
self.config['commands'][i] = (command_id, event, cmd)
|
||||
break
|
||||
self.config.save()
|
||||
|
||||
@ -27,12 +27,12 @@ EXECUTE_EVENT = 1
|
||||
EXECUTE_COMMAND = 2
|
||||
|
||||
EVENT_MAP = {
|
||||
"complete": _("Torrent Complete"),
|
||||
"added": _("Torrent Added"),
|
||||
"removed": _("Torrent Removed")
|
||||
'complete': _('Torrent Complete'),
|
||||
'added': _('Torrent Added'),
|
||||
'removed': _('Torrent Removed')
|
||||
}
|
||||
|
||||
EVENTS = ["complete", "added", "removed"]
|
||||
EVENTS = ['complete', 'added', 'removed']
|
||||
|
||||
|
||||
class ExecutePreferences(object):
|
||||
@ -40,13 +40,13 @@ class ExecutePreferences(object):
|
||||
self.plugin = plugin
|
||||
|
||||
def load(self):
|
||||
log.debug("Adding Execute Preferences page")
|
||||
self.glade = gtk.glade.XML(common.get_resource("execute_prefs.glade"))
|
||||
log.debug('Adding Execute Preferences page')
|
||||
self.glade = gtk.glade.XML(common.get_resource('execute_prefs.glade'))
|
||||
self.glade.signal_autoconnect({
|
||||
"on_add_button_clicked": self.on_add_button_clicked
|
||||
'on_add_button_clicked': self.on_add_button_clicked
|
||||
})
|
||||
|
||||
events = self.glade.get_widget("event_combobox")
|
||||
events = self.glade.get_widget('event_combobox')
|
||||
|
||||
store = gtk.ListStore(str, str)
|
||||
for event in EVENTS:
|
||||
@ -55,31 +55,31 @@ class ExecutePreferences(object):
|
||||
events.set_model(store)
|
||||
events.set_active(0)
|
||||
|
||||
self.plugin.add_preferences_page(_("Execute"), self.glade.get_widget("execute_box"))
|
||||
self.plugin.register_hook("on_show_prefs", self.load_commands)
|
||||
self.plugin.register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
self.plugin.add_preferences_page(_('Execute'), self.glade.get_widget('execute_box'))
|
||||
self.plugin.register_hook('on_show_prefs', self.load_commands)
|
||||
self.plugin.register_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
|
||||
self.load_commands()
|
||||
|
||||
client.register_event_handler("ExecuteCommandAddedEvent", self.on_command_added_event)
|
||||
client.register_event_handler("ExecuteCommandRemovedEvent", self.on_command_removed_event)
|
||||
client.register_event_handler('ExecuteCommandAddedEvent', self.on_command_added_event)
|
||||
client.register_event_handler('ExecuteCommandRemovedEvent', self.on_command_removed_event)
|
||||
|
||||
def unload(self):
|
||||
self.plugin.remove_preferences_page(_("Execute"))
|
||||
self.plugin.deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
self.plugin.deregister_hook("on_show_prefs", self.load_commands)
|
||||
self.plugin.remove_preferences_page(_('Execute'))
|
||||
self.plugin.deregister_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
self.plugin.deregister_hook('on_show_prefs', self.load_commands)
|
||||
|
||||
def add_command(self, command_id, event, command):
|
||||
log.debug("Adding command `%s`", command_id)
|
||||
vbox = self.glade.get_widget("commands_vbox")
|
||||
log.debug('Adding command `%s`', command_id)
|
||||
vbox = self.glade.get_widget('commands_vbox')
|
||||
hbox = gtk.HBox(False, 5)
|
||||
hbox.set_name(command_id + "_" + event)
|
||||
hbox.set_name(command_id + '_' + event)
|
||||
label = gtk.Label(EVENT_MAP[event])
|
||||
entry = gtk.Entry()
|
||||
entry.set_text(command)
|
||||
button = gtk.Button()
|
||||
button.set_name("remove_%s" % command_id)
|
||||
button.connect("clicked", self.on_remove_button_clicked)
|
||||
button.set_name('remove_%s' % command_id)
|
||||
button.connect('clicked', self.on_remove_button_clicked)
|
||||
|
||||
img = gtk.Image()
|
||||
img.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON)
|
||||
@ -92,15 +92,15 @@ class ExecutePreferences(object):
|
||||
vbox.pack_start(hbox)
|
||||
|
||||
def remove_command(self, command_id):
|
||||
vbox = self.glade.get_widget("commands_vbox")
|
||||
vbox = self.glade.get_widget('commands_vbox')
|
||||
children = vbox.get_children()
|
||||
for child in children:
|
||||
if child.get_name().split("_")[0] == command_id:
|
||||
if child.get_name().split('_')[0] == command_id:
|
||||
vbox.remove(child)
|
||||
break
|
||||
|
||||
def clear_commands(self):
|
||||
vbox = self.glade.get_widget("commands_vbox")
|
||||
vbox = self.glade.get_widget('commands_vbox')
|
||||
children = vbox.get_children()
|
||||
for child in children:
|
||||
vbox.remove(child)
|
||||
@ -108,7 +108,7 @@ class ExecutePreferences(object):
|
||||
def load_commands(self):
|
||||
def on_get_commands(commands):
|
||||
self.clear_commands()
|
||||
log.debug("on_get_commands: %s", commands)
|
||||
log.debug('on_get_commands: %s', commands)
|
||||
for command in commands:
|
||||
command_id, event, command = command
|
||||
self.add_command(command_id, event, command)
|
||||
@ -116,38 +116,38 @@ class ExecutePreferences(object):
|
||||
client.execute.get_commands().addCallback(on_get_commands)
|
||||
|
||||
def on_add_button_clicked(self, *args):
|
||||
command = self.glade.get_widget("command_entry").get_text()
|
||||
events = self.glade.get_widget("event_combobox")
|
||||
command = self.glade.get_widget('command_entry').get_text()
|
||||
events = self.glade.get_widget('event_combobox')
|
||||
event = events.get_model()[events.get_active()][1]
|
||||
client.execute.add_command(event, command)
|
||||
|
||||
def on_remove_button_clicked(self, widget, *args):
|
||||
command_id = widget.get_name().replace("remove_", "")
|
||||
command_id = widget.get_name().replace('remove_', '')
|
||||
client.execute.remove_command(command_id)
|
||||
|
||||
def on_apply_prefs(self):
|
||||
vbox = self.glade.get_widget("commands_vbox")
|
||||
vbox = self.glade.get_widget('commands_vbox')
|
||||
children = vbox.get_children()
|
||||
for child in children:
|
||||
command_id, event = child.get_name().split("_")
|
||||
command_id, event = child.get_name().split('_')
|
||||
for widget in child.get_children():
|
||||
if isinstance(widget, gtk.Entry):
|
||||
command = widget.get_text()
|
||||
client.execute.save_command(command_id, event, command)
|
||||
|
||||
def on_command_added_event(self, command_id, event, command):
|
||||
log.debug("Adding command %s: %s", event, command)
|
||||
log.debug('Adding command %s: %s', event, command)
|
||||
self.add_command(command_id, event, command)
|
||||
|
||||
def on_command_removed_event(self, command_id):
|
||||
log.debug("Removing command %s", command_id)
|
||||
log.debug('Removing command %s', command_id)
|
||||
self.remove_command(command_id)
|
||||
|
||||
|
||||
class GtkUI(GtkPluginBase):
|
||||
|
||||
def enable(self):
|
||||
self.plugin = component.get("PluginManager")
|
||||
self.plugin = component.get('PluginManager')
|
||||
self.preferences = ExecutePreferences(self.plugin)
|
||||
self.preferences.load()
|
||||
|
||||
|
||||
@ -18,5 +18,5 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("execute.js")]
|
||||
scripts = [get_resource('execute.js')]
|
||||
debug_scripts = scripts
|
||||
|
||||
@ -9,15 +9,15 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Execute"
|
||||
__author__ = "Damien Churchill"
|
||||
__author_email__ = "damoxc@gmail.com"
|
||||
__version__ = "1.2"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Plugin to execute a command upon an event"
|
||||
__plugin_name__ = 'Execute'
|
||||
__author__ = 'Damien Churchill'
|
||||
__author_email__ = 'damoxc@gmail.com'
|
||||
__version__ = '1.2'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Plugin to execute a command upon an event'
|
||||
__long_description__ = __description__
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -30,7 +30,7 @@ setup(
|
||||
long_description=__long_description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -13,5 +13,5 @@ import pkg_resources
|
||||
|
||||
|
||||
def get_resource(filename):
|
||||
return pkg_resources.resource_filename("deluge.plugins.extractor",
|
||||
os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.extractor',
|
||||
os.path.join('data', filename))
|
||||
|
||||
@ -27,8 +27,8 @@ from deluge.plugins.pluginbase import CorePluginBase
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"extract_path": "",
|
||||
"use_name_folder": True
|
||||
'extract_path': '',
|
||||
'use_name_folder': True
|
||||
}
|
||||
|
||||
if windows_check():
|
||||
@ -40,15 +40,15 @@ if windows_check():
|
||||
|
||||
import _winreg
|
||||
try:
|
||||
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\7-Zip")
|
||||
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\7-Zip')
|
||||
except WindowsError: # pylint: disable=undefined-variable
|
||||
pass
|
||||
else:
|
||||
win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, "Path")[0], "7z.exe")
|
||||
win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe')
|
||||
_winreg.CloseKey(hkey)
|
||||
win_7z_exes.insert(1, win_7z_path)
|
||||
|
||||
switch_7z = "x -y"
|
||||
switch_7z = 'x -y'
|
||||
# Future suport:
|
||||
# 7-zip cannot extract tar.* with single command.
|
||||
# ".tar.gz", ".tgz",
|
||||
@ -56,15 +56,15 @@ if windows_check():
|
||||
# ".tar.lzma", ".tlz",
|
||||
# ".tar.xz", ".txz",
|
||||
exts_7z = [
|
||||
".rar", ".zip", ".tar",
|
||||
".7z", ".xz", ".lzma",
|
||||
'.rar', '.zip', '.tar',
|
||||
'.7z', '.xz', '.lzma',
|
||||
]
|
||||
for win_7z_exe in win_7z_exes:
|
||||
if which(win_7z_exe):
|
||||
EXTRACT_COMMANDS = dict.fromkeys(exts_7z, [win_7z_exe, switch_7z])
|
||||
break
|
||||
else:
|
||||
required_cmds = ["unrar", "unzip", "tar", "unxz", "unlzma", "7zr", "bunzip2"]
|
||||
required_cmds = ['unrar', 'unzip', 'tar', 'unxz', 'unlzma', '7zr', 'bunzip2']
|
||||
# Possible future suport:
|
||||
# gunzip: gz (cmd will delete original archive)
|
||||
# the following do not extract to dest dir
|
||||
@ -73,36 +73,36 @@ else:
|
||||
# ".bz2": ["bzip2", "-d --keep"],
|
||||
|
||||
EXTRACT_COMMANDS = {
|
||||
".rar": ["unrar", "x -o+ -y"],
|
||||
".tar": ["tar", "-xf"],
|
||||
".zip": ["unzip", ""],
|
||||
".tar.gz": ["tar", "-xzf"], ".tgz": ["tar", "-xzf"],
|
||||
".tar.bz2": ["tar", "-xjf"], ".tbz": ["tar", "-xjf"],
|
||||
".tar.lzma": ["tar", "--lzma -xf"], ".tlz": ["tar", "--lzma -xf"],
|
||||
".tar.xz": ["tar", "--xz -xf"], ".txz": ["tar", "--xz -xf"],
|
||||
".7z": ["7zr", "x"],
|
||||
'.rar': ['unrar', 'x -o+ -y'],
|
||||
'.tar': ['tar', '-xf'],
|
||||
'.zip': ['unzip', ''],
|
||||
'.tar.gz': ['tar', '-xzf'], '.tgz': ['tar', '-xzf'],
|
||||
'.tar.bz2': ['tar', '-xjf'], '.tbz': ['tar', '-xjf'],
|
||||
'.tar.lzma': ['tar', '--lzma -xf'], '.tlz': ['tar', '--lzma -xf'],
|
||||
'.tar.xz': ['tar', '--xz -xf'], '.txz': ['tar', '--xz -xf'],
|
||||
'.7z': ['7zr', 'x'],
|
||||
}
|
||||
# Test command exists and if not, remove.
|
||||
for command in required_cmds:
|
||||
if not which(command):
|
||||
for k, v in EXTRACT_COMMANDS.items():
|
||||
if command in v[0]:
|
||||
log.warning("%s not found, disabling support for %s", command, k)
|
||||
log.warning('%s not found, disabling support for %s', command, k)
|
||||
del EXTRACT_COMMANDS[k]
|
||||
|
||||
if not EXTRACT_COMMANDS:
|
||||
raise Exception("No archive extracting programs found, plugin will be disabled")
|
||||
raise Exception('No archive extracting programs found, plugin will be disabled')
|
||||
|
||||
|
||||
class Core(CorePluginBase):
|
||||
def enable(self):
|
||||
self.config = deluge.configmanager.ConfigManager("extractor.conf", DEFAULT_PREFS)
|
||||
if not self.config["extract_path"]:
|
||||
self.config["extract_path"] = deluge.configmanager.ConfigManager("core.conf")["download_location"]
|
||||
component.get("EventManager").register_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
|
||||
self.config = deluge.configmanager.ConfigManager('extractor.conf', DEFAULT_PREFS)
|
||||
if not self.config['extract_path']:
|
||||
self.config['extract_path'] = deluge.configmanager.ConfigManager('core.conf')['download_location']
|
||||
component.get('EventManager').register_event_handler('TorrentFinishedEvent', self._on_torrent_finished)
|
||||
|
||||
def disable(self):
|
||||
component.get("EventManager").deregister_event_handler("TorrentFinishedEvent", self._on_torrent_finished)
|
||||
component.get('EventManager').deregister_event_handler('TorrentFinishedEvent', self._on_torrent_finished)
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
@ -111,57 +111,57 @@ class Core(CorePluginBase):
|
||||
"""
|
||||
This is called when a torrent finishes and checks if any files to extract.
|
||||
"""
|
||||
tid = component.get("TorrentManager").torrents[torrent_id]
|
||||
tid_status = tid.get_status(["download_location", "name"])
|
||||
tid = component.get('TorrentManager').torrents[torrent_id]
|
||||
tid_status = tid.get_status(['download_location', 'name'])
|
||||
|
||||
files = tid.get_files()
|
||||
for f in files:
|
||||
file_root, file_ext = os.path.splitext(f["path"])
|
||||
file_root, file_ext = os.path.splitext(f['path'])
|
||||
file_ext_sec = os.path.splitext(file_root)[1]
|
||||
if file_ext_sec and file_ext_sec + file_ext in EXTRACT_COMMANDS:
|
||||
file_ext = file_ext_sec + file_ext
|
||||
elif file_ext not in EXTRACT_COMMANDS or file_ext_sec == '.tar':
|
||||
log.debug("Can't extract file with unknown file type: %s", f["path"])
|
||||
log.debug("Can't extract file with unknown file type: %s", f['path'])
|
||||
continue
|
||||
elif file_ext == ".rar" and "part" in file_ext_sec:
|
||||
part_num = file_ext_sec.split("part")[1]
|
||||
elif file_ext == '.rar' and 'part' in file_ext_sec:
|
||||
part_num = file_ext_sec.split('part')[1]
|
||||
if part_num.isdigit() and int(part_num) != 1:
|
||||
log.debug("Skipping remaining multi-part rar files: %s", f["path"])
|
||||
log.debug('Skipping remaining multi-part rar files: %s', f['path'])
|
||||
continue
|
||||
|
||||
cmd = EXTRACT_COMMANDS[file_ext]
|
||||
fpath = os.path.join(tid_status["download_location"], os.path.normpath(f["path"]))
|
||||
dest = os.path.normpath(self.config["extract_path"])
|
||||
if self.config["use_name_folder"]:
|
||||
dest = os.path.join(dest, tid_status["name"])
|
||||
fpath = os.path.join(tid_status['download_location'], os.path.normpath(f['path']))
|
||||
dest = os.path.normpath(self.config['extract_path'])
|
||||
if self.config['use_name_folder']:
|
||||
dest = os.path.join(dest, tid_status['name'])
|
||||
|
||||
try:
|
||||
os.makedirs(dest)
|
||||
except OSError as ex:
|
||||
if not (ex.errno == errno.EEXIST and os.path.isdir(dest)):
|
||||
log.error("Error creating destination folder: %s", ex)
|
||||
log.error('Error creating destination folder: %s', ex)
|
||||
break
|
||||
|
||||
def on_extract(result, torrent_id, fpath):
|
||||
# Check command exit code.
|
||||
if not result[2]:
|
||||
log.info("Extract successful: %s (%s)", fpath, torrent_id)
|
||||
log.info('Extract successful: %s (%s)', fpath, torrent_id)
|
||||
else:
|
||||
log.error("Extract failed: %s (%s) %s", fpath, torrent_id, result[1])
|
||||
log.error('Extract failed: %s (%s) %s', fpath, torrent_id, result[1])
|
||||
|
||||
# Run the command and add callback.
|
||||
log.debug("Extracting %s from %s with %s %s to %s", fpath, torrent_id, cmd[0], cmd[1], dest)
|
||||
log.debug('Extracting %s from %s with %s %s to %s', fpath, torrent_id, cmd[0], cmd[1], dest)
|
||||
d = getProcessOutputAndValue(cmd[0], cmd[1].split() + [str(fpath)], os.environ, str(dest))
|
||||
d.addCallback(on_extract, torrent_id, fpath)
|
||||
|
||||
@export
|
||||
def set_config(self, config):
|
||||
"sets the config dictionary"
|
||||
'sets the config dictionary'
|
||||
for key in config.keys():
|
||||
self.config[key] = config[key]
|
||||
self.config.save()
|
||||
|
||||
@export
|
||||
def get_config(self):
|
||||
"returns the config dictionary"
|
||||
'returns the config dictionary'
|
||||
return self.config.config
|
||||
|
||||
@ -27,47 +27,47 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class GtkUI(GtkPluginBase):
|
||||
def enable(self):
|
||||
self.glade = gtk.glade.XML(get_resource("extractor_prefs.glade"))
|
||||
self.glade = gtk.glade.XML(get_resource('extractor_prefs.glade'))
|
||||
|
||||
component.get("Preferences").add_page(_("Extractor"), self.glade.get_widget("extractor_prefs_box"))
|
||||
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get('Preferences').add_page(_('Extractor'), self.glade.get_widget('extractor_prefs_box'))
|
||||
component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
|
||||
self.on_show_prefs()
|
||||
|
||||
def disable(self):
|
||||
component.get("Preferences").remove_page(_("Extractor"))
|
||||
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get('Preferences').remove_page(_('Extractor'))
|
||||
component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
|
||||
del self.glade
|
||||
|
||||
def on_apply_prefs(self):
|
||||
log.debug("applying prefs for Extractor")
|
||||
log.debug('applying prefs for Extractor')
|
||||
if client.is_localhost():
|
||||
path = self.glade.get_widget("folderchooser_path").get_filename()
|
||||
path = self.glade.get_widget('folderchooser_path').get_filename()
|
||||
else:
|
||||
path = self.glade.get_widget("entry_path").get_text()
|
||||
path = self.glade.get_widget('entry_path').get_text()
|
||||
|
||||
config = {
|
||||
"extract_path": path,
|
||||
"use_name_folder": self.glade.get_widget("chk_use_name").get_active()
|
||||
'extract_path': path,
|
||||
'use_name_folder': self.glade.get_widget('chk_use_name').get_active()
|
||||
}
|
||||
|
||||
client.extractor.set_config(config)
|
||||
|
||||
def on_show_prefs(self):
|
||||
if client.is_localhost():
|
||||
self.glade.get_widget("folderchooser_path").show()
|
||||
self.glade.get_widget("entry_path").hide()
|
||||
self.glade.get_widget('folderchooser_path').show()
|
||||
self.glade.get_widget('entry_path').hide()
|
||||
else:
|
||||
self.glade.get_widget("folderchooser_path").hide()
|
||||
self.glade.get_widget("entry_path").show()
|
||||
self.glade.get_widget('folderchooser_path').hide()
|
||||
self.glade.get_widget('entry_path').show()
|
||||
|
||||
def on_get_config(config):
|
||||
if client.is_localhost():
|
||||
self.glade.get_widget("folderchooser_path").set_current_folder(config["extract_path"])
|
||||
self.glade.get_widget('folderchooser_path').set_current_folder(config['extract_path'])
|
||||
else:
|
||||
self.glade.get_widget("entry_path").set_text(config["extract_path"])
|
||||
self.glade.get_widget('entry_path').set_text(config['extract_path'])
|
||||
|
||||
self.glade.get_widget("chk_use_name").set_active(config["use_name_folder"])
|
||||
self.glade.get_widget('chk_use_name').set_active(config['use_name_folder'])
|
||||
|
||||
client.extractor.get_config().addCallback(on_get_config)
|
||||
|
||||
@ -22,5 +22,5 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("extractor.js")]
|
||||
scripts = [get_resource('extractor.js')]
|
||||
debug_scripts = scripts
|
||||
|
||||
@ -13,13 +13,13 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Extractor"
|
||||
__author__ = "Andrew Resch"
|
||||
__author_email__ = "andrewresch@gmail.com"
|
||||
__version__ = "0.6"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Extract files upon torrent completion"
|
||||
__plugin_name__ = 'Extractor'
|
||||
__author__ = 'Andrew Resch'
|
||||
__author_email__ = 'andrewresch@gmail.com'
|
||||
__version__ = '0.6'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Extract files upon torrent completion'
|
||||
__long_description__ = """
|
||||
Extract files upon torrent completion
|
||||
|
||||
@ -30,7 +30,7 @@ Windows support: .rar, .zip, .tar, .7z, .xz, .lzma
|
||||
|
||||
Note: Will not extract with 'Move Completed' enabled
|
||||
"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -43,7 +43,7 @@ setup(
|
||||
long_description=__long_description__ if __long_description__ else __description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -26,40 +26,40 @@ from deluge.plugins.pluginbase import CorePluginBase
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
RE_VALID = re.compile(r"[a-z0-9_\-\.]*\Z")
|
||||
RE_VALID = re.compile(r'[a-z0-9_\-\.]*\Z')
|
||||
|
||||
KNOWN_STATES = ['Downloading', 'Seeding', 'Paused', 'Checking', 'Queued', 'Error']
|
||||
STATE = "state"
|
||||
TRACKER = "tracker"
|
||||
KEYWORD = "keyword"
|
||||
LABEL = "label"
|
||||
STATE = 'state'
|
||||
TRACKER = 'tracker'
|
||||
KEYWORD = 'keyword'
|
||||
LABEL = 'label'
|
||||
CONFIG_DEFAULTS = {
|
||||
"torrent_labels": {}, # torrent_id:label_id
|
||||
"labels": {}, # label_id:{name:value}
|
||||
'torrent_labels': {}, # torrent_id:label_id
|
||||
'labels': {}, # label_id:{name:value}
|
||||
}
|
||||
|
||||
CORE_OPTIONS = ["auto_add_trackers"]
|
||||
CORE_OPTIONS = ['auto_add_trackers']
|
||||
|
||||
OPTIONS_DEFAULTS = {
|
||||
"apply_max": False,
|
||||
"max_download_speed": -1,
|
||||
"max_upload_speed": -1,
|
||||
"max_connections": -1,
|
||||
"max_upload_slots": -1,
|
||||
"prioritize_first_last": False,
|
||||
"apply_queue": False,
|
||||
"is_auto_managed": False,
|
||||
"stop_at_ratio": False,
|
||||
"stop_ratio": 2.0,
|
||||
"remove_at_ratio": False,
|
||||
"apply_move_completed": False,
|
||||
"move_completed": False,
|
||||
"move_completed_path": "",
|
||||
"auto_add": False,
|
||||
"auto_add_trackers": []
|
||||
'apply_max': False,
|
||||
'max_download_speed': -1,
|
||||
'max_upload_speed': -1,
|
||||
'max_connections': -1,
|
||||
'max_upload_slots': -1,
|
||||
'prioritize_first_last': False,
|
||||
'apply_queue': False,
|
||||
'is_auto_managed': False,
|
||||
'stop_at_ratio': False,
|
||||
'stop_ratio': 2.0,
|
||||
'remove_at_ratio': False,
|
||||
'apply_move_completed': False,
|
||||
'move_completed': False,
|
||||
'move_completed_path': '',
|
||||
'auto_add': False,
|
||||
'auto_add_trackers': []
|
||||
}
|
||||
|
||||
NO_LABEL = "No Label"
|
||||
NO_LABEL = 'No Label'
|
||||
|
||||
|
||||
def check_input(cond, message):
|
||||
@ -73,35 +73,35 @@ class Core(CorePluginBase):
|
||||
self.torrent_labels = {torrent_id:label_id}
|
||||
"""
|
||||
def enable(self):
|
||||
log.info("*** Start Label plugin ***")
|
||||
self.plugin = component.get("CorePluginManager")
|
||||
self.plugin.register_status_field("label", self._status_get_label)
|
||||
log.info('*** Start Label plugin ***')
|
||||
self.plugin = component.get('CorePluginManager')
|
||||
self.plugin.register_status_field('label', self._status_get_label)
|
||||
|
||||
# __init__
|
||||
core = component.get("Core")
|
||||
self.config = ConfigManager("label.conf", defaults=CONFIG_DEFAULTS)
|
||||
self.core_cfg = ConfigManager("core.conf")
|
||||
core = component.get('Core')
|
||||
self.config = ConfigManager('label.conf', defaults=CONFIG_DEFAULTS)
|
||||
self.core_cfg = ConfigManager('core.conf')
|
||||
|
||||
# reduce typing, assigning some values to self...
|
||||
self.torrents = core.torrentmanager.torrents
|
||||
self.labels = self.config["labels"]
|
||||
self.torrent_labels = self.config["torrent_labels"]
|
||||
self.labels = self.config['labels']
|
||||
self.torrent_labels = self.config['torrent_labels']
|
||||
|
||||
self.clean_initial_config()
|
||||
|
||||
component.get("EventManager").register_event_handler("TorrentAddedEvent", self.post_torrent_add)
|
||||
component.get("EventManager").register_event_handler("TorrentRemovedEvent", self.post_torrent_remove)
|
||||
component.get('EventManager').register_event_handler('TorrentAddedEvent', self.post_torrent_add)
|
||||
component.get('EventManager').register_event_handler('TorrentRemovedEvent', self.post_torrent_remove)
|
||||
|
||||
# register tree:
|
||||
component.get("FilterManager").register_tree_field("label", self.init_filter_dict)
|
||||
component.get('FilterManager').register_tree_field('label', self.init_filter_dict)
|
||||
|
||||
log.debug("Label plugin enabled..")
|
||||
log.debug('Label plugin enabled..')
|
||||
|
||||
def disable(self):
|
||||
self.plugin.deregister_status_field("label")
|
||||
component.get("FilterManager").deregister_tree_field("label")
|
||||
component.get("EventManager").deregister_event_handler("TorrentAddedEvent", self.post_torrent_add)
|
||||
component.get("EventManager").deregister_event_handler("TorrentRemovedEvent", self.post_torrent_remove)
|
||||
self.plugin.deregister_status_field('label')
|
||||
component.get('FilterManager').deregister_tree_field('label')
|
||||
component.get('EventManager').deregister_event_handler('TorrentAddedEvent', self.post_torrent_add)
|
||||
component.get('EventManager').deregister_event_handler('TorrentRemovedEvent', self.post_torrent_remove)
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
@ -115,17 +115,17 @@ class Core(CorePluginBase):
|
||||
def post_torrent_add(self, torrent_id, from_state):
|
||||
if from_state:
|
||||
return
|
||||
log.debug("post_torrent_add")
|
||||
log.debug('post_torrent_add')
|
||||
torrent = self.torrents[torrent_id]
|
||||
|
||||
for label_id, options in self.labels.iteritems():
|
||||
if options["auto_add"]:
|
||||
if options['auto_add']:
|
||||
if self._has_auto_match(torrent, options):
|
||||
self.set_torrent(torrent_id, label_id)
|
||||
return
|
||||
|
||||
def post_torrent_remove(self, torrent_id):
|
||||
log.debug("post_torrent_remove")
|
||||
log.debug('post_torrent_remove')
|
||||
if torrent_id in self.torrent_labels:
|
||||
del self.torrent_labels[torrent_id]
|
||||
|
||||
@ -134,7 +134,7 @@ class Core(CorePluginBase):
|
||||
"""remove invalid data from config-file"""
|
||||
for torrent_id, label_id in list(self.torrent_labels.iteritems()):
|
||||
if (label_id not in self.labels) or (torrent_id not in self.torrents):
|
||||
log.debug("label: rm %s:%s", torrent_id, label_id)
|
||||
log.debug('label: rm %s:%s', torrent_id, label_id)
|
||||
del self.torrent_labels[torrent_id]
|
||||
|
||||
def clean_initial_config(self):
|
||||
@ -168,9 +168,9 @@ class Core(CorePluginBase):
|
||||
see label_set_options for more options.
|
||||
"""
|
||||
label_id = label_id.lower()
|
||||
check_input(RE_VALID.match(label_id), _("Invalid label, valid characters:[a-z0-9_-]"))
|
||||
check_input(label_id, _("Empty Label"))
|
||||
check_input(not (label_id in self.labels), _("Label already exists"))
|
||||
check_input(RE_VALID.match(label_id), _('Invalid label, valid characters:[a-z0-9_-]'))
|
||||
check_input(label_id, _('Empty Label'))
|
||||
check_input(not (label_id in self.labels), _('Label already exists'))
|
||||
|
||||
self.labels[label_id] = dict(OPTIONS_DEFAULTS)
|
||||
self.config.save()
|
||||
@ -178,7 +178,7 @@ class Core(CorePluginBase):
|
||||
@export
|
||||
def remove(self, label_id):
|
||||
"""remove a label"""
|
||||
check_input(label_id in self.labels, _("Unknown Label"))
|
||||
check_input(label_id in self.labels, _('Unknown Label'))
|
||||
del self.labels[label_id]
|
||||
self.clean_config()
|
||||
self.config.save()
|
||||
@ -187,27 +187,27 @@ class Core(CorePluginBase):
|
||||
options = self.labels[label_id]
|
||||
torrent = self.torrents[torrent_id]
|
||||
|
||||
if not options["move_completed_path"]:
|
||||
options["move_completed_path"] = "" # no None.
|
||||
if not options['move_completed_path']:
|
||||
options['move_completed_path'] = '' # no None.
|
||||
|
||||
if options["apply_max"]:
|
||||
torrent.set_max_download_speed(options["max_download_speed"])
|
||||
torrent.set_max_upload_speed(options["max_upload_speed"])
|
||||
torrent.set_max_connections(options["max_connections"])
|
||||
torrent.set_max_upload_slots(options["max_upload_slots"])
|
||||
torrent.set_prioritize_first_last_pieces(options["prioritize_first_last"])
|
||||
if options['apply_max']:
|
||||
torrent.set_max_download_speed(options['max_download_speed'])
|
||||
torrent.set_max_upload_speed(options['max_upload_speed'])
|
||||
torrent.set_max_connections(options['max_connections'])
|
||||
torrent.set_max_upload_slots(options['max_upload_slots'])
|
||||
torrent.set_prioritize_first_last_pieces(options['prioritize_first_last'])
|
||||
|
||||
if options["apply_queue"]:
|
||||
if options['apply_queue']:
|
||||
torrent.set_auto_managed(options['is_auto_managed'])
|
||||
torrent.set_stop_at_ratio(options['stop_at_ratio'])
|
||||
torrent.set_stop_ratio(options['stop_ratio'])
|
||||
torrent.set_remove_at_ratio(options['remove_at_ratio'])
|
||||
|
||||
if options["apply_move_completed"]:
|
||||
if options['apply_move_completed']:
|
||||
torrent.set_options(
|
||||
{
|
||||
"move_completed": options["move_completed"],
|
||||
"move_completed_path": options["move_completed_path"]
|
||||
'move_completed': options['move_completed'],
|
||||
'move_completed_path': options['move_completed_path']
|
||||
}
|
||||
)
|
||||
|
||||
@ -215,32 +215,32 @@ class Core(CorePluginBase):
|
||||
options = self.labels[label_id]
|
||||
torrent = self.torrents[torrent_id]
|
||||
|
||||
if options["apply_max"]:
|
||||
torrent.set_max_download_speed(self.core_cfg.config["max_download_speed_per_torrent"])
|
||||
torrent.set_max_upload_speed(self.core_cfg.config["max_upload_speed_per_torrent"])
|
||||
torrent.set_max_connections(self.core_cfg.config["max_connections_per_torrent"])
|
||||
torrent.set_max_upload_slots(self.core_cfg.config["max_upload_slots_per_torrent"])
|
||||
torrent.set_prioritize_first_last_pieces(self.core_cfg.config["prioritize_first_last_pieces"])
|
||||
if options['apply_max']:
|
||||
torrent.set_max_download_speed(self.core_cfg.config['max_download_speed_per_torrent'])
|
||||
torrent.set_max_upload_speed(self.core_cfg.config['max_upload_speed_per_torrent'])
|
||||
torrent.set_max_connections(self.core_cfg.config['max_connections_per_torrent'])
|
||||
torrent.set_max_upload_slots(self.core_cfg.config['max_upload_slots_per_torrent'])
|
||||
torrent.set_prioritize_first_last_pieces(self.core_cfg.config['prioritize_first_last_pieces'])
|
||||
|
||||
if options["apply_queue"]:
|
||||
if options['apply_queue']:
|
||||
torrent.set_auto_managed(self.core_cfg.config['auto_managed'])
|
||||
torrent.set_stop_at_ratio(self.core_cfg.config['stop_seed_at_ratio'])
|
||||
torrent.set_stop_ratio(self.core_cfg.config['stop_seed_ratio'])
|
||||
torrent.set_remove_at_ratio(self.core_cfg.config['remove_seed_at_ratio'])
|
||||
|
||||
if options["apply_move_completed"]:
|
||||
if options['apply_move_completed']:
|
||||
torrent.set_options(
|
||||
{
|
||||
"move_completed": self.core_cfg.config["move_completed"],
|
||||
"move_completed_path": self.core_cfg.config["move_completed_path"]
|
||||
'move_completed': self.core_cfg.config['move_completed'],
|
||||
'move_completed_path': self.core_cfg.config['move_completed_path']
|
||||
}
|
||||
)
|
||||
|
||||
def _has_auto_match(self, torrent, label_options):
|
||||
"""match for auto_add fields"""
|
||||
for tracker_match in label_options["auto_add_trackers"]:
|
||||
for tracker_match in label_options['auto_add_trackers']:
|
||||
for tracker in torrent.trackers:
|
||||
if tracker_match in tracker["url"]:
|
||||
if tracker_match in tracker['url']:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -258,10 +258,10 @@ class Core(CorePluginBase):
|
||||
"move_completed_to":string() or None
|
||||
}
|
||||
"""
|
||||
check_input(label_id in self.labels, _("Unknown Label"))
|
||||
check_input(label_id in self.labels, _('Unknown Label'))
|
||||
for key in options_dict.keys():
|
||||
if key not in OPTIONS_DEFAULTS:
|
||||
raise Exception("label: Invalid options_dict key:%s" % key)
|
||||
raise Exception('label: Invalid options_dict key:%s' % key)
|
||||
|
||||
self.labels[label_id].update(options_dict)
|
||||
|
||||
@ -272,7 +272,7 @@ class Core(CorePluginBase):
|
||||
|
||||
# auto add
|
||||
options = self.labels[label_id]
|
||||
if options["auto_add"]:
|
||||
if options['auto_add']:
|
||||
for torrent_id, torrent in self.torrents.iteritems():
|
||||
if self._has_auto_match(torrent, options):
|
||||
self.set_torrent(torrent_id, label_id)
|
||||
@ -293,8 +293,8 @@ class Core(CorePluginBase):
|
||||
if label_id == NO_LABEL:
|
||||
label_id = None
|
||||
|
||||
check_input((not label_id) or (label_id in self.labels), _("Unknown Label"))
|
||||
check_input(torrent_id in self.torrents, _("Unknown Torrent"))
|
||||
check_input((not label_id) or (label_id in self.labels), _('Unknown Label'))
|
||||
check_input(torrent_id in self.torrents, _('Unknown Torrent'))
|
||||
|
||||
if torrent_id in self.torrent_labels:
|
||||
self._unset_torrent_options(torrent_id, self.torrent_labels[torrent_id])
|
||||
@ -322,4 +322,4 @@ class Core(CorePluginBase):
|
||||
self.config.save()
|
||||
|
||||
def _status_get_label(self, torrent_id):
|
||||
return self.torrent_labels.get(torrent_id) or ""
|
||||
return self.torrent_labels.get(torrent_id) or ''
|
||||
|
||||
@ -16,7 +16,7 @@ from . import label_config, sidebar_menu, submenu
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
NO_LABEL = "No Label"
|
||||
NO_LABEL = 'No Label'
|
||||
|
||||
|
||||
def cell_data_label(column, cell, model, row, data):
|
||||
@ -29,8 +29,8 @@ class GtkUI(GtkPluginBase):
|
||||
self.label_menu.on_show()
|
||||
|
||||
def enable(self):
|
||||
self.plugin = component.get("PluginManager")
|
||||
self.torrentmenu = component.get("MenuBar").torrentmenu
|
||||
self.plugin = component.get('PluginManager')
|
||||
self.torrentmenu = component.get('MenuBar').torrentmenu
|
||||
self.label_menu = None
|
||||
self.labelcfg = None
|
||||
self.sidebar_menu = None
|
||||
@ -44,7 +44,7 @@ class GtkUI(GtkPluginBase):
|
||||
self.sidebar_menu.unload()
|
||||
del self.sidebar_menu
|
||||
|
||||
component.get("TorrentView").remove_column(_("Label"))
|
||||
component.get('TorrentView').remove_column(_('Label'))
|
||||
|
||||
def load_interface(self):
|
||||
# sidebar
|
||||
@ -54,7 +54,7 @@ class GtkUI(GtkPluginBase):
|
||||
# self.sidebar.load()
|
||||
|
||||
# menu:
|
||||
log.debug("add items to torrentview-popup menu.")
|
||||
log.debug('add items to torrentview-popup menu.')
|
||||
self.label_menu = submenu.LabelMenu()
|
||||
self.torrentmenu.append(self.label_menu)
|
||||
self.label_menu.show_all()
|
||||
@ -70,6 +70,6 @@ class GtkUI(GtkPluginBase):
|
||||
log.debug('Finished loading Label plugin')
|
||||
|
||||
def load_columns(self):
|
||||
log.debug("add columns")
|
||||
log.debug('add columns')
|
||||
|
||||
component.get("TorrentView").add_text_column(_("Label"), status_field=["label"])
|
||||
component.get('TorrentView').add_text_column(_('Label'), status_field=['label'])
|
||||
|
||||
@ -29,29 +29,29 @@ class LabelConfig(object):
|
||||
|
||||
def load(self):
|
||||
log.debug('Adding Label Preferences page')
|
||||
self.glade = gtk.glade.XML(self.get_resource("label_pref.glade"))
|
||||
self.glade = gtk.glade.XML(self.get_resource('label_pref.glade'))
|
||||
|
||||
self.plugin.add_preferences_page(_("Label"), self.glade.get_widget("label_prefs_box"))
|
||||
self.plugin.register_hook("on_show_prefs", self.load_settings)
|
||||
self.plugin.register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
self.plugin.add_preferences_page(_('Label'), self.glade.get_widget('label_prefs_box'))
|
||||
self.plugin.register_hook('on_show_prefs', self.load_settings)
|
||||
self.plugin.register_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
|
||||
self.load_settings()
|
||||
|
||||
def unload(self):
|
||||
self.plugin.remove_preferences_page(_("Label"))
|
||||
self.plugin.deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
self.plugin.deregister_hook("on_show_prefs", self.load_settings)
|
||||
self.plugin.remove_preferences_page(_('Label'))
|
||||
self.plugin.deregister_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
self.plugin.deregister_hook('on_show_prefs', self.load_settings)
|
||||
|
||||
def get_resource(self, filename):
|
||||
return pkg_resources.resource_filename(
|
||||
"deluge.plugins.label", os.path.join("data", filename)
|
||||
'deluge.plugins.label', os.path.join('data', filename)
|
||||
)
|
||||
|
||||
def load_settings(self, widget=None, data=None):
|
||||
client.label.get_config().addCallback(self.cb_global_options)
|
||||
|
||||
def cb_global_options(self, options):
|
||||
log.debug("options=%s", options)
|
||||
log.debug('options=%s', options)
|
||||
|
||||
# for id in self.chk_ids:
|
||||
# self.glade.get_widget(id).set_active(bool(options[id]))
|
||||
|
||||
@ -18,7 +18,7 @@ from deluge.ui.client import client
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
NO_LABEL = "No Label"
|
||||
NO_LABEL = 'No Label'
|
||||
|
||||
|
||||
# helpers:
|
||||
@ -26,7 +26,7 @@ def get_resource(filename):
|
||||
import pkg_resources
|
||||
import os
|
||||
return pkg_resources.resource_filename(
|
||||
"deluge.plugins.label", os.path.join("data", filename)
|
||||
'deluge.plugins.label', os.path.join('data', filename)
|
||||
)
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ def get_resource(filename):
|
||||
class LabelSidebarMenu(object):
|
||||
def __init__(self):
|
||||
|
||||
self.treeview = component.get("FilterTreeView")
|
||||
self.treeview = component.get('FilterTreeView')
|
||||
self.menu = self.treeview.menu
|
||||
self.items = []
|
||||
|
||||
@ -42,27 +42,27 @@ class LabelSidebarMenu(object):
|
||||
sep = gtk.SeparatorMenuItem()
|
||||
self.items.append(sep)
|
||||
self.menu.prepend(sep)
|
||||
self._add_item("options", _("Label _Options"), gtk.STOCK_PREFERENCES)
|
||||
self._add_item("remove", _("_Remove Label"), gtk.STOCK_REMOVE)
|
||||
self._add_item("add", _("_Add Label"), gtk.STOCK_ADD)
|
||||
self._add_item('options', _('Label _Options'), gtk.STOCK_PREFERENCES)
|
||||
self._add_item('remove', _('_Remove Label'), gtk.STOCK_REMOVE)
|
||||
self._add_item('add', _('_Add Label'), gtk.STOCK_ADD)
|
||||
|
||||
self.menu.show_all()
|
||||
# dialogs:
|
||||
self.add_dialog = AddDialog()
|
||||
self.options_dialog = OptionsDialog()
|
||||
# hooks:
|
||||
self.menu.connect("show", self.on_show, None)
|
||||
self.menu.connect('show', self.on_show, None)
|
||||
|
||||
def _add_item(self, item_id, label, stock):
|
||||
"""I hate glade.
|
||||
id is automatically-added as self.item_<id>
|
||||
"""
|
||||
func = getattr(self, "on_%s" % item_id)
|
||||
func = getattr(self, 'on_%s' % item_id)
|
||||
item = gtk.ImageMenuItem(stock)
|
||||
item.get_children()[0].set_label(label)
|
||||
item.connect("activate", func)
|
||||
item.connect('activate', func)
|
||||
self.menu.prepend(item)
|
||||
setattr(self, "item_%s" % item_id, item)
|
||||
setattr(self, 'item_%s' % item_id, item)
|
||||
self.items.append(item)
|
||||
return item
|
||||
|
||||
@ -76,17 +76,17 @@ class LabelSidebarMenu(object):
|
||||
self.options_dialog.show(self.treeview.value)
|
||||
|
||||
def on_show(self, widget=None, data=None):
|
||||
"No Label:disable options/del"
|
||||
log.debug("label-sidebar-popup:on-show")
|
||||
'No Label:disable options/del'
|
||||
log.debug('label-sidebar-popup:on-show')
|
||||
|
||||
cat = self.treeview.cat
|
||||
label = self.treeview.value
|
||||
if cat == "label" or (cat == "cat" and label == "label"):
|
||||
if cat == 'label' or (cat == 'cat' and label == 'label'):
|
||||
# is a label : show menu-items
|
||||
for item in self.items:
|
||||
item.show()
|
||||
# default items
|
||||
sensitive = ((label not in (NO_LABEL, None, "", "All")) and (cat != "cat"))
|
||||
sensitive = ((label not in (NO_LABEL, None, '', 'All')) and (cat != 'cat'))
|
||||
for item in self.items:
|
||||
item.set_sensitive(sensitive)
|
||||
|
||||
@ -98,11 +98,11 @@ class LabelSidebarMenu(object):
|
||||
item.hide()
|
||||
|
||||
def unload(self):
|
||||
log.debug("disable01")
|
||||
log.debug('disable01')
|
||||
for item in list(self.items):
|
||||
item.hide()
|
||||
item.destroy()
|
||||
log.debug("disable02")
|
||||
log.debug('disable02')
|
||||
self.items = []
|
||||
|
||||
|
||||
@ -112,18 +112,18 @@ class AddDialog(object):
|
||||
pass
|
||||
|
||||
def show(self):
|
||||
self.glade = gtk.glade.XML(get_resource("label_options.glade"))
|
||||
self.dialog = self.glade.get_widget("dlg_label_add")
|
||||
self.dialog.set_transient_for(component.get("MainWindow").window)
|
||||
self.glade = gtk.glade.XML(get_resource('label_options.glade'))
|
||||
self.dialog = self.glade.get_widget('dlg_label_add')
|
||||
self.dialog.set_transient_for(component.get('MainWindow').window)
|
||||
|
||||
self.glade.signal_autoconnect({
|
||||
"on_add_ok": self.on_ok,
|
||||
"on_add_cancel": self.on_cancel,
|
||||
'on_add_ok': self.on_ok,
|
||||
'on_add_cancel': self.on_cancel,
|
||||
})
|
||||
self.dialog.run()
|
||||
|
||||
def on_ok(self, event=None):
|
||||
value = self.glade.get_widget("txt_add").get_text()
|
||||
value = self.glade.get_widget('txt_add').get_text()
|
||||
client.label.add(value)
|
||||
self.dialog.destroy()
|
||||
|
||||
@ -132,19 +132,19 @@ class AddDialog(object):
|
||||
|
||||
|
||||
class OptionsDialog(object):
|
||||
spin_ids = ["max_download_speed", "max_upload_speed", "stop_ratio"]
|
||||
spin_int_ids = ["max_upload_slots", "max_connections"]
|
||||
chk_ids = ["apply_max", "apply_queue", "stop_at_ratio", "apply_queue", "remove_at_ratio",
|
||||
"apply_move_completed", "move_completed", "is_auto_managed", "auto_add"]
|
||||
spin_ids = ['max_download_speed', 'max_upload_speed', 'stop_ratio']
|
||||
spin_int_ids = ['max_upload_slots', 'max_connections']
|
||||
chk_ids = ['apply_max', 'apply_queue', 'stop_at_ratio', 'apply_queue', 'remove_at_ratio',
|
||||
'apply_move_completed', 'move_completed', 'is_auto_managed', 'auto_add']
|
||||
|
||||
# list of tuples, because order matters when nesting.
|
||||
sensitive_groups = [
|
||||
("apply_max", ["max_download_speed", "max_upload_speed", "max_upload_slots", "max_connections"]),
|
||||
("apply_queue", ["is_auto_managed", "stop_at_ratio"]),
|
||||
("stop_at_ratio", ["remove_at_ratio", "stop_ratio"]), # nested
|
||||
("apply_move_completed", ["move_completed"]),
|
||||
("move_completed", ["move_completed_path"]), # nested
|
||||
("auto_add", ["auto_add_trackers"])
|
||||
('apply_max', ['max_download_speed', 'max_upload_speed', 'max_upload_slots', 'max_connections']),
|
||||
('apply_queue', ['is_auto_managed', 'stop_at_ratio']),
|
||||
('stop_at_ratio', ['remove_at_ratio', 'stop_ratio']), # nested
|
||||
('apply_move_completed', ['move_completed']),
|
||||
('move_completed', ['move_completed_path']), # nested
|
||||
('auto_add', ['auto_add_trackers'])
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
@ -152,20 +152,20 @@ class OptionsDialog(object):
|
||||
|
||||
def show(self, label):
|
||||
self.label = label
|
||||
self.glade = gtk.glade.XML(get_resource("label_options.glade"))
|
||||
self.dialog = self.glade.get_widget("dlg_label_options")
|
||||
self.dialog.set_transient_for(component.get("MainWindow").window)
|
||||
self.glade = gtk.glade.XML(get_resource('label_options.glade'))
|
||||
self.dialog = self.glade.get_widget('dlg_label_options')
|
||||
self.dialog.set_transient_for(component.get('MainWindow').window)
|
||||
self.glade.signal_autoconnect({
|
||||
"on_options_ok": self.on_ok,
|
||||
"on_options_cancel": self.on_cancel,
|
||||
'on_options_ok': self.on_ok,
|
||||
'on_options_cancel': self.on_cancel,
|
||||
})
|
||||
|
||||
# Show the label name in the header label
|
||||
self.glade.get_widget("label_header").set_markup("<b>%s:</b> %s" % (_("Label Options"), self.label))
|
||||
self.glade.get_widget('label_header').set_markup('<b>%s:</b> %s' % (_('Label Options'), self.label))
|
||||
|
||||
for chk_id, group in self.sensitive_groups:
|
||||
chk = self.glade.get_widget(chk_id)
|
||||
chk.connect("toggled", self.apply_sensitivity)
|
||||
chk.connect('toggled', self.apply_sensitivity)
|
||||
|
||||
client.label.get_options(self.label).addCallback(self.load_options)
|
||||
|
||||
@ -180,20 +180,20 @@ class OptionsDialog(object):
|
||||
self.glade.get_widget(chk_id).set_active(bool(options[chk_id]))
|
||||
|
||||
if client.is_localhost():
|
||||
self.glade.get_widget("move_completed_path").set_filename(options["move_completed_path"])
|
||||
self.glade.get_widget("move_completed_path").show()
|
||||
self.glade.get_widget("move_completed_path_entry").hide()
|
||||
self.glade.get_widget('move_completed_path').set_filename(options['move_completed_path'])
|
||||
self.glade.get_widget('move_completed_path').show()
|
||||
self.glade.get_widget('move_completed_path_entry').hide()
|
||||
else:
|
||||
self.glade.get_widget("move_completed_path_entry").set_text(options["move_completed_path"])
|
||||
self.glade.get_widget("move_completed_path_entry").show()
|
||||
self.glade.get_widget("move_completed_path").hide()
|
||||
self.glade.get_widget('move_completed_path_entry').set_text(options['move_completed_path'])
|
||||
self.glade.get_widget('move_completed_path_entry').show()
|
||||
self.glade.get_widget('move_completed_path').hide()
|
||||
|
||||
self.glade.get_widget("auto_add_trackers").get_buffer().set_text("\n".join(options["auto_add_trackers"]))
|
||||
self.glade.get_widget('auto_add_trackers').get_buffer().set_text('\n'.join(options['auto_add_trackers']))
|
||||
|
||||
self.apply_sensitivity()
|
||||
|
||||
def on_ok(self, event=None):
|
||||
"save options.."
|
||||
'save options..'
|
||||
options = {}
|
||||
|
||||
for spin_id in self.spin_ids:
|
||||
@ -204,13 +204,13 @@ class OptionsDialog(object):
|
||||
options[chk_id] = self.glade.get_widget(chk_id).get_active()
|
||||
|
||||
if client.is_localhost():
|
||||
options["move_completed_path"] = self.glade.get_widget("move_completed_path").get_filename()
|
||||
options['move_completed_path'] = self.glade.get_widget('move_completed_path').get_filename()
|
||||
else:
|
||||
options["move_completed_path"] = self.glade.get_widget("move_completed_path_entry").get_text()
|
||||
options['move_completed_path'] = self.glade.get_widget('move_completed_path_entry').get_text()
|
||||
|
||||
buff = self.glade.get_widget("auto_add_trackers").get_buffer() # sometimes I hate gtk...
|
||||
tracker_lst = buff.get_text(buff.get_start_iter(), buff.get_end_iter()).strip().split("\n")
|
||||
options["auto_add_trackers"] = [x for x in tracker_lst if x] # filter out empty lines.
|
||||
buff = self.glade.get_widget('auto_add_trackers').get_buffer() # sometimes I hate gtk...
|
||||
tracker_lst = buff.get_text(buff.get_start_iter(), buff.get_end_iter()).strip().split('\n')
|
||||
options['auto_add_trackers'] = [x for x in tracker_lst if x] # filter out empty lines.
|
||||
|
||||
log.debug(options)
|
||||
client.label.set_options(self.label, options)
|
||||
@ -219,7 +219,7 @@ class OptionsDialog(object):
|
||||
def apply_sensitivity(self, event=None):
|
||||
for chk_id, sensitive_list in self.sensitive_groups:
|
||||
chk = self.glade.get_widget(chk_id)
|
||||
sens = chk.get_active() and chk.get_property("sensitive")
|
||||
sens = chk.get_active() and chk.get_property('sensitive')
|
||||
for widget_id in sensitive_list:
|
||||
self.glade.get_widget(widget_id).set_sensitive(sens)
|
||||
|
||||
|
||||
@ -21,26 +21,26 @@ log = logging.getLogger(__name__)
|
||||
# Deferred Translation
|
||||
def _(message):
|
||||
return message
|
||||
NO_LABEL = _("No Label")
|
||||
NO_LABEL = _('No Label')
|
||||
del _
|
||||
|
||||
|
||||
class LabelMenu(gtk.MenuItem):
|
||||
def __init__(self):
|
||||
gtk.MenuItem.__init__(self, _("Label"))
|
||||
gtk.MenuItem.__init__(self, _('Label'))
|
||||
|
||||
self.sub_menu = gtk.Menu()
|
||||
self.set_submenu(self.sub_menu)
|
||||
self.items = []
|
||||
|
||||
# attach..
|
||||
self.sub_menu.connect("show", self.on_show, None)
|
||||
self.sub_menu.connect('show', self.on_show, None)
|
||||
|
||||
def get_torrent_ids(self):
|
||||
return component.get("TorrentView").get_selected_torrents()
|
||||
return component.get('TorrentView').get_selected_torrents()
|
||||
|
||||
def on_show(self, widget=None, data=None):
|
||||
log.debug("label-on-show")
|
||||
log.debug('label-on-show')
|
||||
client.label.get_labels().addCallback(self.cb_labels)
|
||||
|
||||
def cb_labels(self, labels):
|
||||
@ -50,12 +50,12 @@ class LabelMenu(gtk.MenuItem):
|
||||
if label == NO_LABEL:
|
||||
item = gtk.MenuItem(_(NO_LABEL))
|
||||
else:
|
||||
item = gtk.MenuItem(label.replace("_", "__"))
|
||||
item.connect("activate", self.on_select_label, label)
|
||||
item = gtk.MenuItem(label.replace('_', '__'))
|
||||
item.connect('activate', self.on_select_label, label)
|
||||
self.sub_menu.append(item)
|
||||
self.show_all()
|
||||
|
||||
def on_select_label(self, widget=None, label_id=None):
|
||||
log.debug("select label:%s,%s", label_id, self.get_torrent_ids())
|
||||
log.debug('select label:%s,%s', label_id, self.get_torrent_ids())
|
||||
for torrent_id in self.get_torrent_ids():
|
||||
client.label.set_torrent(torrent_id, label_id)
|
||||
|
||||
@ -19,32 +19,32 @@ sclient.set_core_uri()
|
||||
print(sclient.get_enabled_plugins())
|
||||
|
||||
# enable plugin.
|
||||
if "label" not in sclient.get_enabled_plugins():
|
||||
sclient.enable_plugin("label")
|
||||
if 'label' not in sclient.get_enabled_plugins():
|
||||
sclient.enable_plugin('label')
|
||||
|
||||
|
||||
# test labels.
|
||||
print("#init labels")
|
||||
print('#init labels')
|
||||
try:
|
||||
sclient.label_remove("test")
|
||||
sclient.label_remove('test')
|
||||
except Exception:
|
||||
pass
|
||||
sess_id = sclient.get_session_state()[0]
|
||||
|
||||
print("#add")
|
||||
sclient.label_add("test")
|
||||
print("#set")
|
||||
sclient.label_set_torrent(id, "test")
|
||||
print('#add')
|
||||
sclient.label_add('test')
|
||||
print('#set')
|
||||
sclient.label_set_torrent(id, 'test')
|
||||
|
||||
print(sclient.get_torrents_status({"label": "test"}, "name"))
|
||||
print(sclient.get_torrents_status({'label': 'test'}, 'name'))
|
||||
|
||||
|
||||
print("#set options")
|
||||
sclient.label_set_options("test", {"max_download_speed": 999}, True)
|
||||
print(sclient.get_torrent_status(sess_id, ["max_download_speed"]), "999")
|
||||
sclient.label_set_options("test", {"max_download_speed": 9}, True)
|
||||
print(sclient.get_torrent_status(sess_id, ["max_download_speed"]), "9")
|
||||
sclient.label_set_options("test", {"max_download_speed": 888}, False)
|
||||
print(sclient.get_torrent_status(sess_id, ["max_download_speed"]), "9 (888)")
|
||||
print('#set options')
|
||||
sclient.label_set_options('test', {'max_download_speed': 999}, True)
|
||||
print(sclient.get_torrent_status(sess_id, ['max_download_speed']), '999')
|
||||
sclient.label_set_options('test', {'max_download_speed': 9}, True)
|
||||
print(sclient.get_torrent_status(sess_id, ['max_download_speed']), '9')
|
||||
sclient.label_set_options('test', {'max_download_speed': 888}, False)
|
||||
print(sclient.get_torrent_status(sess_id, ['max_download_speed']), '9 (888)')
|
||||
|
||||
print(sclient.get_torrent_status(sess_id, ['name', 'tracker_host', 'label']))
|
||||
|
||||
@ -22,11 +22,11 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_resource(filename):
|
||||
return pkg_resources.resource_filename("deluge.plugins.label",
|
||||
os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.label',
|
||||
os.path.join('data', filename))
|
||||
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("label.js")]
|
||||
scripts = [get_resource('label.js')]
|
||||
debug_scripts = scripts
|
||||
|
||||
@ -9,19 +9,19 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Label"
|
||||
__author__ = "Martijn Voncken"
|
||||
__author_email__ = "mvoncken@gmail.com"
|
||||
__version__ = "0.2"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Allows labels to be assigned to torrents"
|
||||
__plugin_name__ = 'Label'
|
||||
__author__ = 'Martijn Voncken'
|
||||
__author_email__ = 'mvoncken@gmail.com'
|
||||
__version__ = '0.2'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Allows labels to be assigned to torrents'
|
||||
__long_description__ = """
|
||||
Allows labels to be assigned to torrents
|
||||
|
||||
Also offers filters on state, tracker and keywords
|
||||
"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -34,7 +34,7 @@ setup(
|
||||
long_description=__long_description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -30,17 +30,17 @@ except ImportError:
|
||||
def get_resource(filename):
|
||||
import os
|
||||
import pkg_resources
|
||||
return pkg_resources.resource_filename("deluge.plugins.notifications", os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.notifications', os.path.join('data', filename))
|
||||
|
||||
|
||||
class CustomNotifications(object):
|
||||
|
||||
def __init__(self, plugin_name=None):
|
||||
self.custom_notifications = {
|
||||
"email": {},
|
||||
"popup": {},
|
||||
"blink": {},
|
||||
"sound": {}
|
||||
'email': {},
|
||||
'popup': {},
|
||||
'blink': {},
|
||||
'sound': {}
|
||||
}
|
||||
|
||||
def enable(self):
|
||||
@ -55,9 +55,9 @@ class CustomNotifications(object):
|
||||
def _handle_custom_providers(self, kind, eventtype, *args, **kwargs):
|
||||
log.debug("Calling CORE's custom %s providers for %s: %s %s",
|
||||
kind, eventtype, args, kwargs)
|
||||
if eventtype in self.config["subscriptions"][kind]:
|
||||
if eventtype in self.config['subscriptions'][kind]:
|
||||
wrapper, handler = self.custom_notifications[kind][eventtype]
|
||||
log.debug("Found handler for kind %s: %s", kind, handler)
|
||||
log.debug('Found handler for kind %s: %s', kind, handler)
|
||||
custom_notif_func = getattr(self,
|
||||
'handle_custom_%s_notification' % kind)
|
||||
d = defer.maybeDeferred(handler, *args, **kwargs)
|
||||
@ -68,7 +68,7 @@ class CustomNotifications(object):
|
||||
|
||||
def _register_custom_provider(self, kind, eventtype, handler):
|
||||
if not self._handled_eventtype(eventtype, handler):
|
||||
return defer.succeed("Event not handled")
|
||||
return defer.succeed('Event not handled')
|
||||
if eventtype not in self.custom_notifications:
|
||||
def wrapper(*args, **kwargs):
|
||||
return self._handle_custom_providers(kind, eventtype, *args, **kwargs)
|
||||
@ -76,7 +76,7 @@ class CustomNotifications(object):
|
||||
else:
|
||||
wrapper, handler = self.custom_notifications[kind][eventtype]
|
||||
try:
|
||||
component.get("EventManager").register_event_handler(
|
||||
component.get('EventManager').register_event_handler(
|
||||
eventtype, wrapper
|
||||
)
|
||||
except KeyError:
|
||||
@ -87,7 +87,7 @@ class CustomNotifications(object):
|
||||
try:
|
||||
wrapper, handler = self.custom_notifications[kind][eventtype]
|
||||
try:
|
||||
component.get("EventManager").deregister_event_handler(
|
||||
component.get('EventManager').deregister_event_handler(
|
||||
eventtype, wrapper
|
||||
)
|
||||
except KeyError:
|
||||
@ -104,15 +104,15 @@ class CustomNotifications(object):
|
||||
if known_events[eventtype].__module__.startswith('deluge.event'):
|
||||
if handler.__self__ is self:
|
||||
return True
|
||||
log.error("You cannot register custom notification providers "
|
||||
"for built-in event types.")
|
||||
log.error('You cannot register custom notification providers '
|
||||
'for built-in event types.')
|
||||
return False
|
||||
return True
|
||||
|
||||
def _on_notify_sucess(self, result, kind):
|
||||
log.debug("Notification success using %s: %s", kind, result)
|
||||
log.debug('Notification success using %s: %s', kind, result)
|
||||
return result
|
||||
|
||||
def _on_notify_failure(self, failure, kind):
|
||||
log.debug("Notification failure using %s: %s", kind, failure)
|
||||
log.debug('Notification failure using %s: %s', kind, failure)
|
||||
return failure
|
||||
|
||||
@ -29,17 +29,17 @@ from .common import CustomNotifications
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"smtp_enabled": False,
|
||||
"smtp_host": "",
|
||||
"smtp_port": 25,
|
||||
"smtp_user": "",
|
||||
"smtp_pass": "",
|
||||
"smtp_from": "",
|
||||
"smtp_tls": False, # SSL or TLS
|
||||
"smtp_recipients": [],
|
||||
'smtp_enabled': False,
|
||||
'smtp_host': '',
|
||||
'smtp_port': 25,
|
||||
'smtp_user': '',
|
||||
'smtp_pass': '',
|
||||
'smtp_from': '',
|
||||
'smtp_tls': False, # SSL or TLS
|
||||
'smtp_recipients': [],
|
||||
# Subscriptions
|
||||
"subscriptions": {
|
||||
"email": []
|
||||
'subscriptions': {
|
||||
'email': []
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,9 +73,9 @@ class CoreNotifications(CustomNotifications):
|
||||
|
||||
def handle_custom_email_notification(self, result, eventtype):
|
||||
if not self.config['smtp_enabled']:
|
||||
return defer.succeed("SMTP notification not enabled.")
|
||||
return defer.succeed('SMTP notification not enabled.')
|
||||
subject, message = result
|
||||
log.debug("Spawning new thread to send email with subject: %s: %s",
|
||||
log.debug('Spawning new thread to send email with subject: %s: %s',
|
||||
subject, message)
|
||||
# Spawn thread because we don't want Deluge to lock up while we send the
|
||||
# email.
|
||||
@ -90,11 +90,11 @@ class CoreNotifications(CustomNotifications):
|
||||
continue
|
||||
classdoc = known_events[evt].__doc__.strip()
|
||||
handled_events.append((evt, classdoc))
|
||||
log.debug("Handled Notification Events: %s", handled_events)
|
||||
log.debug('Handled Notification Events: %s', handled_events)
|
||||
return handled_events
|
||||
|
||||
def _notify_email(self, subject='', message=''):
|
||||
log.debug("Email prepared")
|
||||
log.debug('Email prepared')
|
||||
to_addrs = self.config['smtp_recipients']
|
||||
to_addrs_str = ', '.join(self.config['smtp_recipients'])
|
||||
headers_dict = {
|
||||
@ -115,9 +115,9 @@ Date: %(date)s
|
||||
|
||||
try:
|
||||
# Python 2.6
|
||||
server = smtplib.SMTP(self.config["smtp_host"], self.config["smtp_port"], timeout=60)
|
||||
server = smtplib.SMTP(self.config['smtp_host'], self.config['smtp_port'], timeout=60)
|
||||
except Exception as ex:
|
||||
err_msg = _("There was an error sending the notification email: %s") % ex
|
||||
err_msg = _('There was an error sending the notification email: %s') % ex
|
||||
log.error(err_msg)
|
||||
return ex
|
||||
|
||||
@ -126,7 +126,7 @@ Date: %(date)s
|
||||
if security_enabled:
|
||||
server.ehlo()
|
||||
if 'starttls' not in server.esmtp_features:
|
||||
log.warning("TLS/SSL enabled but server does not support it")
|
||||
log.warning('TLS/SSL enabled but server does not support it')
|
||||
else:
|
||||
server.starttls()
|
||||
server.ehlo()
|
||||
@ -136,12 +136,12 @@ Date: %(date)s
|
||||
server.login(self.config['smtp_user'], self.config['smtp_pass'])
|
||||
except smtplib.SMTPHeloError as ex:
|
||||
err_msg = _("The server didn't reply properly to the helo "
|
||||
"greeting: %s") % ex
|
||||
'greeting: %s') % ex
|
||||
log.error(err_msg)
|
||||
return ex
|
||||
except smtplib.SMTPAuthenticationError as ex:
|
||||
err_msg = _("The server didn't accept the username/password "
|
||||
"combination: %s") % ex
|
||||
'combination: %s') % ex
|
||||
log.error(err_msg)
|
||||
return ex
|
||||
|
||||
@ -149,8 +149,8 @@ Date: %(date)s
|
||||
try:
|
||||
server.sendmail(self.config['smtp_from'], to_addrs, message)
|
||||
except smtplib.SMTPException as ex:
|
||||
err_msg = _("There was an error sending the notification email:"
|
||||
" %s") % ex
|
||||
err_msg = _('There was an error sending the notification email:'
|
||||
' %s') % ex
|
||||
log.error(err_msg)
|
||||
return ex
|
||||
finally:
|
||||
@ -164,20 +164,20 @@ Date: %(date)s
|
||||
pass
|
||||
else:
|
||||
server.quit()
|
||||
return _("Notification email sent.")
|
||||
return _('Notification email sent.')
|
||||
|
||||
def _on_torrent_finished_event(self, torrent_id):
|
||||
log.debug("Handler for TorrentFinishedEvent called for CORE")
|
||||
torrent = component.get("TorrentManager")[torrent_id]
|
||||
log.debug('Handler for TorrentFinishedEvent called for CORE')
|
||||
torrent = component.get('TorrentManager')[torrent_id]
|
||||
torrent_status = torrent.get_status({})
|
||||
# Email
|
||||
subject = _("Finished Torrent \"%(name)s\"") % torrent_status
|
||||
message = _(
|
||||
"This email is to inform you that Deluge has finished "
|
||||
'This email is to inform you that Deluge has finished '
|
||||
"downloading \"%(name)s\", which includes %(num_files)i files."
|
||||
"\nTo stop receiving these alerts, simply turn off email "
|
||||
'\nTo stop receiving these alerts, simply turn off email '
|
||||
"notification in Deluge's preferences.\n\n"
|
||||
"Thank you,\nDeluge."
|
||||
'Thank you,\nDeluge.'
|
||||
) % torrent_status
|
||||
return subject, message
|
||||
|
||||
@ -197,23 +197,23 @@ class Core(CorePluginBase, CoreNotifications):
|
||||
def enable(self):
|
||||
CoreNotifications.enable(self)
|
||||
self.config = deluge.configmanager.ConfigManager(
|
||||
"notifications-core.conf", DEFAULT_PREFS)
|
||||
log.debug("ENABLING CORE NOTIFICATIONS")
|
||||
'notifications-core.conf', DEFAULT_PREFS)
|
||||
log.debug('ENABLING CORE NOTIFICATIONS')
|
||||
|
||||
def disable(self):
|
||||
log.debug("DISABLING CORE NOTIFICATIONS")
|
||||
log.debug('DISABLING CORE NOTIFICATIONS')
|
||||
CoreNotifications.disable(self)
|
||||
|
||||
@export
|
||||
def set_config(self, config):
|
||||
"sets the config dictionary"
|
||||
'sets the config dictionary'
|
||||
for key in config.keys():
|
||||
self.config[key] = config[key]
|
||||
self.config.save()
|
||||
|
||||
@export
|
||||
def get_config(self):
|
||||
"returns the config dictionary"
|
||||
'returns the config dictionary'
|
||||
return self.config.config
|
||||
|
||||
@export
|
||||
|
||||
@ -48,20 +48,20 @@ except ImportError:
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
# BLINK
|
||||
"blink_enabled": False,
|
||||
'blink_enabled': False,
|
||||
# FLASH
|
||||
"flash_enabled": False,
|
||||
'flash_enabled': False,
|
||||
# POPUP
|
||||
"popup_enabled": False,
|
||||
'popup_enabled': False,
|
||||
# SOUND
|
||||
"sound_enabled": False,
|
||||
"sound_path": "",
|
||||
"custom_sounds": {},
|
||||
'sound_enabled': False,
|
||||
'sound_path': '',
|
||||
'custom_sounds': {},
|
||||
# Subscriptions
|
||||
"subscriptions": {
|
||||
"popup": [],
|
||||
"blink": [],
|
||||
"sound": [],
|
||||
'subscriptions': {
|
||||
'popup': [],
|
||||
'blink': [],
|
||||
'sound': [],
|
||||
},
|
||||
}
|
||||
|
||||
@ -79,19 +79,19 @@ class GtkUiNotifications(CustomNotifications):
|
||||
def enable(self):
|
||||
CustomNotifications.enable(self)
|
||||
self.register_custom_blink_notification(
|
||||
"TorrentFinishedEvent", self._on_torrent_finished_event_blink
|
||||
'TorrentFinishedEvent', self._on_torrent_finished_event_blink
|
||||
)
|
||||
self.register_custom_sound_notification(
|
||||
"TorrentFinishedEvent", self._on_torrent_finished_event_sound
|
||||
'TorrentFinishedEvent', self._on_torrent_finished_event_sound
|
||||
)
|
||||
self.register_custom_popup_notification(
|
||||
"TorrentFinishedEvent", self._on_torrent_finished_event_popup
|
||||
'TorrentFinishedEvent', self._on_torrent_finished_event_popup
|
||||
)
|
||||
|
||||
def disable(self):
|
||||
self.deregister_custom_blink_notification("TorrentFinishedEvent")
|
||||
self.deregister_custom_sound_notification("TorrentFinishedEvent")
|
||||
self.deregister_custom_popup_notification("TorrentFinishedEvent")
|
||||
self.deregister_custom_blink_notification('TorrentFinishedEvent')
|
||||
self.deregister_custom_sound_notification('TorrentFinishedEvent')
|
||||
self.deregister_custom_popup_notification('TorrentFinishedEvent')
|
||||
CustomNotifications.disable(self)
|
||||
|
||||
def register_custom_popup_notification(self, eventtype, handler):
|
||||
@ -146,7 +146,7 @@ class GtkUiNotifications(CustomNotifications):
|
||||
if result:
|
||||
return defer.maybeDeferred(self.__blink)
|
||||
return defer.succeed("Won't blink. The returned value from the custom "
|
||||
"handler was: %s" % result)
|
||||
'handler was: %s' % result)
|
||||
|
||||
def handle_custom_sound_notification(self, result, eventtype):
|
||||
if isinstance(result, basestring):
|
||||
@ -155,33 +155,33 @@ class GtkUiNotifications(CustomNotifications):
|
||||
self.__play_sound, self.config['custom_sounds'][eventtype])
|
||||
return defer.maybeDeferred(self.__play_sound, result)
|
||||
return defer.succeed("Won't play sound. The returned value from the "
|
||||
"custom handler was: %s" % result)
|
||||
'custom handler was: %s' % result)
|
||||
|
||||
def __blink(self):
|
||||
self.systray.blink(True)
|
||||
return defer.succeed(_("Notification Blink shown"))
|
||||
return defer.succeed(_('Notification Blink shown'))
|
||||
|
||||
def __popup(self, title='', message=''):
|
||||
if not self.config['popup_enabled']:
|
||||
return defer.succeed(_("Popup notification is not enabled."))
|
||||
return defer.succeed(_('Popup notification is not enabled.'))
|
||||
if not POPUP_AVAILABLE:
|
||||
return defer.fail(_("pynotify is not installed"))
|
||||
return defer.fail(_('pynotify is not installed'))
|
||||
|
||||
if pynotify.init("Deluge"):
|
||||
icon = gtk.gdk.pixbuf_new_from_file_at_size(deluge.common.get_pixmap("deluge.svg"), 48, 48)
|
||||
if pynotify.init('Deluge'):
|
||||
icon = gtk.gdk.pixbuf_new_from_file_at_size(deluge.common.get_pixmap('deluge.svg'), 48, 48)
|
||||
self.note = pynotify.Notification(title, message)
|
||||
self.note.set_icon_from_pixbuf(icon)
|
||||
if not self.note.show():
|
||||
err_msg = _("pynotify failed to show notification")
|
||||
err_msg = _('pynotify failed to show notification')
|
||||
log.warning(err_msg)
|
||||
return defer.fail(err_msg)
|
||||
return defer.succeed(_("Notification popup shown"))
|
||||
return defer.succeed(_('Notification popup shown'))
|
||||
|
||||
def __play_sound(self, sound_path=''):
|
||||
if not self.config['sound_enabled']:
|
||||
return defer.succeed(_("Sound notification not enabled"))
|
||||
return defer.succeed(_('Sound notification not enabled'))
|
||||
if not SOUND_AVAILABLE:
|
||||
err_msg = _("pygame is not installed")
|
||||
err_msg = _('pygame is not installed')
|
||||
log.warning(err_msg)
|
||||
return defer.fail(err_msg)
|
||||
|
||||
@ -193,11 +193,11 @@ class GtkUiNotifications(CustomNotifications):
|
||||
alert_sound.load(sound_path)
|
||||
alert_sound.play()
|
||||
except pygame.error as ex:
|
||||
err_msg = _("Sound notification failed %s") % ex
|
||||
err_msg = _('Sound notification failed %s') % ex
|
||||
log.warning(err_msg)
|
||||
return defer.fail(err_msg)
|
||||
else:
|
||||
msg = _("Sound notification Success")
|
||||
msg = _('Sound notification Success')
|
||||
log.info(msg)
|
||||
return defer.succeed(msg)
|
||||
|
||||
@ -209,21 +209,21 @@ class GtkUiNotifications(CustomNotifications):
|
||||
return ''
|
||||
|
||||
def _on_torrent_finished_event_popup(self, torrent_id):
|
||||
d = client.core.get_torrent_status(torrent_id, ["name", "file_progress"])
|
||||
d = client.core.get_torrent_status(torrent_id, ['name', 'file_progress'])
|
||||
d.addCallback(self._on_torrent_finished_event_got_torrent_status)
|
||||
d.addErrback(self._on_torrent_finished_event_torrent_status_failure)
|
||||
return d
|
||||
|
||||
def _on_torrent_finished_event_torrent_status_failure(self, failure):
|
||||
log.debug("Failed to get torrent status to be able to show the popup")
|
||||
log.debug('Failed to get torrent status to be able to show the popup')
|
||||
|
||||
def _on_torrent_finished_event_got_torrent_status(self, torrent_status):
|
||||
log.debug("Handler for TorrentFinishedEvent GTKUI called. "
|
||||
"Got Torrent Status")
|
||||
title = _("Finished Torrent")
|
||||
torrent_status["num_files"] = torrent_status["file_progress"].count(1.0)
|
||||
log.debug('Handler for TorrentFinishedEvent GTKUI called. '
|
||||
'Got Torrent Status')
|
||||
title = _('Finished Torrent')
|
||||
torrent_status['num_files'] = torrent_status['file_progress'].count(1.0)
|
||||
message = _("The torrent \"%(name)s\" including %(num_files)i file(s) "
|
||||
"has finished downloading.") % torrent_status
|
||||
'has finished downloading.') % torrent_status
|
||||
return title, message
|
||||
|
||||
|
||||
@ -234,11 +234,11 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
|
||||
def enable(self):
|
||||
self.config = deluge.configmanager.ConfigManager(
|
||||
"notifications-gtk.conf", DEFAULT_PREFS
|
||||
'notifications-gtk.conf', DEFAULT_PREFS
|
||||
)
|
||||
self.glade = gtk.glade.XML(get_resource("config.glade"))
|
||||
self.glade.get_widget("smtp_port").set_value(25)
|
||||
self.prefs = self.glade.get_widget("prefs_box")
|
||||
self.glade = gtk.glade.XML(get_resource('config.glade'))
|
||||
self.glade.get_widget('smtp_port').set_value(25)
|
||||
self.prefs = self.glade.get_widget('prefs_box')
|
||||
self.prefs.show_all()
|
||||
|
||||
self.build_recipients_model_populate_treeview()
|
||||
@ -261,25 +261,25 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
'on_sound_path_update_preview': self.on_sound_path_update_preview
|
||||
})
|
||||
|
||||
prefs = component.get("Preferences")
|
||||
prefs = component.get('Preferences')
|
||||
parent = self.prefs.get_parent()
|
||||
if parent:
|
||||
parent.remove(self.prefs)
|
||||
index = prefs.notebook.append_page(self.prefs)
|
||||
prefs.liststore.append([index, _("Notifications")])
|
||||
prefs.liststore.append([index, _('Notifications')])
|
||||
|
||||
component.get("PluginManager").register_hook("on_apply_prefs",
|
||||
component.get('PluginManager').register_hook('on_apply_prefs',
|
||||
self.on_apply_prefs)
|
||||
component.get("PluginManager").register_hook("on_show_prefs",
|
||||
component.get('PluginManager').register_hook('on_show_prefs',
|
||||
self.on_show_prefs)
|
||||
|
||||
if not POPUP_AVAILABLE:
|
||||
self.glade.get_widget("popup_enabled").set_property('sensitive',
|
||||
self.glade.get_widget('popup_enabled').set_property('sensitive',
|
||||
False)
|
||||
if not SOUND_AVAILABLE:
|
||||
# for widget_name in ('sound_enabled', 'sound_path', 'sounds_page', 'sounds_page_label'):
|
||||
# self.glade.get_widget(widget_name).set_property('sensitive', False)
|
||||
self.glade.get_widget("sound_enabled").set_property('sensitive',
|
||||
self.glade.get_widget('sound_enabled').set_property('sensitive',
|
||||
False)
|
||||
self.glade.get_widget('sound_path').set_property('sensitive', False)
|
||||
self.glade.get_widget('sounds_page').set_property('sensitive',
|
||||
@ -287,7 +287,7 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
self.glade.get_widget('sounds_page_label').set_property('sensitive',
|
||||
False)
|
||||
|
||||
self.systray = component.get("SystemTray")
|
||||
self.systray = component.get('SystemTray')
|
||||
if not hasattr(self.systray, 'tray'):
|
||||
# Tray is not beeing used
|
||||
self.glade.get_widget('blink_enabled').set_property('sensitive',
|
||||
@ -297,25 +297,25 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
|
||||
def disable(self):
|
||||
GtkUiNotifications.disable(self)
|
||||
component.get("Preferences").remove_page(_("Notifications"))
|
||||
component.get("PluginManager").deregister_hook("on_apply_prefs",
|
||||
component.get('Preferences').remove_page(_('Notifications'))
|
||||
component.get('PluginManager').deregister_hook('on_apply_prefs',
|
||||
self.on_apply_prefs)
|
||||
component.get("PluginManager").deregister_hook("on_show_prefs",
|
||||
component.get('PluginManager').deregister_hook('on_show_prefs',
|
||||
self.on_show_prefs)
|
||||
|
||||
def build_recipients_model_populate_treeview(self):
|
||||
# SMTP Recipients treeview/model
|
||||
self.recipients_treeview = self.glade.get_widget("smtp_recipients")
|
||||
self.recipients_treeview = self.glade.get_widget('smtp_recipients')
|
||||
treeview_selection = self.recipients_treeview.get_selection()
|
||||
treeview_selection.connect(
|
||||
"changed", self.on_recipients_treeview_selection_changed
|
||||
'changed', self.on_recipients_treeview_selection_changed
|
||||
)
|
||||
self.recipients_model = gtk.ListStore(str, bool)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.connect("edited", self.on_cell_edited, self.recipients_model)
|
||||
renderer.set_data("recipient", RECIPIENT_FIELD)
|
||||
column = gtk.TreeViewColumn("Recipients", renderer,
|
||||
renderer.connect('edited', self.on_cell_edited, self.recipients_model)
|
||||
renderer.set_data('recipient', RECIPIENT_FIELD)
|
||||
column = gtk.TreeViewColumn('Recipients', renderer,
|
||||
text=RECIPIENT_FIELD,
|
||||
editable=RECIPIENT_EDIT)
|
||||
column.set_expand(True)
|
||||
@ -327,32 +327,32 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
self.sounds_treeview = self.glade.get_widget('sounds_treeview')
|
||||
sounds_selection = self.sounds_treeview.get_selection()
|
||||
sounds_selection.connect(
|
||||
"changed", self.on_sounds_treeview_selection_changed
|
||||
'changed', self.on_sounds_treeview_selection_changed
|
||||
)
|
||||
|
||||
self.sounds_treeview.set_tooltip_column(SND_EVENT_DOC)
|
||||
self.sounds_model = gtk.ListStore(str, str, str, str)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data("event", SND_EVENT)
|
||||
column = gtk.TreeViewColumn("Event", renderer, text=SND_EVENT)
|
||||
renderer.set_data('event', SND_EVENT)
|
||||
column = gtk.TreeViewColumn('Event', renderer, text=SND_EVENT)
|
||||
column.set_expand(True)
|
||||
self.sounds_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data("event_doc", SND_EVENT_DOC)
|
||||
column = gtk.TreeViewColumn("Doc", renderer, text=SND_EVENT_DOC)
|
||||
renderer.set_data('event_doc', SND_EVENT_DOC)
|
||||
column = gtk.TreeViewColumn('Doc', renderer, text=SND_EVENT_DOC)
|
||||
column.set_property('visible', False)
|
||||
self.sounds_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data("sound_name", SND_NAME)
|
||||
column = gtk.TreeViewColumn("Name", renderer, text=SND_NAME)
|
||||
renderer.set_data('sound_name', SND_NAME)
|
||||
column = gtk.TreeViewColumn('Name', renderer, text=SND_NAME)
|
||||
self.sounds_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data("sound_path", SND_PATH)
|
||||
column = gtk.TreeViewColumn("Path", renderer, text=SND_PATH)
|
||||
renderer.set_data('sound_path', SND_PATH)
|
||||
column = gtk.TreeViewColumn('Path', renderer, text=SND_PATH)
|
||||
column.set_property('visible', False)
|
||||
self.sounds_treeview.append_column(column)
|
||||
|
||||
@ -360,51 +360,51 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
|
||||
def build_notifications_model_populate_treeview(self):
|
||||
# Notification Subscriptions treeview/model
|
||||
self.subscriptions_treeview = self.glade.get_widget("subscriptions_treeview")
|
||||
self.subscriptions_treeview = self.glade.get_widget('subscriptions_treeview')
|
||||
subscriptions_selection = self.subscriptions_treeview.get_selection()
|
||||
subscriptions_selection.connect(
|
||||
"changed", self.on_subscriptions_treeview_selection_changed
|
||||
'changed', self.on_subscriptions_treeview_selection_changed
|
||||
)
|
||||
self.subscriptions_treeview.set_tooltip_column(SUB_EVENT_DOC)
|
||||
self.subscriptions_model = gtk.ListStore(str, str, bool, bool, bool, bool)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data("event", SUB_EVENT)
|
||||
column = gtk.TreeViewColumn("Event", renderer, text=SUB_EVENT)
|
||||
renderer.set_data('event', SUB_EVENT)
|
||||
column = gtk.TreeViewColumn('Event', renderer, text=SUB_EVENT)
|
||||
column.set_expand(True)
|
||||
self.subscriptions_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_data("event_doc", SUB_EVENT)
|
||||
column = gtk.TreeViewColumn("Doc", renderer, text=SUB_EVENT_DOC)
|
||||
renderer.set_data('event_doc', SUB_EVENT)
|
||||
column = gtk.TreeViewColumn('Doc', renderer, text=SUB_EVENT_DOC)
|
||||
column.set_property('visible', False)
|
||||
self.subscriptions_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererToggle()
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self._on_email_col_toggled)
|
||||
column = gtk.TreeViewColumn("Email", renderer, active=SUB_NOT_EMAIL)
|
||||
column = gtk.TreeViewColumn('Email', renderer, active=SUB_NOT_EMAIL)
|
||||
column.set_clickable(True)
|
||||
self.subscriptions_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererToggle()
|
||||
renderer.set_property("activatable", True)
|
||||
renderer.connect("toggled", self._on_popup_col_toggled)
|
||||
column = gtk.TreeViewColumn("Popup", renderer, active=SUB_NOT_POPUP)
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self._on_popup_col_toggled)
|
||||
column = gtk.TreeViewColumn('Popup', renderer, active=SUB_NOT_POPUP)
|
||||
column.set_clickable(True)
|
||||
self.subscriptions_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererToggle()
|
||||
renderer.set_property("activatable", True)
|
||||
renderer.connect("toggled", self._on_blink_col_toggled)
|
||||
column = gtk.TreeViewColumn("Blink", renderer, active=SUB_NOT_BLINK)
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self._on_blink_col_toggled)
|
||||
column = gtk.TreeViewColumn('Blink', renderer, active=SUB_NOT_BLINK)
|
||||
column.set_clickable(True)
|
||||
self.subscriptions_treeview.append_column(column)
|
||||
|
||||
renderer = gtk.CellRendererToggle()
|
||||
renderer.set_property('activatable', True)
|
||||
renderer.connect('toggled', self._on_sound_col_toggled)
|
||||
column = gtk.TreeViewColumn("Sound", renderer, active=SUB_NOT_SOUND)
|
||||
column = gtk.TreeViewColumn('Sound', renderer, active=SUB_NOT_SOUND)
|
||||
column.set_clickable(True)
|
||||
self.subscriptions_treeview.append_column(column)
|
||||
self.subscriptions_treeview.set_model(self.subscriptions_model)
|
||||
@ -444,13 +444,13 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
SUB_EVENT, event_name,
|
||||
SUB_EVENT_DOC, event_doc,
|
||||
SUB_NOT_EMAIL, event_name in email_subscriptions,
|
||||
SUB_NOT_POPUP, event_name in subscriptions_dict["popup"],
|
||||
SUB_NOT_POPUP, event_name in subscriptions_dict['popup'],
|
||||
SUB_NOT_BLINK, event_name in subscriptions_dict['blink'],
|
||||
SUB_NOT_SOUND, event_name in subscriptions_dict['sound']
|
||||
)
|
||||
|
||||
def on_apply_prefs(self):
|
||||
log.debug("applying prefs for Notifications")
|
||||
log.debug('applying prefs for Notifications')
|
||||
|
||||
current_popup_subscriptions = []
|
||||
current_blink_subscriptions = []
|
||||
@ -467,8 +467,8 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
current_sound_subscriptions.append(event)
|
||||
|
||||
old_sound_file = self.config['sound_path']
|
||||
new_sound_file = self.glade.get_widget("sound_path").get_filename()
|
||||
log.debug("Old Default sound file: %s New one: %s",
|
||||
new_sound_file = self.glade.get_widget('sound_path').get_filename()
|
||||
log.debug('Old Default sound file: %s New one: %s',
|
||||
old_sound_file, new_sound_file)
|
||||
custom_sounds = {}
|
||||
for event_name, event_doc, filename, filepath in self.sounds_model:
|
||||
@ -478,30 +478,30 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
custom_sounds[event_name] = filepath
|
||||
|
||||
self.config.config.update({
|
||||
"popup_enabled": self.glade.get_widget("popup_enabled").get_active(),
|
||||
"blink_enabled": self.glade.get_widget("blink_enabled").get_active(),
|
||||
"sound_enabled": self.glade.get_widget("sound_enabled").get_active(),
|
||||
"sound_path": new_sound_file,
|
||||
"subscriptions": {
|
||||
"popup": current_popup_subscriptions,
|
||||
"blink": current_blink_subscriptions,
|
||||
"sound": current_sound_subscriptions
|
||||
'popup_enabled': self.glade.get_widget('popup_enabled').get_active(),
|
||||
'blink_enabled': self.glade.get_widget('blink_enabled').get_active(),
|
||||
'sound_enabled': self.glade.get_widget('sound_enabled').get_active(),
|
||||
'sound_path': new_sound_file,
|
||||
'subscriptions': {
|
||||
'popup': current_popup_subscriptions,
|
||||
'blink': current_blink_subscriptions,
|
||||
'sound': current_sound_subscriptions
|
||||
},
|
||||
"custom_sounds": custom_sounds
|
||||
'custom_sounds': custom_sounds
|
||||
})
|
||||
self.config.save()
|
||||
|
||||
core_config = {
|
||||
"smtp_enabled": self.glade.get_widget("smtp_enabled").get_active(),
|
||||
"smtp_host": self.glade.get_widget("smtp_host").get_text(),
|
||||
"smtp_port": self.glade.get_widget("smtp_port").get_value(),
|
||||
"smtp_user": self.glade.get_widget("smtp_user").get_text(),
|
||||
"smtp_pass": self.glade.get_widget("smtp_pass").get_text(),
|
||||
"smtp_from": self.glade.get_widget("smtp_from").get_text(),
|
||||
"smtp_tls": self.glade.get_widget("smtp_tls").get_active(),
|
||||
"smtp_recipients": [dest[0] for dest in self.recipients_model if
|
||||
dest[0] != "USER@HOST"],
|
||||
"subscriptions": {"email": current_email_subscriptions}
|
||||
'smtp_enabled': self.glade.get_widget('smtp_enabled').get_active(),
|
||||
'smtp_host': self.glade.get_widget('smtp_host').get_text(),
|
||||
'smtp_port': self.glade.get_widget('smtp_port').get_value(),
|
||||
'smtp_user': self.glade.get_widget('smtp_user').get_text(),
|
||||
'smtp_pass': self.glade.get_widget('smtp_pass').get_text(),
|
||||
'smtp_from': self.glade.get_widget('smtp_from').get_text(),
|
||||
'smtp_tls': self.glade.get_widget('smtp_tls').get_active(),
|
||||
'smtp_recipients': [dest[0] for dest in self.recipients_model if
|
||||
dest[0] != 'USER@HOST'],
|
||||
'subscriptions': {'email': current_email_subscriptions}
|
||||
}
|
||||
|
||||
client.notifications.set_config(core_config)
|
||||
@ -511,37 +511,37 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
client.notifications.get_config().addCallback(self.cb_get_config)
|
||||
|
||||
def cb_get_config(self, core_config):
|
||||
"callback for on show_prefs"
|
||||
self.glade.get_widget("smtp_host").set_text(core_config["smtp_host"])
|
||||
self.glade.get_widget("smtp_port").set_value(core_config["smtp_port"])
|
||||
self.glade.get_widget("smtp_user").set_text(core_config["smtp_user"])
|
||||
self.glade.get_widget("smtp_pass").set_text(core_config["smtp_pass"])
|
||||
self.glade.get_widget("smtp_from").set_text(core_config["smtp_from"])
|
||||
self.glade.get_widget("smtp_tls").set_active(core_config["smtp_tls"])
|
||||
'callback for on show_prefs'
|
||||
self.glade.get_widget('smtp_host').set_text(core_config['smtp_host'])
|
||||
self.glade.get_widget('smtp_port').set_value(core_config['smtp_port'])
|
||||
self.glade.get_widget('smtp_user').set_text(core_config['smtp_user'])
|
||||
self.glade.get_widget('smtp_pass').set_text(core_config['smtp_pass'])
|
||||
self.glade.get_widget('smtp_from').set_text(core_config['smtp_from'])
|
||||
self.glade.get_widget('smtp_tls').set_active(core_config['smtp_tls'])
|
||||
self.recipients_model.clear()
|
||||
for recipient in core_config['smtp_recipients']:
|
||||
self.recipients_model.set(self.recipients_model.append(),
|
||||
RECIPIENT_FIELD, recipient,
|
||||
RECIPIENT_EDIT, False)
|
||||
self.glade.get_widget("smtp_enabled").set_active(
|
||||
self.glade.get_widget('smtp_enabled').set_active(
|
||||
core_config['smtp_enabled']
|
||||
)
|
||||
self.glade.get_widget("sound_enabled").set_active(
|
||||
self.glade.get_widget('sound_enabled').set_active(
|
||||
self.config['sound_enabled']
|
||||
)
|
||||
self.glade.get_widget("popup_enabled").set_active(
|
||||
self.glade.get_widget('popup_enabled').set_active(
|
||||
self.config['popup_enabled']
|
||||
)
|
||||
self.glade.get_widget("blink_enabled").set_active(
|
||||
self.glade.get_widget('blink_enabled').set_active(
|
||||
self.config['blink_enabled']
|
||||
)
|
||||
if self.config['sound_path']:
|
||||
sound_path = self.config['sound_path']
|
||||
else:
|
||||
sound_path = deluge.common.get_default_download_dir()
|
||||
self.glade.get_widget("sound_path").set_filename(sound_path)
|
||||
self.glade.get_widget('sound_path').set_filename(sound_path)
|
||||
# Force toggle
|
||||
self.on_enabled_toggled(self.glade.get_widget("smtp_enabled"))
|
||||
self.on_enabled_toggled(self.glade.get_widget('smtp_enabled'))
|
||||
self.on_sound_enabled_toggled(self.glade.get_widget('sound_enabled'))
|
||||
|
||||
client.notifications.get_handled_events().addCallback(
|
||||
@ -557,7 +557,7 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
def on_add_button_clicked(self, widget, treeview):
|
||||
model = treeview.get_model()
|
||||
model.set(model.append(),
|
||||
RECIPIENT_FIELD, "USER@HOST",
|
||||
RECIPIENT_FIELD, 'USER@HOST',
|
||||
RECIPIENT_EDIT, True)
|
||||
|
||||
def on_delete_button_clicked(self, widget, treeview):
|
||||
@ -573,53 +573,53 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
def on_recipients_treeview_selection_changed(self, selection):
|
||||
model, selected_connection_iter = selection.get_selected()
|
||||
if selected_connection_iter:
|
||||
self.glade.get_widget("delete_button").set_property('sensitive',
|
||||
self.glade.get_widget('delete_button').set_property('sensitive',
|
||||
True)
|
||||
else:
|
||||
self.glade.get_widget("delete_button").set_property('sensitive',
|
||||
self.glade.get_widget('delete_button').set_property('sensitive',
|
||||
False)
|
||||
|
||||
def on_subscriptions_treeview_selection_changed(self, selection):
|
||||
model, selected_connection_iter = selection.get_selected()
|
||||
if selected_connection_iter:
|
||||
self.glade.get_widget("delete_button").set_property('sensitive',
|
||||
self.glade.get_widget('delete_button').set_property('sensitive',
|
||||
True)
|
||||
else:
|
||||
self.glade.get_widget("delete_button").set_property('sensitive',
|
||||
self.glade.get_widget('delete_button').set_property('sensitive',
|
||||
False)
|
||||
|
||||
def on_sounds_treeview_selection_changed(self, selection):
|
||||
model, selected_iter = selection.get_selected()
|
||||
if selected_iter:
|
||||
self.glade.get_widget("sounds_edit_button").set_property("sensitive", True)
|
||||
self.glade.get_widget('sounds_edit_button').set_property('sensitive', True)
|
||||
path = model.get(selected_iter, SND_PATH)[0]
|
||||
log.debug("Sound selection changed: %s", path)
|
||||
log.debug('Sound selection changed: %s', path)
|
||||
if path != self.config['sound_path']:
|
||||
self.glade.get_widget("sounds_revert_button").set_property("sensitive", True)
|
||||
self.glade.get_widget('sounds_revert_button').set_property('sensitive', True)
|
||||
else:
|
||||
self.glade.get_widget("sounds_revert_button").set_property("sensitive", False)
|
||||
self.glade.get_widget('sounds_revert_button').set_property('sensitive', False)
|
||||
else:
|
||||
self.glade.get_widget("sounds_edit_button").set_property("sensitive", False)
|
||||
self.glade.get_widget("sounds_revert_button").set_property("sensitive", False)
|
||||
self.glade.get_widget('sounds_edit_button').set_property('sensitive', False)
|
||||
self.glade.get_widget('sounds_revert_button').set_property('sensitive', False)
|
||||
|
||||
def on_sounds_revert_button_clicked(self, widget):
|
||||
log.debug("on_sounds_revert_button_clicked")
|
||||
log.debug('on_sounds_revert_button_clicked')
|
||||
selection = self.sounds_treeview.get_selection()
|
||||
model, selected_iter = selection.get_selected()
|
||||
if selected_iter:
|
||||
log.debug("on_sounds_revert_button_clicked: got iter")
|
||||
log.debug('on_sounds_revert_button_clicked: got iter')
|
||||
model.set(selected_iter,
|
||||
SND_PATH, self.config['sound_path'],
|
||||
SND_NAME, basename(self.config['sound_path']))
|
||||
|
||||
def on_sounds_edit_button_clicked(self, widget):
|
||||
log.debug("on_sounds_edit_button_clicked")
|
||||
log.debug('on_sounds_edit_button_clicked')
|
||||
selection = self.sounds_treeview.get_selection()
|
||||
model, selected_iter = selection.get_selected()
|
||||
if selected_iter:
|
||||
path = model.get(selected_iter, SND_PATH)[0]
|
||||
dialog = gtk.FileChooserDialog(
|
||||
title=_("Choose Sound File"),
|
||||
title=_('Choose Sound File'),
|
||||
buttons=(gtk.STOCK_CANCEL,
|
||||
gtk.RESPONSE_CANCEL,
|
||||
gtk.STOCK_OPEN,
|
||||
@ -638,7 +638,7 @@ class GtkUI(GtkPluginBase, GtkUiNotifications):
|
||||
d = defer.maybeDeferred(dialog.run)
|
||||
d.addCallback(update_model)
|
||||
|
||||
log.debug("dialog should have been shown")
|
||||
log.debug('dialog should have been shown')
|
||||
|
||||
def on_enabled_toggled(self, widget):
|
||||
for widget_name in ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass',
|
||||
|
||||
@ -37,16 +37,16 @@ class TestEmailNotifications(component.Component):
|
||||
self.events_classes = []
|
||||
|
||||
def enable(self):
|
||||
log.debug("\n\nEnabling %s", self.__class__.__name__)
|
||||
log.debug('\n\nEnabling %s', self.__class__.__name__)
|
||||
for event in self.events:
|
||||
if self.__imp == 'core':
|
||||
# component.get("CorePlugin.Notifications").register_custom_email_notification(
|
||||
component.get("Notifications").register_custom_email_notification(
|
||||
component.get('Notifications').register_custom_email_notification(
|
||||
event.__class__.__name__,
|
||||
self.custom_email_message_provider
|
||||
)
|
||||
elif self.__imp == 'gtk':
|
||||
notifications_component = component.get("Notifications")
|
||||
notifications_component = component.get('Notifications')
|
||||
notifications_component.register_custom_popup_notification(
|
||||
event.__class__.__name__,
|
||||
self.custom_popup_message_provider
|
||||
@ -63,32 +63,32 @@ class TestEmailNotifications(component.Component):
|
||||
self.lc.start(60, False)
|
||||
|
||||
def disable(self):
|
||||
log.debug("\n\nDisabling %s", self.__class__.__name__)
|
||||
log.debug('\n\nDisabling %s', self.__class__.__name__)
|
||||
self.lc.stop()
|
||||
|
||||
def update(self):
|
||||
if self.__imp == 'core':
|
||||
log.debug("\n\nUpdating %s", self.__class__.__name__)
|
||||
log.debug('\n\nUpdating %s', self.__class__.__name__)
|
||||
self.events.append(self.events.pop(0)) # Re-Queue
|
||||
self.n += 1
|
||||
component.get("EventManager").emit(self.events[0])
|
||||
component.get('EventManager').emit(self.events[0])
|
||||
|
||||
def custom_email_message_provider(self, *evt_args, **evt_kwargs):
|
||||
log.debug("Running custom email message provider: %s %s", evt_args, evt_kwargs)
|
||||
subject = "%s Email Subject: %s" % (self.events[0].__class__.__name__, self.n)
|
||||
message = "%s Email Message: %s" % (self.events[0].__class__.__name__, self.n)
|
||||
log.debug('Running custom email message provider: %s %s', evt_args, evt_kwargs)
|
||||
subject = '%s Email Subject: %s' % (self.events[0].__class__.__name__, self.n)
|
||||
message = '%s Email Message: %s' % (self.events[0].__class__.__name__, self.n)
|
||||
return subject, message
|
||||
|
||||
def custom_popup_message_provider(self, *evt_args, **evt_kwargs):
|
||||
log.debug("Running custom popup message provider: %s %s", evt_args, evt_kwargs)
|
||||
title = "%s Popup Title: %s" % (self.events[0].__class__.__name__, self.n)
|
||||
message = "%s Popup Message: %s" % (self.events[0].__class__.__name__, self.n)
|
||||
log.debug('Running custom popup message provider: %s %s', evt_args, evt_kwargs)
|
||||
title = '%s Popup Title: %s' % (self.events[0].__class__.__name__, self.n)
|
||||
message = '%s Popup Message: %s' % (self.events[0].__class__.__name__, self.n)
|
||||
return title, message
|
||||
|
||||
def custom_blink_message_provider(self, *evt_args, **evt_kwargs):
|
||||
log.debug("Running custom blink message provider: %s %s", evt_args, evt_kwargs)
|
||||
log.debug('Running custom blink message provider: %s %s', evt_args, evt_kwargs)
|
||||
return True
|
||||
|
||||
def custom_sound_message_provider(self, *evt_args, **evt_kwargs):
|
||||
log.debug("Running custom sound message provider: %s %s", evt_args, evt_kwargs)
|
||||
log.debug('Running custom sound message provider: %s %s', evt_args, evt_kwargs)
|
||||
return ''
|
||||
|
||||
@ -23,11 +23,11 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("notifications.js")]
|
||||
scripts = [get_resource('notifications.js')]
|
||||
debug_scripts = scripts
|
||||
|
||||
def enable(self):
|
||||
log.debug("Enabling Web UI notifications")
|
||||
log.debug('Enabling Web UI notifications')
|
||||
|
||||
def disable(self):
|
||||
log.debug("Disabling Web UI notifications")
|
||||
log.debug('Disabling Web UI notifications')
|
||||
|
||||
@ -14,13 +14,13 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Notifications"
|
||||
__author__ = "Pedro Algarvio"
|
||||
__author_email__ = "pedro@algarvio.me"
|
||||
__version__ = "0.2"
|
||||
__url__ = "http://dev.deluge-torrent.org/"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Plugin which provides notifications to Deluge."
|
||||
__plugin_name__ = 'Notifications'
|
||||
__author__ = 'Pedro Algarvio'
|
||||
__author_email__ = 'pedro@algarvio.me'
|
||||
__version__ = '0.2'
|
||||
__url__ = 'http://dev.deluge-torrent.org/'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Plugin which provides notifications to Deluge.'
|
||||
__long_description__ = """
|
||||
Plugin which provides notifications to Deluge
|
||||
|
||||
@ -29,7 +29,7 @@ Email, Popup, Blink and Sound notifications
|
||||
The plugin also allows other plugins to make
|
||||
use of itself for their own custom notifications
|
||||
"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -42,7 +42,7 @@ setup(
|
||||
long_description=__long_description__ if __long_description__ else __description__,
|
||||
|
||||
packages=find_packages(exclude=['**/test.py']),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -15,4 +15,4 @@
|
||||
def get_resource(filename):
|
||||
import os
|
||||
import pkg_resources
|
||||
return pkg_resources.resource_filename("deluge.plugins.scheduler", os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.scheduler', os.path.join('data', filename))
|
||||
|
||||
@ -25,26 +25,26 @@ from deluge.plugins.pluginbase import CorePluginBase
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"low_down": -1.0,
|
||||
"low_up": -1.0,
|
||||
"low_active": -1,
|
||||
"low_active_down": -1,
|
||||
"low_active_up": -1,
|
||||
"button_state": [[0] * 7 for dummy in xrange(24)]
|
||||
'low_down': -1.0,
|
||||
'low_up': -1.0,
|
||||
'low_active': -1,
|
||||
'low_active_down': -1,
|
||||
'low_active_up': -1,
|
||||
'button_state': [[0] * 7 for dummy in xrange(24)]
|
||||
}
|
||||
|
||||
STATES = {
|
||||
0: "Green",
|
||||
1: "Yellow",
|
||||
2: "Red"
|
||||
0: 'Green',
|
||||
1: 'Yellow',
|
||||
2: 'Red'
|
||||
}
|
||||
|
||||
CONTROLLED_SETTINGS = [
|
||||
"max_download_speed",
|
||||
"max_upload_speed",
|
||||
"max_active_limit",
|
||||
"max_active_downloading",
|
||||
"max_active_seeding"
|
||||
'max_download_speed',
|
||||
'max_upload_speed',
|
||||
'max_active_limit',
|
||||
'max_active_downloading',
|
||||
'max_active_seeding'
|
||||
]
|
||||
|
||||
|
||||
@ -62,14 +62,14 @@ class SchedulerEvent(DelugeEvent):
|
||||
class Core(CorePluginBase):
|
||||
def enable(self):
|
||||
# Create the defaults with the core config
|
||||
core_config = component.get("Core").config
|
||||
DEFAULT_PREFS["low_down"] = core_config["max_download_speed"]
|
||||
DEFAULT_PREFS["low_up"] = core_config["max_upload_speed"]
|
||||
DEFAULT_PREFS["low_active"] = core_config["max_active_limit"]
|
||||
DEFAULT_PREFS["low_active_down"] = core_config["max_active_downloading"]
|
||||
DEFAULT_PREFS["low_active_up"] = core_config["max_active_seeding"]
|
||||
core_config = component.get('Core').config
|
||||
DEFAULT_PREFS['low_down'] = core_config['max_download_speed']
|
||||
DEFAULT_PREFS['low_up'] = core_config['max_upload_speed']
|
||||
DEFAULT_PREFS['low_active'] = core_config['max_active_limit']
|
||||
DEFAULT_PREFS['low_active_down'] = core_config['max_active_downloading']
|
||||
DEFAULT_PREFS['low_active_up'] = core_config['max_active_seeding']
|
||||
|
||||
self.config = deluge.configmanager.ConfigManager("scheduler.conf", DEFAULT_PREFS)
|
||||
self.config = deluge.configmanager.ConfigManager('scheduler.conf', DEFAULT_PREFS)
|
||||
|
||||
self.state = self.get_state()
|
||||
|
||||
@ -82,12 +82,12 @@ class Core(CorePluginBase):
|
||||
self.timer = reactor.callLater(secs_to_next_hour, self.do_schedule)
|
||||
|
||||
# Register for config changes so state isn't overridden
|
||||
component.get("EventManager").register_event_handler("ConfigValueChangedEvent", self.on_config_value_changed)
|
||||
component.get('EventManager').register_event_handler('ConfigValueChangedEvent', self.on_config_value_changed)
|
||||
|
||||
def disable(self):
|
||||
if self.timer.active():
|
||||
self.timer.cancel()
|
||||
component.get("EventManager").deregister_event_handler("ConfigValueChangedEvent", self.on_config_value_changed)
|
||||
component.get('EventManager').deregister_event_handler('ConfigValueChangedEvent', self.on_config_value_changed)
|
||||
self.__apply_set_functions()
|
||||
|
||||
def update(self):
|
||||
@ -101,11 +101,11 @@ class Core(CorePluginBase):
|
||||
"""
|
||||
Have the core apply it's bandwidth settings as specified in core.conf.
|
||||
"""
|
||||
core_config = deluge.configmanager.ConfigManager("core.conf")
|
||||
core_config = deluge.configmanager.ConfigManager('core.conf')
|
||||
for setting in CONTROLLED_SETTINGS:
|
||||
component.get("PreferencesManager").do_config_set_func(setting, core_config[setting])
|
||||
component.get('PreferencesManager').do_config_set_func(setting, core_config[setting])
|
||||
# Resume the session if necessary
|
||||
component.get("Core").resume_session()
|
||||
component.get('Core').resume_session()
|
||||
|
||||
def do_schedule(self, timer=True):
|
||||
"""
|
||||
@ -114,30 +114,30 @@ class Core(CorePluginBase):
|
||||
|
||||
state = self.get_state()
|
||||
|
||||
if state == "Green":
|
||||
if state == 'Green':
|
||||
# This is Green (Normal) so we just make sure we've applied the
|
||||
# global defaults
|
||||
self.__apply_set_functions()
|
||||
elif state == "Yellow":
|
||||
elif state == 'Yellow':
|
||||
# This is Yellow (Slow), so use the settings provided from the user
|
||||
settings = {
|
||||
"active_limit": self.config["low_active"],
|
||||
"active_downloads": self.config["low_active_down"],
|
||||
"active_seeds": self.config["low_active_up"],
|
||||
"download_rate_limit": int(self.config["low_down"] * 1024),
|
||||
"upload_rate_limit": int(self.config["low_up"] * 1024)
|
||||
'active_limit': self.config['low_active'],
|
||||
'active_downloads': self.config['low_active_down'],
|
||||
'active_seeds': self.config['low_active_up'],
|
||||
'download_rate_limit': int(self.config['low_down'] * 1024),
|
||||
'upload_rate_limit': int(self.config['low_up'] * 1024)
|
||||
}
|
||||
component.get("Core").apply_session_settings(settings)
|
||||
component.get('Core').apply_session_settings(settings)
|
||||
# Resume the session if necessary
|
||||
component.get("Core").resume_session()
|
||||
elif state == "Red":
|
||||
component.get('Core').resume_session()
|
||||
elif state == 'Red':
|
||||
# This is Red (Stop), so pause the libtorrent session
|
||||
component.get("Core").pause_session()
|
||||
component.get('Core').pause_session()
|
||||
|
||||
if state != self.state:
|
||||
# The state has changed since last update so we need to emit an event
|
||||
self.state = state
|
||||
component.get("EventManager").emit(SchedulerEvent(self.state))
|
||||
component.get('EventManager').emit(SchedulerEvent(self.state))
|
||||
|
||||
if timer:
|
||||
# Call this again in 1 hour
|
||||
@ -145,7 +145,7 @@ class Core(CorePluginBase):
|
||||
|
||||
@export()
|
||||
def set_config(self, config):
|
||||
"sets the config dictionary"
|
||||
'sets the config dictionary'
|
||||
for key in config.keys():
|
||||
self.config[key] = config[key]
|
||||
self.config.save()
|
||||
@ -153,11 +153,11 @@ class Core(CorePluginBase):
|
||||
|
||||
@export()
|
||||
def get_config(self):
|
||||
"returns the config dictionary"
|
||||
'returns the config dictionary'
|
||||
return self.config.config
|
||||
|
||||
@export()
|
||||
def get_state(self):
|
||||
now = time.localtime(time.time())
|
||||
level = self.config["button_state"][now[3]][now[6]]
|
||||
level = self.config['button_state'][now[3]][now[6]]
|
||||
return STATES[level]
|
||||
|
||||
@ -25,7 +25,7 @@ from .common import get_resource
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
||||
DAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
|
||||
|
||||
class SchedulerSelectWidget(gtk.DrawingArea):
|
||||
@ -34,11 +34,11 @@ class SchedulerSelectWidget(gtk.DrawingArea):
|
||||
self.set_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK |
|
||||
gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.LEAVE_NOTIFY_MASK)
|
||||
|
||||
self.connect("expose_event", self.expose)
|
||||
self.connect("button_press_event", self.mouse_down)
|
||||
self.connect("button_release_event", self.mouse_up)
|
||||
self.connect("motion_notify_event", self.mouse_hover)
|
||||
self.connect("leave_notify_event", self.mouse_leave)
|
||||
self.connect('expose_event', self.expose)
|
||||
self.connect('button_press_event', self.mouse_down)
|
||||
self.connect('button_release_event', self.mouse_up)
|
||||
self.connect('motion_notify_event', self.mouse_hover)
|
||||
self.connect('leave_notify_event', self.mouse_leave)
|
||||
|
||||
self.colors = [[115 / 255, 210 / 255, 22 / 255],
|
||||
[237 / 255, 212 / 255, 0 / 255],
|
||||
@ -124,8 +124,8 @@ class SchedulerSelectWidget(gtk.DrawingArea):
|
||||
self.hover_point = self.get_point(event)
|
||||
|
||||
self.hover_label.set_text(self.hover_days[self.hover_point[1]] +
|
||||
" " + str(self.hover_point[0]) +
|
||||
":00 - " + str(self.hover_point[0]) + ":59")
|
||||
' ' + str(self.hover_point[0]) +
|
||||
':00 - ' + str(self.hover_point[0]) + ':59')
|
||||
|
||||
if self.mouse_press:
|
||||
points = [[self.hover_point[0], self.start_point[0]], [self.hover_point[1], self.start_point[1]]]
|
||||
@ -138,7 +138,7 @@ class SchedulerSelectWidget(gtk.DrawingArea):
|
||||
|
||||
# clear hover text on mouse leave
|
||||
def mouse_leave(self, widget, event):
|
||||
self.hover_label.set_text("")
|
||||
self.hover_label.set_text('')
|
||||
self.hover_point = [-1, -1]
|
||||
|
||||
|
||||
@ -146,63 +146,63 @@ class GtkUI(GtkPluginBase):
|
||||
def enable(self):
|
||||
self.create_prefs_page()
|
||||
|
||||
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
|
||||
self.statusbar = component.get("StatusBar")
|
||||
component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
|
||||
self.statusbar = component.get('StatusBar')
|
||||
self.status_item = self.statusbar.add_item(
|
||||
image=get_resource("green.png"),
|
||||
text="",
|
||||
image=get_resource('green.png'),
|
||||
text='',
|
||||
callback=self.on_status_item_clicked,
|
||||
tooltip="Scheduler")
|
||||
tooltip='Scheduler')
|
||||
|
||||
def on_state_deferred(state):
|
||||
self.state = state
|
||||
self.on_scheduler_event(state)
|
||||
client.scheduler.get_state().addCallback(on_state_deferred)
|
||||
client.register_event_handler("SchedulerEvent", self.on_scheduler_event)
|
||||
client.register_event_handler('SchedulerEvent', self.on_scheduler_event)
|
||||
|
||||
def disable(self):
|
||||
component.get("Preferences").remove_page(_("Scheduler"))
|
||||
component.get('Preferences').remove_page(_('Scheduler'))
|
||||
# Reset statusbar dict.
|
||||
self.statusbar.config_value_changed_dict["max_download_speed"] = self.statusbar._on_max_download_speed
|
||||
self.statusbar.config_value_changed_dict["max_upload_speed"] = self.statusbar._on_max_upload_speed
|
||||
self.statusbar.config_value_changed_dict['max_download_speed'] = self.statusbar._on_max_download_speed
|
||||
self.statusbar.config_value_changed_dict['max_upload_speed'] = self.statusbar._on_max_upload_speed
|
||||
# Remove statusbar item.
|
||||
self.statusbar.remove_item(self.status_item)
|
||||
del self.status_item
|
||||
|
||||
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
|
||||
|
||||
def on_apply_prefs(self):
|
||||
log.debug("applying prefs for Scheduler")
|
||||
log.debug('applying prefs for Scheduler')
|
||||
config = {}
|
||||
config["low_down"] = self.spin_download.get_value()
|
||||
config["low_up"] = self.spin_upload.get_value()
|
||||
config["low_active"] = self.spin_active.get_value_as_int()
|
||||
config["low_active_down"] = self.spin_active_down.get_value_as_int()
|
||||
config["low_active_up"] = self.spin_active_up.get_value_as_int()
|
||||
config["button_state"] = self.scheduler_select.button_state
|
||||
config['low_down'] = self.spin_download.get_value()
|
||||
config['low_up'] = self.spin_upload.get_value()
|
||||
config['low_active'] = self.spin_active.get_value_as_int()
|
||||
config['low_active_down'] = self.spin_active_down.get_value_as_int()
|
||||
config['low_active_up'] = self.spin_active_up.get_value_as_int()
|
||||
config['button_state'] = self.scheduler_select.button_state
|
||||
client.scheduler.set_config(config)
|
||||
|
||||
def on_show_prefs(self):
|
||||
def on_get_config(config):
|
||||
log.debug("config: %s", config)
|
||||
self.scheduler_select.set_button_state(config["button_state"])
|
||||
self.spin_download.set_value(config["low_down"])
|
||||
self.spin_upload.set_value(config["low_up"])
|
||||
self.spin_active.set_value(config["low_active"])
|
||||
self.spin_active_down.set_value(config["low_active_down"])
|
||||
self.spin_active_up.set_value(config["low_active_up"])
|
||||
log.debug('config: %s', config)
|
||||
self.scheduler_select.set_button_state(config['button_state'])
|
||||
self.spin_download.set_value(config['low_down'])
|
||||
self.spin_upload.set_value(config['low_up'])
|
||||
self.spin_active.set_value(config['low_active'])
|
||||
self.spin_active_down.set_value(config['low_active_down'])
|
||||
self.spin_active_up.set_value(config['low_active_up'])
|
||||
|
||||
client.scheduler.get_config().addCallback(on_get_config)
|
||||
|
||||
def on_scheduler_event(self, state):
|
||||
self.state = state
|
||||
self.status_item.set_image_from_file(get_resource(self.state.lower() + ".png"))
|
||||
if self.state == "Yellow":
|
||||
self.status_item.set_image_from_file(get_resource(self.state.lower() + '.png'))
|
||||
if self.state == 'Yellow':
|
||||
# Prevent func calls in Statusbar if the config changes.
|
||||
self.statusbar.config_value_changed_dict.pop("max_download_speed", None)
|
||||
self.statusbar.config_value_changed_dict.pop("max_upload_speed", None)
|
||||
self.statusbar.config_value_changed_dict.pop('max_download_speed', None)
|
||||
self.statusbar.config_value_changed_dict.pop('max_upload_speed', None)
|
||||
try:
|
||||
self.statusbar._on_max_download_speed(self.spin_download.get_value())
|
||||
self.statusbar._on_max_upload_speed(self.spin_upload.get_value())
|
||||
@ -210,20 +210,20 @@ class GtkUI(GtkPluginBase):
|
||||
# Skip error due to Plugin being enabled before statusbar items created on startup.
|
||||
pass
|
||||
else:
|
||||
self.statusbar.config_value_changed_dict["max_download_speed"] = self.statusbar._on_max_download_speed
|
||||
self.statusbar.config_value_changed_dict["max_upload_speed"] = self.statusbar._on_max_upload_speed
|
||||
self.statusbar.config_value_changed_dict['max_download_speed'] = self.statusbar._on_max_download_speed
|
||||
self.statusbar.config_value_changed_dict['max_upload_speed'] = self.statusbar._on_max_upload_speed
|
||||
|
||||
def update_config_values(config):
|
||||
try:
|
||||
self.statusbar._on_max_download_speed(config["max_download_speed"])
|
||||
self.statusbar._on_max_upload_speed(config["max_upload_speed"])
|
||||
self.statusbar._on_max_download_speed(config['max_download_speed'])
|
||||
self.statusbar._on_max_upload_speed(config['max_upload_speed'])
|
||||
except AttributeError:
|
||||
# Skip error due to Plugin being enabled before statusbar items created on startup.
|
||||
pass
|
||||
client.core.get_config_values(["max_download_speed", "max_upload_speed"]).addCallback(update_config_values)
|
||||
client.core.get_config_values(['max_download_speed', 'max_upload_speed']).addCallback(update_config_values)
|
||||
|
||||
def on_status_item_clicked(self, widget, event):
|
||||
component.get("Preferences").show("Scheduler")
|
||||
component.get('Preferences').show('Scheduler')
|
||||
|
||||
# Configuration dialog
|
||||
def create_prefs_page(self):
|
||||
@ -240,7 +240,7 @@ class GtkUI(GtkPluginBase):
|
||||
hbox.pack_start(self.scheduler_select, True, True)
|
||||
frame = gtk.Frame()
|
||||
label = gtk.Label()
|
||||
label.set_markup("<b>Schedule</b>")
|
||||
label.set_markup('<b>Schedule</b>')
|
||||
frame.set_label_widget(label)
|
||||
frame.set_shadow_type(gtk.SHADOW_NONE)
|
||||
frame.add(hbox)
|
||||
@ -250,7 +250,7 @@ class GtkUI(GtkPluginBase):
|
||||
|
||||
table = gtk.Table(3, 4)
|
||||
|
||||
label = gtk.Label(_("Download Limit:"))
|
||||
label = gtk.Label(_('Download Limit:'))
|
||||
label.set_alignment(0.0, 0.6)
|
||||
table.attach(label, 0, 1, 0, 1, gtk.FILL)
|
||||
self.spin_download = gtk.SpinButton()
|
||||
@ -259,7 +259,7 @@ class GtkUI(GtkPluginBase):
|
||||
self.spin_download.set_increments(1, 10)
|
||||
table.attach(self.spin_download, 1, 2, 0, 1, gtk.FILL)
|
||||
|
||||
label = gtk.Label(_("Upload Limit:"))
|
||||
label = gtk.Label(_('Upload Limit:'))
|
||||
label.set_alignment(0.0, 0.6)
|
||||
table.attach(label, 0, 1, 1, 2, gtk.FILL)
|
||||
self.spin_upload = gtk.SpinButton()
|
||||
@ -268,7 +268,7 @@ class GtkUI(GtkPluginBase):
|
||||
self.spin_upload.set_increments(1, 10)
|
||||
table.attach(self.spin_upload, 1, 2, 1, 2, gtk.FILL)
|
||||
|
||||
label = gtk.Label(_("Active Torrents:"))
|
||||
label = gtk.Label(_('Active Torrents:'))
|
||||
label.set_alignment(0.0, 0.6)
|
||||
table.attach(label, 2, 3, 0, 1, gtk.FILL)
|
||||
self.spin_active = gtk.SpinButton()
|
||||
@ -277,7 +277,7 @@ class GtkUI(GtkPluginBase):
|
||||
self.spin_active.set_increments(1, 10)
|
||||
table.attach(self.spin_active, 3, 4, 0, 1, gtk.FILL)
|
||||
|
||||
label = gtk.Label(_("Active Downloading:"))
|
||||
label = gtk.Label(_('Active Downloading:'))
|
||||
label.set_alignment(0.0, 0.6)
|
||||
table.attach(label, 2, 3, 1, 2, gtk.FILL)
|
||||
self.spin_active_down = gtk.SpinButton()
|
||||
@ -286,7 +286,7 @@ class GtkUI(GtkPluginBase):
|
||||
self.spin_active_down.set_increments(1, 10)
|
||||
table.attach(self.spin_active_down, 3, 4, 1, 2, gtk.FILL)
|
||||
|
||||
label = gtk.Label(_("Active Seeding:"))
|
||||
label = gtk.Label(_('Active Seeding:'))
|
||||
label.set_alignment(0.0, 0.6)
|
||||
table.attach(label, 2, 3, 2, 3, gtk.FILL)
|
||||
self.spin_active_up = gtk.SpinButton()
|
||||
@ -296,16 +296,16 @@ class GtkUI(GtkPluginBase):
|
||||
table.attach(self.spin_active_up, 3, 4, 2, 3, gtk.FILL)
|
||||
|
||||
eventbox = gtk.EventBox()
|
||||
eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#EDD400"))
|
||||
eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#EDD400'))
|
||||
eventbox.add(table)
|
||||
frame = gtk.Frame()
|
||||
label = gtk.Label()
|
||||
label.set_markup(_("<b>Slow Settings</b>"))
|
||||
label.set_markup(_('<b>Slow Settings</b>'))
|
||||
frame.set_label_widget(label)
|
||||
frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#CDB400"))
|
||||
frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#CDB400'))
|
||||
frame.set_border_width(2)
|
||||
frame.add(eventbox)
|
||||
vbox.pack_start(frame, False, False)
|
||||
|
||||
vbox.show_all()
|
||||
component.get("Preferences").add_page(_("Scheduler"), vbox)
|
||||
component.get('Preferences').add_page(_('Scheduler'), vbox)
|
||||
|
||||
@ -23,5 +23,5 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("scheduler.js")]
|
||||
scripts = [get_resource('scheduler.js')]
|
||||
debug_scripts = scripts
|
||||
|
||||
@ -13,15 +13,15 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Scheduler"
|
||||
__author__ = "Andrew Resch"
|
||||
__author_email__ = "andrewresch@gmail.com"
|
||||
__version__ = "0.2"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Schedule limits on a per-hour per-day basis."
|
||||
__plugin_name__ = 'Scheduler'
|
||||
__author__ = 'Andrew Resch'
|
||||
__author_email__ = 'andrewresch@gmail.com'
|
||||
__version__ = '0.2'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Schedule limits on a per-hour per-day basis.'
|
||||
__long_description__ = """"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -34,7 +34,7 @@ setup(
|
||||
long_description=__long_description__ if __long_description__ else __description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -13,4 +13,4 @@ import pkg_resources
|
||||
|
||||
|
||||
def get_resource(filename):
|
||||
return pkg_resources.resource_filename("deluge.plugins.stats", os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.stats', os.path.join('data', filename))
|
||||
|
||||
@ -23,17 +23,17 @@ from deluge.core.rpcserver import export
|
||||
from deluge.plugins.pluginbase import CorePluginBase
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"test": "NiNiNi",
|
||||
"update_interval": 1, # 2 seconds.
|
||||
"length": 150, # 2 seconds * 150 --> 5 minutes.
|
||||
'test': 'NiNiNi',
|
||||
'update_interval': 1, # 2 seconds.
|
||||
'length': 150, # 2 seconds * 150 --> 5 minutes.
|
||||
}
|
||||
|
||||
DEFAULT_TOTALS = {
|
||||
"total_upload": 0,
|
||||
"total_download": 0,
|
||||
"total_payload_upload": 0,
|
||||
"total_payload_download": 0,
|
||||
"stats": {}
|
||||
'total_upload': 0,
|
||||
'total_download': 0,
|
||||
'total_payload_upload': 0,
|
||||
'total_payload_download': 0,
|
||||
'stats': {}
|
||||
}
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -57,8 +57,8 @@ class Core(CorePluginBase):
|
||||
totals = {} # class var to catch only updating this once per session in enable.
|
||||
|
||||
def enable(self):
|
||||
log.debug("Stats plugin enabled")
|
||||
self.core = component.get("Core")
|
||||
log.debug('Stats plugin enabled')
|
||||
self.core = component.get('Core')
|
||||
self.stats = {}
|
||||
self.count = {}
|
||||
self.intervals = [1, 5, 30, 300]
|
||||
@ -70,12 +70,12 @@ class Core(CorePluginBase):
|
||||
self.last_update[i] = t
|
||||
self.count[i] = 0
|
||||
|
||||
self.config = configmanager.ConfigManager("stats.conf", DEFAULT_PREFS)
|
||||
self.saved_stats = configmanager.ConfigManager("stats.totals", DEFAULT_TOTALS)
|
||||
self.config = configmanager.ConfigManager('stats.conf', DEFAULT_PREFS)
|
||||
self.saved_stats = configmanager.ConfigManager('stats.totals', DEFAULT_TOTALS)
|
||||
if self.totals == {}:
|
||||
self.totals.update(self.saved_stats.config)
|
||||
|
||||
self.length = self.config["length"]
|
||||
self.length = self.config['length']
|
||||
|
||||
# self.stats = get_key(self.saved_stats, "stats") or {}
|
||||
self.stats_keys = []
|
||||
@ -92,7 +92,7 @@ class Core(CorePluginBase):
|
||||
self.update_stats()
|
||||
|
||||
self.update_timer = LoopingCall(self.update_stats)
|
||||
self.update_timer.start(self.config["update_interval"])
|
||||
self.update_timer.start(self.config['update_interval'])
|
||||
|
||||
self.save_timer = LoopingCall(self.save_stats)
|
||||
self.save_timer.start(60)
|
||||
@ -124,10 +124,10 @@ class Core(CorePluginBase):
|
||||
stats.update(self.core.get_session_status([key]))
|
||||
except AttributeError:
|
||||
pass
|
||||
stats["num_connections"] = stats["num_peers"]
|
||||
stats.update(self.core.get_config_values(["max_download",
|
||||
"max_upload",
|
||||
"max_num_connections"]))
|
||||
stats['num_connections'] = stats['num_peers']
|
||||
stats.update(self.core.get_config_values(['max_download',
|
||||
'max_upload',
|
||||
'max_num_connections']))
|
||||
# status = self.core.session.status()
|
||||
# for stat in dir(status):
|
||||
# if not stat.startswith('_') and stat not in stats:
|
||||
@ -166,16 +166,16 @@ class Core(CorePluginBase):
|
||||
update_interval(300, 30, 10)
|
||||
|
||||
except Exception as ex:
|
||||
log.error("Stats update error %s", ex)
|
||||
log.error('Stats update error %s', ex)
|
||||
return True
|
||||
|
||||
def save_stats(self):
|
||||
try:
|
||||
self.saved_stats["stats"] = self.stats
|
||||
self.saved_stats['stats'] = self.stats
|
||||
self.saved_stats.config.update(self.get_totals())
|
||||
self.saved_stats.save()
|
||||
except Exception as ex:
|
||||
log.error("Stats save error %s", ex)
|
||||
log.error('Stats save error %s', ex)
|
||||
return True
|
||||
|
||||
# export:
|
||||
@ -189,9 +189,9 @@ class Core(CorePluginBase):
|
||||
if key in self.stats[interval]:
|
||||
stats_dict[key] = self.stats[interval][key]
|
||||
|
||||
stats_dict["_last_update"] = self.last_update[interval]
|
||||
stats_dict["_length"] = self.config["length"]
|
||||
stats_dict["_update_interval"] = interval
|
||||
stats_dict['_last_update'] = self.last_update[interval]
|
||||
stats_dict['_length'] = self.config['length']
|
||||
stats_dict['_update_interval'] = interval
|
||||
return stats_dict
|
||||
|
||||
@export
|
||||
@ -206,25 +206,25 @@ class Core(CorePluginBase):
|
||||
def get_session_totals(self):
|
||||
status = self.core.session.status()
|
||||
return {
|
||||
"total_upload": status.total_upload,
|
||||
"total_download": status.total_download,
|
||||
"total_payload_upload": status.total_payload_upload,
|
||||
"total_payload_download": status.total_payload_download
|
||||
'total_upload': status.total_upload,
|
||||
'total_download': status.total_download,
|
||||
'total_payload_upload': status.total_payload_upload,
|
||||
'total_payload_download': status.total_payload_download
|
||||
}
|
||||
|
||||
@export
|
||||
def set_config(self, config):
|
||||
"sets the config dictionary"
|
||||
'sets the config dictionary'
|
||||
for key in config.keys():
|
||||
self.config[key] = config[key]
|
||||
self.config.save()
|
||||
|
||||
@export
|
||||
def get_config(self):
|
||||
"returns the config dictionary"
|
||||
'returns the config dictionary'
|
||||
return self.config.config
|
||||
|
||||
@export
|
||||
def get_intervals(self):
|
||||
"Returns the available resolutions"
|
||||
'Returns the available resolutions'
|
||||
return self.intervals
|
||||
|
||||
@ -88,12 +88,12 @@ class Graph(object):
|
||||
}
|
||||
|
||||
def set_stats(self, stats):
|
||||
self.last_update = stats["_last_update"]
|
||||
del stats["_last_update"]
|
||||
self.length = stats["_length"]
|
||||
del stats["_length"]
|
||||
self.interval = stats["_update_interval"]
|
||||
del stats["_update_interval"]
|
||||
self.last_update = stats['_last_update']
|
||||
del stats['_last_update']
|
||||
self.length = stats['_length']
|
||||
del stats['_length']
|
||||
self.interval = stats['_update_interval']
|
||||
del stats['_update_interval']
|
||||
self.stats = stats
|
||||
return
|
||||
|
||||
|
||||
@ -36,17 +36,17 @@ DEFAULT_CONF = {
|
||||
'version': 1,
|
||||
'colors': {
|
||||
'bandwidth_graph': {
|
||||
'upload_rate': str(gtk.gdk.Color("blue")),
|
||||
'download_rate': str(gtk.gdk.Color("green")),
|
||||
'upload_rate': str(gtk.gdk.Color('blue')),
|
||||
'download_rate': str(gtk.gdk.Color('green')),
|
||||
},
|
||||
'connections_graph': {
|
||||
'dht_nodes': str(gtk.gdk.Color("orange")),
|
||||
'dht_cache_nodes': str(gtk.gdk.Color("blue")),
|
||||
'dht_torrents': str(gtk.gdk.Color("green")),
|
||||
'num_connections': str(gtk.gdk.Color("darkred")),
|
||||
'dht_nodes': str(gtk.gdk.Color('orange')),
|
||||
'dht_cache_nodes': str(gtk.gdk.Color('blue')),
|
||||
'dht_torrents': str(gtk.gdk.Color('green')),
|
||||
'num_connections': str(gtk.gdk.Color('darkred')),
|
||||
},
|
||||
'seeds_graph': {
|
||||
'num_peers': str(gtk.gdk.Color("blue")),
|
||||
'num_peers': str(gtk.gdk.Color('blue')),
|
||||
}}}
|
||||
|
||||
|
||||
@ -54,13 +54,13 @@ def neat_time(column, cell, model, data):
|
||||
"""Render seconds as seconds or minutes with label"""
|
||||
seconds = model.get_value(data, 0)
|
||||
if seconds > 60:
|
||||
text = "%d %s" % (seconds // 60, _("minutes"))
|
||||
text = '%d %s' % (seconds // 60, _('minutes'))
|
||||
elif seconds == 60:
|
||||
text = _("1 minute")
|
||||
text = _('1 minute')
|
||||
elif seconds == 1:
|
||||
text = _("1 second")
|
||||
text = _('1 second')
|
||||
else:
|
||||
text = "%d %s" % (seconds, _("seconds"))
|
||||
text = '%d %s' % (seconds, _('seconds'))
|
||||
cell.set_property('text', text)
|
||||
return
|
||||
|
||||
@ -114,7 +114,7 @@ class GraphsTab(Tab):
|
||||
cell = gtk.CellRendererText()
|
||||
self.intervals_combo.pack_start(cell, True)
|
||||
self.intervals_combo.set_cell_data_func(cell, neat_time)
|
||||
self.intervals_combo.connect("changed", self._on_selected_interval_changed)
|
||||
self.intervals_combo.connect('changed', self._on_selected_interval_changed)
|
||||
self.update_intervals()
|
||||
|
||||
def graph_expose(self, widget, event):
|
||||
@ -145,7 +145,7 @@ class GraphsTab(Tab):
|
||||
client.stats.get_intervals().addCallback(self._on_intervals_changed)
|
||||
|
||||
def select_bandwidth_graph(self):
|
||||
log.debug("Selecting bandwidth graph")
|
||||
log.debug('Selecting bandwidth graph')
|
||||
self.graph_widget = self.bandwidth_graph
|
||||
self.graph = Graph()
|
||||
colors = self.colors['bandwidth_graph']
|
||||
@ -157,7 +157,7 @@ class GraphsTab(Tab):
|
||||
formatter_scale=size_formatter_scale)
|
||||
|
||||
def select_connections_graph(self):
|
||||
log.debug("Selecting connections graph")
|
||||
log.debug('Selecting connections graph')
|
||||
self.graph_widget = self.connections_graph
|
||||
g = Graph()
|
||||
self.graph = g
|
||||
@ -169,7 +169,7 @@ class GraphsTab(Tab):
|
||||
g.set_left_axis(formatter=int_str, min=10)
|
||||
|
||||
def select_seeds_graph(self):
|
||||
log.debug("Selecting connections graph")
|
||||
log.debug('Selecting connections graph')
|
||||
self.graph_widget = self.seeds_graph
|
||||
self.graph = Graph()
|
||||
colors = self.colors['seeds_graph']
|
||||
@ -219,32 +219,32 @@ class GraphsTab(Tab):
|
||||
class GtkUI(GtkPluginBase):
|
||||
|
||||
def enable(self):
|
||||
log.debug("Stats plugin enable called")
|
||||
self.config = deluge.configmanager.ConfigManager("stats.gtkui.conf", DEFAULT_CONF)
|
||||
self.glade = XML(common.get_resource("config.glade"))
|
||||
component.get("Preferences").add_page("Stats", self.glade.get_widget("prefs_box"))
|
||||
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
|
||||
log.debug('Stats plugin enable called')
|
||||
self.config = deluge.configmanager.ConfigManager('stats.gtkui.conf', DEFAULT_CONF)
|
||||
self.glade = XML(common.get_resource('config.glade'))
|
||||
component.get('Preferences').add_page('Stats', self.glade.get_widget('prefs_box'))
|
||||
component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
|
||||
self.on_show_prefs()
|
||||
|
||||
self.graphs_tab = GraphsTab(XML(common.get_resource("tabs.glade")), self.config['colors'])
|
||||
self.graphs_tab = GraphsTab(XML(common.get_resource('tabs.glade')), self.config['colors'])
|
||||
self.torrent_details = component.get('TorrentDetails')
|
||||
self.torrent_details.add_tab(self.graphs_tab)
|
||||
|
||||
def disable(self):
|
||||
component.get("Preferences").remove_page("Stats")
|
||||
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get('Preferences').remove_page('Stats')
|
||||
component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
|
||||
self.torrent_details.remove_tab(self.graphs_tab.get_name())
|
||||
|
||||
def on_apply_prefs(self):
|
||||
log.debug("applying prefs for Stats")
|
||||
log.debug('applying prefs for Stats')
|
||||
gtkconf = {}
|
||||
for graph, colors in self.config['colors'].items():
|
||||
gtkconf[graph] = {}
|
||||
for value, color in colors.items():
|
||||
try:
|
||||
color_btn = self.glade.get_widget("%s_%s_color" % (graph, value))
|
||||
color_btn = self.glade.get_widget('%s_%s_color' % (graph, value))
|
||||
gtkconf[graph][value] = str(color_btn.get_color())
|
||||
except Exception:
|
||||
gtkconf[graph][value] = DEFAULT_CONF['colors'][graph][value]
|
||||
@ -258,12 +258,12 @@ class GtkUI(GtkPluginBase):
|
||||
for graph, colors in self.config['colors'].items():
|
||||
for value, color in colors.items():
|
||||
try:
|
||||
color_btn = self.glade.get_widget("%s_%s_color" % (graph, value))
|
||||
color_btn = self.glade.get_widget('%s_%s_color' % (graph, value))
|
||||
color_btn.set_color(gtk.gdk.Color(color))
|
||||
except Exception:
|
||||
log.debug("Unable to set %s %s %s", graph, value, color)
|
||||
log.debug('Unable to set %s %s %s', graph, value, color)
|
||||
client.stats.get_config().addCallback(self.cb_get_config)
|
||||
|
||||
def cb_get_config(self, config):
|
||||
"callback for on show_prefs"
|
||||
'callback for on show_prefs'
|
||||
pass
|
||||
|
||||
@ -21,9 +21,9 @@ def print_totals(totals):
|
||||
for name, value in totals.iteritems():
|
||||
print(name, fsize(value))
|
||||
|
||||
print("overhead:")
|
||||
print("up:", fsize(totals["total_upload"] - totals["total_payload_upload"]))
|
||||
print("down:", fsize(totals["total_download"] - totals["total_payload_download"]))
|
||||
print('overhead:')
|
||||
print('up:', fsize(totals['total_upload'] - totals['total_payload_upload']))
|
||||
print('down:', fsize(totals['total_download'] - totals['total_payload_download']))
|
||||
|
||||
|
||||
class StatsTestCase(BaseTestCase):
|
||||
@ -32,7 +32,7 @@ class StatsTestCase(BaseTestCase):
|
||||
defer.setDebugging(True)
|
||||
tests_common.set_tmp_config_dir()
|
||||
client.start_standalone()
|
||||
client.core.enable_plugin("Stats")
|
||||
client.core.enable_plugin('Stats')
|
||||
return component.start()
|
||||
|
||||
def tear_down(self):
|
||||
@ -42,8 +42,8 @@ class StatsTestCase(BaseTestCase):
|
||||
@defer.inlineCallbacks
|
||||
def test_client_totals(self):
|
||||
plugins = yield client.core.get_available_plugins()
|
||||
if "Stats" not in plugins:
|
||||
raise unittest.SkipTest("WebUi plugin not available for testing")
|
||||
if 'Stats' not in plugins:
|
||||
raise unittest.SkipTest('WebUi plugin not available for testing')
|
||||
|
||||
totals = yield client.stats.get_totals()
|
||||
self.assertEquals(totals['total_upload'], 0)
|
||||
@ -55,8 +55,8 @@ class StatsTestCase(BaseTestCase):
|
||||
@defer.inlineCallbacks
|
||||
def test_session_totals(self):
|
||||
plugins = yield client.core.get_available_plugins()
|
||||
if "Stats" not in plugins:
|
||||
raise unittest.SkipTest("WebUi plugin not available for testing")
|
||||
if 'Stats' not in plugins:
|
||||
raise unittest.SkipTest('WebUi plugin not available for testing')
|
||||
|
||||
totals = yield client.stats.get_session_totals()
|
||||
self.assertEquals(totals['total_upload'], 0)
|
||||
@ -82,7 +82,7 @@ class StatsTestCase(BaseTestCase):
|
||||
from deluge.ui.gtkui.torrentview import TorrentView
|
||||
from deluge.plugins.Stats.deluge.plugins.stats import graph, gtkui
|
||||
|
||||
ConfigManager("gtkui.conf", defaults=DEFAULT_PREFS)
|
||||
ConfigManager('gtkui.conf', defaults=DEFAULT_PREFS)
|
||||
|
||||
self.plugins = PluginManager()
|
||||
MainWindow()
|
||||
@ -97,7 +97,7 @@ class StatsTestCase(BaseTestCase):
|
||||
def write(self, data):
|
||||
self.data.append(data)
|
||||
|
||||
stats_gtkui = gtkui.GtkUI("test_stats")
|
||||
stats_gtkui = gtkui.GtkUI('test_stats')
|
||||
stats_gtkui.enable()
|
||||
yield stats_gtkui.graphs_tab.update()
|
||||
|
||||
@ -109,6 +109,6 @@ class StatsTestCase(BaseTestCase):
|
||||
surface = g.draw(900, 150)
|
||||
file_like = FakeFile()
|
||||
surface.write_to_png(file_like)
|
||||
data = "".join(file_like.data)
|
||||
with open("file_like.png", "wb") as _file:
|
||||
data = ''.join(file_like.data)
|
||||
with open('file_like.png', 'wb') as _file:
|
||||
_file.write(data)
|
||||
|
||||
@ -22,13 +22,13 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("stats.js")]
|
||||
scripts = [get_resource('stats.js')]
|
||||
|
||||
# The enable and disable methods are not scrictly required on the WebUI
|
||||
# plugins. They are only here if you need to register images/stylesheets
|
||||
# with the webserver.
|
||||
def enable(self):
|
||||
log.debug("Stats Web plugin enabled!")
|
||||
log.debug('Stats Web plugin enabled!')
|
||||
|
||||
def disable(self):
|
||||
log.debug("Stats Web plugin disabled!")
|
||||
log.debug('Stats Web plugin disabled!')
|
||||
|
||||
@ -14,18 +14,18 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Stats"
|
||||
__author__ = "Ian Martin"
|
||||
__author_email__ = "ianmartin@cantab.net"
|
||||
__version__ = "0.3.2"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Display stats graphs"
|
||||
__plugin_name__ = 'Stats'
|
||||
__author__ = 'Ian Martin'
|
||||
__author_email__ = 'ianmartin@cantab.net'
|
||||
__version__ = '0.3.2'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Display stats graphs'
|
||||
__long_description__ = """
|
||||
Records lots of extra stats
|
||||
and produces time series
|
||||
graphs"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -38,7 +38,7 @@ setup(
|
||||
long_description=__long_description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -16,5 +16,5 @@
|
||||
def get_resource(filename):
|
||||
import os.path
|
||||
import pkg_resources
|
||||
return pkg_resources.resource_filename("deluge.plugins.toggle",
|
||||
os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.toggle',
|
||||
os.path.join('data', filename))
|
||||
|
||||
@ -26,7 +26,7 @@ DEFAULT_PREFS = {
|
||||
|
||||
class Core(CorePluginBase):
|
||||
def enable(self):
|
||||
self.core = component.get("Core")
|
||||
self.core = component.get('Core')
|
||||
|
||||
def disable(self):
|
||||
pass
|
||||
|
||||
@ -24,25 +24,25 @@ log = logging.getLogger(__name__)
|
||||
class GtkUI(GtkPluginBase):
|
||||
def enable(self):
|
||||
self.core = client.toggle
|
||||
self.plugin = component.get("PluginManager")
|
||||
self.plugin = component.get('PluginManager')
|
||||
self.separator = self.plugin.add_toolbar_separator()
|
||||
self.button = self.plugin.add_toolbar_button(self._on_button_clicked, label="Pause Session",
|
||||
stock="gtk-media-pause", tooltip="Pause the session")
|
||||
self.button = self.plugin.add_toolbar_button(self._on_button_clicked, label='Pause Session',
|
||||
stock='gtk-media-pause', tooltip='Pause the session')
|
||||
|
||||
def disable(self):
|
||||
component.get("PluginManager").remove_toolbar_button(self.button)
|
||||
component.get("PluginManager").remove_toolbar_button(self.separator)
|
||||
component.get('PluginManager').remove_toolbar_button(self.button)
|
||||
component.get('PluginManager').remove_toolbar_button(self.separator)
|
||||
|
||||
def update(self):
|
||||
def _on_get_status(paused):
|
||||
if paused:
|
||||
self.button.set_label("Resume Session")
|
||||
self.button.set_tooltip_text("Resume the session")
|
||||
self.button.set_stock_id("gtk-media-play")
|
||||
self.button.set_label('Resume Session')
|
||||
self.button.set_tooltip_text('Resume the session')
|
||||
self.button.set_stock_id('gtk-media-play')
|
||||
else:
|
||||
self.button.set_label("Pause Session")
|
||||
self.button.set_tooltip_text("Pause the session")
|
||||
self.button.set_stock_id("gtk-media-pause")
|
||||
self.button.set_label('Pause Session')
|
||||
self.button.set_tooltip_text('Pause the session')
|
||||
self.button.set_stock_id('gtk-media-pause')
|
||||
self.core.get_status().addCallback(_on_get_status)
|
||||
|
||||
def _on_button_clicked(self, widget):
|
||||
|
||||
@ -23,7 +23,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class WebUI(WebPluginBase):
|
||||
|
||||
scripts = [get_resource("toggle.js")]
|
||||
scripts = [get_resource('toggle.js')]
|
||||
|
||||
def enable(self):
|
||||
pass
|
||||
|
||||
@ -14,15 +14,15 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "Toggle"
|
||||
__author__ = "John Garland"
|
||||
__author_email__ = "johnnybg+deluge@gmail.com"
|
||||
__version__ = "0.3"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Toggles the session"
|
||||
__plugin_name__ = 'Toggle'
|
||||
__author__ = 'John Garland'
|
||||
__author_email__ = 'johnnybg+deluge@gmail.com'
|
||||
__version__ = '0.3'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Toggles the session'
|
||||
__long_description__ = """"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -35,7 +35,7 @@ setup(
|
||||
long_description=__long_description__ if __long_description__ else __description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -15,5 +15,5 @@
|
||||
def get_resource(filename):
|
||||
import os.path
|
||||
import pkg_resources
|
||||
return pkg_resources.resource_filename("deluge.plugins.webui",
|
||||
os.path.join("data", filename))
|
||||
return pkg_resources.resource_filename('deluge.plugins.webui',
|
||||
os.path.join('data', filename))
|
||||
|
||||
@ -24,9 +24,9 @@ from deluge.plugins.pluginbase import CorePluginBase
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_PREFS = {
|
||||
"enabled": False,
|
||||
"ssl": False,
|
||||
"port": 8112
|
||||
'enabled': False,
|
||||
'ssl': False,
|
||||
'port': 8112
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ class Core(CorePluginBase):
|
||||
server = None
|
||||
|
||||
def enable(self):
|
||||
self.config = configmanager.ConfigManager("web_plugin.conf", DEFAULT_PREFS)
|
||||
self.config = configmanager.ConfigManager('web_plugin.conf', DEFAULT_PREFS)
|
||||
if self.config['enabled']:
|
||||
self.start_server()
|
||||
|
||||
@ -63,16 +63,16 @@ class Core(CorePluginBase):
|
||||
return False
|
||||
|
||||
try:
|
||||
self.server = component.get("DelugeWeb")
|
||||
self.server = component.get('DelugeWeb')
|
||||
except KeyError:
|
||||
self.server = server.DelugeWeb(daemon=False)
|
||||
|
||||
self.server.port = self.config["port"]
|
||||
self.server.https = self.config["ssl"]
|
||||
self.server.port = self.config['port']
|
||||
self.server.https = self.config['ssl']
|
||||
try:
|
||||
self.server.start()
|
||||
except CannotListenError as ex:
|
||||
log.warn("Failed to start WebUI server: %s", ex)
|
||||
log.warn('Failed to start WebUI server: %s', ex)
|
||||
raise
|
||||
return True
|
||||
|
||||
@ -86,14 +86,14 @@ class Core(CorePluginBase):
|
||||
|
||||
@export
|
||||
def set_config(self, config):
|
||||
"sets the config dictionary"
|
||||
'sets the config dictionary'
|
||||
|
||||
action = None
|
||||
if "enabled" in config:
|
||||
if config["enabled"] != self.config["enabled"]:
|
||||
action = config["enabled"] and 'start' or 'stop'
|
||||
if 'enabled' in config:
|
||||
if config['enabled'] != self.config['enabled']:
|
||||
action = config['enabled'] and 'start' or 'stop'
|
||||
|
||||
if "ssl" in config:
|
||||
if 'ssl' in config:
|
||||
if not action:
|
||||
action = 'restart'
|
||||
|
||||
@ -110,5 +110,5 @@ class Core(CorePluginBase):
|
||||
|
||||
@export
|
||||
def get_config(self):
|
||||
"returns the config dictionary"
|
||||
'returns the config dictionary'
|
||||
return self.config.config
|
||||
|
||||
@ -27,27 +27,27 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class GtkUI(GtkPluginBase):
|
||||
def enable(self):
|
||||
self.glade = gtk.glade.XML(get_resource("config.glade"))
|
||||
self.glade = gtk.glade.XML(get_resource('config.glade'))
|
||||
|
||||
component.get("Preferences").add_page(_("WebUi"), self.glade.get_widget("prefs_box"))
|
||||
component.get("PluginManager").register_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").register_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get('Preferences').add_page(_('WebUi'), self.glade.get_widget('prefs_box'))
|
||||
component.get('PluginManager').register_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').register_hook('on_show_prefs', self.on_show_prefs)
|
||||
client.webui.get_config().addCallback(self.cb_get_config)
|
||||
client.webui.got_deluge_web().addCallback(self.cb_chk_deluge_web)
|
||||
|
||||
def disable(self):
|
||||
component.get("Preferences").remove_page(_("WebUi"))
|
||||
component.get("PluginManager").deregister_hook("on_apply_prefs", self.on_apply_prefs)
|
||||
component.get("PluginManager").deregister_hook("on_show_prefs", self.on_show_prefs)
|
||||
component.get('Preferences').remove_page(_('WebUi'))
|
||||
component.get('PluginManager').deregister_hook('on_apply_prefs', self.on_apply_prefs)
|
||||
component.get('PluginManager').deregister_hook('on_show_prefs', self.on_show_prefs)
|
||||
|
||||
def on_apply_prefs(self):
|
||||
if not self.have_web:
|
||||
return
|
||||
log.debug("applying prefs for WebUi")
|
||||
log.debug('applying prefs for WebUi')
|
||||
config = {
|
||||
"enabled": self.glade.get_widget("enabled_checkbutton").get_active(),
|
||||
"ssl": self.glade.get_widget("ssl_checkbutton").get_active(),
|
||||
"port": self.glade.get_widget("port_spinbutton").get_value_as_int()
|
||||
'enabled': self.glade.get_widget('enabled_checkbutton').get_active(),
|
||||
'ssl': self.glade.get_widget('ssl_checkbutton').get_active(),
|
||||
'port': self.glade.get_widget('port_spinbutton').get_value_as_int()
|
||||
}
|
||||
client.webui.set_config(config)
|
||||
|
||||
@ -55,26 +55,26 @@ class GtkUI(GtkPluginBase):
|
||||
client.webui.get_config().addCallback(self.cb_get_config)
|
||||
|
||||
def cb_get_config(self, config):
|
||||
"callback for on show_prefs"
|
||||
self.glade.get_widget("enabled_checkbutton").set_active(config["enabled"])
|
||||
self.glade.get_widget("ssl_checkbutton").set_active(config["ssl"])
|
||||
self.glade.get_widget("port_spinbutton").set_value(config["port"])
|
||||
'callback for on show_prefs'
|
||||
self.glade.get_widget('enabled_checkbutton').set_active(config['enabled'])
|
||||
self.glade.get_widget('ssl_checkbutton').set_active(config['ssl'])
|
||||
self.glade.get_widget('port_spinbutton').set_value(config['port'])
|
||||
|
||||
def cb_chk_deluge_web(self, have_web):
|
||||
self.have_web = have_web
|
||||
if have_web:
|
||||
return
|
||||
self.glade.get_widget("settings_vbox").set_sensitive(False)
|
||||
self.glade.get_widget('settings_vbox').set_sensitive(False)
|
||||
|
||||
vbox = self.glade.get_widget("prefs_box")
|
||||
vbox = self.glade.get_widget('prefs_box')
|
||||
|
||||
hbox = gtk.HBox()
|
||||
icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||
icon.set_padding(5, 5)
|
||||
hbox.pack_start(icon, False, False)
|
||||
|
||||
label = gtk.Label(_("The Deluge web interface is not installed, "
|
||||
"please install the\ninterface and try again"))
|
||||
label = gtk.Label(_('The Deluge web interface is not installed, '
|
||||
'please install the\ninterface and try again'))
|
||||
label.set_alignment(0, 0.5)
|
||||
label.set_padding(5, 5)
|
||||
hbox.pack_start(label)
|
||||
|
||||
@ -34,14 +34,14 @@ class WebUIPluginTestCase(BaseTestCase):
|
||||
return component.shutdown().addCallback(on_shutdown)
|
||||
|
||||
def test_enable_webui(self):
|
||||
if "WebUi" not in self.core.get_available_plugins():
|
||||
raise unittest.SkipTest("WebUi plugin not available for testing")
|
||||
if 'WebUi' not in self.core.get_available_plugins():
|
||||
raise unittest.SkipTest('WebUi plugin not available for testing')
|
||||
|
||||
d = self.core.enable_plugin("WebUi")
|
||||
d = self.core.enable_plugin('WebUi')
|
||||
|
||||
def result_cb(result):
|
||||
if "WebUi" not in self.core.get_enabled_plugins():
|
||||
self.fail("Failed to enable WebUi plugin")
|
||||
if 'WebUi' not in self.core.get_enabled_plugins():
|
||||
self.fail('Failed to enable WebUi plugin')
|
||||
self.assertTrue(result)
|
||||
|
||||
d.addBoth(result_cb)
|
||||
|
||||
@ -13,15 +13,15 @@
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
__plugin_name__ = "WebUi"
|
||||
__author__ = "Damien Churchill"
|
||||
__author_email__ = "damoxc@gmail.com"
|
||||
__version__ = "0.1"
|
||||
__url__ = "http://deluge-torrent.org"
|
||||
__license__ = "GPLv3"
|
||||
__description__ = "Allows starting the web interface within the daemon."
|
||||
__plugin_name__ = 'WebUi'
|
||||
__author__ = 'Damien Churchill'
|
||||
__author_email__ = 'damoxc@gmail.com'
|
||||
__version__ = '0.1'
|
||||
__url__ = 'http://deluge-torrent.org'
|
||||
__license__ = 'GPLv3'
|
||||
__description__ = 'Allows starting the web interface within the daemon.'
|
||||
__long_description__ = """"""
|
||||
__pkg_data__ = {"deluge.plugins." + __plugin_name__.lower(): ["template/*", "data/*"]}
|
||||
__pkg_data__ = {'deluge.plugins.' + __plugin_name__.lower(): ['template/*', 'data/*']}
|
||||
|
||||
setup(
|
||||
name=__plugin_name__,
|
||||
@ -34,7 +34,7 @@ setup(
|
||||
long_description=__long_description__ if __long_description__ else __description__,
|
||||
|
||||
packages=find_packages(),
|
||||
namespace_packages=["deluge", "deluge.plugins"],
|
||||
namespace_packages=['deluge', 'deluge.plugins'],
|
||||
package_data=__pkg_data__,
|
||||
|
||||
entry_points="""
|
||||
|
||||
@ -22,22 +22,22 @@ class PluginBase(component.Component):
|
||||
super(PluginBase, self).__init__(name, self.update_interval)
|
||||
|
||||
def enable(self):
|
||||
raise NotImplementedError("Need to define an enable method!")
|
||||
raise NotImplementedError('Need to define an enable method!')
|
||||
|
||||
def disable(self):
|
||||
raise NotImplementedError("Need to define a disable method!")
|
||||
raise NotImplementedError('Need to define a disable method!')
|
||||
|
||||
|
||||
class CorePluginBase(PluginBase):
|
||||
|
||||
def __init__(self, plugin_name):
|
||||
super(CorePluginBase, self).__init__("CorePlugin." + plugin_name)
|
||||
super(CorePluginBase, self).__init__('CorePlugin.' + plugin_name)
|
||||
# Register RPC methods
|
||||
component.get("RPCServer").register_object(self, plugin_name.lower())
|
||||
log.debug("CorePlugin initialized..")
|
||||
component.get('RPCServer').register_object(self, plugin_name.lower())
|
||||
log.debug('CorePlugin initialized..')
|
||||
|
||||
def __del__(self):
|
||||
component.get("RPCServer").deregister_object(self)
|
||||
component.get('RPCServer').deregister_object(self)
|
||||
|
||||
def enable(self):
|
||||
super(CorePluginBase, self).enable()
|
||||
@ -49,8 +49,8 @@ class CorePluginBase(PluginBase):
|
||||
class GtkPluginBase(PluginBase):
|
||||
|
||||
def __init__(self, plugin_name):
|
||||
super(GtkPluginBase, self).__init__("GtkPlugin." + plugin_name)
|
||||
log.debug("GtkPlugin initialized..")
|
||||
super(GtkPluginBase, self).__init__('GtkPlugin.' + plugin_name)
|
||||
log.debug('GtkPlugin initialized..')
|
||||
|
||||
def enable(self):
|
||||
super(GtkPluginBase, self).enable()
|
||||
@ -68,11 +68,11 @@ class WebPluginBase(PluginBase):
|
||||
debug_stylesheets = []
|
||||
|
||||
def __init__(self, plugin_name):
|
||||
super(WebPluginBase, self).__init__("WebPlugin." + plugin_name)
|
||||
super(WebPluginBase, self).__init__('WebPlugin.' + plugin_name)
|
||||
|
||||
# Register JSON rpc methods
|
||||
component.get("JSON").register_object(self, plugin_name.lower())
|
||||
log.debug("WebPlugin initialized..")
|
||||
component.get('JSON').register_object(self, plugin_name.lower())
|
||||
log.debug('WebPlugin initialized..')
|
||||
|
||||
def enable(self):
|
||||
pass
|
||||
|
||||
@ -62,7 +62,7 @@ import struct
|
||||
import sys
|
||||
from threading import Lock
|
||||
|
||||
__version__ = ("Python", 1, 0, 4)
|
||||
__version__ = ('Python', 1, 0, 4)
|
||||
__all__ = ['dumps', 'loads']
|
||||
|
||||
py3 = sys.version_info[0] >= 3
|
||||
@ -244,7 +244,7 @@ def make_fixed_length_string_decoders():
|
||||
def f(x, f):
|
||||
s = x[f + 1:f + 1 + slen]
|
||||
if _decode_utf8:
|
||||
s = s.decode("utf8")
|
||||
s = s.decode('utf8')
|
||||
return (s, f + 1 + slen)
|
||||
return f
|
||||
for i in range(STR_FIXED_COUNT):
|
||||
@ -324,7 +324,7 @@ def encode_int(x, r):
|
||||
else:
|
||||
s = str(x)
|
||||
if py3:
|
||||
s = bytes(s, "ascii")
|
||||
s = bytes(s, 'ascii')
|
||||
|
||||
if len(s) >= MAX_INT_LENGTH:
|
||||
raise ValueError('overflow')
|
||||
@ -353,12 +353,12 @@ def encode_string(x, r):
|
||||
else:
|
||||
s = str(len(x))
|
||||
if py3:
|
||||
s = bytes(s, "ascii")
|
||||
s = bytes(s, 'ascii')
|
||||
r.extend((s, b':', x))
|
||||
|
||||
|
||||
def encode_unicode(x, r):
|
||||
encode_string(x.encode("utf8"), r)
|
||||
encode_string(x.encode('utf8'), r)
|
||||
|
||||
|
||||
def encode_list(x, r):
|
||||
@ -447,7 +447,7 @@ def test():
|
||||
assert 1e-10 < abs(loads(dumps(1.1)) - 1.1) < 1e-6
|
||||
assert 1e-10 < abs(loads(dumps(1.1, 32)) - 1.1) < 1e-6
|
||||
assert abs(loads(dumps(1.1, 64)) - 1.1) < 1e-12
|
||||
assert loads(dumps("Hello World!!"), decode_utf8=True)
|
||||
assert loads(dumps('Hello World!!'), decode_utf8=True)
|
||||
try:
|
||||
import psyco
|
||||
psyco.bind(dumps)
|
||||
|
||||
@ -16,15 +16,15 @@ from datetime import datetime
|
||||
import deluge.common
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-n", "--name", metavar="<plugin name>", required=True, help="Plugin name")
|
||||
parser.add_argument("-m", "--module-name", metavar="<module name>", help="Module name")
|
||||
parser.add_argument("-p", "--basepath", metavar="<path>", required=True, help="Base path")
|
||||
parser.add_argument("-a", "--author-name", metavar="<author name>", required=True,
|
||||
help="Author name,for the GPL header")
|
||||
parser.add_argument("-e", "--author-email", metavar="<author email>", required=True,
|
||||
help="Author email,for the GPL header")
|
||||
parser.add_argument("-u", "--url", metavar="<URL>", help="Homepage URL")
|
||||
parser.add_argument("-c", "--config", metavar="<Config dir>", dest="configdir", help="Location of deluge configuration")
|
||||
parser.add_argument('-n', '--name', metavar='<plugin name>', required=True, help='Plugin name')
|
||||
parser.add_argument('-m', '--module-name', metavar='<module name>', help='Module name')
|
||||
parser.add_argument('-p', '--basepath', metavar='<path>', required=True, help='Base path')
|
||||
parser.add_argument('-a', '--author-name', metavar='<author name>', required=True,
|
||||
help='Author name,for the GPL header')
|
||||
parser.add_argument('-e', '--author-email', metavar='<author email>', required=True,
|
||||
help='Author email,for the GPL header')
|
||||
parser.add_argument('-u', '--url', metavar='<URL>', help='Homepage URL')
|
||||
parser.add_argument('-c', '--config', metavar='<Config dir>', dest='configdir', help='Location of deluge configuration')
|
||||
|
||||
options = parser.parse_args()
|
||||
|
||||
@ -32,10 +32,10 @@ options = parser.parse_args()
|
||||
def create_plugin():
|
||||
|
||||
if not options.url:
|
||||
options.url = ""
|
||||
options.url = ''
|
||||
|
||||
if not os.path.exists(options.basepath):
|
||||
print("basepath does not exist")
|
||||
print('basepath does not exist')
|
||||
return
|
||||
|
||||
if not options.configdir:
|
||||
@ -44,65 +44,65 @@ def create_plugin():
|
||||
options.configdir = os.path.realpath(options.configdir)
|
||||
|
||||
real_name = options.name
|
||||
name = real_name.replace(" ", "_")
|
||||
name = real_name.replace(' ', '_')
|
||||
safe_name = name.lower()
|
||||
if options.module_name:
|
||||
safe_name = options.module_name.lower()
|
||||
plugin_base = os.path.realpath(os.path.join(options.basepath, name))
|
||||
deluge_namespace = os.path.join(plugin_base, "deluge")
|
||||
plugins_namespace = os.path.join(deluge_namespace, "plugins")
|
||||
deluge_namespace = os.path.join(plugin_base, 'deluge')
|
||||
plugins_namespace = os.path.join(deluge_namespace, 'plugins')
|
||||
src = os.path.join(plugins_namespace, safe_name)
|
||||
data_dir = os.path.join(src, "data")
|
||||
data_dir = os.path.join(src, 'data')
|
||||
python_path = sys.executable
|
||||
|
||||
if os.path.exists(plugin_base):
|
||||
print("the directory %s already exists, delete it first" % plugin_base)
|
||||
print('the directory %s already exists, delete it first' % plugin_base)
|
||||
return
|
||||
|
||||
def write_file(path, filename, template, include_gpl=True):
|
||||
plugin_args = {
|
||||
"author_name": options.author_name,
|
||||
"author_email": options.author_email,
|
||||
"name": name,
|
||||
"safe_name": safe_name,
|
||||
"filename": filename,
|
||||
"plugin_base": plugin_base,
|
||||
"python_path": python_path,
|
||||
"url": options.url,
|
||||
"configdir": options.configdir,
|
||||
"current_year": datetime.utcnow().year
|
||||
'author_name': options.author_name,
|
||||
'author_email': options.author_email,
|
||||
'name': name,
|
||||
'safe_name': safe_name,
|
||||
'filename': filename,
|
||||
'plugin_base': plugin_base,
|
||||
'python_path': python_path,
|
||||
'url': options.url,
|
||||
'configdir': options.configdir,
|
||||
'current_year': datetime.utcnow().year
|
||||
}
|
||||
|
||||
filename = os.path.join(path, filename)
|
||||
with open(filename, "w") as _file:
|
||||
if filename.endswith(".py") and include_gpl:
|
||||
with open(filename, 'w') as _file:
|
||||
if filename.endswith('.py') and include_gpl:
|
||||
_file.write(GPL % plugin_args)
|
||||
_file.write(template % plugin_args)
|
||||
|
||||
print("creating folders..")
|
||||
print('creating folders..')
|
||||
os.mkdir(plugin_base)
|
||||
os.mkdir(deluge_namespace)
|
||||
os.mkdir(plugins_namespace)
|
||||
os.mkdir(src)
|
||||
os.mkdir(data_dir)
|
||||
|
||||
print("creating files..")
|
||||
write_file(plugin_base, "setup.py", SETUP)
|
||||
write_file(deluge_namespace, "__init__.py", NAMESPACE_INIT, False)
|
||||
write_file(plugins_namespace, "__init__.py", NAMESPACE_INIT, False)
|
||||
write_file(src, "__init__.py", INIT)
|
||||
write_file(src, "gtkui.py", GTKUI)
|
||||
write_file(src, "webui.py", WEBUI)
|
||||
write_file(src, "core.py", CORE)
|
||||
write_file(src, "common.py", COMMON)
|
||||
write_file(data_dir, "config.glade", GLADE)
|
||||
write_file(data_dir, "%s.js" % safe_name, DEFAULT_JS)
|
||||
print('creating files..')
|
||||
write_file(plugin_base, 'setup.py', SETUP)
|
||||
write_file(deluge_namespace, '__init__.py', NAMESPACE_INIT, False)
|
||||
write_file(plugins_namespace, '__init__.py', NAMESPACE_INIT, False)
|
||||
write_file(src, '__init__.py', INIT)
|
||||
write_file(src, 'gtkui.py', GTKUI)
|
||||
write_file(src, 'webui.py', WEBUI)
|
||||
write_file(src, 'core.py', CORE)
|
||||
write_file(src, 'common.py', COMMON)
|
||||
write_file(data_dir, 'config.glade', GLADE)
|
||||
write_file(data_dir, '%s.js' % safe_name, DEFAULT_JS)
|
||||
|
||||
# add an input parameter for this?
|
||||
print("building dev-link..")
|
||||
write_file(plugin_base, "create_dev_link.sh", CREATE_DEV_LINK)
|
||||
dev_link_path = os.path.join(plugin_base, "create_dev_link.sh")
|
||||
os.system("chmod +x %s" % dev_link_path) # lazy..
|
||||
print('building dev-link..')
|
||||
write_file(plugin_base, 'create_dev_link.sh', CREATE_DEV_LINK)
|
||||
dev_link_path = os.path.join(plugin_base, 'create_dev_link.sh')
|
||||
os.system('chmod +x %s' % dev_link_path) # lazy..
|
||||
os.system(dev_link_path)
|
||||
|
||||
|
||||
|
||||
@ -28,21 +28,21 @@ def is_float_digit(string):
|
||||
|
||||
# set up command-line options
|
||||
parser = OptionParser()
|
||||
parser.add_option("--port", help="port for deluge backend host (default: 58846)", default="58846", dest="port")
|
||||
parser.add_option("--host", help="hostname of deluge backend to connect to (default: localhost)",
|
||||
default="localhost", dest="host")
|
||||
parser.add_option("--max_active_limit", dest="max_active_limit",
|
||||
help="sets the absolute maximum number of active torrents on the deluge backend")
|
||||
parser.add_option("--max_active_downloading", dest="max_active_downloading",
|
||||
help="sets the maximum number of active downloading torrents on the deluge backend")
|
||||
parser.add_option("--max_active_seeding", dest="max_active_seeding",
|
||||
help="sets the maximum number of active seeding torrents on the deluge backend")
|
||||
parser.add_option("--max_download_speed", help="sets the maximum global download speed on the deluge backend",
|
||||
dest="max_download_speed")
|
||||
parser.add_option("--max_upload_speed", help="sets the maximum global upload speed on the deluge backend",
|
||||
dest="max_upload_speed")
|
||||
parser.add_option("--debug", help="outputs debug information to the console", default=False, action="store_true",
|
||||
dest="debug")
|
||||
parser.add_option('--port', help='port for deluge backend host (default: 58846)', default='58846', dest='port')
|
||||
parser.add_option('--host', help='hostname of deluge backend to connect to (default: localhost)',
|
||||
default='localhost', dest='host')
|
||||
parser.add_option('--max_active_limit', dest='max_active_limit',
|
||||
help='sets the absolute maximum number of active torrents on the deluge backend')
|
||||
parser.add_option('--max_active_downloading', dest='max_active_downloading',
|
||||
help='sets the maximum number of active downloading torrents on the deluge backend')
|
||||
parser.add_option('--max_active_seeding', dest='max_active_seeding',
|
||||
help='sets the maximum number of active seeding torrents on the deluge backend')
|
||||
parser.add_option('--max_download_speed', help='sets the maximum global download speed on the deluge backend',
|
||||
dest='max_download_speed')
|
||||
parser.add_option('--max_upload_speed', help='sets the maximum global upload speed on the deluge backend',
|
||||
dest='max_upload_speed')
|
||||
parser.add_option('--debug', help='outputs debug information to the console', default=False, action='store_true',
|
||||
dest='debug')
|
||||
|
||||
# grab command-line options
|
||||
(options, args) = parser.parse_args()
|
||||
@ -57,21 +57,21 @@ if options.max_active_limit:
|
||||
if options.max_active_limit.isdigit() and int(options.max_active_limit) >= 0:
|
||||
settings['max_active_limit'] = int(options.max_active_limit)
|
||||
else:
|
||||
sys.stderr.write("ERROR: Invalid max_active_limit parameter!\n")
|
||||
sys.stderr.write('ERROR: Invalid max_active_limit parameter!\n')
|
||||
sys.exit(-1)
|
||||
|
||||
if options.max_active_downloading:
|
||||
if options.max_active_downloading.isdigit() and int(options.max_active_downloading) >= 0:
|
||||
settings['max_active_downloading'] = int(options.max_active_downloading)
|
||||
else:
|
||||
sys.stderr.write("ERROR: Invalid max_active_downloading parameter!\n")
|
||||
sys.stderr.write('ERROR: Invalid max_active_downloading parameter!\n')
|
||||
sys.exit(-1)
|
||||
|
||||
if options.max_active_seeding:
|
||||
if options.max_active_seeding.isdigit() and int(options.max_active_seeding) >= 0:
|
||||
settings['max_active_seeding'] = int(options.max_active_seeding)
|
||||
else:
|
||||
sys.stderr.write("ERROR: Invalid max_active_seeding parameter!\n")
|
||||
sys.stderr.write('ERROR: Invalid max_active_seeding parameter!\n')
|
||||
sys.exit(-1)
|
||||
|
||||
if options.max_download_speed:
|
||||
@ -79,7 +79,7 @@ if options.max_download_speed:
|
||||
float(options.max_download_speed) >= 0.0 or float(options.max_download_speed) == -1.0):
|
||||
settings['max_download_speed'] = float(options.max_download_speed)
|
||||
else:
|
||||
sys.stderr.write("ERROR: Invalid max_download_speed parameter!\n")
|
||||
sys.stderr.write('ERROR: Invalid max_download_speed parameter!\n')
|
||||
sys.exit(-1)
|
||||
|
||||
if options.max_upload_speed:
|
||||
@ -87,14 +87,14 @@ if options.max_upload_speed:
|
||||
float(options.max_upload_speed) >= 0.0 or float(options.max_upload_speed) == -1.0):
|
||||
settings['max_upload_speed'] = float(options.max_upload_speed)
|
||||
else:
|
||||
sys.stderr.write("ERROR: Invalid max_upload_speed parameter!\n")
|
||||
sys.stderr.write('ERROR: Invalid max_upload_speed parameter!\n')
|
||||
sys.exit(-1)
|
||||
|
||||
# If there is something to do ...
|
||||
if settings:
|
||||
# create connection to daemon
|
||||
from deluge.ui.client import sclient as client
|
||||
client.set_core_uri("http://" + options.host + ":" + options.port)
|
||||
client.set_core_uri('http://' + options.host + ':' + options.port)
|
||||
|
||||
# commit configurations changes
|
||||
client.set_config(settings)
|
||||
|
||||
@ -10,4 +10,4 @@ else:
|
||||
try:
|
||||
resource.setrlimit(resource.RLIMIT_NOFILE, (65536, 65536))
|
||||
except (ValueError, resource.error) as ex:
|
||||
print("Failed to raise file descriptor limit:", ex)
|
||||
print('Failed to raise file descriptor limit:', ex)
|
||||
|
||||
@ -16,13 +16,13 @@ class BaseTestCase(unittest.TestCase):
|
||||
def setUp(self): # NOQA
|
||||
|
||||
if len(component._ComponentRegistry.components) != 0:
|
||||
warnings.warn("The component._ComponentRegistry.components is not empty on test setup.\n"
|
||||
warnings.warn('The component._ComponentRegistry.components is not empty on test setup.\n'
|
||||
"This is probably caused by another test that didn't clean up after finishing!: %s" %
|
||||
component._ComponentRegistry.components)
|
||||
d = maybeDeferred(self.set_up)
|
||||
|
||||
def on_setup_error(error):
|
||||
warnings.warn("Error caught in test setup!\n%s" % error.getTraceback())
|
||||
warnings.warn('Error caught in test setup!\n%s' % error.getTraceback())
|
||||
self.fail()
|
||||
|
||||
return d.addErrback(on_setup_error)
|
||||
@ -31,7 +31,7 @@ class BaseTestCase(unittest.TestCase):
|
||||
d = maybeDeferred(self.tear_down)
|
||||
|
||||
def on_teardown_failed(error):
|
||||
warnings.warn("Error caught in test teardown!\n%s" % error.getTraceback())
|
||||
warnings.warn('Error caught in test teardown!\n%s' % error.getTraceback())
|
||||
self.fail()
|
||||
|
||||
def on_teardown_complete(result):
|
||||
|
||||
@ -26,11 +26,11 @@ from deluge.error import DelugeError
|
||||
from deluge.ui.util import lang
|
||||
|
||||
# This sets log level to critical, so use log.critical() to debug while running unit tests
|
||||
deluge.log.setup_logger("none")
|
||||
deluge.log.setup_logger('none')
|
||||
|
||||
|
||||
def disable_new_release_check():
|
||||
deluge.core.preferencesmanager.DEFAULT_PREFS["new_release_check"] = False
|
||||
deluge.core.preferencesmanager.DEFAULT_PREFS['new_release_check'] = False
|
||||
|
||||
|
||||
def set_tmp_config_dir():
|
||||
@ -39,24 +39,24 @@ def set_tmp_config_dir():
|
||||
return config_directory
|
||||
|
||||
|
||||
def setup_test_logger(level="info", prefix="deluge"):
|
||||
deluge.log.setup_logger(level, filename="%s.log" % prefix, twisted_observer=False)
|
||||
def setup_test_logger(level='info', prefix='deluge'):
|
||||
deluge.log.setup_logger(level, filename='%s.log' % prefix, twisted_observer=False)
|
||||
|
||||
|
||||
def get_test_data_file(filename):
|
||||
return os.path.join(os.path.join(os.path.dirname(__file__), "data"), filename)
|
||||
return os.path.join(os.path.join(os.path.dirname(__file__), 'data'), filename)
|
||||
|
||||
|
||||
def todo_test(caller):
|
||||
# If we are using the delugereporter we can set todo mark on the test
|
||||
# Without the delugereporter the todo would print a stack trace, so in
|
||||
# that case we rely only on skipTest
|
||||
if os.environ.get("DELUGE_REPORTER", None):
|
||||
getattr(caller, caller._testMethodName).__func__.todo = "To be fixed"
|
||||
if os.environ.get('DELUGE_REPORTER', None):
|
||||
getattr(caller, caller._testMethodName).__func__.todo = 'To be fixed'
|
||||
|
||||
filename = os.path.basename(traceback.extract_stack(None, 2)[0][0])
|
||||
funcname = traceback.extract_stack(None, 2)[0][2]
|
||||
raise unittest.SkipTest("TODO: %s:%s" % (filename, funcname))
|
||||
raise unittest.SkipTest('TODO: %s:%s' % (filename, funcname))
|
||||
|
||||
|
||||
def add_watchdog(deferred, timeout=0.05, message=None):
|
||||
@ -85,9 +85,9 @@ class ReactorOverride(object):
|
||||
"""
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == "run":
|
||||
if attr == 'run':
|
||||
return self._run
|
||||
if attr == "stop":
|
||||
if attr == 'stop':
|
||||
return self._stop
|
||||
return getattr(reactor, attr)
|
||||
|
||||
@ -115,8 +115,8 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
|
||||
"""
|
||||
self.callbacks = callbacks
|
||||
self.script = script
|
||||
self.log_output = ""
|
||||
self.stderr_out = ""
|
||||
self.log_output = ''
|
||||
self.stderr_out = ''
|
||||
self.logfile = logfile
|
||||
self.print_stderr = print_stderr
|
||||
self.quit_d = None
|
||||
@ -163,24 +163,24 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
|
||||
else:
|
||||
self.quit_d.errback(status)
|
||||
|
||||
def check_callbacks(self, data, cb_type="stdout"):
|
||||
def check_callbacks(self, data, cb_type='stdout'):
|
||||
ret = False
|
||||
for c in self.callbacks:
|
||||
if cb_type not in c["types"] or c["deferred"].called:
|
||||
if cb_type not in c['types'] or c['deferred'].called:
|
||||
continue
|
||||
for trigger in c["triggers"]:
|
||||
if trigger["expr"] in data:
|
||||
for trigger in c['triggers']:
|
||||
if trigger['expr'] in data:
|
||||
ret = True
|
||||
if "cb" in trigger:
|
||||
trigger["cb"](self, c["deferred"], data, self.log_output)
|
||||
elif "value" not in trigger:
|
||||
if 'cb' in trigger:
|
||||
trigger['cb'](self, c['deferred'], data, self.log_output)
|
||||
elif 'value' not in trigger:
|
||||
raise Exception("Trigger must specify either 'cb' or 'value'")
|
||||
else:
|
||||
val = trigger["value"](self, data, self.log_output)
|
||||
if trigger.get("type", "callback") == "errback":
|
||||
c["deferred"].errback(val)
|
||||
val = trigger['value'](self, data, self.log_output)
|
||||
if trigger.get('type', 'callback') == 'errback':
|
||||
c['deferred'].errback(val)
|
||||
else:
|
||||
c["deferred"].callback(val)
|
||||
c['deferred'].callback(val)
|
||||
return ret
|
||||
|
||||
def outReceived(self, data): # NOQA
|
||||
@ -195,16 +195,16 @@ class ProcessOutputHandler(protocol.ProcessProtocol):
|
||||
"""Process output from stderr"""
|
||||
self.log_output += data
|
||||
self.stderr_out += data
|
||||
self.check_callbacks(data, cb_type="stderr")
|
||||
self.check_callbacks(data, cb_type='stderr')
|
||||
if not self.print_stderr:
|
||||
return
|
||||
data = "\n%s" % data.strip()
|
||||
prefixed = data.replace("\n", "\nSTDERR: ")
|
||||
print("\n%s" % prefixed)
|
||||
data = '\n%s' % data.strip()
|
||||
prefixed = data.replace('\n', '\nSTDERR: ')
|
||||
print('\n%s' % prefixed)
|
||||
|
||||
|
||||
def start_core(listen_port=58846, logfile=None, timeout=10, timeout_msg=None,
|
||||
custom_script="", print_stderr=True, extra_callbacks=None):
|
||||
custom_script='', print_stderr=True, extra_callbacks=None):
|
||||
"""Start the deluge core as a daemon.
|
||||
|
||||
Args:
|
||||
@ -240,18 +240,18 @@ except:
|
||||
sys.stderr.write("Exception raised:\\n %%s" %% traceback.format_exc())
|
||||
""" % (config_directory, listen_port, custom_script)
|
||||
callbacks = []
|
||||
default_core_cb = {"deferred": Deferred(), "types": "stdout"}
|
||||
default_core_cb = {'deferred': Deferred(), 'types': 'stdout'}
|
||||
if timeout:
|
||||
default_core_cb["timeout"] = timeout
|
||||
default_core_cb['timeout'] = timeout
|
||||
|
||||
# Specify the triggers for daemon log output
|
||||
default_core_cb["triggers"] = [
|
||||
{"expr": "Finished loading ", "value": lambda reader, data, data_all: reader},
|
||||
{"expr": "Couldn't listen on localhost:%d" % (listen_port), "type": "errback", # Error from libtorrent
|
||||
"value": lambda reader, data, data_all: CannotListenError("localhost", listen_port,
|
||||
"Could not start deluge test client!\n%s" % data)},
|
||||
{"expr": "Traceback", "type": "errback",
|
||||
"value": lambda reader, data, data_all: DelugeError("Traceback found when starting daemon:\n%s" % data)}
|
||||
default_core_cb['triggers'] = [
|
||||
{'expr': 'Finished loading ', 'value': lambda reader, data, data_all: reader},
|
||||
{'expr': "Couldn't listen on localhost:%d" % (listen_port), 'type': 'errback', # Error from libtorrent
|
||||
'value': lambda reader, data, data_all: CannotListenError('localhost', listen_port,
|
||||
'Could not start deluge test client!\n%s' % data)},
|
||||
{'expr': 'Traceback', 'type': 'errback',
|
||||
'value': lambda reader, data, data_all: DelugeError('Traceback found when starting daemon:\n%s' % data)}
|
||||
]
|
||||
|
||||
callbacks.append(default_core_cb)
|
||||
@ -259,7 +259,7 @@ except:
|
||||
callbacks.extend(extra_callbacks)
|
||||
|
||||
process_protocol = start_process(daemon_script, callbacks, logfile, print_stderr)
|
||||
return default_core_cb["deferred"], process_protocol
|
||||
return default_core_cb['deferred'], process_protocol
|
||||
|
||||
|
||||
def start_process(script, callbacks, logfile=None, print_stderr=True):
|
||||
@ -291,8 +291,8 @@ def start_process(script, callbacks, logfile=None, print_stderr=True):
|
||||
|
||||
# Add timeouts to deferreds
|
||||
for c in callbacks:
|
||||
if "timeout" in c:
|
||||
w = add_watchdog(c["deferred"], timeout=c["timeout"], message=c.get("timeout_msg", None))
|
||||
if 'timeout' in c:
|
||||
w = add_watchdog(c['deferred'], timeout=c['timeout'], message=c.get('timeout_msg', None))
|
||||
process_protocol.watchdogs.append(w)
|
||||
|
||||
reactor.spawnProcess(process_protocol, sys.executable, args=[sys.executable], path=cwd)
|
||||
|
||||
@ -29,9 +29,9 @@ class ReactorOverride(object):
|
||||
|
||||
"""
|
||||
def __getattr__(self, attr):
|
||||
if attr == "run":
|
||||
if attr == 'run':
|
||||
return self._run
|
||||
if attr == "stop":
|
||||
if attr == 'stop':
|
||||
return self._stop
|
||||
return getattr(reactor, attr)
|
||||
|
||||
@ -59,14 +59,14 @@ class WebServerTestBase(BaseTestCase, DaemonBase):
|
||||
self.webserver_listen_port = 8999
|
||||
|
||||
config_defaults = deluge.ui.web.server.CONFIG_DEFAULTS.copy()
|
||||
config_defaults["port"] = self.webserver_listen_port
|
||||
self.config = configmanager.ConfigManager("web.conf", config_defaults)
|
||||
config_defaults['port'] = self.webserver_listen_port
|
||||
self.config = configmanager.ConfigManager('web.conf', config_defaults)
|
||||
|
||||
self.deluge_web = DelugeWeb(daemon=False)
|
||||
|
||||
host = list(self.deluge_web.web_api.host_list["hosts"][0])
|
||||
host = list(self.deluge_web.web_api.host_list['hosts'][0])
|
||||
host[2] = self.listen_port
|
||||
self.deluge_web.web_api.host_list["hosts"][0] = tuple(host)
|
||||
self.deluge_web.web_api.host_list['hosts'][0] = tuple(host)
|
||||
self.host_id = host[0]
|
||||
self.deluge_web.start()
|
||||
|
||||
@ -86,11 +86,11 @@ class WebServerMockBase(object):
|
||||
def check_request(request, method=None, level=None):
|
||||
pass
|
||||
|
||||
self.patch(auth, "check_request", check_request)
|
||||
self.patch(auth, 'check_request', check_request)
|
||||
|
||||
def mock_compress_body(self):
|
||||
|
||||
def compress(contents, request):
|
||||
return contents
|
||||
# Patch compress to avoid having to decompress output with zlib
|
||||
self.patch(deluge.ui.web.json_api, "compress", compress)
|
||||
self.patch(deluge.ui.web.json_api, 'compress', compress)
|
||||
|
||||
@ -21,21 +21,21 @@ class DaemonBase(object):
|
||||
|
||||
def terminate_core(self, *args):
|
||||
if args[0] is not None:
|
||||
if hasattr(args[0], "getTraceback"):
|
||||
print("terminate_core: Errback Exception: %s" % args[0].getTraceback())
|
||||
if hasattr(args[0], 'getTraceback'):
|
||||
print('terminate_core: Errback Exception: %s' % args[0].getTraceback())
|
||||
|
||||
if not self.core.killed:
|
||||
d = self.core.kill()
|
||||
return d
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def start_core(self, arg, custom_script="", logfile="", print_stderr=True, timeout=5,
|
||||
def start_core(self, arg, custom_script='', logfile='', print_stderr=True, timeout=5,
|
||||
port_range=10, extra_callbacks=None):
|
||||
if logfile == "":
|
||||
logfile = "daemon_%s.log" % self.id()
|
||||
if logfile == '':
|
||||
logfile = 'daemon_%s.log' % self.id()
|
||||
|
||||
# We are running py.test
|
||||
if hasattr(pytest, "config"):
|
||||
if hasattr(pytest, 'config'):
|
||||
# Put log file in the py.test --basetemp argument
|
||||
basetemp = pytest.config.option.basetemp
|
||||
if basetemp:
|
||||
@ -46,7 +46,7 @@ class DaemonBase(object):
|
||||
for dummy in range(port_range):
|
||||
try:
|
||||
d, self.core = common.start_core(listen_port=self.listen_port, logfile=logfile,
|
||||
timeout=timeout, timeout_msg="Timeout!",
|
||||
timeout=timeout, timeout_msg='Timeout!',
|
||||
custom_script=custom_script,
|
||||
print_stderr=print_stderr,
|
||||
extra_callbacks=extra_callbacks)
|
||||
|
||||
@ -15,8 +15,8 @@ class AlertManagerTestCase(BaseTestCase):
|
||||
|
||||
def set_up(self):
|
||||
self.core = Core()
|
||||
self.am = component.get("AlertManager")
|
||||
return component.start(["AlertManager"])
|
||||
self.am = component.get('AlertManager')
|
||||
return component.start(['AlertManager'])
|
||||
|
||||
def tear_down(self):
|
||||
return component.shutdown()
|
||||
@ -25,13 +25,13 @@ class AlertManagerTestCase(BaseTestCase):
|
||||
def handler(alert):
|
||||
return
|
||||
|
||||
self.am.register_handler("dummy_alert", handler)
|
||||
self.assertEquals(self.am.handlers["dummy_alert"], [handler])
|
||||
self.am.register_handler('dummy_alert', handler)
|
||||
self.assertEquals(self.am.handlers['dummy_alert'], [handler])
|
||||
|
||||
def test_deregister_handler(self):
|
||||
def handler(alert):
|
||||
return
|
||||
|
||||
self.am.register_handler("dummy_alert", handler)
|
||||
self.am.register_handler('dummy_alert', handler)
|
||||
self.am.deregister_handler(handler)
|
||||
self.assertEquals(self.am.handlers["dummy_alert"], [])
|
||||
self.assertEquals(self.am.handlers['dummy_alert'], [])
|
||||
|
||||
@ -20,7 +20,7 @@ from .daemon_base import DaemonBase
|
||||
class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy):
|
||||
def authenticate(self, username, password):
|
||||
self.login_deferred = defer.Deferred()
|
||||
d = self.call("daemon.login", username, password)
|
||||
d = self.call('daemon.login', username, password)
|
||||
d.addCallback(self.__on_login, username)
|
||||
d.addErrback(self.__on_login_fail)
|
||||
return self.login_deferred
|
||||
@ -34,7 +34,7 @@ class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy):
|
||||
|
||||
class NoVersionSendingClient(Client):
|
||||
|
||||
def connect(self, host="127.0.0.1", port=58846, username="", password="",
|
||||
def connect(self, host='127.0.0.1', port=58846, username='', password='',
|
||||
skip_authentication=False):
|
||||
self._daemon_proxy = NoVersionSendingDaemonSSLProxy()
|
||||
self._daemon_proxy.set_disconnect_callback(self.__on_disconnect)
|
||||
@ -85,7 +85,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
return d
|
||||
|
||||
def test_connect_no_credentials(self):
|
||||
d = client.connect("localhost", self.listen_port, username="", password="")
|
||||
d = client.connect('localhost', self.listen_port, username='', password='')
|
||||
|
||||
def on_connect(result):
|
||||
self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN)
|
||||
@ -97,7 +97,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
|
||||
def test_connect_localclient(self):
|
||||
username, password = deluge.ui.common.get_localhost_auth()
|
||||
d = client.connect("localhost", self.listen_port, username=username, password=password)
|
||||
d = client.connect('localhost', self.listen_port, username=username, password=password)
|
||||
|
||||
def on_connect(result):
|
||||
self.assertEqual(client.get_auth_level(), AUTH_LEVEL_ADMIN)
|
||||
@ -109,14 +109,14 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
|
||||
def test_connect_bad_password(self):
|
||||
username, password = deluge.ui.common.get_localhost_auth()
|
||||
d = client.connect("localhost", self.listen_port, username=username, password=password + "1")
|
||||
d = client.connect('localhost', self.listen_port, username=username, password=password + '1')
|
||||
|
||||
def on_failure(failure):
|
||||
self.assertEqual(
|
||||
failure.trap(error.BadLoginError),
|
||||
error.BadLoginError
|
||||
)
|
||||
self.assertEquals(failure.value.message, "Password does not match")
|
||||
self.assertEquals(failure.value.message, 'Password does not match')
|
||||
self.addCleanup(client.disconnect)
|
||||
|
||||
d.addCallbacks(self.fail, on_failure)
|
||||
@ -124,14 +124,14 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
|
||||
def test_connect_invalid_user(self):
|
||||
username, password = deluge.ui.common.get_localhost_auth()
|
||||
d = client.connect("localhost", self.listen_port, username="invalid-user")
|
||||
d = client.connect('localhost', self.listen_port, username='invalid-user')
|
||||
|
||||
def on_failure(failure):
|
||||
self.assertEqual(
|
||||
failure.trap(error.BadLoginError),
|
||||
error.BadLoginError
|
||||
)
|
||||
self.assertEquals(failure.value.message, "Username does not exist")
|
||||
self.assertEquals(failure.value.message, 'Username does not exist')
|
||||
self.addCleanup(client.disconnect)
|
||||
|
||||
d.addCallbacks(self.fail, on_failure)
|
||||
@ -139,7 +139,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
|
||||
def test_connect_without_password(self):
|
||||
username, password = deluge.ui.common.get_localhost_auth()
|
||||
d = client.connect("localhost", self.listen_port, username=username)
|
||||
d = client.connect('localhost', self.listen_port, username=username)
|
||||
|
||||
def on_failure(failure):
|
||||
self.assertEqual(
|
||||
@ -155,16 +155,16 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
@defer.inlineCallbacks
|
||||
def test_connect_with_password(self):
|
||||
username, password = deluge.ui.common.get_localhost_auth()
|
||||
yield client.connect("localhost", self.listen_port, username=username, password=password)
|
||||
yield client.core.create_account("testuser", "testpw", "DEFAULT")
|
||||
yield client.connect('localhost', self.listen_port, username=username, password=password)
|
||||
yield client.core.create_account('testuser', 'testpw', 'DEFAULT')
|
||||
yield client.disconnect()
|
||||
ret = yield client.connect("localhost", self.listen_port, username="testuser", password="testpw")
|
||||
ret = yield client.connect('localhost', self.listen_port, username='testuser', password='testpw')
|
||||
self.assertEquals(ret, deluge.common.AUTH_LEVEL_NORMAL)
|
||||
yield
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def test_invalid_rpc_method_call(self):
|
||||
yield client.connect("localhost", self.listen_port, username="", password="")
|
||||
yield client.connect('localhost', self.listen_port, username='', password='')
|
||||
d = client.core.invalid_method()
|
||||
|
||||
def on_failure(failure):
|
||||
@ -177,7 +177,7 @@ class ClientTestCase(BaseTestCase, DaemonBase):
|
||||
username, password = deluge.ui.common.get_localhost_auth()
|
||||
no_version_sending_client = NoVersionSendingClient()
|
||||
d = no_version_sending_client.connect(
|
||||
"localhost", self.listen_port, username=username, password=password
|
||||
'localhost', self.listen_port, username=username, password=password
|
||||
)
|
||||
|
||||
def on_failure(failure):
|
||||
|
||||
@ -15,95 +15,95 @@ class CommonTestCase(unittest.TestCase):
|
||||
pass
|
||||
|
||||
def test_fsize(self):
|
||||
self.assertEquals(fsize(0), "0 B")
|
||||
self.assertEquals(fsize(100), "100 B")
|
||||
self.assertEquals(fsize(1023), "1023 B")
|
||||
self.assertEquals(fsize(1024), "1.0 KiB")
|
||||
self.assertEquals(fsize(1048575), "1024.0 KiB")
|
||||
self.assertEquals(fsize(1048576), "1.0 MiB")
|
||||
self.assertEquals(fsize(1073741823), "1024.0 MiB")
|
||||
self.assertEquals(fsize(1073741824), "1.0 GiB")
|
||||
self.assertEquals(fsize(112245), "109.6 KiB")
|
||||
self.assertEquals(fsize(110723441824), "103.1 GiB")
|
||||
self.assertEquals(fsize(1099511627775), "1024.0 GiB")
|
||||
self.assertEquals(fsize(1099511627777), "1.0 TiB")
|
||||
self.assertEquals(fsize(766148267453245), "696.8 TiB")
|
||||
self.assertEquals(fsize(0), '0 B')
|
||||
self.assertEquals(fsize(100), '100 B')
|
||||
self.assertEquals(fsize(1023), '1023 B')
|
||||
self.assertEquals(fsize(1024), '1.0 KiB')
|
||||
self.assertEquals(fsize(1048575), '1024.0 KiB')
|
||||
self.assertEquals(fsize(1048576), '1.0 MiB')
|
||||
self.assertEquals(fsize(1073741823), '1024.0 MiB')
|
||||
self.assertEquals(fsize(1073741824), '1.0 GiB')
|
||||
self.assertEquals(fsize(112245), '109.6 KiB')
|
||||
self.assertEquals(fsize(110723441824), '103.1 GiB')
|
||||
self.assertEquals(fsize(1099511627775), '1024.0 GiB')
|
||||
self.assertEquals(fsize(1099511627777), '1.0 TiB')
|
||||
self.assertEquals(fsize(766148267453245), '696.8 TiB')
|
||||
|
||||
def test_fpcnt(self):
|
||||
self.failUnless(fpcnt(0.9311) == "93.11%")
|
||||
self.failUnless(fpcnt(0.9311) == '93.11%')
|
||||
|
||||
def test_fspeed(self):
|
||||
self.failUnless(fspeed(43134) == "42.1 KiB/s")
|
||||
self.failUnless(fspeed(43134) == '42.1 KiB/s')
|
||||
|
||||
def test_fpeer(self):
|
||||
self.failUnless(fpeer(10, 20) == "10 (20)")
|
||||
self.failUnless(fpeer(10, -1) == "10")
|
||||
self.failUnless(fpeer(10, 20) == '10 (20)')
|
||||
self.failUnless(fpeer(10, -1) == '10')
|
||||
|
||||
def test_ftime(self):
|
||||
self.failUnless(ftime(0) == "")
|
||||
self.failUnless(ftime(5) == "5s")
|
||||
self.failUnless(ftime(100) == "1m 40s")
|
||||
self.failUnless(ftime(3789) == "1h 3m")
|
||||
self.failUnless(ftime(23011) == "6h 23m")
|
||||
self.failUnless(ftime(391187) == "4d 12h")
|
||||
self.failUnless(ftime(604800) == "1w 0d")
|
||||
self.failUnless(ftime(13893086) == "22w 6d")
|
||||
self.failUnless(ftime(59740269) == "1y 46w")
|
||||
self.failUnless(ftime(0) == '')
|
||||
self.failUnless(ftime(5) == '5s')
|
||||
self.failUnless(ftime(100) == '1m 40s')
|
||||
self.failUnless(ftime(3789) == '1h 3m')
|
||||
self.failUnless(ftime(23011) == '6h 23m')
|
||||
self.failUnless(ftime(391187) == '4d 12h')
|
||||
self.failUnless(ftime(604800) == '1w 0d')
|
||||
self.failUnless(ftime(13893086) == '22w 6d')
|
||||
self.failUnless(ftime(59740269) == '1y 46w')
|
||||
|
||||
def test_fdate(self):
|
||||
self.failUnless(fdate(-1) == "")
|
||||
self.failUnless(fdate(-1) == '')
|
||||
|
||||
def test_is_url(self):
|
||||
self.failUnless(is_url("http://deluge-torrent.org"))
|
||||
self.failIf(is_url("file://test.torrent"))
|
||||
self.failUnless(is_url('http://deluge-torrent.org'))
|
||||
self.failIf(is_url('file://test.torrent'))
|
||||
|
||||
def test_is_magnet(self):
|
||||
self.failUnless(is_magnet("magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN"))
|
||||
self.failUnless(is_magnet('magnet:?xt=urn:btih:SU5225URMTUEQLDXQWRB2EQWN6KLTYKN'))
|
||||
|
||||
def test_is_infohash(self):
|
||||
self.failUnless(is_infohash("2dc5d0e71a66fe69649a640d39cb00a259704973"))
|
||||
self.failUnless(is_infohash('2dc5d0e71a66fe69649a640d39cb00a259704973'))
|
||||
|
||||
def test_get_path_size(self):
|
||||
self.failUnless(get_path_size(os.devnull) == 0)
|
||||
self.failUnless(get_path_size("non-existant.file") == -1)
|
||||
self.failUnless(get_path_size('non-existant.file') == -1)
|
||||
|
||||
def test_is_ip(self):
|
||||
self.failUnless(is_ip("127.0.0.1"))
|
||||
self.failIf(is_ip("127..0.0"))
|
||||
self.failUnless(is_ip('127.0.0.1'))
|
||||
self.failIf(is_ip('127..0.0'))
|
||||
|
||||
def test_version_split(self):
|
||||
self.failUnless(VersionSplit("1.2.2") == VersionSplit("1.2.2"))
|
||||
self.failUnless(VersionSplit("1.2.1") < VersionSplit("1.2.2"))
|
||||
self.failUnless(VersionSplit("1.1.9") < VersionSplit("1.2.2"))
|
||||
self.failUnless(VersionSplit("1.2.2") > VersionSplit("1.2.1"))
|
||||
self.failUnless(VersionSplit("1.2.2") < VersionSplit("1.2.2-dev"))
|
||||
self.failUnless(VersionSplit("1.2.2-dev") < VersionSplit("1.3.0-rc2"))
|
||||
self.failUnless(VersionSplit("1.2.2") > VersionSplit("1.2.2-rc2"))
|
||||
self.failUnless(VersionSplit("1.2.2-rc2-dev") > VersionSplit("1.2.2-rc2"))
|
||||
self.failUnless(VersionSplit("1.2.2-rc3") > VersionSplit("1.2.2-rc2"))
|
||||
self.failUnless(VersionSplit("0.14.9") == VersionSplit("0.14.9"))
|
||||
self.failUnless(VersionSplit("0.14.9") > VersionSplit("0.14.5"))
|
||||
self.failUnless(VersionSplit("0.14.10") >= VersionSplit("0.14.9"))
|
||||
self.failUnless(VersionSplit("1.4.0") > VersionSplit("1.3.900.dev123"))
|
||||
self.failUnless(VersionSplit("1.3.2rc2.dev1") < VersionSplit("1.3.2-rc2"))
|
||||
self.failUnless(VersionSplit("1.3.900.dev888") > VersionSplit("1.3.900.dev123"))
|
||||
self.failUnless(VersionSplit("1.4.0") > VersionSplit("1.4.0.dev123"))
|
||||
self.failUnless(VersionSplit("1.4.0.dev1") < VersionSplit("1.4.0"))
|
||||
self.failUnless(VersionSplit("1.4.0a1") < VersionSplit("1.4.0"))
|
||||
self.failUnless(VersionSplit('1.2.2') == VersionSplit('1.2.2'))
|
||||
self.failUnless(VersionSplit('1.2.1') < VersionSplit('1.2.2'))
|
||||
self.failUnless(VersionSplit('1.1.9') < VersionSplit('1.2.2'))
|
||||
self.failUnless(VersionSplit('1.2.2') > VersionSplit('1.2.1'))
|
||||
self.failUnless(VersionSplit('1.2.2') < VersionSplit('1.2.2-dev'))
|
||||
self.failUnless(VersionSplit('1.2.2-dev') < VersionSplit('1.3.0-rc2'))
|
||||
self.failUnless(VersionSplit('1.2.2') > VersionSplit('1.2.2-rc2'))
|
||||
self.failUnless(VersionSplit('1.2.2-rc2-dev') > VersionSplit('1.2.2-rc2'))
|
||||
self.failUnless(VersionSplit('1.2.2-rc3') > VersionSplit('1.2.2-rc2'))
|
||||
self.failUnless(VersionSplit('0.14.9') == VersionSplit('0.14.9'))
|
||||
self.failUnless(VersionSplit('0.14.9') > VersionSplit('0.14.5'))
|
||||
self.failUnless(VersionSplit('0.14.10') >= VersionSplit('0.14.9'))
|
||||
self.failUnless(VersionSplit('1.4.0') > VersionSplit('1.3.900.dev123'))
|
||||
self.failUnless(VersionSplit('1.3.2rc2.dev1') < VersionSplit('1.3.2-rc2'))
|
||||
self.failUnless(VersionSplit('1.3.900.dev888') > VersionSplit('1.3.900.dev123'))
|
||||
self.failUnless(VersionSplit('1.4.0') > VersionSplit('1.4.0.dev123'))
|
||||
self.failUnless(VersionSplit('1.4.0.dev1') < VersionSplit('1.4.0'))
|
||||
self.failUnless(VersionSplit('1.4.0a1') < VersionSplit('1.4.0'))
|
||||
|
||||
def test_parse_human_size(self):
|
||||
from deluge.common import parse_human_size
|
||||
sizes = [("1", 1),
|
||||
("10 bytes", 10),
|
||||
("2048 bytes", 2048),
|
||||
("1MiB", 2**(10 * 2)),
|
||||
("1 MiB", 2**(10 * 2)),
|
||||
("1 GiB", 2**(10 * 3)),
|
||||
("1 GiB", 2**(10 * 3)),
|
||||
("1M", 10**6),
|
||||
("1MB", 10**6),
|
||||
("1 GB", 10**9),
|
||||
("1 TB", 10**12)]
|
||||
sizes = [('1', 1),
|
||||
('10 bytes', 10),
|
||||
('2048 bytes', 2048),
|
||||
('1MiB', 2**(10 * 2)),
|
||||
('1 MiB', 2**(10 * 2)),
|
||||
('1 GiB', 2**(10 * 3)),
|
||||
('1 GiB', 2**(10 * 3)),
|
||||
('1M', 10**6),
|
||||
('1MB', 10**6),
|
||||
('1 GB', 10**9),
|
||||
('1 TB', 10**12)]
|
||||
|
||||
for human_size, byte_size in sizes:
|
||||
parsed = parse_human_size(human_size)
|
||||
|
||||
@ -69,41 +69,41 @@ class ComponentTestClass(BaseTestCase):
|
||||
|
||||
def test_start_component(self):
|
||||
def on_start(result, c):
|
||||
self.assertEquals(c._component_state, "Started")
|
||||
self.assertEquals(c._component_state, 'Started')
|
||||
self.assertEquals(c.start_count, 1)
|
||||
|
||||
c = ComponentTester("test_start_c1")
|
||||
d = component.start(["test_start_c1"])
|
||||
c = ComponentTester('test_start_c1')
|
||||
d = component.start(['test_start_c1'])
|
||||
d.addCallback(on_start, c)
|
||||
return d
|
||||
|
||||
def test_start_stop_depends(self):
|
||||
def on_stop(result, c1, c2):
|
||||
self.assertEquals(c1._component_state, "Stopped")
|
||||
self.assertEquals(c2._component_state, "Stopped")
|
||||
self.assertEquals(c1._component_state, 'Stopped')
|
||||
self.assertEquals(c2._component_state, 'Stopped')
|
||||
self.assertEquals(c1.stop_count, 1)
|
||||
self.assertEquals(c2.stop_count, 1)
|
||||
|
||||
def on_start(result, c1, c2):
|
||||
self.assertEquals(c1._component_state, "Started")
|
||||
self.assertEquals(c2._component_state, "Started")
|
||||
self.assertEquals(c1._component_state, 'Started')
|
||||
self.assertEquals(c2._component_state, 'Started')
|
||||
self.assertEquals(c1.start_count, 1)
|
||||
self.assertEquals(c2.start_count, 1)
|
||||
return component.stop(["test_start_depends_c1"]).addCallback(on_stop, c1, c2)
|
||||
return component.stop(['test_start_depends_c1']).addCallback(on_stop, c1, c2)
|
||||
|
||||
c1 = ComponentTester("test_start_depends_c1")
|
||||
c2 = ComponentTester("test_start_depends_c2", depend=["test_start_depends_c1"])
|
||||
c1 = ComponentTester('test_start_depends_c1')
|
||||
c2 = ComponentTester('test_start_depends_c2', depend=['test_start_depends_c1'])
|
||||
|
||||
d = component.start(["test_start_depends_c2"])
|
||||
d = component.start(['test_start_depends_c2'])
|
||||
d.addCallback(on_start, c1, c2)
|
||||
return d
|
||||
|
||||
def start_with_depends(self):
|
||||
c1 = ComponentTesterDelayStart("test_start_all_c1")
|
||||
c2 = ComponentTester("test_start_all_c2", depend=["test_start_all_c4"])
|
||||
c3 = ComponentTesterDelayStart("test_start_all_c3", depend=["test_start_all_c5", "test_start_all_c1"])
|
||||
c4 = ComponentTester("test_start_all_c4", depend=["test_start_all_c3"])
|
||||
c5 = ComponentTester("test_start_all_c5")
|
||||
c1 = ComponentTesterDelayStart('test_start_all_c1')
|
||||
c2 = ComponentTester('test_start_all_c2', depend=['test_start_all_c4'])
|
||||
c3 = ComponentTesterDelayStart('test_start_all_c3', depend=['test_start_all_c5', 'test_start_all_c1'])
|
||||
c4 = ComponentTester('test_start_all_c4', depend=['test_start_all_c3'])
|
||||
c5 = ComponentTester('test_start_all_c5')
|
||||
|
||||
d = component.start()
|
||||
return (d, c1, c2, c3, c4, c5)
|
||||
@ -115,7 +115,7 @@ class ComponentTestClass(BaseTestCase):
|
||||
def test_start_all(self):
|
||||
def on_start(*args):
|
||||
for c in args[1:]:
|
||||
self.assertEquals(c._component_state, "Started")
|
||||
self.assertEquals(c._component_state, 'Started')
|
||||
self.assertEquals(c.start_count, 1)
|
||||
|
||||
ret = self.start_with_depends()
|
||||
@ -124,36 +124,36 @@ class ComponentTestClass(BaseTestCase):
|
||||
return ret[0]
|
||||
|
||||
def test_register_exception(self):
|
||||
ComponentTester("test_register_exception_c1")
|
||||
ComponentTester('test_register_exception_c1')
|
||||
self.assertRaises(
|
||||
component.ComponentAlreadyRegistered,
|
||||
ComponentTester,
|
||||
"test_register_exception_c1")
|
||||
'test_register_exception_c1')
|
||||
|
||||
def test_stop_component(self):
|
||||
def on_stop(result, c):
|
||||
self.assertEquals(c._component_state, "Stopped")
|
||||
self.assertEquals(c._component_state, 'Stopped')
|
||||
self.assertFalse(c._component_timer.running)
|
||||
self.assertEquals(c.stop_count, 1)
|
||||
|
||||
def on_start(result, c):
|
||||
self.assertEquals(c._component_state, "Started")
|
||||
return component.stop(["test_stop_component_c1"]).addCallback(on_stop, c)
|
||||
self.assertEquals(c._component_state, 'Started')
|
||||
return component.stop(['test_stop_component_c1']).addCallback(on_stop, c)
|
||||
|
||||
c = ComponentTesterUpdate("test_stop_component_c1")
|
||||
d = component.start(["test_stop_component_c1"])
|
||||
c = ComponentTesterUpdate('test_stop_component_c1')
|
||||
d = component.start(['test_stop_component_c1'])
|
||||
d.addCallback(on_start, c)
|
||||
return d
|
||||
|
||||
def test_stop_all(self):
|
||||
def on_stop(result, *args):
|
||||
for c in args:
|
||||
self.assertEquals(c._component_state, "Stopped")
|
||||
self.assertEquals(c._component_state, 'Stopped')
|
||||
self.assertEquals(c.stop_count, 1)
|
||||
|
||||
def on_start(result, *args):
|
||||
for c in args:
|
||||
self.assertEquals(c._component_state, "Started")
|
||||
self.assertEquals(c._component_state, 'Started')
|
||||
return component.stop().addCallback(on_stop, *args)
|
||||
|
||||
ret = self.start_with_depends()
|
||||
@ -168,50 +168,50 @@ class ComponentTestClass(BaseTestCase):
|
||||
self.assertNotEqual(c1.counter, counter)
|
||||
return component.stop()
|
||||
|
||||
c1 = ComponentTesterUpdate("test_update_c1")
|
||||
c1 = ComponentTesterUpdate('test_update_c1')
|
||||
cnt = int(c1.counter)
|
||||
d = component.start(["test_update_c1"])
|
||||
d = component.start(['test_update_c1'])
|
||||
|
||||
d.addCallback(on_start, c1, cnt)
|
||||
return d
|
||||
|
||||
def test_pause(self):
|
||||
def on_pause(result, c1, counter):
|
||||
self.assertEqual(c1._component_state, "Paused")
|
||||
self.assertEqual(c1._component_state, 'Paused')
|
||||
self.assertNotEqual(c1.counter, counter)
|
||||
self.assertFalse(c1._component_timer.running)
|
||||
|
||||
def on_start(result, c1, counter):
|
||||
self.assertTrue(c1._component_timer)
|
||||
self.assertNotEqual(c1.counter, counter)
|
||||
d = component.pause(["test_pause_c1"])
|
||||
d = component.pause(['test_pause_c1'])
|
||||
d.addCallback(on_pause, c1, counter)
|
||||
return d
|
||||
|
||||
c1 = ComponentTesterUpdate("test_pause_c1")
|
||||
c1 = ComponentTesterUpdate('test_pause_c1')
|
||||
cnt = int(c1.counter)
|
||||
d = component.start(["test_pause_c1"])
|
||||
d = component.start(['test_pause_c1'])
|
||||
|
||||
d.addCallback(on_start, c1, cnt)
|
||||
return d
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def test_component_start_error(self):
|
||||
ComponentTesterUpdate("test_pause_c1")
|
||||
yield component.start(["test_pause_c1"])
|
||||
yield component.pause(["test_pause_c1"])
|
||||
test_comp = component.get("test_pause_c1")
|
||||
ComponentTesterUpdate('test_pause_c1')
|
||||
yield component.start(['test_pause_c1'])
|
||||
yield component.pause(['test_pause_c1'])
|
||||
test_comp = component.get('test_pause_c1')
|
||||
try:
|
||||
result = self.failureResultOf(test_comp._component_start())
|
||||
except AttributeError:
|
||||
raise SkipTest("This test requires trial failureResultOf() in Twisted version >= 13")
|
||||
raise SkipTest('This test requires trial failureResultOf() in Twisted version >= 13')
|
||||
self.assertEqual(result.check(component.ComponentException), component.ComponentException)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def test_start_paused_error(self):
|
||||
ComponentTesterUpdate("test_pause_c1")
|
||||
yield component.start(["test_pause_c1"])
|
||||
yield component.pause(["test_pause_c1"])
|
||||
ComponentTesterUpdate('test_pause_c1')
|
||||
yield component.start(['test_pause_c1'])
|
||||
yield component.pause(['test_pause_c1'])
|
||||
|
||||
# Deferreds that fail in component have to error handler which results in
|
||||
# twisted doing a log.err call which causes the test to fail.
|
||||
@ -223,12 +223,12 @@ class ComponentTestClass(BaseTestCase):
|
||||
[(defer.FAILURE,
|
||||
component.ComponentException("Trying to start a component ('%s') not in "
|
||||
"stopped state. Current state: '%s'" %
|
||||
("test_pause_c1", "Paused"), ""))])
|
||||
('test_pause_c1', 'Paused'), ''))])
|
||||
|
||||
def test_shutdown(self):
|
||||
def on_shutdown(result, c1):
|
||||
self.assertTrue(c1.shutdowned)
|
||||
self.assertEquals(c1._component_state, "Stopped")
|
||||
self.assertEquals(c1._component_state, 'Stopped')
|
||||
self.assertEquals(c1.stop_count, 1)
|
||||
|
||||
def on_start(result, c1):
|
||||
@ -236,7 +236,7 @@ class ComponentTestClass(BaseTestCase):
|
||||
d.addCallback(on_shutdown, c1)
|
||||
return d
|
||||
|
||||
c1 = ComponentTesterShutdown("test_shutdown_c1")
|
||||
d = component.start(["test_shutdown_c1"])
|
||||
c1 = ComponentTesterShutdown('test_shutdown_c1')
|
||||
d = component.start(['test_shutdown_c1'])
|
||||
d.addCallback(on_start, c1)
|
||||
return d
|
||||
|
||||
@ -10,7 +10,7 @@ from deluge.config import Config
|
||||
|
||||
from .common import set_tmp_config_dir
|
||||
|
||||
DEFAULTS = {"string": "foobar", "int": 1, "float": 0.435, "bool": True, "unicode": u"foobar"}
|
||||
DEFAULTS = {'string': 'foobar', 'int': 1, 'float': 0.435, 'bool': True, 'unicode': u'foobar'}
|
||||
|
||||
|
||||
class ConfigTestCase(unittest.TestCase):
|
||||
@ -18,102 +18,102 @@ class ConfigTestCase(unittest.TestCase):
|
||||
self.config_dir = set_tmp_config_dir()
|
||||
|
||||
def test_init(self):
|
||||
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
self.assertEquals(DEFAULTS, config.config)
|
||||
|
||||
config = Config("test.conf", config_dir=self.config_dir)
|
||||
config = Config('test.conf', config_dir=self.config_dir)
|
||||
self.assertEquals({}, config.config)
|
||||
|
||||
def test_set_get_item(self):
|
||||
config = Config("test.conf", config_dir=self.config_dir)
|
||||
config["foo"] = 1
|
||||
self.assertEquals(config["foo"], 1)
|
||||
self.assertRaises(ValueError, config.set_item, "foo", "bar")
|
||||
config = Config('test.conf', config_dir=self.config_dir)
|
||||
config['foo'] = 1
|
||||
self.assertEquals(config['foo'], 1)
|
||||
self.assertRaises(ValueError, config.set_item, 'foo', 'bar')
|
||||
|
||||
config["foo"] = 2
|
||||
self.assertEquals(config.get_item("foo"), 2)
|
||||
config['foo'] = 2
|
||||
self.assertEquals(config.get_item('foo'), 2)
|
||||
|
||||
config["foo"] = "3"
|
||||
self.assertEquals(config.get_item("foo"), 3)
|
||||
config['foo'] = '3'
|
||||
self.assertEquals(config.get_item('foo'), 3)
|
||||
|
||||
config["unicode"] = u"ВИДЕОФИЛЬМЫ"
|
||||
self.assertEquals(config["unicode"], u"ВИДЕОФИЛЬМЫ")
|
||||
config['unicode'] = u'ВИДЕОФИЛЬМЫ'
|
||||
self.assertEquals(config['unicode'], u'ВИДЕОФИЛЬМЫ')
|
||||
|
||||
config["unicode"] = "foostring"
|
||||
self.assertTrue(isinstance(config.get_item("unicode"), unicode))
|
||||
config['unicode'] = 'foostring'
|
||||
self.assertTrue(isinstance(config.get_item('unicode'), unicode))
|
||||
|
||||
config._save_timer.cancel()
|
||||
|
||||
def test_set_get_item_none(self):
|
||||
config = Config("test.conf", config_dir=self.config_dir)
|
||||
config = Config('test.conf', config_dir=self.config_dir)
|
||||
|
||||
config["foo"] = None
|
||||
self.assertIsNone(config["foo"])
|
||||
self.assertIsInstance(config["foo"], type(None))
|
||||
config['foo'] = None
|
||||
self.assertIsNone(config['foo'])
|
||||
self.assertIsInstance(config['foo'], type(None))
|
||||
|
||||
config["foo"] = 1
|
||||
self.assertEquals(config.get("foo"), 1)
|
||||
config['foo'] = 1
|
||||
self.assertEquals(config.get('foo'), 1)
|
||||
|
||||
config["foo"] = None
|
||||
self.assertIsNone(config["foo"])
|
||||
config['foo'] = None
|
||||
self.assertIsNone(config['foo'])
|
||||
|
||||
config["bar"] = None
|
||||
self.assertIsNone(config["bar"])
|
||||
config['bar'] = None
|
||||
self.assertIsNone(config['bar'])
|
||||
|
||||
config["bar"] = None
|
||||
self.assertIsNone(config["bar"])
|
||||
config['bar'] = None
|
||||
self.assertIsNone(config['bar'])
|
||||
|
||||
config._save_timer.cancel()
|
||||
|
||||
def test_get(self):
|
||||
config = Config("test.conf", config_dir=self.config_dir)
|
||||
config["foo"] = 1
|
||||
self.assertEquals(config.get("foo"), 1)
|
||||
self.assertEquals(config.get("foobar"), None)
|
||||
self.assertEquals(config.get("foobar", 2), 2)
|
||||
config["foobar"] = 5
|
||||
self.assertEquals(config.get("foobar", 2), 5)
|
||||
config = Config('test.conf', config_dir=self.config_dir)
|
||||
config['foo'] = 1
|
||||
self.assertEquals(config.get('foo'), 1)
|
||||
self.assertEquals(config.get('foobar'), None)
|
||||
self.assertEquals(config.get('foobar', 2), 2)
|
||||
config['foobar'] = 5
|
||||
self.assertEquals(config.get('foobar', 2), 5)
|
||||
|
||||
def test_load(self):
|
||||
def check_config():
|
||||
config = Config("test.conf", config_dir=self.config_dir)
|
||||
config = Config('test.conf', config_dir=self.config_dir)
|
||||
|
||||
self.assertEquals(config["string"], "foobar")
|
||||
self.assertEquals(config["float"], 0.435)
|
||||
self.assertEquals(config['string'], 'foobar')
|
||||
self.assertEquals(config['float'], 0.435)
|
||||
|
||||
# Test loading an old config from 1.1.x
|
||||
import pickle
|
||||
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file:
|
||||
with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
|
||||
pickle.dump(DEFAULTS, _file)
|
||||
|
||||
check_config()
|
||||
|
||||
# Test opening a previous 1.2 config file of just a json object
|
||||
import json
|
||||
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file:
|
||||
with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
|
||||
json.dump(DEFAULTS, _file, indent=2)
|
||||
|
||||
check_config()
|
||||
|
||||
# Test opening a previous 1.2 config file of having the format versions
|
||||
# as ints
|
||||
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file:
|
||||
_file.write(str(1) + "\n")
|
||||
_file.write(str(1) + "\n")
|
||||
with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
|
||||
_file.write(str(1) + '\n')
|
||||
_file.write(str(1) + '\n')
|
||||
json.dump(DEFAULTS, _file, indent=2)
|
||||
|
||||
check_config()
|
||||
|
||||
# Test the 1.2 config format
|
||||
version = {"format": 1, "file": 1}
|
||||
with open(os.path.join(self.config_dir, "test.conf"), "wb") as _file:
|
||||
version = {'format': 1, 'file': 1}
|
||||
with open(os.path.join(self.config_dir, 'test.conf'), 'wb') as _file:
|
||||
json.dump(version, _file, indent=2)
|
||||
json.dump(DEFAULTS, _file, indent=2)
|
||||
|
||||
check_config()
|
||||
|
||||
def test_save(self):
|
||||
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
# We do this twice because the first time we need to save the file to disk
|
||||
# and the second time we do a compare and we should not write
|
||||
ret = config.save()
|
||||
@ -121,23 +121,23 @@ class ConfigTestCase(unittest.TestCase):
|
||||
ret = config.save()
|
||||
self.assertTrue(ret)
|
||||
|
||||
config["string"] = "baz"
|
||||
config["int"] = 2
|
||||
config['string'] = 'baz'
|
||||
config['int'] = 2
|
||||
ret = config.save()
|
||||
self.assertTrue(ret)
|
||||
del config
|
||||
|
||||
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
self.assertEquals(config["string"], "baz")
|
||||
self.assertEquals(config["int"], 2)
|
||||
config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
self.assertEquals(config['string'], 'baz')
|
||||
self.assertEquals(config['int'], 2)
|
||||
|
||||
def test_save_timer(self):
|
||||
self.clock = task.Clock()
|
||||
deluge.config.callLater = self.clock.callLater
|
||||
|
||||
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
config["string"] = "baz"
|
||||
config["int"] = 2
|
||||
config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
config['string'] = 'baz'
|
||||
config['int'] = 2
|
||||
self.assertTrue(config._save_timer.active())
|
||||
|
||||
# Timeout set for 5 seconds in config, so lets move clock by 5 seconds
|
||||
@ -146,9 +146,9 @@ class ConfigTestCase(unittest.TestCase):
|
||||
def check_config(config):
|
||||
self.assertTrue(not config._save_timer.active())
|
||||
del config
|
||||
config = Config("test.conf", defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
self.assertEquals(config["string"], "baz")
|
||||
self.assertEquals(config["int"], 2)
|
||||
config = Config('test.conf', defaults=DEFAULTS, config_dir=self.config_dir)
|
||||
self.assertEquals(config['string'], 'baz')
|
||||
self.assertEquals(config['int'], 2)
|
||||
|
||||
check_config(config)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user