mirror of
https://github.com/correl/Transmission-XBMC.git
synced 2025-01-08 19:08:20 +00:00
Replaced transmissionrpc with stock 0.8 release
This commit is contained in:
parent
e357a254d6
commit
4b8a270714
8 changed files with 305 additions and 272 deletions
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
from transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT, STATUS, PRIORITY, RATIO_LIMIT, LOGGER
|
from transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT, PRIORITY, RATIO_LIMIT, LOGGER
|
||||||
from transmissionrpc.error import TransmissionError, HTTPHandlerError
|
from transmissionrpc.error import TransmissionError, HTTPHandlerError
|
||||||
from transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler
|
from transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler
|
||||||
from transmissionrpc.torrent import Torrent
|
from transmissionrpc.torrent import Torrent
|
||||||
|
@ -11,6 +11,6 @@ from transmissionrpc.client import Client
|
||||||
from transmissionrpc.utils import add_stdout_logger
|
from transmissionrpc.utils import add_stdout_logger
|
||||||
|
|
||||||
__author__ = u'Erik Svensson <erik.public@gmail.com>'
|
__author__ = u'Erik Svensson <erik.public@gmail.com>'
|
||||||
__version__ = u'0.7'
|
__version__ = u'0.8'
|
||||||
__copyright__ = u'Copyright (c) 2008-2010 Erik Svensson'
|
__copyright__ = u'Copyright (c) 2008-2011 Erik Svensson'
|
||||||
__license__ = u'MIT'
|
__license__ = u'MIT'
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import os, re, time
|
import re, time
|
||||||
import warnings
|
import urllib2, urlparse, base64
|
||||||
import httplib, urllib2, urlparse, base64
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
|
@ -41,56 +40,11 @@ def debug_httperror(error):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _urlparse(address):
|
|
||||||
"""
|
|
||||||
Mimic python 2.5+ urlparse.urlparse
|
|
||||||
"""
|
|
||||||
class ParsedResult(tuple):
|
|
||||||
def __init__(self, address = None):
|
|
||||||
self.scheme = ''
|
|
||||||
self.netloc = ''
|
|
||||||
self.path = ''
|
|
||||||
self.params = ''
|
|
||||||
self.query = ''
|
|
||||||
self.fragment = ''
|
|
||||||
self.username = None
|
|
||||||
self.password = None
|
|
||||||
self.hostname = None
|
|
||||||
self.port = None
|
|
||||||
|
|
||||||
if address:
|
|
||||||
self.parse(address)
|
|
||||||
def parse(self, address):
|
|
||||||
(
|
|
||||||
self.scheme,
|
|
||||||
self.netloc,
|
|
||||||
self.path,
|
|
||||||
self.params,
|
|
||||||
self.query,
|
|
||||||
self.fragment
|
|
||||||
) = urlparse.urlparse(address)
|
|
||||||
self.hostname = self.netloc
|
|
||||||
if '@' in self.netloc:
|
|
||||||
(login, self.hostname) = self.netloc.split('@')
|
|
||||||
if ':' in login:
|
|
||||||
(self.username, self.password) = login.split(':')
|
|
||||||
else:
|
|
||||||
self.username = login
|
|
||||||
if ':' in self.hostname:
|
|
||||||
(self.hostname, self.port) = self.hostname.split(':')
|
|
||||||
try:
|
|
||||||
self.port = int(self.port)
|
|
||||||
except:
|
|
||||||
self.port = None
|
|
||||||
|
|
||||||
result = ParsedResult(address)
|
|
||||||
return result
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Torrent ids
|
Torrent ids
|
||||||
|
|
||||||
Many functions in Client takes torrent id. A torrent id can either be id or
|
Many functions in Client takes torrent id. A torrent id can either be id or
|
||||||
hashString. When suppling multiple id's it is possible to use a list mixed
|
hashString. When supplying multiple id's it is possible to use a list mixed
|
||||||
with both id and hashString.
|
with both id and hashString.
|
||||||
|
|
||||||
Timeouts
|
Timeouts
|
||||||
|
@ -110,7 +64,7 @@ class Client(object):
|
||||||
self._query_timeout = float(timeout)
|
self._query_timeout = float(timeout)
|
||||||
else:
|
else:
|
||||||
self._query_timeout = DEFAULT_TIMEOUT
|
self._query_timeout = DEFAULT_TIMEOUT
|
||||||
urlo = _urlparse(address)
|
urlo = urlparse.urlparse(address)
|
||||||
if urlo.scheme == '':
|
if urlo.scheme == '':
|
||||||
base_url = 'http://' + address + ':' + str(port)
|
base_url = 'http://' + address + ':' + str(port)
|
||||||
self.url = base_url + '/transmission/rpc'
|
self.url = base_url + '/transmission/rpc'
|
||||||
|
@ -125,7 +79,7 @@ class Client(object):
|
||||||
password = urlo.password
|
password = urlo.password
|
||||||
elif urlo.username or urlo.password:
|
elif urlo.username or urlo.password:
|
||||||
LOGGER.warning('Either user or password missing, not using authentication.')
|
LOGGER.warning('Either user or password missing, not using authentication.')
|
||||||
if http_handler == None:
|
if http_handler is None:
|
||||||
self.http_handler = DefaultHTTPHandler()
|
self.http_handler = DefaultHTTPHandler()
|
||||||
else:
|
else:
|
||||||
if hasattr(http_handler, 'set_authentication') and hasattr(http_handler, 'request'):
|
if hasattr(http_handler, 'set_authentication') and hasattr(http_handler, 'request'):
|
||||||
|
@ -170,8 +124,9 @@ class Client(object):
|
||||||
Query Transmission through HTTP.
|
Query Transmission through HTTP.
|
||||||
"""
|
"""
|
||||||
headers = {'x-transmission-session-id': str(self.session_id)}
|
headers = {'x-transmission-session-id': str(self.session_id)}
|
||||||
|
result = {}
|
||||||
request_count = 0
|
request_count = 0
|
||||||
if timeout == None:
|
if timeout is None:
|
||||||
timeout = self._query_timeout
|
timeout = self._query_timeout
|
||||||
while True:
|
while True:
|
||||||
LOGGER.debug(json.dumps({'url': self.url, 'headers': headers, 'query': query, 'timeout': timeout}, indent=2))
|
LOGGER.debug(json.dumps({'url': self.url, 'headers': headers, 'query': query, 'timeout': timeout}, indent=2))
|
||||||
|
@ -192,7 +147,7 @@ class Client(object):
|
||||||
else:
|
else:
|
||||||
debug_httperror(error)
|
debug_httperror(error)
|
||||||
raise TransmissionError('Request failed.', error)
|
raise TransmissionError('Request failed.', error)
|
||||||
request_count = request_count + 1
|
request_count += 1
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _request(self, method, arguments=None, ids=None, require_ids=False, timeout=None):
|
def _request(self, method, arguments=None, ids=None, require_ids=False, timeout=None):
|
||||||
|
@ -201,7 +156,7 @@ class Client(object):
|
||||||
"""
|
"""
|
||||||
if not isinstance(method, (str, unicode)):
|
if not isinstance(method, (str, unicode)):
|
||||||
raise ValueError('request takes method as string')
|
raise ValueError('request takes method as string')
|
||||||
if arguments == None:
|
if arguments is None:
|
||||||
arguments = {}
|
arguments = {}
|
||||||
if not isinstance(arguments, dict):
|
if not isinstance(arguments, dict):
|
||||||
raise ValueError('request takes arguments as dict')
|
raise ValueError('request takes arguments as dict')
|
||||||
|
@ -264,7 +219,7 @@ class Client(object):
|
||||||
"""
|
"""
|
||||||
ids = []
|
ids = []
|
||||||
|
|
||||||
if args == None:
|
if args is None:
|
||||||
pass
|
pass
|
||||||
elif isinstance(args, (int, long)):
|
elif isinstance(args, (int, long)):
|
||||||
ids.append(args)
|
ids.append(args)
|
||||||
|
@ -298,7 +253,7 @@ class Client(object):
|
||||||
if not addition:
|
if not addition:
|
||||||
raise ValueError(u'Invalid torrent id, \"%s\"' % item)
|
raise ValueError(u'Invalid torrent id, \"%s\"' % item)
|
||||||
ids.extend(addition)
|
ids.extend(addition)
|
||||||
elif isinstance(args, (list)):
|
elif isinstance(args, list):
|
||||||
for item in args:
|
for item in args:
|
||||||
ids.extend(self._format_ids(item))
|
ids.extend(self._format_ids(item))
|
||||||
else:
|
else:
|
||||||
|
@ -312,14 +267,14 @@ class Client(object):
|
||||||
self.session.update(data)
|
self.session.update(data)
|
||||||
|
|
||||||
def _update_server_version(self):
|
def _update_server_version(self):
|
||||||
if self.server_version == None:
|
if self.server_version is None:
|
||||||
version_major = 1
|
version_major = 1
|
||||||
version_minor = 30
|
version_minor = 30
|
||||||
version_changeset = 0
|
version_changeset = 0
|
||||||
version_parser = re.compile('(\d).(\d+) \((\d+)\)')
|
version_parser = re.compile('(\d).(\d+) \((\d+)\)')
|
||||||
if hasattr(self.session, 'version'):
|
if hasattr(self.session, 'version'):
|
||||||
match = version_parser.match(self.session.version)
|
match = version_parser.match(self.session.version)
|
||||||
if (match):
|
if match:
|
||||||
version_major = int(match.group(1))
|
version_major = int(match.group(1))
|
||||||
version_minor = int(match.group(2))
|
version_minor = int(match.group(2))
|
||||||
version_changeset = match.group(3)
|
version_changeset = match.group(3)
|
||||||
|
@ -330,9 +285,12 @@ class Client(object):
|
||||||
"""
|
"""
|
||||||
Get the Transmission RPC version. Trying to deduct if the server don't have a version value.
|
Get the Transmission RPC version. Trying to deduct if the server don't have a version value.
|
||||||
"""
|
"""
|
||||||
if self.protocol_version == None:
|
if self.protocol_version is None:
|
||||||
|
# Ugly fix for 2.20 - 2.22 reporting rpc-version 11, but having new arguments
|
||||||
|
if self.server_version and (self.server_version[0] == 2 and self.server_version[1] in [20, 21, 22]):
|
||||||
|
self.protocol_version = 12
|
||||||
# Ugly fix for 2.12 reporting rpc-version 10, but having new arguments
|
# Ugly fix for 2.12 reporting rpc-version 10, but having new arguments
|
||||||
if (self.server_version and (self.server_version[0] == 2 and self.server_version[1] == 12)):
|
elif self.server_version and (self.server_version[0] == 2 and self.server_version[1] == 12):
|
||||||
self.protocol_version = 11
|
self.protocol_version = 11
|
||||||
elif hasattr(self.session, 'rpc_version'):
|
elif hasattr(self.session, 'rpc_version'):
|
||||||
self.protocol_version = self.session.rpc_version
|
self.protocol_version = self.session.rpc_version
|
||||||
|
@ -354,21 +312,21 @@ class Client(object):
|
||||||
Add torrent to transfers list. Takes a base64 encoded .torrent file in data.
|
Add torrent to transfers list. Takes a base64 encoded .torrent file in data.
|
||||||
Additional arguments are:
|
Additional arguments are:
|
||||||
|
|
||||||
===================== ==== =============================================================
|
===================== ===== =========== =============================================================
|
||||||
Argument RPC Description
|
Argument RPC Replaced by Description
|
||||||
===================== ==== =============================================================
|
===================== ===== =========== =============================================================
|
||||||
``bandwidthPriority`` 8 - Priority for this transfer.
|
``bandwidthPriority`` 8 - Priority for this transfer.
|
||||||
``download_dir`` 1 - The directory where the downloaded contents will be saved in.
|
``cookies`` 13 - One or more HTTP cookie(s).
|
||||||
``filename`` 1 - A filepath or URL to a torrent file or a magnet link.
|
``download_dir`` 1 - The directory where the downloaded contents will be saved in.
|
||||||
``files_unwanted`` 1 - A list of file id's that shouldn't be downloaded.
|
``files_unwanted`` 1 - A list of file id's that shouldn't be downloaded.
|
||||||
``files_wanted`` 1 - A list of file id's that should be downloaded.
|
``files_wanted`` 1 - A list of file id's that should be downloaded.
|
||||||
``metainfo`` 1 - The content of a torrent file, base64 encoded.
|
``paused`` 1 - If True, does not start the transfer when added.
|
||||||
``paused`` 1 - If True, does not start the transfer when added.
|
``peer_limit`` 1 - Maximum number of peers allowed.
|
||||||
``peer_limit`` 1 - Maximum number of peers allowed.
|
``priority_high`` 1 - A list of file id's that should have high priority.
|
||||||
``priority_high`` 1 - A list of file id's that should have high priority.
|
``priority_low`` 1 - A list of file id's that should have low priority.
|
||||||
``priority_low`` 1 - A list of file id's that should have low priority.
|
``priority_normal`` 1 - A list of file id's that should have normal priority.
|
||||||
``priority_normal`` 1 - A list of file id's that should have normal priority.
|
===================== ===== =========== =============================================================
|
||||||
===================== ==== =============================================================
|
|
||||||
"""
|
"""
|
||||||
args = {}
|
args = {}
|
||||||
if data:
|
if data:
|
||||||
|
@ -388,27 +346,28 @@ class Client(object):
|
||||||
all uri's supported by Transmissions torrent-add 'filename'
|
all uri's supported by Transmissions torrent-add 'filename'
|
||||||
argument. Additional arguments are:
|
argument. Additional arguments are:
|
||||||
|
|
||||||
===================== ==== =============================================================
|
===================== ===== =========== =============================================================
|
||||||
Argument RPC Description
|
Argument RPC Replaced by Description
|
||||||
===================== ==== =============================================================
|
===================== ===== =========== =============================================================
|
||||||
``bandwidthPriority`` 8 - Priority for this transfer.
|
``bandwidthPriority`` 8 - Priority for this transfer.
|
||||||
``download_dir`` 1 - The directory where the downloaded contents will be saved in.
|
``cookies`` 13 - One or more HTTP cookie(s).
|
||||||
``files_unwanted`` 1 - A list of file id's that shouldn't be downloaded.
|
``download_dir`` 1 - The directory where the downloaded contents will be saved in.
|
||||||
``files_wanted`` 1 - A list of file id's that should be downloaded.
|
``files_unwanted`` 1 - A list of file id's that shouldn't be downloaded.
|
||||||
``paused`` 1 - If True, does not start the transfer when added.
|
``files_wanted`` 1 - A list of file id's that should be downloaded.
|
||||||
``peer_limit`` 1 - Maximum number of peers allowed.
|
``paused`` 1 - If True, does not start the transfer when added.
|
||||||
``priority_high`` 1 - A list of file id's that should have high priority.
|
``peer_limit`` 1 - Maximum number of peers allowed.
|
||||||
``priority_low`` 1 - A list of file id's that should have low priority.
|
``priority_high`` 1 - A list of file id's that should have high priority.
|
||||||
``priority_normal`` 1 - A list of file id's that should have normal priority.
|
``priority_low`` 1 - A list of file id's that should have low priority.
|
||||||
===================== ==== =============================================================
|
``priority_normal`` 1 - A list of file id's that should have normal priority.
|
||||||
|
===================== ===== =========== =============================================================
|
||||||
"""
|
"""
|
||||||
if uri == None:
|
if uri is None:
|
||||||
raise ValueError('add_uri requires a URI.')
|
raise ValueError('add_uri requires a URI.')
|
||||||
# there has been some problem with T's built in torrent fetcher,
|
# there has been some problem with T's built in torrent fetcher,
|
||||||
# use a python one instead
|
# use a python one instead
|
||||||
parseduri = _urlparse(uri)
|
parsed_uri = urlparse.urlparse(uri)
|
||||||
torrent_data = None
|
torrent_data = None
|
||||||
if parseduri.scheme in ['file', 'ftp', 'ftps', 'http', 'https']:
|
if parsed_uri.scheme in ['file', 'ftp', 'ftps', 'http', 'https']:
|
||||||
torrent_file = urllib2.urlopen(uri)
|
torrent_file = urllib2.urlopen(uri)
|
||||||
torrent_data = base64.b64encode(torrent_file.read())
|
torrent_data = base64.b64encode(torrent_file.read())
|
||||||
if torrent_data:
|
if torrent_data:
|
||||||
|
@ -425,9 +384,12 @@ class Client(object):
|
||||||
self._request('torrent-remove',
|
self._request('torrent-remove',
|
||||||
{'delete-local-data':rpc_bool(delete_data)}, ids, True, timeout=timeout)
|
{'delete-local-data':rpc_bool(delete_data)}, ids, True, timeout=timeout)
|
||||||
|
|
||||||
def start(self, ids, timeout=None):
|
def start(self, ids, bypass_queue=False, timeout=None):
|
||||||
"""start torrent(s) with provided id(s)"""
|
"""start torrent(s) with provided id(s)"""
|
||||||
self._request('torrent-start', {}, ids, True, timeout=timeout)
|
method = 'torrent-start'
|
||||||
|
if bypass_queue and self.rpc_version >= 14:
|
||||||
|
method = 'torrent-start-now'
|
||||||
|
self._request(method, {}, ids, True, timeout=timeout)
|
||||||
|
|
||||||
def stop(self, ids, timeout=None):
|
def stop(self, ids, timeout=None):
|
||||||
"""stop torrent(s) with provided id(s)"""
|
"""stop torrent(s) with provided id(s)"""
|
||||||
|
@ -451,7 +413,7 @@ class Client(object):
|
||||||
def get_files(self, ids=None, timeout=None):
|
def get_files(self, ids=None, timeout=None):
|
||||||
"""
|
"""
|
||||||
Get list of files for provided torrent id(s). If ids is empty,
|
Get list of files for provided torrent id(s). If ids is empty,
|
||||||
information for all torrents are fetched. This function returns a dictonary
|
information for all torrents are fetched. This function returns a dictionary
|
||||||
for each requested torrent id holding the information about the files.
|
for each requested torrent id holding the information about the files.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -481,7 +443,7 @@ class Client(object):
|
||||||
|
|
||||||
def set_files(self, items, timeout=None):
|
def set_files(self, items, timeout=None):
|
||||||
"""
|
"""
|
||||||
Set file properties. Takes a dictonary with similar contents as the result
|
Set file properties. Takes a dictionary with similar contents as the result
|
||||||
of `get_files`.
|
of `get_files`.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -506,9 +468,9 @@ class Client(object):
|
||||||
continue
|
continue
|
||||||
wanted = []
|
wanted = []
|
||||||
unwanted = []
|
unwanted = []
|
||||||
priority_high = []
|
high = []
|
||||||
priority_normal = []
|
normal = []
|
||||||
priority_low = []
|
low = []
|
||||||
for fid, file_desc in files.iteritems():
|
for fid, file_desc in files.iteritems():
|
||||||
if not isinstance(file_desc, dict):
|
if not isinstance(file_desc, dict):
|
||||||
continue
|
continue
|
||||||
|
@ -518,22 +480,29 @@ class Client(object):
|
||||||
unwanted.append(fid)
|
unwanted.append(fid)
|
||||||
if 'priority' in file_desc:
|
if 'priority' in file_desc:
|
||||||
if file_desc['priority'] == 'high':
|
if file_desc['priority'] == 'high':
|
||||||
priority_high.append(fid)
|
high.append(fid)
|
||||||
elif file_desc['priority'] == 'normal':
|
elif file_desc['priority'] == 'normal':
|
||||||
priority_normal.append(fid)
|
normal.append(fid)
|
||||||
elif file_desc['priority'] == 'low':
|
elif file_desc['priority'] == 'low':
|
||||||
priority_low.append(fid)
|
low.append(fid)
|
||||||
self.change([tid], files_wanted = wanted
|
args = {
|
||||||
, files_unwanted = unwanted
|
'timeout': timeout,
|
||||||
, priority_high = priority_high
|
'files_wanted': wanted,
|
||||||
, priority_normal = priority_normal
|
'files_unwanted': unwanted,
|
||||||
, priority_low = priority_low, timeout=timeout)
|
}
|
||||||
|
if len(high) > 0:
|
||||||
|
args['priority_high'] = high
|
||||||
|
if len(normal) > 0:
|
||||||
|
args['priority_normal'] = normal
|
||||||
|
if len(low) > 0:
|
||||||
|
args['priority_low'] = low
|
||||||
|
self.change([tid], **args)
|
||||||
|
|
||||||
def list(self, timeout=None):
|
def list(self, timeout=None):
|
||||||
"""list all torrents"""
|
"""list all torrents"""
|
||||||
fields = ['id', 'hashString', 'name', 'sizeWhenDone', 'leftUntilDone'
|
fields = ['id', 'hashString', 'name', 'sizeWhenDone', 'leftUntilDone'
|
||||||
, 'eta', 'status', 'rateUpload', 'rateDownload', 'uploadedEver'
|
, 'eta', 'status', 'rateUpload', 'rateDownload', 'uploadedEver'
|
||||||
, 'downloadedEver']
|
, 'downloadedEver', 'uploadRatio']
|
||||||
return self._request('torrent-get', {'fields': fields}, timeout=timeout)
|
return self._request('torrent-get', {'fields': fields}, timeout=timeout)
|
||||||
|
|
||||||
def change(self, ids, timeout=None, **kwargs):
|
def change(self, ids, timeout=None, **kwargs):
|
||||||
|
@ -550,11 +519,12 @@ class Client(object):
|
||||||
``files_unwanted`` 1 - A list of file id's that shouldn't be downloaded.
|
``files_unwanted`` 1 - A list of file id's that shouldn't be downloaded.
|
||||||
``files_wanted`` 1 - A list of file id's that should be downloaded.
|
``files_wanted`` 1 - A list of file id's that should be downloaded.
|
||||||
``honorsSessionLimits`` 5 - Enables or disables the transfer to honour the upload limit set in the session.
|
``honorsSessionLimits`` 5 - Enables or disables the transfer to honour the upload limit set in the session.
|
||||||
``ids`` 1 - Local download location.
|
``location`` 1 - Local download location.
|
||||||
``peer_limit`` 1 - The peer limit for the torrents.
|
``peer_limit`` 1 - The peer limit for the torrents.
|
||||||
``priority_high`` 1 - A list of file id's that should have high priority.
|
``priority_high`` 1 - A list of file id's that should have high priority.
|
||||||
``priority_low`` 1 - A list of file id's that should have normal priority.
|
``priority_low`` 1 - A list of file id's that should have normal priority.
|
||||||
``priority_normal`` 1 - A list of file id's that should have low priority.
|
``priority_normal`` 1 - A list of file id's that should have low priority.
|
||||||
|
``queuePosition`` 14 - Position of this transfer in its queue.
|
||||||
``seedIdleLimit`` 10 - Seed inactivity limit in minutes.
|
``seedIdleLimit`` 10 - Seed inactivity limit in minutes.
|
||||||
``seedIdleMode`` 10 - Seed inactivity mode. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.
|
``seedIdleMode`` 10 - Seed inactivity mode. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.
|
||||||
``seedRatioLimit`` 5 - Seeding ratio.
|
``seedRatioLimit`` 5 - Seeding ratio.
|
||||||
|
@ -597,6 +567,26 @@ class Client(object):
|
||||||
args = {'location': location, 'move': False}
|
args = {'location': location, 'move': False}
|
||||||
self._request('torrent-set-location', args, ids, True, timeout=timeout)
|
self._request('torrent-set-location', args, ids, True, timeout=timeout)
|
||||||
|
|
||||||
|
def queue_top(self, ids, timeout=None):
|
||||||
|
"""Move transfer to the top of the queue."""
|
||||||
|
self._rpc_version_warning(14)
|
||||||
|
self._request('queue-move-top', ids=ids, require_ids=True, timeout=timeout)
|
||||||
|
|
||||||
|
def queue_bottom(self, ids, timeout=None):
|
||||||
|
"""Move transfer to the bottom of the queue."""
|
||||||
|
self._rpc_version_warning(14)
|
||||||
|
self._request('queue-move-bottom', ids=ids, require_ids=True, timeout=timeout)
|
||||||
|
|
||||||
|
def queue_up(self, ids, timeout=None):
|
||||||
|
"""Move transfer up in the queue."""
|
||||||
|
self._rpc_version_warning(14)
|
||||||
|
self._request('queue-move-up', ids=ids, require_ids=True, timeout=timeout)
|
||||||
|
|
||||||
|
def queue_down(self, ids, timeout=None):
|
||||||
|
"""Move transfer down in the queue."""
|
||||||
|
self._rpc_version_warning(14)
|
||||||
|
self._request('queue-move-down', ids=ids, require_ids=True, timeout=timeout)
|
||||||
|
|
||||||
def get_session(self, timeout=None):
|
def get_session(self, timeout=None):
|
||||||
"""Get session parameters"""
|
"""Get session parameters"""
|
||||||
self._request('session-get', timeout=timeout)
|
self._request('session-get', timeout=timeout)
|
||||||
|
@ -618,9 +608,12 @@ class Client(object):
|
||||||
``alt_speed_time_end`` 5 - Time when alternate speeds should be disabled. Minutes after midnight.
|
``alt_speed_time_end`` 5 - Time when alternate speeds should be disabled. Minutes after midnight.
|
||||||
``alt_speed_up`` 5 - Alternate session upload speed limit (in Kib/s).
|
``alt_speed_up`` 5 - Alternate session upload speed limit (in Kib/s).
|
||||||
``blocklist_enabled`` 5 - Enables the block list
|
``blocklist_enabled`` 5 - Enables the block list
|
||||||
|
``blocklist_url`` 11 - Location of the block list. Updated with blocklist-update.
|
||||||
``cache_size_mb`` 10 - The maximum size of the disk cache in MB
|
``cache_size_mb`` 10 - The maximum size of the disk cache in MB
|
||||||
``dht_enabled`` 6 - Enables DHT.
|
``dht_enabled`` 6 - Enables DHT.
|
||||||
``download_dir`` 1 - Set the session download directory.
|
``download_dir`` 1 - Set the session download directory.
|
||||||
|
``download_queue_enabled`` 14 - Enable parallel download restriction.
|
||||||
|
``download_queue_size`` 14 - Number of parallel downloads.
|
||||||
``encryption`` 1 - Set the session encryption mode, one of ``required``, ``preferred`` or ``tolerated``.
|
``encryption`` 1 - Set the session encryption mode, one of ``required``, ``preferred`` or ``tolerated``.
|
||||||
``idle_seeding_limit`` 10 - The default seed inactivity limit in minutes.
|
``idle_seeding_limit`` 10 - The default seed inactivity limit in minutes.
|
||||||
``idle_seeding_limit_enabled`` 10 - Enables the default seed inactivity limit
|
``idle_seeding_limit_enabled`` 10 - Enables the default seed inactivity limit
|
||||||
|
@ -636,9 +629,13 @@ class Client(object):
|
||||||
``pex_enabled`` 5 - Allowing PEX in public torrents.
|
``pex_enabled`` 5 - Allowing PEX in public torrents.
|
||||||
``port`` 1 - 5 peer-port Peer port.
|
``port`` 1 - 5 peer-port Peer port.
|
||||||
``port_forwarding_enabled`` 1 - Enables port forwarding.
|
``port_forwarding_enabled`` 1 - Enables port forwarding.
|
||||||
|
``queue_stalled_enabled`` 14 - Enable tracking of stalled transfers.
|
||||||
|
``queue_stalled_minutes`` 14 - Number of minutes of idle that marks a transfer as stalled.
|
||||||
``rename_partial_files`` 8 - Appends ".part" to incomplete files
|
``rename_partial_files`` 8 - Appends ".part" to incomplete files
|
||||||
``script_torrent_done_enabled`` 9 - Whether or not to call the "done" script.
|
``script_torrent_done_enabled`` 9 - Whether or not to call the "done" script.
|
||||||
``script_torrent_done_filename`` 9 - Filename of the script to run when the transfer is done.
|
``script_torrent_done_filename`` 9 - Filename of the script to run when the transfer is done.
|
||||||
|
``seed_queue_enabled`` 14 - Enable parallel upload restriction.
|
||||||
|
``seed_queue_size`` 14 - Number of parallel uploads.
|
||||||
``seedRatioLimit`` 5 - Seed ratio limit. 1.0 means 1:1 download and upload ratio.
|
``seedRatioLimit`` 5 - Seed ratio limit. 1.0 means 1:1 download and upload ratio.
|
||||||
``seedRatioLimited`` 5 - Enables seed ration limit.
|
``seedRatioLimited`` 5 - Enables seed ration limit.
|
||||||
``speed_limit_down`` 1 - Download speed limit (in Kib/s).
|
``speed_limit_down`` 1 - Download speed limit (in Kib/s).
|
||||||
|
@ -647,6 +644,7 @@ class Client(object):
|
||||||
``speed_limit_up_enabled`` 1 - Enables upload speed limiting.
|
``speed_limit_up_enabled`` 1 - Enables upload speed limiting.
|
||||||
``start_added_torrents`` 9 - Added torrents will be started right away.
|
``start_added_torrents`` 9 - Added torrents will be started right away.
|
||||||
``trash_original_torrent_files`` 9 - The .torrent file of added torrents will be deleted.
|
``trash_original_torrent_files`` 9 - The .torrent file of added torrents will be deleted.
|
||||||
|
``utp_enabled`` 13 - Enables Micro Transport Protocol (UTP).
|
||||||
================================ ===== ================= ==========================================================================================================================
|
================================ ===== ================= ==========================================================================================================================
|
||||||
|
|
||||||
.. NOTE::
|
.. NOTE::
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
@ -18,20 +18,6 @@ DEFAULT_PORT = 9091
|
||||||
|
|
||||||
DEFAULT_TIMEOUT = 30.0
|
DEFAULT_TIMEOUT = 30.0
|
||||||
|
|
||||||
TR_STATUS_CHECK_WAIT = (1<<0)
|
|
||||||
TR_STATUS_CHECK = (1<<1)
|
|
||||||
TR_STATUS_DOWNLOAD = (1<<2)
|
|
||||||
TR_STATUS_SEED = (1<<3)
|
|
||||||
TR_STATUS_STOPPED = (1<<4)
|
|
||||||
|
|
||||||
STATUS = mirror_dict({
|
|
||||||
'check pending' : TR_STATUS_CHECK_WAIT,
|
|
||||||
'checking' : TR_STATUS_CHECK,
|
|
||||||
'downloading' : TR_STATUS_DOWNLOAD,
|
|
||||||
'seeding' : TR_STATUS_SEED,
|
|
||||||
'stopped' : TR_STATUS_STOPPED,
|
|
||||||
})
|
|
||||||
|
|
||||||
TR_PRI_LOW = -1
|
TR_PRI_LOW = -1
|
||||||
TR_PRI_NORMAL = 0
|
TR_PRI_NORMAL = 0
|
||||||
TR_PRI_HIGH = 1
|
TR_PRI_HIGH = 1
|
||||||
|
@ -103,6 +89,7 @@ TORRENT_ARGS = {
|
||||||
'id': ('number', 1, None, None, None, ''),
|
'id': ('number', 1, None, None, None, ''),
|
||||||
'isFinished': ('boolean', 9, None, None, None, ''),
|
'isFinished': ('boolean', 9, None, None, None, ''),
|
||||||
'isPrivate': ('boolean', 1, None, None, None, ''),
|
'isPrivate': ('boolean', 1, None, None, None, ''),
|
||||||
|
'isStalled': ('boolean', 14, None, None, None, ''),
|
||||||
'lastAnnounceTime': ('number', 1, 7, None, None, ''),
|
'lastAnnounceTime': ('number', 1, 7, None, None, ''),
|
||||||
'lastScrapeTime': ('number', 1, 7, None, None, ''),
|
'lastScrapeTime': ('number', 1, 7, None, None, ''),
|
||||||
'leechers': ('number', 1, 7, None, None, ''),
|
'leechers': ('number', 1, 7, None, None, ''),
|
||||||
|
@ -119,13 +106,14 @@ TORRENT_ARGS = {
|
||||||
'peersConnected': ('number', 1, None, None, None, ''),
|
'peersConnected': ('number', 1, None, None, None, ''),
|
||||||
'peersFrom': ('object', 1, None, None, None, ''),
|
'peersFrom': ('object', 1, None, None, None, ''),
|
||||||
'peersGettingFromUs': ('number', 1, None, None, None, ''),
|
'peersGettingFromUs': ('number', 1, None, None, None, ''),
|
||||||
'peersKnown': ('number', 1, None, None, None, ''),
|
'peersKnown': ('number', 1, 13, None, None, ''),
|
||||||
'peersSendingToUs': ('number', 1, None, None, None, ''),
|
'peersSendingToUs': ('number', 1, None, None, None, ''),
|
||||||
'percentDone': ('double', 5, None, None, None, ''),
|
'percentDone': ('double', 5, None, None, None, ''),
|
||||||
'pieces': ('string', 5, None, None, None, ''),
|
'pieces': ('string', 5, None, None, None, ''),
|
||||||
'pieceCount': ('number', 1, None, None, None, ''),
|
'pieceCount': ('number', 1, None, None, None, ''),
|
||||||
'pieceSize': ('number', 1, None, None, None, ''),
|
'pieceSize': ('number', 1, None, None, None, ''),
|
||||||
'priorities': ('array', 1, None, None, None, ''),
|
'priorities': ('array', 1, None, None, None, ''),
|
||||||
|
'queuePosition': ('number', 14, None, None, None, ''),
|
||||||
'rateDownload': ('number', 1, None, None, None, ''),
|
'rateDownload': ('number', 1, None, None, None, ''),
|
||||||
'rateUpload': ('number', 1, None, None, None, ''),
|
'rateUpload': ('number', 1, None, None, None, ''),
|
||||||
'recheckProgress': ('double', 1, None, None, None, ''),
|
'recheckProgress': ('double', 1, None, None, None, ''),
|
||||||
|
@ -161,11 +149,12 @@ TORRENT_ARGS = {
|
||||||
'files-wanted': ('array', 1, None, None, None, "A list of file id's that should be downloaded."),
|
'files-wanted': ('array', 1, None, None, None, "A list of file id's that should be downloaded."),
|
||||||
'files-unwanted': ('array', 1, None, None, None, "A list of file id's that shouldn't be downloaded."),
|
'files-unwanted': ('array', 1, None, None, None, "A list of file id's that shouldn't be downloaded."),
|
||||||
'honorsSessionLimits': ('boolean', 5, None, None, None, "Enables or disables the transfer to honour the upload limit set in the session."),
|
'honorsSessionLimits': ('boolean', 5, None, None, None, "Enables or disables the transfer to honour the upload limit set in the session."),
|
||||||
'ids': ('array', 1, None, None, None, 'Local download location.'),
|
'location': ('array', 1, None, None, None, 'Local download location.'),
|
||||||
'peer-limit': ('number', 1, None, None, None, 'The peer limit for the torrents.'),
|
'peer-limit': ('number', 1, None, None, None, 'The peer limit for the torrents.'),
|
||||||
'priority-high': ('array', 1, None, None, None, "A list of file id's that should have high priority."),
|
'priority-high': ('array', 1, None, None, None, "A list of file id's that should have high priority."),
|
||||||
'priority-low': ('array', 1, None, None, None, "A list of file id's that should have normal priority."),
|
'priority-low': ('array', 1, None, None, None, "A list of file id's that should have normal priority."),
|
||||||
'priority-normal': ('array', 1, None, None, None, "A list of file id's that should have low priority."),
|
'priority-normal': ('array', 1, None, None, None, "A list of file id's that should have low priority."),
|
||||||
|
'queuePosition': ('number', 14, None, None, None, 'Position of this transfer in its queue.'),
|
||||||
'seedIdleLimit': ('number', 10, None, None, None, 'Seed inactivity limit in minutes.'),
|
'seedIdleLimit': ('number', 10, None, None, None, 'Seed inactivity limit in minutes.'),
|
||||||
'seedIdleMode': ('number', 10, None, None, None, 'Seed inactivity mode. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.'),
|
'seedIdleMode': ('number', 10, None, None, None, 'Seed inactivity mode. 0 = Use session limit, 1 = Use transfer limit, 2 = Disable limit.'),
|
||||||
'seedRatioLimit': ('double', 5, None, None, None, 'Seeding ratio.'),
|
'seedRatioLimit': ('double', 5, None, None, None, 'Seeding ratio.'),
|
||||||
|
@ -183,7 +172,8 @@ TORRENT_ARGS = {
|
||||||
'add': {
|
'add': {
|
||||||
'bandwidthPriority': ('number', 8, None, None, None, 'Priority for this transfer.'),
|
'bandwidthPriority': ('number', 8, None, None, None, 'Priority for this transfer.'),
|
||||||
'download-dir': ('string', 1, None, None, None, 'The directory where the downloaded contents will be saved in.'),
|
'download-dir': ('string', 1, None, None, None, 'The directory where the downloaded contents will be saved in.'),
|
||||||
'filename': ('string', 1, None, None, None, "A filepath or URL to a torrent file or a magnet link."),
|
'cookies': ('string', 13, None, None, None, 'One or more HTTP cookie(s).'),
|
||||||
|
'filename': ('string', 1, None, None, None, "A file path or URL to a torrent file or a magnet link."),
|
||||||
'files-wanted': ('array', 1, None, None, None, "A list of file id's that should be downloaded."),
|
'files-wanted': ('array', 1, None, None, None, "A list of file id's that should be downloaded."),
|
||||||
'files-unwanted': ('array', 1, None, None, None, "A list of file id's that shouldn't be downloaded."),
|
'files-unwanted': ('array', 1, None, None, None, "A list of file id's that shouldn't be downloaded."),
|
||||||
'metainfo': ('string', 1, None, None, None, 'The content of a torrent file, base64 encoded.'),
|
'metainfo': ('string', 1, None, None, None, 'The content of a torrent file, base64 encoded.'),
|
||||||
|
@ -212,6 +202,9 @@ SESSION_ARGS = {
|
||||||
"config-dir": ('string', 8, None, None, None, ''),
|
"config-dir": ('string', 8, None, None, None, ''),
|
||||||
"dht-enabled": ('boolean', 6, None, None, None, ''),
|
"dht-enabled": ('boolean', 6, None, None, None, ''),
|
||||||
"download-dir": ('string', 1, None, None, None, ''),
|
"download-dir": ('string', 1, None, None, None, ''),
|
||||||
|
"download-dir-free-space": ('number', 12, None, None, None, ''),
|
||||||
|
"download-queue-size": ('number', 14, None, None, None, ''),
|
||||||
|
"download-queue-enabled": ('boolean', 14, None, None, None, ''),
|
||||||
"encryption": ('string', 1, None, None, None, ''),
|
"encryption": ('string', 1, None, None, None, ''),
|
||||||
"idle-seeding-limit": ('number', 10, None, None, None, ''),
|
"idle-seeding-limit": ('number', 10, None, None, None, ''),
|
||||||
"idle-seeding-limit-enabled": ('boolean', 10, None, None, None, ''),
|
"idle-seeding-limit-enabled": ('boolean', 10, None, None, None, ''),
|
||||||
|
@ -227,6 +220,8 @@ SESSION_ARGS = {
|
||||||
"peer-port": ('number', 5, None, None, None, ''),
|
"peer-port": ('number', 5, None, None, None, ''),
|
||||||
"peer-port-random-on-start": ('boolean', 5, None, None, None, ''),
|
"peer-port-random-on-start": ('boolean', 5, None, None, None, ''),
|
||||||
"port-forwarding-enabled": ('boolean', 1, None, None, None, ''),
|
"port-forwarding-enabled": ('boolean', 1, None, None, None, ''),
|
||||||
|
"queue-stalled-minutes": ('number', 14, None, None, None, ''),
|
||||||
|
"queue-stalled-enabled": ('boolean', 14, None, None, None, ''),
|
||||||
"rename-partial-files": ('boolean', 8, None, None, None, ''),
|
"rename-partial-files": ('boolean', 8, None, None, None, ''),
|
||||||
"rpc-version": ('number', 4, None, None, None, ''),
|
"rpc-version": ('number', 4, None, None, None, ''),
|
||||||
"rpc-version-minimum": ('number', 4, None, None, None, ''),
|
"rpc-version-minimum": ('number', 4, None, None, None, ''),
|
||||||
|
@ -234,6 +229,8 @@ SESSION_ARGS = {
|
||||||
"script-torrent-done-filename": ('string', 9, None, None, None, ''),
|
"script-torrent-done-filename": ('string', 9, None, None, None, ''),
|
||||||
"seedRatioLimit": ('double', 5, None, None, None, ''),
|
"seedRatioLimit": ('double', 5, None, None, None, ''),
|
||||||
"seedRatioLimited": ('boolean', 5, None, None, None, ''),
|
"seedRatioLimited": ('boolean', 5, None, None, None, ''),
|
||||||
|
"seed-queue-size": ('number', 14, None, None, None, ''),
|
||||||
|
"seed-queue-enabled": ('boolean', 14, None, None, None, ''),
|
||||||
"speed-limit-down": ('number', 1, None, None, None, ''),
|
"speed-limit-down": ('number', 1, None, None, None, ''),
|
||||||
"speed-limit-down-enabled": ('boolean', 1, None, None, None, ''),
|
"speed-limit-down-enabled": ('boolean', 1, None, None, None, ''),
|
||||||
"speed-limit-up": ('number', 1, None, None, None, ''),
|
"speed-limit-up": ('number', 1, None, None, None, ''),
|
||||||
|
@ -241,6 +238,7 @@ SESSION_ARGS = {
|
||||||
"start-added-torrents": ('boolean', 9, None, None, None, ''),
|
"start-added-torrents": ('boolean', 9, None, None, None, ''),
|
||||||
"trash-original-torrent-files": ('boolean', 9, None, None, None, ''),
|
"trash-original-torrent-files": ('boolean', 9, None, None, None, ''),
|
||||||
'units': ('object', 10, None, None, None, ''),
|
'units': ('object', 10, None, None, None, ''),
|
||||||
|
'utp-enabled': ('boolean', 13, None, None, None, ''),
|
||||||
"version": ('string', 3, None, None, None, ''),
|
"version": ('string', 3, None, None, None, ''),
|
||||||
},
|
},
|
||||||
'set': {
|
'set': {
|
||||||
|
@ -252,10 +250,12 @@ SESSION_ARGS = {
|
||||||
"alt-speed-time-day": ('number', 5, None, None, None, 'Enables alternate speeds scheduling these days.'),
|
"alt-speed-time-day": ('number', 5, None, None, None, 'Enables alternate speeds scheduling these days.'),
|
||||||
"alt-speed-up": ('number', 5, None, None, None, 'Alternate session upload speed limit (in Kib/s).'),
|
"alt-speed-up": ('number', 5, None, None, None, 'Alternate session upload speed limit (in Kib/s).'),
|
||||||
"blocklist-enabled": ('boolean', 5, None, None, None, 'Enables the block list'),
|
"blocklist-enabled": ('boolean', 5, None, None, None, 'Enables the block list'),
|
||||||
"blocklist-url": ('string', 11, None, None, None, 'Location of the blocklist. Updated with blocklist-update.'),
|
"blocklist-url": ('string', 11, None, None, None, 'Location of the block list. Updated with blocklist-update.'),
|
||||||
"cache-size-mb": ('number', 10, None, None, None, 'The maximum size of the disk cache in MB'),
|
"cache-size-mb": ('number', 10, None, None, None, 'The maximum size of the disk cache in MB'),
|
||||||
"dht-enabled": ('boolean', 6, None, None, None, 'Enables DHT.'),
|
"dht-enabled": ('boolean', 6, None, None, None, 'Enables DHT.'),
|
||||||
"download-dir": ('string', 1, None, None, None, 'Set the session download directory.'),
|
"download-dir": ('string', 1, None, None, None, 'Set the session download directory.'),
|
||||||
|
"download-queue-size": ('number', 14, None, None, None, 'Number of parallel downloads.'),
|
||||||
|
"download-queue-enabled": ('boolean', 14, None, None, None, 'Enable parallel download restriction.'),
|
||||||
"encryption": ('string', 1, None, None, None, 'Set the session encryption mode, one of ``required``, ``preferred`` or ``tolerated``.'),
|
"encryption": ('string', 1, None, None, None, 'Set the session encryption mode, one of ``required``, ``preferred`` or ``tolerated``.'),
|
||||||
"idle-seeding-limit": ('number', 10, None, None, None, 'The default seed inactivity limit in minutes.'),
|
"idle-seeding-limit": ('number', 10, None, None, None, 'The default seed inactivity limit in minutes.'),
|
||||||
"idle-seeding-limit-enabled": ('boolean', 10, None, None, None, 'Enables the default seed inactivity limit'),
|
"idle-seeding-limit-enabled": ('boolean', 10, None, None, None, 'Enables the default seed inactivity limit'),
|
||||||
|
@ -272,8 +272,12 @@ SESSION_ARGS = {
|
||||||
"peer-port-random-on-start": ('boolean', 5, None, None, None, 'Enables randomized peer port on start of Transmission.'),
|
"peer-port-random-on-start": ('boolean', 5, None, None, None, 'Enables randomized peer port on start of Transmission.'),
|
||||||
"port-forwarding-enabled": ('boolean', 1, None, None, None, 'Enables port forwarding.'),
|
"port-forwarding-enabled": ('boolean', 1, None, None, None, 'Enables port forwarding.'),
|
||||||
"rename-partial-files": ('boolean', 8, None, None, None, 'Appends ".part" to incomplete files'),
|
"rename-partial-files": ('boolean', 8, None, None, None, 'Appends ".part" to incomplete files'),
|
||||||
|
"queue-stalled-minutes": ('number', 14, None, None, None, 'Number of minutes of idle that marks a transfer as stalled.'),
|
||||||
|
"queue-stalled-enabled": ('boolean', 14, None, None, None, 'Enable tracking of stalled transfers.'),
|
||||||
"script-torrent-done-enabled": ('boolean', 9, None, None, None, 'Whether or not to call the "done" script.'),
|
"script-torrent-done-enabled": ('boolean', 9, None, None, None, 'Whether or not to call the "done" script.'),
|
||||||
"script-torrent-done-filename": ('string', 9, None, None, None, 'Filename of the script to run when the transfer is done.'),
|
"script-torrent-done-filename": ('string', 9, None, None, None, 'Filename of the script to run when the transfer is done.'),
|
||||||
|
"seed-queue-size": ('number', 14, None, None, None, 'Number of parallel uploads.'),
|
||||||
|
"seed-queue-enabled": ('boolean', 14, None, None, None, 'Enable parallel upload restriction.'),
|
||||||
"seedRatioLimit": ('double', 5, None, None, None, 'Seed ratio limit. 1.0 means 1:1 download and upload ratio.'),
|
"seedRatioLimit": ('double', 5, None, None, None, 'Seed ratio limit. 1.0 means 1:1 download and upload ratio.'),
|
||||||
"seedRatioLimited": ('boolean', 5, None, None, None, 'Enables seed ration limit.'),
|
"seedRatioLimited": ('boolean', 5, None, None, None, 'Enables seed ration limit.'),
|
||||||
"speed-limit-down": ('number', 1, None, None, None, 'Download speed limit (in Kib/s).'),
|
"speed-limit-down": ('number', 1, None, None, None, 'Download speed limit (in Kib/s).'),
|
||||||
|
@ -282,5 +286,6 @@ SESSION_ARGS = {
|
||||||
"speed-limit-up-enabled": ('boolean', 1, None, None, None, 'Enables upload speed limiting.'),
|
"speed-limit-up-enabled": ('boolean', 1, None, None, None, 'Enables upload speed limiting.'),
|
||||||
"start-added-torrents": ('boolean', 9, None, None, None, 'Added torrents will be started right away.'),
|
"start-added-torrents": ('boolean', 9, None, None, None, 'Added torrents will be started right away.'),
|
||||||
"trash-original-torrent-files": ('boolean', 9, None, None, None, 'The .torrent file of added torrents will be deleted.'),
|
"trash-original-torrent-files": ('boolean', 9, None, None, None, 'The .torrent file of added torrents will be deleted.'),
|
||||||
|
'utp-enabled': ('boolean', 13, None, None, None, 'Enables Micro Transport Protocol (UTP).'),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
class TransmissionError(Exception):
|
class TransmissionError(Exception):
|
||||||
"""
|
"""
|
||||||
This exception is raised when there has occured an error related to
|
This exception is raised when there has occurred an error related to
|
||||||
communication with Transmission. It is a subclass of Exception.
|
communication with Transmission. It is a subclass of Exception.
|
||||||
"""
|
"""
|
||||||
def __init__(self, message='', original=None):
|
def __init__(self, message='', original=None):
|
||||||
Exception.__init__(self)
|
Exception.__init__(self)
|
||||||
self.message = message
|
self._message = message
|
||||||
self.original = original
|
self.original = original
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -21,14 +21,14 @@ class TransmissionError(Exception):
|
||||||
|
|
||||||
class HTTPHandlerError(Exception):
|
class HTTPHandlerError(Exception):
|
||||||
"""
|
"""
|
||||||
This exception is raised when there has occured an error related to
|
This exception is raised when there has occurred an error related to
|
||||||
the HTTP handler. It is a subclass of Exception.
|
the HTTP handler. It is a subclass of Exception.
|
||||||
"""
|
"""
|
||||||
def __init__(self, httpurl=None, httpcode=None, httpmsg=None, httpheaders=None, httpdata=None):
|
def __init__(self, httpurl=None, httpcode=None, httpmsg=None, httpheaders=None, httpdata=None):
|
||||||
Exception.__init__(self)
|
Exception.__init__(self)
|
||||||
self.url = ''
|
self.url = ''
|
||||||
self.code = 600
|
self.code = 600
|
||||||
self.message = ''
|
self._message = ''
|
||||||
self.headers = {}
|
self.headers = {}
|
||||||
self.data = ''
|
self.data = ''
|
||||||
if isinstance(httpurl, (str, unicode)):
|
if isinstance(httpurl, (str, unicode)):
|
||||||
|
@ -36,17 +36,17 @@ class HTTPHandlerError(Exception):
|
||||||
if isinstance(httpcode, (int, long)):
|
if isinstance(httpcode, (int, long)):
|
||||||
self.code = httpcode
|
self.code = httpcode
|
||||||
if isinstance(httpmsg, (str, unicode)):
|
if isinstance(httpmsg, (str, unicode)):
|
||||||
self.message = httpmsg
|
self._message = httpmsg
|
||||||
if isinstance(httpheaders, (dict)):
|
if isinstance(httpheaders, dict):
|
||||||
self.headers = httpheaders
|
self.headers = httpheaders
|
||||||
if isinstance(httpdata, (str, unicode)):
|
if isinstance(httpdata, (str, unicode)):
|
||||||
self.data = httpdata
|
self.data = httpdata
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<HTTPHandlerError %d, %s>' % (self.code, self.message)
|
return '<HTTPHandlerError %d, %s>' % (self.code, self._message)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '<HTTPHandlerError %d, %s>' % (self.code, self.message)
|
return 'HTTPHandlerError %d: %s' % (self.code, self._message)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'<HTTPHandlerError %d, %s>' % (self.code, self.message)
|
return u'HTTPHandlerError %d: %s' % (self.code, self._message)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import sys, httplib, urllib2
|
import sys, httplib, urllib2
|
||||||
|
@ -56,12 +56,12 @@ class DefaultHTTPHandler(HTTPHandler):
|
||||||
else:
|
else:
|
||||||
response = urllib2.urlopen(request)
|
response = urllib2.urlopen(request)
|
||||||
except urllib2.HTTPError, error:
|
except urllib2.HTTPError, error:
|
||||||
if error.fp == None:
|
if error.fp is None:
|
||||||
raise HTTPHandlerError(error.filename, error.code, error.msg, dict(error.hdrs))
|
raise HTTPHandlerError(error.filename, error.code, error.msg, dict(error.hdrs))
|
||||||
else:
|
else:
|
||||||
raise HTTPHandlerError(error.filename, error.code, error.msg, dict(error.hdrs), error.read())
|
raise HTTPHandlerError(error.filename, error.code, error.msg, dict(error.hdrs), error.read())
|
||||||
except urllib2.URLError, error:
|
except urllib2.URLError, error:
|
||||||
# urllib2.URLError documentation is absymal!
|
# urllib2.URLError documentation is horrendous!
|
||||||
# Try to get the tuple arguments of URLError
|
# Try to get the tuple arguments of URLError
|
||||||
if hasattr(error.reason, 'args') and isinstance(error.reason.args, tuple) and len(error.reason.args) == 2:
|
if hasattr(error.reason, 'args') and isinstance(error.reason.args, tuple) and len(error.reason.args) == 2:
|
||||||
raise HTTPHandlerError(httpcode=error.reason.args[0], httpmsg=error.reason.args[1])
|
raise HTTPHandlerError(httpcode=error.reason.args[0], httpmsg=error.reason.args[1])
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
class Session(object):
|
class Session(object):
|
||||||
|
@ -8,17 +8,17 @@ class Session(object):
|
||||||
|
|
||||||
Access the session field can be done through attributes.
|
Access the session field can be done through attributes.
|
||||||
The attributes available are the same as the session arguments in the
|
The attributes available are the same as the session arguments in the
|
||||||
Transmission RPC specification, but with underscore instead of hypen.
|
Transmission RPC specification, but with underscore instead of hyphen.
|
||||||
``download-dir`` -> ``download_dir``.
|
``download-dir`` -> ``download_dir``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, fields=None):
|
def __init__(self, fields=None):
|
||||||
self.fields = {}
|
self.fields = {}
|
||||||
if fields != None:
|
if fields is not None:
|
||||||
self.update(fields)
|
self.update(fields)
|
||||||
|
|
||||||
def update(self, other):
|
def update(self, other):
|
||||||
"""Update the session data from a session arguments dictinary"""
|
"""Update the session data from a session arguments dictionary"""
|
||||||
|
|
||||||
fields = None
|
fields = None
|
||||||
if isinstance(other, dict):
|
if isinstance(other, dict):
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import sys, datetime
|
import sys, datetime
|
||||||
|
|
||||||
from transmissionrpc.constants import STATUS, PRIORITY
|
from transmissionrpc.constants import PRIORITY
|
||||||
from transmissionrpc.utils import format_timedelta
|
from transmissionrpc.utils import format_timedelta
|
||||||
|
|
||||||
class Torrent(object):
|
class Torrent(object):
|
||||||
"""
|
"""
|
||||||
Torrent is a class holding the data raceived from Transmission regarding a bittorrent transfer.
|
Torrent is a class holding the data received from Transmission regarding a bittorrent transfer.
|
||||||
All fetched torrent fields are accessable through this class using attributes.
|
All fetched torrent fields are accessible through this class using attributes.
|
||||||
This class has a few convenience properties using the torrent data.
|
This class has a few convenience properties using the torrent data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class Torrent(object):
|
||||||
self.client = client
|
self.client = client
|
||||||
|
|
||||||
def _getNameString(self, codec=None):
|
def _getNameString(self, codec=None):
|
||||||
if codec == None:
|
if codec is None:
|
||||||
codec = sys.getdefaultencoding()
|
codec = sys.getdefaultencoding()
|
||||||
name = None
|
name = None
|
||||||
# try to find name
|
# try to find name
|
||||||
|
@ -54,9 +54,43 @@ class Torrent(object):
|
||||||
def __copy__(self):
|
def __copy__(self):
|
||||||
return Torrent(self.client, self.fields)
|
return Torrent(self.client, self.fields)
|
||||||
|
|
||||||
|
def _rpc_version(self):
|
||||||
|
if self.client:
|
||||||
|
return self.client.rpc_version
|
||||||
|
return 2
|
||||||
|
|
||||||
|
def _status_old(self, code):
|
||||||
|
mapping = {
|
||||||
|
(1<<0): 'check pending',
|
||||||
|
(1<<1): 'checking',
|
||||||
|
(1<<2): 'downloading',
|
||||||
|
(1<<3): 'seeding',
|
||||||
|
(1<<4): 'stopped',
|
||||||
|
}
|
||||||
|
return mapping[code]
|
||||||
|
|
||||||
|
def _status_new(self, code):
|
||||||
|
mapping = {
|
||||||
|
0: 'stopped',
|
||||||
|
1: 'check pending',
|
||||||
|
2: 'checking',
|
||||||
|
3: 'download pending',
|
||||||
|
4: 'downloading',
|
||||||
|
5: 'seed pending',
|
||||||
|
6: 'seeding',
|
||||||
|
}
|
||||||
|
return mapping[code]
|
||||||
|
|
||||||
|
def _status(self):
|
||||||
|
code = self.fields['status']
|
||||||
|
if self._rpc_version() >= 14:
|
||||||
|
return self._status_new(code)
|
||||||
|
else:
|
||||||
|
return self._status_old(code)
|
||||||
|
|
||||||
def update(self, other):
|
def update(self, other):
|
||||||
"""
|
"""
|
||||||
Update the torrent data from a Transmission JSON-RPC arguments dictinary
|
Update the torrent data from a Transmission JSON-RPC arguments dictionary
|
||||||
"""
|
"""
|
||||||
fields = None
|
fields = None
|
||||||
if isinstance(other, dict):
|
if isinstance(other, dict):
|
||||||
|
@ -70,32 +104,31 @@ class Torrent(object):
|
||||||
|
|
||||||
def files(self):
|
def files(self):
|
||||||
"""
|
"""
|
||||||
Get list of files for this torrent.
|
Get list of files for this torrent.
|
||||||
|
|
||||||
This function returns a dictionary with file information for each file.
|
This function returns a dictionary with file information for each file.
|
||||||
The file information is has following fields:
|
The file information is has following fields:
|
||||||
::
|
::
|
||||||
|
|
||||||
{
|
{
|
||||||
<file id>: {
|
<file id>: {
|
||||||
'name': <file name>,
|
'name': <file name>,
|
||||||
'size': <file size in bytes>,
|
'size': <file size in bytes>,
|
||||||
'completed': <bytes completed>,
|
'completed': <bytes completed>,
|
||||||
'priority': <priority ('high'|'normal'|'low')>,
|
'priority': <priority ('high'|'normal'|'low')>,
|
||||||
'selected': <selected for download>
|
'selected': <selected for download>
|
||||||
}
|
}
|
||||||
|
...
|
||||||
...
|
}
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
result = {}
|
result = {}
|
||||||
if 'files' in self.fields:
|
if 'files' in self.fields:
|
||||||
indicies = xrange(len(self.fields['files']))
|
indices = xrange(len(self.fields['files']))
|
||||||
files = self.fields['files']
|
files = self.fields['files']
|
||||||
priorities = self.fields['priorities']
|
priorities = self.fields['priorities']
|
||||||
wanted = self.fields['wanted']
|
wanted = self.fields['wanted']
|
||||||
for item in zip(indicies, files, priorities, wanted):
|
for item in zip(indices, files, priorities, wanted):
|
||||||
selected = bool(item[3])
|
selected = True if item[3] else False
|
||||||
priority = PRIORITY[item[2]]
|
priority = PRIORITY[item[2]]
|
||||||
result[item[0]] = {
|
result[item[0]] = {
|
||||||
'selected': selected,
|
'selected': selected,
|
||||||
|
@ -115,10 +148,10 @@ class Torrent(object):
|
||||||
def status(self):
|
def status(self):
|
||||||
"""
|
"""
|
||||||
Returns the torrent status. Is either one of 'check pending', 'checking',
|
Returns the torrent status. Is either one of 'check pending', 'checking',
|
||||||
'downloading', 'seeding' or 'stopped'. The first two is related to
|
'downloading', 'seeding' or 'stopped'. The first two is related to
|
||||||
verification.
|
verification.
|
||||||
"""
|
"""
|
||||||
return STATUS[self.fields['status']]
|
return self._status()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def progress(self):
|
def progress(self):
|
||||||
|
@ -131,10 +164,7 @@ class Torrent(object):
|
||||||
@property
|
@property
|
||||||
def ratio(self):
|
def ratio(self):
|
||||||
"""Get the upload/download ratio."""
|
"""Get the upload/download ratio."""
|
||||||
try:
|
return float(self.fields['uploadRatio'])
|
||||||
return self.fields['uploadedEver'] / float(self.fields['downloadedEver'])
|
|
||||||
except ZeroDivisionError:
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def eta(self):
|
def eta(self):
|
||||||
|
@ -167,12 +197,12 @@ class Torrent(object):
|
||||||
|
|
||||||
def format_eta(self):
|
def format_eta(self):
|
||||||
"""
|
"""
|
||||||
Returns the attribute *eta* formatted as a string.
|
Returns the attribute *eta* formatted as a string.
|
||||||
|
|
||||||
* If eta is -1 the result is 'not available'
|
* If eta is -1 the result is 'not available'
|
||||||
* If eta is -2 the result is 'unknown'
|
* If eta is -2 the result is 'unknown'
|
||||||
* Otherwise eta is formatted as <days> <hours>:<minutes>:<seconds>.
|
* Otherwise eta is formatted as <days> <hours>:<minutes>:<seconds>.
|
||||||
"""
|
"""
|
||||||
eta = self.fields['eta']
|
eta = self.fields['eta']
|
||||||
if eta == -1:
|
if eta == -1:
|
||||||
return 'not available'
|
return 'not available'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
# Copyright (c) 2008-2011 Erik Svensson <erik.public@gmail.com>
|
||||||
# Licensed under the MIT license.
|
# Licensed under the MIT license.
|
||||||
|
|
||||||
import socket, datetime, logging
|
import socket, datetime, logging
|
||||||
|
@ -28,18 +28,21 @@ def format_speed(size):
|
||||||
|
|
||||||
def format_timedelta(delta):
|
def format_timedelta(delta):
|
||||||
"""
|
"""
|
||||||
Format datetime.timedelta into <days> <hours>:<mminutes>:<seconds>.
|
Format datetime.timedelta into <days> <hours>:<minutes>:<seconds>.
|
||||||
"""
|
"""
|
||||||
minutes, seconds = divmod(delta.seconds, 60)
|
minutes, seconds = divmod(delta.seconds, 60)
|
||||||
hours, minutes = divmod(minutes, 60)
|
hours, minutes = divmod(minutes, 60)
|
||||||
return '%d %02d:%02d:%02d' % (delta.days, hours, minutes, seconds)
|
return '%d %02d:%02d:%02d' % (delta.days, hours, minutes, seconds)
|
||||||
|
|
||||||
def format_timestamp(timestamp):
|
def format_timestamp(timestamp, utc=False):
|
||||||
"""
|
"""
|
||||||
Format unix timestamp into ISO date format.
|
Format unix timestamp into ISO date format.
|
||||||
"""
|
"""
|
||||||
if timestamp > 0:
|
if timestamp > 0:
|
||||||
dt_timestamp = datetime.datetime.fromtimestamp(timestamp)
|
if utc:
|
||||||
|
dt_timestamp = datetime.datetime.utcfromtimestamp(timestamp)
|
||||||
|
else:
|
||||||
|
dt_timestamp = datetime.datetime.fromtimestamp(timestamp)
|
||||||
return dt_timestamp.isoformat(' ')
|
return dt_timestamp.isoformat(' ')
|
||||||
else:
|
else:
|
||||||
return '-'
|
return '-'
|
||||||
|
@ -88,10 +91,7 @@ def rpc_bool(arg):
|
||||||
arg = bool(int(arg))
|
arg = bool(int(arg))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
arg = arg.lower() in [u'true', u'yes']
|
arg = arg.lower() in [u'true', u'yes']
|
||||||
if bool(arg):
|
return 1 if bool(arg) else 0
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
TR_TYPE_MAP = {
|
TR_TYPE_MAP = {
|
||||||
'number' : int,
|
'number' : int,
|
||||||
|
|
Loading…
Reference in a new issue