Ejemplo n.º 1
0
    def start_download(self, torrentfilename=None, infohash=None, tdef=None, dconfig=None):
        self._logger.debug(u"starting download: filename: %s, torrent def: %s", torrentfilename, tdef)

        if infohash is not None:
            assert isinstance(infohash, str), "infohash type: %s" % type(infohash)
            assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (len(infohash), infohash)

        # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file.
        # so if we have tdef, infohash and torrent_file will be ignored, and so on.
        if tdef is None:
            if infohash is not None:
                # try to get the torrent from torrent_store if the infohash is provided
                torrent_data = self.tribler_session.get_collected_torrent(infohash)
                if torrent_data is not None:
                    # use this torrent data for downloading
                    tdef = TorrentDef.load_from_memory(torrent_data)

            if tdef is None:
                assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given"
                # try to get the torrent from the given torrent file
                torrent_data = fix_torrent(torrentfilename)
                if torrent_data is None:
                    raise TorrentFileException("error while decoding torrent file")

                tdef = TorrentDef.load_from_memory(torrent_data)

        assert tdef is not None, "tdef MUST not be None after loading torrent"

        default_dl_config = DefaultDownloadStartupConfig.getInstance()
        dscfg = default_dl_config.copy()

        if dconfig is not None:
            dscfg = dconfig

        d = self.tribler_session.get_download(tdef.get_infohash())
        if d:
            # If there is an existing credit mining download with the same infohash
            # then move to the user download directory and checkpoint the download immediately.
            if d.get_credit_mining():
                self.tribler_session.lm.credit_mining_manager.torrents.pop(hexlify(tdef.get_infohash()), None)
                d.set_credit_mining(False)
                d.move_storage(dscfg.get_dest_dir())
                d.checkpoint()

            new_trackers = list(set(tdef.get_trackers_as_single_tuple()) - set(
                d.get_def().get_trackers_as_single_tuple()))
            if new_trackers:
                self.tribler_session.update_trackers(tdef.get_infohash(), new_trackers)

        self._logger.info('start_download: Starting in VOD mode')
        result = self.tribler_session.start_download_from_tdef(tdef, dscfg)

        return result
Ejemplo n.º 2
0
    def resume_download(self, filename, setupDelay=0):
        tdef = dscfg = pstate = None

        try:
            pstate = self.load_download_pstate(filename)

            # SWIFTPROC
            metainfo = pstate.get('state', 'metainfo')
            if 'infohash' in metainfo:
                tdef = TorrentDefNoMetainfo(metainfo['infohash'], metainfo['name'], metainfo.get('url', None))
            else:
                tdef = TorrentDef.load_from_dict(metainfo)

            if pstate.has_option('download_defaults', 'saveas') and \
                    isinstance(pstate.get('download_defaults', 'saveas'), tuple):
                pstate.set('download_defaults', 'saveas', pstate.get('download_defaults', 'saveas')[-1])

            dscfg = DownloadStartupConfig(pstate)

        except:
            # pstate is invalid or non-existing
            _, file = os.path.split(filename)

            infohash = binascii.unhexlify(file[:-6])

            torrent_data = self.torrent_store.get(infohash)
            if torrent_data:
                try:
                    tdef = TorrentDef.load_from_memory(torrent_data)
                    defaultDLConfig = DefaultDownloadStartupConfig.getInstance()
                    dscfg = defaultDLConfig.copy()

                    if self.mypref_db is not None:
                        dest_dir = self.mypref_db.getMyPrefStatsInfohash(infohash)
                        if dest_dir and os.path.isdir(dest_dir):
                            dscfg.set_dest_dir(dest_dir)
                except ValueError:
                    self._logger.warning("tlm: torrent data invalid")

        if pstate is not None:
            has_resume_data = pstate.get('state', 'engineresumedata') is not None
            self._logger.debug("tlm: load_checkpoint: resumedata %s",
                               'len %s ' % len(pstate.get('state', 'engineresumedata')) if has_resume_data else 'None')

        if tdef and dscfg:
            if dscfg.get_dest_dir() != '':  # removed torrent ignoring
                try:
                    if self.download_exists(tdef.get_infohash()):
                        self._logger.info("tlm: not resuming checkpoint because download has already been added")
                    elif dscfg.get_credit_mining() and not self.session.config.get_credit_mining_enabled():
                        self._logger.info("tlm: not resuming checkpoint since token mining is disabled")
                    else:
                        self.add(tdef, dscfg, pstate, setupDelay=setupDelay)
                except Exception as e:
                    self._logger.exception("tlm: load check_point: exception while adding download %s", tdef)
            else:
                self._logger.info("tlm: removing checkpoint %s destdir is %s", filename, dscfg.get_dest_dir())
                os.remove(filename)
        else:
            self._logger.info("tlm: could not resume checkpoint %s %s %s", filename, tdef, dscfg)
Ejemplo n.º 3
0
    def check_watch_folder(self):
        if not os.path.isdir(self.session.config.get_watch_folder_path()):
            return

        for root, _, files in os.walk(self.session.config.get_watch_folder_path()):
            for name in files:
                if not name.endswith(u".torrent"):
                    continue

                try:
                    tdef = TorrentDef.load_from_memory(fix_torrent(os.path.join(root, name)))
                except:  # torrent appears to be corrupt
                    self.cleanup_torrent_file(root, name)
                    continue

                infohash = tdef.get_infohash()

                if not self.session.has_download(infohash):
                    self._logger.info("Starting download from torrent file %s", name)
                    dl_config = DefaultDownloadStartupConfig.getInstance().copy()

                    anon_enabled = self.session.config.get_default_anonymity_enabled()
                    default_num_hops = self.session.config.get_default_number_hops()
                    dl_config.set_hops(default_num_hops if anon_enabled else 0)
                    dl_config.set_safe_seeding(self.session.config.get_default_safeseeding_enabled())
                    dl_config.set_dest_dir(self.session.config.get_default_destination_dir())
                    self.session.lm.ltmgr.start_download(tdef=tdef, dconfig=dl_config)
Ejemplo n.º 4
0
    def _on_download_successful(self, address, file_name, file_data, extra_info):
        self._logger.debug(u"successfully downloaded %s from %s:%s", file_name, address[0], address[1])

        key = extra_info[u'key']
        info_hash = extra_info.get(u"info_hash")
        thumb_hash = extra_info.get(u"thumb_hash")

        assert key in self._active_request_list, u"key = %s, active_request_list = %s" % (repr(key),
                                                                                          self._active_request_list)

        self._requests_succeeded += 1
        self._total_bandwidth += len(file_data)

        # save data
        try:
            if info_hash is not None:
                # save torrent
                tdef = TorrentDef.load_from_memory(file_data)
                self._remote_torrent_handler.save_torrent(tdef)
            elif thumb_hash is not None:
                # save metadata
                self._remote_torrent_handler.save_metadata(thumb_hash, file_data)
        except ValueError:
            self._logger.warning("Remote peer sent us invalid (torrent) content over TFTP socket, ignoring it.")
        finally:
            # start the next request
            self._clear_active_request(key)
            self._start_pending_requests()
