diff --git a/pyrogram/client.py b/pyrogram/client.py index 28c65c16..df06e94c 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -47,6 +47,7 @@ from pyrogram.storage import Storage, FileStorage, MemoryStorage from pyrogram.types import User, TermsOfService from pyrogram.utils import ainput from .dispatcher import Dispatcher +from .file_id import FileId, FileType, ThumbnailSource from .scaffold import Scaffold log = logging.getLogger(__name__) @@ -493,22 +494,11 @@ class Client(Methods, Scaffold): final_file_path = "" try: - data, directory, file_name, progress, progress_args = packet + file_id, directory, file_name, file_size, progress, progress_args = packet temp_file_path = await self.get_file( - media_type=data.media_type, - dc_id=data.dc_id, - document_id=data.document_id, - access_hash=data.access_hash, - thumb_size=data.thumb_size, - peer_id=data.peer_id, - peer_type=data.peer_type, - peer_access_hash=data.peer_access_hash, - volume_id=data.volume_id, - local_id=data.local_id, - file_ref=data.file_ref, - file_size=data.file_size, - is_big=data.is_big, + file_id=file_id, + file_size=file_size, progress=progress, progress_args=progress_args ) @@ -817,22 +807,13 @@ class Client(Methods, Scaffold): 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_id: FileId, file_size: int, - is_big: bool, progress: callable, progress_args: tuple = () ) -> str: + dc_id = file_id.dc_id + async with self.media_sessions_lock: session = self.media_sessions.get(dc_id, None) @@ -874,49 +855,43 @@ class Client(Methods, Scaffold): self.media_sessions[dc_id] = session - file_ref = utils.decode_file_ref(file_ref) + file_type = file_id.file_type - if media_type == 1: - if peer_type == "user": + if file_type == FileType.CHAT_PHOTO: + if file_id.chat_id > 0: 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 + user_id=file_id.chat_id, + access_hash=file_id.chat_access_hash ) else: - peer = raw.types.InputPeerChannel( - channel_id=peer_id, - access_hash=peer_access_hash - ) + if file_id.chat_access_hash == 0: + peer = raw.types.InputPeerChat( + chat_id=file_id.chat_id + ) + else: + peer = raw.types.InputPeerChannel( + channel_id=file_id.chat_id, + access_hash=file_id.chat_access_hash + ) location = raw.types.InputPeerPhotoFileLocation( peer=peer, - volume_id=volume_id, - local_id=local_id, - big=is_big or None + volume_id=file_id.volume_id, + local_id=file_id.local_id, + big=file_id.thumbnail_source == ThumbnailSource.CHAT_PHOTO_BIG ) - elif media_type in (0, 2): + elif file_type in (FileType.THUMBNAIL, FileType.PHOTO): 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 + id=file_id.media_id, + access_hash=file_id.access_hash, + file_reference=file_id.file_reference, + thumb_size=file_id.thumbnail_size ) else: location = raw.types.InputDocumentFileLocation( - id=document_id, - access_hash=access_hash, - file_reference=file_ref, + id=file_id.media_id, + access_hash=file_id.access_hash, + file_reference=file_id.file_reference, thumb_size="" ) diff --git a/pyrogram/methods/chats/set_chat_photo.py b/pyrogram/methods/chats/set_chat_photo.py index 8ccb123c..0474fd18 100644 --- a/pyrogram/methods/chats/set_chat_photo.py +++ b/pyrogram/methods/chats/set_chat_photo.py @@ -22,6 +22,7 @@ from typing import Union, BinaryIO from pyrogram import raw from pyrogram import utils from pyrogram.scaffold import Scaffold +from pyrogram.file_id import FileType class SetChatPhoto(Scaffold): @@ -30,8 +31,7 @@ class SetChatPhoto(Scaffold): chat_id: Union[int, str], *, photo: Union[str, BinaryIO] = None, - video: Union[str, BinaryIO] = None, - file_ref: str = None + video: Union[str, BinaryIO] = None ) -> bool: """Set a new chat photo or video (H.264/MPEG-4 AVC video, max 5 seconds). @@ -45,19 +45,15 @@ class SetChatPhoto(Scaffold): Unique identifier (int) or username (str) of the target chat. photo (``str`` | ``BinaryIO``, *optional*): - New chat photo. You can pass a :obj:`~pyrogram.types.Photo` file_id (in pair with a valid file_ref), a - file path to upload a new photo from your local machine or a binary file-like object with its attribute + New chat photo. You can pass a :obj:`~pyrogram.types.Photo` file_id, a file path to upload a new photo + from your local machine or a binary file-like object with its attribute ".name" set for in-memory uploads. video (``str`` | ``BinaryIO``, *optional*): - New chat video. You can pass a :obj:`~pyrogram.types.Video` file_id (in pair with a valid file_ref), a - file path to upload a new video from your local machine or a binary file-like object with its attribute + New chat video. You can pass a :obj:`~pyrogram.types.Video` file_id, a file path to upload a new video + from your local machine or a binary file-like object with its attribute ".name" set for in-memory uploads. - file_ref (``str``, *optional*): - A valid file reference obtained by a recently fetched media message. - To be used in combination with a file_id in case a file reference is needed. - Returns: ``bool``: True on success. @@ -71,14 +67,14 @@ class SetChatPhoto(Scaffold): app.set_chat_photo(chat_id, photo="photo.jpg") # Set chat photo using an exiting Photo file_id - app.set_chat_photo(chat_id, photo=photo.file_id, file_ref=photo.file_ref) + app.set_chat_photo(chat_id, photo=photo.file_id) # Set chat video using a local file app.set_chat_photo(chat_id, video="video.mp4") # Set chat photo using an exiting Video file_id - app.set_chat_photo(chat_id, video=video.file_id, file_ref=video.file_ref) + app.set_chat_photo(chat_id, video=video.file_id) """ peer = await self.resolve_peer(chat_id) @@ -89,7 +85,7 @@ class SetChatPhoto(Scaffold): video=await self.save_file(video) ) else: - photo = utils.get_input_media_from_file_id(photo, file_ref, 2) + photo = utils.get_input_media_from_file_id(photo, FileType.PHOTO) photo = raw.types.InputChatPhoto(id=photo.id) else: photo = raw.types.InputChatUploadedPhoto( diff --git a/pyrogram/methods/messages/download_media.py b/pyrogram/methods/messages/download_media.py index c6919809..c2d4d0b4 100644 --- a/pyrogram/methods/messages/download_media.py +++ b/pyrogram/methods/messages/download_media.py @@ -17,51 +17,22 @@ # along with Pyrogram. If not, see . import asyncio -import binascii import os -import struct import time from datetime import datetime from typing import Union from pyrogram import types -from pyrogram import utils -from pyrogram.errors import FileIdInvalid +from pyrogram.file_id import FileId, FileType, PHOTO_TYPES from pyrogram.scaffold import Scaffold DEFAULT_DOWNLOAD_DIR = "downloads/" -class FileData: - def __init__( - self, *, media_type: int = None, dc_id: int = None, document_id: int = None, access_hash: int = None, - thumb_size: str = None, peer_id: int = None, peer_type: str = None, peer_access_hash: int = None, - volume_id: int = None, local_id: int = None, is_big: bool = None, file_size: int = None, mime_type: str = None, - file_name: str = None, date: int = None, file_ref: str = None - ): - self.media_type = media_type - self.dc_id = dc_id - self.document_id = document_id - self.access_hash = access_hash - self.thumb_size = thumb_size - self.peer_id = peer_id - self.peer_type = peer_type - self.peer_access_hash = peer_access_hash - self.volume_id = volume_id - self.local_id = local_id - self.is_big = is_big - self.file_size = file_size - self.mime_type = mime_type - self.file_name = file_name - self.date = date - self.file_ref = file_ref - - class DownloadMedia(Scaffold): async def download_media( self, - message: Union["types.Message", str], - file_ref: str = None, + media: Union["types.Message", str], file_name: str = DEFAULT_DOWNLOAD_DIR, block: bool = True, progress: callable = None, @@ -70,13 +41,9 @@ class DownloadMedia(Scaffold): """Download the media from a message. Parameters: - message (:obj:`~pyrogram.types.Message` | ``str``): - Pass a Message containing the media, the media itself (message.audio, message.video, ...) or - the file id as string. - - file_ref (``str``, *optional*): - A valid file reference obtained by a recently fetched media message. - To be used in combination with a file id in case a file reference is needed. + media (:obj:`~pyrogram.types.Message` | ``str``): + Pass a Message containing the media, the media itself (message.audio, message.video, ...) or a file id + as string. file_name (``str``, *optional*): A custom *file_name* to be used instead of the one provided by Telegram. @@ -133,136 +100,63 @@ class DownloadMedia(Scaffold): app.download_media(message, progress=progress) """ - error_message = "This message doesn't contain any downloadable media" - available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note", "new_chat_photo") + available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note", + "new_chat_photo") - media_file_name = None - file_size = None - mime_type = None - date = None - - if isinstance(message, types.Message): + if isinstance(media, types.Message): for kind in available_media: - media = getattr(message, kind, None) + media = getattr(media, kind, None) if media is not None: break else: - raise ValueError(error_message) - else: - media = message + raise ValueError("This message doesn't contain any downloadable media") if isinstance(media, str): file_id_str = media else: file_id_str = media.file_id - media_file_name = getattr(media, "file_name", "") - file_size = getattr(media, "file_size", None) - mime_type = getattr(media, "mime_type", None) - date = getattr(media, "date", None) - file_ref = getattr(media, "file_ref", None) - data = FileData( - file_name=media_file_name, - file_size=file_size, - mime_type=mime_type, - date=date, - file_ref=file_ref - ) + file_id_obj = FileId.decode(file_id_str) - def get_existing_attributes() -> dict: - return dict(filter(lambda x: x[1] is not None, data.__dict__.items())) - - try: - decoded = utils.decode_file_id(file_id_str) - media_type = decoded[0] - - if media_type == 1: - unpacked = struct.unpack(". -from struct import pack from typing import List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -31,10 +30,11 @@ class Animation(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. width (``int``): Animation width as defined by sender. @@ -66,7 +66,7 @@ class Animation(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, width: int, height: int, duration: int, @@ -79,7 +79,7 @@ class Animation(Object): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.file_name = file_name self.mime_type = mime_type self.file_size = file_size @@ -97,16 +97,17 @@ class Animation(Object): file_name: str ) -> "Animation": return Animation( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -31,14 +30,21 @@ class Audio(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. duration (``int``): Duration of the audio in seconds as defined by sender. + performer (``str``, *optional*): + Performer of the audio as defined by sender or by audio tags. + + title (``str``, *optional*): + Title of the audio as defined by sender or by audio tags. + file_name (``str``, *optional*): Audio file name. @@ -49,13 +55,7 @@ class Audio(Object): File size. date (``int``, *optional*): - Date the audio was sent in Unix time. - - performer (``str``, *optional*): - Performer of the audio as defined by sender or by audio tags. - - title (``str``, *optional*): - Title of the audio as defined by sender or by audio tags. + Date the audio was originally sent, in Unix time. thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Thumbnails of the music file album cover. @@ -66,27 +66,27 @@ class Audio(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, duration: int, + performer: str = None, + title: str = None, file_name: str = None, mime_type: str = None, file_size: int = None, date: int = None, - performer: str = None, - title: str = None, thumbs: List["types.Thumbnail"] = None ): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id + self.duration = duration + self.performer = performer + self.title = title self.file_name = file_name self.mime_type = mime_type self.file_size = file_size self.date = date - self.duration = duration - self.performer = performer - self.title = title self.thumbs = thumbs @staticmethod @@ -97,16 +97,17 @@ class Audio(Object): file_name: str ) -> "Audio": return Audio( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -31,10 +30,11 @@ class Document(Object): Parameters: file_id (``str``): - Unique file identifier. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. file_name (``str``, *optional*): Original filename as defined by sender. @@ -57,7 +57,7 @@ class Document(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, file_name: str = None, mime_type: str = None, file_size: int = None, @@ -67,7 +67,7 @@ class Document(Object): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.file_name = file_name self.mime_type = mime_type self.file_size = file_size @@ -77,16 +77,17 @@ class Document(Object): @staticmethod def _parse(client, document: "raw.types.Document", file_name: str) -> "Document": return Document( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object @@ -31,10 +30,11 @@ class Photo(Object): Parameters: file_id (``str``): - Unique identifier for this photo. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. width (``int``): Photo width. @@ -60,7 +60,7 @@ class Photo(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, width: int, height: int, file_size: int, @@ -71,7 +71,7 @@ class Photo(Object): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.width = width self.height = height self.file_size = file_size @@ -82,18 +82,36 @@ class Photo(Object): @staticmethod def _parse(client, photo: "raw.types.Photo", ttl_seconds: int = None) -> "Photo": if isinstance(photo, raw.types.Photo): - big = list(filter(lambda p: isinstance(p, raw.types.PhotoSize), photo.sizes))[-1] + big = photo.sizes[-1] + + if isinstance(big, raw.types.PhotoSizeProgressive): + big = raw.types.PhotoSize( + type=big.type, + location=big.location, + w=big.w, + h=big.h, + size=big.sizes[-1] + ) return Photo( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import List from async_lru import alru_cache @@ -25,7 +24,7 @@ import pyrogram from pyrogram import raw from pyrogram import types from pyrogram.errors import StickersetInvalid -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -34,10 +33,11 @@ class Sticker(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. width (``int``): Sticker width. @@ -77,7 +77,7 @@ class Sticker(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, width: int, height: int, is_animated: bool, @@ -92,7 +92,7 @@ class Sticker(Object): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.file_name = file_name self.mime_type = mime_type self.file_size = file_size @@ -137,16 +137,17 @@ class Sticker(Object): set_name = None return Sticker( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import Union, List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object @@ -31,7 +30,11 @@ class Thumbnail(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. + + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. width (``int``): Photo width. @@ -48,6 +51,7 @@ class Thumbnail(Object): *, client: "pyrogram.Client" = None, file_id: str, + file_unique_id: str, width: int, height: int, file_size: int @@ -55,6 +59,7 @@ class Thumbnail(Object): super().__init__(client) self.file_id = file_id + self.file_unique_id = file_unique_id self.width = width self.height = height self.file_size = file_size @@ -66,10 +71,8 @@ class Thumbnail(Object): ) -> Union[List[Union["types.StrippedThumbnail", "Thumbnail"]], None]: if isinstance(media, raw.types.Photo): raw_thumbnails = media.sizes[:-1] - media_type = 2 elif isinstance(media, raw.types.Document): raw_thumbnails = media.thumbs - media_type = 14 if not raw_thumbnails: return None @@ -78,6 +81,9 @@ class Thumbnail(Object): thumbnails = [] + file_type = FileType.PHOTO if isinstance(media, raw.types.Photo) else FileType.THUMBNAIL + thumbnail_file_type = file_type + for thumbnail in raw_thumbnails: # TODO: Enable this # if isinstance(thumbnail, types.PhotoStrippedSize): @@ -85,14 +91,24 @@ class Thumbnail(Object): if isinstance(thumbnail, raw.types.PhotoSize): thumbnails.append( Thumbnail( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -31,10 +30,11 @@ class Video(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. width (``int``): Video width as defined by sender. @@ -51,18 +51,18 @@ class Video(Object): mime_type (``str``, *optional*): Mime type of a file as defined by sender. - supports_streaming (``bool``, *optional*): - True, if the video was uploaded with streaming support. - file_size (``int``, *optional*): File size. - date (``int``, *optional*): - Date the video was sent in Unix time. + supports_streaming (``bool``, *optional*): + True, if the video was uploaded with streaming support. ttl_seconds (``int``. *optional*): Time-to-live seconds, for secret photos. + date (``int``, *optional*): + Date the video was sent in Unix time. + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Video thumbnails. """ @@ -72,31 +72,31 @@ class Video(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, width: int, height: int, duration: int, file_name: str = None, mime_type: str = None, - supports_streaming: bool = None, file_size: int = None, - date: int = None, + supports_streaming: bool = None, ttl_seconds: int = None, + date: int = None, thumbs: List["types.Thumbnail"] = None ): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.width = width self.height = height self.duration = duration self.file_name = file_name self.mime_type = mime_type - self.supports_streaming = supports_streaming self.file_size = file_size - self.date = date + self.supports_streaming = supports_streaming self.ttl_seconds = ttl_seconds + self.date = date self.thumbs = thumbs @staticmethod @@ -108,16 +108,17 @@ class Video(Object): ttl_seconds: int = None ) -> "Video": return Video( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import List import pyrogram from pyrogram import raw from pyrogram import types -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -31,10 +30,11 @@ class VideoNote(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. length (``int``): Video width and height as defined by sender. @@ -60,7 +60,7 @@ class VideoNote(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, length: int, duration: int, thumbs: List["types.Thumbnail"] = None, @@ -71,7 +71,7 @@ class VideoNote(Object): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.mime_type = mime_type self.file_size = file_size self.date = date @@ -86,16 +86,17 @@ class VideoNote(Object): video_attributes: "raw.types.DocumentAttributeVideo" ) -> "VideoNote": return VideoNote( - file_id=encode_file_id( - pack( - ". -from struct import pack - import pyrogram from pyrogram import raw -from pyrogram.utils import encode_file_id, encode_file_ref +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType from ..object import Object @@ -29,10 +27,11 @@ class Voice(Object): Parameters: file_id (``str``): - Unique identifier for this file. + Identifier for this file, which can be used to download or reuse the file. - file_ref (``str``): - Up to date file reference. + file_unique_id (``str``): + Unique identifier for this file, which is supposed to be the same over time and for different accounts. + Can't be used to download or reuse the file. duration (``int``): Duration of the audio in seconds as defined by sender. @@ -55,7 +54,7 @@ class Voice(Object): *, client: "pyrogram.Client" = None, file_id: str, - file_ref: str, + file_unique_id: str, duration: int, waveform: bytes = None, mime_type: str = None, @@ -65,7 +64,7 @@ class Voice(Object): super().__init__(client) self.file_id = file_id - self.file_ref = file_ref + self.file_unique_id = file_unique_id self.duration = duration self.waveform = waveform self.mime_type = mime_type @@ -75,16 +74,17 @@ class Voice(Object): @staticmethod def _parse(client, voice: "raw.types.Document", attributes: "raw.types.DocumentAttributeAudio") -> "Voice": return Voice( - file_id=encode_file_id( - pack( - ". -from struct import pack from typing import Union import pyrogram from pyrogram import raw -from pyrogram.utils import encode_file_id +from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from ..object import Object -from ... import utils class ChatPhoto(Object): @@ -34,9 +32,17 @@ class ChatPhoto(Object): File identifier of small (160x160) chat photo. This file_id can be used only for photo download and only for as long as the photo is not changed. + small_photo_unique_id (``str``): + Unique file identifier of small (160x160) chat photo, which is supposed to be the same over time and for + different accounts. Can't be used to download or reuse the file. + big_file_id (``str``): File identifier of big (640x640) chat photo. This file_id can be used only for photo download and only for as long as the photo is not changed. + + big_photo_unique_id (``str``): + Unique file identifier of big (640x640) chat photo, which is supposed to be the same over time and for + different accounts. Can't be used to download or reuse the file. """ def __init__( @@ -44,12 +50,17 @@ class ChatPhoto(Object): *, client: "pyrogram.Client" = None, small_file_id: str, - big_file_id: str + small_photo_unique_id: str, + big_file_id: str, + big_photo_unique_id: str + ): super().__init__(client) self.small_file_id = small_file_id + self.small_photo_unique_id = small_photo_unique_id self.big_file_id = big_file_id + self.big_photo_unique_id = big_photo_unique_id @staticmethod def _parse( @@ -61,39 +72,40 @@ class ChatPhoto(Object): if not isinstance(chat_photo, (raw.types.UserProfilePhoto, raw.types.ChatPhoto)): return None - if peer_access_hash is None: - return None - - photo_id = getattr(chat_photo, "photo_id", 0) - loc_small = chat_photo.photo_small - loc_big = chat_photo.photo_big - - peer_type = utils.get_peer_type(peer_id) - - if peer_type == "user": - x = 0 - elif peer_type == "chat": - x = -1 - else: - peer_id += 1000727379968 - x = -234 + media_id = chat_photo.photo_id if isinstance(chat_photo, raw.types.UserProfilePhoto) else 0 return ChatPhoto( - small_file_id=encode_file_id( - pack( - " bytes: - s = base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) - r = b"" - - major = s[-1] - minor = s[-2] if major != 2 else 0 - - assert minor in (0, 22, 24) - - skip = 2 if minor else 1 - - i = 0 - - while i < len(s) - skip: - if s[i] != 0: - r += bytes([s[i]]) - else: - r += b"\x00" * s[i + 1] - i += 1 - - i += 1 - - return r - - -def encode_file_id(s: bytes) -> str: - r = b"" - n = 0 - - for i in s + bytes([22]) + bytes([4]): - if i == 0: - n += 1 - else: - if n: - r += b"\x00" + bytes([n]) - n = 0 - - r += bytes([i]) - - return base64.urlsafe_b64encode(r).decode().rstrip("=") - - -def encode_file_ref(file_ref: bytes) -> str: - return base64.urlsafe_b64encode(file_ref).decode().rstrip("=") - - -def decode_file_ref(file_ref: str) -> bytes: - if file_ref is None: - return b"" - - return base64.urlsafe_b64decode(file_ref + "=" * (-len(file_ref) % 4)) +from pyrogram.file_id import FileId, FileType, PHOTO_TYPES, DOCUMENT_TYPES async def ainput(prompt: str = "", *, hide: bool = False): @@ -102,52 +49,38 @@ def get_offset_date(dialogs): def get_input_media_from_file_id( - file_id_str: str, - file_ref: str = None, - expected_media_type: int = None + file_id: str, + expected_file_type: FileType = None ) -> Union["raw.types.InputMediaPhoto", "raw.types.InputMediaDocument"]: - try: - decoded = decode_file_id(file_id_str) - except Exception: - raise ValueError(f"Failed to decode file_id: {file_id_str}") - else: - media_type = decoded[0] + decoded = FileId.decode(file_id) - if expected_media_type is not None: - if media_type != expected_media_type: - media_type_str = Scaffold.MEDIA_TYPE_ID.get(media_type, None) - expected_media_type_str = Scaffold.MEDIA_TYPE_ID.get(expected_media_type, None) + file_type = decoded.file_type - raise ValueError(f'Expected: "{expected_media_type_str}", got "{media_type_str}" file_id instead') + if expected_file_type is not None and file_type != expected_file_type: + raise ValueError(f'Expected: "{expected_file_type}", got "{file_type}" file_id instead') - if media_type in (0, 1, 14): - raise ValueError(f"This file_id can only be used for download: {file_id_str}") + if file_type in (FileType.THUMBNAIL, FileType.CHAT_PHOTO): + raise ValueError(f"This file_id can only be used for download: {file_id}") - if media_type == 2: - unpacked = struct.unpack(" List["types.Message"]: