コード例 #1
0
    def __init__(self,
                 metainfo=None,
                 torrent_parameters=None,
                 ignore_validation=False):
        """
        Create a new TorrentDef object, possibly based on existing data.
        :param metainfo: A dictionary with metainfo, i.e. from a .torrent file.
        :param torrent_parameters: User-defined parameters for the new TorrentDef.
        :param ignore_validation: Whether we ignore the libtorrent validation.
        """
        self._logger = logging.getLogger(self.__class__.__name__)
        self.torrent_parameters = {}
        self.metainfo = None
        self.files_list = []
        self.infohash = None

        if metainfo is not None:
            # First, make sure the passed metainfo is valid
            if not ignore_validation:
                try:
                    lt.torrent_info(metainfo)
                except RuntimeError as exc:
                    raise ValueError(str(exc))
            self.metainfo = metainfo
            self.infohash = sha1(lt.bencode(self.metainfo[b'info'])).digest()
            self.copy_metainfo_to_torrent_parameters()

        elif torrent_parameters:
            self.torrent_parameters.update(torrent_parameters)
コード例 #2
0
ファイル: channel_metadata.py プロジェクト: xoriole/tribler
def create_torrent_from_dir(directory, torrent_filename):
    fs = lt.file_storage()
    lt.add_files(fs, str(directory))
    t = lt.create_torrent(fs)
    # t = create_torrent(fs, flags=17) # piece alignment
    t.set_priv(False)
    lt.set_piece_hashes(t, str(directory.parent))
    torrent = t.generate()
    with open(torrent_filename, 'wb') as f:
        f.write(lt.bencode(torrent))

    infohash = lt.torrent_info(torrent).info_hash().to_bytes()
    return torrent, infohash
コード例 #3
0
ファイル: downloads_endpoint.py プロジェクト: overflw/tribler
    async def get_torrent(self, request):
        infohash = unhexlify(request.match_info['infohash'])
        download = self.download_manager.get_download(infohash)
        if not download:
            return DownloadsEndpoint.return_404(request)

        torrent = download.get_torrent_data()
        if not torrent:
            return DownloadsEndpoint.return_404(request)

        return RESTResponse(lt.bencode(torrent),
                            headers={
                                'content-type':
                                'application/x-bittorrent',
                                'Content-Disposition':
                                'attachment; filename=%s.torrent' %
                                hexlify(infohash).encode('utf-8')
                            })
コード例 #4
0
ファイル: download_manager.py プロジェクト: overflw/tribler
    async def shutdown(self, timeout=30):
        if self.downloads:
            self.notify_shutdown_state("Checkpointing Downloads...")
            await gather(
                *[download.stop() for download in self.downloads.values()],
                return_exceptions=True)
            self.notify_shutdown_state("Shutting down Downloads...")
            await gather(
                *[download.shutdown() for download in self.downloads.values()],
                return_exceptions=True)

        self.notify_shutdown_state("Shutting down Libtorrent Manager...")
        # If libtorrent session has pending disk io, wait until timeout (default: 30 seconds) to let it finish.
        # In between ask for session stats to check if state is clean for shutdown.
        # In dummy mode, we immediately shut down the download manager.
        while not self.dummy_mode and not self.is_shutdown_ready(
        ) and timeout >= 1:
            self.notify_shutdown_state("Waiting for Libtorrent to finish...")
            self.post_session_stats()
            timeout -= 1
            await asyncio.sleep(1)

        await self.shutdown_task_manager()

        if self.dht_health_manager:
            await self.dht_health_manager.shutdown_task_manager()

        # Save libtorrent state
        if self.has_session():
            with open(self.state_dir / LTSTATE_FILENAME, 'wb') as ltstate_file:
                ltstate_file.write(lt.bencode(self.get_session().save_state()))

        if self.has_session() and self.config.upnp:
            self.get_session().stop_upnp()

        for ltsession in self.ltsessions.values():
            del ltsession
        self.ltsessions = None

        # Remove metadata temporary directory
        if self.metadata_tmpdir:
            rmtree(self.metadata_tmpdir, ignore_errors=True)
            self.metadata_tmpdir = None