Ejemplo n.º 5
0
    def _on_download_successful(self, address, file_name, file_data, extra_info):
        self._logger.debug(u"successfully downloaded %s from %s:%s", file_name, address[0], address[1])

        key = extra_info[u"key"]
        info_hash = extra_info.get(u"info_hash")
        thumb_hash = extra_info.get(u"thumb_hash")

        assert key in self._active_request_list, u"key = %s, active_request_list = %s" % (
            repr(key),
            self._active_request_list,
        )

        self._requests_succeeded += 1
        self._total_bandwidth += len(file_data)

        # save data
        try:
            if info_hash is not None:
                # save torrent
                tdef = TorrentDef.load_from_memory(file_data)
                self._remote_torrent_handler.save_torrent(tdef)
            elif thumb_hash is not None:
                # save metadata
                self._remote_torrent_handler.save_metadata(thumb_hash, file_data)
        finally:
            # start the next request
            self._clear_active_request(key)
            self._start_pending_requests()
Ejemplo n.º 6
0
    def resume_download(self, filename, setupDelay=0):
        tdef = dscfg = pstate = None

        try:
            pstate = self.load_download_pstate(filename)

            # SWIFTPROC
            metainfo = pstate.get('state', 'metainfo')
            if 'infohash' in metainfo:
                tdef = TorrentDefNoMetainfo(metainfo['infohash'], metainfo['name'], metainfo.get('url', None))
            else:
                tdef = TorrentDef.load_from_dict(metainfo)

            if pstate.has_option('download_defaults', 'saveas') and \
                    isinstance(pstate.get('download_defaults', 'saveas'), tuple):
                pstate.set('download_defaults', 'saveas', pstate.get('download_defaults', 'saveas')[-1])

            dscfg = DownloadStartupConfig(pstate)

        except:
            # pstate is invalid or non-existing
            _, file = os.path.split(filename)

            infohash = binascii.unhexlify(file[:-6])

            torrent_data = self.torrent_store.get(infohash)
            if torrent_data:
                try:
                    tdef = TorrentDef.load_from_memory(torrent_data)
                    defaultDLConfig = DefaultDownloadStartupConfig.getInstance()
                    dscfg = defaultDLConfig.copy()

                    if self.mypref_db is not None:
                        dest_dir = self.mypref_db.getMyPrefStatsInfohash(infohash)
                        if dest_dir and os.path.isdir(dest_dir):
                            dscfg.set_dest_dir(dest_dir)
                except ValueError:
                    self._logger.warning("tlm: torrent data invalid")

        if pstate is not None:
            has_resume_data = pstate.get('state', 'engineresumedata') is not None
            self._logger.debug("tlm: load_checkpoint: resumedata %s",
                               'len %s ' % len(pstate.get('state', 'engineresumedata')) if has_resume_data else 'None')

        if tdef and dscfg:
            if dscfg.get_dest_dir() != '':  # removed torrent ignoring
                try:
                    if not self.download_exists(tdef.get_infohash()):
                        self.add(tdef, dscfg, pstate, setupDelay=setupDelay)
                    else:
                        self._logger.info("tlm: not resuming checkpoint because download has already been added")

                except Exception as e:
                    self._logger.exception("tlm: load check_point: exception while adding download %s", tdef)
            else:
                self._logger.info("tlm: removing checkpoint %s destdir is %s", filename, dscfg.get_dest_dir())
                os.remove(filename)
        else:
            self._logger.info("tlm: could not resume checkpoint %s %s %s", filename, tdef, dscfg)
Ejemplo n.º 7
0
 def add_to_loaded(infohash_str):
     """
     function to add loaded infohash to memory
     """
     self.loaded_torrent[unhexlify(infohash_str)].callback(
         TorrentDef.load_from_memory(
             self.session.get_collected_torrent(
                 unhexlify(infohash_str))))
Ejemplo n.º 8
0
    def render_PUT(self, request):
        """
        .. http:put:: /channels/discovered/(string: channelid)/torrents

        Add a torrent file to your own channel. Returns error 500 if something is wrong with the torrent file
        and DuplicateTorrentFileError if already added to your channel. The torrent data is passed as base-64 encoded
        string. The description is optional.

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/channels/discovered/abcd/torrents
                --data "torrent=...&description=funny video"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": True
                }

            :statuscode 404: if your channel does not exist.
            :statuscode 500: if the passed torrent data is corrupt.
        """
        channel = self.get_channel_from_db(self.cid)
        if channel is None:
            return ChannelsTorrentsEndpoint.return_404(request)

        parameters = http.parse_qs(request.content.read(), 1)

        if 'torrent' not in parameters or len(parameters['torrent']) == 0:
            request.setResponseCode(http.BAD_REQUEST)
            return json.dumps({"error": "torrent parameter missing"})

        if 'description' not in parameters or len(
                parameters['description']) == 0:
            extra_info = {}
        else:
            extra_info = {'description': parameters['description'][0]}

        try:
            torrent = base64.b64decode(parameters['torrent'][0])
            torrent_def = TorrentDef.load_from_memory(torrent)
            self.session.add_torrent_def_to_channel(channel[0],
                                                    torrent_def,
                                                    extra_info,
                                                    forward=True)

        except (DuplicateTorrentFileError, ValueError) as ex:
            return BaseChannelsEndpoint.return_500(self, request, ex)

        return json.dumps({"added": True})
        def verify_torrent(body):
            response = json.loads(body)
            torrent = base64.b64decode(response["torrent"])
            tdef = TorrentDef.load_from_memory(torrent)

            # Copy expected creation date and created by (Tribler version) from actual result
            creation_date = tdef.get_creation_date()
            expected_tdef.metainfo["creation date"] = creation_date
            expected_tdef.metainfo["created by"] = tdef.metainfo['created by']

            self.assertEqual(dir(expected_tdef), dir(tdef))
Ejemplo n.º 10
0
        def verify_torrent(body):
            response = json.loads(body)
            torrent = base64.b64decode(response["torrent"])
            tdef = TorrentDef.load_from_memory(torrent)

            # Copy expected creation date and created by (Tribler version) from actual result
            creation_date = tdef.get_creation_date()
            expected_tdef.metainfo["creation date"] = creation_date
            expected_tdef.metainfo["created by"] = tdef.metainfo['created by']

            self.assertEqual(dir(expected_tdef), dir(tdef))
Ejemplo n.º 11
0
    def render_PUT(self, request):
        """
        .. http:put:: /download/(string: infohash)

        A PUT request to this endpoint will start a download from a given infohash. Metadata and peers will be fetched
        from the libtorrent DHT. Various options can be passed:
        - anon_hops: the number of hops for the anonymous download. 0 hops is equivalent to a plain download
        - safe_seeding: whether the seeding of the download should be anonymous or not (0 = off, 1 = on)
        - destination: the download destination path of the torrent

            **Example request**:

                .. sourcecode:: none

                    curl -X PUT http://localhost:8085/downloads/4344503b7e797ebf31582327a5baae35b11bda01
                    --data "anon_hops=2&safe_seeding=1&destination=/my/dest/on/disk/"

            **Example response**:

                .. sourcecode:: javascript

                    {"started": True}
        """
        parameters = http.parse_qs(request.content.read(), 1)

        if self.session.has_download(self.infohash):
            request.setResponseCode(http.CONFLICT)
            return json.dumps({
                "error":
                "the download with the given infohash already exists"
            })

        # Check whether we have the torrent file, otherwise, create a tdef without metainfo.
        torrent_data = self.session.get_collected_torrent(self.infohash)
        if torrent_data is not None:
            tdef_download = TorrentDef.load_from_memory(torrent_data)
        else:
            torrent_db = self.session.open_dbhandler(NTFY_TORRENTS)
            torrent = torrent_db.getTorrent(self.infohash,
                                            keys=['C.torrent_id', 'name'])
            tdef_download = TorrentDefNoMetainfo(self.infohash,
                                                 torrent['name'])

        download_config, error = DownloadSpecificEndpoint.create_dconfig_from_params(
            parameters)
        if not error:
            self.session.start_download_from_tdef(tdef_download,
                                                  download_config)
        else:
            request.setResponseCode(http.BAD_REQUEST)
            return json.dumps({"error": error})

        return json.dumps({"started": True})
