def main(): """ Entry function """ parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument( '-d', '--dir', type=lambda x: is_valid_directory(parser, x), help='the directory to hold the file structure', required=True ) parser.add_argument( 'hosts', metavar='H', type=lambda x: is_valid_host(parser, x), nargs='+', help='the Deluge hosts' ) args = parser.parse_args() tracker_map = {} clients = [] for host in args.hosts: client = DelugeRPCClient(*host) client.connect() clients.append(client) for entry in listdir_fullpath(args.dir): recursive_rm_dir(entry) for client in clients: torrents = client.call( 'core.get_torrents_status', {}, ['name', 'save_path', 'tracker_host'] ) for _, torrent in torrents.items(): if torrent[b'tracker_host'] not in tracker_map: tracker_map[torrent[b'tracker_host'].decode('utf-8')] = [] tracker_map[torrent[b'tracker_host'].decode('utf-8')].append(torrent) for tracker, torrents in tracker_map.items(): loc = os.path.join(args.dir, tracker) if not os.path.exists(loc): os.makedirs(loc) for torrent in torrents: link_from = os.path.join(loc, torrent[b'name'].decode('utf-8')) link_to = os.path.join( torrent[b'save_path'].decode('utf-8'), torrent[b'name'].decode('utf-8') ) if not os.path.exists(link_from): try: os.symlink(link_to, link_from) except OSError as error: if error.errno == errno.EEXIST: os.remove(link_from) os.symlink(link_to, link_from) else: raise error
def __init__(self, username, password, host="127.0.0.1", port=58846): self._username = username self._password = password self._host = host self._port = port self.__client = DelugeRPCClient(host, int(port), username, password)
def connect(self, host, username, password, test=False): if self.conn is not None: return self.connect if not host: return {'status': False, 'error': 'No host specified'} if not username: return {'status': False, 'error': 'No username specified'} if not password: return {'status': False, 'error': 'No password specified'} # Get port from the config host,portnr = host.split(':') # logger.info('Connecting to ' + host + ':' + portnr + ' Username: '******' Password: '******'Could not create DelugeRPCClient Object %s' % e) return {'status': False, 'error': e} else: try: self.client.connect() except Exception as e: logger.error('Could not connect to Deluge: %s' % host) return {'status': False, 'error': e} else: if test is True: daemon_version = self.client.call('daemon.info') libtorrent_version = self.client.call('core.get_libtorrent_version') return {'status': True, 'daemon_version': daemon_version, 'libtorrent_version': libtorrent_version} else: return self.client
def connect(self, host, username, password): if self.conn is not None: return self.connect if not host: return False # Get port from the config host,portnr = host.split(':') #if username and password: # logger.info('Connecting to ' + host + ':' + portnr + ' Username: '******' Password: '******'Could not create DelugeRPCClient Object' + e) return False else: try: self.client.connect() except Exception as e: logger.error('Could not connect to Deluge ' + host) else: return self.client
def connect(self, timeout=20): config = cherrypy.tree.apps[''].config['opmuse'] if 'deluge.host' not in config: log('Deluge not configured, skipping') return False host = config['deluge.host'] port = config['deluge.port'] user = config['deluge.user'] password = config['deluge.password'] DelugeRPCClient.timeout = timeout self.client = DelugeRPCClient(host, port, user, password) try: self.client.connect() except OSError as e: if e.errno == 113: # "No route to host" log('No route to host: %s' % host) return False else: raise e return self.client.connected
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Deluge switch.""" from deluge_client import DelugeRPCClient name = config.get(CONF_NAME) host = config.get(CONF_HOST) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) port = config.get(CONF_PORT) deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() except ConnectionRefusedError: _LOGGER.error("Connection to Deluge Daemon failed") raise PlatformNotReady add_entities([DelugeSwitch(deluge_api, name)])
class DelugePlugin(object): """Base class for deluge plugins, contains settings and methods for connecting to a deluge daemon.""" def on_task_start(self, task, config): """Raise a DependencyError if our dependencies aren't available""" try: from deluge_client import DelugeRPCClient except ImportError as e: log.debug('Error importing deluge-client: %s' % e) raise plugin.DependencyError('deluge', 'deluge-client', 'deluge-client >=1.5 is required. `pip install deluge-client` to install.', log) config = self.prepare_config(config) if config['host'] in ['localhost', '127.0.0.1'] and not config.get('username'): # If an username is not specified, we have to do a lookup for the localclient username/password auth = self.get_localhost_auth() if auth and auth[0]: config['username'], config['password'] = auth else: raise plugin.PluginError('Unable to get local authentication info for Deluge. You may need to ' 'specify an username and password from your Deluge auth file.') self.client = DelugeRPCClient(config['host'], config['port'], config['username'], config['password'], decode_utf8=True) def prepare_config(self, config): config.setdefault('host', 'localhost') config.setdefault('port', 58846) return config def get_torrents_status(self, fields, filters=None): """Fetches all torrents and their requested fields optionally filtered""" if filters is None: filters = {} return self.client.call('core.get_torrents_status', filters, fields) @staticmethod def get_localhost_auth(): if sys.platform.startswith('win'): auth_file = os.path.join(os.getenv('APPDATA'), 'deluge', 'auth') else: auth_file = os.path.expanduser('~/.config/deluge/auth') if not os.path.isfile(auth_file): return None with open(auth_file) as auth: for line in auth: line = line.strip() if line.startswith('#') or not line: # This is a comment or blank line continue lsplit = line.split(':') if lsplit[0] == 'localclient': username, password = lsplit[:2] return username, password
def torrents_status(): STATUS_KEYS = [ "state", "download_location", "tracker_host", "tracker_status", "next_announce", "name", "total_size", "progress", "num_seeds", "total_seeds", "num_peers", "total_peers", "eta", "download_payload_rate", "upload_payload_rate", "ratio", "distributed_copies", "num_pieces", "piece_length", "total_done", "files", "file_priorities", "file_progress", "peers", "is_seed", "is_finished", "active_time", "seeding_time" ] from deluge_client import DelugeRPCClient client = DelugeRPCClient('127.0.0.1', 2196, "seftembr", "TuGsFYqlNP") client.connect() print "--- ACTIVE ---" for (hashid, fields) in client.call('core.get_torrents_status', {"state":"Active"}, STATUS_KEYS).iteritems(): print "%s: %s (%.2f out of %s - active for %s so far)" % (hashid, fields['name'], fields['progress'], sizeof_fmt(fields['total_size']), human_time(seconds=fields['active_time'])) print "--- PAUSED ---" for (hashid, fields) in client.call('core.get_torrents_status', {"state":"Paused"}, STATUS_KEYS).iteritems(): if fields['progress'] == 100: print "%s: %s (%s downloaded in %s)" % (hashid, fields['name'], sizeof_fmt(fields['total_size']), human_time(seconds=fields['active_time'])) else: print "%s: %s (%.2f out of %s - was active for %s - and paused)" % (hashid, fields['name'], fields['progress'], sizeof_fmt(fields['total_size']), human_time(seconds=fields['active_time']))
def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Deluge sensors.""" from deluge_client import DelugeRPCClient name = config.get(CONF_NAME) host = config.get(CONF_HOST) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) port = config.get(CONF_PORT) deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() except ConnectionRefusedError: _LOGGER.error("Connection to Deluge Daemon failed") raise PlatformNotReady dev = [] for variable in config[CONF_MONITORED_VARIABLES]: dev.append(DelugeSensor(variable, deluge_api, name)) add_devices(dev)
def __init__(self, host, port, username, password): """ Initializes a new Deluge client. url - The url where deluge json can be reached. password - The password used to login """ self.host = host self.port = port self.username = username self.password = password self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password)
def __init__(self, host, username, password, label=None): """ Initializes a new Deluge client. url - The url where deluge json can be reached. password - The password used to login """ host, port = host.split(':') self.host = host self.port = int(port) self.username = username self.password = password self.label = label self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True)
def uploadTorrent(self, filename): """ Upload a torrent to the deluge host based on the config file """ print('Uploading torrent %s' % (filename)) client = DelugeRPCClient(self.hostDeluge, self.portDeluge, self.usernameDeluge, self.passwordDeluge) client.connect() f = open(filename, 'rb') filedump = base64.encodestring(f.read()) f.close() client.call('core.add_torrent_file', filename, filedump, {}, ) bytes_available = client.call('core.get_free_space') gig_available = bytes_available/(1024.*1024*1024) print('There is %.1f GB available on the host \'%s\'.' % (gig_available, self.hostDeluge))
def on_task_start(self, task, config): """Raise a DependencyError if our dependencies aren't available""" try: from deluge_client import DelugeRPCClient except ImportError as e: log.debug('Error importing deluge-client: %s' % e) raise plugin.DependencyError('deluge', 'deluge-client', 'deluge-client >=1.5 is required. `pip install deluge-client` to install.', log) config = self.prepare_config(config) if config['host'] in ['localhost', '127.0.0.1'] and not config.get('username'): # If an username is not specified, we have to do a lookup for the localclient username/password auth = self.get_localhost_auth() if auth and auth[0]: config['username'], config['password'] = auth else: raise plugin.PluginError('Unable to get local authentication info for Deluge. You may need to ' 'specify an username and password from your Deluge auth file.') self.client = DelugeRPCClient(config['host'], config['port'], config['username'], config['password'], decode_utf8=True)
def collect(self): deluge_host = os.environ.get('DELUGE_HOST', '127.0.0.1') client = DelugeRPCClient(deluge_host, self.rpc_port, self.rpc_user, self.rpc_password) client.connect() libtorrent_status_metrics = get_libtorrent_status_metrics_meta() libtorrent_status_metric_source_names = [ x['source'] for x in libtorrent_status_metrics.values() ] libtorrent_status_metric_values = client.call( 'core.get_session_status', libtorrent_status_metric_source_names) for metric, props in libtorrent_status_metrics.items(): if props['type'] is None: continue value = libtorrent_status_metric_values[props['source']] if 'conv' in props: value = props['conv'](value) yield props['type']('deluge_libtorrent_{}'.format(metric), props['help'], value=value) for direction in ['upload', 'download']: transfer_metric = CounterMetricFamily( 'deluge_libtorrent_{}_bytes_total'.format(direction), 'Total bytes {}ed for all torrents.'.format(direction), labels=['type']) for traffic_type in ['payload', 'ip_overhead', 'dht', 'tracker']: transfer_metric.add_metric( [traffic_type], libtorrent_status_metric_values['total_{}_{}'.format( traffic_type, direction).encode('ascii')]) yield transfer_metric yield new_metric_with_labels_and_value( GaugeMetricFamily, 'deluge_info', 'Deluge information', labels={ 'version': client.call('daemon.info').decode('utf-8'), 'libtorrent_version': client.call('core.get_libtorrent_version').decode('utf-8'), }, value=1) for key, value in client.call('core.get_config').items(): if isinstance(value, (int, float, bool)): yield GaugeMetricFamily( 'deluge_config_{}'.format(key.decode('utf-8')), 'Value of the deluge config setting {}'.format( key.decode('utf-8')), value=value) torrents_by_state = { 'downloading': 0, 'seeding': 0, 'paused': 0, 'checking': 0, 'queued': 0, 'error': 0, 'active': 0, # not the prometheus way, but the states above (as defined by deluge) are already overlapping, so sum() over them is already meaningless 'total': 0, } torrents_by_label = defaultdict(int) for torrent in client.core.get_torrents_status({}, [ b'label', b'state', b'download_payload_rate', b'upload_payload_rate' ]).values(): if b'label' in torrent: torrents_by_label[torrent[b'label'].decode('utf-8')] += 1 torrents_by_state[torrent[b'state'].decode('utf-8').lower()] += 1 torrents_by_state['total'] += 1 if torrent[b'download_payload_rate'] > 0 or torrent[ b'upload_payload_rate'] > 0: torrents_by_state['active'] += 1 if len(torrents_by_label) > 0: torrents_by_label_metric = GaugeMetricFamily( 'deluge_torrents_by_label', 'The number of torrents for each label assigned to a torrent using the deluge label plugin', labels=['label']) for label, count in torrents_by_label.items(): torrents_by_label_metric.add_metric([label], count) yield torrents_by_label_metric torrents_metric = GaugeMetricFamily( 'deluge_torrents', 'The number of torrents in a specific state (note: some states overlap)', labels=['state']) for state, torrent_count in torrents_by_state.items(): torrents_metric.add_metric([state], torrent_count) yield torrents_metric client.disconnect()
def init(self): self.client = DelugeRPCClient(self.host, self.port, self.username, self.password) self.data = {}
def collect(self): deluge_host = os.environ.get('DELUGE_HOST', '127.0.0.1') client = DelugeRPCClient(deluge_host, self.rpc_port, self.rpc_user, self.rpc_password) client.connect() libtorrent_metrics = get_libtorrent_metrics_meta() libtorrent_metric_values = client.call('core.get_session_status', []) for metric, metric_type in libtorrent_metrics.items(): encoded_name = metric.encode('ascii') if encoded_name in libtorrent_metric_values: yield metric_type( 'deluge_libtorrent_{}'.format(metric.replace('.', '_')), 'libtorrent metric {}'.format(metric), value=libtorrent_metric_values[encoded_name] ) yield new_metric_with_labels_and_value(GaugeMetricFamily, 'deluge_info', 'Deluge information', labels={ 'version': client.call('daemon.info').decode('utf-8'), 'libtorrent_version': client.call('core.get_libtorrent_version').decode('utf-8'), }, value=1 ) for key, value in client.call('core.get_config').items(): if isinstance(value, (int, float, bool)): yield GaugeMetricFamily('deluge_config_{}'.format(key.decode('utf-8')), 'Value of the deluge config setting {}'.format(key.decode('utf-8')), value=value) torrents_by_state = { 'downloading': 0, 'seeding': 0, 'paused': 0, 'checking': 0, 'queued': 0, 'error': 0, 'active': 0, # not the prometheus way, but the states above (as defined by deluge) are already overlapping, so sum() over them is already meaningless 'total': 0, } torrents_by_label = defaultdict(int) for torrent in client.core.get_torrents_status({}, [b'label', b'state', b'download_payload_rate', b'upload_payload_rate']).values(): if b'label' in torrent: torrents_by_label[torrent[b'label'].decode('utf-8')] += 1 torrents_by_state[torrent[b'state'].decode('utf-8').lower()] += 1 torrents_by_state['total'] += 1 if torrent[b'download_payload_rate'] > 0 or torrent[b'upload_payload_rate'] > 0: torrents_by_state['active'] += 1 if len(torrents_by_label) > 0: torrents_by_label_metric = GaugeMetricFamily('deluge_torrents_by_label', 'The number of torrents for each label assigned to a torrent using the deluge label plugin', labels=['label']) for label, count in torrents_by_label.items(): torrents_by_label_metric.add_metric([label], count) yield torrents_by_label_metric torrents_metric = GaugeMetricFamily('deluge_torrents', 'The number of torrents in a specific state (note: some states overlap)', labels=['state']) for state, torrent_count in torrents_by_state.items(): torrents_metric.add_metric([state], torrent_count) yield torrents_metric if self.per_torrent_metrics_enabled: per_torrent_keys = [ (CounterMetricFamily, b'total_done', 'The amount of data downloaded for this torrent'), (CounterMetricFamily, b'total_size', 'The size of this torrent'), (CounterMetricFamily, b'total_uploaded', 'The amount of data uploaded for this torrent'), (GaugeMetricFamily, b'num_peers', 'The number of peers currently connected to for this torrent'), (GaugeMetricFamily, b'num_seeds', 'The number of seeds currently connected to for this torrent'), (GaugeMetricFamily, b'total_peers', 'The number of peers in the swarm for this torrent'), (GaugeMetricFamily, b'total_seeds', 'The number of seeds in the swarm for this torrent'), ] per_torrent_metrics = dict(generate_per_torrent_metrics(per_torrent_keys)) for torrent_hash, torrent in client.core.get_torrents_status({}, [key[1] for key in per_torrent_keys] + [b'name']).items(): for metric_name, metric in per_torrent_metrics.items(): metric.add_metric( [ torrent[b'name'].decode('utf-8'), torrent_hash.decode('utf-8') ], torrent[metric_name] ) for metric in per_torrent_metrics.values(): yield metric client.disconnect()
from deluge_client import DelugeRPCClient from config import config client = DelugeRPCClient(config.delugehost.strip('"'), int(config.delugeport), config.delugeuser.strip('"'), config.delugepass.strip('"')) client.connect() def clean(id): client.call("core.remove_torrent", id, True)
class TorrentUtils: client = None methods = [] torrents = [] def __init__(self, username='******', password='******', host='127.0.0.1', port=58846): self.checkDelugeExist() if username and password: self.client = DelugeRPCClient(host, port, username, password) try: self.client.connect() except ConnectionRefusedError: pass self.checkConnection() self.getMethods() self.getTorrents() def checkConnection(self): if not self.client or not self.client.connected: globalUtils.messageHandler('Torrent daemon not connected', tp='err') exit() @staticmethod def checkDelugeExist(): if not which('deluge') or not which('deluged'): globalUtils.messageHandler('Deluge or Deluged daemon not installed', tp='err') exit() def getMethods(self) -> list: self.methods = self.client.call('daemon.get_method_list') return self.methods def getTorrents(self, fields: list = [], filters: dict = {}) -> list: self.torrents = self.client.call('core.get_torrents_status', filters, fields) return self.torrents def addTorrent(self, path: Union[str, Path]) -> Union[str, bool]: try: torrent = Torrent.from_file(path) except BencodeDecodingError: return False torrentId = torrent.info_hash if not self.checkTorrentExist(torrent.info_hash): fileEncoded = globalUtils.readFile(path) torrentId = self.client.call('core.add_torrent_file', '', fileEncoded, { 'sequential_download': True, 'prioritize_first_last': True}) globalUtils.messageHandler(self.getTorrentName(path), '+ Download', tp='msg') return torrentId globalUtils.messageHandler(self.getTorrentName(path), 'Exist', tp='err') self.resumeTorrent(torrentId) return torrentId def stopTorrent(self, torrentHash: str): self.client.call('core.pause_torrent', [torrentHash]) def resumeTorrent(self, torrentHash: str): self.client.call('core.resume_torrent', [torrentHash]) def setTorrentOptions(self, torrentId: list, options: dict): self.client.call('core.set_torrent_options', [torrentId], options) def addPlugin(self, path: Union[str, Path]): fileEncoded = globalUtils.readFile(path) fileName = Path(path).name self.client.call('core.upload_plugin', fileName, fileEncoded) def checkTorrentExist(self, torrentHash): if type(torrentHash) != bytes: torrentHash = torrentHash.encode('UTF-8') return bool(torrentHash in self.torrents) @staticmethod def saveTorrentFile(torrentUrl, fileName): torrentData = requests.get(torrentUrl).content path = globalUtils.saveFile(torrentData, fileName, 'torrentFiles') return path @staticmethod def deleteTorrentFile(fileName): globalUtils.deleteFile(fileName, 'torrentFiles') @staticmethod def getTorrentName(torrent: Union[str, Path]): return Torrent.from_file(torrent).name @staticmethod def getSavedTorrentFiles(): files = Path('torrentFiles').glob('*.torrent') filesList = [] for f in files: filesList.append(str(f)) return filesList
import os import base64 from deluge_client import DelugeRPCClient import time tInicial = time.time() client = DelugeRPCClient('127.0.0.1', 58846, 'monitoria', 'monitoria') client.connect() print(client.connected) path = "C:/Users/Profesor/Documents/monitoria/nueva/torrents/ubuntu.torrent" opts = {} opts[ 'download_location'] = "C:/Users/Profesor/Documents/monitoria/nueva/destino" f = open(path, 'rb') filedump = base64.encodestring(f.read()) f.close() filename = os.path.basename(path) a = client.call('core.add_torrent_file', filename, filedump, opts) tFinal = time.time() print(tFinal - tInicial)
class DelugeClient(BTClientBase): def __init__(self, rpc_address, rpc_port, username, password, config=None): if config is None: self.use_config = False self.rpc_address = rpc_address self.rpc_port = int(rpc_port) self.username = username self.password = password self.client = DelugeRPCClient(self.rpc_address, self.rpc_port, self.username, self.password, automatic_reconnect=True) self.connected = False else: self.use_config = True self.config = config def connect(self): self.client.connect() self.connected = self.client.connected if self.connected: ret = ClientRet(ret_type=2) else: ret = ClientRet(ret_type=-2) return ret def add_torrent(self, torrent_path, download_path=None): if not self.connected: ret = ClientRet(ret_type=-2) return ret options = { } # Ref: https://github.com/deluge-torrent/deluge/blob/1.3-stable/deluge/core/torrent.py options['add_paused'] = False if download_path is not None: options['download_location'] = str(Path(download_path).resolve()) abs_torrent_path = str(Path(torrent_path).resolve()) torrent_content = open(abs_torrent_path, 'rb').read() torrent_base64 = base64.b64encode(torrent_content) torrent_idx = self.client.core.add_torrent_file( filename=abs_torrent_path, filedump=torrent_base64, options=options) if torrent_idx is not None: ret = ClientRet(ret_type=3, ret_value=torrent_idx.decode()) else: ret = ClientRet(ret_type=-3) return ret def list_torrents(self): if not self.connected: ret = ClientRet(ret_type=-2) return ret torrent_id_list = self.client.core.get_session_state() session_status = {} for idx in torrent_id_list: torrent_status_raw = self.client.core.get_torrent_status( torrent_id=idx, keys=bt_client.client_base.torrent_status_key) torrent_status = TorrentStatus( torrent_id=idx.decode(), is_finished=torrent_status_raw['is_finished'.encode()], name=torrent_status_raw['name'.encode()].decode()) session_status[torrent_status.torrent_id] = torrent_status ret = ClientRet(ret_type=4, ret_value=session_status) return ret def get_torrent_status( self, idx ): # All the value inputted and returned back should be string, not bytearray if not self.connected: ret = ClientRet(ret_type=-2) return ret idx = idx.encode() # Convert to byte array for Deluge torrent_status_raw = self.client.core.get_torrent_status( torrent_id=idx, keys=bt_client.client_base.torrent_status_key) torrent_status = TorrentStatus( torrent_id=idx.decode(), is_finished=torrent_status_raw[ 'is_finished'.encode()], # Decode bytearray to string name=torrent_status_raw[ 'name'.encode()].decode()) # Decode bytearray to string ret = ClientRet(ret_type=6, ret_value=torrent_status) return ret def del_torrent(self, idx, remove_data=True): if not self.connected: ret = ClientRet(ret_type=-2) return ret idx_byte = str(idx).encode() torrent_id_list = self.client.core.get_session_state() if idx_byte in torrent_id_list: self.client.core.remove_torrent(torrent_id=idx_byte, remove_data=remove_data) tlist = self.client.core.get_session_state() if idx not in tlist: ret = ClientRet(ret_type=5) return ret else: ret = ClientRet(ret_type=-5) return ret else: ret = ClientRet(ret_type=-5) return ret def disconnect(self): if self.connected: self.client.disconnect() self.connected = False ret = ClientRet(ret_type=0) return ret
def deluge_connect(host, port, username, password): client = DelugeRPCClient(host, port, username, password) client.connect() assert client.connected return client
def get_movie(my_call, search_lst): for item, var in my_call.items(): search_me = str(var[b'name'], 'utf-8') new_srch = PTN.parse(search_me.lower()) if 'episode' in new_srch and 'season' in new_srch: continue choice = process.extractOne(new_srch['title'], search_lst) if choice[1] > 95: print(choice) print(item, var) paramiko.util.log_to_file('/tmp/paramiko.log') transport = paramiko.Transport(("dragoncave8.ddns.net", 1889)) transport.connect(None, "retsu", "dragon1991!") sftp = paramiko.SFTPClient.from_transport(transport) movies = sftp.listdir("/mnt/Media/Movies") search_lst = [PTN.parse(item.lower())['title'] for item in movies] client = DelugeRPCClient('perses.feralhosting.com', 53305, 'retsu8', 'yf-AXshN8_FjXTZA') client.connect() my_call = client.call('core.get_torrents_status', {}, ['name', 'ratio']) if transport is not None: transport.close()
class Client(GenericClient, DelugeBase): def __init__(self, host=None, username=None, password=None): super(Client, self).__init__('DelugeD', host, username, password) self.client = None def setup(self): parsed_url = urlparse(self.host) if self.client and all([ self.client.host == parsed_url.hostname, self.client.port == parsed_url.port, self.client.username == self.username, self.client.password == self.password ]): return self.client = DelugeRPCClient(parsed_url.hostname, parsed_url.port or 58846, self.username, self.password) def _get_auth(self): self.setup() if not self.client.connected: for attempt in range(0, 5): try: self.client.connect() break except FailedToReconnectException: time.sleep(5) self.auth = self.client.connected return self.auth def _add_torrent_uri(self, result): remote_torrent = self.client.core.add_torrent_magnet( result.url, self.make_options(result)) if not remote_torrent: return None result.hash = remote_torrent return remote_torrent def _add_torrent_file(self, result): if not result.content: result.content = {} return None remote_torrent = self.client.core.add_torrent_file( result.name + '.torrent', b64encode(result.content), self.make_options(result)) if not remote_torrent: return None result.hash = remote_torrent return remote_torrent def _set_torrent_label(self, result): # No option for this built into the rpc, because it is a plugin label = sickbeard.TORRENT_LABEL.lower() if result.show.is_anime: label = sickbeard.TORRENT_LABEL_ANIME.lower() if ' ' in label: logger.log( self.name + ': Invalid label. Label must not contain a space', logger.ERROR) return False if label: try: labels = self.client.label.get_labels() if label not in labels: logger.log( self.name + ': ' + label + " label does not exist in Deluge we must add it", logger.DEBUG) self.client.labels.add(label) logger.log( self.name + ': ' + label + " label added to Deluge", logger.DEBUG) self.client.label.set_torrent(result.hash, label) except: logger.log(self.name + ': ' + "label plugin not detected", logger.DEBUG) return False logger.log(self.name + ': ' + label + " label added to torrent", logger.DEBUG) return True def testAuthentication(self): if self._get_auth() and self.client.daemon.info(): return True, 'Success: Connected and Authenticated' else: return False, 'Error: Unable to Authenticate! Please check your config!'
class DelugeClient(BaseClient): identifier = 'deluge' def __init__(self, host, username, password): """ Initializes a new Deluge client. url - The url where deluge json can be reached. password - The password used to login """ host, port = host.split(':') self.host = host self.port = int(port) self.username = username self.password = password self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password) def _login(self): """ Logs into deluge """ if not self.rpcclient.connected: self.rpcclient.connect() def get_config(self): """ Get the current configuration that can be used in the autotorrent config file """ return { 'host': '%s:%s' % (self.host, self.port), 'username': self.username, 'password': self.password, } @classmethod def auto_config(cls): """ Tries to auto configure deluge using the .config/deluge files """ config_path = os.path.expanduser('~/.config/deluge/core.conf') if not os.path.isfile(config_path): logger.debug('deluge config file was not found') return if not os.access(config_path, os.R_OK): logger.debug('Unable to access deluge config file at %s' % config_path) return auth_path = os.path.expanduser('~/.config/deluge/auth') if not os.path.isfile(auth_path): logger.debug('deluge auth file was not found') return if not os.access(auth_path, os.R_OK): logger.debug('Unable to access deluge confauthig file at %s' % auth_path) return with open(config_path, 'r') as f: config_data = f.read() daemon_port = re.findall('"daemon_port":\s*(\d+)', config_data) if not daemon_port: logger.debug('No deluge port, just trying to use default') daemon_port = 58846 else: daemon_port = int(daemon_port[0]) with open(auth_path, 'r') as f: auth_data = f.read() auth_data = auth_data.split('\n')[0].split(':') if len(auth_data[0]) < 2: logger.debug('Invalid entry found in auth file') return username = auth_data[0] password = auth_data[1] return cls('127.0.0.1:%s' % daemon_port, username, password) def test_connection(self): """ Tests the Deluge RPC connection, returns message if found. """ self._login() return 'Free space: %s' % humanize_bytes( self.rpcclient.call('core.get_free_space')) def get_torrents(self): """ Returns a set of info hashes currently added to the client. """ logger.info('Getting a list of torrent hashes') self._login() result = self.rpcclient.call('core.get_torrents_status', {}, ['name']) return set(x.lower().decode('ascii') for x in result.keys()) def add_torrent(self, torrent, destination_path, files, fast_resume=True): """ Add a new torrent to Deluge. torrent is the decoded file as a python object. destination_path is where the links are. The complete files must be linked already. files is a list of files found in the torrent. """ name = torrent[b'info'][b'name'] logger.info('Trying to add a new torrent to deluge: %r' % name) destination_path = os.path.abspath(destination_path) infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest() encoded_torrent = base64.b64encode(bencode(torrent)) basename = os.path.basename(destination_path) mapped_files = {} for i, f in enumerate(files): mapped_files[i] = os.path.join(basename, *f['path']) self._login() result = self.rpcclient.call( 'core.add_torrent_file', 'torrent.torrent', encoded_torrent, { 'download_location': os.path.dirname(destination_path), 'mapped_files': mapped_files, 'seed_mode': fast_resume }) return result and result.decode('utf-8') == infohash
def connect(self): """Connect to the host using synchronousdeluge API.""" self.client = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True) self.client.connect()
class DelugeRPC(object): """Deluge RPC client class.""" def __init__(self, host='localhost', port=58846, username=None, password=None): """Constructor. :param host: :type host: str :param port: :type port: int :param username: :type username: str :param password: :type password: str """ super(DelugeRPC, self).__init__() self.host = host self.port = int(port) self.username = username self.password = password def connect(self): """Connect to the host using synchronousdeluge API.""" self.client = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True) self.client.connect() def test(self): """Test connection. :return: :rtype: bool """ try: self.connect() except Exception: return False else: return True def remove_torrent_data(self, torrent_id): """Remove torrent from client using given info_hash. :param torrent_id: :type torrent_id: str :return: :rtype: str or bool """ try: self.connect() self.client.core.remove_torrent(torrent_id, True) except Exception: return False else: return True finally: if self.client: self.disconnect() def move_storage(self, torrent_id, location): """Move torrent to new location and return torrent id/hash. :param torrent_id: :type torrent_id: str :param location: :type location: str :return: :rtype: str or bool """ try: self.connect() self.client.core.move_storage(torrent_id, location) except Exception: return False else: return True finally: if self.client: self.disconnect() def add_torrent_magnet(self, torrent, options, info_hash): """Add Torrent magnet and return torrent id/hash. :param torrent: :type torrent: str :param options: :type options: dict :param info_hash: :type info_hash: str :return: :rtype: str or bool """ try: self.connect() torrent_id = self.client.core.add_torrent_magnet(torrent, options) if not torrent_id: torrent_id = self._check_torrent(info_hash) except Exception: raise return False else: return torrent_id finally: if self.client: self.disconnect() def add_torrent_file(self, filename, torrent, options, info_hash): """Add Torrent file and return torrent id/hash. :param filename: :type filename: str :param torrent: :type torrent: str :param options: :type options: dict :param info_hash: :type info_hash: str :return: :rtype: str or bool """ try: self.connect() torrent_id = self.client.core.add_torrent_file(filename, b64encode(torrent), options) if not torrent_id: torrent_id = self._check_torrent(info_hash) except Exception: return False else: return torrent_id finally: if self.client: self.disconnect() def set_torrent_label(self, torrent_id, label): """Set Torrent label. :param torrent_id: :type torrent_id: str :param label: :type label: str :return: :rtype: bool """ try: self.connect() self.client.label.set_torrent(torrent_id, label) except Exception: return False else: return True finally: if self.client: self.disconnect() def set_torrent_path(self, torrent_id, path): """Set Torrent path. :param torrent_id: :type torrent_id: str :param path: :type path: str :return: :rtype: bool """ try: self.connect() self.client.core.set_torrent_move_completed_path(torrent_id, path) self.client.core.set_torrent_move_completed(torrent_id, 1) except Exception: return False else: return True finally: if self.client: self.disconnect() def set_torrent_priority(self, torrent_id, priority): """Set Torrent priority. :param torrent_id: :type torrent_id: str :param priority: :type priority: bool :return: :rtype: bool """ try: self.connect() if priority: self.client.core.queue_top([torrent_id]) except Exception: return False else: return True finally: if self.client: self.disconnect() def set_torrent_ratio(self, torrent_id, ratio): """Set Torrent ratio. :param torrent_id: :type torrent_id: str :param ratio: :type ratio: float :return: :rtype: bool """ try: self.connect() self.client.core.set_torrent_stop_at_ratio(torrent_id, True) self.client.core.set_torrent_stop_ratio(torrent_id, ratio) except Exception: return False else: return True finally: if self.client: self.disconnect() def pause_torrent(self, torrent_ids): """Pause torrent. :param torrent_ids: :type torrent_ids: list of str :return: :rtype: bool """ try: self.connect() self.client.core.pause_torrent(torrent_ids) except Exception: return False else: return True finally: if self.client: self.disconnect() def disconnect(self): """Disconnect RPC client.""" self.client.disconnect() def _check_torrent(self, info_hash): torrent_id = self.client.core.get_torrent_status(info_hash, {}) if torrent_id.get('hash'): log.debug('DelugeD: Torrent already exists in Deluge') return info_hash return False def get_all_torrents(self): """Get all torrents in client. :return: :rtype: bool """ try: self.connect() torrents_data = self.client.core.get_torrents_status({}, ('name', 'hash', 'progress', 'state', 'ratio', 'stop_ratio', 'is_seed', 'is_finished', 'paused', 'files')) except Exception: return False else: return torrents_data finally: if self.client: self.disconnect()
class Deluge(IntervalModule): """ Deluge torrent module Requires `deluge-client` .. rubric:: Formatters: * `{num_torrents}` - number of torrents in deluge * `{free_space_bytes}` - bytes free in path * `{used_space_bytes}` - bytes used in path * `{upload_rate}` - bytes sent per second * `{download_rate}` - bytes received per second * `{total_uploaded}` - bytes sent total * `{total_downloaded}` - bytes received total """ settings = ( 'format', 'color', ('rounding', 'number of decimal places to round numbers too'), ('host', 'address of deluge server (default: 127.0.0.1)'), ('port', 'port of deluge server (default: 58846)'), ('username', 'username to authenticate with deluge'), ('password', 'password to authenticate to deluge'), ('path', 'override "download path" server-side when checking space used/free'), ('offline_string', 'string to output while unable to connect to deluge daemon')) required = ('username', 'password') host = '127.0.0.1' port = 58846 path = None color = None libtorrent_stats = False rounding = 2 offline_string = 'offline' format = '⛆{num_torrents} ✇{free_space_bytes}' id = int(time.time()) # something random def init(self): self.client = DelugeRPCClient(self.host, self.port, self.username, self.password) self.data = {} def run(self): if not self.client.connected: try: self.client.connect() except OSError: self.output = {'full_text': self.offline_string} return try: self.data = self.get_session_statistics() torrents = self.get_torrents_status() if torrents: self.data['num_torrents'] = len(torrents) if 'free_space_bytes' in self.format: self.data['free_space_bytes'] = self.get_free_space(self.path) if 'used_space_bytes' in self.format: self.data['used_space_bytes'] = self.get_path_size(self.path) except FailedToReconnectException: return self.parse_values(self.data) self.output = {'full_text': self.format.format(**self.data)} if self.color: self.output['color'] = self.color def parse_values(self, values): for k, v in values.items(): if v: if k in [ 'total_upload', 'total_download', 'download_rate', 'upload_rate' ] or k.endswith('_bytes'): values[k] = '{value:.{round}f}{unit}'.format( round=self.rounding, **bytes_info_dict(v)) def get_path_size(self, path=None): """ get used space of path in bytes (default: download location) """ if path is None: path = [] return self.client.call('core.get_path_size', path) def get_free_space(self, path=None): """ get free space of path in bytes (default: download location) """ if path is None: path = [] return self.client.call('core.get_free_space', path) def get_torrents_status(self, torrent_id=None, keys=None): if torrent_id is None: torrent_id = [] if keys is None: keys = [] return self.client.call('core.get_torrents_status', torrent_id, keys) def get_session_statistics(self): keys = [ 'upload_rate', 'download_rate', 'total_upload', 'total_download' ] out = { } # some of the values from deluge-client are bytes, the others are ints - we need to decode them for k, v in self.client.call('core.get_session_status', keys).items(): k = k.decode('utf-8') # keys aswell if type(v) == bytes: out[k] = v.decode('utf-8') else: out[k] = v return out
class DelugeClient(BaseClient): identifier = 'deluge' def __init__(self, host, username, password): """ Initializes a new Deluge client. url - The url where deluge json can be reached. password - The password used to login """ host, port = host.split(':') self.host = host self.port = int(port) self.username = username self.password = password self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password) def _login(self): """ Logs into deluge """ if not self.rpcclient.connected: self.rpcclient.connect() def get_config(self): """ Get the current configuration that can be used in the autotorrent config file """ return { 'host': '%s:%s' % (self.host, self.port), 'username': self.username, 'password': self.password, } @classmethod def auto_config(cls): """ Tries to auto configure deluge using the .config/deluge files """ config_path = os.path.expanduser('~/.config/deluge/core.conf') if not os.path.isfile(config_path): logger.debug('deluge config file was not found') return if not os.access(config_path, os.R_OK): logger.debug('Unable to access deluge config file at %s' % config_path) return auth_path = os.path.expanduser('~/.config/deluge/auth') if not os.path.isfile(auth_path): logger.debug('deluge auth file was not found') return if not os.access(auth_path, os.R_OK): logger.debug('Unable to access deluge confauthig file at %s' % auth_path) return with open(config_path, 'r') as f: config_data = f.read() daemon_port = re.findall('"daemon_port":\s*(\d+)', config_data) if not daemon_port: logger.debug('No deluge port, just trying to use default') daemon_port = 58846 else: daemon_port = int(daemon_port[0]) with open(auth_path, 'r') as f: auth_data = f.read() auth_data = auth_data.split('\n')[0].split(':') if len(auth_data[0]) < 2: logger.debug('Invalid entry found in auth file') return username = auth_data[0] password = auth_data[1] return cls('127.0.0.1:%s' % daemon_port, username, password) def test_connection(self): """ Tests the Deluge RPC connection, returns message if found. """ self._login() return 'Free space: %s' % humanize_bytes(self.rpcclient.call('core.get_free_space')) def get_torrents(self): """ Returns a set of info hashes currently added to the client. """ logger.info('Getting a list of torrent hashes') self._login() result = self.rpcclient.call('core.get_torrents_status', {}, ['name']) return set(x.lower().decode('ascii') for x in result.keys()) def add_torrent(self, torrent, destination_path, files, fast_resume=True): """ Add a new torrent to Deluge. torrent is the decoded file as a python object. destination_path is where the links are. The complete files must be linked already. files is a list of files found in the torrent. """ name = torrent[b'info'][b'name'] logger.info('Trying to add a new torrent to deluge: %r' % name) destination_path = os.path.abspath(destination_path) infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest() encoded_torrent = base64.b64encode(bencode(torrent)) basename = os.path.basename(destination_path) mapped_files = {} for i, f in enumerate(files): mapped_files[i] = os.path.join(basename, *f['path']) self._login() result = self.rpcclient.call('core.add_torrent_file', 'torrent.torrent', encoded_torrent, { 'download_location': os.path.dirname(destination_path), 'mapped_files': mapped_files, 'seed_mode': fast_resume}) return result and result.decode('utf-8') == infohash
class Deluge: def _mkdtemp(self): cache_path = cherrypy.config['opmuse'].get('cache.path') dir = os.path.join(cache_path, 'deluge') if not os.path.exists(dir): os.mkdir(dir) return tempfile.mkdtemp(dir=dir) def connect(self, timeout=20): config = cherrypy.tree.apps[''].config['opmuse'] if 'deluge.host' not in config: log('Deluge not configured, skipping') return False host = config['deluge.host'] port = config['deluge.port'] user = config['deluge.user'] password = config['deluge.password'] DelugeRPCClient.timeout = timeout self.client = DelugeRPCClient(host, port, user, password) try: self.client.connect() except OSError as e: if e.errno == 113: # "No route to host" log('No route to host: %s' % host) return False else: raise e return self.client.connected def update_torrents(self): torrents = self.client.call('core.get_torrents_status', {}, ['name', 'files', 'save_path', 'time_added', 'total_size', 'paused', 'is_finished', 'progress']) all_torrents = set() for torrent_id, in get_database().query(Torrent.torrent_id).all(): all_torrents.add(torrent_id) for torrent_id, data in torrents.items(): torrent_id = torrent_id.decode('utf-8') if torrent_id in all_torrents: all_torrents.remove(torrent_id) torrent = get_database().query(Torrent).filter(Torrent.torrent_id == torrent_id).one() else: torrent = Torrent() for file in data[b'files']: if Library.is_supported(file[b'path']): has_supported_files = True break else: has_supported_files = False torrent.torrent_id = torrent_id torrent.name = data[b'name'].decode('utf-8') torrent.has_supported_files = has_supported_files torrent.added = datetime.datetime.fromtimestamp(data[b'time_added']) torrent.size = data[b'total_size'] torrent.paused = data[b'paused'] torrent.finished = data[b'is_finished'] torrent.progress = data[b'progress'] get_database().add(torrent) get_database().commit() if len(all_torrents) > 0: (get_database().query(Torrent).filter(Torrent.torrent_id.in_(all_torrents)) .delete(synchronize_session='fetch')) get_database().commit() def import_torrent(self, torrent_id): config = cherrypy.tree.apps[''].config['opmuse'] ssh_host = config['deluge.ssh_host'] if ssh_host is None: raise Exception('You need to set deluge.ssh_host') debug('fetching torrent %s info' % torrent_id) torrent = self.client.call('core.get_torrent_status', torrent_id, []) filelist_fd, filelist_path = tempfile.mkstemp() files = [] tempdir = self._mkdtemp().encode() with os.fdopen(filelist_fd, 'bw') as f: for file in torrent[b'files']: path = os.path.join(torrent[b'save_path'], file[b'path']) f.write(path + b"\n") files.append(os.path.join(tempdir, path[1:])) try: debug('rsync torrent %s from %s' % (torrent_id, ssh_host)) output = subprocess.check_output([ 'rsync', '-a', '-e', 'ssh -oBatchMode=yes -oVisualHostKey=no', '--files-from=%s' % filelist_path, '%s:/' % ssh_host, tempdir ], stderr=subprocess.STDOUT) except CalledProcessError as error: log('Failed to rsync', traceback=True) shutil.rmtree(tempdir) raise Exception(error.output.decode()) except Exception: log('Failed to rsync', traceback=True) shutil.rmtree(tempdir) raise finally: os.remove(filelist_path) debug('done rsyncing torrent %s' % torrent_id) return files
class DelugeHelper: client = None def __init__(self, ip, port, user, password): self.client = DelugeRPCClient(ip, int(port), user, password) self.client.connect() def add_torrent(self, magnetlink, download_location): torrent_id = self.client.call( 'core.add_torrent_magnet', magnetlink, { 'download_location': download_location, 'prioritize_first_last_pieces': True, 'sequential_download': True }) time.sleep(2) torrent_name = str( self.client.call('core.get_torrent_status', torrent_id, ['name']).get(b'name'), 'utf-8') return 'Torrent %s started' % torrent_name def delete_torrent(self, torrent_id): torrent_name = str( self.client.call('core.get_torrent_status', torrent_id, ['name']).get(b'name'), 'utf-8') if self.client.call('core.remove_torrent', torrent_id, True): return 'Torrent %s was successfully deleted' % torrent_name else: return 'An error occurred while deleting %s' % torrent_name def get_torrents_to_delete(self): status_keys = ['name', 'total_size'] results = self.client.call('core.get_torrents_status', {}, status_keys) message = 'Name - Size\n' for torrent_id, status in results.items(): message += '%s - %s /del_%s \n' % (str( status.get(b'name'), 'utf-8'), format_size( status.get(b'total_size')), str(torrent_id).split("'")[1]) return message def get_active_torrents(self): status_keys = [ 'name', 'download_payload_rate', 'progress', 'eta', 'total_size' ] results = self.client.call('core.get_torrents_status', {'state': 'Allocating'}, status_keys) results.update( self.client.call('core.get_torrents_status', {'state': 'Checking'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Downloading'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Error'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Queued'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Moving'}, status_keys)) message = 'Name - Downloading speed - Progress - ETA - Size\n' for torrent_id, status in results.items(): message += '%s - %s - %.1f%% - %s - %s \n' % ( str(status.get(b'name'), 'utf-8'), format_speed(status.get(b'download_payload_rate')), status.get(b'progress'), format_time(status.get(b'eta')), format_size(status.get(b'total_size'))) return message def get_finished_torrents(self): status_keys = ['name', 'upload_payload_rate', 'progress', 'total_size'] results = self.client.call('core.get_torrents_status', {'state': 'Seeding'}, status_keys) results.update( self.client.call('core.get_torrents_status', {'state': 'Paused'}, status_keys)) message = 'Name - Uploading speed - Progress - Size\n' for torrent_id, status in results.items(): message += '%s - %s - %.1f%% - %s \n' % ( str(status.get(b'name'), 'utf-8'), format_speed(status.get(b'upload_payload_rate')), status.get(b'progress'), format_size( status.get(b'total_size'))) return message
class Deluge(object): def __init__(self, host): # Host self._host = host # RPC Client self._client = None # Torrent Properties Cache self._torrent_cache = {} # Cache Valid Time self._refresh_expire_time = 30 # Last Time of Refreshing Cache self._last_refresh = 0 # Login to Deluge def login(self, username, password): # Split IP(or domain name) and port splits = self._host.split(':') host = splits[0] if len(splits) > 0 else '' port = int(splits[1]) if len(splits) > 1 else DEFAULT_PORT # Create RPC client and connect to Deluge self._client = DelugeRPCClient(host, port, username, password, decode_utf8=True) try: self._client.connect() except DelugeClientException as e: # Display class name of the exception if there is no error messages raise LoginFailure(e.args[0].split('\n')[0] if len(e.args) > 0 else e.__class__.__name__) # A caller to call deluge api; includes exception processing def _call(self, method, *args, **kwargs): try: return self._client.call(method, *args, **kwargs) except DelugeClientException as e: # Raise our own exception raise RemoteFailure(e.args[0].split('\n')[0] if len(e.args) > 0 else e.__class__.__name__) # Get client status def client_status(self): cs = ClientStatus() # Set remote free space checker cs.free_space = self.remote_free_space # Get DL/UL information session_stats = self._call('core.get_session_status', [ 'payload_download_rate', 'payload_upload_rate', 'total_download', 'total_upload', ]) cs.download_speed = session_stats['payload_download_rate'] cs.total_downloaded = session_stats['total_download'] cs.upload_speed = session_stats['payload_upload_rate'] cs.total_uploaded = session_stats['total_upload'] # Get port status port_is_open = self._call('core.test_listen_port') cs.port_status = PortStatus.Open if port_is_open else PortStatus.Closed return cs # Get Deluge version def version(self): funcs = { 1: 'daemon.info', # For Deluge 1.x, use daemon.info 2: 'daemon.get_version', # For Deluge 2.x, use daemon.get_version } ver = self._call(funcs[self._client.deluge_version]) return ('Deluge %s' % ver) # Get API version def api_version(self): # Returns the protocol version return self._client.deluge_protocol_version if self._client.deluge_protocol_version is not None else 'not provided' # Get torrent list def torrents_list(self): # Save hashes torrents_hash = [] # Get torrent list (and their properties) torrent_list = self._call( 'core.get_torrents_status', {}, [ 'active_time', 'all_time_download', 'download_payload_rate', 'finished_time', 'hash', 'label', # Available when the plugin 'label' is enabled 'name', 'num_peers', 'num_seeds', 'progress', 'ratio', 'seeding_time', 'state', 'time_added', 'time_since_transfer', 'total_peers', 'total_seeds', 'total_size', 'total_uploaded', 'trackers', 'upload_payload_rate', ]) # Save properties to cache self._torrent_cache = torrent_list self._last_refresh = time.time() # Return torrent hashes for h in torrent_list: torrents_hash.append(h) return torrents_hash # Get Torrent Properties def torrent_properties(self, torrent_hash): # Check cache expiration if time.time() - self._last_refresh > self._refresh_expire_time: self.torrents_list() # Extract properties torrent = self._torrent_cache[torrent_hash] # Create torrent object torrent_obj = Torrent() torrent_obj.hash = torrent['hash'] torrent_obj.name = torrent['name'] if 'label' in torrent: torrent_obj.category = [torrent['label'] ] if len(torrent['label']) > 0 else [] torrent_obj.tracker = [ tracker['url'] for tracker in torrent['trackers'] ] torrent_obj.status = Deluge._judge_status(torrent['state']) torrent_obj.size = torrent['total_size'] torrent_obj.ratio = torrent['ratio'] torrent_obj.uploaded = torrent['total_uploaded'] torrent_obj.downloaded = torrent['all_time_download'] torrent_obj.create_time = int(torrent['time_added']) torrent_obj.seeding_time = torrent['seeding_time'] torrent_obj.upload_speed = torrent['upload_payload_rate'] torrent_obj.download_speed = torrent['download_payload_rate'] torrent_obj.seeder = torrent['total_seeds'] torrent_obj.connected_seeder = torrent['num_seeds'] torrent_obj.leecher = torrent['total_peers'] torrent_obj.connected_leecher = torrent['num_peers'] torrent_obj.average_upload_speed = torrent['total_uploaded'] / torrent[ 'active_time'] if torrent['active_time'] > 0 else 0 if 'finished_time' in torrent: download_time = torrent['active_time'] - torrent['finished_time'] torrent_obj.average_download_speed = torrent[ 'all_time_download'] / download_time if download_time > 0 else 0 if 'time_since_transfer' in torrent: # Set the last active time of those never active torrents to timestamp 0 torrent_obj.last_activity = torrent[ 'time_since_transfer'] if torrent[ 'time_since_transfer'] > 0 else 0 torrent_obj.progress = torrent['progress'] / 100 # Accept Range: 0-1 return torrent_obj # Get free space def remote_free_space(self, path): return self._call('core.get_free_space', path) # Judge Torrent Status @staticmethod def _judge_status(state): return { 'Allocating': TorrentStatus.Unknown, # Ignore this state 'Checking': TorrentStatus.Checking, 'Downloading': TorrentStatus.Downloading, 'Error': TorrentStatus.Error, 'Moving': TorrentStatus.Unknown, # Ignore this state 'Paused': TorrentStatus.Paused, 'Queued': TorrentStatus.Queued, 'Seeding': TorrentStatus.Uploading, }[state] # Batch Remove Torrents def remove_torrents(self, torrent_hash_list, remove_data): if self._client.deluge_version >= 2: # Method 'core.remove_torrents' is only available in Deluge 2.x failures = self._call('core.remove_torrents', torrent_hash_list, remove_data) failed_hash = [torrent[0] for torrent in failures] return ( [ torrent for torrent in torrent_hash_list if torrent not in failed_hash ], [{ 'hash': torrent[0], 'reason': torrent[1], } for torrent in failures], ) else: # For Deluge 1.x, remove torrents one by one success_hash = [] failures = [] for torrent in torrent_hash_list: try: self._call('core.remove_torrent', torrent, remove_data) success_hash.append(torrent) except RemoteFailure as e: failures.append({ 'hash': torrent, 'reason': e.args[0], }) return (success_hash, failures)
def __init__(self, ip, port, user, password): self.client = DelugeRPCClient(ip, int(port), user, password) self.client.connect()
if len(sys.argv) < 4: log.error("Not enough command line parameters present, are you launching this from deluge?") sys.exit(1) path = str(sys.argv[3]) torrent_name = str(sys.argv[2]) torrent_id = str(sys.argv[1]) delete_dir = None path_mapping = settings.deluge['path-mapping'] log.debug("Path: %s." % path) log.debug("Torrent: %s." % torrent_name) log.debug("Hash: %s." % torrent_id) client = DelugeRPCClient(host=settings.deluge['host'], port=int(settings.deluge['port']), username=settings.deluge['user'], password=settings.deluge['pass']) client.connect() if client.connected: log.info("Successfully connected to Deluge") else: log.error("Failed to connect to Deluge") sys.exit(1) torrent_data = client.call('core.get_torrent_status', torrent_id, ['files', 'label']) try: torrent_files = torrent_data[b'files'] category = torrent_data[b'label'].lower().decode() except: torrent_files = torrent_data['files'] category = torrent_data['label'].lower()
@version: 0 @autor: David Ramirez Sierra @doc: Funciones RPC --> http://deluge.readthedocs.io/en/develop/core/rpc.html ''' import sys import time from deluge_client import DelugeRPCClient # https://github.com/JohnDoee/deluge-client servidor='127.0.0.1' puerto= 58846 # De tipo entero username='******' # Se puede ver en home/.config/deluge/auth . Este es de level 10 = admin password='******' # Se puede ver en home/.config/deluge/auth client = DelugeRPCClient(servidor, puerto, username, password) client.connect() if client.connected: print "Conectado a " +servidor+':'+str(puerto) if len(sys.argv) > 1: if sys.argv[1] == '-add': if sys.argv[2] == '-magnet': uri = sys.argv[3] client.call('core.add_torrent_magnet', uri,{}) elif sys.argv[2] == '-torrent': uri = sys.argv[3] # TODO
def login(self): self.client = DelugeRPCClient(host, port, username, password) self.client.connect()
class TorrentClient(object): def __init__(self): self.conn = None def connect(self, host, username, password): if self.conn is not None: return self.connect if not host: return False # Get port from the config host,portnr = host.split(':') #if username and password: # logger.info('Connecting to ' + host + ':' + portnr + ' Username: '******' Password: '******'Could not create DelugeRPCClient Object' + e) return False else: try: self.client.connect() except Exception as e: logger.error('Could not connect to Deluge ' + host) else: return self.client def find_torrent(self, hash): logger.debug('Finding Torrent hash: ' + hash) torrent_info = self.get_torrent(hash) if torrent_info: return True else: return False def get_torrent(self, hash): logger.debug('Getting Torrent info from hash: ' + hash) try: torrent_info = self.client.call('core.get_torrent_status', hash, '') except Exception as e: logger.error('Could not get torrent info for ' + hash) return False else: if torrent_info is None: torrent_info = False return torrent_info def start_torrent(self, hash): try: self.find_torrent(hash) except Exception as e: return False else: try: self.client.call('core.resume_torrent', hash) except Exception as e: logger.error('Torrent failed to start ' + e) else: logger.info('Torrent ' + hash + ' was started') return True def stop_torrent(self, hash): try: self.client.find_torrent(hash) except Exception as e: logger.error('Torrent Not Found') return False else: try: self.client.call('core.pause_torrent', hash) except Exception as e: logger.error('Torrent failed to be stopped: ' + e) return False else: logger.info('Torrent ' + hash + ' was stopped') return True def load_torrent(self, filepath): logger.info('filepath to torrent file set to : ' + filepath) torrent_id = False if self.client.connected is True: logger.info('Checking if Torrent Exists!') if not filepath.startswith('magnet'): torrentcontent = open(filepath, 'rb').read() hash = str.lower(self.get_the_hash(filepath)) # Deluge expects a lower case hash logger.debug('Torrent Hash (load_torrent): "' + hash + '"') logger.debug('FileName (load_torrent): ' + str(os.path.basename(filepath))) #Check if torrent already added if self.find_torrent(str.lower(hash)): logger.info('load_torrent: Torrent already exists!') #should set something here to denote that it's already loaded, and then the failed download checker not run so it doesn't download #multiple copies of the same issues that's already downloaded else: logger.info('Torrent not added yet, trying to add it now!') try: torrent_id = self.client.call('core.add_torrent_file', str(os.path.basename(filepath)), base64.encodestring(torrentcontent), '') except Exception as e: logger.debug('Torrent not added') return False else: try: torrent_id = self.client.call('core.add_torrent_magnet', str(filepath), {}) except Exception as e: logger.debug('Torrent not added') return False # If label enabled put label on torrent in Deluge if torrent_id and mylar.CONFIG.DELUGE_LABEL: logger.info ('Setting label to ' + mylar.CONFIG.DELUGE_LABEL) try: self.client.call('label.set_torrent', torrent_id, mylar.CONFIG.DELUGE_LABEL) except: #if label isn't set, let's try and create one. try: self.client.call('label.add', mylar.CONFIG.DELUGE_LABEL) self.client.call('label.set_torrent', torrent_id, mylar.CONFIG.DELUGE_LABEL) except: logger.warn('Unable to set label - Either try to create it manually within Deluge, and/or ensure there are no spaces, capitalization or special characters in label') else: logger.info('Succesfully set label to ' + mylar.CONFIG.DELUGE_LABEL) try: torrent_info = self.get_torrent(torrent_id) logger.info('Double checking that the torrent was added.') except Exception as e: logger.warn('Torrent was not added! Please check logs') return False else: logger.info('Torrent successfully added!') return {'hash': torrent_info['hash'], 'label': mylar.CONFIG.DELUGE_LABEL, 'folder': torrent_info['save_path'], 'total_filesize': torrent_info['total_size'], 'name': torrent_info['name'], 'files': torrent_info['files'], 'time_started': torrent_info['active_time'], 'completed': torrent_info['is_finished']} def delete_torrent(self, hash, removeData=False): try: self.client.find_torrent(hash) except Exception as e: logger.error('Torrent ' + hash + ' does not exist') return False else: try: self.client.call('core.remote_torrent', hash, removeData) except Exception as e: logger.error('Unable to delete torrent ' + hash) return False else: logger.info('Torrent deleted ' + hash) return True def get_the_hash(self, filepath): import hashlib, StringIO import bencode # Open torrent file torrent_file = open(filepath, "rb") metainfo = bencode.decode(torrent_file.read()) info = metainfo['info'] thehash = hashlib.sha1(bencode.encode(info)).hexdigest().upper() logger.debug('Hash: ' + thehash) return thehash
class DelugeRPC(object): host = 'localhost' port = 58846 username = None password = None client = None def __init__(self, host='localhost', port=58846, username=None, password=None): super(DelugeRPC, self).__init__() self.host = host self.port = port self.username = username self.password = password def connect(self): self.client = DelugeRPCClient(self.host, int(self.port), self.username, self.password) self.client.connect() return self.client.connected def disconnect(self): self.client.disconnect() def test(self): try: return self.connect() except Exception: return False def add_torrent_magnet(self, torrent, options, torrent_hash): try: if not self.connect(): return False torrent_id = self.client.core.add_torrent_magnet(torrent, options).get() if not torrent_id: torrent_id = self._check_torrent(torrent_hash) except Exception: return False finally: if self.client: self.disconnect() return torrent_id def add_torrent_file(self, filename, torrent, options, torrent_hash): try: if not self.connect(): return False torrent_id = self.client.core.add_torrent_file( filename, b64encode(torrent), options).get() if not torrent_id: torrent_id = self._check_torrent(torrent_hash) except Exception: return False finally: if self.client: self.disconnect() return torrent_id def set_torrent_label(self, torrent_id, label): try: if not self.connect(): return False self.client.label.set_torrent(torrent_id, label).get() except Exception: return False finally: if self.client: self.disconnect() return True def set_torrent_path(self, torrent_id, path): try: if not self.connect(): return False self.client.core.set_torrent_move_completed_path(torrent_id, path).get() self.client.core.set_torrent_move_completed(torrent_id, 1).get() except Exception: return False finally: if self.client: self.disconnect() return True def set_torrent_priority(self, torrent_ids, priority): try: if not self.connect(): return False if priority: self.client.core.queue_top([torrent_ids]).get() except Exception as err: return False finally: if self.client: self.disconnect() return True def set_torrent_ratio(self, torrent_ids, ratio): try: if not self.connect(): return False self.client.core.set_torrent_stop_at_ratio(torrent_ids, True).get() self.client.core.set_torrent_stop_ratio(torrent_ids, ratio).get() except Exception as err: return False finally: if self.client: self.disconnect() return True def pause_torrent(self, torrent_ids): try: if not self.connect(): return False self.client.core.pause_torrent(torrent_ids).get() except Exception: return False finally: if self.client: self.disconnect() return True def _check_torrent(self, torrent_hash): torrent_id = self.client.core.get_torrent_status(torrent_hash, {}).get() if torrent_id['hash']: sickrage.app.log.debug('DelugeD: Torrent already exists in Deluge') return torrent_hash return False
if len(sys.argv) < 4: log.error("Not enough command line parameters present, are you launching this from deluge?") sys.exit() path = str(sys.argv[3]) torrent_name = str(sys.argv[2]) torrent_id = str(sys.argv[1]) log.debug("Path: %s." % path) log.debug("Torrent: %s." % torrent_name) log.debug("Hash: %s." % torrent_id) client = DelugeRPCClient( host=settings.deluge["host"], port=int(settings.deluge["port"]), username=settings.deluge["user"], password=settings.deluge["pass"], ) client.connect() if client.connected: log.info("Successfully connected to Deluge") else: log.error("Failed to connect to Deluge") sys.exit() torrent_data = client.call("core.get_torrent_status", torrent_id, ["files", "label"]) torrent_files = torrent_data["files"] category = torrent_data["label"].lower() files = []
import argparse import urllib from deluge_client import DelugeRPCClient if __name__ == '__main__': parser = argparse.ArgumentParser(description='Stream something.') parser.add_argument('username', type=str, help='Deluge username') parser.add_argument('password', type=str, help='Deluge password') parser.add_argument('path_or_url', type=str, help='Path or URL to torrent') parser.add_argument('--hostname', '-o', type=str, default='localhost', help='Deluge daemon hostname or ip') parser.add_argument('--port', '-p', type=int, default=58846, help='Deluge daemon port') args = parser.parse_args() if args.path_or_url.startswith('http'): filedata = urllib.urlopen(args.path_or_url).read() else: with open(args.path_or_url, 'rb') as f: filedata = f.read() client = DelugeRPCClient(args.hostname, args.port, args.username, args.password) client.connect() result = client.streaming.stream_torrent(None, None, filedata, None, None, True) print(result['url'])
print("QB not found, trying deluge") if config["deluge"]["deluge_pass"] == "": password = "" if platform.system() == "Linux": with open(os.getenv('HOME') + "/.config/deluge/auth", mode="r") as file: auth = file.read() else: with open(os.getenv('APPDATA') + r'\deluge\auth', mode="r") as file: auth = file.read() password = auth.split(":")[1] with open("config.json", mode="w") as file2: config["deluge"]["deluge_pass"] = password json.dump(config, file2, indent=4) client = DelugeRPCClient(config["deluge"]["deluge_ip"], config["deluge"]["deluge_port"], config["deluge"]["deluge_user"], config["deluge"]["deluge_pass"]) client.connect() print("Connected to Deluge") except ConnectionRefusedError: print("Deluge not found") exit(0) while True: nomicon = loadNomicon() loopNomicon(client, nomicon) dumpNomicon(nomicon) time.sleep(1500)
class DelugeClient: def __init__(self, host="", port=58846, username="", password=""): self.filter = {} self.rpc = DelugeRPCClient( host, port, username, password, ) self.rpc.connect() if not self.rpc.connected: raise RuntimeError("Failed to connect to deluge rpc") def get_labels(self): labels = [] results = self.rpc.call("label.get_labels") for result in results: labels.append(result.decode("utf-8")) return labels def search(self, filter_dict={}) -> list[Torrent]: results = [] keys = ["name", "label", "progress", "save_path"] for filter_key in filter_dict.keys(): if not filter_key in keys: keys.append(filter_key) if "extension" in keys: keys.remove("extension") if "file_path" in keys: keys.remove("file_path") torrents = self.rpc.call( "core.get_torrents_status", {}, keys, ) for id in torrents: torrent_data = {} for (key, value) in torrents[id].items(): data_key = key.decode("utf-8") data_value = value try: data_value = value.decode("utf-8") except (UnicodeDecodeError, AttributeError): pass torrent_data[data_key] = data_value results.append(Torrent(id, torrent_data)) return list(filter(lambda x: filter_torrent(x, filter_dict), results)) def fuzzy_select(self, results: list[Torrent], query="") -> list[Torrent]: lines = [] for result in results: lines.append( f"{result.id};;;{result.name};;;label: {result.label}") search_uuid = uuid.uuid4() search_filename = f"/tmp/deluge-search-{search_uuid}.tmp" output_filename = f"{search_filename}.out" search_file = open(search_filename, "w") search_file.write("\n".join(lines)) search_file.close() cmd = f'cat {search_filename} | fzf --multi --delimiter=";;;" --with-nth=2.. --nth=1 --query="{query}" > {output_filename}' subprocess.call(cmd, shell=True) output_file = open(output_filename, "r") output = output_file.read() os.remove(search_filename) os.remove(output_filename) selected_ids = [] selected_torrents = [] output_lines = output.split("\n") for output_line in output_lines: selected_ids.append(output_line.split(";;;")[0]) for selected_id in selected_ids: for result in results: if result.id == selected_id: selected_torrents.append(result) return selected_torrents def move_torrents(self, ids, dest): self.rpc.call("core.move_storage", ids, dest)
def init(self): self.client = DelugeRPCClient(self.host, self.port, self.username, self.password) self.data = {}
def main(torrent_id, torrent_name, save_path): file_extensions = ['r\d+', 'rar', 'zip'] client = DelugeRPCClient(cfg.deluge_address, cfg.deluge_port, cfg.deluge_user, cfg.deluge_pass) client.connect() print("Starting '%s' with id='%s' at %s" % (torrent_name, torrent_id, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) if not client.connected: print("Error connecting to deluge") sys.exit() #pprint.pprint(client.call('core.get_torrents_status', {}, ['name'])) #pprint.pprint(client.call('core.get_torrent_status', torrent_id, ['files'])) #print("|".join(file_extensions)) try: torrent_file = client.call('core.get_torrent_status', torrent_id, ['files'])['files'] except: print("Error matching torrent_id in deluge") sys.exit() neither_radarr_sonarr = True search = False for file in torrent_file: search = re.search("(" + "|".join(file_extensions) + ")$", file['path']) search = search.group() if search else None if search: print("Torrent contained unwanted file type:") print("\t" + file['path'] + "\t" + str(search)) sonarr_item = search_sonarr_for_torrent_name(torrent_name) if not sonarr_item: radarr_item = search_radarr_for_torrent_name(torrent_name) if not radarr_item: print("Torrent not found in radarr or sonarr") break else: neither_radarr_sonarr = False # Blacklist in sonarr if radarr_item: id = radarr_item['id'] sonarr_radarr_target = delete_from_radarr print("\tSending to radarr background thread.") if sonarr_item: id = sonarr_item['id'] sonarr_radarr_target = delete_from_sonarr print("\tSending to sonarr background thread.") thread = Thread(target = sonarr_radarr_target, args = (id, )) thread.start() thread.join() break if (not search) and (neither_radarr_sonarr): # Torrent is okay, lets start the download. print("Torrent is okay, un-pausing download. Neither radar or sonarr == %s" % (neither_radarr_sonarr)) client.call('core.resume_torrent', [torrent_id]) else: if sonarr_item: print("Requesting sonarr searches for the eppisode again") url = "http://%s:%s/sonarr/api/command?apikey=%s" % (sonarr_host, sonarr_port, cfg.sonarr_apikey) elif radarr_item: print("Requesting radarr searches for the eppisode again") url = "http://%s:%s/radarr/api/command?apikey=%s" % (radarr_host, radarr_port, cfg.radarr_apikey) else: print("Neither sonar or radarr... exiting...") sys.exit(0) data={"name": "EpisodeSearch", "episodeIds": [sonarr_item['episode']['id']]} #pprint.pprint(data) time.sleep(90) d = requests.post(url, json=data) print("\t'" + url + "', response=" + str(d.status_code) + "\r\n") print("____________________________________________\r\n")
def connect(self): self.client = DelugeRPCClient(self.host, int(self.port), self.username, self.password) self.client.connect() return self.client.connected
class DelugePlugin(object): """Base class for deluge plugins, contains settings and methods for connecting to a deluge daemon.""" def on_task_start(self, task, config): """Raise a DependencyError if our dependencies aren't available""" try: from deluge_client import DelugeRPCClient except ImportError as e: log.debug('Error importing deluge-client: %s' % e) raise plugin.DependencyError( 'deluge', 'deluge-client', 'deluge-client >=1.5 is required. `pip install deluge-client` to install.', log) config = self.prepare_config(config) if config['host'] in ['localhost', '127.0.0.1' ] and not config.get('username'): # If an username is not specified, we have to do a lookup for the localclient username/password auth = self.get_localhost_auth() if auth and auth[0]: config['username'], config['password'] = auth else: raise plugin.PluginError( 'Unable to get local authentication info for Deluge. You may need to ' 'specify an username and password from your Deluge auth file.' ) self.client = DelugeRPCClient(config['host'], config['port'], config['username'], config['password'], decode_utf8=True) def prepare_config(self, config): config.setdefault('host', 'localhost') config.setdefault('port', 58846) return config def get_torrents_status(self, fields, filters=None): """Fetches all torrents and their requested fields optionally filtered""" if filters is None: filters = {} return self.client.call('core.get_torrents_status', filters, fields) @staticmethod def get_localhost_auth(): if sys.platform.startswith('win'): auth_file = os.path.join(os.getenv('APPDATA'), 'deluge', 'auth') else: auth_file = os.path.expanduser('~/.config/deluge/auth') if not os.path.isfile(auth_file): return None with open(auth_file) as auth: for line in auth: line = line.strip() if line.startswith('#') or not line: # This is a comment or blank line continue lsplit = line.split(':') if lsplit[0] == 'localclient': username, password = lsplit[:2] return username, password
import requests import json import time # **************** # CHANGE INFO BELOW # **************** __APIURL__ = input("输入API地址(站内查看):") __DE_URL__ = input("输入客户端IP(http://IP):") __DE_PORT__ = input("输入客户端后端端口(非WebUI端口):") __DE_PORT__ = int(__DE_PORT__) __DE_USER__ = input("输入客户端用户名:") __DE_PW__ = input("输入客户端密码:") count = 0 client = DelugeRPCClient(__DE_URL__, __DE_PORT__, __DE_USER__, __DE_PW__) print("Connecting to Deluge...") client.connect() print("Fetching DMHY torrents from Deluge...") torrent_list = client.core.get_torrents_status({}, ['trackers']) dmhy_torrent_hash_list = [ hash_ for hash_ in torrent_list if "dmhy" in str(torrent_list[hash_][b'trackers'][0][b'url']) ] dmhy_req_list = [] for i, hash_ in enumerate(dmhy_torrent_hash_list): dmhy_req_list.append({ "jsonrpc": "2.0", "method": "query", "params": [str(hash_)[2:-1]], "id": i + 1
class DelugeClient(object): def __init__(self, host, port, username, password): """ Initializes a new Deluge client. url - The url where deluge json can be reached. password - The password used to login """ self.host = host self.port = port self.username = username self.password = password self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password) def _login(self): """ Logs into deluge """ if not self.rpcclient.connected: self.rpcclient.connect() def test_connection(self): """ Tests the Deluge RPC connection, returns message if found. """ self._login() return 'Free space: %s' % humanize_bytes(self.rpcclient.call('core.get_free_space')) def get_torrents(self): """ Returns a set of info hashes currently added to the client. """ logger.info('Getting a list of torrent hashes') self._login() result = self.rpcclient.call('core.get_torrents_status', {}, ['name']) return set(x.lower() for x in result.keys()) def add_torrent(self, torrent, destination_path, files, fast_resume=True): """ Add a new torrent to Deluge. torrent is the decoded file as a python object. destination_path is where the links are. The complete files must be linked already. files is a list of files found in the torrent. """ name = torrent[b'info'][b'name'] logger.info('Trying to add a new torrent to deluge: %r' % name) destination_path = os.path.abspath(destination_path) infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest() encoded_torrent = base64.b64encode(bencode(torrent)) basename = os.path.basename(destination_path) mapped_files = {} for i, f in enumerate(files): mapped_files[i] = os.path.join(basename, *f['path']) self._login() result = self.rpcclient.call('core.add_torrent_file', 'torrent.torrent', encoded_torrent, { 'download_location': os.path.dirname(destination_path), 'mapped_files': mapped_files}) return result and result.decode('utf-8') == infohash
def main(): parser = argparse.ArgumentParser(description="Clean up deluge torrents") parser.add_argument( "-s", "--server", action="append", type=DelugeUri, required=True, help= "Deluge host or IP addresses to connect to in the form of user:pass@hostname:port" ) subparser_action = parser.add_subparsers(dest='action', help='action to take') parser_unreg = subparser_action.add_parser( 'unreg', help='Delete torrents with "Unregistered torrent" error state') parser_free = subparser_action.add_parser( 'space', help='Delete oldest torrents to reach a free disk space quota') parser_free.add_argument("-f", "--free", help="Target free space in GB", type=int, required=True) args = parser.parse_args() if not args.action: print("No action specified") sys.exit(2) clients = [] futures = [] for server in args.server: uri = urlparse('deluge://{}'.format(server)) client = DelugeRPCClient(uri.hostname, uri.port if uri.port else 58846, uri.username, uri.password) client.connect() clients.append(client) if args.action == "unreg": with ThreadPoolExecutor(max_workers=10) as pool: futures += [pool.submit(cull_unregistered, c) for c in clients] elif args.action == "space": with ThreadPoolExecutor(max_workers=10) as pool: futures += [ pool.submit(cull_by_diskspace, c, want_free=args.free * GB) for c in clients ] print( tabulate([[ "{}:{}".format(clients[i].host, clients[i].port), "{} GB".format( round( decodedict(clients[i].call('core.get_free_space')) / GB, 2)), futures[i].result()[0], "{} GB".format( round(futures[i].result()[1] / GB, 2)) ] for i in range(0, len(clients))], headers=["server", "space free", "rm'd", "newly freed"]))
def add_torrent(magnet_url): from deluge_client import DelugeRPCClient client = DelugeRPCClient('127.0.0.1', 2196, "seftembr", "TuGsFYqlNP") client.connect() result = client.call('core.add_torrent_magnet', magnet_url, {}) print "Returned hash:", result
class Deluge(implements(TorrentClient)): def __init__(self): self.client = DelugeRPCClient(config["deluge_hostname"], config["deluge_port"], config["deluge_username"], config["deluge_password"], decode_utf8=True, automatic_reconnect=True) def setup(self) -> bool: daemon_path = config["deluge_daemon_path"] if not os.path.isfile(daemon_path): logger.error("Deluge daemon path is invalid, cannot setup") return False config_path = os.path.join(ROOT_PATH, "deluged_config") logger.debug(f"Running deluge daemon with config path '{config_path}'") logger.debug(f'"{daemon_path}" -c "{config_path}"') subprocess.Popen(f'"{daemon_path}" -c "{config_path}"', stdout=subprocess.PIPE, shell=True) time.sleep(6) # TODO: Check if deluge has correct settings, if not change them and restart it # TODO: enable labels plugin return True def connect(self) -> bool: """Tries to connect to the service automatically""" try: self.client.connect() return self.client.connected except Exception as ex: logger.error(f"Could not connect to deluge daemon: {ex}") return False def run(self): """Tries to setup and connect automatically""" # Try to connect, maybe the daemon is already running if self.connect(): logger.info("Deluge daemon is already running, skipping setup") return if self.setup() and self.connect(): logger.info("Deluge daemon is up") return raise Exception("Failed to run Deluge") def add_torrent(self, magnet_uri: str, uid: str) -> TorrentInfo: # uid = uid.lower() # Labels plugin is not case sensitive # logger.debug(self.client.call('label.get_labels')) torrent_info = self.get_torrent_info(uid) if torrent_info: return torrent_info # https://github.com/deluge-torrent/deluge/blob/develop/deluge/core/torrent.py infohash = self.client.core.add_torrent_magnet( magnet_uri, { 'download_location': os.path.abspath( config['download_folder']), 'stop_at_ratio': True, 'stop_ratio': config["deluge_share_ratio"], 'prioritize_first_last_pieces': True, 'sequential_download': True, 'name': uid }) logger.debug(f"Torrent infohash: {infohash}") logger.debug( self.client.core.get_torrent_status(infohash, ["name", "paused"])) if not infohash: raise Exception("Unable to add torrent") # Set more trackers (this can speed up download) self.client.core.set_torrent_trackers(infohash, [{ "url": t, "tier": i } for i, t in enumerate(TrackerList.get_list(TrackerList.Type.Best))]) return self.get_torrent_info(uid) def list_torrents(self) -> List[str]: logger.info('Getting a list of torrent hashes') self._login() result = self.rpcclient.call('core.get_torrents_status', {}, ['name']) logger.debug(set(x.lower() for x in result.keys())) return result def get_torrent_info(self, uid: str) -> Optional[TorrentInfo]: # https://github.com/deluge-torrent/deluge/blob/develop/deluge/core/torrent.py#L1037 result = self.client.core.get_torrents_status({'name': uid}, [ "download_location", "download_payload_rate", "num_peers", "num_seeds", "ratio", "total_size", "progress", "files" ]) if len(result.keys()) > 1: logger.error( f"More than one torrent with uid '{uid}'... This should not happen" ) logger.debug(result) if result: hash = list(result.keys())[0] return TorrentInfo(hash=hash, speed=result[hash]['download_payload_rate'], peers=result[hash]['num_peers'], seeders=result[hash]['num_seeds'], ratio=result[hash]['ratio'], size=result[hash]['total_size'], progress=result[hash]['progress'] / 100., files=[ os.path.join( result[hash]['download_location'], file['path']) for file in result[hash]['files'] ]) return None def set_seed_ratio(self, seed_ratio): pass
remove = settings.deluge['remove'] if len(sys.argv) < 4: log.error("Not enough command line parameters present, are you launching this from deluge?") sys.exit() path = str(sys.argv[3]) torrent_name = str(sys.argv[2]) torrent_id = str(sys.argv[1]) delete_dir = None log.debug("Path: %s." % path) log.debug("Torrent: %s." % torrent_name) log.debug("Hash: %s." % torrent_id) client = DelugeRPCClient(host=settings.deluge['host'], port=int(settings.deluge['port']), username=settings.deluge['user'], password=settings.deluge['pass']) client.connect() if client.connected: log.info("Successfully connected to Deluge") else: log.error("Failed to connect to Deluge") sys.exit() torrent_data = client.call('core.get_torrent_status', torrent_id, ['files', 'label']) torrent_files = torrent_data['files'] category = torrent_data['label'].lower() files = [] log.debug("List of files in torrent:") for contents in torrent_files:
import shutil import xmlrpclib from deluge_client import DelugeRPCClient DelugeIp = "<Deluge IP>" DelugePort = <Deluge Port> DelugeUser = "******" DelugePass = "******" DelugeStatePath = "/home/user1/.config/deluge/state/" rTorrentUrl = "https://<Username>:<Password>@<XmlRpc Url> TorrentLabel = "Archive/MoreThanTV" TorrentPath = "/home/user1/torrents/rtorrent/archive/morethantv/" TempPath = "/home/user1/scripts/ruTorrentXmlRpc/temp/" if not os.path.exists(TempPath): os.makedirs(TempPath) dClient = DelugeRPCClient(DelugeIp, DelugePort, DelugeUser, DelugePass) dClient.connect() rClient = xmlrpclib.ServerProxy(rTorrentUrl); torrents = dClient.core.get_torrents_status({"tracker_host": "morethantv.net"}, []) for t in torrents: print([t]) dClient.core.move_storage([t], TorrentPath) shutil.copyfile(DelugeStatePath + str(t) + ".torrent", TempPath + str(t) + ".torrent") dClient.core.remove_torrent(t, False) rClient.load_start_verbose(TempPath + str(t) + ".torrent", "d.custom1.set=" + TorrentLabel, "d.directory.set=" + TorrentPath, "d.delete_tied=") dClient.disconnect()
class Deluge(IntervalModule): """ Deluge torrent module Requires `deluge-client` .. rubric:: Formatters: * `{num_torrents}` - number of torrents in deluge * `{free_space_bytes}` - bytes free in path * `{used_space_bytes}` - bytes used in path * `{upload_rate}` - bytes sent per second * `{download_rate}` - bytes received per second * `{total_uploaded}` - bytes sent total * `{total_downloaded}` - bytes received total """ settings = ( 'format', ('rounding', 'number of decimal places to round numbers too'), ('host', 'address of deluge server (default: 127.0.0.1)'), ('port', 'port of deluge server (default: 58846)'), ('username', 'username to authenticate with deluge'), ('password', 'password to authenticate to deluge'), ('path', 'override "download path" server-side when checking space used/free'), ('offline_string', 'string to output while unable to connect to deluge daemon') ) required = ('username', 'password') host = '127.0.0.1' port = 58846 path = None libtorrent_stats = False rounding = 2 offline_string = 'offline' format = '⛆{num_torrents} ✇{free_space_bytes}' id = int(time.time()) # something random def init(self): self.client = DelugeRPCClient(self.host, self.port, self.username, self.password) self.data = {} def run(self): if not self.client.connected: try: self.client.connect() except OSError: self.output = { 'full_text': self.offline_string } return try: self.data = self.get_session_statistics() torrents = self.get_torrents_status() if torrents: self.data['num_torrents'] = len(torrents) if 'free_space_bytes' in self.format: self.data['free_space_bytes'] = self.get_free_space(self.path) if 'used_space_bytes' in self.format: self.data['used_space_bytes'] = self.get_path_size(self.path) except FailedToReconnectException: return self.parse_values(self.data) self.output = { 'full_text': self.format.format(**self.data) } def parse_values(self, values): for k, v in values.items(): if v: if k in ['total_upload', 'total_download', 'download_rate', 'upload_rate'] or k.endswith('_bytes'): values[k] = '{value:.{round}f}{unit}'.format(round=self.rounding, **bytes_info_dict(v)) def get_path_size(self, path=None): """ get used space of path in bytes (default: download location) """ if path is None: path = [] return self.client.call('core.get_path_size', path) def get_free_space(self, path=None): """ get free space of path in bytes (default: download location) """ if path is None: path = [] return self.client.call('core.get_free_space', path) def get_torrents_status(self, torrent_id=None, keys=None): if torrent_id is None: torrent_id = [] if keys is None: keys = [] return self.client.call('core.get_torrents_status', torrent_id, keys) def get_session_statistics(self): keys = ['upload_rate', 'download_rate', 'total_upload', 'total_download'] out = {} # some of the values from deluge-client are bytes, the others are ints - we need to decode them for k, v in self.client.call('core.get_session_status', keys).items(): k = k.decode('utf-8') # keys aswell if type(v) == bytes: out[k] = v.decode('utf-8') else: out[k] = v return out
class Client(GenericClient, DelugeBase): def __init__(self, host=None, username=None, password=None): super().__init__('DelugeD', host, username, password) self.client = None def setup(self): parsed_url = urlparse(self.host) if self.client and all( [ self.client.host == parsed_url.hostname, self.client.port == parsed_url.port, self.client.username == self.username, self.client.password == self.password ] ): return self.client = DelugeRPCClient(parsed_url.hostname, parsed_url.port or 58846, self.username, self.password) def _get_auth(self): self.setup() if not self.client.connected: try: for attempt in range(0, 5): try: self.client.connect() break except FailedToReconnectException: time.sleep(5) except Exception as error: logger.debug(f"{self.name}: {error}") self.auth = self.client.connected return self.auth def _add_torrent_uri(self, result): remote_torrent = self.client.core.add_torrent_magnet(result.url, self.make_options(result)) if not remote_torrent: return None result.hash = remote_torrent return remote_torrent def _add_torrent_file(self, result): if not result.content: result.content = {} return None remote_torrent = self.client.core.add_torrent_file(result.name + '.torrent', b64encode(result.content).decode('ascii'), self.make_options(result)) if not remote_torrent: return None result.hash = remote_torrent return remote_torrent def _set_torrent_label(self, result): # No option for this built into the rpc, because it is a plugin label = settings.TORRENT_LABEL.lower() if result.show.is_anime: label = settings.TORRENT_LABEL_ANIME.lower() if ' ' in label: logger.exception(f'{self.name}: Invalid label. Label must not contain a space') return False if label: try: if 'label' not in [x.decode().lower() for x in self.client.core.get_available_plugins()]: logger.debug(f'{self.name}: label plugin not detected') return False self.client.core.enable_plugin('Label') self.client.core.enable_plugin('label') labels = [x.decode() for x in self.client.label.get_labels()] if label not in labels: logger.debug(f'{self.name}: {label} label does not exist in Deluge we must add it') self.client.label.add(label) logger.debug(f'{self.name}: [{label}] label added to deluge') self.client.label.set_torrent(result.hash, label) except Exception as error: logger.info(f'{self.name}: Could not add label to torrent') logger.debug(error) # logger.debug(self.client.daemon.get_method_list()) return False logger.debug(f'{self.name}: [{label}] label added to torrent') return True def testAuthentication(self): if self._get_auth() and self.client.daemon.info(): return True, 'Success: Connected and Authenticated' else: return False, 'Error: Unable to Authenticate! Please check your config!'
class DelugeClientKORPI(): """ Class for controlling deluge client. """ def __init__(self, username, password, host="127.0.0.1", port=58846): self._username = username self._password = password self._host = host self._port = port self.__client = DelugeRPCClient(host, int(port), username, password) def connect(self): self.__client.connect() def list(self): """Returns tuple with torrent hashes""" return self.__client.call("core.get_session_state") def status(self, thash=None): if thash: return self.__client.call('core.get_torrents_status', {"hash": thash}, []) else: return self.__client.call('core.get_torrents_status', {}, []) def completed(self, thash): """Returns % of downloaded from torrent.""" status = self.__client.call('core.get_torrents_status', {"hash": thash}, []) thash = thash.encode("utf-8") if status[thash][b"total_wanted"] == 0: return 0 else: return status[thash][b"total_done"] / status[thash][b"total_wanted"] * 100 def pause(self, thash=None): """ If hash not provided, pause/resume all torrents. Returns False if torrent(s) was paused, True otherwise. """ if thash: status = self.status(thash)[thash.encode("utf-8")][b"paused"] if status: self.__client.call('core.resume_torrent', [thash]) else: self.__client.call('core.pause_torrent', [thash]) return status else: if self.all_paused(): self.__client.call("core.resume_torrent", self.list()) else: self.__client.call("core.pause_torrent", self.list()) return self.all_paused() def add(self, magnet, directory, max_speed): return self.__client.call('core.add_torrent_magnet', magnet, {"download_location": directory, "max_download_speed": max_speed}) def remove(self, thash, with_files): """Set with_files True to remove with files""" if with_files == "True": with_files = True elif with_files == "False": with_files = False return self.__client.call("core.remove_torrent", thash, with_files) def free_space(self, directory): """Get free space in megabytes.""" return self.__client.call("core.get_free_space", directory) * TO_GB def download_speed(self, dmax=-1): for thash in self.list(): self.__client.call("core.set_torrent_max_download_speed", thash, int(dmax)) def all_paused(self): return all(paused[b"paused"] for _, paused in self.status().items())
def c_De(): __APIURL__ = input("输入API地址(站内查看):") __DE_URL__ = input("输入客户端IP(http://IP):") __DE_PORT__ = input("输入客户端后端端口(非WebUI端口):") __DE_USER__ = input("输入客户端用户名:") __DE_PW__ = input("输入客户端密码:") count = 0 client = DelugeRPCClient(__DE_URL__, __DE_PORT__, __DE_USER__, __DE_PW__) print("Connecting to Deluge...") client.connect() print("Fetching DMHY torrents from Deluge...") torrent_list = client.core.get_torrents_status({}, ['trackers']) dmhy_torrent_hash_list = [ hash_ for hash_ in torrent_list if "dmhy" in str(torrent_list[hash_][b'trackers'][0][b'url']) ] dmhy_req_list = [] for i, hash_ in enumerate(dmhy_torrent_hash_list): dmhy_req_list.append({ "jsonrpc": "2.0", "method": "query", "params": [str(hash_)[2:-1]], "id": i + 1 }) print("Fetching Secure Code...") resp = requests.post(__APIURL__, json=dmhy_req_list) if resp.status_code != 200: raise (Exception("Error with Code {} Pls Try Again!".format( resp.status_code))) requested_secure_list = resp.json() error_torrent_hash_list = [] print("Begin Updating...") for i, hash_ in enumerate(dmhy_torrent_hash_list): if "result" in requested_secure_list[i]: count += 1 client.core.set_torrent_trackers(hash_, [{ 'url': "https://daydream.dmhy.best/announce?secure={}".format( requested_secure_list[i]["result"]), 'tier': 0 }]) print("Edited Tracker for {} ({}/{})".format( str(hash_)[2:-1], count, len(requested_secure_list))) elif "error" in requested_secure_list[i]: print("Editing Tracker for {} failed {}. {}".format( str(hash_)[2:-1], requested_secure_list[i]["error"]["code"], requested_secure_list[i]["error"]["message"])) error_torrent_hash_list.append(str(hash_)[2:-1]) else: print("Editing Tracker for {} failed.".format(str(hash_)[2:-1])) error_torrent_hash_list.append(str(hash_)[2:-1]) print() print("Successfully edited {} of {} torrents with errors occurred below:". format(count, len(requested_secure_list))) for each in error_torrent_hash_list: print(each) print() for i in range(2): print("Retry Time {}".format(i + 1)) dmhy_req_list.clear() dmhy_torrent_hash_list.clear() count = 0 for i, hash_ in enumerate(error_torrent_hash_list): dmhy_torrent_hash_list.append(hash_) dmhy_req_list.append({ "jsonrpc": "2.0", "method": "query", "params": [hash_], "id": i + 1 }) print("Fetching Secure Code...") resp = requests.post(__APIURL__, json=dmhy_req_list) if resp.status_code != 200: print("Failed to fetch secure code, retry later") time.sleep(20) continue requested_secure_list = resp.json() error_torrent_hash_list.clear() print("Begin Updating...") for i, hash_ in enumerate(dmhy_torrent_hash_list): if "result" in requested_secure_list[i]: count += 1 client.core.set_torrent_trackers(hash_, [{ 'url': "https://daydream.dmhy.best/announce?secure={}".format( requested_secure_list[i]["result"]), 'tier': 0 }]) print("Edited Tracker for {} ({}/{})".format( str(hash_)[2:-1], count, len(requested_secure_list))) elif "error" in requested_secure_list[i]: print("Editing Tracker for {} failed {}. {}".format( str(hash_)[2:-1], requested_secure_list[i]["error"]["code"], requested_secure_list[i]["error"]["message"])) error_torrent_hash_list.append(str(hash_)[2:-1]) else: print("Editing Tracker for {} failed.".format( str(hash_)[2:-1])) error_torrent_hash_list.append(str(hash_)[2:-1]) print( "Successfully edited {} of {} torrents with errors occurred below:" .format(count, len(requested_secure_list))) if len(error_torrent_hash_list) == 0: break return 0
def connect_to_deluge(): client = DelugeRPCClient(config.DLGD_HOST, config.DLGD_PORT, config.DLGD_USER, config.DLGD_PASS) client.connect() if client.connected: print "Connected to deluge daemon" from types import MethodType def add_torr_url(self, url): return self.call('core.add_torrent_url', wz.urls.url_fix(url), {}) client.add_torr_url = MethodType(add_torr_url, client, DelugeRPCClient) def add_torr_file(self, file): f = open(file, 'rb') filedump = base64.encodestring(f.read()) f.close() return self.call('core.add_torrent_file', file, filedump, {}) client.add_torr_file = MethodType(add_torr_file, client, DelugeRPCClient) def add_label(self, label, options={}): label = normalize_label(label) self.call('label.add', label) if options: if options['move_completed_path']: options.update({'move_completed': True, 'apply_move_completed': True}) self.call('label.set_options', label, options) client.add_label = MethodType(add_label, client, DelugeRPCClient) def label_exist(self, label): label = normalize_label(label) if label in self.list_labels(): return True else: return False client.label_exist = MethodType(label_exist, client, DelugeRPCClient) def list_labels(self): return self.call('label.get_labels') client.list_labels = MethodType(list_labels, client, DelugeRPCClient) def add_tor_label(self, tor_id, label): return self.call('label.set_torrent', tor_id, normalize_label(label)) client.add_tor_label = MethodType(add_tor_label, client, DelugeRPCClient) def session_state(self): return self.call('core.get_session_state') client.session_state = MethodType(session_state, client, DelugeRPCClient) def torrent_status(self, tid, fields = {}): return self.call('core.get_torrent_status', tid, fields) client.torrent_status = MethodType(torrent_status, client, DelugeRPCClient) def torrents_status(self, filters = {}, fields = []): return self.call('core.get_torrents_status', filters, fields) client.torrents_status = MethodType(torrents_status, client, DelugeRPCClient) def get_finished(self): torrs = torrents_status(self) for k,v in torrs.items(): #print(k,v['name']) if v['is_finished'] == False: #print("Removing unfinished: " + v['name'] + " " + str(v['is_finished'])) torrs.pop(k) elif v['tracker_host'] in config.REMOVE_SEEDS_EXCEPTION_TRACKERS: #print("Removing exception_tracker: " + v['name']) torrs.pop(k) elif not is_all_files_done(v): #print("Removing not_all_done: " + v['name']) torrs.pop(k) return torrs client.get_finished = MethodType(get_finished, client, DelugeRPCClient) def remove_finished(self): for k in get_finished(self): self.call('core.remove_torrent', k, False) client.remove_finished = MethodType(remove_finished, client, DelugeRPCClient) def is_all_files_done(tor): for i in tor['file_progress']: if i != 1.0: return False return True return client
import time import vk_api from deluge_client import DelugeRPCClient vk = vk_api.VkApi(token='твой_ключ') values = {'count': 1, 'time_offset': 5, 'filter': 'unread'} client = DelugeRPCClient('127.0.0.1', 58846, 'pi', 'пароль_твоей_Raspberry') client.connect() def write_msg(user_id, msg, random): vk.method('messages.send', { 'user_id': user_id, 'message': msg, 'random_id': random }) try: while True: response = vk.method('messages.getConversations', values) if response['items']: item = response['items'][0] last_mess = item['last_message'] random = last_mess['random_id'] my_id = last_mess['peer_id'] text = last_mess['text']