示例#1
0
 def __init__(self, client: TelegramClient, sender: MTProtoSender, file: TypeLocation, offset: int, limit: int,
              stride: int, count: int) -> None:
     self.sender = sender
     self.client = client
     self.request = GetFileRequest(file, offset=offset, limit=limit)
     self.stride = stride
     self.remaining = count
示例#2
0
    def download(self, file: TypeLocation, file_size: int, offset: int,
                 limit: int) -> AsyncGenerator[bytes, None]:
        dc_id, location = utils.get_input_location(file)
        part_size = 512 * 1024
        first_part_cut = offset % part_size
        first_part = math.floor(offset / part_size)
        last_part_cut = part_size - (limit % part_size)
        last_part = math.ceil(limit / part_size)
        part_count = math.ceil(file_size / part_size)
        self.log.debug(
            f"Starting parallel download: chunks {first_part}-{last_part}"
            f" of {part_count} {location!s}")
        request = GetFileRequest(location,
                                 offset=first_part * part_size,
                                 limit=part_size)

        return self._int_download(
            request,
            first_part,
            last_part,
            part_count,
            part_size,
            dc_id,
            first_part_cut,
            last_part_cut,
        )
示例#3
0
    def download_file_loc(self,
                          input_location,
                          file_path,
                          part_size_kb=64,
                          file_size=None,
                          progress_callback=None):
        """Downloads media from the given input_file_location to the specified file_path.
           If a progress_callback function is given, it will be called taking two
           arguments (downloaded bytes count and total file size)"""

        if not part_size_kb:
            if not file_size:
                raise ValueError('A part size value must be provided')
            else:
                part_size_kb = get_appropiate_part_size(file_size)

        part_size = int(part_size_kb * 1024)
        if part_size % 1024 != 0:
            raise ValueError('The part size must be evenly divisible by 1024')

        # Ensure that we'll be able to download the media
        utils.ensure_parent_dir_exists(file_path)

        # Start with an offset index of 0
        offset_index = 0
        with open(file_path, 'wb') as file:
            while True:
                # The current offset equals the offset_index multiplied by the part size
                offset = offset_index * part_size
                result = self.invoke(
                    GetFileRequest(input_location, offset, part_size))
                offset_index += 1

                # If we have received no data (0 bytes), the file is over
                # So there is nothing left to download and write
                if not result.bytes:
                    return result.type  # Return some extra information

                file.write(result.bytes)
                if progress_callback:
                    progress_callback(file.tell(), file_size)
示例#4
0
    def download_file(self,
                      input_location,
                      file=None,
                      part_size_kb=None,
                      file_size=None,
                      progress_callback=None):

        """
        Downloads the given input location to a file.

        Args:
            input_location (:tl:`InputFileLocation`):
                The file location from which the file will be downloaded.

            file (`str` | `file`):
                The output file path, directory, or stream-like object.
                If the path exists and is a file, it will be overwritten.

            part_size_kb (`int`, optional):
                Chunk size when downloading files. The larger, the less
                requests will be made (up to 512KB maximum).

            file_size (`int`, optional):
                The file size that is about to be downloaded, if known.
                Only used if ``progress_callback`` is specified.

            progress_callback (`callable`, optional):
                A callback function accepting two parameters:
                ``(downloaded bytes, total)``. Note that the
                ``total`` is the provided ``file_size``.
        """
        if not part_size_kb:
            if not file_size:
                part_size_kb = 64  # Reasonable default
            else:
                part_size_kb = utils.get_appropriated_part_size(file_size)

        part_size = int(part_size_kb * 1024)
        # https://core.telegram.org/api/files says:
        # > part_size % 1024 = 0 (divisible by 1KB)
        #
        # But https://core.telegram.org/cdn (more recent) says:
        # > limit must be divisible by 4096 bytes
        # So we just stick to the 4096 limit.
        if part_size % 4096 != 0:
            raise ValueError(
                'The part size must be evenly divisible by 4096.')

        in_memory = file is None
        if in_memory:
            f = io.BytesIO()
        elif isinstance(file, str):
            # Ensure that we'll be able to download the media
            helpers.ensure_parent_dir_exists(file)
            f = open(file, 'wb')
        else:
            f = file

        # The used client will change if FileMigrateError occurs
        client = self
        cdn_decrypter = None
        input_location = utils.get_input_location(input_location)
        download_thread = []
        q_request = []

        __log__.info('Downloading file in chunks of %d bytes', part_size)
        threads_count = 2 + int((self._download_threads_count - 2) * float(file_size) / (1024 * 1024 * 10))
        threads_count = min(threads_count, self._download_threads_count)
        # threads_count = 1
        # threads_count = min(part_count, threads_count)
        try:
            offset = 0
            result = None
            try:
                request = GetFileRequest(input_location, offset, part_size)
                result = client(request)
                if isinstance(result, FileCdnRedirect):
                    __log__.info('File lives in a CDN')
                    cdn_decrypter, result = CdnDecrypter.prepare_decrypter(client, self._get_cdn_client(result), result)
                else:
                    f.write(result.bytes)
                    offset += part_size
            except FileMigrateError as e:
                __log__.info('File lives in another DC')
                client = self._get_exported_client(e.new_dc)

            # if cdn_decrypter:
            #     result = cdn_decrypter.get_file()

            # if not result.bytes:
            #     return getattr(result, 'type', '')
            # f.write(result.bytes)
            __log__.debug('Saved %d more bytes', len(result.bytes))
            if progress_callback:
                progress_callback(f.tell(), file_size)

            # spawn threads
            for i in range(threads_count):
                q_request.append(Queue())
                thread_dl = self.ProcessDownload('thread {0}'.format(i), self, q_request[i])
                thread_dl.start()
                download_thread.append(thread_dl)
            # offset += part_size
            while True:
                for i in range(threads_count):
                    if cdn_decrypter:
                        q_request[i].put(cdn_decrypter)
                    else:
                        request = GetFileRequest(input_location, offset, part_size)
                        q_request[i].put(request)
                    offset += part_size
                for q in q_request:
                    q.join()
                for th in download_thread:
                    if th.result and th.result.bytes:
                        f.write(th.result.bytes)
                        if progress_callback:
                            progress_callback(f.tell(), file_size)
                    else:
                        for i in range(threads_count):
                            q_request[i].put(None)
                        for th in download_thread:
                            th.join()
                        return getattr(th.result, 'type', '')
        finally:
            if client != self:
                client.disconnect()

            if cdn_decrypter:
                try:
                    cdn_decrypter.client.disconnect()
                except:
                    pass
            if isinstance(file, str):
                f.close()
