def enqueue_deluge(): max_items = 200 mongo = MongoClient(MONGO_HOST, MONGO_PORT) yts_db = mongo['yts'] movies_collection = yts_db['movies'] print colored("MESSG:Updating Deluge", "cyan") deluge = Deluge("127.0.0.1", 58846, 'admin', 'deluge') deluge.connect() torrents = deluge.call('core.get_torrents_status', {}, {}) #remove completed torrents torrents_to_remove = [] for torrent in torrents: if torrents[torrent]['is_finished']: deluge.call("core.remove_torrent", torrent, {}) torrents_to_remove.append(torrent) print colored("DELTE:","red") + "{}".format(torrent) for id in torrents_to_remove: del torrents[id] #add a new one(s) to replace diff = max_items - len(torrents) if(diff > 0): for i in range(0,diff): movie = movies_collection.find({"downloaded": False, "year": {"$gt": 1970}, "language": "English"}).sort([("rating", -1),("year", -1)]).limit(1)[0] movie['downloaded'] = True movies_collection.save(movie); deluge.call('core.add_torrent_magnet', movie['magnet_url'], {}) print colored("QUEUE:","yellow") + "({}) {} - {}".format(movie['rating'], movie['year'], movie['title'].encode("utf-8"))
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 dwnTorrent(magnet, hash, dir): client = DelugeRPCClient(dHost, dPort, dUser, dPass) try: client.connect() except: return path = '' torrent = client.call('core.get_torrent_status', hash, []) if torrent: percent = float(torrent[b'file_progress'][0] * 100) #msg = 'already in deluge ({0})'.format(percent) else: client.call('core.add_torrent_magnet', magnet, {'download_location': dir}) #msg = 'not found, adding to deluge' #waiting for the files to appear while not (client.call('core.get_torrent_status', hash, [])[b'files']): time.sleep(2) else: files = client.call('core.get_torrent_status', hash, [])[b'files'] for format in video_formats: for file in files: if format in file[b'path'].decode('utf-8'): path = file[b'path'].replace(b'/', b'\\').decode('utf-8') client.disconnect() return path
def add_rutracker_torrent(self, filename: str, torrent: bytes) -> None: logger.info("Add torrent") client = DelugeRPCClient( self.host, self.port, self.user, self.password, ) client.call('core.add_torrent_file', filename, b64encode(torrent), {})
class DelugeHost(object): def __init__(self, host, port, username, password): self.host = host self.port = port self.username = username self.password = password self.client = DelugeRPCClient( self.host, self.port, self.username, self.password ) self.client.connect() if not self.client.connected: raise DelugeNotConnectedException() @property def display(self): return f"{self.username}@{self.host}:{self.port}" @property def torrent_hashes(self): if "_torrent_hashes" not in self.__dict__ or self._torrent_hashes is None: logger.debug("Getting hashes from {}", self.display) self._torrent_hashes = [ key.decode("utf-8") for key in self.client.call("core.get_torrents_status", {}, []).keys() ] return self._torrent_hashes @property def torrent_count(self): return len(self.torrent_hashes) def add_torrent(self, torrent): with open(torrent, "rb") as file: data = bdecode(file.read()) info = data[b"info"] hash = sha1(bencode(info)).hexdigest() if hash in self.torrent_hashes or []: raise TorrentAlreadyPresentException(hash) with open(torrent, "rb") as file: filedump = encodestring(file.read()) filename = basename(torrent) result = self.client.call("core.add_torrent_file", filename, filedump, {}) logger.debug("Returning {}", result.decode("utf-8")) if result.decode("utf-8") != hash: raise Exception(result.decode("utf-8")) self._torrent_hashes = None return True
def uploadTorrent(self, filename): """ Upload a torrent to the deluge host based on the config file """ print('Uploading torrent %s' % (filename)) client = DelugeRPCClient(self.hostDeluge, self.portDeluge, self.usernameDeluge, self.passwordDeluge) client.connect() f = open(filename, 'rb') filedump = base64.encodestring(f.read()) f.close() client.call('core.add_torrent_file', filename, filedump, {}, ) bytes_available = client.call('core.get_free_space') gig_available = bytes_available/(1024.*1024*1024) print('There is %.1f GB available on the host \'%s\'.' % (gig_available, self.hostDeluge))
def 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
class DelugePlugin(object): """Base class for deluge plugins, contains settings and methods for connecting to a deluge daemon.""" def on_task_start(self, task, config): """Raise a DependencyError if our dependencies aren't available""" try: from deluge_client import DelugeRPCClient except ImportError as e: log.debug('Error importing deluge-client: %s' % e) raise plugin.DependencyError('deluge', 'deluge-client', 'deluge-client >=1.5 is required. `pip install deluge-client` to install.', log) config = self.prepare_config(config) if config['host'] in ['localhost', '127.0.0.1'] and not config.get('username'): # If an username is not specified, we have to do a lookup for the localclient username/password auth = self.get_localhost_auth() if auth and auth[0]: config['username'], config['password'] = auth else: raise plugin.PluginError('Unable to get local authentication info for Deluge. You may need to ' 'specify an username and password from your Deluge auth file.') self.client = DelugeRPCClient(config['host'], config['port'], config['username'], config['password'], decode_utf8=True) def prepare_config(self, config): config.setdefault('host', 'localhost') config.setdefault('port', 58846) return config def get_torrents_status(self, fields, filters=None): """Fetches all torrents and their requested fields optionally filtered""" if filters is None: filters = {} return self.client.call('core.get_torrents_status', filters, fields) @staticmethod def get_localhost_auth(): if sys.platform.startswith('win'): auth_file = os.path.join(os.getenv('APPDATA'), 'deluge', 'auth') else: auth_file = os.path.expanduser('~/.config/deluge/auth') if not os.path.isfile(auth_file): return None with open(auth_file) as auth: for line in auth: line = line.strip() if line.startswith('#') or not line: # This is a comment or blank line continue lsplit = line.split(':') if lsplit[0] == 'localclient': username, password = lsplit[:2] return username, password
def 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 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 get_progress(hash): client = DelugeRPCClient(dHost, dPort, dUser, dPass) try: client.connect() except ValueError as err: if ('already-connected SSLSocket' in str(err)): pass torrent = client.call('core.get_torrent_status', hash, []) percent = float(torrent[b'progress']) client.disconnect() return ('%.2f' % percent)
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}])
class DelugeClient(): def __init__(self): import config self.client = DelugeRPCClient( host=config.DELUGE['host'], port=config.DELUGE['port'], username=config.DELUGE['uname'], password=config.DELUGE['pword'] ) self.client.connect() self.torrent_status_data = None def connected(self): return self.client.connected def all_torrent_id(self): return self.client.call('core.get_session_state') def torrent_status(self, torrent_id): return self.client.call('core.get_torrent_status', torrent_id, []) def all_torrent_status(self, refresh=False): if refresh or self.torrent_status_data is None: self.torrent_status_data = [self.torrent_status(t_id) for t_id in self.all_torrent_id()] return self.torrent_status_data def torrent_exists(self, torrent_name): res = self.all_torrent_status() for torrent in res: if torrent[b'name'].decode('ascii') == torrent_name: return torrent return None def recheck_torrent(self, torrent_id): return self.client.call('core.force_recheck', [torrent_id]) def resume_torrent(self, torrent_id): return self.client.call('core.resume_torrent', [torrent_id]) def remove_torrent(self, torrent_id, remove_data=False): return self.client.call('core.remove_torrent', torrent_id, remove_data) def set_do_not_download(self, torrent_id): res = self.torrent_status(torrent_id) if res: new_file_priorities = [0 for _ in res[b'file_priorities']] self.client.call('core.set_torrent_file_priorities', torrent_id, new_file_priorities) else: return None
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()) })
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 DelugeClient(BaseClient): identifier = 'deluge' def __init__(self, host, username, password): """ Initializes a new Deluge client. url - The url where deluge json can be reached. password - The password used to login """ host, port = host.split(':') self.host = host self.port = int(port) self.username = username self.password = password self.rpcclient = DelugeRPCClient(self.host, self.port, self.username, self.password) def _login(self): """ Logs into deluge """ if not self.rpcclient.connected: self.rpcclient.connect() def get_config(self): """ Get the current configuration that can be used in the autotorrent config file """ return { 'host': '%s:%s' % (self.host, self.port), 'username': self.username, 'password': self.password, } @classmethod def auto_config(cls): """ Tries to auto configure deluge using the .config/deluge files """ config_path = os.path.expanduser('~/.config/deluge/core.conf') if not os.path.isfile(config_path): logger.debug('deluge config file was not found') return if not os.access(config_path, os.R_OK): logger.debug('Unable to access deluge config file at %s' % config_path) return auth_path = os.path.expanduser('~/.config/deluge/auth') if not os.path.isfile(auth_path): logger.debug('deluge auth file was not found') return if not os.access(auth_path, os.R_OK): logger.debug('Unable to access deluge confauthig file at %s' % auth_path) return with open(config_path, 'r') as f: config_data = f.read() daemon_port = re.findall('"daemon_port":\s*(\d+)', config_data) if not daemon_port: logger.debug('No deluge port, just trying to use default') daemon_port = 58846 else: daemon_port = int(daemon_port[0]) with open(auth_path, 'r') as f: auth_data = f.read() auth_data = auth_data.split('\n')[0].split(':') if len(auth_data[0]) < 2: logger.debug('Invalid entry found in auth file') return username = auth_data[0] password = auth_data[1] return cls('127.0.0.1:%s' % daemon_port, username, password) def test_connection(self): """ Tests the Deluge RPC connection, returns message if found. """ self._login() return 'Free space: %s' % humanize_bytes(self.rpcclient.call('core.get_free_space')) def get_torrents(self): """ Returns a set of info hashes currently added to the client. """ logger.info('Getting a list of torrent hashes') self._login() result = self.rpcclient.call('core.get_torrents_status', {}, ['name']) return set(x.lower().decode('ascii') for x in result.keys()) def add_torrent(self, torrent, destination_path, files, fast_resume=True): """ Add a new torrent to Deluge. torrent is the decoded file as a python object. destination_path is where the links are. The complete files must be linked already. files is a list of files found in the torrent. """ name = torrent[b'info'][b'name'] logger.info('Trying to add a new torrent to deluge: %r' % name) destination_path = os.path.abspath(destination_path) infohash = hashlib.sha1(bencode(torrent[b'info'])).hexdigest() encoded_torrent = base64.b64encode(bencode(torrent)) basename = os.path.basename(destination_path) mapped_files = {} for i, f in enumerate(files): mapped_files[i] = os.path.join(basename, *f['path']) self._login() result = self.rpcclient.call('core.add_torrent_file', 'torrent.torrent', encoded_torrent, { 'download_location': os.path.dirname(destination_path), 'mapped_files': mapped_files, 'seed_mode': fast_resume}) return result and result.decode('utf-8') == infohash
class Deluge(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 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 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 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)
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"]) log.debug(contents["path"]) if category.lower() not in categories: log.error("No valid category detected.") sys.exit() if len(categories) != len(set(categories)): log.error("Duplicate category detected. Category names must be unique.")
class DelugeHelper: client = None def __init__(self, ip, port, user, password): self.client = DelugeRPCClient(ip, int(port), user, password) self.client.connect() def add_torrent(self, magnetlink, download_location): torrent_id = self.client.call( 'core.add_torrent_magnet', magnetlink, { 'download_location': download_location, 'prioritize_first_last_pieces': True, 'sequential_download': True }) time.sleep(2) torrent_name = str( self.client.call('core.get_torrent_status', torrent_id, ['name']).get(b'name'), 'utf-8') return 'Torrent %s started' % torrent_name def delete_torrent(self, torrent_id): torrent_name = str( self.client.call('core.get_torrent_status', torrent_id, ['name']).get(b'name'), 'utf-8') if self.client.call('core.remove_torrent', torrent_id, True): return 'Torrent %s was successfully deleted' % torrent_name else: return 'An error occurred while deleting %s' % torrent_name def get_torrents_to_delete(self): status_keys = ['name', 'total_size'] results = self.client.call('core.get_torrents_status', {}, status_keys) message = 'Name - Size\n' for torrent_id, status in results.items(): message += '%s - %s /del_%s \n' % (str( status.get(b'name'), 'utf-8'), format_size( status.get(b'total_size')), str(torrent_id).split("'")[1]) return message def get_active_torrents(self): status_keys = [ 'name', 'download_payload_rate', 'progress', 'eta', 'total_size' ] results = self.client.call('core.get_torrents_status', {'state': 'Allocating'}, status_keys) results.update( self.client.call('core.get_torrents_status', {'state': 'Checking'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Downloading'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Error'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Queued'}, status_keys)) results.update( self.client.call('core.get_torrents_status', {'state': 'Moving'}, status_keys)) message = 'Name - Downloading speed - Progress - ETA - Size\n' for torrent_id, status in results.items(): message += '%s - %s - %.1f%% - %s - %s \n' % ( str(status.get(b'name'), 'utf-8'), format_speed(status.get(b'download_payload_rate')), status.get(b'progress'), format_time(status.get(b'eta')), format_size(status.get(b'total_size'))) return message def get_finished_torrents(self): status_keys = ['name', 'upload_payload_rate', 'progress', 'total_size'] results = self.client.call('core.get_torrents_status', {'state': 'Seeding'}, status_keys) results.update( self.client.call('core.get_torrents_status', {'state': 'Paused'}, status_keys)) message = 'Name - Uploading speed - Progress - Size\n' for torrent_id, status in results.items(): message += '%s - %s - %.1f%% - %s \n' % ( str(status.get(b'name'), 'utf-8'), format_speed(status.get(b'upload_payload_rate')), status.get(b'progress'), format_size( status.get(b'total_size'))) return message
'message': msg, 'random_id': random }) try: while True: response = vk.method('messages.getConversations', values) if response['items']: item = response['items'][0] last_mess = item['last_message'] random = last_mess['random_id'] my_id = last_mess['peer_id'] text = last_mess['text'] try: client.call('core.add_torrent_url', text, {'download_location': '/home/pi/Torrents'}) except Exception: write_msg(my_id, 'Link doesn\'t work', random) else: write_msg(my_id, 'Download started!', random) time.sleep(1) except KeyboardInterrupt: print('Keyboard interrupt detected.') finally: print('Program was stopped.') # #(4) Импортируем класс DelugeRPCClient из библиотеки deluge_client . #(14-18) Создаём объект client для подключения к серверу deluge-web. Указываем локальный IP-адрес, порт, логин и пароль. #(21) Подключаемся к серверу. #(40) Функция API core.add_torrent_url принимает URL на торрент-файл и ставит его в очередь на скачивание. Дополнительно передаём параметр download_location, чтобы сохранить совместимость с deluge-web и web-пультом в хранении файлов.
class Deluge(object): def __init__(self, host): # Host self._host = host # RPC Client self._client = None # Torrent Properties Cache self._torrent_cache = {} # Cache Valid Time self._refresh_expire_time = 30 # Last Time of Refreshing Cache self._last_refresh = 0 # Login to Deluge def login(self, username, password): # Split IP(or domain name) and port splits = self._host.split(':') host = splits[0] if len(splits) > 0 else '' port = int(splits[1]) if len(splits) > 1 else DEFAULT_PORT # Create RPC client and connect to Deluge self._client = DelugeRPCClient(host, port, username, password, decode_utf8=True) try: self._client.connect() except DelugeClientException as e: # Display class name of the exception if there is no error messages raise LoginFailure(e.args[0].split('\n')[0] if len(e.args) > 0 else e.__class__.__name__) # A caller to call deluge api; includes exception processing def _call(self, method, *args, **kwargs): try: return self._client.call(method, *args, **kwargs) except DelugeClientException as e: # Raise our own exception raise RemoteFailure(e.args[0].split('\n')[0] if len(e.args) > 0 else e.__class__.__name__) # Get client status def client_status(self): cs = ClientStatus() # Set remote free space checker cs.free_space = self.remote_free_space # Get DL/UL information session_stats = self._call('core.get_session_status', [ 'payload_download_rate', 'payload_upload_rate', 'total_download', 'total_upload', ]) cs.download_speed = session_stats['payload_download_rate'] cs.total_downloaded = session_stats['total_download'] cs.upload_speed = session_stats['payload_upload_rate'] cs.total_uploaded = session_stats['total_upload'] # Get port status port_is_open = self._call('core.test_listen_port') cs.port_status = PortStatus.Open if port_is_open else PortStatus.Closed return cs # Get Deluge version def version(self): funcs = { 1: 'daemon.info', # For Deluge 1.x, use daemon.info 2: 'daemon.get_version', # For Deluge 2.x, use daemon.get_version } ver = self._call(funcs[self._client.deluge_version]) return ('Deluge %s' % ver) # Get API version def api_version(self): # Returns the protocol version return self._client.deluge_protocol_version if self._client.deluge_protocol_version is not None else 'not provided' # Get torrent list def torrents_list(self): # Save hashes torrents_hash = [] # Get torrent list (and their properties) torrent_list = self._call( 'core.get_torrents_status', {}, [ 'active_time', 'all_time_download', 'download_payload_rate', 'finished_time', 'hash', 'label', # Available when the plugin 'label' is enabled 'name', 'num_peers', 'num_seeds', 'progress', 'ratio', 'seeding_time', 'state', 'time_added', 'time_since_transfer', 'total_peers', 'total_seeds', 'total_size', 'total_uploaded', 'trackers', 'upload_payload_rate', ]) # Save properties to cache self._torrent_cache = torrent_list self._last_refresh = time.time() # Return torrent hashes for h in torrent_list: torrents_hash.append(h) return torrents_hash # Get Torrent Properties def torrent_properties(self, torrent_hash): # Check cache expiration if time.time() - self._last_refresh > self._refresh_expire_time: self.torrents_list() # Extract properties torrent = self._torrent_cache[torrent_hash] # Create torrent object torrent_obj = Torrent() torrent_obj.hash = torrent['hash'] torrent_obj.name = torrent['name'] if 'label' in torrent: torrent_obj.category = [torrent['label'] ] if len(torrent['label']) > 0 else [] torrent_obj.tracker = [ tracker['url'] for tracker in torrent['trackers'] ] torrent_obj.status = Deluge._judge_status(torrent['state']) torrent_obj.size = torrent['total_size'] torrent_obj.ratio = torrent['ratio'] torrent_obj.uploaded = torrent['total_uploaded'] torrent_obj.downloaded = torrent['all_time_download'] torrent_obj.create_time = int(torrent['time_added']) torrent_obj.seeding_time = torrent['seeding_time'] torrent_obj.upload_speed = torrent['upload_payload_rate'] torrent_obj.download_speed = torrent['download_payload_rate'] torrent_obj.seeder = torrent['total_seeds'] torrent_obj.connected_seeder = torrent['num_seeds'] torrent_obj.leecher = torrent['total_peers'] torrent_obj.connected_leecher = torrent['num_peers'] torrent_obj.average_upload_speed = torrent['total_uploaded'] / torrent[ 'active_time'] if torrent['active_time'] > 0 else 0 if 'finished_time' in torrent: download_time = torrent['active_time'] - torrent['finished_time'] torrent_obj.average_download_speed = torrent[ 'all_time_download'] / download_time if download_time > 0 else 0 if 'time_since_transfer' in torrent: # Set the last active time of those never active torrents to timestamp 0 torrent_obj.last_activity = torrent[ 'time_since_transfer'] if torrent[ 'time_since_transfer'] > 0 else 0 torrent_obj.progress = torrent['progress'] / 100 # Accept Range: 0-1 return torrent_obj # Get free space def remote_free_space(self, path): return self._call('core.get_free_space', path) # Judge Torrent Status @staticmethod def _judge_status(state): return { 'Allocating': TorrentStatus.Unknown, # Ignore this state 'Checking': TorrentStatus.Checking, 'Downloading': TorrentStatus.Downloading, 'Error': TorrentStatus.Error, 'Moving': TorrentStatus.Unknown, # Ignore this state 'Paused': TorrentStatus.Paused, 'Queued': TorrentStatus.Queued, 'Seeding': TorrentStatus.Uploading, }[state] # Batch Remove Torrents def remove_torrents(self, torrent_hash_list, remove_data): if self._client.deluge_version >= 2: # Method 'core.remove_torrents' is only available in Deluge 2.x failures = self._call('core.remove_torrents', torrent_hash_list, remove_data) failed_hash = [torrent[0] for torrent in failures] return ( [ torrent for torrent in torrent_hash_list if torrent not in failed_hash ], [{ 'hash': torrent[0], 'reason': torrent[1], } for torrent in failures], ) else: # For Deluge 1.x, remove torrents one by one success_hash = [] failures = [] for torrent in torrent_hash_list: try: self._call('core.remove_torrent', torrent, remove_data) success_hash.append(torrent) except RemoteFailure as e: failures.append({ 'hash': torrent, 'reason': e.args[0], }) return (success_hash, failures)
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']) log.debug(contents['path']) if category.lower() not in categories: log.error("No valid category detected.") sys.exit() if len(categories) != len(set(categories)): log.error("Duplicate category detected. Category names must be unique.")
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 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 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: logger.info('Getting Torrent Info!') 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!') 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: logger.debug('TorrentID: ' + torrent_id) # If label enabled put label on torrent in Deluge if torrent_id and mylar.DELUGE_LABEL: logger.info('Setting label to ' + mylar.DELUGE_LABEL) try: self.client.call('label.set_torrent', torrent_id, mylar.DELUGE_LABEL) except: #if label isn't set, let's try and create one. try: self.client.call('label.add', mylar.DELUGE_LABEL) self.client.call('label.set_torrent', torrent_id, mylar.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' ) return torrent_id #False logger.info('Succesfully set label to ' + mylar.DELUGE_LABEL) try: self.find_torrent(torrent_id) logger.info('Double checking 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 torrent_id #True 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 from mylar import bencode # Open torrent file torrent_file = open(filepath, "rb") metainfo = bencode.bdecode(torrent_file.read()) info = metainfo['info'] thehash = hashlib.sha1(bencode.bencode(info)).hexdigest().upper() logger.debug('Hash: ' + thehash) return thehash
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 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
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 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
tID = sys.argv[1] dHost = "127.0.0.1" dPort = 58846 dUser = "******" dPass = "******" client = DelugeRPCClient(dHost,dPort,dUser,dPass) client.connect() while client.connected == False: time.sleep(3) client = DelugeRPCClient(dHost,dPort,dUser,dPass) client.connect() time.sleep(3) tData = client.call('core.get_torrent_status',tID,{}) print(tData) while tData[b'state'] == b'Downloading' or tData[b'state'] == b'Paused': # if len(tData[b'peers']) < 1: if len(tData[b'peers']) < 1 or len(tData[b'num_seeds']) == 0: client.call('core.pause_torrent',tID) time.sleep(3) client.call('core.resume_torrent',tID) time.sleep(2) client.call('core.force_reannounce',[tID]) time.sleep(3) tData = client.call('core.get_torrent_status',tID,{}) else: exit() exit()
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 DelugeClientKORPI(): """ Class for controlling deluge client. """ def __init__(self, username, password, host="127.0.0.1", port=58846): self._username = username self._password = password self._host = host self._port = port self.__client = DelugeRPCClient(host, int(port), username, password) def connect(self): self.__client.connect() def list(self): """Returns tuple with torrent hashes""" return self.__client.call("core.get_session_state") def status(self, thash=None): if thash: return self.__client.call('core.get_torrents_status', {"hash": thash}, []) else: return self.__client.call('core.get_torrents_status', {}, []) def completed(self, thash): """Returns % of downloaded from torrent.""" status = self.__client.call('core.get_torrents_status', {"hash": thash}, []) thash = thash.encode("utf-8") if status[thash][b"total_wanted"] == 0: return 0 else: return status[thash][b"total_done"] / status[thash][b"total_wanted"] * 100 def pause(self, thash=None): """ If hash not provided, pause/resume all torrents. Returns False if torrent(s) was paused, True otherwise. """ if thash: status = self.status(thash)[thash.encode("utf-8")][b"paused"] if status: self.__client.call('core.resume_torrent', [thash]) else: self.__client.call('core.pause_torrent', [thash]) return status else: if self.all_paused(): self.__client.call("core.resume_torrent", self.list()) else: self.__client.call("core.pause_torrent", self.list()) return self.all_paused() def add(self, magnet, directory, max_speed): return self.__client.call('core.add_torrent_magnet', magnet, {"download_location": directory, "max_download_speed": max_speed}) def remove(self, thash, with_files): """Set with_files True to remove with files""" if with_files == "True": with_files = True elif with_files == "False": with_files = False return self.__client.call("core.remove_torrent", thash, with_files) def free_space(self, directory): """Get free space in megabytes.""" return self.__client.call("core.get_free_space", directory) * TO_GB def download_speed(self, dmax=-1): for thash in self.list(): self.__client.call("core.set_torrent_max_download_speed", thash, int(dmax)) def all_paused(self): return all(paused[b"paused"] for _, paused in self.status().items())
def 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
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']) log.debug(contents['path']) if category.lower() not in categories: log.error("No valid category detected.") sys.exit() if len(categories) != len(set(categories)): log.error("Duplicate category detected. Category names must be unique.")
def get_movie(my_call, search_lst): for item, var in my_call.items(): search_me = str(var[b'name'], 'utf-8') new_srch = PTN.parse(search_me.lower()) if 'episode' in new_srch and 'season' in new_srch: continue choice = process.extractOne(new_srch['title'], search_lst) if choice[1] > 95: print(choice) print(item, var) paramiko.util.log_to_file('/tmp/paramiko.log') transport = paramiko.Transport(("dragoncave8.ddns.net", 1889)) transport.connect(None, "retsu", "dragon1991!") sftp = paramiko.SFTPClient.from_transport(transport) movies = sftp.listdir("/mnt/Media/Movies") search_lst = [PTN.parse(item.lower())['title'] for item in movies] client = DelugeRPCClient('perses.feralhosting.com', 53305, 'retsu8', 'yf-AXshN8_FjXTZA') client.connect() my_call = client.call('core.get_torrents_status', {}, ['name', 'ratio']) if transport is not None: transport.close()
class 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
username='******' # Se puede ver en home/.config/deluge/auth . Este es de level 10 = admin password='******' # Se puede ver en home/.config/deluge/auth client = DelugeRPCClient(servidor, puerto, username, password) client.connect() if client.connected: print "Conectado a " +servidor+':'+str(puerto) if len(sys.argv) > 1: if sys.argv[1] == '-add': if sys.argv[2] == '-magnet': uri = sys.argv[3] client.call('core.add_torrent_magnet', uri,{}) elif sys.argv[2] == '-torrent': uri = sys.argv[3] # TODO else: print 'Error: Algo no va bien...' elif sys.argv[1] == '-s': status = client.call('core.get_torrents_status', {}, []) if sys.argv > 2: if sys.argv[2] == '-list': print 'Num. de Torrents: '+ str(len(status)) c=0 for i in status.values(): c+=1
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