Ejemplo n.º 12
0
    def on_got_torrent(self, torrent_data, rss_item=None):
        if self._to_stop:
            return

        # save torrent
        tdef = TorrentDef.load_from_memory(torrent_data)
        self.session.lm.rtorrent_handler.save_torrent(tdef)

        # create channel torrent
        self.channel_community._disp_create_torrent_from_torrentdef(tdef, long(time.time()))

        # update URL cache
        self._url_cache.add(rss_item[u'torrent_url'])
        self._url_cache.save()

        self._logger.info(u"Channel torrent %s created", tdef.get_name_as_unicode())
Ejemplo n.º 13
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
Ejemplo n.º 14
0
    def on_got_torrent(self, torrent_data, rss_item=None):
        if self._to_stop:
            return

        # save torrent
        tdef = TorrentDef.load_from_memory(torrent_data)
        self.session.lm.rtorrent_handler.save_torrent(tdef)

        # create channel torrent
        self.channel_community._disp_create_torrent_from_torrentdef(
            tdef, long(time.time()))

        # update URL cache
        self._url_cache.add(rss_item[u'torrent_url'])
        self._url_cache.save()

        self._logger.info(u"Channel torrent %s created",
                          tdef.get_name_as_unicode())
Ejemplo n.º 15
0
    def create_torrent(self, infohash, store=True, update=True, forward=True):
        torrent_data = self.tribler_session.get_collected_torrent(infohash)
        if torrent_data is not None:
            try:
                torrentdef = TorrentDef.load_from_memory(torrent_data)
                files = torrentdef.get_files_with_length()

                meta = self.get_meta_message(u"torrent")
                message = meta.impl(authentication=(self._my_member,),
                                    distribution=(self.claim_global_time(),),
                                    payload=(torrentdef.get_infohash(), long(time()), torrentdef.get_name_as_unicode(),
                                             tuple(files), torrentdef.get_trackers_as_single_tuple()))

                self._dispersy.store_update_forward([message], store, update, forward)
                self._torrent_db.updateTorrent(torrentdef.get_infohash(), notify=False, dispersy_id=message.packet_id)

                return message
            except ValueError:
                pass
            except:
                print_exc()
        return False
Ejemplo n.º 16
0
    def check_watch_folder(self):
        if not os.path.isdir(self.session.config.get_watch_folder_path()):
            return

        # Make sure that we pass a str to os.walk
        watch_dir = self.session.config.get_watch_folder_path().encode(
            'raw_unicode_escape')

        for root, _, files in os.walk(watch_dir):
            for name in files:
                if not name.endswith(".torrent"):
                    continue

                try:
                    tdef = TorrentDef.load_from_memory(
                        fix_torrent(os.path.join(root, name)))
                except:  # torrent appears to be corrupt
                    self.cleanup_torrent_file(root, name)
                    continue

                infohash = tdef.get_infohash()

                if not self.session.has_download(infohash):
                    self._logger.info("Starting download from torrent file %s",
                                      name)
                    dl_config = DefaultDownloadStartupConfig.getInstance(
                    ).copy()

                    anon_enabled = self.session.config.get_default_anonymity_enabled(
                    )
                    default_num_hops = self.session.config.get_default_number_hops(
                    )
                    dl_config.set_hops(default_num_hops if anon_enabled else 0)
                    dl_config.set_safe_seeding(
                        self.session.config.get_default_safeseeding_enabled())
                    dl_config.set_dest_dir(
                        self.session.config.get_default_destination_dir())
                    self.session.lm.ltmgr.start_download(tdef=tdef,
                                                         dconfig=dl_config)
Ejemplo n.º 17
0
    def reimport_torrents(self):
        """Import all torrent files in the collected torrent dir, all the files already in the database will be ignored.
        """
        self.status_update_func("Opening TorrentDBHandler...")
        # TODO(emilon): That's a freakishly ugly hack.
        torrent_db_handler = TorrentDBHandler(self.session)
        torrent_db_handler.category = Category()

        # TODO(emilon): It would be nice to drop the corrupted torrent data from the store as a bonus.
        self.status_update_func("Registering recovered torrents...")
        try:
            for infoshash_str, torrent_data in self.torrent_store.iteritems():
                self.status_update_func("> %s" % infoshash_str)
                torrentdef = TorrentDef.load_from_memory(torrent_data)
                if torrentdef.is_finalized():
                    infohash = torrentdef.get_infohash()
                    if not torrent_db_handler.hasTorrent(infohash):
                        self.status_update_func(u"Registering recovered torrent: %s" % hexlify(infohash))
                        torrent_db_handler._addTorrentToDB(torrentdef, extra_info={"filename": infoshash_str})
        finally:
            torrent_db_handler.close()
            self.db.commit_now()
            return self.torrent_store.flush()
Ejemplo n.º 18
0
    def on_got_torrent(self, torrent_data, rss_item=None):
        if self._to_stop:
            return

        # save torrent
        tdef = TorrentDef.load_from_memory(torrent_data)
        self.session.lm.rtorrent_handler.save_torrent(tdef)

        # add metadata pending request
        info_hash = tdef.get_infohash()
        if u'thumbnail_list' in rss_item and rss_item[u'thumbnail_list']:
            # only use the first thumbnail
            rss_item[u'thumbnail_url'] = rss_item[u'thumbnail_list'][0]
            if info_hash not in self._pending_metadata_requests:
                self._pending_metadata_requests[info_hash] = rss_item

        # create channel torrent
        self.channel_community._disp_create_torrent_from_torrentdef(tdef, long(time.time()))

        # update URL cache
        self._url_cache.add(rss_item[u'torrent_url'])
        self._url_cache.save()

        self._logger.info(u"Channel torrent %s created", tdef.get_name_as_unicode())
Ejemplo n.º 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"})

            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