示例#5
0
async def get_sticker_set(context: Message):
    """ get sticker set """
    reply = await context.get_reply_message()
    if not reply:
        await context.edit('出错了呜呜呜 ~ 没有回复贴纸消息。')
        return
    if not reply.media:
        await context.edit('出错了呜呜呜 ~ 没有回复贴纸消息。')
        return
    if isinstance(reply.media, MessageMediaPhoto):
        await context.edit('出错了呜呜呜 ~ 没有回复贴纸消息。')
        return
    elif "image" in reply.media.document.mime_type.split('/'):
        if (DocumentAttributeFilename(file_name='sticker.webp') not in
                reply.media.document.attributes):
            await context.edit('出错了呜呜呜 ~ 没有回复贴纸消息。')
            return
    elif (DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in
          reply.media.document.attributes):
        pass
    else:
        await context.edit('出错了呜呜呜 ~ 没有回复贴纸消息。')
        return
    sticker_set = reply.media.document.attributes[1].stickerset
    if isinstance(sticker_set, InputStickerSetEmpty):
        await context.edit('出错了呜呜呜 ~ 您回复的贴纸不包含任何贴纸包信息。')
        return
    await context.edit('获取中。。。')
    try:
        stickers = await context.client(GetStickerSetRequest(
            stickerset=InputStickerSetID(id=sticker_set.id, access_hash=sticker_set.access_hash)))
    except StickersetInvalidError:
        await context.edit('出错了呜呜呜 ~ 您回复的贴纸不包含任何贴纸包信息。')
        return
    stickers_set = stickers.set
    # 再次判断变量类型
    if not isinstance(stickers_set, StickerSet):
        await context.edit('出错了呜呜呜 ~ 您回复的贴纸不包含任何贴纸包信息。')
        return
    # 初始化变量
    sid = sticker_set.id
    access_hash = sticker_set.access_hash
    thumb_version = stickers_set.thumb_version
    official = '✅' if stickers_set.official else ''
    animated = '(动态)' if stickers_set.animated else ''
    archived = '💤' if stickers_set.archived else ''
    time_zone = timezone('Etc/GMT-8')
    installed_date = stickers_set.installed_date.astimezone(time_zone).strftime('%Y-%m-%d %H:%M:%S') if \
        stickers_set.installed_date else '未添加'
    # 下载预览图
    file = None
    if thumb_version:
        try:
            thumb = await bot(GetFileRequest(location=InputStickerSetThumb(
                stickerset=InputStickerSetID(id=sid, access_hash=access_hash),
                thumb_version=thumb_version), offset=-1, limit=1048576, precise=False, cdn_supported=True))
            with open('data/sticker_thumb.jpg', 'wb') as f:
                f.write(thumb.bytes)
            file = 'data/sticker_thumb.jpg'
        except FileMigrateError:
            pass
    else:
        if not stickers_set.animated:
            await bot.download_media(stickers.documents[0], file='data/sticker_thumb.webp')
            convert_png('data/sticker_thumb.webp')
            file = 'data/sticker_thumb.png'
    text = f'贴纸包:{official}[{stickers_set.title}](https://t.me/addstickers/{stickers_set.short_name}) {animated}' \
           f'{archived}\n' \
           f'贴纸数:`{stickers_set.count}`\n' \
           f'添加时间:`{installed_date}`\n' \
           f'id:`{sid}`\n' \
           f'access_hash: `{access_hash}`'
    if file:
        await context.client.send_file(
            context.chat_id,
            file,
            caption=text,
            force_document=False,
            allow_cache=False
        )
        await context.delete()
    else:
        await context.edit(text)