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
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, )
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)
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()
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)