Example #1
0
    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
Example #2
0
    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
Example #3
0
    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