2023-01-12 01:04:47 +00:00
|
|
|
# Copyright (c) 2013 Chris Lucas, <chris@chrisjlucas.com>
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
# a copy of this software and associated documentation files (the
|
|
|
|
# "Software"), to deal in the Software without restriction, including
|
|
|
|
# without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
# permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
# the following conditions:
|
|
|
|
#
|
|
|
|
# The above copyright notice and this permission notice shall be
|
|
|
|
# included in all copies or substantial portions of the Software.
|
|
|
|
#
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
import os.path
|
|
|
|
import time
|
|
|
|
|
|
|
|
from .lib.torrentparser import TorrentParser
|
|
|
|
from .lib.xmlrpc.basic_auth import BasicAuthTransport
|
|
|
|
from .lib.xmlrpc.http import HTTPServerProxy
|
|
|
|
from .lib.xmlrpc.scgi import SCGIServerProxy
|
|
|
|
|
|
|
|
from . import rpc
|
|
|
|
from .common import convert_version_tuple_to_str, find_torrent, is_valid_port, join_uri, update_uri
|
|
|
|
from .compat import urlparse, xmlrpclib
|
|
|
|
from .file import File, methods as file_methods
|
|
|
|
from .group import Group
|
|
|
|
from .peer import Peer, methods as peer_methods
|
|
|
|
from .rpc import Method
|
|
|
|
from .torrent import Torrent, methods as torrent_methods
|
|
|
|
from .tracker import Tracker, methods as tracker_methods
|
|
|
|
|
|
|
|
|
|
|
|
__version__ = '0.2.10'
|
|
|
|
__author__ = 'Chris Lucas'
|
|
|
|
__maintainer__ = 'SickGear'
|
|
|
|
__contact__ = 'chris@chrisjlucas.com'
|
|
|
|
__license__ = 'MIT'
|
|
|
|
|
|
|
|
MIN_RTORRENT_VERSION = (0, 8, 1)
|
|
|
|
MIN_RTORRENT_VERSION_STR = convert_version_tuple_to_str(MIN_RTORRENT_VERSION)
|
|
|
|
|
|
|
|
|
|
|
|
class RTorrent(object):
|
|
|
|
""" Create a new rTorrent connection """
|
|
|
|
rpc_prefix = None
|
|
|
|
|
|
|
|
def __init__(self, uri, username=None, password=None, check_connection=True, sp=None, sp_kwargs=None):
|
|
|
|
|
|
|
|
self.username = username
|
|
|
|
self.password = password
|
|
|
|
|
|
|
|
self.scheme, self.uri = self._transform_uri(uri)
|
|
|
|
if sp:
|
|
|
|
self.sp = sp
|
|
|
|
elif self.scheme in ['http', 'https']:
|
|
|
|
self.sp = HTTPServerProxy
|
|
|
|
elif 'scgi' == self.scheme:
|
|
|
|
self.sp = SCGIServerProxy
|
|
|
|
else:
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
self.sp_kwargs = sp_kwargs or {}
|
|
|
|
|
|
|
|
self.torrents = [] # : List of L{Torrent} instances
|
|
|
|
self._rpc_methods = [] # : List of rTorrent RPC methods
|
|
|
|
self._torrent_cache = []
|
|
|
|
self._client_version_tuple = ()
|
|
|
|
self.use_target = False
|
|
|
|
self.dht_port = None
|
|
|
|
self.request_interval = 3
|
|
|
|
|
|
|
|
if check_connection:
|
|
|
|
self._check_connection()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _transform_uri(uri):
|
|
|
|
scheme = urlparse(uri).scheme
|
|
|
|
|
|
|
|
if 'httprpc' == scheme or scheme.startswith('httprpc+'):
|
|
|
|
# Transform URI with new path and scheme
|
|
|
|
uri = join_uri(uri, 'plugins/httprpc/action.php', construct=False)
|
|
|
|
|
|
|
|
# Try find HTTPRPC transport (token after '+' in 'httprpc+https'), otherwise assume HTTP
|
|
|
|
transport = 'http' if '+' not in scheme else scheme[scheme.index('+') + 1:]
|
|
|
|
|
|
|
|
uri = update_uri(uri, scheme=transport)
|
|
|
|
|
|
|
|
return urlparse(uri).scheme, uri
|
|
|
|
|
|
|
|
def get_connection(self):
|
|
|
|
"""Get ServerProxy instance"""
|
|
|
|
|
|
|
|
if not (self.username and self.password):
|
|
|
|
return self.sp(self.uri, **self.sp_kwargs)
|
|
|
|
|
|
|
|
if 'scgi' == self.scheme:
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
return self.sp(self.uri,
|
|
|
|
transport=BasicAuthTransport('https' == self.scheme, self.username, self.password),
|
|
|
|
**self.sp_kwargs)
|
|
|
|
|
|
|
|
def test_connection(self):
|
|
|
|
"""
|
|
|
|
Test connection to rT
|
|
|
|
:return: True of connection successful, otherwise False
|
|
|
|
:rtype: Boolean
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
self._check_connection()
|
|
|
|
return True
|
|
|
|
except (BaseException, Exception):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _check_connection(self):
|
|
|
|
# check for rpc methods that should be available
|
|
|
|
assert self.method_exists('system.client_version'), \
|
|
|
|
'Required RPC method (client_version) not available. Check connection settings in client.'
|
|
|
|
assert self.method_exists('system.library_version'), \
|
|
|
|
'Required RPC method (system.library_version) not available. Check connection settings in client.'
|
|
|
|
|
|
|
|
# minimum rTorrent version check
|
|
|
|
assert self._meets_version_requirement() is True, \
|
|
|
|
'Error: Minimum rTorrent version required is %s' % MIN_RTORRENT_VERSION_STR
|
|
|
|
|
|
|
|
def method_exists(self, name):
|
|
|
|
"""
|
|
|
|
Check if rpc method exists
|
|
|
|
:param name: Name of method
|
|
|
|
:type name: str
|
|
|
|
:return: True if method is found
|
|
|
|
:rtype: Boolean
|
|
|
|
"""
|
|
|
|
return name in self.get_rpc_methods()
|
|
|
|
|
|
|
|
def get_rpc_methods(self):
|
|
|
|
""" Get list of raw RPC commands
|
|
|
|
|
|
|
|
@return: raw RPC commands
|
|
|
|
@rtype: list
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._rpc_methods or self._fetch_rpc_methods()
|
|
|
|
|
|
|
|
def _fetch_rpc_methods(self):
|
|
|
|
|
|
|
|
self._rpc_methods = self.get_connection().system.listMethods()
|
|
|
|
|
|
|
|
return self._rpc_methods
|
|
|
|
|
|
|
|
def _meets_version_requirement(self):
|
|
|
|
return self.get_client_version_tuple() >= MIN_RTORRENT_VERSION
|
|
|
|
|
|
|
|
def get_client_version_tuple(self):
|
|
|
|
conn = self.get_connection()
|
|
|
|
|
|
|
|
if not self._client_version_tuple:
|
|
|
|
if not hasattr(self, 'client_version'):
|
|
|
|
setattr(self, 'client_version',
|
|
|
|
conn.system.client_version())
|
|
|
|
|
|
|
|
rtver = getattr(self, 'client_version')
|
|
|
|
self._client_version_tuple = tuple([int(i) for i in
|
|
|
|
rtver.split('.')])
|
|
|
|
|
|
|
|
return self._client_version_tuple
|
|
|
|
|
|
|
|
def get_torrents(self, view='main'):
|
|
|
|
"""Get list of all torrents in specified view
|
|
|
|
|
|
|
|
@return: list of L{Torrent} instances
|
|
|
|
|
|
|
|
@rtype: list
|
|
|
|
|
|
|
|
@todo: add validity check for specified view
|
|
|
|
"""
|
|
|
|
self.torrents = []
|
2023-02-11 18:02:58 +00:00
|
|
|
retriever_methods = list(filter(lambda m: m.is_retriever() and m.is_available(self), torrent_methods))
|
2023-01-12 01:04:47 +00:00
|
|
|
mc = rpc.Multicall(self)
|
|
|
|
|
|
|
|
if self.method_exists('d.multicall2'):
|
|
|
|
mc.add('d.multicall2', '', view, 'd.hash=',
|
2023-02-11 18:02:58 +00:00
|
|
|
*list(map(lambda m2: ((getattr(m2, 'aliases') or [''])[-1] or m2.rpc_call) + '=',
|
|
|
|
retriever_methods)))
|
2023-01-12 01:04:47 +00:00
|
|
|
else:
|
|
|
|
mc.add('d.multicall', view, 'd.get_hash=',
|
2023-02-11 18:02:58 +00:00
|
|
|
*list(map(lambda m1: m1.rpc_call + '=', retriever_methods)))
|
2023-01-12 01:04:47 +00:00
|
|
|
|
|
|
|
results = mc.call()[0] # only sent one call, only need first result
|
|
|
|
|
|
|
|
for result in results:
|
|
|
|
self.torrents.append(
|
|
|
|
Torrent(self, info_hash=result[0],
|
|
|
|
**dict((mc.varname, rpc.process_result(mc, r))
|
|
|
|
for (mc, r) in list(zip(retriever_methods, result[1:]))))) # result[0]=info_hash
|
|
|
|
|
|
|
|
self._manage_torrent_cache()
|
|
|
|
return self.torrents
|
|
|
|
|
|
|
|
def _manage_torrent_cache(self):
|
|
|
|
"""Carry tracker/peer/file lists over to new torrent list"""
|
|
|
|
for t in self._torrent_cache:
|
|
|
|
new_torrent = common.find_torrent(t.info_hash, self.torrents)
|
|
|
|
if new_torrent is not None:
|
|
|
|
new_torrent.files = t.files
|
|
|
|
new_torrent.peers = t.peers
|
|
|
|
new_torrent.trackers = t.trackers
|
|
|
|
|
|
|
|
self._torrent_cache = self.torrents
|
|
|
|
|
|
|
|
def _get_load_function(self, file_type, start, verbose):
|
|
|
|
"""Determine correct "load torrent" RPC method"""
|
|
|
|
func_name = file_type in ('url', 'file', 'raw') and (
|
|
|
|
dict(sv='load_raw_start_verbose', s='load_raw_start', v='load_raw_verbose', ld='load_raw'),
|
|
|
|
dict(sv='load_start_verbose', s='load_start', v='load_verbose', ld='load')
|
|
|
|
)['url' == file_type][
|
|
|
|
((('ld', 'v')[verbose], 's')[start], 'sv')[start and verbose]] or None
|
|
|
|
|
|
|
|
if not self.method_exists(func_name):
|
|
|
|
if 'load' == func_name:
|
|
|
|
func_name = 'load.normal'
|
|
|
|
func_name = func_name.replace('load_', 'load.')
|
|
|
|
if not self.method_exists(func_name):
|
|
|
|
func_name = None
|
|
|
|
|
|
|
|
return func_name
|
|
|
|
|
|
|
|
def execute_func(self, func_name, param=None, extra=None):
|
|
|
|
|
|
|
|
param = ([param], param)[isinstance(param, list)]
|
|
|
|
for x in (extra or []):
|
|
|
|
try:
|
|
|
|
call, arg = x.split('=')
|
|
|
|
method = rpc.find_method(call)
|
2023-02-11 18:02:58 +00:00
|
|
|
method_name = next(filter(lambda m: self.method_exists(m), (method.rpc_call,) + method.aliases))
|
2023-01-12 01:04:47 +00:00
|
|
|
param += ['%s=%s' % (method_name, arg)]
|
|
|
|
except (BaseException, Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
method = getattr(self.get_connection(), func_name)
|
|
|
|
|
|
|
|
if not self.use_target:
|
|
|
|
try:
|
|
|
|
method(*param)
|
|
|
|
except (BaseException, Exception):
|
|
|
|
self.use_target = True
|
|
|
|
if self.use_target:
|
|
|
|
method('', *param)
|
|
|
|
|
|
|
|
def load_magnet(self, magneturl, info_hash, extra=None, start=False, verbose=False, verify_load=True):
|
|
|
|
|
|
|
|
func_name = self._get_load_function('url', start, verbose)
|
|
|
|
# load magnet
|
|
|
|
self.execute_func(func_name, magneturl, extra)
|
|
|
|
|
|
|
|
t = None
|
|
|
|
if verify_load:
|
|
|
|
info_hash = info_hash.upper()
|
|
|
|
max_retries = 10
|
|
|
|
while max_retries:
|
|
|
|
try:
|
2023-02-11 18:02:58 +00:00
|
|
|
t = next(filter(lambda td: td.info_hash.upper() == info_hash, self.get_torrents()))
|
2023-01-12 01:04:47 +00:00
|
|
|
break
|
|
|
|
except (BaseException, Exception):
|
|
|
|
time.sleep(self.request_interval)
|
|
|
|
max_retries -= 1
|
|
|
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
def load_torrent(self, data, extra=None, start=False, verbose=False, verify_load=True, verify_retries=3):
|
|
|
|
"""
|
|
|
|
Loads torrent into rTorrent (with various enhancements)
|
|
|
|
|
|
|
|
@param data: can be a url, a path to a local file, or the raw data
|
|
|
|
of a torrent file
|
|
|
|
@type data: str
|
|
|
|
|
|
|
|
@param extra: extra commands to send
|
|
|
|
@type extra: array
|
|
|
|
|
|
|
|
@param start: start torrent when loaded
|
|
|
|
@type start: bool
|
|
|
|
|
|
|
|
@param verbose: print error messages to rTorrent log
|
|
|
|
@type verbose: bool
|
|
|
|
|
|
|
|
@param verify_load: verify that torrent was added to rTorrent successfully
|
|
|
|
@type verify_load: bool
|
|
|
|
|
|
|
|
@param verify_retries: number of times to attempt verification
|
|
|
|
@type verify_load: int
|
|
|
|
|
|
|
|
@return: Depends on verify_load:
|
|
|
|
- if verify_load is True, (and the torrent was
|
|
|
|
loaded successfully), it'll return a L{Torrent} instance
|
|
|
|
- if verify_load is False, it'll return None
|
|
|
|
|
|
|
|
@rtype: L{Torrent} instance or None
|
|
|
|
|
|
|
|
@raise AssertionError: If the torrent wasn't successfully added to rTorrent
|
|
|
|
- Check L{TorrentParser} for the AssertionError's
|
|
|
|
it raises
|
|
|
|
|
|
|
|
|
|
|
|
@note: Because this function includes url verification (if a url was input)
|
|
|
|
as well as verification as to whether the torrent was successfully added,
|
|
|
|
this function doesn't execute instantaneously. If that's what you're
|
|
|
|
looking for, use load_torrent_simple() instead.
|
|
|
|
"""
|
|
|
|
tp = TorrentParser(data)
|
|
|
|
info_hash = tp.info_hash
|
|
|
|
|
|
|
|
# load torrent
|
|
|
|
self.execute_func(self._get_load_function('url', False, False), '')
|
|
|
|
self.execute_func(self._get_load_function('raw', start, verbose), xmlrpclib.Binary(tp.raw_torrent), extra)
|
|
|
|
|
|
|
|
t = None
|
|
|
|
if verify_load:
|
|
|
|
while verify_retries:
|
|
|
|
try:
|
2023-02-11 18:02:58 +00:00
|
|
|
t = next(filter(lambda td: td.info_hash == info_hash, self.get_torrents()))
|
2023-01-12 01:04:47 +00:00
|
|
|
break
|
|
|
|
except (BaseException, Exception):
|
|
|
|
time.sleep(self.request_interval)
|
|
|
|
verify_retries -= 1
|
|
|
|
|
|
|
|
assert None is not t, 'Adding torrent was unsuccessful.'
|
|
|
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
def load_torrent_simple(self, data, file_type, extra=None, start=False, verbose=False):
|
|
|
|
"""Loads torrent into rTorrent
|
|
|
|
|
|
|
|
@param data: can be a url, a path to a local file, or the raw data
|
|
|
|
of a torrent file
|
|
|
|
@type data: str
|
|
|
|
|
|
|
|
@param file_type: valid options: "url", "file", or "raw"
|
|
|
|
@type file_type: str
|
|
|
|
|
|
|
|
@param extra: extra commands to send
|
|
|
|
@type extra: array
|
|
|
|
|
|
|
|
@param start: start torrent when loaded
|
|
|
|
@type start: bool
|
|
|
|
|
|
|
|
@param verbose: print error messages to rTorrent log
|
|
|
|
@type verbose: bool
|
|
|
|
|
|
|
|
@return: None
|
|
|
|
|
|
|
|
@raise AssertionError: if incorrect file_type is specified
|
|
|
|
|
|
|
|
@note: This function was written for speed, it includes no enhancements.
|
|
|
|
If you input a url, it won't check if it's valid. You also can't get
|
|
|
|
verification that the torrent was successfully added to rTorrent.
|
|
|
|
Use load_torrent() if you would like these features.
|
|
|
|
"""
|
|
|
|
assert file_type in ['raw', 'file', 'url'], \
|
|
|
|
'Invalid file_type, options are: \'url\', \'file\', \'raw\'.'
|
|
|
|
func_name = self._get_load_function(file_type, start, verbose)
|
|
|
|
|
|
|
|
if 'file' == file_type:
|
|
|
|
# since we have to assume we're connected to a remote rTorrent
|
|
|
|
# client, we have to read the file and send it to rT as raw
|
|
|
|
assert os.path.isfile(data), \
|
|
|
|
'Invalid path: "{0}"'.format(data)
|
|
|
|
data = open(data, 'rb').read()
|
|
|
|
elif 'raw' == file_type:
|
|
|
|
self.execute_func(self._get_load_function('url', False, False), '')
|
|
|
|
|
|
|
|
finput = None
|
|
|
|
if file_type in ['raw', 'file']:
|
|
|
|
finput = xmlrpclib.Binary(data)
|
|
|
|
elif 'url' == file_type:
|
|
|
|
finput = data
|
|
|
|
|
|
|
|
self.execute_func(func_name, finput, extra)
|
|
|
|
|
|
|
|
def get_views(self):
|
|
|
|
p = self.get_connection()
|
|
|
|
return p.view_list()
|
|
|
|
|
|
|
|
def create_group(self, name, persistent=True, view=None):
|
|
|
|
p = self.get_connection()
|
|
|
|
|
|
|
|
if persistent is True:
|
|
|
|
p.group.insert_persistent_view('', name)
|
|
|
|
else:
|
|
|
|
assert view is not None, 'view parameter required on non-persistent groups'
|
|
|
|
p.group.insert('', name, view)
|
|
|
|
|
|
|
|
self._fetch_rpc_methods()
|
|
|
|
|
|
|
|
def get_group(self, name):
|
|
|
|
assert name is not None, 'group name required'
|
|
|
|
|
|
|
|
grp = Group(self, name)
|
|
|
|
grp.update()
|
|
|
|
return grp
|
|
|
|
|
|
|
|
def set_dht_port(self, port):
|
|
|
|
"""Set DHT port
|
|
|
|
|
|
|
|
@param port: port
|
|
|
|
@type port: int
|
|
|
|
|
|
|
|
@raise AssertionError: if invalid port is given
|
|
|
|
"""
|
|
|
|
assert is_valid_port(port), 'Valid port range is 0-65535'
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
|
|
self.dht_port = self._p.set_dht_port(port)
|
|
|
|
|
|
|
|
def enable_check_hash(self):
|
|
|
|
"""Alias for set_check_hash(True)"""
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
|
|
self.set_check_hash(True)
|
|
|
|
|
|
|
|
def disable_check_hash(self):
|
|
|
|
"""Alias for set_check_hash(False)"""
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
|
|
self.set_check_hash(False)
|
|
|
|
|
|
|
|
def find_torrent(self, info_hash):
|
|
|
|
"""Frontend for common.find_torrent"""
|
|
|
|
return common.find_torrent(info_hash, self.get_torrents())
|
|
|
|
|
|
|
|
def has_local_id(self, info_hash):
|
|
|
|
method = rpc.find_method('d.get_local_id')
|
|
|
|
result = True
|
|
|
|
try:
|
2023-02-11 18:02:58 +00:00
|
|
|
func = next(filter(lambda m: self.method_exists(m), (method.rpc_call,) + method.aliases))
|
2023-01-12 01:04:47 +00:00
|
|
|
getattr(self.get_connection(), func)(info_hash)
|
|
|
|
except (BaseException, Exception):
|
|
|
|
result = False
|
|
|
|
return result
|
|
|
|
|
|
|
|
def poll(self):
|
|
|
|
""" poll rTorrent to get latest torrent/peer/tracker/file information
|
|
|
|
|
|
|
|
@note: This essentially refreshes every aspect of the rTorrent
|
|
|
|
connection, so it can be very slow if working with a remote
|
|
|
|
connection that has a lot of torrents loaded.
|
|
|
|
|
|
|
|
@return: None
|
|
|
|
"""
|
|
|
|
self.update()
|
|
|
|
torrents = self.get_torrents()
|
|
|
|
for t in torrents:
|
|
|
|
t.poll()
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
"""Refresh rTorrent client info
|
|
|
|
|
|
|
|
@note: All fields are stored as attributes to self.
|
|
|
|
|
|
|
|
@return: None
|
|
|
|
"""
|
|
|
|
mc = rpc.Multicall(self)
|
|
|
|
|
2023-02-11 18:02:58 +00:00
|
|
|
for method in filter(lambda m: m.is_retriever() and m.is_available(self), methods):
|
2023-01-12 01:04:47 +00:00
|
|
|
mc.add(method)
|
|
|
|
|
|
|
|
mc.call()
|
|
|
|
|
|
|
|
|
|
|
|
def _build_class_methods(class_obj):
|
|
|
|
# multicall add class
|
|
|
|
caller = (lambda self, mc, method, *args: mc.add(method, self.rpc_id, *args))
|
|
|
|
|
|
|
|
caller.__doc__ = """Same as Multicall.add(), but with automatic inclusion
|
|
|
|
of the rpc_id
|
|
|
|
|
|
|
|
@param multicall: A L{Multicall} instance
|
|
|
|
@type: multicall: Multicall
|
|
|
|
|
|
|
|
@param method: L{Method} instance or raw rpc method
|
|
|
|
@type: Method or str
|
|
|
|
|
|
|
|
@param args: optional arguments to pass
|
|
|
|
"""
|
|
|
|
setattr(class_obj, 'multicall_add', caller)
|
|
|
|
|
|
|
|
|
|
|
|
def __compare_rpc_methods(rt_new, rt_old):
|
|
|
|
from pprint import pprint
|
|
|
|
rt_new_methods = set(rt_new.get_rpc_methods())
|
|
|
|
rt_old_methods = set(rt_old.get_rpc_methods())
|
|
|
|
print('New Methods:')
|
|
|
|
pprint(rt_new_methods - rt_old_methods)
|
|
|
|
print('Methods not in new rTorrent:')
|
|
|
|
pprint(rt_old_methods - rt_new_methods)
|
|
|
|
|
|
|
|
|
|
|
|
def __check_supported_methods(rt):
|
|
|
|
from pprint import pprint
|
|
|
|
supported_methods = set(
|
|
|
|
[m.rpc_call for m in methods + file_methods + torrent_methods + tracker_methods + peer_methods])
|
|
|
|
all_methods = set(rt.get_rpc_methods())
|
|
|
|
|
|
|
|
print('Methods NOT in supported methods')
|
|
|
|
pprint(all_methods - supported_methods)
|
|
|
|
print('Supported methods NOT in all methods')
|
|
|
|
pprint(supported_methods - all_methods)
|
|
|
|
|
|
|
|
|
|
|
|
methods = [
|
|
|
|
# RETRIEVERS
|
|
|
|
Method(RTorrent, 'get_xmlrpc_size_limit', 'get_xmlrpc_size_limit',
|
|
|
|
aliases=('network.xmlrpc.size_limit',)),
|
|
|
|
Method(RTorrent, 'get_proxy_address', 'get_proxy_address',
|
|
|
|
aliases=('network.proxy_address',)),
|
|
|
|
Method(RTorrent, 'get_split_suffix', 'get_split_suffix',
|
|
|
|
aliases=('system.file.split_suffix',)),
|
|
|
|
Method(RTorrent, 'get_up_limit', 'get_upload_rate',
|
|
|
|
aliases=('throttle.global_up.max_rate',)),
|
|
|
|
Method(RTorrent, 'get_max_memory_usage', 'get_max_memory_usage',
|
|
|
|
aliases=('pieces.memory.max',)),
|
|
|
|
Method(RTorrent, 'get_max_open_files', 'get_max_open_files',
|
|
|
|
aliases=('network.max_open_files',)),
|
|
|
|
Method(RTorrent, 'get_min_peers_seed', 'get_min_peers_seed',
|
|
|
|
aliases=('throttle.min_peers.seed',)),
|
|
|
|
Method(RTorrent, 'get_use_udp_trackers', 'get_use_udp_trackers',
|
|
|
|
aliases=('trackers.use_udp',)),
|
|
|
|
Method(RTorrent, 'get_preload_min_size', 'get_preload_min_size',
|
|
|
|
aliases=('pieces.preload.min_size',)),
|
|
|
|
Method(RTorrent, 'get_max_uploads', 'get_max_uploads',
|
|
|
|
aliases=('throttle.max_uploads',)),
|
|
|
|
Method(RTorrent, 'get_max_peers', 'get_max_peers',
|
|
|
|
aliases=('throttle.max_peers.normal',)),
|
|
|
|
Method(RTorrent, 'get_timeout_sync', 'get_timeout_sync',
|
|
|
|
aliases=('pieces.sync.timeout',)),
|
|
|
|
Method(RTorrent, 'get_receive_buffer_size', 'get_receive_buffer_size',
|
|
|
|
aliases=('network.receive_buffer.size',)),
|
|
|
|
Method(RTorrent, 'get_split_file_size', 'get_split_file_size',
|
|
|
|
aliases=('system.file.split_size',)),
|
|
|
|
Method(RTorrent, 'get_dht_throttle', 'get_dht_throttle',
|
|
|
|
aliases=('dht.throttle.name',)),
|
|
|
|
Method(RTorrent, 'get_max_peers_seed', 'get_max_peers_seed',
|
|
|
|
aliases=('throttle.max_peers.seed',)),
|
|
|
|
Method(RTorrent, 'get_min_peers', 'get_min_peers',
|
|
|
|
aliases=('throttle.min_peers.normal',)),
|
|
|
|
Method(RTorrent, 'get_tracker_numwant', 'get_tracker_numwant',
|
|
|
|
aliases=('trackers.numwant',)),
|
|
|
|
Method(RTorrent, 'get_max_open_sockets', 'get_max_open_sockets',
|
|
|
|
aliases=('network.max_open_sockets',)),
|
|
|
|
Method(RTorrent, 'get_session', 'get_session',
|
|
|
|
aliases=('session.path',)),
|
|
|
|
Method(RTorrent, 'get_ip', 'get_ip',
|
|
|
|
aliases=('network.local_address',)),
|
|
|
|
Method(RTorrent, 'get_scgi_dont_route', 'get_scgi_dont_route',
|
|
|
|
aliases=('network.scgi.dont_route',)),
|
|
|
|
Method(RTorrent, 'get_hash_read_ahead', 'get_hash_read_ahead'),
|
|
|
|
Method(RTorrent, 'get_http_cacert', 'get_http_cacert',
|
|
|
|
aliases=('network.http.cacert',)),
|
|
|
|
Method(RTorrent, 'get_dht_port', 'get_dht_port',
|
|
|
|
aliases=('dht.port',)),
|
|
|
|
Method(RTorrent, 'get_handshake_log', 'get_handshake_log'),
|
|
|
|
Method(RTorrent, 'get_preload_type', 'get_preload_type',
|
|
|
|
aliases=('pieces.preload.type',)),
|
|
|
|
Method(RTorrent, 'get_max_open_http', 'get_max_open_http',
|
|
|
|
aliases=('network.http.max_open',)),
|
|
|
|
Method(RTorrent, 'get_http_capath', 'get_http_capath',
|
|
|
|
aliases=('network.http.capath',)),
|
|
|
|
Method(RTorrent, 'get_max_downloads_global', 'get_max_downloads_global',
|
|
|
|
aliases=('throttle.max_downloads.global',)),
|
|
|
|
Method(RTorrent, 'get_name', 'get_name',
|
|
|
|
aliases=('session.name',)),
|
|
|
|
Method(RTorrent, 'get_session_on_completion', 'get_session_on_completion',
|
|
|
|
aliases=('session.on_completion',)),
|
|
|
|
Method(RTorrent, 'get_down_limit', 'get_download_rate',
|
|
|
|
aliases=('throttle.global_down.max_rate',)),
|
|
|
|
Method(RTorrent, 'get_down_total', 'get_down_total',
|
|
|
|
aliases=('throttle.global_down.total',)),
|
|
|
|
Method(RTorrent, 'get_up_rate', 'get_up_rate',
|
|
|
|
aliases=('throttle.global_up.rate',)),
|
|
|
|
Method(RTorrent, 'get_hash_max_tries', 'get_hash_max_tries'),
|
|
|
|
Method(RTorrent, 'get_peer_exchange', 'get_peer_exchange',
|
|
|
|
aliases=('protocol.pex',)),
|
|
|
|
Method(RTorrent, 'get_down_rate', 'get_down_rate',
|
|
|
|
aliases=('throttle.global_down.rate',)),
|
|
|
|
Method(RTorrent, 'get_connection_seed', 'get_connection_seed',
|
|
|
|
aliases=('protocol.connection.seed',)),
|
|
|
|
Method(RTorrent, 'get_http_proxy', 'get_http_proxy',
|
|
|
|
aliases=('network.http.proxy_address',)),
|
|
|
|
Method(RTorrent, 'get_stats_preloaded', 'get_stats_preloaded',
|
|
|
|
aliases=('pieces.stats_preloaded',)),
|
|
|
|
Method(RTorrent, 'get_timeout_safe_sync', 'get_timeout_safe_sync',
|
|
|
|
aliases=('pieces.sync.timeout_safe',)),
|
|
|
|
Method(RTorrent, 'get_hash_interval', 'get_hash_interval'),
|
|
|
|
Method(RTorrent, 'get_port_random', 'get_port_random',
|
|
|
|
aliases=('network.port_random',)),
|
|
|
|
Method(RTorrent, 'get_directory', 'get_directory',
|
|
|
|
aliases=('directory.default',)),
|
|
|
|
Method(RTorrent, 'get_port_open', 'get_port_open',
|
|
|
|
aliases=('network.port_open',)),
|
|
|
|
Method(RTorrent, 'get_max_file_size', 'get_max_file_size',
|
|
|
|
aliases=('system.file.max_size',)),
|
|
|
|
Method(RTorrent, 'get_stats_not_preloaded', 'get_stats_not_preloaded',
|
|
|
|
aliases=('pieces.stats_not_preloaded',)),
|
|
|
|
Method(RTorrent, 'get_memory_usage', 'get_memory_usage',
|
|
|
|
aliases=('pieces.memory.current',)),
|
|
|
|
Method(RTorrent, 'get_connection_leech', 'get_connection_leech',
|
|
|
|
aliases=('protocol.connection.leech',)),
|
|
|
|
Method(RTorrent, 'get_check_hash', 'get_check_hash',
|
|
|
|
boolean=True,
|
|
|
|
aliases=('pieces.hash.on_completion',)
|
|
|
|
),
|
|
|
|
Method(RTorrent, 'get_session_lock', 'get_session_lock',
|
|
|
|
aliases=('session.use_lock',)),
|
|
|
|
Method(RTorrent, 'get_preload_required_rate', 'get_preload_required_rate',
|
|
|
|
aliases=('pieces.preload.min_rate',)),
|
|
|
|
Method(RTorrent, 'get_max_uploads_global', 'get_max_uploads_global',
|
|
|
|
aliases=('throttle.max_uploads.global',)),
|
|
|
|
Method(RTorrent, 'get_send_buffer_size', 'get_send_buffer_size',
|
|
|
|
aliases=('network.send_buffer.size',)),
|
|
|
|
Method(RTorrent, 'get_port_range', 'get_port_range',
|
|
|
|
aliases=('network.port_range',)),
|
|
|
|
Method(RTorrent, 'get_max_downloads_div', 'get_max_downloads_div',
|
|
|
|
aliases=('throttle.max_downloads.div',)),
|
|
|
|
Method(RTorrent, 'get_max_uploads_div', 'get_max_uploads_div',
|
|
|
|
aliases=('throttle.max_uploads.div',)),
|
|
|
|
Method(RTorrent, 'get_safe_sync', 'get_safe_sync',
|
|
|
|
aliases=('pieces.sync.always_safe',)),
|
|
|
|
Method(RTorrent, 'get_bind', 'get_bind',
|
|
|
|
aliases=('network.bind_address',)),
|
|
|
|
Method(RTorrent, 'get_up_total', 'get_up_total',
|
|
|
|
aliases=('throttle.global_up.total',)),
|
|
|
|
Method(RTorrent, 'get_client_version', 'system.client_version'),
|
|
|
|
Method(RTorrent, 'get_library_version', 'system.library_version'),
|
|
|
|
Method(RTorrent, 'get_api_version', 'system.api_version',
|
|
|
|
min_version=(0, 9, 1)
|
|
|
|
),
|
|
|
|
Method(RTorrent, 'get_system_time', 'system.time',
|
|
|
|
docstring="""Get the current time of the system rTorrent is running on
|
|
|
|
|
|
|
|
@return: time (posix)
|
|
|
|
@rtype: int""",
|
|
|
|
),
|
|
|
|
|
|
|
|
# MODIFIERS
|
|
|
|
Method(RTorrent, 'set_http_proxy', 'set_http_proxy',
|
|
|
|
aliases=('network.http.proxy_address.set',)),
|
|
|
|
Method(RTorrent, 'set_max_memory_usage', 'set_max_memory_usage',
|
|
|
|
aliases=('pieces.memory.max.set',)),
|
|
|
|
Method(RTorrent, 'set_max_file_size', 'set_max_file_size',
|
|
|
|
aliases=('system.file.max_size.set',)),
|
|
|
|
Method(RTorrent, 'set_bind', 'set_bind',
|
|
|
|
docstring="""Set address bind
|
|
|
|
|
|
|
|
@param arg: ip address
|
|
|
|
@type arg: str
|
|
|
|
""",
|
|
|
|
aliases=('network.bind_address.set',)
|
|
|
|
),
|
|
|
|
Method(RTorrent, 'set_up_limit', 'set_upload_rate',
|
|
|
|
docstring="""Set global upload limit (in bytes)
|
|
|
|
|
|
|
|
@param arg: speed limit
|
|
|
|
@type arg: int
|
|
|
|
""",
|
|
|
|
aliases=('throttle.global_up.max_rate.set',)
|
|
|
|
),
|
|
|
|
Method(RTorrent, 'set_port_random', 'set_port_random',
|
|
|
|
aliases=('network.port_random.set',)),
|
|
|
|
Method(RTorrent, 'set_connection_leech', 'set_connection_leech',
|
|
|
|
aliases=('protocol.connection.leech.set',)),
|
|
|
|
Method(RTorrent, 'set_tracker_numwant', 'set_tracker_numwant',
|
|
|
|
aliases=('trackers.numwant.set',)),
|
|
|
|
Method(RTorrent, 'set_max_peers', 'set_max_peers',
|
|
|
|
aliases=('throttle.max_peers.normal.set',)),
|
|
|
|
Method(RTorrent, 'set_min_peers', 'set_min_peers',
|
|
|
|
aliases=('throttle.min_peers.normal.set',)),
|
|
|
|
Method(RTorrent, 'set_max_uploads_div', 'set_max_uploads_div',
|
|
|
|
aliases=('throttle.max_uploads.div.set',)),
|
|
|
|
Method(RTorrent, 'set_max_open_files', 'set_max_open_files',
|
|
|
|
aliases=('network.max_open_files.set',)),
|
|
|
|
Method(RTorrent, 'set_max_downloads_global', 'set_max_downloads_global',
|
|
|
|
aliases=('throttle.max_downloads.global.set',)),
|
|
|
|
Method(RTorrent, 'set_session_lock', 'set_session_lock',
|
|
|
|
aliases=('session.use_lock.set',)),
|
|
|
|
Method(RTorrent, 'set_session', 'set_session',
|
|
|
|
aliases=('session.path.set',)),
|
|
|
|
Method(RTorrent, 'set_split_suffix', 'set_split_suffix',
|
|
|
|
aliases=('system.file.split_suffix.set',)),
|
|
|
|
Method(RTorrent, 'set_hash_interval', 'set_hash_interval'),
|
|
|
|
Method(RTorrent, 'set_handshake_log', 'set_handshake_log'),
|
|
|
|
Method(RTorrent, 'set_port_range', 'set_port_range',
|
|
|
|
aliases=('network.port_range.set',)),
|
|
|
|
Method(RTorrent, 'set_min_peers_seed', 'set_min_peers_seed',
|
|
|
|
aliases=('throttle.min_peers.seed.set',)),
|
|
|
|
Method(RTorrent, 'set_scgi_dont_route', 'set_scgi_dont_route',
|
|
|
|
aliases=('network.scgi.dont_route.set',)),
|
|
|
|
Method(RTorrent, 'set_preload_min_size', 'set_preload_min_size',
|
|
|
|
aliases=('pieces.preload.min_size.set',)),
|
|
|
|
Method(RTorrent, 'set_log.tracker', 'set_log.tracker'),
|
|
|
|
Method(RTorrent, 'set_max_uploads_global', 'set_max_uploads_global',
|
|
|
|
aliases=('throttle.max_uploads.global.set',)),
|
|
|
|
Method(RTorrent, 'set_down_limit', 'set_download_rate',
|
|
|
|
docstring="""Set global download limit (in bytes)
|
|
|
|
|
|
|
|
@param arg: speed limit
|
|
|
|
@type arg: int
|
|
|
|
""",
|
|
|
|
aliases=('throttle.global_down.max_rate.set',)
|
|
|
|
),
|
|
|
|
Method(RTorrent, 'set_preload_required_rate', 'set_preload_required_rate',
|
|
|
|
aliases=('pieces.preload.min_rate.set',)),
|
|
|
|
Method(RTorrent, 'set_hash_read_ahead', 'set_hash_read_ahead'),
|
|
|
|
Method(RTorrent, 'set_max_peers_seed', 'set_max_peers_seed',
|
|
|
|
aliases=('throttle.max_peers.seed.set',)),
|
|
|
|
Method(RTorrent, 'set_max_uploads', 'set_max_uploads',
|
|
|
|
aliases=('throttle.max_uploads.set',)),
|
|
|
|
Method(RTorrent, 'set_session_on_completion', 'set_session_on_completion',
|
|
|
|
aliases=('session.on_completion.set',)),
|
|
|
|
Method(RTorrent, 'set_max_open_http', 'set_max_open_http',
|
|
|
|
aliases=('network.http.max_open.set',)),
|
|
|
|
Method(RTorrent, 'set_directory', 'set_directory',
|
|
|
|
aliases=('directory.default.set',)),
|
|
|
|
Method(RTorrent, 'set_http_cacert', 'set_http_cacert',
|
|
|
|
aliases=('network.http.cacert.set',)),
|
|
|
|
Method(RTorrent, 'set_dht_throttle', 'set_dht_throttle',
|
|
|
|
aliases=('dht.throttle.name.set',)),
|
|
|
|
Method(RTorrent, 'set_hash_max_tries', 'set_hash_max_tries'),
|
|
|
|
Method(RTorrent, 'set_proxy_address', 'set_proxy_address',
|
|
|
|
aliases=('network.proxy_address.set',)),
|
|
|
|
Method(RTorrent, 'set_split_file_size', 'set_split_file_size',
|
|
|
|
aliases=('system.file.split_size.set',)),
|
|
|
|
Method(RTorrent, 'set_receive_buffer_size', 'set_receive_buffer_size',
|
|
|
|
aliases=('network.receive_buffer.size.set',)),
|
|
|
|
Method(RTorrent, 'set_use_udp_trackers', 'set_use_udp_trackers',
|
|
|
|
aliases=('trackers.use_udp.set',)),
|
|
|
|
Method(RTorrent, 'set_connection_seed', 'set_connection_seed',
|
|
|
|
aliases=('protocol.connection.seed.set',)),
|
|
|
|
Method(RTorrent, 'set_xmlrpc_size_limit', 'set_xmlrpc_size_limit',
|
|
|
|
aliases=('network.xmlrpc.size_limit.set',)),
|
|
|
|
Method(RTorrent, 'set_xmlrpc_dialect', 'set_xmlrpc_dialect',
|
|
|
|
aliases=('network.xmlrpc.dialect.set',)),
|
|
|
|
Method(RTorrent, 'set_safe_sync', 'set_safe_sync',
|
|
|
|
aliases=('pieces.sync.always_safe.set',)),
|
|
|
|
Method(RTorrent, 'set_http_capath', 'set_http_capath',
|
|
|
|
aliases=('network.http.capath.set',)),
|
|
|
|
Method(RTorrent, 'set_send_buffer_size', 'set_send_buffer_size',
|
|
|
|
aliases=('network.send_buffer.size.set',)),
|
|
|
|
Method(RTorrent, 'set_max_downloads_div', 'set_max_downloads_div',
|
|
|
|
aliases=('throttle.max_downloads.div.set',)),
|
|
|
|
Method(RTorrent, 'set_name', 'set_name',
|
|
|
|
aliases=('session.name.set',)),
|
|
|
|
Method(RTorrent, 'set_port_open', 'set_port_open',
|
|
|
|
aliases=('network.port_open.set',)),
|
|
|
|
Method(RTorrent, 'set_timeout_sync', 'set_timeout_sync',
|
|
|
|
aliases=('pieces.sync.timeout.set',)),
|
|
|
|
Method(RTorrent, 'set_peer_exchange', 'set_peer_exchange',
|
|
|
|
aliases=('protocol.pex.set',)),
|
|
|
|
Method(RTorrent, 'set_ip', 'set_ip',
|
|
|
|
docstring="""Set IP
|
|
|
|
|
|
|
|
@param arg: ip address
|
|
|
|
@type arg: str
|
|
|
|
""",
|
|
|
|
aliases=('network.local_address.set',)
|
|
|
|
),
|
|
|
|
Method(RTorrent, 'set_timeout_safe_sync', 'set_timeout_safe_sync',
|
|
|
|
aliases=('pieces.sync.timeout_safe.set',)),
|
|
|
|
Method(RTorrent, 'set_preload_type', 'set_preload_type',
|
|
|
|
aliases=('pieces.preload.type.set',)),
|
|
|
|
Method(RTorrent, 'set_check_hash', 'set_check_hash',
|
|
|
|
docstring="""Enable/Disable hash checking on finished torrents
|
|
|
|
|
|
|
|
@param arg: True to enable, False to disable
|
|
|
|
@type arg: bool
|
|
|
|
""",
|
|
|
|
boolean=True,
|
|
|
|
aliases=('pieces.hash.on_completion.set',)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
|
|
|
|
class_methods = [
|
|
|
|
(RTorrent, methods),
|
|
|
|
(File, file_methods),
|
|
|
|
(Torrent, torrent_methods),
|
|
|
|
(Tracker, tracker_methods),
|
|
|
|
(Peer, peer_methods)]
|
|
|
|
|
|
|
|
for c, methods in class_methods:
|
|
|
|
# noinspection PyProtectedMember
|
|
|
|
rpc._build_rpc_methods(c, methods)
|
|
|
|
_build_class_methods(c)
|