def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: ltsession = self.get_session(atp.pop('hops', 0)) if 'ti' in atp: infohash = str(atp['ti'].info_hash()) elif 'url' in atp: infohash = binascii.hexlify(parse_magnetlink(atp['url'])[1]) else: raise ValueError('No ti or url key in add_torrent_params') # Check if we added this torrent before known = [str(h.info_hash()) for h in ltsession.get_torrents()] if infohash in known: self.torrents[infohash] = (torrentdl, ltsession) infohash_bin = binascii.unhexlify(infohash) return succeed(ltsession.find_torrent(lt.big_number(infohash_bin))) if infohash in self.torrents: self._logger.info("Torrent already exists in the downloads. Infohash:%s", infohash.encode('hex')) # Otherwise, add it anew ltsession.async_add_torrent(encode_atp(atp)) self.torrents[infohash] = (torrentdl, ltsession) self._logger.debug("Adding torrent %s", infohash) return torrentdl.deferred_added
def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: ltsession = self.get_session(atp.pop('hops', 0)) if 'ti' in atp: infohash = str(atp['ti'].info_hash()) elif 'url' in atp: infohash = binascii.hexlify(parse_magnetlink(atp['url'])[1]) else: raise ValueError('No ti or url key in add_torrent_params') if infohash in self.metainfo_requests: self._logger.info("killing get_metainfo request for %s", infohash) handle = self.metainfo_requests.pop(infohash)['handle'] if handle: ltsession.remove_torrent(handle, 0) handle = ltsession.add_torrent(encode_atp(atp)) infohash = str(handle.info_hash()) if infohash in self.torrents: raise DuplicateDownloadException() self.torrents[infohash] = (torrentdl, ltsession) self._logger.debug("added torrent %s", infohash) return handle
def startDownloadFromMagnet(self, url, destdir=None, cmdline=False, selectedFiles=None, vodmode=False, hops=0): name, infohash, _ = parse_magnetlink(url) if name is None: name = "" try: if infohash is None: raise RuntimeError("Missing infohash") tdef = TorrentDefNoMetainfo(infohash, name, url=url) wx.CallAfter(self.startDownload, tdef=tdef, cmdline=cmdline, destdir=destdir, selectedFiles=selectedFiles, vodmode=vodmode, hops=0) except Exception, e: # show an error dialog dlg = wx.MessageBox(self, "The magnet link is invalid: %s" % str(e), "The magnet link is invalid", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy()
def test_parse_magnetlink_lowercase(self): """ Test if a lowercase magnet link can be parsed """ _, hashed, _ = parse_magnetlink('magnet:?xt=urn:btih:apctqfwnowubxzoidazgaj2ba6fs6juc') self.assertEqual(hashed, "\x03\xc58\x16\xcdu\xa8\x1b\xe5\xc8\x182`'A\x07\x8b/&\x82")
def test_parse_magnetlink_uppercase(self): """ Test if a lowercase magnet link can be parsed """ _, hashed, _ = parse_magnetlink('magnet:?xt=urn:btih:APCTQFWNOWUBXZOIDAZGAJ2BA6FS6JUC') self.assertEqual(hashed, "\x03\xc58\x16\xcdu\xa8\x1b\xe5\xc8\x182`'A\x07\x8b/&\x82")
def test_parse_magnetlink_uppercase(self): """ Test if a lowercase magnet link can be parsed """ _, hashed, _ = parse_magnetlink('magnet:?xt=urn:btih:APCTQFWNOWUBXZOIDAZGAJ2BA6FS6JUC') self.assertEqual(hashed, "\x03\xc58\x16\xcdu\xa8\x1b\xe5\xc8\x182`'A\x07\x8b/&\x82")
def test_parse_magnetlink_lowercase(self): """ Test if a lowercase magnet link can be parsed """ _, hashed, _ = parse_magnetlink('magnet:?xt=urn:btih:apctqfwnowubxzoidazgaj2ba6fs6juc') self.assertEqual(hashed, "\x03\xc58\x16\xcdu\xa8\x1b\xe5\xc8\x182`'A\x07\x8b/&\x82")
def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: ltsession = self.get_session(atp.pop('hops', 0)) if 'ti' in atp: infohash = str(atp['ti'].info_hash()) elif 'url' in atp: infohash = binascii.hexlify(parse_magnetlink(atp['url'])[1]) else: raise ValueError('No ti or url key in add_torrent_params') if infohash in self.metainfo_requests: self._logger.info("killing get_metainfo request for %s", infohash) request_handle = self.metainfo_requests.pop(infohash)['handle'] if request_handle: ltsession.remove_torrent(request_handle, 0) torrent_handle = ltsession.add_torrent(encode_atp(atp)) infohash = str(torrent_handle.info_hash()) if infohash in self.torrents: raise DuplicateDownloadException("This download already exists.") self.torrents[infohash] = (torrentdl, ltsession) self._logger.debug("added torrent %s", infohash) return torrent_handle
def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: ltsession = self.get_session(atp.pop('hops', 0)) if 'ti' in atp: infohash = str(atp['ti'].info_hash()) elif 'url' in atp: infohash = binascii.hexlify(parse_magnetlink(atp['url'])[1]) else: raise ValueError('No ti or url key in add_torrent_params') # Check if we added this torrent before known = [str(h.info_hash()) for h in ltsession.get_torrents()] if infohash in known: self.torrents[infohash] = (torrentdl, ltsession) infohash_bin = binascii.unhexlify(infohash) return ltsession.find_torrent(lt.big_number(infohash_bin)) # Otherwise, add it anew torrent_handle = ltsession.add_torrent(encode_atp(atp)) infohash = str(torrent_handle.info_hash()) if infohash in self.torrents: raise DuplicateDownloadException( "This download already exists.") self.torrents[infohash] = (torrentdl, ltsession) self._logger.debug("added torrent %s", infohash) return torrent_handle
def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: ltsession = self.get_session(atp.pop('hops', 0)) if 'ti' in atp: infohash = str(atp['ti'].info_hash()) elif 'url' in atp: infohash = hexlify(parse_magnetlink(atp['url'])[1]) else: raise ValueError('No ti or url key in add_torrent_params') # Check if we added this torrent before known = {str(h.info_hash()): h for h in ltsession.get_torrents()} existing_handle = known.get(infohash) if existing_handle: self.torrents[infohash] = (torrentdl, ltsession) return succeed(existing_handle) if infohash in self.torrents: self._logger.info("Torrent already exists in the downloads. Infohash:%s", hexlify(infohash)) # Otherwise, add it anew ltsession.async_add_torrent(encode_atp(atp)) self.torrents[infohash] = (torrentdl, ltsession) self._logger.debug("Adding torrent %s", infohash) return torrentdl.deferred_added
def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: if atp.has_key('ti'): infohash = str(atp['ti'].info_hash()) elif atp.has_key('url'): infohash = binascii.hexlify(parse_magnetlink(atp['url'])[1]) else: infohash = str(atp["info_hash"]) if infohash in self.metainfo_requests: print >> sys.stderr, "LibtorrentMgr: killing get_metainfo request for", infohash handle, _ = self.metainfo_requests.pop(infohash) if handle: self.ltsession.remove_torrent(handle, 0) handle = self.ltsession.add_torrent(atp) infohash = str(handle.info_hash()) with self.torlock: if infohash in self.torrents: raise DuplicateDownloadException() self.torrents[infohash] = torrentdl if DEBUG: print >> sys.stderr, "LibtorrentMgr: added torrent", infohash return handle
def add_torrent(self, torrentdl, atp): # If we are collecting the torrent for this infohash, abort this first. with self.metainfo_lock: if atp.has_key('ti'): infohash = str(atp['ti'].info_hash()) elif atp.has_key('url'): infohash = binascii.hexlify(parse_magnetlink(atp['url'])[1]) else: infohash = str(atp["info_hash"]) if infohash in self.metainfo_requests: print >> sys.stderr, "LibtorrentMgr: killing get_metainfo request for", infohash handle, _ = self.metainfo_requests.pop(infohash) if handle: self.ltsession.remove_torrent(handle, 0) handle = self.ltsession.add_torrent(atp) infohash = str(handle.info_hash()) with self.torlock: if infohash in self.torrents: raise DuplicateDownloadException() self.torrents[infohash] = torrentdl if DEBUG: print >> sys.stderr, "LibtorrentMgr: added torrent", infohash return handle
def get_metainfo(self, infohash_or_magnet, callback, timeout=30, timeout_callback=None, notify=True): magnet = infohash_or_magnet if infohash_or_magnet.startswith('magnet') else None infohash_bin = infohash_or_magnet if not magnet else parse_magnetlink(magnet)[1] infohash = hexlify(infohash_bin) if infohash in self.torrents: return with self.metainfo_lock: self._logger.debug('get_metainfo %s %s %s', infohash_or_magnet, callback, timeout) cache_result = self._get_cached_metainfo(infohash) if cache_result: callback(deepcopy(cache_result)) elif infohash not in self.metainfo_requests: # Flags = 4 (upload mode), should prevent libtorrent from creating files atp = {'save_path': self.metadata_tmpdir, 'flags': (lt.add_torrent_params_flags_t.flag_upload_mode)} if magnet: atp['url'] = magnet else: atp['info_hash'] = lt.sha1_hash(infohash_bin) try: handle = self.ltsession_metainfo.add_torrent(encode_atp(atp)) except TypeError as e: self._logger.warning("Failed to add torrent with infohash %s, " "attempting to use it as it is and hoping for the best", hexlify(infohash_bin)) self._logger.warning("Error was: %s", e) atp['info_hash'] = infohash_bin handle = self.ltsession_metainfo.add_torrent(encode_atp(atp)) if notify: self.notifier.notify(NTFY_TORRENTS, NTFY_MAGNET_STARTED, infohash_bin) self.metainfo_requests[infohash] = {'handle': handle, 'callbacks': [callback], 'timeout_callbacks': [timeout_callback] if timeout_callback else [], 'notify': notify} # if the handle is valid and already has metadata which is the case when torrent already exists in # session then metadata_received_alert is not fired so we call self.got_metainfo() directly here if handle.is_valid() and handle.has_metadata(): self.got_metainfo(infohash, timeout=False) return def schedule_call(): self.register_anonymous_task("schedule_got_metainfo_lookup", reactor.callLater(timeout, lambda: self.got_metainfo(infohash, timeout=True))) reactor.callFromThread(schedule_call) else: self.metainfo_requests[infohash]['notify'] = self.metainfo_requests[infohash]['notify'] and notify callbacks = self.metainfo_requests[infohash]['callbacks'] if callback not in callbacks: callbacks.append(callback) else: self._logger.debug('get_metainfo duplicate detected, ignoring')
def _on_loaded(response): if response.startswith('magnet'): _, infohash, _ = parse_magnetlink(response) if infohash: self.session.lm.ltmgr.get_metainfo(response, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) return metainfo_deferred.callback(bdecode(response))
def start_download_from_magnet(self, url, dconfig=None): name, infohash, _ = parse_magnetlink(url) if name is None: name = "Unknown name" if infohash is None: raise RuntimeError("Missing infohash") tdef = TorrentDefNoMetainfo(infohash, name, url=url) return self.start_download(tdef=tdef, dconfig=dconfig)
def start_download_from_magnet(self, url, dconfig=None): name, infohash, _ = parse_magnetlink(url) if name is None: name = "Unknown name" if infohash is None: raise RuntimeError("Missing infohash") tdef = TorrentDefNoMetainfo(infohash, name, url=url) return self.start_download(tdef=tdef, dconfig=dconfig)
def test_parse_magnetlink_valid(self): result = parse_magnetlink( "magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1&xl=10826029&dn=mediawiki-1.15.1.tar.gz&xt=urn:tree:tiger:7N5OAMRNGMSSEUE3ORHOKWN4WWIQ5X4EBOOTLJY&xt=urn:btih:QHQXPYWMACKDWKP47RRVIV7VOURXFE5Q&tr=http%3A%2F%2Ftracker.example.org%2Fannounce.php%3Fuk%3D1111111111%26&as=http%3A%2F%2Fdownload.wikimedia.org%2Fmediawiki%2F1.15%2Fmediawiki-1.15.1.tar.gz&xs=http%3A%2F%2Fcache.example.org%2FXRX2PEFXOOEJFRVUCX6HMZMKS5TWG4K5&xs=dchub://example.org" ) self.assertEqual( result, (u'mediawiki-1.15.1.tar.gz', '\x81\xe1w\xe2\xcc\x00\x94;)\xfc\xfccTW\xf5u#r\x93\xb0', ['http://tracker.example.org/announce.php?uk=1111111111&']))
def test_parse_magnetlink_valid(self): result = parse_magnetlink("magnet:?xt=urn:ed2k:354B15E68FB8F36D7CD88FF94116CDC1&xl=10826029&dn=mediawiki-1.15.1" ".tar.gz&xt=urn:tree:tiger:7N5OAMRNGMSSEUE3ORHOKWN4WWIQ5X4EBOOTLJY&xt=urn:btih:QHQXPY" "WMACKDWKP47RRVIV7VOURXFE5Q&tr=http%3A%2F%2Ftracker.example.org%2Fannounce.php%3Fuk" "%3D1111111111%26&as=http%3A%2F%2Fdownload.wikimedia.org%2Fmediawiki%2F1.15%2Fmediawi" "ki-1.15.1.tar.gz&xs=http%3A%2F%2Fcache.example.org%2FXRX2PEFXOOEJFRVUCX6HMZMKS5TWG4K" "5&xs=dchub://example.org") self.assertEqual(result, (u'mediawiki-1.15.1.tar.gz', '\x81\xe1w\xe2\xcc\x00\x94;)\xfc\xfccTW\xf5u#r\x93\xb0', ['http://tracker.example.org/announce.php?uk=1111111111&']))
def on_magnet(mlink=None): infohash = parse_magnetlink(mlink or uri)[1] if infohash is None: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "missing infohash"}) self.session.lm.ltmgr.get_metainfo(mlink or uri, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) return NOT_DONE_YET
def get_metainfo(self, infohash_or_magnet, callback, timeout=30, timeout_callback=None, notify=True): if not self.is_dht_ready() and timeout > 5: self._logger.info("DHT not ready, rescheduling get_metainfo") self.trsession.lm.threadpool.add_task(lambda i=infohash_or_magnet, c=callback, t=timeout - 5, tcb=timeout_callback, n=notify: self.get_metainfo(i, c, t, tcb, n), 5) return magnet = infohash_or_magnet if infohash_or_magnet.startswith('magnet') else None infohash_bin = infohash_or_magnet if not magnet else parse_magnetlink(magnet)[1] infohash = binascii.hexlify(infohash_bin) if infohash in self.torrents: return with self.metainfo_lock: self._logger.debug('get_metainfo %s %s %s', infohash_or_magnet, callback, timeout) cache_result = self._get_cached_metainfo(infohash) if cache_result: self.trsession.lm.threadpool.call_in_thread(0, callback, deepcopy(cache_result)) elif infohash not in self.metainfo_requests: # Flags = 4 (upload mode), should prevent libtorrent from creating files atp = {'save_path': self.metadata_tmpdir, 'duplicate_is_error': True, 'paused': False, 'auto_managed': False, 'upload_mode': True} if magnet: atp['url'] = magnet else: atp['info_hash'] = lt.big_number(infohash_bin) try: handle = self.get_session().add_torrent(encode_atp(atp)) except TypeError as e: self._logger.warning("Failed to add torrent with infohash %s, using libtorrent version %s, " "attempting to use it as it is and hoping for the best", hexlify(infohash_bin), lt.version) self._logger.warning("Error was: %s", e) atp['info_hash'] = infohash_bin handle = self.get_session().add_torrent(encode_atp(atp)) if notify: self.notifier.notify(NTFY_TORRENTS, NTFY_MAGNET_STARTED, infohash_bin) self.metainfo_requests[infohash] = {'handle': handle, 'callbacks': [callback], 'timeout_callbacks': [timeout_callback] if timeout_callback else [], 'notify': notify} self.trsession.lm.threadpool.add_task(lambda: self.got_metainfo(infohash, timeout=True), timeout) else: self.metainfo_requests[infohash]['notify'] = self.metainfo_requests[infohash]['notify'] and notify callbacks = self.metainfo_requests[infohash]['callbacks'] if callback not in callbacks: callbacks.append(callback) else: self._logger.debug('get_metainfo duplicate detected, ignoring')
def get_metainfo(self, infohash_or_magnet, callback, timeout=30): if not self.is_dht_ready() and timeout > 5: print >> sys.stderr, "LibtorrentDownloadImpl: DHT not ready, rescheduling get_metainfo" self.trsession.lm.rawserver.add_task( lambda i=infohash_or_magnet, c=callback, t=timeout - 5: self. get_metainfo(i, c, t), 5) return magnet = infohash_or_magnet if infohash_or_magnet.startswith( 'magnet') else None infohash_bin = infohash_or_magnet if not magnet else parse_magnetlink( magnet)[1] infohash = binascii.hexlify(infohash_bin) with self.torlock: if infohash in self.torrents: return with self.metainfo_lock: if DEBUG: print >> sys.stderr, 'LibtorrentMgr: get_metainfo', infohash_or_magnet, callback, timeout cache_result = self._get_cached_metainfo(infohash) if cache_result: self.trsession.uch.perform_usercallback( lambda cb=callback, mi=deepcopy(cache_result): cb(mi)) elif infohash not in self.metainfo_requests: # Flags = 4 (upload mode), should prevent libtorrent from creating files atp = { 'save_path': tempfile.gettempdir(), 'duplicate_is_error': True, 'paused': False, 'auto_managed': False, 'flags': 4 } if magnet: atp['url'] = magnet else: atp['info_hash'] = lt.big_number(infohash_bin) handle = self.ltsession.add_torrent(atp) self.metainfo_requests[infohash] = (handle, [callback]) self.trsession.lm.rawserver.add_task( lambda: self.got_metainfo(infohash, True), timeout) else: callbacks = self.metainfo_requests[infohash][1] if callback not in callbacks: callbacks.append(callback) elif DEBUG: print >> sys.stderr, 'LibtorrentMgr: get_metainfo duplicate detected, ignoring'
def _on_loaded(response): if response.startswith('magnet'): _, infohash, _ = parse_magnetlink(response) if infohash: self.session.lm.ltmgr.get_metainfo( response, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) return metainfo_deferred.callback(bdecode(response))
def on_magnet(mlink=None): infohash = parse_magnetlink(mlink or uri)[1] if infohash is None: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "missing infohash"}) self.session.lm.ltmgr.get_metainfo( mlink or uri, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) return NOT_DONE_YET
def startDownloadFromMagnet(self, url, destdir=None, cmdline=False, selectedFiles=None, vodmode=False, hops=0): name, infohash, _ = parse_magnetlink(url) if name is None: name = "" try: if infohash is None: raise RuntimeError("Missing infohash") tdef = TorrentDefNoMetainfo(infohash, name, url=url) wx.CallAfter(self.startDownload, tdef=tdef, cmdline=cmdline, destdir=destdir, selectedFiles=selectedFiles, vodmode=vodmode, hops=0) except Exception, e: # show an error dialog dlg = wx.MessageBox(self, "The magnet link is invalid: %s" % str(e), "The magnet link is invalid", wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy()
def on_magnet(mlink=None): infohash = parse_magnetlink(mlink or uri)[1] if infohash is None: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "missing infohash"}) if self.session.has_collected_torrent(infohash): try: tdef = TorrentDef.load_from_memory(self.session.get_collected_torrent(infohash)) except ValueError as exc: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps({"error": "invalid torrent file: %s" % str(exc)}) on_got_metainfo(tdef.get_metainfo()) return NOT_DONE_YET self.session.lm.ltmgr.get_metainfo(mlink or uri, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) return NOT_DONE_YET
def dbreadTrackers(self, torrent): announce = announce_list = None # try using magnet torrentcollecting url sources = self.torrentdb.getTorrentCollecting(torrent['torrent_id']) for source, in sources: if source.startswith('magnet'): dn, xt, trs = parse_magnetlink(source) if len(trs) > 0: if 'info' not in torrent: torrent["info"] = {} announce = trs[0] announce_list = [trs] break if not (announce or announce_list): # see if we have a TorrentTracker entry trackers = self.torrentdb.getTracker(torrent['infohash']) if trackers and len(trackers) > 0: announce_list = [] for tracker, tier in trackers: if tier == 0: announce = tracker else: # tier 1 is actually first in announce-list tier = max(tier - 1, 0) while len(announce_list) <= tier: announce_list.append([]) announce_list[tier].append(tracker) if announce and announce_list: if 'info' not in torrent: torrent["info"] = {} torrent["info"]["announce"] = announce torrent['info']["announce-list"] = announce_list return torrent
def get_metainfo(self, infohash_or_magnet, callback, timeout=30): if not self.is_dht_ready() and timeout > 5: print >> sys.stderr, "LibtorrentDownloadImpl: DHT not ready, rescheduling get_metainfo" self.trsession.lm.rawserver.add_task(lambda i=infohash_or_magnet, c=callback, t=timeout - 5: self.get_metainfo(i, c, t), 5) return magnet = infohash_or_magnet if infohash_or_magnet.startswith('magnet') else None infohash_bin = infohash_or_magnet if not magnet else parse_magnetlink(magnet)[1] infohash = binascii.hexlify(infohash_bin) with self.torlock: if infohash in self.torrents: return with self.metainfo_lock: if DEBUG: print >> sys.stderr, 'LibtorrentMgr: get_metainfo', infohash_or_magnet, callback, timeout cache_result = self._get_cached_metainfo(infohash) if cache_result: self.trsession.uch.perform_usercallback(lambda cb=callback, mi=deepcopy(cache_result): cb(mi)) elif infohash not in self.metainfo_requests: # Flags = 4 (upload mode), should prevent libtorrent from creating files atp = {'save_path': tempfile.gettempdir(), 'duplicate_is_error': True, 'paused': False, 'auto_managed': False, 'flags': 4} if magnet: atp['url'] = magnet else: atp['info_hash'] = lt.big_number(infohash_bin) handle = self.ltsession.add_torrent(atp) self.metainfo_requests[infohash] = (handle, [callback]) self.trsession.lm.rawserver.add_task(lambda: self.got_metainfo(infohash, True), timeout) else: callbacks = self.metainfo_requests[infohash][1] if callback not in callbacks: callbacks.append(callback) elif DEBUG: print >> sys.stderr, 'LibtorrentMgr: get_metainfo duplicate detected, ignoring'
def on_magnet(mlink=None): infohash = parse_magnetlink(mlink or uri)[1] if infohash is None: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "missing infohash"}) if self.session.has_collected_torrent(infohash): try: tdef = TorrentDef.load_from_memory( self.session.get_collected_torrent(infohash)) except ValueError as exc: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps( {"error": "invalid torrent file: %s" % str(exc)}) on_got_metainfo(tdef.get_metainfo()) return NOT_DONE_YET self.session.lm.ltmgr.get_metainfo( mlink or uri, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) return NOT_DONE_YET
def test_parse_magnetlink_nomagnet(self): result = parse_magnetlink("http://") self.assertEqual(result, (None, None, []))
def get_metainfo(self, infohash_or_magnet, callback, timeout=30, timeout_callback=None, notify=True): if not self.is_dht_ready() and timeout > 5: self._logger.info("DHT not ready, rescheduling get_metainfo") def schedule_call(): random_id = ''.join( random.choice('0123456789abcdef') for _ in xrange(30)) self.register_task( "schedule_metainfo_lookup_%s" % random_id, reactor.callLater( 5, lambda i=infohash_or_magnet, c=callback, t=timeout - 5, tcb=timeout_callback, n=notify: self.get_metainfo( i, c, t, tcb, n))) reactor.callFromThread(schedule_call) return magnet = infohash_or_magnet if infohash_or_magnet.startswith( 'magnet') else None infohash_bin = infohash_or_magnet if not magnet else parse_magnetlink( magnet)[1] infohash = binascii.hexlify(infohash_bin) if infohash in self.torrents: return with self.metainfo_lock: self._logger.debug('get_metainfo %s %s %s', infohash_or_magnet, callback, timeout) cache_result = self._get_cached_metainfo(infohash) if cache_result: callback(deepcopy(cache_result)) elif infohash not in self.metainfo_requests: # Flags = 4 (upload mode), should prevent libtorrent from creating files atp = { 'save_path': self.metadata_tmpdir, 'flags': (lt.add_torrent_params_flags_t.flag_upload_mode) } if magnet: atp['url'] = magnet else: atp['info_hash'] = lt.big_number(infohash_bin) try: handle = self.ltsession_metainfo.add_torrent( encode_atp(atp)) except TypeError as e: self._logger.warning( "Failed to add torrent with infohash %s, " "attempting to use it as it is and hoping for the best", hexlify(infohash_bin)) self._logger.warning("Error was: %s", e) atp['info_hash'] = infohash_bin handle = self.ltsession_metainfo.add_torrent( encode_atp(atp)) if notify: self.notifier.notify(NTFY_TORRENTS, NTFY_MAGNET_STARTED, infohash_bin) self.metainfo_requests[infohash] = { 'handle': handle, 'callbacks': [callback], 'timeout_callbacks': [timeout_callback] if timeout_callback else [], 'notify': notify } # if the handle is valid and already has metadata which is the case when torrent already exists in # session then metadata_received_alert is not fired so we call self.got_metainfo() directly here if handle.is_valid() and handle.has_metadata(): self.got_metainfo(infohash, timeout=False) return def schedule_call(): random_id = ''.join( random.choice('0123456789abcdef') for _ in xrange(30)) self.register_task( "schedule_got_metainfo_lookup_%s" % random_id, reactor.callLater( timeout, lambda: self.got_metainfo(infohash, timeout=True))) reactor.callFromThread(schedule_call) else: self.metainfo_requests[infohash][ 'notify'] = self.metainfo_requests[infohash][ 'notify'] and notify callbacks = self.metainfo_requests[infohash]['callbacks'] if callback not in callbacks: callbacks.append(callback) else: self._logger.debug( 'get_metainfo duplicate detected, ignoring')
def get_metainfo(self, infohash_or_magnet, callback, timeout=30, timeout_callback=None, notify=True): if not self.is_dht_ready() and timeout > 5: self._logger.info("DHT not ready, rescheduling get_metainfo") self.trsession.lm.threadpool.add_task( lambda i=infohash_or_magnet, c=callback, t=timeout - 5, tcb= timeout_callback, n=notify: self.get_metainfo(i, c, t, tcb, n), 5) return magnet = infohash_or_magnet if infohash_or_magnet.startswith( 'magnet') else None infohash_bin = infohash_or_magnet if not magnet else parse_magnetlink( magnet)[1] infohash = binascii.hexlify(infohash_bin) if infohash in self.torrents: return with self.metainfo_lock: self._logger.debug('get_metainfo %s %s %s', infohash_or_magnet, callback, timeout) cache_result = self._get_cached_metainfo(infohash) if cache_result: self.trsession.lm.threadpool.call_in_thread( 0, callback, deepcopy(cache_result)) elif infohash not in self.metainfo_requests: # Flags = 4 (upload mode), should prevent libtorrent from creating files atp = { 'save_path': self.metadata_tmpdir, 'duplicate_is_error': True, 'paused': False, 'auto_managed': False, 'upload_mode': True } if magnet: atp['url'] = magnet else: atp['info_hash'] = lt.big_number(infohash_bin) try: handle = self.get_session().add_torrent(encode_atp(atp)) except TypeError as e: self._logger.warning( "Failed to add torrent with infohash %s, using libtorrent version %s, " "attempting to use it as it is and hoping for the best", hexlify(infohash_bin), lt.version) self._logger.warning("Error was: %s", e) atp['info_hash'] = infohash_bin handle = self.get_session().add_torrent(encode_atp(atp)) if notify: self.notifier.notify(NTFY_TORRENTS, NTFY_MAGNET_STARTED, infohash_bin) self.metainfo_requests[infohash] = { 'handle': handle, 'callbacks': [callback], 'timeout_callbacks': [timeout_callback] if timeout_callback else [], 'notify': notify } self.trsession.lm.threadpool.add_task( lambda: self.got_metainfo(infohash, timeout=True), timeout) else: self.metainfo_requests[infohash][ 'notify'] = self.metainfo_requests[infohash][ 'notify'] and notify callbacks = self.metainfo_requests[infohash]['callbacks'] if callback not in callbacks: callbacks.append(callback) else: self._logger.debug( 'get_metainfo duplicate detected, ignoring')
def render_GET(self, request): """ .. http:get:: /torrentinfo A GET request to this endpoint will return information from a torrent found at a provided URI. This URI can either represent a file location, a magnet link or a HTTP(S) url. - torrent: the URI of the torrent file that should be downloaded. This parameter is required. **Example request**: .. sourcecode:: none curl -X PUT http://localhost:8085/torrentinfo?torrent=file:/home/me/test.torrent **Example response**: .. sourcecode:: javascript {"metainfo": <torrent metainfo dictionary>} """ metainfo_deferred = Deferred() def on_got_metainfo(metainfo): if not isinstance(metainfo, dict) or 'info' not in metainfo: self._logger.warning( "Received metainfo is not a valid dictionary") request.setResponseCode(http.INTERNAL_SERVER_ERROR) request.write(json.dumps({"error": 'invalid response'})) self.finish_request(request) return infohash = hashlib.sha1(bencode(metainfo['info'])).digest() # Save the torrent to our store try: self.session.save_collected_torrent(infohash, bencode(metainfo)) except TypeError: # Note: in libtorrent 1.1.1, bencode throws a TypeError which is a known bug pass request.write( json.dumps({"metainfo": metainfo}, ensure_ascii=False)) self.finish_request(request) def on_metainfo_timeout(_): if not request.finished: request.setResponseCode(http.REQUEST_TIMEOUT) request.write(json.dumps({"error": "timeout"})) # If the above request.write failed, the request will have already been finished if not request.finished: self.finish_request(request) def on_lookup_error(failure): failure.trap(ConnectError, DNSLookupError, HttpError) request.setResponseCode(http.INTERNAL_SERVER_ERROR) request.write(json.dumps({"error": failure.getErrorMessage()})) self.finish_request(request) if 'uri' not in request.args or len(request.args['uri']) == 0: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "uri parameter missing"}) uri = unicode(request.args['uri'][0], 'utf-8') if uri.startswith('file:'): try: filename = url2pathname(uri[5:].replace("+", " ")) metainfo_deferred.callback(bdecode(fix_torrent(filename))) except TypeError: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps( {"error": "error while decoding torrent file"}) elif uri.startswith('http'): def _on_loaded(metadata): metainfo_deferred.callback(bdecode(metadata)) http_get(uri.encode('utf-8')).addCallback(_on_loaded).addErrback( on_lookup_error) elif uri.startswith('magnet'): infohash = parse_magnetlink(uri)[1] if infohash is None: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "missing infohash"}) if self.session.has_collected_torrent(infohash): try: tdef = TorrentDef.load_from_memory( self.session.get_collected_torrent(infohash)) except ValueError as exc: request.setResponseCode(http.INTERNAL_SERVER_ERROR) return json.dumps( {"error": "invalid torrent file: %s" % str(exc)}) on_got_metainfo(tdef.get_metainfo()) return NOT_DONE_YET self.session.lm.ltmgr.get_metainfo( uri, callback=metainfo_deferred.callback, timeout=20, timeout_callback=on_metainfo_timeout, notify=True) else: request.setResponseCode(http.BAD_REQUEST) return json.dumps({"error": "invalid uri"}) metainfo_deferred.addCallback(on_got_metainfo) return NOT_DONE_YET
def get_trackers_as_single_tuple(self): if self.url and self.url.startswith('magnet:'): _, _, trs = parse_magnetlink(self.url) return tuple(trs) return ()
def get_trackers_as_single_tuple(self): if self.url and self.url.startswith('magnet:'): _, _, trs = parse_magnetlink(self.url) return tuple(trs) return ()
def test_parse_magnetlink_nomagnet(self): result = parse_magnetlink("http://") self.assertEqual(result, (None, None, []))
def startDownloadFromMagnet(self, url, destdir=None, cmdline=False, selectedFiles=None, vodmode=False): name, infohash, _ = parse_magnetlink(url) tdef = TorrentDefNoMetainfo(infohash, name, url=url) wx.CallAfter(self.startDownload, tdef=tdef, cmdline=cmdline, destdir=destdir, selectedFiles=selectedFiles, vodmode=vodmode) return True