async def yield_file(self, media_msg: Message, offset: int, first_part_cut: int, last_part_cut: int, part_count: int, chunk_size: int) -> Union[str, None]: client = self.main_bot data = await self.generate_file_properties(media_msg) media_session = await self.generate_media_session(client, media_msg) current_part = 1 file_ref = utils.decode_file_ref(data.file_ref) location = await self.get_location(data, file_ref) r = await media_session.send( raw.functions.upload.GetFile( location=location, offset=offset, limit=chunk_size ), ) if isinstance(r, raw.types.upload.File): while current_part <= part_count: chunk = r.bytes if not chunk: break offset += chunk_size if part_count == 1: yield chunk[first_part_cut:last_part_cut] break if current_part == 1: yield chunk[first_part_cut:] if 1 < current_part < part_count: yield chunk r = await media_session.send( raw.functions.upload.GetFile( location=location, offset=offset, limit=chunk_size ), ) current_part += 1
async def download_as_bytesio(self, media_msg: Message): client = self.main_bot data = await self.generate_file_properties(media_msg) media_session = await self.generate_media_session(client, media_msg) file_ref = utils.decode_file_ref(data.file_ref) location = await self.get_location(data, file_ref) limit = 1024 * 1024 offset = 0 r = await media_session.send( raw.functions.upload.GetFile( location=location, offset=offset, limit=limit ) ) if isinstance(r, raw.types.upload.File): m_file = [] # m_file.name = file_name while True: chunk = r.bytes if not chunk: break m_file.append(chunk) offset += limit r = await media_session.send( raw.functions.upload.GetFile( location=location, offset=offset, limit=limit ) ) return m_file
async def get_file(self, media_type: int, dc_id: int, document_id: int, access_hash: int, thumb_size: str, peer_id: int, peer_type: str, peer_access_hash: int, volume_id: int, local_id: int, file_ref: str, file_size: int, is_big: bool, progress: callable, progress_args: tuple = ()) -> str: async with self.media_sessions_lock: session = self.media_sessions.get(dc_id, None) if session is None: if dc_id != await self.storage.dc_id(): session = Session(self, dc_id, await Auth(self, dc_id, await self.storage.test_mode()).create(), await self.storage.test_mode(), is_media=True) await session.start() for _ in range(3): exported_auth = await self.send( raw.functions.auth.ExportAuthorization(dc_id=dc_id) ) try: await session.send( raw.functions.auth.ImportAuthorization( id=exported_auth.id, bytes=exported_auth.bytes)) except AuthBytesInvalid: continue else: break else: await session.stop() raise AuthBytesInvalid else: session = Session(self, dc_id, await self.storage.auth_key(), await self.storage.test_mode(), is_media=True) await session.start() self.media_sessions[dc_id] = session file_ref = utils.decode_file_ref(file_ref) if media_type == 1: if peer_type == "user": peer = raw.types.InputPeerUser(user_id=peer_id, access_hash=peer_access_hash) elif peer_type == "chat": peer = raw.types.InputPeerChat(chat_id=peer_id) else: peer = raw.types.InputPeerChannel(channel_id=peer_id, access_hash=peer_access_hash) location = raw.types.InputPeerPhotoFileLocation( peer=peer, volume_id=volume_id, local_id=local_id, big=is_big or None) elif media_type in (0, 2): location = raw.types.InputPhotoFileLocation( id=document_id, access_hash=access_hash, file_reference=file_ref, thumb_size=thumb_size) elif media_type == 14: location = raw.types.InputDocumentFileLocation( id=document_id, access_hash=access_hash, file_reference=file_ref, thumb_size=thumb_size) else: location = raw.types.InputDocumentFileLocation( id=document_id, access_hash=access_hash, file_reference=file_ref, thumb_size="") limit = 1024 * 1024 offset = 0 file_name = "" try: r = await session.send(raw.functions.upload.GetFile( location=location, offset=offset, limit=limit), sleep_threshold=30) if isinstance(r, raw.types.upload.File): with tempfile.NamedTemporaryFile("wb", delete=False) as f: file_name = f.name while True: chunk = r.bytes if not chunk: break f.write(chunk) offset += limit if progress: func = functools.partial( progress, min(offset, file_size) if file_size != 0 else offset, file_size, *progress_args) if inspect.iscoroutinefunction(progress): await func() else: await self.loop.run_in_executor( self.executor, func) r = await session.send(raw.functions.upload.GetFile( location=location, offset=offset, limit=limit), sleep_threshold=30) elif isinstance(r, raw.types.upload.FileCdnRedirect): async with self.media_sessions_lock: cdn_session = self.media_sessions.get(r.dc_id, None) if cdn_session is None: cdn_session = Session( self, r.dc_id, await Auth(self, r.dc_id, await self.storage.test_mode()).create(), await self.storage.test_mode(), is_media=True, is_cdn=True) await cdn_session.start() self.media_sessions[r.dc_id] = cdn_session try: with tempfile.NamedTemporaryFile("wb", delete=False) as f: file_name = f.name while True: r2 = await cdn_session.send( raw.functions.upload.GetCdnFile( file_token=r.file_token, offset=offset, limit=limit)) if isinstance( r2, raw.types.upload.CdnFileReuploadNeeded): try: await session.send( raw.functions.upload.ReuploadCdnFile( file_token=r.file_token, request_token=r2.request_token)) except VolumeLocNotFound: break else: continue chunk = r2.bytes # https://core.telegram.org/cdn#decrypting-files decrypted_chunk = aes.ctr256_decrypt( chunk, r.encryption_key, bytearray(r.encryption_iv[:-4] + (offset // 16).to_bytes(4, "big"))) hashes = await session.send( raw.functions.upload.GetCdnFileHashes( file_token=r.file_token, offset=offset)) # https://core.telegram.org/cdn#verifying-files for i, h in enumerate(hashes): cdn_chunk = decrypted_chunk[h.limit * i:h.limit * (i + 1)] assert h.hash == sha256(cdn_chunk).digest( ), f"Invalid CDN hash part {i}" f.write(decrypted_chunk) offset += limit if progress: func = functools.partial( progress, min(offset, file_size) if file_size != 0 else offset, file_size, *progress_args) if inspect.iscoroutinefunction(progress): await func() else: await self.loop.run_in_executor( self.executor, func) if len(chunk) < limit: break except Exception as e: raise e except Exception as e: if not isinstance(e, pyrogram.StopTransmission): log.error(e, exc_info=True) try: os.remove(file_name) except OSError: pass return "" else: return file_name
async def download_as_bytesio(self, media_msg: Message): client = self.main_bot data = await self.generate_file_properties(media_msg) media_session = await self.generate_media_session(client, media_msg) file_ref = utils.decode_file_ref(data.file_ref) if data.media_type == 1: if data.peer_type == "user": peer = raw.types.InputPeerUser( user_id=data.peer_id, access_hash=data.peer_access_hash) elif data.peer_type == "chat": peer = raw.types.InputPeerChat(chat_id=data.peer_id) else: peer = raw.types.InputPeerChannel( channel_id=data.peer_id, access_hash=data.peer_access_hash) location = raw.types.InputPeerPhotoFileLocation( peer=peer, volume_id=data.volume_id, local_id=data.local_id, big=data.is_big or None) elif data.media_type in (0, 2): location = raw.types.InputPhotoFileLocation( id=data.document_id, access_hash=data.access_hash, file_reference=file_ref, thumb_size=data.thumb_size) elif data.media_type == 14: location = raw.types.InputDocumentFileLocation( id=data.document_id, access_hash=data.access_hash, file_reference=file_ref, thumb_size=data.thumb_size) else: location = raw.types.InputDocumentFileLocation( id=data.document_id, access_hash=data.access_hash, file_reference=file_ref, thumb_size="") limit = 1024 * 1024 offset = 0 r = await media_session.send( raw.functions.upload.GetFile(location=location, offset=offset, limit=limit)) if isinstance(r, raw.types.upload.File): m_file = [] # m_file.name = file_name while True: chunk = r.bytes if not chunk: break m_file.append(chunk) offset += limit r = await media_session.send( raw.functions.upload.GetFile(location=location, offset=offset, limit=limit)) return m_file
async def yield_file(self, media_msg: Message, offset: int, first_part_cut: int, last_part_cut: int, part_count: int, chunk_size: int) -> Union[str, None]: client = self.main_bot data = await self.generate_file_properties(media_msg) media_session = await self.generate_media_session(client, media_msg) current_part = 1 file_ref = utils.decode_file_ref(data.file_ref) if data.media_type == 1: if data.peer_type == "user": peer = raw.types.InputPeerUser( user_id=data.peer_id, access_hash=data.peer_access_hash) elif data.peer_type == "chat": peer = raw.types.InputPeerChat(chat_id=data.peer_id) else: peer = raw.types.InputPeerChannel( channel_id=data.peer_id, access_hash=data.peer_access_hash) location = raw.types.InputPeerPhotoFileLocation( peer=peer, volume_id=data.volume_id, local_id=data.local_id, big=data.is_big or None) elif data.media_type in (0, 2): location = raw.types.InputPhotoFileLocation( id=data.document_id, access_hash=data.access_hash, file_reference=file_ref, thumb_size=data.thumb_size) elif data.media_type == 14: location = raw.types.InputDocumentFileLocation( id=data.document_id, access_hash=data.access_hash, file_reference=file_ref, thumb_size=data.thumb_size) else: location = raw.types.InputDocumentFileLocation( id=data.document_id, access_hash=data.access_hash, file_reference=file_ref, thumb_size="") r = await media_session.send( raw.functions.upload.GetFile(location=location, offset=offset, limit=chunk_size), ) if isinstance(r, raw.types.upload.File): while current_part <= part_count: chunk = r.bytes if not chunk: break offset += chunk_size if part_count == 1: yield chunk[first_part_cut:last_part_cut] break if current_part == 1: yield chunk[first_part_cut:] if 1 < current_part < part_count: yield chunk r = await media_session.send( raw.functions.upload.GetFile(location=location, offset=offset, limit=chunk_size), ) current_part += 1