コード例 #5
0
    def get_atp(self):
        save_path = self.config.get_dest_dir()
        atp = {
            "save_path":
            str(save_path),
            "storage_mode":
            lt.storage_mode_t.storage_mode_sparse,
            "flags":
            lt.add_torrent_params_flags_t.flag_paused
            | lt.add_torrent_params_flags_t.flag_duplicate_is_error
            | lt.add_torrent_params_flags_t.flag_update_subscribe
        }

        if self.config.get_share_mode():
            atp["flags"] = atp[
                "flags"] | lt.add_torrent_params_flags_t.flag_share_mode
        if self.config.get_upload_mode():
            atp["flags"] = atp[
                "flags"] | lt.add_torrent_params_flags_t.flag_upload_mode

        resume_data = self.config.get_engineresumedata()
        if not isinstance(self.tdef, TorrentDefNoMetainfo):
            metainfo = self.tdef.get_metainfo()
            torrentinfo = lt.torrent_info(metainfo)

            atp["ti"] = torrentinfo
            if resume_data and isinstance(resume_data, dict):
                # Rewrite save_path as a global path, if it is given as a relative path
                save_path = (ensure_unicode(resume_data[b"save_path"], 'utf8')
                             if b"save_path" in resume_data else None)
                if save_path and not Path(save_path).is_absolute():
                    resume_data[b"save_path"] = str(self.state_dir / save_path)
                atp["resume_data"] = lt.bencode(resume_data)
        else:
            atp["url"] = self.tdef.get_url(
            ) or "magnet:?xt=urn:btih:" + hexlify(self.tdef.get_infohash())
            atp["name"] = self.tdef.get_name_as_unicode()

        return atp
コード例 #6
0
ファイル: download_config.py プロジェクト: overflw/tribler
 def set_engineresumedata(self, engineresumedata):
     self.config['state']['engineresumedata'] = base64.b64encode(
         lt.bencode(engineresumedata)).decode('utf-8')
コード例 #7
0
ファイル: download_config.py プロジェクト: overflw/tribler
 def set_metainfo(self, metainfo):
     self.config['state']['metainfo'] = base64.b64encode(
         lt.bencode(metainfo)).decode('utf-8')
コード例 #8
0
    async def get_torrent_info(self, request):
        args = request.query

        hops = None
        if 'hops' in args:
            try:
                hops = int(args['hops'])
            except ValueError:
                return RESTResponse(
                    {
                        "error":
                        f"wrong value of 'hops' parameter: {repr(args['hops'])}"
                    },
                    status=HTTP_BAD_REQUEST)

        if 'uri' not in args or not args['uri']:
            return RESTResponse({"error": "uri parameter missing"},
                                status=HTTP_BAD_REQUEST)

        uri = args['uri']
        metainfo = None
        if uri.startswith('file:'):
            try:
                filename = uri_to_path(uri)
                tdef = TorrentDef.load(filename)
                metainfo = tdef.get_metainfo()
            except (TypeError, RuntimeError):
                return RESTResponse(
                    {"error": "error while decoding torrent file"},
                    status=HTTP_INTERNAL_SERVER_ERROR)
        elif uri.startswith('http'):
            try:
                response = await query_http_uri(uri)
            except (ServerConnectionError, ClientResponseError) as e:
                return RESTResponse({"error": str(e)},
                                    status=HTTP_INTERNAL_SERVER_ERROR)

            if response.startswith(b'magnet'):
                _, infohash, _ = parse_magnetlink(response)
                if infohash:
                    metainfo = await self.download_manager.get_metainfo(
                        infohash, timeout=60, hops=hops, url=response)
            else:
                metainfo = bdecode_compat(response)
        elif uri.startswith('magnet'):
            infohash = parse_magnetlink(uri)[1]
            if infohash is None:
                return RESTResponse({"error": "missing infohash"},
                                    status=HTTP_BAD_REQUEST)
            metainfo = await self.download_manager.get_metainfo(infohash,
                                                                timeout=60,
                                                                hops=hops,
                                                                url=uri)
        else:
            return RESTResponse({"error": "invalid uri"},
                                status=HTTP_BAD_REQUEST)

        if not metainfo:
            return RESTResponse({"error": "metainfo error"},
                                status=HTTP_INTERNAL_SERVER_ERROR)

        if not isinstance(metainfo, dict) or b'info' not in metainfo:
            self._logger.warning("Received metainfo is not a valid dictionary")
            return RESTResponse({"error": "invalid response"},
                                status=HTTP_INTERNAL_SERVER_ERROR)

        # Add the torrent to GigaChannel as a free-for-all entry, so others can search it
        self.download_manager.notifier.notify(
            NTFY.TORRENT_METADATA_ADDED.value,
            tdef_to_metadata_dict(TorrentDef.load_from_dict(metainfo)))

        # TODO(Martijn): store the stuff in a database!!!
        # TODO(Vadim): this means cache the downloaded torrent in a binary storage, like LevelDB
        infohash = hashlib.sha1(lt.bencode(metainfo[b'info'])).digest()

        download = self.download_manager.downloads.get(infohash)
        metainfo_request = self.download_manager.metainfo_requests.get(
            infohash, [None])[0]
        download_is_metainfo_request = download == metainfo_request

        # Check if the torrent is already in the downloads
        encoded_metainfo = deepcopy(metainfo)

        # FIXME: json.dumps garbles binary data that is used by the 'pieces' field
        # However, this is fine as long as the GUI does not use this field.
        encoded_metainfo[b'info'][b'pieces'] = hexlify(
            encoded_metainfo[b'info'][b'pieces']).encode('utf-8')
        encoded_metainfo = hexlify(
            json.dumps(recursive_unicode(encoded_metainfo, ignore_errors=True),
                       ensure_ascii=False).encode('utf-8'))
        return RESTResponse({
            "metainfo":
            encoded_metainfo,
            "download_exists":
            download and not download_is_metainfo_request
        })