Ejemplo n.º 20
0
    def load_torrent(self, torrent, callback=None):
        """
        function to load torrent dictionary to torrent object.

        From TorrentManager.loadTorrent in SearchGridManager
        """

        # session is quitting
        if not (self.session and self.session.get_torrent_store()
                and self.session.lm.torrent_store):
            return

        if not isinstance(torrent, CollectedTorrent):
            if torrent.torrent_id <= 0:
                torrent_id = self.torrent_db.getTorrentID(torrent.infohash)
                if torrent_id:
                    torrent.update_torrent_id(torrent_id)

            if not self.session.has_collected_torrent(torrent.infohash):
                files = []
                trackers = []

                # see if we have most info in our tables
                if isinstance(torrent, RemoteTorrent):
                    torrent_id = self.torrent_db.getTorrentID(torrent.infohash)
                else:
                    torrent_id = torrent.torrent_id

                trackers.extend(
                    self.torrent_db.getTrackerListByTorrentID(torrent_id))

                if 'DHT' in trackers:
                    trackers.remove('DHT')
                if 'no-DHT' in trackers:
                    trackers.remove('no-DHT')

                # replacement # self.downloadTorrentfileFromPeers(torrent, None)
                if self.session.has_download(torrent.infohash):
                    return False

                if torrent.query_candidates is None or len(
                        torrent.query_candidates) == 0:
                    self.session.download_torrentfile(torrent.infohash, None,
                                                      0)
                else:
                    for candidate in torrent.query_candidates:
                        self.session.download_torrentfile_from_peer(
                            candidate, torrent.infohash, None, 0)

                torrent = NotCollectedTorrent(torrent, files, trackers)

            else:
                tdef = TorrentDef.load_from_memory(
                    self.session.get_collected_torrent(torrent.infohash))

                if torrent.torrent_id <= 0:
                    del torrent.torrent_id

                torrent = CollectedTorrent(torrent, tdef)

        # replacement # self.library_manager.addDownloadState(torrent)
        for dl_state in self.dslist:
            torrent.addDs(dl_state)

        # return
        if callback is not None:
            callback(torrent)
        else:
            return torrent
Ejemplo n.º 21
0
 def _on_url_fetched(data):
     return TorrentDef.load_from_memory(data)
Ejemplo n.º 22
0
    def render_PUT(self, request):
        """
        .. http:put:: /channels/discovered/(string: channelid)/torrents

        Add a torrent file to your own channel. Returns error 500 if something is wrong with the torrent file
        and DuplicateTorrentFileError if already added to your channel. The torrent data is passed as base-64 encoded
        string. The description is optional.

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/channels/discovered/abcd/torrents
                --data "torrent=...&description=funny video"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": True
                }

            :statuscode 404: if your channel does not exist.
            :statuscode 500: if the passed torrent data is corrupt.
        """
        key = self.session.trustchain_keypair
        my_channel_id = key.pub().key_to_bin()

        # First check whether the channel actually exists
        if self.is_chant_channel:
            if my_channel_id != self.cid:
                request.setResponseCode(http.NOT_ALLOWED)
                return json.dumps({
                    "error":
                    "you can only add torrents to your own chant channel"
                })

            channel = self.session.lm.mds.ChannelMetadata.get_channel_with_id(
                my_channel_id)
            if not channel:
                return ChannelsTorrentsEndpoint.return_404(request)
        else:
            channel = self.get_channel_from_db(self.cid)
            if channel is None:
                return ChannelsTorrentsEndpoint.return_404(request)

        parameters = http.parse_qs(request.content.read(), 1)

        if 'torrent' not in parameters or len(parameters['torrent']) == 0:
            request.setResponseCode(http.BAD_REQUEST)
            return json.dumps({"error": "torrent parameter missing"})

        if 'description' not in parameters or len(
                parameters['description']) == 0:
            extra_info = {}
        else:
            extra_info = {'description': parameters['description'][0]}

        # Try to parse the torrent data
        try:
            torrent = base64.b64decode(parameters['torrent'][0])
            torrent_def = TorrentDef.load_from_memory(torrent)
        except ValueError as exc:
            return BaseChannelsEndpoint.return_500(self, request, exc)

        if self.is_chant_channel:
            try:
                channel.add_torrent_to_channel(torrent_def, extra_info)
            except DuplicateTorrentFileError as exc:
                return BaseChannelsEndpoint.return_500(self, request, exc)
        else:
            try:
                self.session.add_torrent_def_to_channel(channel[0],
                                                        torrent_def,
                                                        extra_info,
                                                        forward=True)
            except (DuplicateTorrentFileError, HttpError) as ex:
                return BaseChannelsEndpoint.return_500(self, request, ex)

        return json.dumps({"added": True})
Ejemplo n.º 23
0
 def _on_url_fetched(data):
     return TorrentDef.load_from_memory(data)
Ejemplo n.º 24
0
 def get_metainfo(infohash, callback, **_):
     with open(os.path.join(TESTS_DATA_DIR, "bak_single.torrent"), mode='rb') as torrent_file:
         torrent_data = torrent_file.read()
     tdef = TorrentDef.load_from_memory(torrent_data)
     callback(tdef.get_metainfo())
Ejemplo n.º 25
0
    def resume_download(self, filename, initialdlstatus=None, initialdlstatus_dict={}, setupDelay=0):
        tdef = dscfg = pstate = None

        try:
            pstate = self.load_download_pstate(filename)

            # SWIFTPROC
            metainfo = pstate.get('state', 'metainfo')
            if 'infohash' in metainfo:
                tdef = TorrentDefNoMetainfo(metainfo['infohash'], metainfo['name'], metainfo.get('url', None))
            else:
                tdef = TorrentDef.load_from_dict(metainfo)

            if pstate.has_option('downloadconfig', 'saveas') and \
                    isinstance(pstate.get('downloadconfig', 'saveas'), tuple):
                pstate.set('downloadconfig', 'saveas', pstate.get('downloadconfig', 'saveas')[-1])

            dscfg = DownloadStartupConfig(pstate)

        except:
            # pstate is invalid or non-existing
            _, file = os.path.split(filename)

            infohash = binascii.unhexlify(file[:-6])

            torrent_data = self.torrent_store.get(infohash)
            if torrent_data:
                tdef = TorrentDef.load_from_memory(torrent_data)

                defaultDLConfig = DefaultDownloadStartupConfig.getInstance()
                dscfg = defaultDLConfig.copy()

                if self.mypref_db is not None:
                    dest_dir = self.mypref_db.getMyPrefStatsInfohash(infohash)
                    if dest_dir:
                        if os.path.isdir(dest_dir) or dest_dir == '':
                            dscfg.set_dest_dir(dest_dir)

        self._logger.debug("tlm: load_checkpoint: pstate is %s %s",
                           pstate.get('dlstate', 'status'), pstate.get('dlstate', 'progress'))
        if pstate is None or pstate.get('state', 'engineresumedata') is None:
            self._logger.debug("tlm: load_checkpoint: resumedata None")
        else:
            self._logger.debug("tlm: load_checkpoint: resumedata len %d", len(pstate.get('state', 'engineresumedata')))

        if tdef and dscfg:
            if dscfg.get_dest_dir() != '':  # removed torrent ignoring
                try:
                    if not self.download_exists(tdef.get_infohash()):
                        initialdlstatus = initialdlstatus_dict.get(tdef.get_infohash(), initialdlstatus)
                        self.add(tdef, dscfg, pstate, initialdlstatus, setupDelay=setupDelay)
                    else:
                        self._logger.info("tlm: not resuming checkpoint because download has already been added")

                except Exception as e:
                    self._logger.exception("tlm: load check_point: exception while adding download %s", tdef)
            else:
                self._logger.info("tlm: removing checkpoint %s destdir is %s", filename, dscfg.get_dest_dir())
                os.remove(filename)
        else:
            self._logger.info("tlm: could not resume checkpoint %s %s %s", filename, tdef, dscfg)
