def download(self, url=None, user_data=None, resume_data=None): atp = { "save_path": self.download_dir.encode("utf-8"), "storage_mode": lt.storage_mode_t.storage_mode_sparse, #lt.storage_mode_t.storage_mode_allocate, "paused": False, "auto_managed": True, "duplicate_is_error": False, "override_resume_data": True, # for manual pause handling } if resume_data: atp["save_path"] = resume_data.get("download_dir", old_download_dir).encode("utf-8") if "resume_data" in resume_data: atp["resume_data"] = resume_data["resume_data"] if "url" in resume_data: atp["url"] = resume_data["url"] if "torrent" in resume_data: atp["ti"] = lt.torrent_info(lt.bdecode(resume_data["torrent"])) if "paused" in resume_data: atp["paused"] = resume_data["paused"] atp["auto_managed"] = not resume_data["paused"] if resume_data.get("finished", False) or resume_data.get("hidden", False): atp["upload_mode"] = True atp["auto_managed"] = False # prevents libtorrent from change upload_mode atp["storage_mode"] = lt.storage_mode_t.storage_mode_sparse # otherwise libtorrent generates null files resume_data["hidden"] = True elif self.can_download(url): if not url.startswith("magnet:?"): if not check_if_torrent_url(url): return False for k, v in self._html_url_unescape.iteritems(): url = url.replace(k, v) atp["url"] = str(url) resume_data = {"url": url.encode("utf-8"), "user_data": user_data} else: if url.startswith("file://"): urlp = urlparse.urlparse(url).path path = os.path.join(urlp.netloc, urlp.path) else: path = url path = os.path.abspath(path) if os.path.isfile(path): f = open(path, "rb") data = f.read() f.close() try: atp["ti"] = lt.torrent_info(lt.bdecode(data)) except BaseException: return False resume_data = {"torrent": data, "user_data": user_data} if "url" in atp or "ti" in atp: # is atp valid? try: resume_data_id = str(atp["ti"].info_hash()) if "ti" in atp else atp["url"] self.tmp_resume_data[resume_data_id] = resume_data self.session.async_add_torrent(atp) return True except RuntimeError as e: # Torrent already in session logger.warn(e) return False
async def on_http_request(self, source_address, payload, circuit_id): if circuit_id not in self.exit_sockets: self.logger.warning("Received unexpected http-request") return if len([ cache for cache in self.request_cache._identifiers.values() if isinstance(cache, HTTPRequestCache) and cache.circuit_id == circuit_id ]) > 5: self.logger.warning( "Too many HTTP requests coming from circuit %s") return self.logger.debug("Got http-request from %s", source_address) target_address = decode_address(payload.target) writer = None try: with async_timeout.timeout(3): self.logger.debug("Opening TCP connection to %s", target_address) reader, writer = await open_connection(*target_address) writer.write(payload.request) response = b'' while True: line = await reader.readline() response += line if not line.strip(): # Read HTTP response body (1MB max) response += await reader.read(1024**2) break except OSError: self.logger.warning('Tunnel HTTP request failed') return except AsyncTimeoutError: self.logger.warning('Tunnel HTTP request timed out') return finally: if writer: writer.close() # Note that, depending on the libtorrent version, bdecode does not always raise # an exception, sometimes it returns None instead. try: response_decoded = lt.bdecode(response.split(b'\r\n\r\n')[1]) except (IndexError, RuntimeError): response_decoded = None if response_decoded is None: self.logger.warning('Tunnel HTTP request not allowed') return num_cells = math.ceil(len(response) / MAX_HTTP_PACKET_SIZE) for i in range(num_cells): self.send_cell( source_address, "http-response", HTTPResponsePayload( circuit_id, payload.identifier, i, num_cells, response[i * MAX_HTTP_PACKET_SIZE:(i + 1) * MAX_HTTP_PACKET_SIZE]))
def file_name(torrent_file): ## metainfo = bencode.bdecode(torrent_file.read()) metainfo = lt.bdecode(torrent_file.read()) info = metainfo[b'info'] if b'files' in info: raise BatchTorrentException('torrent contains multiple files') return info[b'name'].decode('utf8')
def addTorrent(self, save_path, path, entry): atp = {} atp["save_path"] = save_path atp["storage_mode"] = lt.storage_mode_t.storage_mode_sparse atp["paused"] = False atp["auto_managed"] = True atp["duplicate_is_error"] = True if path.startswith('magnet:') or path.startswith('http://') or path.startswith('https://'): atp["url"] = path else: e = lt.bdecode(open(path, 'rb').read()) info = lt.torrent_info(e) #print('Adding \'%s\'...' % info.name()) try: atp["resume_data"] = open(os.path.join(self.save_path, info.name() + '.fastresume'), 'rb').read() except: pass atp["ti"] = info h = self.ses.add_torrent(atp) self.handles[entry] = h
def downloadTorrent(self,torrentfile): """ Download the files the torrent is pointing at """ try: self.ses.listen_on(6881, 6891) e = lt.bdecode(open(torrentfile, 'rb').read()) info = lt.torrent_info(e) params = { 'save_path': self.TORRENT_DIR, \ 'storage_mode': lt.storage_mode_t.storage_mode_sparse, \ 'ti': info } h = self.ses.add_torrent(params) s = h.status() while (not s.is_seeding): s = h.status() state_str = ['queued', 'checking', 'downloading metadata', \ 'downloading', 'finished', 'seeding', 'allocating'] self.logger.info( '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \ (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \ s.num_peers, state_str[s.state])) time.sleep(10) self.logger.info( "[Complete 2/2] Torrent download Completed") self.ses.remove_torrent(h) os.remove(torrentfile) except Exception as e: self.logger.error(traceback.format_exc())
def open(self, path, flags): with self.rwlock: fn = self.hgdb+path if not (flags & (os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREAT | os.O_EXCL | os.O_TRUNC)): if path.startswith('/.__delugefs__'): return os.open(fn, flags) #print '\treadonly' t = get_torrent_dict(fn) if t: name = t['info']['name'] dat_fn = os.path.join(self.dat, name[:2], name) if not os.path.isfile(dat_fn): self.__add_torrent_and_wait(path, t) self.last_read_file[path] = datetime.datetime.now() return os.open(dat_fn, flags) else: return os.open(fn, flags) if path.startswith('/.__delugefs__'): return 0 tmp = uuid.uuid4().hex if os.path.isfile(fn): with open(fn, 'rb') as f: prev = lt.bdecode(f.read())['info']['name'] prev_fn = os.path.join(self.dat, prev[:2], prev) if os.path.isfile(prev_fn): shutil.copyfile(prev_fn, os.path.join(self.tmp, tmp)) self.open_files[path] = tmp return os.open(os.path.join(self.tmp, tmp), flags) return 0
def load_state(state_file, session): try: state = lt.bdecode(open(state_file).read()) print('SAVED STATE:\%s' % (pprint.pformat(state), )) session.load_state(state) except IOError, v: print('Unable to load saved state: %s' % (v, ))
def _init(self, data, magnet): self.magnet = magnet if data is not None: self._info = lt.torrent_info(lt.bdecode(data)) self.options['ti'] = self._info self.id = str(self._info.info_hash()) self._id_event.set() resume_data = self.load_resume_data() if resume_data: self.options["resume_data"] = resume_data self.handle = session.add_torrent(self.options) else: def _on_metadata_received_alert(alert): self._info = self.handle.get_torrent_info() self.options['ti'] = self.info self.unregister_alert('metadata_received_alert', _on_metadata_received_alert) self.register_alert('metadata_received_alert', _on_metadata_received_alert) self._info = None self.handle = session.add_magnet(magnet, self.options) self.id = str(self.handle.info_hash()) self._id_event.set() if self.id == '0000000000000000000000000000000000000000': self.remove() raise ValueError('error getting torrent id. torrent broken?') session.torrents[self.id] = self
def StartSession(self): self.params = { 'save_path': '.', 'storage_mode': lt.storage_mode_t(2), 'paused': True, 'auto_managed': True, 'duplicate_is_error': True } self.tmr_pauseTorrent = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.PauseTorrent, self.tmr_pauseTorrent) self.tmr_pauseTorrent.Start(milliseconds=100, oneShot=False) if os.path.exists(self.path): decodedTorrent = lt.bdecode(open(self.path, 'rb').read()) self.torrentInfo = lt.torrent_info(decodedTorrent) self.params.update({'ti': self.torrentInfo}) self.torrent = self.parent.ses.add_torrent(self.params) self.loaded = True self.ggb_metadata.Hide() self.lbl_metadata.Hide() self.GetTorrentData() else: self.torrent = lt.add_magnet_uri(self.parent.ses, self.path, self.params) self.ggb_metadata.Pulse() self.btn_ok.Disable() self.timeoutCounter = 0 self.tmr_metadata = wx.Timer(self, -1) self.Bind(wx.EVT_TIMER, self.GetMetadata, self.tmr_metadata) self.tmr_metadata.Start(milliseconds=100, oneShot=False)
def load_from_memory(bencoded_data): """ Load some bencoded data into a TorrentDef. :param bencoded_data: The bencoded data to decode and use as metainfo """ metainfo = bdecode(bencoded_data) return TorrentDef.load_from_dict(metainfo)
def open(self, path, flags): with self.rwlock: fn = self.hgdb + path if not (flags & (os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREAT | os.O_EXCL | os.O_TRUNC)): if path.startswith('/.__delugefs__'): return os.open(fn, flags) #print '\treadonly' t = get_torrent_dict(fn) if t: name = t['info']['name'] dat_fn = os.path.join(self.dat, name[:2], name) if not os.path.isfile(dat_fn): self.__add_torrent_and_wait(path, t) self.last_read_file[path] = datetime.datetime.now() return os.open(dat_fn, flags) else: return os.open(fn, flags) if path.startswith('/.__delugefs__'): return 0 tmp = uuid.uuid4().hex if os.path.isfile(fn): with open(fn, 'rb') as f: prev = lt.bdecode(f.read())['info']['name'] prev_fn = os.path.join(self.dat, prev[:2], prev) if os.path.isfile(prev_fn): shutil.copyfile(prev_fn, os.path.join(self.tmp, tmp)) self.open_files[path] = tmp return os.open(os.path.join(self.tmp, tmp), flags) return 0
def _scrape_cache(cache, hash): name = cache["name"] url = re.sub(r'\<info\_hash\>', hash.upper(), cache["pull_url"]) try: r = requests.get(url, headers={"User-agent": "BitTroll"}) if r.status_code == 200: data = lt.bdecode(r.content) info = lt.torrent_info(data) Metadata.logger.info("Metadata recieved from cache (%s)(%s)" % (name, hash)) try: Database.add(info) return True except Exception as e: Metadata.logger.critical( "Failed to add metadata to database (%s)(%s)" % (hash, e.__str__())) elif r.status_code == 404: Metadata.logger.debug("Metadata not found on cache (%s)(%s)" % (name, hash)) else: Metadata.logger.debug( "Error while getting torrent from cache (%s)(%s)(HTTP %s)(Response: %s)" % (name, hash, r.status_code, r.content)) except Exception as e: Metadata.logger.debug( "Failed to get metadata on cache (%s)(%s)(%s)" % (name, hash, e.__str__())) return False
def buildTorrentParams(self, uri): try: absPath = uri2path(uri) logging.info('Opening local torrent file: %s' % (encode_msg(absPath),)) torrent_info = lt.torrent_info(lt.bdecode(open(absPath, 'rb').read())) except Exception as e: strerror = e.args logging.error('Build torrent params error is (%s)' % (strerror,)) raise torrentParams = {} torrentParams['ti'] = torrent_info logging.info('Setting save path: %s' % (encode_msg(self.config.downloadPath),)) torrentParams['save_path'] = self.config.downloadPath if os.path.exists(self.config.resumeFile): logging.info('Loading resume file: %s' % (encode_msg(self.config.resumeFile),)) try: with open(self.config.resumeFile, 'rb') as f: torrentParams["auto_managed"] = True torrentParams['resume_data'] = f.read() except Exception as e: strerror = e.args logging.error(strerror) if self.config.noSparseFile or self.magnet: logging.info('Disabling sparse file support...') torrentParams["storage_mode"] = lt.storage_mode_t.storage_mode_allocate return torrentParams
def test_on_metadata_received_alert(self): """ Testing whether the right operations happen when we receive metadata """ test_deferred = Deferred() def mocked_checkpoint(): test_deferred.callback(None) mocked_file = MockObject() mocked_file.path = 'test' self.libtorrent_download_impl.handle.trackers = lambda: [] self.libtorrent_download_impl.handle.save_resume_data = lambda: None self.libtorrent_download_impl.handle.rename_file = lambda *_: None with open(os.path.join(TESTS_DATA_DIR, "bak_single.torrent"), mode='rb') as torrent_file: encoded_metainfo = torrent_file.read() decoded_metainfo = bdecode(encoded_metainfo) get_info_from_handle(self.libtorrent_download_impl.handle).metadata = lambda: bencode(decoded_metainfo['info']) get_info_from_handle(self.libtorrent_download_impl.handle).files = lambda: [mocked_file] self.libtorrent_download_impl.checkpoint = mocked_checkpoint self.libtorrent_download_impl.session = MockObject() self.libtorrent_download_impl.session.lm = MockObject() self.libtorrent_download_impl.session.lm.torrent_db = None self.libtorrent_download_impl.handle.save_path = lambda: None self.libtorrent_download_impl.handle.prioritize_files = lambda _: None self.libtorrent_download_impl.get_save_path = lambda: '' self.libtorrent_download_impl.get_share_mode = lambda: False self.libtorrent_download_impl.on_metadata_received_alert(None) return test_deferred
def populate_cache(url): RequestProxy.cache = True mkdir_p('./www/') start = time() params = urllib.urlencode({'url': url}) f = urllib.urlopen("http://%s" % RequestProxy.bit_server, params) torrent_data = base64.b64decode(f.read()) finish = time() print "Packaged in %.2f seconds" % (finish-start) e = lt.bdecode(torrent_data) info = lt.torrent_info(e) params = { 'save_path': './www/', 'ti': info } h = RequestProxy.ses.add_torrent(params) time_slept = 0 start = time() while not h.is_seed(): s = h.status() print '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, s.num_peers, s.state) sleep(1) time_slept += 1 if time_slept > 30: break finish = time() print "Downloaded in %.2f seconds" % (finish-start)
def load_from_memory(data): """ Loads a torrent file that is already in memory. :param data: The torrent file data. :return: A TorrentDef object. """ data = bdecode(data) return TorrentDef._create(data)
def init_session(args, seed=False): ses = lt.session() all_torrents = [] for save_path, magnet_or_path in args: if os.path.exists(magnet_or_path): e = lt.bdecode(open(magnet_or_path, "rb").read()) info = lt.torrent_info(e) params = { "save_path": save_path, "storage_mode": lt.storage_mode_t.storage_mode_sparse, "ti": info, "seed_mode": seed, } h = ses.add_torrent(params) else: h = ses.add_torrent( { "save_path": save_path, "storage_mode": lt.storage_mode_t.storage_mode_sparse, "url": magnet_or_path, "seed_mode": seed, } ) all_torrents.append(h) return ses, all_torrents
def summarize_torrent(torrent_file): print(torrent_file) with open(torrent_file, 'rb') as f: torrent = lt.bdecode(f.read()) info = torrent[b'info'] if b'name.utf-8' in info: torrent_name = info[b'name.utf-8'].decode() else: torrent_name = info[b'name'].decode() print(torrent_name) num_files = 1 size = 0 if b'length' in info: num_files = 1 size = info[b'length'] print(' {} - {}'.format(info[b'name'].decode(), human_readable_size(size))) else: num_files = 0 for f in info[b'files']: num_files += 1 size += f[b'length'] print(' {} - {}'.format(human_path(f[b'path']), human_readable_size(f[b'length']))) print()
def download(clientType): if clientType == "server": dest = "" else: dest = expanduser("~") + "\Downloads" ses = lt.session() ses.listen_on(6881, 6901) #keep trying to bind to a port till set value torrentContent = lt.bdecode(open("t.torrent", 'rb').read()) info = lt.torrent_info(torrentContent) if clientType == "server": h = ses.add_torrent({'ti': info, 'save_path': dest, 'seed_mode': True}) else: h = ses.add_torrent({'ti': info, 'save_path': dest}) while (not h.is_seed()): s = h.status() state_str = ['queued', 'checking', 'downloading metadata', \ 'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume'] #print '\r%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \ # (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \ # s.num_peers, state_str[s.state]), #sys.stdout.flush() if clientType != "server": progressSender(str(s.progress * 100)) time.sleep(1) if clientType != "server": print "Download completed" progressSender("Done") print "Seeding...\nCtrl+C to stop" while h.is_seed(): time.sleep(1) #keep process from getting garbage collected?
def setUp(self): # need to keep reference to session() to prevent GC picking it up self.session = session = libtorrent.session() session.listen_on(6881, 6882) torrent = libtorrent.bdecode(open(self.torrent, 'rb').read()) info = libtorrent.torrent_info(torrent) self.transfer = session.add_torrent(info, tempfile.gettempdir())
def __add_torrent(self, filename): self.l.log("TorrentAgent:adding torrent " + filename) if self.__check_dups(filename): self.l.log("TorrentAgent:skipping, already added " + filename) return torrent_data = None try: f = open(filename, 'rb') torrent_data = LT.bdecode(f.read()) f.close() except: self.l.log("TorrentAgent:error reading from " + filename, L.ERR) return try: info = LT.torrent_info(torrent_data) except: self.l.log("TorrentAgent:error adding torrent, corrupt file? " + filename, L.ERR) return resume_data = self.__get_resume_data(str(info.info_hash())) h = self.session.add_torrent(info, self.c["save_path"], resume_data=resume_data, storage_mode=self.c["storage_mode"]) self.__setup_handle(h) self.handle_by_name[filename] = (h, False)
def _setup(self): self.params = {} metainfo_file = open(self.metainfo_file_path, 'rb') metainfo = lt.bdecode(metainfo_file.read()) metainfo_file.close() self.torrent_info = lt.torrent_info(metainfo) self.torrent_info_hash = str(self.torrent_info.info_hash()) self.torrent_name = self.torrent_info.name() self.num_pieces = self.torrent_info.num_pieces() self.params['save_path'] = self.save_directory_path self.params['ti'] = self.torrent_info self.params['paused'] = True self.params['duplicate_is_error'] = True self.params['storage_mode'] = lt.storage_mode_t.storage_mode_allocate # torrent_handle must be set by instantiating class self.torrent_handle = None self.piece_completed_map = dict() self.piece_buffers = dict() self.is_transcoding = threading.Event() self._is_not_transcode_setting_up = threading.Event() self._is_not_transcode_setting_up.set() self.transcode_object = None self.transcode_writer = None self.completed_piece_buffers_loaded = False
def _on_torrent_created(result): """ Success callback :param result: from create_torrent_file """ metainfo_dict = bdecode(result['metainfo']) # Download this torrent if specified if 'download' in request.args and len(request.args['download']) > 0 \ and request.args['download'][0] == "1": download_config = DownloadStartupConfig() download_config.set_dest_dir(result['base_path'] if len( file_path_list) == 1 else result['base_dir']) try: self.session.lm.ltmgr.start_download( tdef=TorrentDef(metainfo=metainfo_dict), dconfig=download_config) except DuplicateDownloadException: self._logger.warning( "The created torrent is already being downloaded.") request.write( json.dumps({"torrent": base64.b64encode(result['metainfo'])})) # If the above request.write failed, the request will have already been finished if not request.finished: request.finish()
def add_torrent(self, session, params): info_hash = params['info_hash'] # convert params into torrent_info e = lt.bdecode(params['torrent_file']) torrent_info = lt.torrent_info(e) # sanity check: info_hash values must match if str(torrent_info.info_hash()) != info_hash: raise Exception('Error adding torrent (%s != %s)' % (torrent_info.info_hash(), info_hash)) # add torrent to session add_torrent_params = { 'ti': torrent_info, 'save_path': str(params['torrent_root']) # cast to regular string; the libtorrent c++ bindings don't like unicode } torrent = session._ses.add_torrent(add_torrent_params) if torrent: if self._torrents.has_key(info_hash): session._log.error('Cannot add duplicate torrent to session (%s)' % (info_hash)) else: self._torrents[info_hash] = torrent session._log.info('Added torrent to session for upload: %s (%s)' % (torrent.name(), info_hash)) else: session._log.error('Error adding torrent to libtorrent session')
def parse_torrent_file(torrent_file): # torrent_file >> torrent_dict >> lt_info >> torrent_info try: import libtorrent as lt except ImportError: raise ImportError('libtorrent package required') torrent_dict = lt.bdecode(torrent_file) lt_info = lt.torrent_info(torrent_dict) torrent_info = Logic.convert_torrent_info(lt_info) if b'announce-list' in torrent_dict: torrent_info.update({ 'trackers': [x.decode('utf-8') for x in torrent_dict[b'announce-list'][0]] }) torrent_info.update({ 'creation_date': datetime.fromtimestamp(torrent_dict[b'creation date']).isoformat() }) # caching for later use if Logic.torrent_cache is None: Logic.cache_init() Logic.torrent_cache[torrent_info['info_hash']] = { 'info': torrent_info, } return torrent_info
def on_metadata_received_alert(self, alert): torrent_info = get_info_from_handle(self.handle) if not torrent_info: return metadata = {'info': lt.bdecode(torrent_info.metadata())} trackers = [tracker['url'] for tracker in self.handle.trackers()] if trackers: if len(trackers) > 1: metadata["announce-list"] = [trackers] else: metadata["announce"] = trackers[0] try: self.tdef = TorrentDef.load_from_dict(metadata) except ValueError as ve: self._logger.exception(ve) return try: torrent_files = lt.torrent_info(metadata).files() except RuntimeError: self._logger.warning("Torrent contains no files!") torrent_files = [] self.orig_files = [torrent_file.path.decode('utf-8') for torrent_file in torrent_files] self.set_corrected_infoname() self.set_filepieceranges() self.set_selected_files() self.checkpoint()
def upload_torrent(session_id, save_path, file=None, magnet=None, url=None, autostart='1', storage_mode='sparse', memory_only=None): if not get_session(session_id): raise APIException('session.notfound') if [file, magnet, url].count(None) != 2: raise APIException('upload.target.selectone') session = get_session_raw(session_id) if file: e = libtorrent.bdecode(file.read()) info = libtorrent.torrent_info(e) elif magnet: info = libtorrent.torrent_info(magnet) else: raise APIException('upload.notsupported') save_path = os.path.normpath(os.path.join(ROOT_DIR, save_path)) if not save_path.startswith(ROOT_DIR): raise APIException('access denied') params = { 'save_path': save_path, 'storage_mode': libtorrent.storage_mode_t.storage_mode_sparse, 'ti': info } torrent_handle = session.add_torrent(params) return get_torrent_info(torrent_handle)
def download(model_name, checkpoint="current"): ses = lt.session() ses.listen_on(6881, 6891) e = lt.bdecode( open(model_name + "_" + checkpoint + ".torrent", 'rb').read()) info = lt.torrent_info(e) params = { 'save_path': '.', 'storage_mode': lt.storage_mode_t.storage_mode_sparse, 'ti': info } h = ses.add_torrent(params) s = h.status() while (not s.is_seeding): s = h.status() state_str = ['queued', 'checking', 'downloading metadata', \ 'downloading', 'finished', 'seeding', 'allocating'] msg = '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' print(msg % (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, s.num_peers, state_str[s.state])) time.sleep(1)
def get_torrent_info_hash(path): """get_torrent_info_hash(path) NOTE: Important. These OS functions can throw IOError or OSError. Make sure you catch these in the caller. """ if os.path.getsize(path) > MAX_TORRENT_SIZE: # file is too large, bailout. (see #12301) raise ValueError("%s is not a valid torrent" % path) f = open(path, "rb") try: import libtorrent data = f.read(MAX_TORRENT_SIZE) if not data or data[0] != "d": # File doesn't start with 'd', bailout (see #12301) raise ValueError("%s is not a valid torrent" % path) metainfo = libtorrent.bdecode(data) try: infohash = metainfo["info"] except StandardError: raise ValueError("%s is not a valid torrent" % path) infohash = sha(libtorrent.bencode(infohash)).digest() return infohash finally: f.close()
def got_metainfo(self, infohash, timeout=False): with self.metainfo_lock: if infohash in self.metainfo_requests: handle, callbacks = self.metainfo_requests.pop(infohash) if DEBUG: print >> sys.stderr, 'LibtorrentMgr: got_metainfo', infohash, handle, timeout if handle and callbacks and not timeout: metainfo = {"info": lt.bdecode(handle.get_torrent_info().metadata())} trackers = [tracker.url for tracker in handle.get_torrent_info().trackers()] peers = [peer.ip for peer in handle.get_peer_info()] if trackers: if len(trackers) > 1: metainfo["announce-list"] = [trackers] metainfo["announce"] = trackers[0] else: metainfo["nodes"] = [] if peers: metainfo["initial peers"] = peers self._add_cached_metainfo(infohash, metainfo) for callback in callbacks: self.trsession.uch.perform_usercallback(lambda cb=callback, mi=deepcopy(metainfo): cb(mi)) if DEBUG: print >> sys.stderr, 'LibtorrentMgr: got_metainfo result', metainfo if handle: self.ltsession.remove_torrent(handle, 1)
def _add_torrent(self, torrent, save_path, resume_data=None, paused=False, cookies=None): """ Add a torrent to the pool. @param torrent: str - the path to a .torrent file or a magnet link @param save_path: str - torrent save path @param resume_data: str - bencoded torrent resume data @return: object - torr_handle """ add_torrent_params = {'save_path': os.path.abspath(save_path), 'storage_mode': libtorrent.storage_mode_t.storage_mode_sparse, 'paused': paused} if resume_data is not None: add_torrent_params['resume_data'] = resume_data if isinstance(torrent, dict): add_torrent_params['ti'] = libtorrent.torrent_info(torrent) elif torrent[:7] == 'magnet:': add_torrent_params['url'] = str(torrent) # libtorrent doesn't like unicode objects here elif torrent[:7] in ('http://', 'https:/'): # Here external http/https client is used in case if libtorrent module is compiled without OpenSSL add_torrent_params['ti'] = libtorrent.torrent_info(libtorrent.bdecode(self.load_torrent(torrent, cookies))) else: try: add_torrent_params['ti'] = libtorrent.torrent_info(os.path.abspath(torrent)) except RuntimeError: raise TorrenterError('Invalid path to the .torrent file!') torr_handle = self._session.add_torrent(add_torrent_params) while not torr_handle.has_metadata(): # Wait until torrent metadata are populated time.sleep(0.1) torr_handle.auto_managed(False) self._torrents_pool[str(torr_handle.info_hash())] = torr_handle return torr_handle
def read_extend_metadata_reject(self, conn, piece): while True: response = conn.recv() assert len(response) > 0 if response[0] == EXTEND: break assert response[0] == EXTEND assert ord(response[1]) == 3 payload = bdecode(response[2:]) length = len(bencode(payload)) assert payload["msg_type"] in (1, 2), [payload, response[2:2 + length]] assert payload["piece"] == piece, [payload, response[2:2 + length]] # some clients return msg_type 1, unfortunately this is not a reject but a proper response. # instead libtorrent warns: max outstanding piece requests reached if payload["msg_type"] == 1: assert response[2 + length:] == self.metadata_list[piece] # some clients return msg_type 2, we must make sure no "data" is given (i.e. the request was # rejected) if payload["msg_type"] == 2: assert payload["piece"] == piece, [payload, response[2:2 + length]] assert not "data" in payload, [payload, response[2:2 + length]]
async def get_torrent_handle(log, torrent): th = None wait_metatada_timeout = 60 if isinstance(torrent, str): if torrent.startswith('magnet'): log.info('Downloading metadata...') th = lt.add_magnet_uri(session, torrent, {'save_path': './'}) time_elasped = 0 while (not th.has_metadata()): await asyncio.sleep(3) time_elasped += 3 log.debug('Wait metadata, time elapsed = {}s'.format( str(time_elasped))) if time_elasped >= wait_metatada_timeout: session.remove_torrent(th) log.info('Magnet link resolve timeout') raise NoMetadataError log.info('Got metadata, starting torrent download...') else: raise Exception('String not a magnet link') elif isinstance(torrent, bytes): bd = lt.bdecode(torrent) info = lt.torrent_info(bd) th = session.add_torrent({'ti': info, 'save_path': '.'}) else: log.error('Torrent handler creating failed, not valid torrent: ', torrent) raise Exception("Not valid torrent") th.calc_prioritized_piece_count() th.prepare_pieces_priority() return th
def add_torrent(self, file, relative_path): _logger.info(f'Add torrent: {file}') directory = self.get_directory(relative_path) decoded_torrent = libtorrent.bdecode(file.read_bytes()) directory.add_torrent_to_channel(TorrentDef(metainfo=decoded_torrent), None)
def downloadTorrent (torrent ): torrent="test.torrent" ses = lt.session() ses.listen_on(TORRENT_PORT1, TORRENT_PORT2) e = lt.bdecode(open(torrent, 'rb').read()) info = lt.torrent_info(e) params = { "save_path": '.', \ "storage_mode": lt.storage_mode_t.storage_mode_sparse, \ "ti": info } h = ses.add_torrent(params) s = h.status() while (not s.is_seeding): s = h.status() state_str = ['queued', 'checking', 'downloading metadata', \ 'downloading', 'finished', 'seeding', 'allocating'] print( '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \ (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \ s.num_peers, state_str[s.state])) time.sleep(1)
def actionAddTorrent(self, to, torrentIdentifier): save_path = './data/' + self.site.address + '/downloads/' try: e = libtorrent.bdecode(base64.b64decode(torrentIdentifier)) info = libtorrent.torrent_info(e) params = { 'save_path': save_path, \ 'storage_mode': libtorrent.storage_mode_t.storage_mode_sparse, \ 'ti': info } except Exception as exception: try: # Test if a magnet params = libtorrent.parse_magnet_uri(torrentIdentifier) params['save_path'] = save_path # HACK: # Doesn't recognise sha1_hash python object when addded to session if not converted to string # 'No registered converter was able to produce a C++ rvalue of type bytes from this Python object of type sha1_hash' params['info_hash'] = params['info_hash'].to_string() except: params = { 'save_path': save_path, \ 'storage_mode': libtorrent.storage_mode_t.storage_mode_sparse, \ 'info_hash': torrentIdentifier.decode('hex') } try: h = self.session.add_torrent(params) except Exception as exception: self.response(to, {'error': str(exception)}) else: info_hash = h.info_hash() self.response(to, {'info_hash': str(info_hash)})
def show_torrent_file(torrent_file): print torrent_file e = lt.bdecode(open(torrent_file, 'rb').read()) torrent_file = lt.torrent_info(e) name = torrent_file.name() files = torrent_file.files() show_content = [] if os.name == 'nt': try: name = name.decode('utf-8').encode('gbk') except Exception as err: name = 'unknown' for file_item in files: try: file_item.path = \ file_item.path.decode('utf-8').encode('gbk') except Exception as err: pass show_content.append(' idx: name %s\n' % name) for file_item in files: if (file_item.size / (1024*1024.0)) > 50: show_content.append(' files(%.3f MB): %s\n' % (file_item.size/(1024*1024.0), file_item.path)) show_content.append('-' * 70) show_content.append('\n') print '\n'.join(show_content)
def _download_from_torrent(self, torrent_id, binary_file, destination_path): e = lt.bdecode(binary_file) params = {'save_path': destination_path, 'storage_mode': lt.storage_mode_t.storage_mode_sparse, 'ti': lt.torrent_info(e)} torrent_handler = self._session.add_torrent(params) self._torrent_handlers[torrent_id] = torrent_handler
def got_metainfo(self): # FIXME: If the client is stopped before a BT download gets # its metadata, we never run this. It's not a huge deal # because it only affects the incomplete filename if not self.restarting: try: metainfo = lt.bdecode(self.metainfo) # if we don't get valid torrent metadata back, then the # metainfo is None. treat that like a runtime error. if not metainfo: raise RuntimeError() name = metainfo['info']['name'] # Note: handle KeyError as well because bdecode() may return # an object with no 'info' key, or with 'info' key but no 'name' # key. This allows us to catch lousily made torrent files. except (KeyError, RuntimeError): self.handle_corrupt_torrent() return self.shortFilename = utf8_to_filename(name) try: self.pick_initial_filename(suffix="", torrent=True) # Somewhere deep it calls makedirs() which can throw exceptions. # # Not sure if this is correct but if we throw a runtime error # like above it can't hurt anyone. except (OSError, IOError): raise RuntimeError self.update_client() self._resume_torrent()
def get_torrent_info_hash(path): """get_torrent_info_hash(path) NOTE: Important. These OS functions can throw IOError or OSError. Make sure you catch these in the caller. """ if os.path.getsize(path) > MAX_TORRENT_SIZE: # file is too large, bailout. (see #12301) raise ValueError("%s is not a valid torrent" % path) f = open(path, 'rb') try: import libtorrent data = f.read(MAX_TORRENT_SIZE) if not data or data[0] != 'd': # File doesn't start with 'd', bailout (see #12301) raise ValueError("%s is not a valid torrent" % path) metainfo = libtorrent.bdecode(data) try: infohash = metainfo['info'] except StandardError: raise ValueError("%s is not a valid torrent" % path) infohash = sha(libtorrent.bencode(infohash)).digest() return infohash finally: f.close()
def start(self, torrent_file, port=6881): if not os.path.isdir('log'): os.mkdir('log') self.ses = lt.session() self.ses.set_alert_mask(lt.alert.category_t.status_notification | 0x400) # lt.alert.category_t.dht_notification self.ses.listen_on(port, port) self.ses.start_dht() self.ses.add_dht_router("router.bittorrent.com", 6881) self.ses.add_dht_router("router.utorrent.com", 6881) self.ses.add_dht_router("router.bitcomet.com", 6881) e = lt.bdecode(open(torrent_file, 'rb').read()) info = lt.torrent_info(e) # info = lt.torrent_info(torrent_file) h = self.ses.add_torrent({'ti': info, 'save_path': './'}) while not h.is_seed(): alert = self.ses.pop_alert() while alert is not None: self.handle_alert(alert) alert = self.ses.pop_alert() time.sleep(0.1) self.ses.remove_torrent(h) while True: alert = self.ses.pop_alert() while alert is not None: self.handle_alert(alert) alert = self.ses.pop_alert() time.sleep(0.1)
def make_torrent(self, tracker_url, torrent_name, dir_name): mkdir_p('torrent_files') fs = lt.file_storage() lt.add_files(fs, dir_name) t = lt.create_torrent(fs) t.add_tracker(tracker_url) lt.set_piece_hashes(t, './torrent_data') f = open(torrent_name, "wb") f.write(lt.bencode(t.generate())) f.close() e = lt.bdecode(open(torrent_name, 'rb').read()) info = lt.torrent_info(e) params = { 'save_path': './torrent_data', 'ti': info, 'seed_mode': True } h = self.ses.add_torrent(params) # Wait a bit for the tracker sleep(5)
def buildTorrentParams(self, uri): try: absPath = uri2path(uri) logging.info('Opening local torrent file: %s' % (encode_msg(absPath), )) torrent_info = lt.torrent_info( lt.bdecode(open(absPath, 'rb').read())) except Exception as e: strerror = e.args logging.error('Build torrent params error is (%s)' % (strerror, )) raise torrentParams = {} torrentParams['ti'] = torrent_info logging.info('Setting save path: %s' % (encode_msg(self.config.downloadPath), )) torrentParams['save_path'] = self.config.downloadPath if os.path.exists(self.config.resumeFile): logging.info('Loading resume file: %s' % (encode_msg(self.config.resumeFile), )) try: with open(self.config.resumeFile, 'rb') as f: torrentParams["auto_managed"] = True torrentParams['resume_data'] = f.read() except Exception as e: strerror = e.args logging.error(strerror) if self.config.noSparseFile or self.magnet: logging.info('Disabling sparse file support...') torrentParams[ "storage_mode"] = lt.storage_mode_t.storage_mode_allocate return torrentParams
def get_torrent_info_from_bytestring(bencoded): """Get torrent metadata from a bencoded string and return info structure.""" torrent_metadata = libtorrent.bdecode(bencoded) torrent_info = libtorrent.torrent_info(torrent_metadata) return torrent_info
def start_real(self): if self.is_finished() and self.seed_requirement_met(): # Restarting a finished torrent, don't autostop immediately self.autostop = False self.download.status = Status.STARTING self.download.status_message = None if not 'state_changed_alert' in self.dfm: self.dfm['state_changed_alert'] = defer.Deferred() if not self.torrent_info: self.torrent_info = lt.torrent_info(lt.bdecode(self.download.metadata)) self.download.description = unicode(self.torrent_info.name()) try: if not self.torrent: resdata = None if self.download.resume_data: resdata = marshal.loads(self.download.resume_data) self.torrent = lt_manager.add_torrent(self, self.torrent_info, self.directory, resume_data=resdata) self.torrent.auto_managed(True) self.rebind() except Exception as e: dfr = self.dfm['state_changed_alert'] del self.dfm['state_changed_alert'] if self.torrent: self.torrent.auto_managed(False) self.torrent.pause() self.torrent.save_resume_data() dfr.errback(failure.Failure(e)) return dfr self.torrent.resume() return self.dfm['state_changed_alert']
def load_session(configuration, session): logger.info('Loading session.') filepath = configuration['session_directory']+'/session' with open(filepath, "rb") as _file: session_state = libtorrent.bdecode(_file.read()) session.load_state(session_state) logger.info('Session loaded')
def main(torrent_path, seed_cache_path, torrent_seed_duration, torrent_listen_port_start, torrent_listen_port_end): seed_time = time.time() + torrent_seed_duration logging.debug("Seeding '%s' for %d secs" % (torrent_path, torrent_seed_duration)) child = _daemonize() if not child: return # At this point we're the daemonized child... session = libtorrent.session() session.listen_on(torrent_listen_port_start, torrent_listen_port_end) torrent_file = open(torrent_path, 'rb') try: torrent_data = torrent_file.read() finally: torrent_file.close() decoded_data = libtorrent.bdecode(torrent_data) info = libtorrent.torrent_info(decoded_data) torrent = session.add_torrent( info, seed_cache_path, storage_mode=libtorrent.storage_mode_t.storage_mode_sparse) try: while time.time() < seed_time: time.sleep(5) finally: session.remove_torrent(torrent) logging.debug("Seeding of '%s' finished" % torrent_path)
def downloadTorrent(torrent): torrent = "test.torrent" ses = lt.session() ses.listen_on(TORRENT_PORT1, TORRENT_PORT2) e = lt.bdecode(open(torrent, 'rb').read()) info = lt.torrent_info(e) params = { "save_path": '.', \ "storage_mode": lt.storage_mode_t.storage_mode_sparse, \ "ti": info } h = ses.add_torrent(params) s = h.status() while (not s.is_seeding): s = h.status() state_str = ['queued', 'checking', 'downloading metadata', \ 'downloading', 'finished', 'seeding', 'allocating'] print( '%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \ (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \ s.num_peers, state_str[s.state])) time.sleep(1)
def run(self): session = lt.session() session.listen_on(6881, 6891) print(self.rutaTorrent) e = lt.bdecode(open("../" + self.rutaTorrent, 'rb').read()) info = lt.torrent_info(e) h = session.add_torrent({'ti': info, 'save_path': '.'}) print('starting', h.name()) state_str = ['queued', 'checking', 'downloading metadata', \ 'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume'] time.sleep(1) s = h.status() infoDescarga = DTOdescarga(h.name(), "%.2f" % (s.progress * 100) + " %", "0.0", "0.0", "0", "cargando", True) # while (not h.is_seed() and self.parar==False): while (self.parar == False): s = h.status() print('\r%.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d) %s' % \ (s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \ s.num_peers, state_str[s.state]), end=' ') sys.stdout.flush() infoDescarga.setPorcentaje("%.2f" % (s.progress * 100) + " %") infoDescarga.setVelDescarga("%.2f" % (s.download_rate / 1000) + " Kb/s") infoDescarga.setVelSubida("%.2f" % (s.upload_rate / 1000) + " Kb/s") infoDescarga.setPeers(s.num_peers) if (s.progress >= 1.0): infoDescarga.setEstado("Completado") else: infoDescarga.setEstado("Descargando") wx.PostEvent(self._ventana, ResultEvent(self.indice, infoDescarga)) time.sleep(1) if not self.salir: infoDescarga.setPorcentaje("%.2f" % (s.progress * 100) + " %") infoDescarga.setVelDescarga("-") infoDescarga.setVelSubida("-") infoDescarga.setPeers("-") infoDescarga.setActivo(False) infoDescarga.setEstado("Detenido") wx.PostEvent(self._ventana, ResultEvent(self.indice, infoDescarga)) print("\n") print(h.name(), 'hilo detenido')
def could_be_dht(data): try: decoded = bdecode(data) if isinstance(decoded, dict) and decoded.get('y') in ['q', 'r', 'e']: return True except: pass return False
def magnet(t): """give magnet from torrent t""" with open(t, 'rb') as tf: metadata = lt.bdecode(tf.read()) hashcontents = lt.bencode(metadata[b'info']) digest = hashlib.sha1(hashcontents).digest() b32hash = base64.b32encode(digest) return(b32hash)
def _read(stream): """ Internal class method that reads a torrent file from stream, checks it for correctness and sets self.input and self.metainfo accordingly. """ bdata = stream.read() stream.close() data = bdecode(bdata) return TorrentDef._create(data)
def _process_scrape_response(self, body): """ This function handles the response body of a HTTP tracker, parsing the results. """ # parse the retrieved results if body is None: self.failed(msg="no response body") return response_dict = bdecode(body) if response_dict is None: self.failed(msg="no valid response") return response_list = [] unprocessed_infohash_list = self._infohash_list[:] if 'files' in response_dict and isinstance(response_dict['files'], dict): for infohash in response_dict['files']: complete = response_dict['files'][infohash].get('complete', 0) incomplete = response_dict['files'][infohash].get( 'incomplete', 0) # Sow complete as seeders. "complete: number of peers with the entire file, i.e. seeders (integer)" # - https://wiki.theory.org/BitTorrentSpecification#Tracker_.27scrape.27_Convention seeders = complete leechers = incomplete # Store the information in the dictionary response_list.append({ 'infohash': infohash.encode('hex'), 'seeders': seeders, 'leechers': leechers }) # remove this infohash in the infohash list of this session if infohash in unprocessed_infohash_list: unprocessed_infohash_list.remove(infohash) elif 'failure reason' in response_dict: self._logger.info(u"%s Failure as reported by tracker [%s]", self, repr(response_dict['failure reason'])) self.failed(msg=repr(response_dict['failure reason'])) return # handle the infohashes with no result (seeders/leechers = 0/0) for infohash in unprocessed_infohash_list: response_list.append({ 'infohash': infohash.encode('hex'), 'seeders': 0, 'leechers': 0 }) self._is_finished = True if self.result_deferred and not self.result_deferred.called: self.result_deferred.callback({self.tracker_url: response_list})
def got_metainfo(self, infohash, timeout=False): with self.metainfo_lock: infohash_bin = binascii.unhexlify(infohash) if infohash in self.metainfo_requests: request_dict = self.metainfo_requests.pop(infohash) handle = request_dict['handle'] callbacks = request_dict['callbacks'] timeout_callbacks = request_dict['timeout_callbacks'] notify = request_dict['notify'] self._logger.debug('got_metainfo %s %s %s', infohash, handle, timeout) assert handle if handle: if callbacks and not timeout: metainfo = {"info": lt.bdecode(get_info_from_handle(handle).metadata())} trackers = [tracker.url for tracker in get_info_from_handle(handle).trackers()] peers = [] leechers = 0 seeders = 0 for peer in handle.get_peer_info(): peers.append(peer.ip) if peer.progress == 1: seeders += 1 else: leechers += 1 if trackers: if len(trackers) > 1: metainfo["announce-list"] = [trackers] metainfo["announce"] = trackers[0] else: metainfo["nodes"] = [] if peers and notify: self.notifier.notify(NTFY_TORRENTS, NTFY_MAGNET_GOT_PEERS, infohash_bin, len(peers)) metainfo["initial peers"] = peers metainfo["leechers"] = leechers metainfo["seeders"] = seeders self._add_cached_metainfo(infohash, metainfo) for callback in callbacks: callback(deepcopy(metainfo)) # let's not print the hashes of the pieces debuginfo = deepcopy(metainfo) del debuginfo['info']['pieces'] self._logger.debug('got_metainfo result %s', debuginfo) elif timeout_callbacks and timeout: for callback in timeout_callbacks: callback(infohash_bin) if handle: self.get_session().remove_torrent(handle, 1) if notify: self.notifier.notify(NTFY_TORRENTS, NTFY_MAGNET_CLOSE, infohash_bin)