Пример #1
0
    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
Пример #2
0
    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
Пример #3
0
 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()
Пример #4
0
    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")
Пример #5
0
    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")
Пример #6
0
    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")
Пример #7
0
    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")
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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
Пример #11
0
    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
Пример #12
0
    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
Пример #13
0
    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')
Пример #14
0
 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))
Пример #15
0
 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)
Пример #16
0
 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)
Пример #17
0
 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&']))
Пример #18
0
 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&']))
Пример #19
0
        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
Пример #20
0
    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')
Пример #21
0
    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'
Пример #22
0
 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))
Пример #23
0
        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
Пример #24
0
 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()
Пример #25
0
        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
Пример #26
0
    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
Пример #27
0
    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'
Пример #28
0
        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
Пример #29
0
 def test_parse_magnetlink_nomagnet(self):
     result = parse_magnetlink("http://")
     self.assertEqual(result, (None, None, []))
Пример #30
0
    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')
Пример #31
0
    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')
Пример #32
0
    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
Пример #33
0
 def get_trackers_as_single_tuple(self):
     if self.url and self.url.startswith('magnet:'):
         _, _, trs = parse_magnetlink(self.url)
         return tuple(trs)
     return ()
Пример #34
0
 def get_trackers_as_single_tuple(self):
     if self.url and self.url.startswith('magnet:'):
         _, _, trs = parse_magnetlink(self.url)
         return tuple(trs)
     return ()
Пример #35
0
 def test_parse_magnetlink_nomagnet(self):
     result = parse_magnetlink("http://")
     self.assertEqual(result, (None, None, []))
Пример #36
0
 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