コード例 #9
0
ファイル: torrent_utils.py プロジェクト: xoriole/tribler
def create_torrent_file(file_path_list, params, torrent_filepath=None):
    fs = lt.file_storage()

    # filter all non-files
    path_list = list(_existing_files(file_path_list))

    # ACHTUNG!
    # In the case of a multi-file torrent, the torrent name plays the role of the toplevel dir name.
    # get the directory where these files are in. If there are multiple files, take the common directory they are in
    base_dir = (commonprefix(path_list).parent
                if len(path_list) > 1 else path_list[0].parent).absolute()
    for path in path_list:
        relative = path.relative_to(base_dir)
        fs.add_file(str(relative), path.size())

    if params.get(b'piece length'):
        piece_size = params[b'piece length']
    else:
        piece_size = 0

    flags = lt.create_torrent_flags_t.optimize

    # This flag doesn't exist anymore in libtorrent V1.1.0
    if hasattr(lt.create_torrent_flags_t, 'calculate_file_hashes'):
        flags |= lt.create_torrent_flags_t.calculate_file_hashes

    params = {
        k: (v.decode('utf-8') if isinstance(v, bytes) else v)
        for k, v in params.items()
    }

    torrent = lt.create_torrent(fs, piece_size=piece_size, flags=flags)
    if params.get(b'comment'):
        torrent.set_comment(params[b'comment'])
    if params.get(b'created by'):
        torrent.set_creator(params[b'created by'])
    # main tracker
    if params.get(b'announce'):
        torrent.add_tracker(params[b'announce'])
    # tracker list
    if params.get(b'announce-list'):
        tier = 1
        for tracker in params[b'announce-list']:
            torrent.add_tracker(tracker, tier=tier)
            tier += 1
    # DHT nodes
    # http://www.bittorrent.org/beps/bep_0005.html
    if params.get(b'nodes'):
        for node in params[b'nodes']:
            torrent.add_node(*node)
    # HTTP seeding
    # http://www.bittorrent.org/beps/bep_0017.html
    if params.get(b'httpseeds'):
        torrent.add_http_seed(params[b'httpseeds'])

    # Web seeding
    # http://www.bittorrent.org/beps/bep_0019.html
    if len(file_path_list) == 1:
        if params.get(b'urllist', False):
            torrent.add_url_seed(params[b'urllist'])

    # read the files and calculate the hashes
    lt.set_piece_hashes(torrent, str(base_dir))

    t1 = torrent.generate()
    torrent = lt.bencode(t1)

    if torrent_filepath:
        with open(torrent_filepath, 'wb') as f:
            f.write(torrent)

    return {
        'success': True,
        'base_dir': base_dir,
        'torrent_file_path': torrent_filepath,
        'metainfo': torrent,
        'infohash': sha1(lt.bencode(t1[b'info'])).digest()
    }