def on_alert_save_resume_data_failed(self, alert): log.debug("on_alert_save_resume_data_failed: %s", decode_string(alert.message())) torrent_id = str(alert.handle.info_hash()) if torrent_id in self.waiting_on_resume_data: self.waiting_on_resume_data[torrent_id].errback( Exception(decode_string(alert.message())))
def on_alert_storage_moved_failed(self, alert): """Alert handler for libtorrent storage_moved_failed_alert""" log.debug("on_alert_storage_moved_failed: %s", decode_string(alert.message())) try: torrent_id = str(alert.handle.info_hash()) torrent = self.torrents[torrent_id] except (RuntimeError, KeyError): return log.error("Torrent %s, %s", torrent_id, decode_string(alert.message())) if torrent_id in self.waiting_on_finish_moving: self.waiting_on_finish_moving.remove(torrent_id) torrent.is_finished = True component.get("EventManager").emit(TorrentFinishedEvent(torrent_id))
def on_alert_tracker_error(self, alert): """Alert handler for libtorrent tracker_error_alert""" error_message = decode_string(alert.msg) # If alert.msg is empty then it's a '-1' code so fallback to a.e.message. Note that alert.msg # cannot be replaced by a.e.message because the code is included in the string (for non-'-1'). if not error_message: error_message = decode_string(alert.error.message()) log.debug("Tracker Error Alert: %s [%s]", decode_string(alert.message()), error_message) try: torrent = self.torrents[str(alert.handle.info_hash())] except (RuntimeError, KeyError): return torrent.set_tracker_status("%s: %s" % (_("Error"), error_message))
def get_peers(self): """Returns a list of peers and various information about them""" ret = [] peers = self.handle.get_peer_info() for peer in peers: # We do not want to report peers that are half-connected if peer.flags & peer.connecting or peer.flags & peer.handshake: continue client = decode_string(str(peer.client)) # Make country a proper string country = str() for c in peer.country: if not c.isalpha(): country += " " else: country += c ret.append({ "client": client, "country": country, "down_speed": peer.payload_down_speed, "ip": "%s:%s" % (peer.ip[0], peer.ip[1]), "progress": peer.progress, "seed": peer.flags & peer.seed, "up_speed": peer.payload_up_speed, }) return ret
def on_alert_file_completed(self, alert): log.debug("file_completed_alert: %s", decode_string(alert.message())) try: torrent_id = str(alert.handle.info_hash()) except: return component.get("EventManager").emit(TorrentFileCompletedEvent(torrent_id, alert.index))
def on_alert_file_renamed(self, alert): log.debug("on_alert_file_renamed") log.debug("index: %s name: %s", alert.index, decode_string(alert.name)) try: torrent = self.torrents[str(alert.handle.info_hash())] torrent_id = str(alert.handle.info_hash()) except: return # We need to see if this file index is in a waiting_on_folder list folder_rename = False for i, wait_on_folder in enumerate(torrent.waiting_on_folder_rename): if alert.index in wait_on_folder[2]: folder_rename = True if len(wait_on_folder[2]) == 1: # This is the last alert we were waiting for, time to send signal component.get("EventManager").emit(TorrentFolderRenamedEvent(torrent_id, wait_on_folder[0], wait_on_folder[1])) # Empty folders are removed after libtorrent folder renames self.remove_empty_folders(torrent_id, wait_on_folder[0]) del torrent.waiting_on_folder_rename[i] self.save_resume_data((torrent_id,)) break # This isn't the last file to be renamed in this folder, so just # remove the index and continue torrent.waiting_on_folder_rename[i][2].remove(alert.index) if not folder_rename: # This is just a regular file rename so send the signal component.get("EventManager").emit(TorrentFileRenamedEvent(torrent_id, alert.index, alert.name)) self.save_resume_data((torrent_id,))
def on_alert_file_error(self, alert): log.debug("on_alert_file_error: %s", decode_string(alert.message())) try: torrent = self.torrents[str(alert.handle.info_hash())] except: return torrent.update_state()
def get_peers(self): """Returns a list of peers and various information about them""" ret = [] peers = self.handle.get_peer_info() for peer in peers: # We do not want to report peers that are half-connected if peer.flags & peer.connecting or peer.flags & peer.handshake: continue client = decode_string(str(peer.client)) # Make country a proper string country = str() for c in peer.country: if not c.isalpha(): country += " " else: country += c ret.append({ "client": client, "country": country, "down_speed": peer.payload_down_speed, "ip": "%s:%s" % (peer.ip[0], peer.ip[1]), "progress": peer.progress, "seed": peer.flags & peer.seed, "up_speed": peer.payload_up_speed, }) return ret
def on_alert_tracker_error(self, alert): log.debug("on_alert_tracker_error") try: torrent = self.torrents[str(alert.handle.info_hash())] except: return tracker_status = "%s: %s" % (_("Error"), decode_string(alert.msg)) torrent.set_tracker_status(tracker_status)
def on_alert_file_completed(self, alert): log.debug("file_completed_alert: %s", decode_string(alert.message())) try: torrent_id = str(alert.handle.info_hash()) except: return component.get("EventManager").emit( TorrentFileCompletedEvent(torrent_id, alert.index))
def get_name(self): if self.has_metadata: name = self.torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0] if not name: name = self.torrent_info.name() return decode_string(name) elif self.magnet: try: keys = dict([k.split('=') for k in self.magnet.split('?')[-1].split('&')]) name = keys.get('dn') if not name: return self.torrent_id name = unquote(name).replace('+', ' ') return decode_string(name) except: pass return self.torrent_id
def on_alert_tracker_error(self, alert): log.debug("on_alert_tracker_error") try: torrent = self.torrents[str(alert.handle.info_hash())] except: return tracker_status = "%s: %s" % (_("Error"), decode_string(alert.msg)) torrent.set_tracker_status(tracker_status)
def on_alert_tracker_warning(self, alert): log.debug("on_alert_tracker_warning") try: torrent = self.torrents[str(alert.handle.info_hash())] except: return tracker_status = '%s: %s' % (_("Warning"), decode_string(alert.message())) # Set the tracker status for the torrent torrent.set_tracker_status(tracker_status)
def on_alert_save_resume_data_failed(self, alert): log.debug("on_alert_save_resume_data_failed: %s", decode_string(alert.message())) try: torrent = self.torrents[str(alert.handle.info_hash())] except: return self.num_resume_data -= 1 torrent.waiting_on_resume_data = False self.save_resume_data_file()
def get_name(self): if self.has_metadata: name = self.torrent_info.file_at(0).path.replace("\\", "/", 1).split("/", 1)[0] if not name: name = self.torrent_info.name() return decode_string(name) elif self.magnet: try: keys = dict([ k.split('=') for k in self.magnet.split('?')[-1].split('&') ]) name = keys.get('dn') if not name: return self.torrent_id name = unquote(name).replace('+', ' ') return decode_string(name) except: pass return self.torrent_id
def on_alert_storage_moved_failed(self, alert): """Alert handler for libtorrent storage_moved_failed_alert""" log.debug("on_alert_storage_moved_failed: %s", decode_string(alert.message())) try: torrent_id = str(alert.handle.info_hash()) torrent = self.torrents[torrent_id] except (RuntimeError, KeyError): return if torrent_id in self.waiting_on_finish_moving: self.waiting_on_finish_moving.remove(torrent_id) torrent.is_finished = True component.get("EventManager").emit(TorrentFinishedEvent(torrent_id))
def on_alert_tracker_reply(self, alert): log.debug("on_alert_tracker_reply: %s", decode_string(alert.message())) try: torrent = self.torrents[str(alert.handle.info_hash())] except: return # Set the tracker status for the torrent if alert.message() != "Got peers from DHT": torrent.set_tracker_status(_("Announce OK")) # Check to see if we got any peer information from the tracker if alert.handle.status().num_complete == -1 or alert.handle.status().num_incomplete == -1: # We didn't get peer information, so lets send a scrape request torrent.scrape_tracker()
def on_alert_tracker_reply(self, alert): log.debug("on_alert_tracker_reply: %s", decode_string(alert.message())) try: torrent = self.torrents[str(alert.handle.info_hash())] except: return # Set the tracker status for the torrent if alert.message() != "Got peers from DHT": torrent.set_tracker_status(_("Announce OK")) # Check to see if we got any peer information from the tracker if alert.handle.status().num_complete == -1 or \ alert.handle.status().num_incomplete == -1: # We didn't get peer information, so lets send a scrape request torrent.scrape_tracker()
def on_alert_file_renamed(self, alert): log.debug("on_alert_file_renamed") log.debug("index: %s name: %s", alert.index, decode_string(alert.name)) try: torrent = self.torrents[str(alert.handle.info_hash())] torrent_id = str(alert.handle.info_hash()) except: return # We need to see if this file index is in a waiting_on_folder dict for wait_on_folder in torrent.waiting_on_folder_rename: if alert.index in wait_on_folder: wait_on_folder[alert.index].callback(None) break else: # This is just a regular file rename so send the signal component.get("EventManager").emit(TorrentFileRenamedEvent(torrent_id, alert.index, alert.name)) self.save_resume_data((torrent_id,))
def on_alert_fastresume_rejected(self, alert): """Alert handler for libtorrent fastresume_rejected_alert""" alert_msg = decode_string(alert.message()) log.error("on_alert_fastresume_rejected: %s", alert_msg) try: torrent_id = str(alert.handle.info_hash()) torrent = self.torrents[torrent_id] except (RuntimeError, KeyError): return if alert.error.value() == 134: if not os.path.isdir(torrent.options["download_location"]): error_msg = "Unable to locate Download Folder!" else: error_msg = "Missing or invalid torrent data!" else: error_msg = "Problem with resume data: %s" % alert_msg.split(":", 1)[1].strip() torrent.force_error_state(error_msg, restart_to_resume=True)
def on_alert_file_renamed(self, alert): log.debug("on_alert_file_renamed") log.debug("index: %s name: %s", alert.index, decode_string(alert.name)) try: torrent = self.torrents[str(alert.handle.info_hash())] torrent_id = str(alert.handle.info_hash()) except: return # We need to see if this file index is in a waiting_on_folder dict for wait_on_folder in torrent.waiting_on_folder_rename: if alert.index in wait_on_folder: wait_on_folder[alert.index].callback(None) break else: # This is just a regular file rename so send the signal component.get("EventManager").emit( TorrentFileRenamedEvent(torrent_id, alert.index, alert.name)) self.save_resume_data((torrent_id, ))
def handle_alerts(self, wait=False): """ Pops all libtorrent alerts in the session queue and handles them appropriately. :param wait: bool, if True then the handler functions will be run right away and waited to return before processing the next alert """ alerts = self.session.pop_alerts() # Loop through all alerts in the queue for alert in alerts: alert_type = type(alert).__name__ # Display the alert message if log.isEnabledFor(logging.DEBUG): log.debug("%s: %s", alert_type, decode_string(alert.message())) # Call any handlers for this alert type if alert_type in self.handlers: for handler in self.handlers[alert_type]: if not wait: self.delayed_calls.append(reactor.callLater(0, handler, alert)) else: handler(alert)
def handle_alerts(self, wait=False): """ Pops all libtorrent alerts in the session queue and handles them appropriately. :param wait: bool, if True then the handler functions will be run right away and waited to return before processing the next alert """ alerts = self.session.pop_alerts() # Loop through all alerts in the queue for alert in alerts: alert_type = type(alert).__name__ # Display the alert message if log.isEnabledFor(logging.DEBUG): log.debug("%s: %s", alert_type, decode_string(alert.message())) # Call any handlers for this alert type if alert_type in self.handlers: for handler in self.handlers[alert_type]: if not wait: self.delayed_calls.append(reactor.callLater(0, handler, alert)) else: handler(alert)
def begin_import(self, resume_data=None, use_wine_mappings=False, force_recheck=True, resume=False, transfer_meta=None): """ attempts to add utorrent torrents to deluge and reports the results back resume_data: path to utorrent resume data use_wine_mappings: bool to check torrent paths against wine mappings before import force_recheck: recheck all torrents after import resume: Do not add torrents in the paused state transfer_meta: a list of torrent option tags to transfer to the new torrent (also support 'time_added') """ self.find_wine_drives() if not resume_data: resume_data = self.get_default_resume_path() try: data = self.read_resume_data(resume_data) except Exception as e: with log: log.error('Failed to get resume.dat. Reason: {0}'.format(e)) defer.returnValue((None, None)) added = [] failed = [] with self.event_ledger: with log: counter = 0 for torrent, info in data.iteritems(): if torrent in self.config["torrent_blacklist"]: log.debug('skipping {0}'.format(torrent)) continue torrent = decode_string(torrent) counter += 1 if counter > 10: yield self.take_breath() counter = 0 if use_wine_mappings: torrent = os.path.abspath( os.path.join( os.path.dirname(resume_data), self.wine_path_check(torrent))) else: torrent = os.path.abspath( os.path.join(os.path.dirname(resume_data), torrent)) success, name = self._import_torrent(torrent, info, use_wine_mappings, force_recheck, resume, transfer_meta) if success: added.append(name) else: if not name: log.debug('blacklisted torrent, skipping') else: failed.append(name) defer.returnValue((added, failed))
def _import_torrent(self, torrent, info, use_wine_mappings=False, force_recheck=True, resume=False, transfer_meta=None): """handles importing of a single torrent. Same arguments as `begin_import`""" try: with open(torrent, 'rb') as f: filedump = base64.encodestring(f.read()) except IOError: log.error(u'Could not open torrent {0}! skipping...'.format(torrent)) return False, torrent try: ut_save_path = decode_string(info['path']) except TypeError: pass if use_wine_mappings: ut_save_path = self.wine_path_check(ut_save_path) torrent_root = os.path.basename(ut_save_path) deluge_storage_path = os.path.dirname(ut_save_path) try: log.debug(u'Adding {0} to deluge.'.format(torrent_root)) except UnicodeDecodeError: log.error('Bad Filename, skipping') return False, torrent_root options = { 'download_location': deluge_storage_path, 'add_paused': True if not resume else False, 'file_priorities': [0 if p == '\x80' else 1 for p in info['prio']], } torrent_id = component.get("Core").add_torrent_file( os.path.basename(torrent), filedump=filedump, options=options) if torrent_id is None: try: log.info(u'FAILURE: "{0}" could not be added, may already ' u'exsist...'.format(torrent_root)) except UnicodeDecodeError: log.error(u'FAILURE: Torrent Unicode Error') return False, torrent_root else: try: log.info(u'SUCCESS!: "{0}" added successfully'.format(torrent_root)) except UnicodeDecodeError: log.info(u'SUCCESS: added but with UnicodeError') try: targets = info['targets'] except KeyError: targets = None self.resolve_path_renames( torrent_id, torrent_root, force_recheck=force_recheck, targets=targets) if transfer_meta: translate_meta.transfer(torrent_id, info, transfer_meta) return True, torrent_root
def parse(self, filetree=1): if not self.__m_filedata: log.error("No data to process!") return try: self.__m_metadata = bencode.bdecode(self.__m_filedata) except Exception as e: log.warning("Failed to decode torrent data %s: %s", self.filename if self.filename else "", e) raise e self.__m_info_hash = sha(bencode.bencode( self.__m_metadata["info"])).hexdigest() # Get encoding from torrent file if available self.encoding = None if "encoding" in self.__m_metadata: self.encoding = self.__m_metadata["encoding"] elif "codepage" in self.__m_metadata: self.encoding = str(self.__m_metadata["codepage"]) if not self.encoding: self.encoding = "UTF-8" # Check if 'name.utf-8' is in the torrent and if not try to decode the string # using the encoding found. if "name.utf-8" in self.__m_metadata["info"]: self.__m_name = decode_string( self.__m_metadata["info"]["name.utf-8"]) else: self.__m_name = decode_string(self.__m_metadata["info"]["name"], self.encoding) # Get list of files from torrent info paths = {} dirs = {} if "files" in self.__m_metadata["info"]: prefix = "" if len(self.__m_metadata["info"]["files"]) > 1: prefix = self.__m_name for index, f in enumerate(self.__m_metadata["info"]["files"]): if "path.utf-8" in f: path = os.path.join(prefix, *f["path.utf-8"]) else: path = decode_string( os.path.join( prefix, decode_string(os.path.join(*f["path"]), self.encoding)), self.encoding) f["index"] = index paths[path] = f dirname = os.path.dirname(path) while dirname: dirinfo = dirs.setdefault(dirname, {}) dirinfo["length"] = dirinfo.get("length", 0) + f["length"] dirname = os.path.dirname(dirname) if filetree == 2: def walk(path, item): if item["type"] == "dir": item.update(dirs[path]) else: item.update(paths[path]) item["download"] = True file_tree = FileTree2(paths.keys()) file_tree.walk(walk) else: def walk(path, item): if type(item) is dict: return item return [paths[path]["index"], paths[path]["length"], True] file_tree = FileTree(paths) file_tree.walk(walk) self.__m_files_tree = file_tree.get_tree() else: if filetree == 2: self.__m_files_tree = { "contents": { self.__m_name: { "type": "file", "index": 0, "length": self.__m_metadata["info"]["length"], "download": True } } } else: self.__m_files_tree = { self.__m_name: (0, self.__m_metadata["info"]["length"], True) } self.__m_files = [] if "files" in self.__m_metadata["info"]: prefix = "" if len(self.__m_metadata["info"]["files"]) > 1: prefix = self.__m_name for f in self.__m_metadata["info"]["files"]: if "path.utf-8" in f: path = os.path.join(prefix, *f["path.utf-8"]) else: path = decode_string( os.path.join( prefix, decode_string(os.path.join(*f["path"]), self.encoding)), self.encoding) self.__m_files.append({ 'path': path, 'size': f["length"], 'download': True }) else: self.__m_files.append({ "path": self.__m_name, "size": self.__m_metadata["info"]["length"], "download": True })
def begin_import(self, resume_data=None, use_wine_mappings=False, force_recheck=True, resume=False, transfer_meta=None): """ attempts to add utorrent torrents to deluge and reports the results back resume_data: path to utorrent resume data use_wine_mappings: bool to check torrent paths against wine mappings before import force_recheck: recheck all torrents after import resume: Do not add torrents in the paused state transfer_meta: a list of torrent option tags to transfer to the new torrent (also support 'time_added') """ self.find_wine_drives() if not resume_data: resume_data = self.get_default_resume_path() try: data = self.read_resume_data(resume_data) except Exception as e: with log: log.error('Failed to get resume.dat. Reason: {0}'.format(e)) defer.returnValue((None, None)) added = [] failed = [] with self.event_ledger: with log: counter = 0 for torrent, info in data.iteritems(): if torrent in self.config["torrent_blacklist"]: log.debug('skipping {0}'.format(torrent)) continue torrent = decode_string(torrent) counter += 1 if counter > 10: yield self.take_breath() counter = 0 if use_wine_mappings: torrent = os.path.abspath( os.path.join(os.path.dirname(resume_data), self.wine_path_check(torrent))) else: torrent = os.path.abspath( os.path.join(os.path.dirname(resume_data), torrent)) success, name = self._import_torrent( torrent, info, use_wine_mappings, force_recheck, resume, transfer_meta) if success: added.append(name) else: if not name: log.debug('blacklisted torrent, skipping') else: failed.append(name) defer.returnValue((added, failed))
def _import_torrent(self, torrent, info, use_wine_mappings=False, force_recheck=True, resume=False, transfer_meta=None): """handles importing of a single torrent. Same arguments as `begin_import`""" try: with open(torrent, 'rb') as f: filedump = base64.encodestring(f.read()) except IOError: log.error( u'Could not open torrent {0}! skipping...'.format(torrent)) return False, torrent try: ut_save_path = decode_string(info['path']) except TypeError: pass if use_wine_mappings: ut_save_path = self.wine_path_check(ut_save_path) torrent_root = os.path.basename(ut_save_path) deluge_storage_path = os.path.dirname(ut_save_path) try: log.debug(u'Adding {0} to deluge.'.format(torrent_root)) except UnicodeDecodeError: log.error('Bad Filename, skipping') return False, torrent_root options = { 'download_location': deluge_storage_path, 'add_paused': True if not resume else False, 'file_priorities': [0 if p == '\x80' else 1 for p in info['prio']], } torrent_id = component.get("Core").add_torrent_file( os.path.basename(torrent), filedump=filedump, options=options) if torrent_id is None: try: log.info(u'FAILURE: "{0}" could not be added, may already ' u'exsist...'.format(torrent_root)) except UnicodeDecodeError: log.error(u'FAILURE: Torrent Unicode Error') return False, torrent_root else: try: log.info( u'SUCCESS!: "{0}" added successfully'.format(torrent_root)) except UnicodeDecodeError: log.info(u'SUCCESS: added but with UnicodeError') try: targets = info['targets'] except KeyError: targets = None self.resolve_path_renames(torrent_id, torrent_root, force_recheck=force_recheck, targets=targets) if transfer_meta: translate_meta.transfer(torrent_id, info, transfer_meta) return True, torrent_root
def _create_status_funcs(self): #if you add a key here->add it to core.py STATUS_KEYS too. self.status_funcs = { "active_time": lambda: self.status.active_time, "all_time_download": lambda: self.status.all_time_download, "compact": lambda: self.options["compact_allocation"], "distributed_copies": lambda: 0.0 if self.status.distributed_copies < 0 else \ self.status.distributed_copies, # Adjust status.distributed_copies to return a non-negative value "download_payload_rate": lambda: self.status.download_payload_rate, "file_priorities": lambda: self.options["file_priorities"], "hash": lambda: self.torrent_id, "is_auto_managed": lambda: self.options["auto_managed"], "is_finished": lambda: self.is_finished, "max_connections": lambda: self.options["max_connections"], "max_download_speed": lambda: self.options["max_download_speed"], "max_upload_slots": lambda: self.options["max_upload_slots"], "max_upload_speed": lambda: self.options["max_upload_speed"], "message": lambda: self.statusmsg, "move_on_completed_path": lambda: self.options["move_completed_path"], "move_on_completed": lambda: self.options["move_completed"], "move_completed_path": lambda: self.options["move_completed_path"], "move_completed": lambda: self.options["move_completed"], "next_announce": lambda: self.status.next_announce.seconds, "num_peers": lambda: self.status.num_peers - self.status.num_seeds, "num_seeds": lambda: self.status.num_seeds, "owner": lambda: self.owner, "paused": lambda: self.status.paused, "prioritize_first_last": lambda: self.options["prioritize_first_last_pieces"], "sequential_download": lambda: self.options["sequential_download"], "progress": lambda: self.status.progress * 100, "shared": lambda: self.options["shared"], "remove_at_ratio": lambda: self.options["remove_at_ratio"], "save_path": lambda: self.options["download_location"], "seeding_time": lambda: self.status.seeding_time, "seeds_peers_ratio": lambda: -1.0 if self.status.num_incomplete == 0 else \ self.status.num_complete / float(self.status.num_incomplete), # Use -1.0 to signify infinity "seed_rank": lambda: self.status.seed_rank, "state": lambda: self.state, "stop_at_ratio": lambda: self.options["stop_at_ratio"], "stop_ratio": lambda: self.options["stop_ratio"], "time_added": lambda: self.time_added, "total_done": lambda: self.status.total_done, "total_payload_download": lambda: self.status.total_payload_download, "total_payload_upload": lambda: self.status.total_payload_upload, "total_peers": lambda: self.status.num_incomplete, "total_seeds": lambda: self.status.num_complete, "total_uploaded": lambda: self.status.all_time_upload, "total_wanted": lambda: self.status.total_wanted, "tracker": lambda: self.status.current_tracker, "trackers": lambda: self.trackers, "tracker_status": lambda: self.tracker_status, "upload_payload_rate": lambda: self.status.upload_payload_rate, "comment": lambda: decode_string(self.torrent_info.comment()) if self.has_metadata else u"", "num_files": lambda: self.torrent_info.num_files() if self.has_metadata else 0, "num_pieces": lambda: self.torrent_info.num_pieces() if self.has_metadata else 0, "piece_length": lambda: self.torrent_info.piece_length() if self.has_metadata else 0, "private": lambda: self.torrent_info.priv() if self.has_metadata else False, "total_size": lambda: self.torrent_info.total_size() if self.has_metadata else 0, "eta": self.get_eta, "file_progress": self.get_file_progress, # Adjust progress to be 0-100 value "files": self.get_files, "is_seed": self.handle.is_seed, "peers": self.get_peers, "queue": self.handle.queue_position, "ratio": self.get_ratio, "tracker_host": self.get_tracker_host, "last_seen_complete": lambda: self.status.last_seen_complete, "name": self.get_name, "pieces": self._get_pieces_info, }
def on_alert_save_resume_data_failed(self, alert): log.debug("on_alert_save_resume_data_failed: %s", decode_string(alert.message())) torrent_id = str(alert.handle.info_hash()) if torrent_id in self.waiting_on_resume_data: self.waiting_on_resume_data[torrent_id].errback(Exception(decode_string(alert.message())))
self.__m_info_hash = sha(bencode.bencode(self.__m_metadata["info"])).hexdigest() # Get encoding from torrent file if available self.encoding = None if "encoding" in self.__m_metadata: self.encoding = self.__m_metadata["encoding"] elif "codepage" in self.__m_metadata: self.encoding = str(self.__m_metadata["codepage"]) if not self.encoding: self.encoding = "UTF-8" # Check if 'name.utf-8' is in the torrent and if not try to decode the string # using the encoding found. if "name.utf-8" in self.__m_metadata["info"]: self.__m_name = decode_string(self.__m_metadata["info"]["name.utf-8"]) else: self.__m_name = decode_string(self.__m_metadata["info"]["name"], self.encoding) # Get list of files from torrent info paths = {} dirs = {} if self.__m_metadata["info"].has_key("files"): prefix = "" if len(self.__m_metadata["info"]["files"]) > 1: prefix = self.__m_name for index, f in enumerate(self.__m_metadata["info"]["files"]): if "path.utf-8" in f: path = os.path.join(prefix, *f["path.utf-8"]) else:
class TorrentInfo(object): """ Collects information about a torrent file. :param filename: The path to the torrent :type filename: string """ def __init__(self, filename, filetree=1): # Get the torrent data from the torrent file try: log.debug("Attempting to open %s.", filename) self.__m_filedata = open(filename, "rb").read() self.__m_metadata = bencode.bdecode(self.__m_filedata) except Exception, e: log.warning("Unable to open %s: %s", filename, e) raise e self.__m_info_hash = sha(bencode.bencode( self.__m_metadata["info"])).hexdigest() # Get encoding from torrent file if available self.encoding = None if "encoding" in self.__m_metadata: self.encoding = self.__m_metadata["encoding"] elif "codepage" in self.__m_metadata: self.encoding = str(self.__m_metadata["codepage"]) if not self.encoding: self.encoding = "UTF-8" # Check if 'name.utf-8' is in the torrent and if not try to decode the string # using the encoding found. if "name.utf-8" in self.__m_metadata["info"]: self.__m_name = decode_string( self.__m_metadata["info"]["name.utf-8"]) else: self.__m_name = decode_string(self.__m_metadata["info"]["name"], self.encoding) # Get list of files from torrent info paths = {} dirs = {} if self.__m_metadata["info"].has_key("files"): prefix = "" if len(self.__m_metadata["info"]["files"]) > 1: prefix = self.__m_name for index, f in enumerate(self.__m_metadata["info"]["files"]): if "path.utf-8" in f: path = os.path.join(prefix, *f["path.utf-8"]) else: path = decode_string( os.path.join( prefix, decode_string(os.path.join(*f["path"]), self.encoding)), self.encoding) f["index"] = index if "sha1" in f and len(f["sha1"]) == 20: f["sha1"] = f["sha1"].encode('hex') if "ed2k" in f and len(f["ed2k"]) == 16: f["ed2k"] = f["ed2k"].encode('hex') paths[path] = f dirname = os.path.dirname(path) while dirname: dirinfo = dirs.setdefault(dirname, {}) dirinfo["length"] = dirinfo.get("length", 0) + f["length"] dirname = os.path.dirname(dirname) if filetree == 2: def walk(path, item): if item["type"] == "dir": item.update(dirs[path]) else: item.update(paths[path]) item["download"] = True file_tree = FileTree2(paths.keys()) file_tree.walk(walk) else: def walk(path, item): if type(item) is dict: return item return [paths[path]["index"], paths[path]["length"], True] file_tree = FileTree(paths) file_tree.walk(walk) self.__m_files_tree = file_tree.get_tree() else: if filetree == 2: self.__m_files_tree = { "contents": { self.__m_name: { "type": "file", "index": 0, "length": self.__m_metadata["info"]["length"], "download": True } } } else: self.__m_files_tree = { self.__m_name: (0, self.__m_metadata["info"]["length"], True) } self.__m_files = [] if self.__m_metadata["info"].has_key("files"): prefix = "" if len(self.__m_metadata["info"]["files"]) > 1: prefix = self.__m_name for f in self.__m_metadata["info"]["files"]: if "path.utf-8" in f: path = os.path.join(prefix, *f["path.utf-8"]) else: path = decode_string( os.path.join( prefix, decode_string(os.path.join(*f["path"]), self.encoding)), self.encoding) self.__m_files.append({ 'path': path, 'size': f["length"], 'download': True }) else: self.__m_files.append({ "path": self.__m_name, "size": self.__m_metadata["info"]["length"], "download": True })
def _create_status_funcs(self): #if you add a key here->add it to core.py STATUS_KEYS too. self.status_funcs = { "active_time": lambda: self.status.active_time, "all_time_download": lambda: self.status.all_time_download, "compact": lambda: self.options["compact_allocation"], "distributed_copies": lambda: 0.0 if self.status.distributed_copies < 0 else \ self.status.distributed_copies, # Adjust status.distributed_copies to return a non-negative value "download_payload_rate": lambda: self.status.download_payload_rate, "file_priorities": lambda: self.options["file_priorities"], "hash": lambda: self.torrent_id, "is_auto_managed": lambda: self.options["auto_managed"], "is_finished": lambda: self.is_finished, "max_connections": lambda: self.options["max_connections"], "max_download_speed": lambda: self.options["max_download_speed"], "max_upload_slots": lambda: self.options["max_upload_slots"], "max_upload_speed": lambda: self.options["max_upload_speed"], "message": lambda: self.statusmsg, "move_on_completed_path": lambda: self.options["move_completed_path"], "move_on_completed": lambda: self.options["move_completed"], "move_completed_path": lambda: self.options["move_completed_path"], "move_completed": lambda: self.options["move_completed"], "next_announce": lambda: self.status.next_announce.seconds, "num_peers": lambda: self.status.num_peers - self.status.num_seeds, "num_seeds": lambda: self.status.num_seeds, "owner": lambda: self.owner, "paused": lambda: self.status.paused, "prioritize_first_last": lambda: self.options["prioritize_first_last_pieces"], "sequential_download": lambda: self.options["sequential_download"], "progress": lambda: self.status.progress * 100, "shared": lambda: self.options["shared"], "remove_at_ratio": lambda: self.options["remove_at_ratio"], "save_path": lambda: self.options["download_location"], "seeding_time": lambda: self.status.seeding_time, "seeds_peers_ratio": lambda: -1.0 if self.status.num_incomplete == 0 else \ self.status.num_complete / float(self.status.num_incomplete), # Use -1.0 to signify infinity "seed_rank": lambda: self.status.seed_rank, "state": lambda: self.state, "stop_at_ratio": lambda: self.options["stop_at_ratio"], "stop_ratio": lambda: self.options["stop_ratio"], "time_added": lambda: self.time_added, "total_done": lambda: self.status.total_done, "total_payload_download": lambda: self.status.total_payload_download, "total_payload_upload": lambda: self.status.total_payload_upload, "total_peers": lambda: self.status.num_incomplete, "total_seeds": lambda: self.status.num_complete, "total_uploaded": lambda: self.status.all_time_upload, "total_wanted": lambda: self.status.total_wanted, "tracker": lambda: self.status.current_tracker, "trackers": lambda: self.trackers, "tracker_status": lambda: self.tracker_status, "upload_payload_rate": lambda: self.status.upload_payload_rate, "comment": lambda: decode_string(self.torrent_info.comment()) if self.has_metadata else u"", "num_files": lambda: self.torrent_info.num_files() if self.has_metadata else 0, "num_pieces": lambda: self.torrent_info.num_pieces() if self.has_metadata else 0, "piece_length": lambda: self.torrent_info.piece_length() if self.has_metadata else 0, "private": lambda: self.torrent_info.priv() if self.has_metadata else False, "total_size": lambda: self.torrent_info.total_size() if self.has_metadata else 0, "eta": self.get_eta, "file_progress": self.get_file_progress, # Adjust progress to be 0-100 value "files": self.get_files, "is_seed": self.handle.is_seed, "peers": self.get_peers, "queue": self.handle.queue_position, "ratio": self.get_ratio, "tracker_host": self.get_tracker_host, "last_seen_complete": lambda: self.status.last_seen_complete, "name": self.get_name, "pieces": self._get_pieces_info, }
self.__m_info_hash = sha(bencode.bencode( self.__m_metadata["info"])).hexdigest() # Get encoding from torrent file if available self.encoding = None if "encoding" in self.__m_metadata: self.encoding = self.__m_metadata["encoding"] elif "codepage" in self.__m_metadata: self.encoding = str(self.__m_metadata["codepage"]) if not self.encoding: self.encoding = "UTF-8" # Check if 'name.utf-8' is in the torrent and if not try to decode the string # using the encoding found. if "name.utf-8" in self.__m_metadata["info"]: self.__m_name = decode_string( self.__m_metadata["info"]["name.utf-8"]) else: self.__m_name = decode_string(self.__m_metadata["info"]["name"], self.encoding) # Get list of files from torrent info paths = {} dirs = {} if "files" in self.__m_metadata["info"]: prefix = "" if len(self.__m_metadata["info"]["files"]) > 1: prefix = self.__m_name for index, f in enumerate(self.__m_metadata["info"]["files"]): if "path.utf-8" in f: path = os.path.join(prefix, *f["path.utf-8"])