Ejemplo n.º 26
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
Ejemplo n.º 27
0
    def render_PUT(self, request):
        """
        .. http:put:: /channels/discovered/(string: channelid)/torrents

        Add a torrent file to your own channel. Returns error 500 if something is wrong with the torrent file
        and DuplicateTorrentFileError if already added to your channel. The torrent data is passed as base-64 encoded
        string. The description is optional.

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/channels/discovered/abcd/torrents
                --data "torrent=...&description=funny video"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": True
                }

            :statuscode 404: if your channel does not exist.
            :statuscode 500: if the passed torrent data is corrupt.
        """
        key = self.session.trustchain_keypair
        my_channel_id = key.pub().key_to_bin()

        # First check whether the channel actually exists
        if self.is_chant_channel:
            if my_channel_id != self.cid:
                request.setResponseCode(http.NOT_ALLOWED)
                return json.dumps({"error": "you can only add torrents to your own chant channel"})

            channel = self.session.lm.mds.ChannelMetadata.get_channel_with_id(my_channel_id)
            if not channel:
                return ChannelsTorrentsEndpoint.return_404(request)
        else:
            channel = self.get_channel_from_db(self.cid)
            if channel is None:
                return ChannelsTorrentsEndpoint.return_404(request)

        parameters = http.parse_qs(request.content.read(), 1)

        if 'torrent' not in parameters or len(parameters['torrent']) == 0:
            request.setResponseCode(http.BAD_REQUEST)
            return json.dumps({"error": "torrent parameter missing"})

        if 'description' not in parameters or len(parameters['description']) == 0:
            extra_info = {}
        else:
            extra_info = {'description': parameters['description'][0]}

        # Try to parse the torrent data
        try:
            torrent = base64.b64decode(parameters['torrent'][0])
            torrent_def = TorrentDef.load_from_memory(torrent)
        except ValueError as exc:
            return BaseChannelsEndpoint.return_500(self, request, exc)

        if self.is_chant_channel:
            try:
                channel.add_torrent_to_channel(torrent_def, extra_info)
            except DuplicateTorrentFileError as exc:
                return BaseChannelsEndpoint.return_500(self, request, exc)
        else:
            try:
                self.session.add_torrent_def_to_channel(channel[0], torrent_def, extra_info, forward=True)
            except (DuplicateTorrentFileError, HttpError) as ex:
                return BaseChannelsEndpoint.return_500(self, request, ex)

        return json.dumps({"added": True})
