diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index dec0ffa4..77531e9b 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -127,4 +127,6 @@ BUTTON_URL_INVALID The button url is invalid AUTH_BYTES_INVALID The authorization bytes are invalid CHANNELS_TOO_MUCH You have joined too many channels or supergroups ADMIN_RANK_INVALID The custom administrator title is invalid or is longer than 16 characters -ADMIN_RANK_EMOJI_NOT_ALLOWED Emojis are not allowed in custom administrator titles \ No newline at end of file +ADMIN_RANK_EMOJI_NOT_ALLOWED Emojis are not allowed in custom administrator titles +FILE_REFERENCE_EMPTY The file reference is empty +FILE_REFERENCE_INVALID The file reference is invalid \ No newline at end of file diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py index c8da0a60..cb1abcaa 100644 --- a/pyrogram/client/client.py +++ b/pyrogram/client/client.py @@ -1235,6 +1235,7 @@ class Client(Methods, BaseClient): 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, progress=progress, @@ -1888,7 +1889,7 @@ class Client(Methods, BaseClient): peer_id: int, peer_access_hash: int, volume_id: int, local_id: int, - file_size: int, + file_ref: str,file_size: int, is_big: bool, progress: callable, @@ -1928,6 +1929,8 @@ class Client(Methods, BaseClient): self.media_sessions[dc_id] = session + file_ref = utils.decode_file_ref(file_ref) + if media_type == 1: location = types.InputPeerPhotoFileLocation( peer=types.InputPeerUser( @@ -1942,21 +1945,21 @@ class Client(Methods, BaseClient): location = types.InputPhotoFileLocation( id=document_id, access_hash=access_hash, - file_reference=b"", + file_reference=file_ref, thumb_size=thumb_size ) elif media_type == 14: location = types.InputDocumentFileLocation( id=document_id, access_hash=access_hash, - file_reference=b"", + file_reference=file_ref, thumb_size=thumb_size ) else: location = types.InputDocumentFileLocation( id=document_id, access_hash=access_hash, - file_reference=b"", + file_reference=file_ref, thumb_size="" ) diff --git a/pyrogram/client/ext/file_data.py b/pyrogram/client/ext/file_data.py index ad1da9b6..ae023d18 100644 --- a/pyrogram/client/ext/file_data.py +++ b/pyrogram/client/ext/file_data.py @@ -22,7 +22,7 @@ class FileData: 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_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 + date: int = None, file_ref: str = None ): self.media_type = media_type self.dc_id = dc_id @@ -38,3 +38,4 @@ class FileData: self.mime_type = mime_type self.file_name = file_name self.date = date + self.file_ref = file_ref diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index ce708786..16f44e2d 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -30,7 +30,7 @@ from . import BaseClient from ...api import types -def decode(s: str) -> bytes: +def decode_file_id(s: str) -> bytes: s = base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) r = b"" @@ -56,7 +56,7 @@ def decode(s: str) -> bytes: return r -def encode(s: bytes) -> str: +def encode_file_id(s: bytes) -> str: r = b"" n = 0 @@ -73,6 +73,17 @@ def encode(s: bytes) -> str: 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)) + + async def ainput(prompt: str = ""): print(prompt, end="", flush=True) @@ -94,10 +105,11 @@ 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 ) -> Union[types.InputMediaPhoto, types.InputMediaDocument]: try: - decoded = decode(file_id_str) + decoded = decode_file_id(file_id_str) except Exception: raise ValueError("Failed to decode file_id: {}".format(file_id_str)) else: @@ -123,7 +135,7 @@ def get_input_media_from_file_id( id=types.InputPhoto( id=file_id, access_hash=access_hash, - file_reference=b"" + file_reference=decode_file_ref(file_ref) ) ) @@ -135,7 +147,7 @@ def get_input_media_from_file_id( id=types.InputDocument( id=file_id, access_hash=access_hash, - file_reference=b"" + file_reference=decode_file_ref(file_ref) ) ) diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/client/methods/messages/download_media.py index 099e3107..d55426cd 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/client/methods/messages/download_media.py @@ -36,6 +36,7 @@ class DownloadMedia(BaseClient): async def download_media( self, message: Union["pyrogram.Message", str], + file_ref: str = None, file_name: str = DEFAULT_DOWNLOAD_DIR, block: bool = True, progress: callable = None, @@ -48,6 +49,10 @@ class DownloadMedia(BaseClient): 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. + file_name (``str``, *optional*): A custom *file_name* to be used instead of the one provided by Telegram. By default, all files are downloaded in the *downloads* folder in your working directory. @@ -123,19 +128,21 @@ class DownloadMedia(BaseClient): 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 + date=date, + file_ref=file_ref ) def get_existing_attributes() -> dict: return dict(filter(lambda x: x[1] is not None, data.__dict__.items())) try: - decoded = utils.decode(file_id_str) + decoded = utils.decode_file_id(file_id_str) media_type = decoded[0] if media_type == 1: diff --git a/pyrogram/client/methods/messages/edit_inline_media.py b/pyrogram/client/methods/messages/edit_inline_media.py index 8cb94d2e..473f7ec9 100644 --- a/pyrogram/client/methods/messages/edit_inline_media.py +++ b/pyrogram/client/methods/messages/edit_inline_media.py @@ -77,35 +77,35 @@ class EditInlineMedia(BaseClient): url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 2) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 2) elif isinstance(media, InputMediaVideo): if media.media.startswith("http"): media = types.InputMediaDocumentExternal( url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 4) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 4) elif isinstance(media, InputMediaAudio): if media.media.startswith("http"): media = types.InputMediaDocumentExternal( url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 9) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 9) elif isinstance(media, InputMediaAnimation): if media.media.startswith("http"): media = types.InputMediaDocumentExternal( url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 10) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 10) elif isinstance(media, InputMediaDocument): if media.media.startswith("http"): media = types.InputMediaDocumentExternal( url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 5) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 5) return await self.send( functions.messages.EditInlineBotMessage( diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py index a4b6f218..579e3c44 100644 --- a/pyrogram/client/methods/messages/edit_message_media.py +++ b/pyrogram/client/methods/messages/edit_message_media.py @@ -100,7 +100,7 @@ class EditMessageMedia(BaseClient): url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 2) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 2) elif isinstance(media, InputMediaVideo): if os.path.exists(media.media): media = await self.send( @@ -137,7 +137,7 @@ class EditMessageMedia(BaseClient): url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 4) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 4) elif isinstance(media, InputMediaAudio): if os.path.exists(media.media): media = await self.send( @@ -173,7 +173,7 @@ class EditMessageMedia(BaseClient): url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 9) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 9) elif isinstance(media, InputMediaAnimation): if os.path.exists(media.media): media = await self.send( @@ -211,7 +211,7 @@ class EditMessageMedia(BaseClient): url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 10) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 10) elif isinstance(media, InputMediaDocument): if os.path.exists(media.media): media = await self.send( @@ -242,7 +242,7 @@ class EditMessageMedia(BaseClient): url=media.media ) else: - media = utils.get_input_media_from_file_id(media.media, 5) + media = utils.get_input_media_from_file_id(media.media, media.file_ref, 5) r = await self.send( functions.messages.EditMessage( diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py index 6ff4453c..0b16bccc 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/client/methods/messages/send_animation.py @@ -30,6 +30,7 @@ class SendAnimation(BaseClient): self, chat_id: Union[int, str], animation: str, + file_ref: str = None, caption: str = "", unsave: bool = False, parse_mode: Union[str, None] = object, @@ -63,6 +64,10 @@ class SendAnimation(BaseClient): pass an HTTP URL as a string for Telegram to get an animation from the Internet, or pass a file path as string to upload a new animation that exists on your local machine. + 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. + caption (``str``, *optional*): Animation caption, 0-1024 characters. @@ -176,7 +181,7 @@ class SendAnimation(BaseClient): url=animation ) else: - media = utils.get_input_media_from_file_id(animation, 10) + media = utils.get_input_media_from_file_id(animation, file_ref, 10) while True: try: @@ -209,7 +214,7 @@ class SendAnimation(BaseClient): if unsave: document = message.animation or message.document - document_id = utils.get_input_media_from_file_id(document.file_id).id + document_id = utils.get_input_media_from_file_id(document.file_id, document.file_ref).id await self.send( functions.messages.SaveGif( diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py index ab416728..495cb52a 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/client/methods/messages/send_audio.py @@ -30,6 +30,7 @@ class SendAudio(BaseClient): self, chat_id: Union[int, str], audio: str, + file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, @@ -63,6 +64,10 @@ class SendAudio(BaseClient): pass an HTTP URL as a string for Telegram to get an audio file from the Internet, or pass a file path as string to upload a new audio file that exists on your local machine. + 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. + caption (``str``, *optional*): Audio caption, 0-1024 characters. @@ -173,7 +178,7 @@ class SendAudio(BaseClient): url=audio ) else: - media = utils.get_input_media_from_file_id(audio, 9) + media = utils.get_input_media_from_file_id(audio, file_ref, 9) while True: try: diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py index 46f81268..1ec62f5d 100644 --- a/pyrogram/client/methods/messages/send_cached_media.py +++ b/pyrogram/client/methods/messages/send_cached_media.py @@ -28,6 +28,7 @@ class SendCachedMedia(BaseClient): self, chat_id: Union[int, str], file_id: str, + file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, disable_notification: bool = None, @@ -56,6 +57,10 @@ class SendCachedMedia(BaseClient): Media to send. Pass a file_id as string to send a media that exists on the Telegram servers. + 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. + caption (``bool``, *optional*): Media caption, 0-1024 characters. @@ -92,7 +97,7 @@ class SendCachedMedia(BaseClient): r = await self.send( functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=utils.get_input_media_from_file_id(file_id), + media=utils.get_input_media_from_file_id(file_id, file_ref), silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py index 3143457d..e2522fd9 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/client/methods/messages/send_document.py @@ -30,6 +30,7 @@ class SendDocument(BaseClient): self, chat_id: Union[int, str], document: str, + file_ref: str = None, thumb: str = None, caption: str = "", parse_mode: Union[str, None] = object, @@ -59,6 +60,10 @@ class SendDocument(BaseClient): pass an HTTP URL as a string for Telegram to get a file from the Internet, or pass a file path as string to upload a new file that exists on your local machine. + 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. + thumb (``str``, *optional*): Thumbnail of the file sent. The thumbnail should be in JPEG format and less than 200 KB in size. @@ -149,7 +154,7 @@ class SendDocument(BaseClient): url=document ) else: - media = utils.get_input_media_from_file_id(document, 5) + media = utils.get_input_media_from_file_id(document, file_ref, 5) while True: try: diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py index 1e16d0d3..ae92c409 100644 --- a/pyrogram/client/methods/messages/send_media_group.py +++ b/pyrogram/client/methods/messages/send_media_group.py @@ -119,7 +119,7 @@ class SendMediaGroup(BaseClient): ) ) else: - media = utils.get_input_media_from_file_id(i.media, 2) + media = utils.get_input_media_from_file_id(i.media, i.file_ref, 2) elif isinstance(i, pyrogram.InputMediaVideo): if os.path.exists(i.media): while True: @@ -174,7 +174,7 @@ class SendMediaGroup(BaseClient): ) ) else: - media = utils.get_input_media_from_file_id(i.media, 4) + media = utils.get_input_media_from_file_id(i.media, i.file_ref, 4) multi_media.append( types.InputSingleMedia( diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py index 3ec2f5b4..93e85092 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/client/methods/messages/send_photo.py @@ -30,6 +30,7 @@ class SendPhoto(BaseClient): self, chat_id: Union[int, str], photo: str, + file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, ttl_seconds: int = None, @@ -59,6 +60,10 @@ class SendPhoto(BaseClient): pass an HTTP URL as a string for Telegram to get a photo from the Internet, or pass a file path as string to upload a new photo that exists on your local machine. + 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. + caption (``bool``, *optional*): Photo caption, 0-1024 characters. @@ -144,7 +149,7 @@ class SendPhoto(BaseClient): ttl_seconds=ttl_seconds ) else: - media = utils.get_input_media_from_file_id(photo, 2) + media = utils.get_input_media_from_file_id(photo, file_ref, 2) while True: try: diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py index 5759fc18..8f7e853a 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/client/methods/messages/send_sticker.py @@ -30,6 +30,7 @@ class SendSticker(BaseClient): self, chat_id: Union[int, str], sticker: str, + file_ref: str = None, disable_notification: bool = None, reply_to_message_id: int = None, schedule_date: int = None, @@ -56,6 +57,10 @@ class SendSticker(BaseClient): pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, or pass a file path as string to upload a new sticker that exists on your local machine. + 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. + disable_notification (``bool``, *optional*): Sends the message silently. Users will receive a notification with no sound. @@ -122,7 +127,7 @@ class SendSticker(BaseClient): url=sticker ) else: - media = utils.get_input_media_from_file_id(sticker, 8) + media = utils.get_input_media_from_file_id(sticker, file_ref, 8) while True: try: diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py index 57e32944..d48ea803 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/client/methods/messages/send_video.py @@ -30,6 +30,7 @@ class SendVideo(BaseClient): self, chat_id: Union[int, str], video: str, + file_ref: str = None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, @@ -63,6 +64,10 @@ class SendVideo(BaseClient): pass an HTTP URL as a string for Telegram to get a video from the Internet, or pass a file path as string to upload a new video that exists on your local machine. + 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. + caption (``str``, *optional*): Video caption, 0-1024 characters. @@ -172,7 +177,7 @@ class SendVideo(BaseClient): url=video ) else: - media = utils.get_input_media_from_file_id(video, 4) + media = utils.get_input_media_from_file_id(video, file_ref, 4) while True: try: diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py index 164b60b7..070fc048 100644 --- a/pyrogram/client/methods/messages/send_video_note.py +++ b/pyrogram/client/methods/messages/send_video_note.py @@ -30,6 +30,7 @@ class SendVideoNote(BaseClient): self, chat_id: Union[int, str], video_note: str, + file_ref: str = None, duration: int = 0, length: int = 1, thumb: str = None, @@ -59,6 +60,10 @@ class SendVideoNote(BaseClient): pass a file path as string to upload a new video note that exists on your local machine. Sending video notes by a URL is currently unsupported. + 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. + duration (``int``, *optional*): Duration of sent video in seconds. @@ -140,7 +145,7 @@ class SendVideoNote(BaseClient): ] ) else: - media = utils.get_input_media_from_file_id(video_note, 13) + media = utils.get_input_media_from_file_id(video_note, file_ref, 13) while True: try: diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py index e8326e8d..dbe30568 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/client/methods/messages/send_voice.py @@ -30,6 +30,7 @@ class SendVoice(BaseClient): self, chat_id: Union[int, str], voice: str, + file_ref=None, caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, @@ -59,6 +60,10 @@ class SendVoice(BaseClient): pass an HTTP URL as a string for Telegram to get an audio from the Internet, or pass a file path as string to upload a new audio that exists on your local machine. + 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. + caption (``str``, *optional*): Voice message caption, 0-1024 characters. @@ -144,7 +149,7 @@ class SendVoice(BaseClient): url=voice ) else: - media = utils.get_input_media_from_file_id(voice, 3) + media = utils.get_input_media_from_file_id(voice, file_ref, 3) while True: try: diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/client/methods/users/delete_profile_photos.py index 6b96e0bb..8ae736de 100644 --- a/pyrogram/client/methods/users/delete_profile_photos.py +++ b/pyrogram/client/methods/users/delete_profile_photos.py @@ -55,7 +55,7 @@ class DeleteProfilePhotos(BaseClient): input_photos = [] for photo_id in photo_ids: - unpacked = unpack(" "Animation": return Animation( - file_id=encode( + file_id=encode_file_id( pack( " "Audio": return Audio( - file_id=encode( + file_id=encode_file_id( pack( " "Document": return Document( - file_id=encode( + file_id=encode_file_id( pack( " "Video": return Video( - file_id=encode( + file_id=encode_file_id( pack( " "VideoNote": return VideoNote( - file_id=encode( + file_id=encode_file_id( pack( " "Voice": return Voice( - file_id=encode( + file_id=encode_file_id( pack( "