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 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 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)])
async def send_request(self, request): conn = DelugeClient('master.seedhost.eu', 21110, os.environ['DELUGE_USER'], os.environ['DELUGE_PASS']) conn.connect() torrent_id = conn.call( 'core.add_torrent_magnet', request.magnet, { 'download_location': f'/home13/fufu/downloads/Watchtower/{request.channel}/{request.name}/' }) with TinyDB('db') as db: db.insert({ 'requester_name': request.requester_name, 'torrent_id': torrent_id.decode(), 'torrent_name': request.name, 'time': int(time.time()) })
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 node_task_del(infohash): client = DelugeRPCClient('127.0.0.1', 58846, u, p) if client.connected is False: client.connect() ret = client.call('core.get_torrents_status', {'id': [infohash]}, [u'name']) if len(ret[infohash]) == 0: # clean cache try: download_location = app.config.get( 'TASK_DOWNLOAD_PATH') + '/' + infohash os.removedirs(download_location) except: pass res = True else: res = client.call('core.remove_torrent', infohash, True) return jsonify({'data': res, 'errCode': 0})
def start(calling_dir=os.getcwd()): global client, deluge_password, deluge_server_ip, deluge_server_port, deluge_username, live_config, CONNECT_TO_DELUGE ##TODO: UPDATE VERSION ON BUILD print("Welcome to TraktPuller v0.7") print( "Source code available at https://github.com/TheSelectiveOppidan/trakt-downloader" ) if not configuration.check(calling_dir): print( "Please fill in the configuration file I just created then rerun me." ) exit() live_config = configuration.get_config(calling_dir) option = "" while option != 'n': option = input("Do you want to add a new account? (y/n)") if option == 'y': if not do_authorize_loop(): option = '' deluge_server_ip = live_config['deluge_ip'] deluge_server_port = int(live_config['deluge_port']) deluge_username = live_config['deluge_username'] deluge_password = live_config['deluge_password'] client = DelugeRPCClient(deluge_server_ip, deluge_server_port, deluge_username, deluge_password) if CONNECT_TO_DELUGE: try: client.connect() except Exception as e: print(e) print("is Connected to Deluge: " + str(client.connected)) main_loop()
def deluge(torrent, CLIENT_URL, TOR_CLIENT_USER, TOR_CLIENT_PW, logger): TOR_CLIENT = "Deluge" print(f"Sending {torrent.description.decode('ascii')} to {TOR_CLIENT}") url = fetch_torrent_url(torrent) try: logger.debug("Connecting to torrent client...") # Connection logger.debug(f"{TOR_CLIENT} connection info: {CLIENT_URL.split(':')[0]}, {int(CLIENT_URL.split(':')[1])}, {TOR_CLIENT_USER}") client = DelugeRPCClient(CLIENT_URL.split(':')[0], int(CLIENT_URL.split(':')[1]), TOR_CLIENT_USER, TOR_CLIENT_PW) client.connect() logger.debug(f"Connected to {TOR_CLIENT}") # Add torrent logger.debug(f"Adding {torrent.description.decode('ascii')} with url: {url}") client.call("download_torrent_from_url", url) print("Torrent sent!") except Exception as e: print(f"Unable to send to {TOR_CLIENT}. Check the logs for more information.") logger.error(f"Error sending to {TOR_CLIENT}. {str(e)}") exit()
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Deluge sensors.""" name = config[CONF_NAME] host = config[CONF_HOST] username = config[CONF_USERNAME] password = config[CONF_PASSWORD] port = config[CONF_PORT] deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() except ConnectionRefusedError as err: _LOGGER.error("Connection to Deluge Daemon failed") raise PlatformNotReady from err dev = [] for variable in config[CONF_MONITORED_VARIABLES]: dev.append(DelugeSensor(variable, deluge_api, name)) add_entities(dev)
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 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") return dev = [] for variable in config[CONF_MONITORED_VARIABLES]: dev.append(DelugeSensor(variable, deluge_api, name)) add_devices(dev)
def setup_platform( hass: HomeAssistant, config: ConfigType, add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the Deluge switch.""" name = config[CONF_NAME] host = config[CONF_HOST] username = config[CONF_USERNAME] password = config[CONF_PASSWORD] port = config[CONF_PORT] deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() except ConnectionRefusedError as err: _LOGGER.error("Connection to Deluge Daemon failed") raise PlatformNotReady from err add_entities([DelugeSwitch(deluge_api, name)])
def create_deluge_client(url, port, username, password): """ Creates a minimal Deluge torrent client to the Deluge seedbox server. :param str url: URL of the Deluge server. :param int port: port used to access the Deluge server. :param str username: server account username. :param str password: server account password. :returns: a lightweight `Deluge RPC client`_. .. seealso:: * :py:meth:`get_deluge_client <plexcore.plexcore_deluge.get_deluge_client>` * :py:meth:`get_deluge_credentials <plexcore.plexcore_deluge.get_deluge_credentials>` * :py:meth:`push_deluge_credentials <plexcore.plexcore_deluge.push_deluge_credentials>` .. _`Deluge RPC client`: https://github.com/JohnDoee/deluge-client """ from deluge_client import DelugeRPCClient client = DelugeRPCClient(url, port, username, password) client.connect() assert (client.connected) # make sure we can connect return client
def main(): parser = argparse.ArgumentParser(description="Change torrent trackers") parser.add_argument("-s", "--server", type=DelugeUri, required=True, help="Deluge host or IP addresses to connect to in the form of user:pass@hostname:port") parser.add_argument("-c", "--src-substr", help="Tracker to replace", required=True) parser.add_argument("-t", "--tracker", help="URL of new tracker", required=True) parser.add_argument("-n", "--dry-run", action="store_true", help="Only print changed torrents") args = parser.parse_args() uri = urlparse('deluge://{}'.format(args.server)) client = DelugeRPCClient(uri.hostname, uri.port if uri.port else 58846, uri.username, uri.password) client.connect() torrents = decodedict(client.call('core.get_torrents_status', {}, ['name', 'trackers'])) for torrent_id, torrent in torrents.items(): tracker = torrent['trackers'][0] if args.src_substr in tracker["url"]: print("Updating '{}' on '{}' ({})".format(tracker["url"], torrent['name'], torrent_id)) if not args.dry_run: client.call('core.set_torrent_trackers', torrent_id, [{"url": args.tracker, "tier": 0}])
def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Deluge sensors.""" name = config[CONF_NAME] host = config[CONF_HOST] username = config[CONF_USERNAME] password = config[CONF_PASSWORD] port = config[CONF_PORT] deluge_api = DelugeRPCClient(host, port, username, password) try: deluge_api.connect() except ConnectionRefusedError as err: _LOGGER.error("Connection to Deluge Daemon failed") raise PlatformNotReady from err monitored_variables = config[CONF_MONITORED_VARIABLES] entities = [ DelugeSensor(deluge_api, name, description) for description in SENSOR_TYPES if description.key in monitored_variables ] add_entities(entities)
def deluge_connect() -> DelugeRPCClient: host = os.getenv('DELUGE_HOST') if not host: raise Exception('DELUGE_HOST not set') port = os.getenv('DELUGE_PORT') if port: try: port = int(port) except Exception as e: raise Exception('DELUGE_PORT is not int ' + str(e)) else: port = 58846 username = os.getenv('DELUGE_USERNAME') if not username: raise Exception('DELUGE_USERNAME not set') password = os.getenv('DELUGE_PASSWORD') if not password: raise Exception('DELUGE_PASSWORD not set') client = DelugeRPCClient(host, port, username, password) client.connect() return client
class DelugeHelper: def __init__(self): self.login() def login(self): self.client = DelugeRPCClient(host, port, username, password) self.client.connect() def get_torrents(self): # list of keys? https://forum.deluge-torrent.org/viewtopic.php?t=54793 res_torrents = self.client.call('core.get_torrents_status', {}, [ 'name', 'progress', 'ratio', 'tracker', 'seeding_time', 'total_size' ]) torrents = [ TorrentStat(_id, torrent[b'name'], torrent[b'ratio'], torrent[b'seeding_time'], torrent[b'tracker']) for _id, torrent in res_torrents.items() ] return torrents def delete_torrent(self, torrent_id): self.client.core.remove_torrent(torrent_id, remove_data=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_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 client.disconnect()
class DelugeRPC(object): """Deluge RPC client class.""" def __init__(self, host='localhost', port=58846, username=None, password=None): """Deluge RPC 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.""" try: self.client = DelugeRPCClient(self.host, self.port, self.username, self.password, decode_utf8=True) self.client.connect() except Exception as error: log.warning('Error while trying to connect to deluge daemon. Error: {error}', {'error': error}) raise def disconnect(self): """Disconnect RPC client.""" self.client.disconnect() def test(self): """Test connection. :return: :rtype: bool """ try: self.connect() except Exception: return False else: return True 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) except Exception: 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) 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 remove_torrent_data(self, torrent_id): """Remove torrent from client and disk 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 remove_torrent(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, False) 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 _torrent_properties(self, info_hash): """Get torrent properties.""" try: self.connect() log.debug('Checking DelugeD torrent {hash} status.', {'hash': info_hash}) torrent_data = self.client.core.get_torrent_status( info_hash, ('name', 'hash', 'progress', 'state', 'ratio', 'stop_ratio', 'is_seed', 'is_finished', 'paused', 'files', 'download_location')) except RequestException as error: raise DownloadClientConnectionException(f'Error while fetching torrent info_hash {info_hash}. Error: {error}') except Exception: log.warning('Error while fetching torrent {hash} status.', {'hash': info_hash}) return else: return torrent_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', ('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'), ) required = ('username', 'password') host = '127.0.0.1' port = 58846 path = None libtorrent_stats = False rounding = 2 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: self.client.connect() 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) 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: 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).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())
class TorrentClient(object): def __init__(self): self.conn = None 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 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): options = {} if mylar.CONFIG.DELUGE_DOWNLOAD_DIRECTORY: options[ 'download_location'] = mylar.CONFIG.DELUGE_DOWNLOAD_DIRECTORY if mylar.CONFIG.DELUGE_DONE_DIRECTORY: options['move_completed'] = 1 options['move_completed_path'] = mylar.CONFIG.DELUGE_DONE_DIRECTORY if mylar.CONFIG.DELUGE_PAUSE: options['add_paused'] = int(mylar.CONFIG.DELUGE_PAUSE) 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), options) except Exception as e: logger.debug('Torrent not added') return False else: try: torrent_id = self.client.call('core.add_torrent_magnet', str(filepath), options) 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'], 'move path': torrent_info['move_completed_path'], 'total_filesize': torrent_info['total_size'], 'name': torrent_info['name'], 'files': torrent_info['files'], 'time_started': torrent_info['active_time'], 'pause': torrent_info['paused'], '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 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
async def on_message(self, message): if message.author == self.user: return text = message.content.strip() if message.channel.id == authentication_channel and message.author.id == authentication_user: if text == "!stop": await sys.exit(1) if text == "!clear": global queued_requests queued_requests = {} if text in queued_requests: request = queued_requests[text] await self.send_request(request) await message.channel.send(f"Request approved: {text}") await request.requester_channel.send( f"The request for '{request.name}' has been approved!") del queued_requests[text] else: await message.channel.send("That uuid doesn't exist...") if not message.guild.name in active_servers: return if not message.channel.name in active_channels: return if text.lower().startswith("!add"): add_regex = "!add\nmagnet: *(magnet:\?[^ ]*)\nchannel: *([\w\d ]*)\nname: *([\w\d ]*)" regex = re.compile(add_regex, re.I | re.M) groups = regex.match(text) if groups is None: await message.channel.send( "Not a valid '!add' command! Use '!help' if you are confused." ) return magnet = groups.group(1).strip() channel = groups.group(2).strip() name = groups.group(3).strip() requester_name = message.author.name + message.author.discriminator if channel.lower() in plex_channels: channel = plex_channels[channel.lower()] else: await message.channel.send( f"That's not a valid channel on plex! Please choose one of {plex_channels.values()}" ) return request = Request(magnet, channel, name, requester_name, message.channel) request_uuid = str(uuid.uuid4()) queued_requests[request_uuid] = request auth_channel = self.get_channel(authentication_channel) await auth_channel.send( f"Request submitted: {request}\n\n ID: {request_uuid}") await message.channel.send( f"Your request has been submitted, and is pending approval") elif text.lower().startswith("!status"): requester_name = message.author.name + message.author.discriminator now = time.time() then = now - 24 * 60 * 60 with TinyDB('db') as db: request = Query() torrents = db.search((request.requester_name == requester_name) & (request.time > then)) status_string = f"Here's the status for all the approved torrents requested by {requester_name} in the last 24 hours:\n" conn = DelugeClient('master.seedhost.eu', 21110, os.environ['DELUGE_USER'], os.environ['DELUGE_PASS']) conn.connect() for torrent in torrents: torrent_name = torrent['torrent_name'] torrent_id = torrent['torrent_id'] status = conn.call('core.get_torrent_status', torrent_id, ['state', 'total_done', 'total_wanted']) if not b'state' in status: continue state = status[b'state'].decode() total_done = status[b'total_done'] total_wanted = status[b'total_wanted'] status_string += "{:<35} {:>15}% completed\n".format( torrent_name, int(total_done / total_wanted * 100)) await message.channel.send(status_string) elif text.lower().startswith("!"): help_text_1 = \ "This is a simple bot that will let you download torrents onto the Plex server, without having harass me " \ "a ton. Right now, there are only 3 commands:\n" \ "!add : Allows you to add torrents to the server. Usage is detailed below.\n" \ "!status : Shows you the download status of all of the approved torrents you requested in the " \ "last 24 hours\n" \ "!help : Shows this message!\n" \ "\n" \ "To use !add, you need to provide a information in a specific format. The three pieces of information " \ "that you will need to provide are: 1) the magnet link to the desired torrent, 2) the plex channel that " \ "you want the torrent to show up on (so, one of: TV, Movies, Weeb TV), and 3) the name of the media you're " \ "downloading. This must be provided in a message the follows the given format: \n" \ "\n" \ "!add\n" \ "magnet: <magnet link>\n" \ "channel: <plex channel>\n" \ "name: <name of thing>\n" \ "\n" \ "So, an example of a valid request would be:\n" \ "\n" \ "!add\n" \ "magnet: magnet:?xt=urn:btih:52FD58172C296021F2E351B8A12BBC8BE7C88F8D&dn=Batman+Begins+%282005%29+1080p+BluRay+x264+-+1.6GB+-+YIFY&tr=udp%3A%2F%2Ftracker.yify-torrents.com%2Fannounce&tr=http%3A%2F%2Finferno.demonoid.me%3A3414%2Fannounce&tr=http%3A%2F%2Ftracker.yify-torrents.com%2Fannounce&tr=udp%3A%2F%2Ftracker.1337x.org%3A80%2Fannounce&tr=http%3A%2F%2Fexodus.desync.com%2Fannounce&tr=http%3A%2F%2Ft1.pow7.com%2Fannounce&tr=http%3A%2F%2Fexodus.desync.com%2Fannounce&tr=http%3A%2F%2Feztv.tracker.prq.to%2Fannounce&tr=http%3A%2F%2Fpow7.com%2Fannounce&tr=http%3A%2F%2Ftracker.torrent.to%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.zer0day.to%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fcoppersurfer.tk%3A6969%2Fannounce\n" \ "channel: Movies\n" \ "name: Batman Begins\n" help_text_2 = \ "\nNote that this command will not immediately download the torrent. Instead, it will send me a message, " \ "asking me if I think it's a responsible request. If I approve it, this bot will update this channel to " \ "let you know its been approved. Only approved torrents will show up in !status.\n" \ "\n" \ "Last thing-- I literally wrote this in a couple of hours, and its not meant tp be super robust (yet!). " \ "I will be continually improving and updating this bot, and I know that there are a few potential bugs, " \ "as well as a bunch of features I wanna add, so if you hit any issues, just lemme know." await message.channel.send(help_text_1) await message.channel.send(help_text_2)
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 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
class p2p_client(): def __init__(self, com_id, host_id): self.com_id = int(com_id) self.host_id = int(host_id) self.port = 62000 + (self.com_id - 1) * 100 + (self.host_id - 1) self.home_dir = './experiment/' self.account = '' self.password = '' def config(self): dir_type = ['Config', 'Log', 'PID', 'Host_Local_Storage', 'NewTorrent'] ids = 'Com' + str(self.com_id) + '_Host' + str(self.host_id) for k in dir_type: path = self.home_dir + k + '/' + ids if not os.path.isdir(path): try: os.makedirs(path) except: print 'Error: error when making directories!! dir:', path sys.exit() log_file = self.home_dir + 'Log/' + ids + '/' + ids + '.txt' pid_file = self.home_dir + 'PID/' + ids + '/' + ids + '.txt' if not os.path.isfile(log_file): try: open(log_file, 'w').close() except: print 'Error when writing log file' sys.exit() if not os.path.isfile(pid_file): try: open(pid_file, 'w').close() except: print 'Error when writing pid file' sys.exit() def get_user_info(self): config = self.home_dir + 'Config/Com' + str( self.com_id) + '_Host' + str(self.host_id) + '/auth' try: f = open(config, 'r') data = f.read().split(':') self.account = data[0] self.password = data[1] f.close() except: print 'Error: error when getting Accoung/Password' sys.exit() def start_daemon(self): ids = 'Com' + str(self.com_id) + '_Host' + str(self.host_id) config_path = self.home_dir + 'Config/' + ids log_file = self.home_dir + 'Log/' + ids + '/' + ids + '.txt' pid_file = self.home_dir + 'PID/' + ids + '/' + ids + '.txt' command = 'deluged -c %s -l %s -P %s -p %s' % ( config_path, log_file, pid_file, str(self.port)) os.system(command) time.sleep(5) def shutdown(self): self.client.call('daemon.shutdown') def login(self): self.client = DelugeRPCClient('127.0.0.1', self.port, self.account, self.password) self.client.connect() def get_session_state(self): return self.client.call('core.get_session_state') def clean_session(self): item = self.get_session_state() for k in item: self.remove_torrent(k) def get_method_list(self): method = sorted(list(self.client.call('daemon.get_method_list'))) for k in method: print k def get_torrent_status(self, hashid): return self.client.call('core.get_torrent_status', hashid, '') def get_torrents_status(self): return self.client.call('core.get_torrents_status', {}, []) def add_torrent(self, file_name): torrent_file = self.home_dir + 'torrent/' + file_name download_path = self.home_dir + 'Host_Local_Storage/' + 'Com' + str( self.com_id) + '_Host' + str(self.host_id) if not os.path.isdir(download_path): try: os.makedirs(download_path) except: print 'Error: error when making download directories' sys.exit() self.client.call('core.add_torrent_file', torrent_file, base64.encodestring(open(torrent_file, 'rb').read()), { 'add_paused': True, 'download_location': download_path }) def remove_torrent(self, hashid, remove_data=True): self.client.call('core.remove_torrent', hashid, remove_data) def create_torrent(self, file_dst, comment='', create_by=''): source = '/home/john/p2p/file/' + file_dst torrent_location = self.home_dir + 'NewTorrent/' + 'Com' + str( self.com_id) + '_Host' + str( self.host_id) + '/' + file_dst + '.torrent' tracker = 'http://192.168.144.126:9010/' piece_length = 30768 webseeds = '' add_to_session = True private = False trackers = '' self.client.call('core.create_torrent', source, tracker, piece_length, comment, torrent_location, webseeds, private, create_by, trackers, add_to_session) def resume_torrent(self, torrents): self.client.call('core.resume_torrent', torrents) def pause_torrent(self, torrents): self.client.call('core.pause_torrent', torrents) def set_torrent_max_download_speed(self, torrent, value): self.client.call('core.set_torrent_max_download_speed', torrent, value) def set_torrent_max_upload_speed(self, torrent, value): self.client.call('core.set_torrent_max_upload_speed', torrent, value) def get_session_status(self, key=''): return self.client.call('core.get_session_status', key)
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
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 on_task_abort(self, task, config): pass def prepare_config(self, config): config.setdefault('host', 'localhost') config.setdefault('port', 58846) return config def connect(self): """Connects to the deluge daemon and runs on_connect_success """ self.client.connect() if not self.client.connected: raise plugin.PluginError('Deluge failed to connect.') def disconnect(self): self.client.disconnect() 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 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 DefineDelugeInterface: def __init__(self, address, port, username, password): # The actual interface with the deluge daemon, via the RPCClient package # This object captures the interface (including address & credentials) to be # opened, closed, and used to pass messages to the daemon self.delugeinterface = DelugeDaemonInterface(address, port, username, password) # The deluge keys used for gaining overall session data via the 'core.get_session_status' call self.delugekeysforsessioninfo = [ "payload_download_rate", "payload_upload_rate", "total_payload_upload" ] # The deluge keys used for gaining detailed data about a single torrent via the 'core.get_torrent_status' call self.delugekeysfortorrentinfo = [ "state", "save_path", "name", "total_size", "progress", "eta", "files", "tracker_status", "is_finished", "time_added", "num_seeds", "num_peers" ] # The full list deluge keys available for gaining detailed data about a single torrent via the # 'core.get_torrent_status' call self.alldelugekeysavailablefortorrentinfo = [ "state", "save_path", "tracker", "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" ] # ========================================================================================= # Opens a connection with the deluge daemon, for messages to be passed to/from it # ========================================================================================= def openconnection(self): # Logging.printout("- Connecting to Deluge Daemon <small>(" + reasontext + ")</small>") try: while self.delugeinterface.connected == False: self.delugeinterface.connect() # print "=========================================================" # print self.delugeinterface.call('client.api_methods') # print "=========================================================" # WORKS! print self.delugeinterface.call('core.get_free_space') # print "=========================================================" # WORKS! print self.delugeinterface.call('core.get_config') # print "=========================================================" outcome = self.delugeinterface.connected except Exception as errortype: outcome = None print( "DELUGE INTERFACE ERROR: Trying to connect to deluge client (", errortype, ")") return outcome # ========================================================================================= # Closes the open connection with the deluge daemon # ========================================================================================= def closeconnection(self): try: while self.delugeinterface.connected == True: self.delugeinterface.disconnect() outcome = self.delugeinterface.connected except Exception as errortype: outcome = None print( "DELUGE INTERFACE ERROR: Trying to disconnect from deluge client (", errortype, ")") return outcome # ========================================================================================= # Returns a list of strings, one per torrent, providing the GUID of each torrent # ========================================================================================= def retrievetorrentlist(self): try: outcome = [] rawtorrentlist = self.delugeinterface.call( 'core.get_session_state') for rawtorrentid in rawtorrentlist: outcome.append(rawtorrentid.decode("ascii", "ignore")) except Exception as errortype: print("DELUGE INTERFACE ERROR: Trying to retrieve torrent list (", errortype, ")") outcome = None return outcome # ========================================================================================= # Returns a structured/layered dictionary of information about a specified (by GUID) torrent # ========================================================================================= def retrievetorrentdata(self, torrentid): try: outcome = {} rawtorrentdata = self.delugeinterface.call( 'core.get_torrent_status', torrentid, self.delugekeysfortorrentinfo) for itemkey in rawtorrentdata: itemdata = rawtorrentdata[itemkey] newkeyname = itemkey.decode("utf-8", "ignore") if isinstance(itemdata, bytes) == True: outcome[newkeyname] = itemdata.decode("utf-8", "ignore") elif isinstance(itemdata, tuple) == True: newlist = [] for subitem in itemdata: newsubdictionary = {} for subitemkey in subitem: newsubitemkey = subitemkey.decode( "utf-8", "ignore") if isinstance(subitem[subitemkey], bytes) == True: newsubitemdata = subitem[subitemkey].decode( "utf-8", "ignore") else: newsubitemdata = subitem[subitemkey] newsubdictionary[newsubitemkey] = newsubitemdata newlist.append(newsubdictionary) outcome[newkeyname] = newlist else: outcome[newkeyname] = itemdata except Exception as errortype: print( "DELUGE INTERFACE ERROR: Trying to retrieve torrent data for " + torrentid + " (", errortype, ")") outcome = None return outcome # ========================================================================================= # Adds a new torrent to the daemon, using the specified link URL # Returns the GUID of the added torrent # ========================================================================================= def addtorrentlink(self, linkstring): try: if linkstring[:7] == "magnet:": newtorrentid = self.delugeinterface.call( 'core.add_torrent_magnet', linkstring, {}) else: newtorrentid = self.delugeinterface.call( 'core.add_torrent_url', linkstring, {}) outcome = newtorrentid.decode("ascii", "ignore") except Exception as errortype: print("DELUGE INTERFACE ERROR: Trying to add new torrent (", errortype, ")") outcome = None return outcome # ========================================================================================= # Instigates a recheck of the specified (by GUID) torrent # (Returns the RPCClient response, an unknown object) # ========================================================================================= def rechecktorrent(self, torrentids): try: outcome = self.delugeinterface.call('core.force_recheck', torrentids) except Exception as errortype: print( "DELUGE INTERFACE ERROR: Trying to force recheck of torrent " + torrentids + " (", errortype, ")") outcome = None return outcome # ========================================================================================= # Pauses the specified (by GUID) torrent # If "ALL" is specified, all torrents in the daemon are paused # (Returns the RPCClient response, an unknown object) # ========================================================================================= def pausetorrent(self, torrentid): try: if torrentid == "ALL": outcome = self.delugeinterface.call('core.pause_all_torrents') else: outcome = self.delugeinterface.call('core.pause_torrent', [torrentid]) except Exception as errortype: print( "DELUGE INTERFACE ERROR: Trying to pause torrent " + torrentid + " (", errortype, ")") outcome = None return outcome # ========================================================================================= # Unpauses the specified (by GUID) torrent # If "ALL" is specified, all torrents in the daemon are unpaused # (Returns the RPCClient response, an unknown object) # ========================================================================================= def resumetorrent(self, torrentid): try: if torrentid == "ALL": outcome = self.delugeinterface.call('core.resume_all_torrents') else: outcome = self.delugeinterface.call('core.resume_torrent', [torrentid]) except Exception as errortype: print( "DELUGE INTERFACE ERROR: Trying to resume torrent " + torrentid + " (", errortype, ")") outcome = None return outcome # ========================================================================================= # Deletes the specified (by GUID) torrent # (Returns the RPCClient response, an unknown object) # ========================================================================================= def deletetorrent(self, torrentid): try: outcome = self.delugeinterface.call('core.remove_torrent', torrentid, True) except Exception as errortype: print( "DELUGE INTERFACE ERROR: Trying to delete torrent " + torrentid + " (", errortype, ")") outcome = None return outcome # ========================================================================================= # Returns a dictionary of information about the daemon session # ========================================================================================= def retrievesessiondata(self): try: rawstats1 = self.delugeinterface.call( 'core.get_session_status', self.delugekeysforsessioninfo) rawstats2 = self.delugeinterface.call('core.get_free_space') outcome = {} outcome['uploadspeed'] = rawstats1[b'payload_upload_rate'] outcome['downloadspeed'] = rawstats1[b'payload_download_rate'] outcome['uploadedtotal'] = rawstats1[b'total_payload_upload'] outcome['freespace'] = rawstats2 / 1000000000 except Exception as errortype: print("DELUGE INTERFACE ERROR: Trying to retrieve session data (", errortype, ")") outcome = None return outcome
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
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")
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 on_task_abort(self, task, config): pass def prepare_config(self, config): config.setdefault('host', 'localhost') config.setdefault('port', 58846) return config def connect(self): """Connects to the deluge daemon and runs on_connect_success """ self.client.connect() if not self.client.connected: raise plugin.PluginError('Deluge failed to connect.') def disconnect(self): self.client.disconnect() 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') 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
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
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: files.append(contents['path'])
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
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()
def c_De(): __APIURL__ = raw_input("输入API地址(站内查看):") __DE_URL__ = raw_input("输入客户端IP(http://IP):") __DE_PORT__ = raw_input("输入客户端后端端口(非WebUI端口):") __DE_PORT__ = int(__DE_PORT__) __DE_USER__ = raw_input("输入客户端用户名:") __DE_PW__ = raw_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
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()
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:
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 DelugeService: # list of deluge filed - https://libtorrent.org/single-page-ref.html def __init__(self, config): self._deluge_client = DelugeRPCClient(config.get('deluge', 'host'), int(config.get('deluge', 'port')), config.get('deluge', 'username'), config.get('deluge', 'password'), decode_utf8=True) self._deluge_client.connect() self._label_enable = False try: self._label_enable = bool( strtobool(config.get('deluge', 'LabelEnable', fallback='false'))) except ValueError: pass self._label_id = config.get('deluge', 'LabelId', fallback=None) if self._is_label_enabled(): self.create_label(self._label_id) def add_torrent_magnet(self, magnet_url: str) -> str: # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L556 torrent_id = self._deluge_client.core.add_torrent_magnet( magnet_url, {}) if self._is_label_enabled(): self.set_torrent_label(torrent_id, self._label_id) return torrent_id def add_torrent_file(self, file_name: str, file_base64_str: str) -> str: # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L407 torrent_id = self._deluge_client.core.add_torrent_file( file_name, file_base64_str, {}) if self._is_label_enabled(): self.set_torrent_label(torrent_id, self._label_id) return torrent_id def create_label(self, label_id: str): # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L178 try: self._deluge_client.label.add(label_id) except Exception as e: if 'Exception: Label already exists' not in str(e): raise e def delete_label(self, label_id: str): # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L193 try: self._deluge_client.label.remove(label_id) except Exception as e: if 'Exception: Unknown Label' not in str(e): raise e def get_labels(self) -> List[str]: # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L173 return self._deluge_client.label.get_labels() def set_torrent_label(self, torrent_id: str, label_id: str): # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/plugins/Label/deluge_label/core.py#L312 self._deluge_client.label.set_torrent(torrent_id, label_id) def delete_torrent(self, torrent_id: str): # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L574 self._deluge_client.core.remove_torrent(torrent_id, False) def torrent_name_by_id(self, torrent_id: str) -> str: # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L758 return self._deluge_client.core.get_torrent_status( torrent_id, ['name'])['name'] def torrent_status(self, torrent_id: str) -> Dict[str, str]: # https://github.com/deluge-torrent/deluge/blob/deluge-2.0.3/deluge/core/core.py#L758 return self._deluge_client.core.get_torrent_status( torrent_id, ['name', 'state']) def torrents_status(self, torrent_ids: List[str]) -> List[Dict[str, str]]: fields = ['name', 'state', 'progress', 'completed_time', 'time_added'] torrents_dict = self._deluge_client.core.get_torrents_status( {"id": [i for i in torrent_ids]}, fields) return DelugeService._dict_key_to_obj(torrents_dict) def labeled_torrents(self) -> List[Dict[str, str]]: if self._is_label_enabled(): fields = [ 'name', 'state', 'progress', 'completed_time', 'time_added' ] labeled_torrents = self._deluge_client.core.get_torrents_status( {'label': self._label_id}, fields) return DelugeService._dict_key_to_obj(labeled_torrents) else: return [] def stop_download_torrents(self): self._deluge_client.core.set_config({'max_download_speed': "0"}) def resume_download_torrents(self): self._deluge_client.core.set_config({'max_download_speed': "-1"}) def _is_label_enabled(self) -> bool: if self._label_enable and self._label_id: return True else: return False @staticmethod def _dict_key_to_obj(d) -> List[Dict[str, str]]: if not d or not len(d): return [] torrents = [] for key, value in d.items(): value['_id'] = key torrents.append(value) return torrents def disconnect(self): self._deluge_client.disconnect()
def init_deluge(): global deluge deluge = DelugeRPCClient(config.deluge_host, config.deluge_port, config.deluge_user, config.deluge_pass) deluge.connect() assert deluge.connected