Ejemplo n.º 28
0
    def startDownload(self, torrentfilename=None, destdir=None, infohash=None, tdef=None, cmdline=False,
                      vodmode=False, hops=0, selectedFiles=None, hidden=False):
        self._logger.debug(u"startDownload: %s %s %s %s %s", torrentfilename, destdir, tdef, vodmode, selectedFiles)

        # TODO(lipu): remove the assertions after it becomes stable
        if infohash is not None:
            assert isinstance(infohash, str), "infohash type: %s" % type(infohash)
            assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (len(infohash), infohash)

        # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file.
        # so if we have tdef, infohash and torrent_file will be ignored, and so on.
        if tdef is None:
            if infohash is not None:
                # try to get the torrent from torrent_store if the infohash is provided
                torrent_data = self.utility.session.get_collected_torrent(infohash)
                if torrent_data is not None:
                    # use this torrent data for downloading
                    tdef = TorrentDef.load_from_memory(torrent_data)

            if tdef is None:
                assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given"
                # try to get the torrent from the given torrent file
                torrent_data = fix_torrent(torrentfilename)
                if torrent_data is None:
                    # show error message: could not open torrent file
                    dlg = wx.MessageBox(self, "Could not open torrent file %s" % torrentfilename,
                                        "Error", wx.OK | wx.ICON_ERROR)
                    dlg.ShowModal()
                    dlg.Destroy()
                    return

                tdef = TorrentDef.load_from_memory(torrent_data)

        assert tdef is not None, "tdef MUST not be None after loading torrent"

        try:
            d = self.utility.session.get_download(tdef.get_infohash())
            if d:
                new_trackers = list(set(tdef.get_trackers_as_single_tuple()) - set(
                    d.get_def().get_trackers_as_single_tuple()))
                if not new_trackers:
                    raise DuplicateDownloadException()

                else:
                    @forceWxThread
                    def do_gui():
                        # Show update tracker dialog
                        dialog = wx.MessageDialog(
                            None, 'This torrent is already being downloaded. Do you wish to load the trackers from it?', 'Tribler', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                        if dialog.ShowModal() == wx.ID_YES:
                            # Update trackers
                            self.utility.session.update_trackers(tdef.get_infohash(), new_trackers)
                        dialog.Destroy()

                    do_gui()
                return

            defaultDLConfig = DefaultDownloadStartupConfig.getInstance()
            dscfg = defaultDLConfig.copy()

            cancelDownload = False
            useDefault = not self.utility.read_config('showsaveas')
            safe_seeding = self.utility.read_config('default_safeseeding_enabled')
            if not useDefault and not destdir:
                defaultname = tdef.get_name_as_unicode() if tdef.is_multifile_torrent() else None

                if wx.Thread_IsMain():
                    dlg = SaveAs(None, tdef, dscfg.get_dest_dir(), defaultname, selectedFiles)
                    dlg.CenterOnParent()

                    if isinstance(tdef, TorrentDefNoMetainfo):
                        # Correct for the smaller size of the dialog if there is no metainfo
                        center_pos = dlg.GetPosition()
                        center_pos[1] -= 150
                        dlg.SetPosition(center_pos)

                    if dlg.ShowModal() == wx.ID_OK:
                        # If the dialog has collected a torrent, use the new tdef
                        tdef = dlg.GetCollected() or tdef

                        if tdef and tdef.is_multifile_torrent():
                            selectedFiles = dlg.GetSelectedFiles()
                        destdir = dlg.GetPath()

                        # Anonymity over exit nodes or hidden services
                        safe_seeding = dlg.UseSafeSeeding()
                        if dlg.UseTunnels():
                            hops = self.utility.read_config('default_number_hops')

                    else:
                        cancelDownload = True
                    dlg.Destroy()
                else:
                    raise Exception("cannot create dialog, not on wx thread")

            # use default setup
            else:
                if useDefault:
                    if self.utility.read_config('default_anonymity_enabled'):
                        # only load default anonymous level if we use default settings
                        hops = self.utility.read_config('default_number_hops')
                    else:
                        hops = 0

            if hops > 0:
                if not tdef:
                    raise Exception('Currently only torrents can be downloaded in anonymous mode')

            dscfg.set_hops(hops)
            dscfg.set_safe_seeding(safe_seeding)

            if not cancelDownload:
                if destdir is not None:
                    dscfg.set_dest_dir(destdir)

                if selectedFiles and len(selectedFiles) == 1:
                    # we should filter files to see if they are all playable
                    videofiles = selectedFiles

                elif tdef and not selectedFiles:
                    videofiles = tdef.get_files(exts=videoextdefaults)

                else:
                    videofiles = []

                # disable vodmode if no videofiles, unless we still need to collect the torrent
                if vodmode and len(videofiles) == 0 and (not tdef or not isinstance(tdef, TorrentDefNoMetainfo)):
                    vodmode = False

                if vodmode:
                    self._logger.info('MainFrame: startDownload: Starting in VOD mode')
                    result = self.utility.session.start_download(tdef, dscfg)
                    self.guiUtility.library_manager.playTorrent(
                        tdef.get_infohash(), videofiles[0] if len(videofiles) == 1 else None)

                else:
                    if selectedFiles:
                        dscfg.set_selected_files(selectedFiles)

                    self._logger.debug('MainFrame: startDownload: Starting in DL mode')
                    result = self.utility.session.start_download(tdef, dscfg, hidden=hidden)

                if result and not hidden:
                    self.show_saved(tdef)

                return result

        except DuplicateDownloadException as e:
            # If there is something on the cmdline, all other torrents start
            # in STOPPED state. Restart
            if cmdline:
                dlist = self.utility.session.get_downloads()
                for d in dlist:
                    if d.get_def().get_infohash() == tdef.get_infohash():
                        d.restart()
                        break

            if wx.Thread_IsMain():
                # show nice warning dialog
                dlg = wx.MessageDialog(None,
                                       "You are already downloading this torrent, see the Downloads section.",
                                       "Duplicate download", wx.OK | wx.ICON_ERROR)
                result = dlg.ShowModal()
                dlg.Destroy()

            else:
                print_exc()
                self.onWarning(e)

        except Exception as e:
            print_exc()
            self.onWarning(e)

        return None
Ejemplo n.º 29
0
    def render_PUT(self, request):
        """
        .. http:put:: /mychannel/torrents

        Add a torrent file to your own channel. Returns error 500 if something is wrong with the torrent file
        and DuplicateTorrentFileError if already added to your channel. The torrent data is passed as base-64 encoded
        string. The description is optional.

        Option torrents_dir adds all .torrent files from a chosen directory
        Option recursive enables recursive scanning of the chosen directory for .torrent files

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/mychannel/torrents
                --data "torrent=...&description=funny video"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": True
                }

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/mychannel/torrents? --data "torrents_dir=some_dir&recursive=1"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": 13
                }

            :statuscode 404: if your channel does not exist.
            :statuscode 500: if the passed torrent data is corrupt.
        """
        my_channel = self.session.lm.mds.ChannelMetadata.get_my_channel()
        if not my_channel:
            request.setResponseCode(http.NOT_FOUND)
            return json.dumps(
                {"error": "your channel has not been created yet"})

        parameters = http.parse_qs(request.content.read(), 1)

        if 'description' not in parameters or not parameters['description']:
            extra_info = {}
        else:
            extra_info = {'description': parameters['description'][0]}

        def _on_url_fetched(data):
            return TorrentDef.load_from_memory(data)

        def _on_magnet_fetched(meta_info):
            return TorrentDef.load_from_dict(meta_info)

        def _on_torrent_def_loaded(torrent_def):
            with db_session:
                channel = self.session.lm.mds.get_my_channel()
                channel.add_torrent_to_channel(torrent_def, extra_info)
            return 1

        def _on_added(added):
            request.write(json.dumps({"added": added}))
            request.finish()

        def _on_add_failed(failure):
            failure.trap(ValueError, DuplicateTorrentFileError,
                         SchemeNotSupported)
            self._logger.exception(failure.value)
            request.write(self.return_500(request, failure.value))
            request.finish()

        def _on_timeout(_):
            request.write(
                self.return_500(request, RuntimeError("Metainfo timeout")))
            request.finish()

        # First, check whether we did upload a magnet link or URL
        if 'uri' in parameters and parameters['uri']:
            deferred = Deferred()
            uri = parameters['uri'][0]
            if uri.startswith("http:") or uri.startswith("https:"):
                deferred = http_get(uri)
                deferred.addCallback(_on_url_fetched)
            elif uri.startswith("magnet:"):
                try:
                    self.session.lm.ltmgr.get_metainfo(
                        uri,
                        callback=deferred.callback,
                        timeout=30,
                        timeout_callback=_on_timeout,
                        notify=True)
                except Exception as ex:
                    deferred.errback(ex)

                deferred.addCallback(_on_magnet_fetched)
            else:
                request.setResponseCode(http.BAD_REQUEST)
                return json.dumps({"error": "unknown uri type"})

            deferred.addCallback(_on_torrent_def_loaded)
            deferred.addCallback(_on_added)
            deferred.addErrback(_on_add_failed)
            return NOT_DONE_YET

        torrents_dir = None
        if 'torrents_dir' in parameters and parameters['torrents_dir'] > 0:
            torrents_dir = parameters['torrents_dir'][0]
            if not os.path.isabs(torrents_dir):
                request.setResponseCode(http.BAD_REQUEST)
                return json.dumps(
                    {"error": "the torrents_dir should point to a directory"})

        recursive = False
        if 'recursive' in parameters and parameters['recursive'] > 0:
            recursive = parameters['recursive'][0]
            if not torrents_dir:
                request.setResponseCode(http.BAD_REQUEST)
                return json.dumps({
                    "error":
                    "the torrents_dir parameter should be provided when the recursive "
                    "parameter is set"
                })

        if torrents_dir:
            torrents_list, errors_list = my_channel.add_torrents_from_dir(
                torrents_dir, recursive)
            return json.dumps({
                "added": len(torrents_list),
                "errors": errors_list
            })

        if 'torrent' not in parameters or not parameters['torrent']:
            request.setResponseCode(http.BAD_REQUEST)
            return json.dumps({"error": "torrent parameter missing"})

        # Try to parse the torrent data
        try:
            torrent = base64.b64decode(parameters['torrent'][0])
            torrent_def = TorrentDef.load_from_memory(torrent)
        except (TypeError, ValueError):
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            return json.dumps({"error": "invalid torrent file"})

        try:
            my_channel.add_torrent_to_channel(torrent_def, extra_info)
        except DuplicateTorrentFileError:
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            return json.dumps(
                {"error": "this torrent already exists in your channel"})

        return json.dumps({"added": 1})
Ejemplo n.º 30
0
 def callback(saveas_id, infohash):
     saveas = wx.FindWindowById(saveas_id)
     if saveas:
         tdef = TorrentDef.load_from_memory(self.utility.session.lm.torrent_store.get(infohash))
         event = CollectedEvent(tdef=tdef)
         wx.PostEvent(saveas, event)
Ejemplo n.º 31
0
    def startDownload(self,
                      torrentfilename=None,
                      destdir=None,
                      infohash=None,
                      tdef=None,
                      cmdline=False,
                      vodmode=False,
                      hops=0,
                      selectedFiles=None,
                      hidden=False):
        self._logger.debug(u"startDownload: %s %s %s %s %s", torrentfilename,
                           destdir, tdef, vodmode, selectedFiles)

        # TODO(lipu): remove the assertions after it becomes stable
        if infohash is not None:
            assert isinstance(infohash,
                              str), "infohash type: %s" % type(infohash)
            assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (
                len(infohash), infohash)

        # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file.
        # so if we have tdef, infohash and torrent_file will be ignored, and so on.
        if tdef is None:
            if infohash is not None:
                # try to get the torrent from torrent_store if the infohash is provided
                torrent_data = self.utility.session.get_collected_torrent(
                    infohash)
                if torrent_data is not None:
                    # use this torrent data for downloading
                    tdef = TorrentDef.load_from_memory(torrent_data)

            if tdef is None:
                assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given"
                # try to get the torrent from the given torrent file
                torrent_data = fix_torrent(torrentfilename)
                if torrent_data is None:
                    # show error message: could not open torrent file
                    dlg = wx.MessageBox(
                        self,
                        "Could not open torrent file %s" % torrentfilename,
                        "Error", wx.OK | wx.ICON_ERROR)
                    dlg.ShowModal()
                    dlg.Destroy()
                    return

                tdef = TorrentDef.load_from_memory(torrent_data)

        assert tdef is not None, "tdef MUST not be None after loading torrent"

        try:
            d = self.utility.session.get_download(tdef.get_infohash())
            if d:
                new_trackers = list(
                    set(tdef.get_trackers_as_single_tuple()) -
                    set(d.get_def().get_trackers_as_single_tuple()))
                if not new_trackers:
                    raise DuplicateDownloadException()

                else:

                    @forceWxThread
                    def do_gui():
                        # Show update tracker dialog
                        dialog = wx.MessageDialog(
                            None,
                            'This torrent is already being downloaded. Do you wish to load the trackers from it?',
                            'Tribler',
                            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
                        if dialog.ShowModal() == wx.ID_YES:
                            # Update trackers
                            self.utility.session.update_trackers(
                                tdef.get_infohash(), new_trackers)
                        dialog.Destroy()

                    do_gui()
                return

            defaultDLConfig = DefaultDownloadStartupConfig.getInstance()
            dscfg = defaultDLConfig.copy()

            cancelDownload = False
            useDefault = not self.utility.read_config('showsaveas')
            safe_seeding = self.utility.read_config(
                'default_safeseeding_enabled')
            if not useDefault and not destdir:
                defaultname = tdef.get_name_as_unicode(
                ) if tdef.is_multifile_torrent() else None

                if wx.Thread_IsMain():
                    dlg = SaveAs(None, tdef, dscfg.get_dest_dir(), defaultname,
                                 selectedFiles)
                    dlg.CenterOnParent()

                    if isinstance(tdef, TorrentDefNoMetainfo):
                        # Correct for the smaller size of the dialog if there is no metainfo
                        center_pos = dlg.GetPosition()
                        center_pos[1] -= 150
                        dlg.SetPosition(center_pos)

                    if dlg.ShowModal() == wx.ID_OK:
                        # If the dialog has collected a torrent, use the new tdef
                        tdef = dlg.GetCollected() or tdef

                        if tdef and tdef.is_multifile_torrent():
                            selectedFiles = dlg.GetSelectedFiles()
                        destdir = dlg.GetPath()

                        # Anonymity over exit nodes or hidden services
                        safe_seeding = dlg.UseSafeSeeding()
                        if dlg.UseTunnels():
                            hops = self.utility.read_config(
                                'default_number_hops')

                    else:
                        cancelDownload = True
                    dlg.Destroy()
                else:
                    raise Exception("cannot create dialog, not on wx thread")

            # use default setup
            else:
                if useDefault:
                    if self.utility.read_config('default_anonymity_enabled'):
                        # only load default anonymous level if we use default settings
                        hops = self.utility.read_config('default_number_hops')
                    else:
                        hops = 0

            if hops > 0:
                if not tdef:
                    raise Exception(
                        'Currently only torrents can be downloaded in anonymous mode'
                    )

            dscfg.set_hops(hops)
            dscfg.set_safe_seeding(safe_seeding)

            if not cancelDownload:
                if destdir is not None:
                    dscfg.set_dest_dir(destdir)

                if selectedFiles and len(selectedFiles) == 1:
                    # we should filter files to see if they are all playable
                    videofiles = selectedFiles

                elif tdef and not selectedFiles:
                    videofiles = tdef.get_files(exts=videoextdefaults)

                else:
                    videofiles = []

                # disable vodmode if no videofiles, unless we still need to collect the torrent
                if vodmode and len(videofiles) == 0 and (
                        not tdef
                        or not isinstance(tdef, TorrentDefNoMetainfo)):
                    vodmode = False

                if vodmode:
                    self._logger.info(
                        'MainFrame: startDownload: Starting in VOD mode')
                    result = self.utility.session.start_download_from_tdef(
                        tdef, dscfg)
                    self.guiUtility.library_manager.playTorrent(
                        tdef.get_infohash(),
                        videofiles[0] if len(videofiles) == 1 else None)

                else:
                    if selectedFiles:
                        dscfg.set_selected_files(selectedFiles)

                    self._logger.debug(
                        'MainFrame: startDownload: Starting in DL mode')
                    result = self.utility.session.start_download_from_tdef(
                        tdef, dscfg, hidden=hidden)

                if result and not hidden:
                    self.show_saved(tdef)

                return result

        except DuplicateDownloadException as e:
            # If there is something on the cmdline, all other torrents start
            # in STOPPED state. Restart
            if cmdline:
                dlist = self.utility.session.get_downloads()
                for d in dlist:
                    if d.get_def().get_infohash() == tdef.get_infohash():
                        d.restart()
                        break

            if wx.Thread_IsMain():
                # show nice warning dialog
                dlg = wx.MessageDialog(
                    None,
                    "You are already downloading this torrent, see the Downloads section.",
                    "Duplicate download", wx.OK | wx.ICON_ERROR)
                result = dlg.ShowModal()
                dlg.Destroy()

            else:
                print_exc()
                self.onWarning(e)

        except Exception as e:
            print_exc()
            self.onWarning(e)

        return None
 def get_metainfo(infohash, callback, **_):
     with open(os.path.join(TESTS_DATA_DIR, "bak_single.torrent"),
               mode='rb') as torrent_file:
         torrent_data = torrent_file.read()
     tdef = TorrentDef.load_from_memory(torrent_data)
     callback(tdef.get_metainfo())
Ejemplo n.º 33
0
    def start_download(self,
                       torrentfilename=None,
                       infohash=None,
                       tdef=None,
                       dconfig=None):
        self._logger.debug(u"starting download: filename: %s, torrent def: %s",
                           torrentfilename, tdef)

        if infohash is not None:
            assert isinstance(infohash,
                              str), "infohash type: %s" % type(infohash)
            assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (
                len(infohash), infohash)

        # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file.
        # so if we have tdef, infohash and torrent_file will be ignored, and so on.
        if tdef is None:
            if infohash is not None:
                # try to get the torrent from torrent_store if the infohash is provided
                torrent_data = self.tribler_session.get_collected_torrent(
                    infohash)
                if torrent_data is not None:
                    # use this torrent data for downloading
                    tdef = TorrentDef.load_from_memory(torrent_data)

            if tdef is None:
                assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given"
                # try to get the torrent from the given torrent file
                torrent_data = fix_torrent(torrentfilename)
                if torrent_data is None:
                    raise TorrentFileException(
                        "error while decoding torrent file")

                tdef = TorrentDef.load_from_memory(torrent_data)

        assert tdef is not None, "tdef MUST not be None after loading torrent"

        d = self.tribler_session.get_download(tdef.get_infohash())
        if d:
            new_trackers = list(
                set(tdef.get_trackers_as_single_tuple()) -
                set(d.get_def().get_trackers_as_single_tuple()))
            if not new_trackers:
                raise DuplicateDownloadException(
                    "This download already exists.")

            else:
                self.tribler_session.update_trackers(tdef.get_infohash(),
                                                     new_trackers)
            return

        default_dl_config = DefaultDownloadStartupConfig.getInstance()
        dscfg = default_dl_config.copy()

        if dconfig is not None:
            dscfg = dconfig

        self._logger.info('start_download: Starting in VOD mode')
        result = self.tribler_session.start_download_from_tdef(tdef, dscfg)

        return result
Ejemplo n.º 34
0
    def start_download(self,
                       torrentfilename=None,
                       infohash=None,
                       tdef=None,
                       dconfig=None):
        self._logger.debug(u"starting download: filename: %s, torrent def: %s",
                           torrentfilename, tdef)

        if infohash is not None:
            assert isinstance(infohash,
                              str), "infohash type: %s" % type(infohash)
            assert len(infohash) == 20, "infohash length is not 20: %s, %s" % (
                len(infohash), infohash)

        # the priority of the parameters is: (1) tdef, (2) infohash, (3) torrent_file.
        # so if we have tdef, infohash and torrent_file will be ignored, and so on.
        if tdef is None:
            if infohash is not None:
                # try to get the torrent from torrent_store if the infohash is provided
                torrent_data = self.tribler_session.get_collected_torrent(
                    infohash)
                if torrent_data is not None:
                    # use this torrent data for downloading
                    tdef = TorrentDef.load_from_memory(torrent_data)

            if tdef is None:
                assert torrentfilename is not None, "torrent file must be provided if tdef and infohash are not given"
                # try to get the torrent from the given torrent file
                torrent_data = fix_torrent(torrentfilename)
                if torrent_data is None:
                    raise TorrentFileException(
                        "error while decoding torrent file")

                tdef = TorrentDef.load_from_memory(torrent_data)

        assert tdef is not None, "tdef MUST not be None after loading torrent"

        d = self.tribler_session.get_download(tdef.get_infohash())
        if d:
            # If there is an existing credit mining download with the same infohash, remove it and restart
            if d.get_credit_mining():
                self.tribler_session.lm.credit_mining_manager.torrents.pop(
                    hexlify(tdef.get_infohash()), None)
                self.tribler_session.remove_download(d).addCallback(
                    lambda _, tf=torrentfilename, ih=infohash, td=tdef, dc=
                    dconfig: self.start_download(tf, ih, td, dc))
                return

            new_trackers = list(
                set(tdef.get_trackers_as_single_tuple()) -
                set(d.get_def().get_trackers_as_single_tuple()))
            if new_trackers:
                self.tribler_session.update_trackers(tdef.get_infohash(),
                                                     new_trackers)

        default_dl_config = DefaultDownloadStartupConfig.getInstance()
        dscfg = default_dl_config.copy()

        if dconfig is not None:
            dscfg = dconfig

        self._logger.info('start_download: Starting in VOD mode')
        result = self.tribler_session.start_download_from_tdef(tdef, dscfg)

        return result
Ejemplo n.º 35
0
    def render_PUT(self, request):
        """
        .. http:put:: /mychannel/torrents

        Add a torrent file to your own channel. Returns error 500 if something is wrong with the torrent file
        and DuplicateTorrentFileError if already added to your channel. The torrent data is passed as base-64 encoded
        string. The description is optional.

        Option torrents_dir adds all .torrent files from a chosen directory
        Option recursive enables recursive scanning of the chosen directory for .torrent files

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/mychannel/torrents
                --data "torrent=...&description=funny video"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": True
                }

            **Example request**:

            .. sourcecode:: none

                curl -X PUT http://localhost:8085/mychannel/torrents? --data "torrents_dir=some_dir&recursive=1"

            **Example response**:

            .. sourcecode:: javascript

                {
                    "added": 13
                }

            :statuscode 404: if your channel does not exist.
            :statuscode 500: if the passed torrent data is corrupt.
        """
        my_channel = self.session.lm.mds.ChannelMetadata.get_my_channel()
        if not my_channel:
            request.setResponseCode(http.NOT_FOUND)
            return json.dumps({"error": "your channel has not been created yet"})

        parameters = http.parse_qs(request.content.read(), 1)

        if 'description' not in parameters or not parameters['description']:
            extra_info = {}
        else:
            extra_info = {'description': parameters['description'][0]}

        def _on_url_fetched(data):
            return TorrentDef.load_from_memory(data)

        def _on_magnet_fetched(meta_info):
            return TorrentDef.load_from_dict(meta_info)

        def _on_torrent_def_loaded(torrent_def):
            with db_session:
                channel = self.session.lm.mds.get_my_channel()
                channel.add_torrent_to_channel(torrent_def, extra_info)
            return 1

        def _on_added(added):
            request.write(json.dumps({"added": added}))
            request.finish()

        def _on_add_failed(failure):
            failure.trap(ValueError, DuplicateTorrentFileError, SchemeNotSupported)
            self._logger.exception(failure.value)
            request.write(self.return_500(request, failure.value))
            request.finish()

        def _on_timeout(_):
            request.write(self.return_500(request, RuntimeError("Metainfo timeout")))
            request.finish()

        # First, check whether we did upload a magnet link or URL
        if 'uri' in parameters and parameters['uri']:
            deferred = Deferred()
            uri = parameters['uri'][0]
            if uri.startswith("http:") or uri.startswith("https:"):
                deferred = http_get(uri)
                deferred.addCallback(_on_url_fetched)
            elif uri.startswith("magnet:"):
                try:
                    self.session.lm.ltmgr.get_metainfo(uri, callback=deferred.callback,
                                                       timeout=30, timeout_callback=_on_timeout, notify=True)
                except Exception as ex:
                    deferred.errback(ex)

                deferred.addCallback(_on_magnet_fetched)
            else:
                request.setResponseCode(http.BAD_REQUEST)
                return json.dumps({"error": "unknown uri type"})

            deferred.addCallback(_on_torrent_def_loaded)
            deferred.addCallback(_on_added)
            deferred.addErrback(_on_add_failed)
            return NOT_DONE_YET

        torrents_dir = None
        if 'torrents_dir' in parameters and parameters['torrents_dir'] > 0:
            torrents_dir = parameters['torrents_dir'][0]
            if not os.path.isabs(torrents_dir):
                request.setResponseCode(http.BAD_REQUEST)
                return json.dumps({"error": "the torrents_dir should point to a directory"})

        recursive = False
        if 'recursive' in parameters and parameters['recursive'] > 0:
            recursive = parameters['recursive'][0]
            if not torrents_dir:
                request.setResponseCode(http.BAD_REQUEST)
                return json.dumps({"error": "the torrents_dir parameter should be provided when the recursive "
                                            "parameter is set"})

        if torrents_dir:
            torrents_list, errors_list = my_channel.add_torrents_from_dir(torrents_dir, recursive)
            return json.dumps({"added": len(torrents_list), "errors": errors_list})

        if 'torrent' not in parameters or not parameters['torrent']:
            request.setResponseCode(http.BAD_REQUEST)
            return json.dumps({"error": "torrent parameter missing"})

        # Try to parse the torrent data
        try:
            torrent = base64.b64decode(parameters['torrent'][0])
            torrent_def = TorrentDef.load_from_memory(torrent)
        except (TypeError, ValueError):
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            return json.dumps({"error": "invalid torrent file"})

        try:
            my_channel.add_torrent_to_channel(torrent_def, extra_info)
        except DuplicateTorrentFileError:
            request.setResponseCode(http.INTERNAL_SERVER_ERROR)
            return json.dumps({"error": "this torrent already exists in your channel"})

        return json.dumps({"added": 1})