2
0
mirror of https://github.com/pyrogram/pyrogram synced 2025-08-29 05:18:10 +00:00

Add support for the new Bot API fields: file_id, file_unique_id

Remove file_ref from Pyrogram's API
This commit is contained in:
Dan 2020-11-27 22:09:17 +01:00
parent e0c3578fbb
commit a4566de2ef
34 changed files with 398 additions and 667 deletions

View File

@ -47,6 +47,7 @@ from pyrogram.storage import Storage, FileStorage, MemoryStorage
from pyrogram.types import User, TermsOfService from pyrogram.types import User, TermsOfService
from pyrogram.utils import ainput from pyrogram.utils import ainput
from .dispatcher import Dispatcher from .dispatcher import Dispatcher
from .file_id import FileId, FileType, ThumbnailSource
from .scaffold import Scaffold from .scaffold import Scaffold
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -493,22 +494,11 @@ class Client(Methods, Scaffold):
final_file_path = "" final_file_path = ""
try: 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( temp_file_path = await self.get_file(
media_type=data.media_type, file_id=file_id,
dc_id=data.dc_id, file_size=file_size,
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,
progress=progress, progress=progress,
progress_args=progress_args progress_args=progress_args
) )
@ -817,22 +807,13 @@ class Client(Methods, Scaffold):
async def get_file( async def get_file(
self, self,
media_type: int, file_id: FileId,
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, file_size: int,
is_big: bool,
progress: callable, progress: callable,
progress_args: tuple = () progress_args: tuple = ()
) -> str: ) -> str:
dc_id = file_id.dc_id
async with self.media_sessions_lock: async with self.media_sessions_lock:
session = self.media_sessions.get(dc_id, None) session = self.media_sessions.get(dc_id, None)
@ -874,49 +855,43 @@ class Client(Methods, Scaffold):
self.media_sessions[dc_id] = session 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 file_type == FileType.CHAT_PHOTO:
if peer_type == "user": if file_id.chat_id > 0:
peer = raw.types.InputPeerUser( peer = raw.types.InputPeerUser(
user_id=peer_id, user_id=file_id.chat_id,
access_hash=peer_access_hash access_hash=file_id.chat_access_hash
)
elif peer_type == "chat":
peer = raw.types.InputPeerChat(
chat_id=peer_id
) )
else: else:
peer = raw.types.InputPeerChannel( if file_id.chat_access_hash == 0:
channel_id=peer_id, peer = raw.types.InputPeerChat(
access_hash=peer_access_hash 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( location = raw.types.InputPeerPhotoFileLocation(
peer=peer, peer=peer,
volume_id=volume_id, volume_id=file_id.volume_id,
local_id=local_id, local_id=file_id.local_id,
big=is_big or None 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( location = raw.types.InputPhotoFileLocation(
id=document_id, id=file_id.media_id,
access_hash=access_hash, access_hash=file_id.access_hash,
file_reference=file_ref, file_reference=file_id.file_reference,
thumb_size=thumb_size thumb_size=file_id.thumbnail_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: else:
location = raw.types.InputDocumentFileLocation( location = raw.types.InputDocumentFileLocation(
id=document_id, id=file_id.media_id,
access_hash=access_hash, access_hash=file_id.access_hash,
file_reference=file_ref, file_reference=file_id.file_reference,
thumb_size="" thumb_size=""
) )

View File

@ -22,6 +22,7 @@ from typing import Union, BinaryIO
from pyrogram import raw from pyrogram import raw
from pyrogram import utils from pyrogram import utils
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
from pyrogram.file_id import FileType
class SetChatPhoto(Scaffold): class SetChatPhoto(Scaffold):
@ -30,8 +31,7 @@ class SetChatPhoto(Scaffold):
chat_id: Union[int, str], chat_id: Union[int, str],
*, *,
photo: Union[str, BinaryIO] = None, photo: Union[str, BinaryIO] = None,
video: Union[str, BinaryIO] = None, video: Union[str, BinaryIO] = None
file_ref: str = None
) -> bool: ) -> bool:
"""Set a new chat photo or video (H.264/MPEG-4 AVC video, max 5 seconds). """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. Unique identifier (int) or username (str) of the target chat.
photo (``str`` | ``BinaryIO``, *optional*): 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 New chat photo. You can pass a :obj:`~pyrogram.types.Photo` file_id, a file path to upload a new photo
file path to upload a new photo from your local machine or a binary file-like object with its attribute from your local machine or a binary file-like object with its attribute
".name" set for in-memory uploads. ".name" set for in-memory uploads.
video (``str`` | ``BinaryIO``, *optional*): 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 New chat video. You can pass a :obj:`~pyrogram.types.Video` file_id, a file path to upload a new video
file path to upload a new video from your local machine or a binary file-like object with its attribute from your local machine or a binary file-like object with its attribute
".name" set for in-memory uploads. ".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: Returns:
``bool``: True on success. ``bool``: True on success.
@ -71,14 +67,14 @@ class SetChatPhoto(Scaffold):
app.set_chat_photo(chat_id, photo="photo.jpg") app.set_chat_photo(chat_id, photo="photo.jpg")
# Set chat photo using an exiting Photo file_id # 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 # Set chat video using a local file
app.set_chat_photo(chat_id, video="video.mp4") app.set_chat_photo(chat_id, video="video.mp4")
# Set chat photo using an exiting Video file_id # 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) peer = await self.resolve_peer(chat_id)
@ -89,7 +85,7 @@ class SetChatPhoto(Scaffold):
video=await self.save_file(video) video=await self.save_file(video)
) )
else: 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) photo = raw.types.InputChatPhoto(id=photo.id)
else: else:
photo = raw.types.InputChatUploadedPhoto( photo = raw.types.InputChatUploadedPhoto(

View File

@ -17,51 +17,22 @@
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import asyncio import asyncio
import binascii
import os import os
import struct
import time import time
from datetime import datetime from datetime import datetime
from typing import Union from typing import Union
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram.file_id import FileId, FileType, PHOTO_TYPES
from pyrogram.errors import FileIdInvalid
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
DEFAULT_DOWNLOAD_DIR = "downloads/" 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): class DownloadMedia(Scaffold):
async def download_media( async def download_media(
self, self,
message: Union["types.Message", str], media: Union["types.Message", str],
file_ref: str = None,
file_name: str = DEFAULT_DOWNLOAD_DIR, file_name: str = DEFAULT_DOWNLOAD_DIR,
block: bool = True, block: bool = True,
progress: callable = None, progress: callable = None,
@ -70,13 +41,9 @@ class DownloadMedia(Scaffold):
"""Download the media from a message. """Download the media from a message.
Parameters: Parameters:
message (:obj:`~pyrogram.types.Message` | ``str``): media (:obj:`~pyrogram.types.Message` | ``str``):
Pass a Message containing the media, the media itself (message.audio, message.video, ...) or Pass a Message containing the media, the media itself (message.audio, message.video, ...) or a file id
the file id as string. 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*): file_name (``str``, *optional*):
A custom *file_name* to be used instead of the one provided by Telegram. 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) 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",
available_media = ("audio", "document", "photo", "sticker", "animation", "video", "voice", "video_note", "new_chat_photo") "new_chat_photo")
media_file_name = None if isinstance(media, types.Message):
file_size = None
mime_type = None
date = None
if isinstance(message, types.Message):
for kind in available_media: for kind in available_media:
media = getattr(message, kind, None) media = getattr(media, kind, None)
if media is not None: if media is not None:
break break
else: else:
raise ValueError(error_message) raise ValueError("This message doesn't contain any downloadable media")
else:
media = message
if isinstance(media, str): if isinstance(media, str):
file_id_str = media file_id_str = media
else: else:
file_id_str = media.file_id 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_id_obj = FileId.decode(file_id_str)
file_name=media_file_name,
file_size=file_size,
mime_type=mime_type,
date=date,
file_ref=file_ref
)
def get_existing_attributes() -> dict: file_type = file_id_obj.file_type
return dict(filter(lambda x: x[1] is not None, data.__dict__.items())) media_file_name = getattr(media, "file_name", "")
file_size = getattr(media, "file_size", 0)
try: mime_type = getattr(media, "mime_type", None)
decoded = utils.decode_file_id(file_id_str) date = getattr(media, "date", 0)
media_type = decoded[0]
if media_type == 1:
unpacked = struct.unpack("<iiqqqiiiqi", decoded)
dc_id, photo_id, _, volume_id, size_type, peer_id, x, peer_access_hash, local_id = unpacked[1:]
if x == 0:
peer_type = "user"
elif x == -1:
peer_id = -peer_id
peer_type = "chat"
else:
peer_id = utils.get_channel_id(peer_id - 1000727379968)
peer_type = "channel"
data = FileData(
**get_existing_attributes(),
media_type=media_type,
dc_id=dc_id,
peer_id=peer_id,
peer_type=peer_type,
peer_access_hash=peer_access_hash,
volume_id=volume_id,
local_id=local_id,
is_big=size_type == 3
)
elif media_type in (0, 2, 14):
unpacked = struct.unpack("<iiqqqiiii", decoded)
dc_id, document_id, access_hash, volume_id, _, _, thumb_size, local_id = unpacked[1:]
data = FileData(
**get_existing_attributes(),
media_type=media_type,
dc_id=dc_id,
document_id=document_id,
access_hash=access_hash,
thumb_size=chr(thumb_size)
)
elif media_type in (3, 4, 5, 8, 9, 10, 13):
unpacked = struct.unpack("<iiqq", decoded)
dc_id, document_id, access_hash = unpacked[1:]
data = FileData(
**get_existing_attributes(),
media_type=media_type,
dc_id=dc_id,
document_id=document_id,
access_hash=access_hash
)
else:
raise ValueError(f"Unknown media type: {file_id_str}")
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
directory, file_name = os.path.split(file_name) directory, file_name = os.path.split(file_name)
file_name = file_name or data.file_name or "" file_name = file_name or media_file_name or ""
if not os.path.isabs(file_name): if not os.path.isabs(file_name):
directory = self.PARENT_DIR / (directory or DEFAULT_DOWNLOAD_DIR) directory = self.PARENT_DIR / (directory or DEFAULT_DOWNLOAD_DIR)
media_type_str = self.MEDIA_TYPE_ID[data.media_type]
if not file_name: if not file_name:
guessed_extension = self.guess_extension(data.mime_type) guessed_extension = self.guess_extension(mime_type)
if data.media_type in (0, 1, 2, 14): if file_type in PHOTO_TYPES:
extension = ".jpg" extension = ".jpg"
elif data.media_type == 3: elif file_type == FileType.VOICE:
extension = guessed_extension or ".ogg" extension = guessed_extension or ".ogg"
elif data.media_type in (4, 10, 13): elif file_type in (FileType.VIDEO, FileType.ANIMATION, FileType.VIDEO_NOTE):
extension = guessed_extension or ".mp4" extension = guessed_extension or ".mp4"
elif data.media_type == 5: elif file_type == FileType.DOCUMENT:
extension = guessed_extension or ".zip" extension = guessed_extension or ".zip"
elif data.media_type == 8: elif file_type == FileType.STICKER:
extension = guessed_extension or ".webp" extension = guessed_extension or ".webp"
elif data.media_type == 9: elif file_type == FileType.AUDIO:
extension = guessed_extension or ".mp3" extension = guessed_extension or ".mp3"
else: else:
extension = ".unknown" extension = ".unknown"
file_name = "{}_{}_{}{}".format( file_name = "{}_{}_{}{}".format(
media_type_str, FileType(file_id_obj.file_type).name.lower(),
datetime.fromtimestamp(data.date or time.time()).strftime("%Y-%m-%d_%H-%M-%S"), datetime.fromtimestamp(date or time.time()).strftime("%Y-%m-%d_%H-%M-%S"),
self.rnd_id(), self.rnd_id(),
extension extension
) )
downloader = self.handle_download((data, directory, file_name, progress, progress_args)) downloader = self.handle_download((file_id_obj, directory, file_name, file_size, progress, progress_args))
if block: if block:
return await downloader return await downloader

View File

@ -23,6 +23,7 @@ from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
from .inline_session import get_session from .inline_session import get_session
from pyrogram.file_id import FileType
class EditInlineMedia(Scaffold): class EditInlineMedia(Scaffold):
@ -76,35 +77,35 @@ class EditInlineMedia(Scaffold):
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 2) media = utils.get_input_media_from_file_id(media.media, FileType.PHOTO)
elif isinstance(media, types.InputMediaVideo): elif isinstance(media, types.InputMediaVideo):
if re.match("^https?://", media.media): if re.match("^https?://", media.media):
media = raw.types.InputMediaDocumentExternal( media = raw.types.InputMediaDocumentExternal(
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 4) media = utils.get_input_media_from_file_id(media.media, FileType.VIDEO)
elif isinstance(media, types.InputMediaAudio): elif isinstance(media, types.InputMediaAudio):
if re.match("^https?://", media.media): if re.match("^https?://", media.media):
media = raw.types.InputMediaDocumentExternal( media = raw.types.InputMediaDocumentExternal(
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 9) media = utils.get_input_media_from_file_id(media.media, FileType.AUDIO)
elif isinstance(media, types.InputMediaAnimation): elif isinstance(media, types.InputMediaAnimation):
if re.match("^https?://", media.media): if re.match("^https?://", media.media):
media = raw.types.InputMediaDocumentExternal( media = raw.types.InputMediaDocumentExternal(
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 10) media = utils.get_input_media_from_file_id(media.media, FileType.ANIMATION)
elif isinstance(media, types.InputMediaDocument): elif isinstance(media, types.InputMediaDocument):
if re.match("^https?://", media.media): if re.match("^https?://", media.media):
media = raw.types.InputMediaDocumentExternal( media = raw.types.InputMediaDocumentExternal(
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 5) media = utils.get_input_media_from_file_id(media.media, FileType.DOCUMENT)
unpacked = utils.unpack_inline_message_id(inline_message_id) unpacked = utils.unpack_inline_message_id(inline_message_id)
dc_id = unpacked.dc_id dc_id = unpacked.dc_id

View File

@ -23,6 +23,7 @@ from typing import Union
from pyrogram import raw from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -102,7 +103,7 @@ class EditMessageMedia(Scaffold):
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 2) media = utils.get_input_media_from_file_id(media.media, FileType.PHOTO)
elif isinstance(media, types.InputMediaVideo): elif isinstance(media, types.InputMediaVideo):
if os.path.isfile(media.media): if os.path.isfile(media.media):
media = await self.send( media = await self.send(
@ -139,7 +140,7 @@ class EditMessageMedia(Scaffold):
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 4) media = utils.get_input_media_from_file_id(media.media, FileType.VIDEO)
elif isinstance(media, types.InputMediaAudio): elif isinstance(media, types.InputMediaAudio):
if os.path.isfile(media.media): if os.path.isfile(media.media):
media = await self.send( media = await self.send(
@ -175,7 +176,7 @@ class EditMessageMedia(Scaffold):
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 9) media = utils.get_input_media_from_file_id(media.media, FileType.AUDIO)
elif isinstance(media, types.InputMediaAnimation): elif isinstance(media, types.InputMediaAnimation):
if os.path.isfile(media.media): if os.path.isfile(media.media):
media = await self.send( media = await self.send(
@ -213,7 +214,7 @@ class EditMessageMedia(Scaffold):
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 10) media = utils.get_input_media_from_file_id(media.media, FileType.ANIMATION)
elif isinstance(media, types.InputMediaDocument): elif isinstance(media, types.InputMediaDocument):
if os.path.isfile(media.media): if os.path.isfile(media.media):
media = await self.send( media = await self.send(
@ -244,7 +245,7 @@ class EditMessageMedia(Scaffold):
url=media.media url=media.media
) )
else: else:
media = utils.get_input_media_from_file_id(media.media, media.file_ref, 5) media = utils.get_input_media_from_file_id(media.media, FileType.DOCUMENT)
r = await self.send( r = await self.send(
raw.functions.messages.EditMessage( raw.functions.messages.EditMessage(

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendAnimation(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
animation: Union[str, BinaryIO], animation: Union[str, BinaryIO],
file_ref: str = None,
caption: str = "", caption: str = "",
unsave: bool = False, unsave: bool = False,
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -69,10 +69,6 @@ class SendAnimation(Scaffold):
pass a file path as string to upload a new animation that exists on your local machine, or pass a file path as string to upload a new animation that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
caption (``str``, *optional*): caption (``str``, *optional*):
Animation caption, 0-1024 characters. Animation caption, 0-1024 characters.
@ -192,7 +188,7 @@ class SendAnimation(Scaffold):
url=animation url=animation
) )
else: else:
media = utils.get_input_media_from_file_id(animation, file_ref, 10) media = utils.get_input_media_from_file_id(animation, FileType.ANIMATION)
else: else:
thumb = await self.save_file(thumb) thumb = await self.save_file(thumb)
file = await self.save_file(animation, progress=progress, progress_args=progress_args) file = await self.save_file(animation, progress=progress, progress_args=progress_args)
@ -242,7 +238,9 @@ class SendAnimation(Scaffold):
if unsave: if unsave:
document = message.animation or message.document document = message.animation or message.document
document_id = utils.get_input_media_from_file_id(document.file_id, document.file_ref).id document_id = utils.get_input_media_from_file_id(
document.file_id, FileType.ANIMATION
).id
await self.send( await self.send(
raw.functions.messages.SaveGif( raw.functions.messages.SaveGif(

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendAudio(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
audio: Union[str, BinaryIO], audio: Union[str, BinaryIO],
file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
@ -69,10 +69,6 @@ class SendAudio(Scaffold):
pass a file path as string to upload a new audio file that exists on your local machine, or pass a file path as string to upload a new audio file that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
caption (``str``, *optional*): caption (``str``, *optional*):
Audio caption, 0-1024 characters. Audio caption, 0-1024 characters.
@ -188,7 +184,7 @@ class SendAudio(Scaffold):
url=audio url=audio
) )
else: else:
media = utils.get_input_media_from_file_id(audio, file_ref, 9) media = utils.get_input_media_from_file_id(audio, FileType.AUDIO)
else: else:
thumb = await self.save_file(thumb) thumb = await self.save_file(thumb)
file = await self.save_file(audio, progress=progress, progress_args=progress_args) file = await self.save_file(audio, progress=progress, progress_args=progress_args)

View File

@ -29,7 +29,6 @@ class SendCachedMedia(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
file_id: str, file_id: str,
file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
disable_notification: bool = None, disable_notification: bool = None,
@ -58,10 +57,6 @@ class SendCachedMedia(Scaffold):
Media to send. Media to send.
Pass a file_id as string to send a media that exists on the Telegram servers. 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 (``str``, *optional*): caption (``str``, *optional*):
Media caption, 0-1024 characters. Media caption, 0-1024 characters.
@ -98,7 +93,7 @@ class SendCachedMedia(Scaffold):
r = await self.send( r = await self.send(
raw.functions.messages.SendMedia( raw.functions.messages.SendMedia(
peer=await self.resolve_peer(chat_id), peer=await self.resolve_peer(chat_id),
media=utils.get_input_media_from_file_id(file_id, file_ref), media=utils.get_input_media_from_file_id(file_id),
silent=disable_notification or None, silent=disable_notification or None,
reply_to_msg_id=reply_to_message_id, reply_to_msg_id=reply_to_message_id,
random_id=self.rnd_id(), random_id=self.rnd_id(),

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendDocument(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
document: Union[str, BinaryIO], document: Union[str, BinaryIO],
file_ref: str = None,
thumb: Union[str, BinaryIO] = None, thumb: Union[str, BinaryIO] = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -66,10 +66,6 @@ class SendDocument(Scaffold):
pass a file path as string to upload a new file that exists on your local machine, or pass a file path as string to upload a new file that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
thumb (``str`` | ``BinaryIO``, *optional*): thumb (``str`` | ``BinaryIO``, *optional*):
Thumbnail of the file sent. Thumbnail of the file sent.
The thumbnail should be in JPEG format and less than 200 KB in size. The thumbnail should be in JPEG format and less than 200 KB in size.
@ -171,7 +167,7 @@ class SendDocument(Scaffold):
url=document url=document
) )
else: else:
media = utils.get_input_media_from_file_id(document, file_ref, 5) media = utils.get_input_media_from_file_id(document, FileType.DOCUMENT)
else: else:
thumb = await self.save_file(thumb) thumb = await self.save_file(thumb)
file = await self.save_file(document, progress=progress, progress_args=progress_args) file = await self.save_file(document, progress=progress, progress_args=progress_args)

View File

@ -24,6 +24,7 @@ from typing import Union, List
from pyrogram import raw from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -117,7 +118,7 @@ class SendMediaGroup(Scaffold):
) )
) )
else: else:
media = utils.get_input_media_from_file_id(i.media, i.file_ref, 2) media = utils.get_input_media_from_file_id(i.media, FileType.PHOTO)
elif isinstance(i, types.InputMediaVideo): elif isinstance(i, types.InputMediaVideo):
if os.path.isfile(i.media): if os.path.isfile(i.media):
media = await self.send( media = await self.send(
@ -165,7 +166,7 @@ class SendMediaGroup(Scaffold):
) )
) )
else: else:
media = utils.get_input_media_from_file_id(i.media, i.file_ref, 4) media = utils.get_input_media_from_file_id(i.media, FileType.VIDEO)
elif isinstance(i, types.InputMediaAudio): elif isinstance(i, types.InputMediaAudio):
if os.path.isfile(i.media): if os.path.isfile(i.media):
media = await self.send( media = await self.send(
@ -212,7 +213,7 @@ class SendMediaGroup(Scaffold):
) )
) )
else: else:
media = utils.get_input_media_from_file_id(i.media, i.file_ref, 9) media = utils.get_input_media_from_file_id(i.media, FileType.AUDIO)
elif isinstance(i, types.InputMediaDocument): elif isinstance(i, types.InputMediaDocument):
if os.path.isfile(i.media): if os.path.isfile(i.media):
media = await self.send( media = await self.send(
@ -254,7 +255,7 @@ class SendMediaGroup(Scaffold):
) )
) )
else: else:
media = utils.get_input_media_from_file_id(i.media, i.file_ref, 5) media = utils.get_input_media_from_file_id(i.media, FileType.DOCUMENT)
multi_media.append( multi_media.append(
raw.types.InputSingleMedia( raw.types.InputSingleMedia(

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendPhoto(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
photo: Union[str, BinaryIO], photo: Union[str, BinaryIO],
file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
ttl_seconds: int = None, ttl_seconds: int = None,
@ -64,10 +64,6 @@ class SendPhoto(Scaffold):
pass a file path as string to upload a new photo that exists on your local machine, or pass a file path as string to upload a new photo that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
caption (``str``, *optional*): caption (``str``, *optional*):
Photo caption, 0-1024 characters. Photo caption, 0-1024 characters.
@ -154,7 +150,7 @@ class SendPhoto(Scaffold):
ttl_seconds=ttl_seconds ttl_seconds=ttl_seconds
) )
else: else:
media = utils.get_input_media_from_file_id(photo, file_ref, 2) media = utils.get_input_media_from_file_id(photo, FileType.PHOTO)
else: else:
file = await self.save_file(photo, progress=progress, progress_args=progress_args) file = await self.save_file(photo, progress=progress, progress_args=progress_args)
media = raw.types.InputMediaUploadedPhoto( media = raw.types.InputMediaUploadedPhoto(

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendSticker(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
sticker: Union[str, BinaryIO], sticker: Union[str, BinaryIO],
file_ref: str = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
schedule_date: int = None, schedule_date: int = None,
@ -61,10 +61,6 @@ class SendSticker(Scaffold):
pass a file path as string to upload a new sticker that exists on your local machine, or pass a file path as string to upload a new sticker that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
disable_notification (``bool``, *optional*): disable_notification (``bool``, *optional*):
Sends the message silently. Sends the message silently.
Users will receive a notification with no sound. Users will receive a notification with no sound.
@ -133,7 +129,7 @@ class SendSticker(Scaffold):
url=sticker url=sticker
) )
else: else:
media = utils.get_input_media_from_file_id(sticker, file_ref, 8) media = utils.get_input_media_from_file_id(sticker, FileType.STICKER)
else: else:
file = await self.save_file(sticker, progress=progress, progress_args=progress_args) file = await self.save_file(sticker, progress=progress, progress_args=progress_args)
media = raw.types.InputMediaUploadedDocument( media = raw.types.InputMediaUploadedDocument(

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendVideo(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
video: Union[str, BinaryIO], video: Union[str, BinaryIO],
file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
@ -69,10 +69,6 @@ class SendVideo(Scaffold):
pass a file path as string to upload a new video that exists on your local machine, or pass a file path as string to upload a new video that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
caption (``str``, *optional*): caption (``str``, *optional*):
Video caption, 0-1024 characters. Video caption, 0-1024 characters.
@ -187,7 +183,7 @@ class SendVideo(Scaffold):
url=video url=video
) )
else: else:
media = utils.get_input_media_from_file_id(video, file_ref, 4) media = utils.get_input_media_from_file_id(video, FileType.VIDEO)
else: else:
thumb = await self.save_file(thumb) thumb = await self.save_file(thumb)
file = await self.save_file(video, progress=progress, progress_args=progress_args) file = await self.save_file(video, progress=progress, progress_args=progress_args)

View File

@ -24,6 +24,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -32,7 +33,6 @@ class SendVideoNote(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
video_note: Union[str, BinaryIO], video_note: Union[str, BinaryIO],
file_ref: str = None,
duration: int = 0, duration: int = 0,
length: int = 1, length: int = 1,
thumb: Union[str, BinaryIO] = None, thumb: Union[str, BinaryIO] = None,
@ -63,10 +63,6 @@ class SendVideoNote(Scaffold):
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass a binary file-like object with its attribute ".name" set for in-memory uploads.
Sending video notes by a URL is currently unsupported. 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 (``int``, *optional*):
Duration of sent video in seconds. Duration of sent video in seconds.
@ -150,7 +146,7 @@ class SendVideoNote(Scaffold):
] ]
) )
else: else:
media = utils.get_input_media_from_file_id(video_note, file_ref, 13) media = utils.get_input_media_from_file_id(video_note, FileType.VIDEO_NOTE)
else: else:
thumb = await self.save_file(thumb) thumb = await self.save_file(thumb)
file = await self.save_file(video_note, progress=progress, progress_args=progress_args) file = await self.save_file(video_note, progress=progress, progress_args=progress_args)

View File

@ -25,6 +25,7 @@ from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram import utils from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -33,7 +34,6 @@ class SendVoice(Scaffold):
self, self,
chat_id: Union[int, str], chat_id: Union[int, str],
voice: Union[str, BinaryIO], voice: Union[str, BinaryIO],
file_ref=None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
duration: int = 0, duration: int = 0,
@ -64,10 +64,6 @@ class SendVoice(Scaffold):
pass a file path as string to upload a new audio that exists on your local machine, or pass a file path as string to upload a new audio that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads. pass 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.
caption (``str``, *optional*): caption (``str``, *optional*):
Voice message caption, 0-1024 characters. Voice message caption, 0-1024 characters.
@ -154,7 +150,7 @@ class SendVoice(Scaffold):
url=voice url=voice
) )
else: else:
media = utils.get_input_media_from_file_id(voice, file_ref, 3) media = utils.get_input_media_from_file_id(voice, FileType.VOICE)
else: else:
file = await self.save_file(voice, progress=progress, progress_args=progress_args) file = await self.save_file(voice, progress=progress, progress_args=progress_args)
media = raw.types.InputMediaUploadedDocument( media = raw.types.InputMediaUploadedDocument(

View File

@ -20,6 +20,7 @@ from typing import List, Union
from pyrogram import raw from pyrogram import raw
from pyrogram import utils from pyrogram import utils
from pyrogram.file_id import FileType
from pyrogram.scaffold import Scaffold from pyrogram.scaffold import Scaffold
@ -51,7 +52,7 @@ class DeleteProfilePhotos(Scaffold):
app.delete_profile_photos([p.file_id for p in photos[1:]]) app.delete_profile_photos([p.file_id for p in photos[1:]])
""" """
photo_ids = photo_ids if isinstance(photo_ids, list) else [photo_ids] photo_ids = photo_ids if isinstance(photo_ids, list) else [photo_ids]
input_photos = [utils.get_input_media_from_file_id(i).id for i in photo_ids] input_photos = [utils.get_input_media_from_file_id(i, FileType.PHOTO).id for i in photo_ids]
return bool(await self.send( return bool(await self.send(
raw.functions.photos.DeletePhotos( raw.functions.photos.DeletePhotos(

View File

@ -31,10 +31,9 @@ class InputMedia(Object):
- :obj:`~pyrogram.types.InputMediaVideo` - :obj:`~pyrogram.types.InputMediaVideo`
""" """
def __init__(self, media: str, file_ref: str, caption: str, parse_mode: str): def __init__(self, media: str, caption: str, parse_mode: str):
super().__init__() super().__init__()
self.media = media self.media = media
self.file_ref = file_ref
self.caption = caption self.caption = caption
self.parse_mode = parse_mode self.parse_mode = parse_mode

View File

@ -30,10 +30,6 @@ class InputMediaAnimation(InputMedia):
Pass a file_id as string to send a file that exists on the Telegram servers or Pass a file_id as string to send a file that exists on the Telegram servers or
pass a file path as string to upload a new file that exists on your local machine. 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*): thumb (``str``, *optional*):
Thumbnail of the animation file sent. Thumbnail of the animation file sent.
The thumbnail should be in JPEG format and less than 200 KB in size. The thumbnail should be in JPEG format and less than 200 KB in size.
@ -63,7 +59,6 @@ class InputMediaAnimation(InputMedia):
def __init__( def __init__(
self, self,
media: str, media: str,
file_ref: str = None,
thumb: str = None, thumb: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -71,7 +66,7 @@ class InputMediaAnimation(InputMedia):
height: int = 0, height: int = 0,
duration: int = 0 duration: int = 0
): ):
super().__init__(media, file_ref, caption, parse_mode) super().__init__(media, caption, parse_mode)
self.thumb = thumb self.thumb = thumb
self.width = width self.width = width

View File

@ -32,10 +32,6 @@ class InputMediaAudio(InputMedia):
Pass a file_id as string to send an audio that exists on the Telegram servers or Pass a file_id as string to send an audio that exists on the Telegram servers or
pass a file path as string to upload a new audio that exists on your local machine. 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.
thumb (``str``, *optional*): thumb (``str``, *optional*):
Thumbnail of the music file album cover. Thumbnail of the music file album cover.
The thumbnail should be in JPEG format and less than 200 KB in size. The thumbnail should be in JPEG format and less than 200 KB in size.
@ -65,7 +61,6 @@ class InputMediaAudio(InputMedia):
def __init__( def __init__(
self, self,
media: str, media: str,
file_ref: str = None,
thumb: str = None, thumb: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -73,7 +68,7 @@ class InputMediaAudio(InputMedia):
performer: str = "", performer: str = "",
title: str = "" title: str = ""
): ):
super().__init__(media, file_ref, caption, parse_mode) super().__init__(media, caption, parse_mode)
self.thumb = thumb self.thumb = thumb
self.duration = duration self.duration = duration

View File

@ -30,10 +30,6 @@ class InputMediaDocument(InputMedia):
Pass a file_id as string to send a file that exists on the Telegram servers or Pass a file_id as string to send a file that exists on the Telegram servers or
pass a file path as string to upload a new file that exists on your local machine. 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``): thumb (``str``):
Thumbnail of the file sent. Thumbnail of the file sent.
The thumbnail should be in JPEG format and less than 200 KB in size. The thumbnail should be in JPEG format and less than 200 KB in size.
@ -54,11 +50,10 @@ class InputMediaDocument(InputMedia):
def __init__( def __init__(
self, self,
media: str, media: str,
file_ref: str = None,
thumb: str = None, thumb: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object parse_mode: Union[str, None] = object
): ):
super().__init__(media, file_ref, caption, parse_mode) super().__init__(media, caption, parse_mode)
self.thumb = thumb self.thumb = thumb

View File

@ -32,10 +32,6 @@ class InputMediaPhoto(InputMedia):
pass a file path as string to upload a new photo that exists on your local machine. pass a file path as string to upload a new photo that exists on your local machine.
Sending photo by a URL is currently unsupported. Sending photo 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.
caption (``str``, *optional*): caption (``str``, *optional*):
Caption of the photo to be sent, 0-1024 characters Caption of the photo to be sent, 0-1024 characters
@ -50,8 +46,7 @@ class InputMediaPhoto(InputMedia):
def __init__( def __init__(
self, self,
media: str, media: str,
file_ref: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object parse_mode: Union[str, None] = object
): ):
super().__init__(media, file_ref, caption, parse_mode) super().__init__(media, caption, parse_mode)

View File

@ -32,10 +32,6 @@ class InputMediaVideo(InputMedia):
pass a file path as string to upload a new video that exists on your local machine. pass a file path as string to upload a new video that exists on your local machine.
Sending video by a URL is currently unsupported. Sending video 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.
thumb (``str``): thumb (``str``):
Thumbnail of the video sent. Thumbnail of the video sent.
The thumbnail should be in JPEG format and less than 200 KB in size. The thumbnail should be in JPEG format and less than 200 KB in size.
@ -68,7 +64,6 @@ class InputMediaVideo(InputMedia):
def __init__( def __init__(
self, self,
media: str, media: str,
file_ref: str = None,
thumb: str = None, thumb: str = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -77,7 +72,7 @@ class InputMediaVideo(InputMedia):
duration: int = 0, duration: int = 0,
supports_streaming: bool = True supports_streaming: bool = True
): ):
super().__init__(media, file_ref, caption, parse_mode) super().__init__(media, caption, parse_mode)
self.thumb = thumb self.thumb = thumb
self.width = width self.width = width

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,10 +30,11 @@ class Animation(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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``): width (``int``):
Animation width as defined by sender. Animation width as defined by sender.
@ -66,7 +66,7 @@ class Animation(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
width: int, width: int,
height: int, height: int,
duration: int, duration: int,
@ -79,7 +79,7 @@ class Animation(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.file_name = file_name self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
@ -97,16 +97,17 @@ class Animation(Object):
file_name: str file_name: str
) -> "Animation": ) -> "Animation":
return Animation( return Animation(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.ANIMATION,
"<iiqq", dc_id=animation.dc_id,
10, media_id=animation.id,
animation.dc_id, access_hash=animation.access_hash,
animation.id, file_reference=animation.file_reference
animation.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(animation.file_reference), media_id=animation.id
).encode(),
width=getattr(video_attributes, "w", 0), width=getattr(video_attributes, "w", 0),
height=getattr(video_attributes, "h", 0), height=getattr(video_attributes, "h", 0),
duration=getattr(video_attributes, "duration", 0), duration=getattr(video_attributes, "duration", 0),

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,14 +30,21 @@ class Audio(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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 (``int``):
Duration of the audio in seconds as defined by sender. 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*): file_name (``str``, *optional*):
Audio file name. Audio file name.
@ -49,13 +55,7 @@ class Audio(Object):
File size. File size.
date (``int``, *optional*): date (``int``, *optional*):
Date the audio was sent in Unix time. Date the audio was originally 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.
thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*):
Thumbnails of the music file album cover. Thumbnails of the music file album cover.
@ -66,27 +66,27 @@ class Audio(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
duration: int, duration: int,
performer: str = None,
title: str = None,
file_name: str = None, file_name: str = None,
mime_type: str = None, mime_type: str = None,
file_size: int = None, file_size: int = None,
date: int = None, date: int = None,
performer: str = None,
title: str = None,
thumbs: List["types.Thumbnail"] = None thumbs: List["types.Thumbnail"] = None
): ):
super().__init__(client) super().__init__(client)
self.file_id = file_id 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.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
self.date = date self.date = date
self.duration = duration
self.performer = performer
self.title = title
self.thumbs = thumbs self.thumbs = thumbs
@staticmethod @staticmethod
@ -97,16 +97,17 @@ class Audio(Object):
file_name: str file_name: str
) -> "Audio": ) -> "Audio":
return Audio( return Audio(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.AUDIO,
"<iiqq", dc_id=audio.dc_id,
9, media_id=audio.id,
audio.dc_id, access_hash=audio.access_hash,
audio.id, file_reference=audio.file_reference
audio.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(audio.file_reference), media_id=audio.id
).encode(),
duration=audio_attributes.duration, duration=audio_attributes.duration,
performer=audio_attributes.performer, performer=audio_attributes.performer,
title=audio_attributes.title, title=audio_attributes.title,

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,10 +30,11 @@ class Document(Object):
Parameters: Parameters:
file_id (``str``): file_id (``str``):
Unique file identifier. Identifier for this file, which can be used to download or reuse the file.
file_ref (``str``): file_unique_id (``str``):
Up to date file reference. 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*): file_name (``str``, *optional*):
Original filename as defined by sender. Original filename as defined by sender.
@ -57,7 +57,7 @@ class Document(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
file_name: str = None, file_name: str = None,
mime_type: str = None, mime_type: str = None,
file_size: int = None, file_size: int = None,
@ -67,7 +67,7 @@ class Document(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.file_name = file_name self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
@ -77,16 +77,17 @@ class Document(Object):
@staticmethod @staticmethod
def _parse(client, document: "raw.types.Document", file_name: str) -> "Document": def _parse(client, document: "raw.types.Document", file_name: str) -> "Document":
return Document( return Document(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.DOCUMENT,
"<iiqq", dc_id=document.dc_id,
5, media_id=document.id,
document.dc_id, access_hash=document.access_hash,
document.id, file_reference=document.file_reference
document.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(document.file_reference), media_id=document.id
).encode(),
file_name=file_name, file_name=file_name,
mime_type=document.mime_type, mime_type=document.mime_type,
file_size=document.size, file_size=document.size,

View File

@ -790,7 +790,6 @@ class Message(Object, Update):
async def reply_animation( async def reply_animation(
self, self,
animation: Union[str, BinaryIO], animation: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -832,10 +831,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get an animation from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -916,7 +911,6 @@ class Message(Object, Update):
return await self._client.send_animation( return await self._client.send_animation(
chat_id=self.chat.id, chat_id=self.chat.id,
animation=animation, animation=animation,
file_ref=file_ref,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
duration=duration, duration=duration,
@ -933,7 +927,6 @@ class Message(Object, Update):
async def reply_audio( async def reply_audio(
self, self,
audio: Union[str, BinaryIO], audio: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -975,10 +968,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get an audio file from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -1059,7 +1048,6 @@ class Message(Object, Update):
return await self._client.send_audio( return await self._client.send_audio(
chat_id=self.chat.id, chat_id=self.chat.id,
audio=audio, audio=audio,
file_ref=file_ref,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
duration=duration, duration=duration,
@ -1076,7 +1064,6 @@ class Message(Object, Update):
async def reply_cached_media( async def reply_cached_media(
self, self,
file_id: str, file_id: str,
file_ref: str = None,
quote: bool = None, quote: bool = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -1110,10 +1097,6 @@ class Message(Object, Update):
Media to send. Media to send.
Pass a file_id as string to send a media that exists on the Telegram servers. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -1155,7 +1138,6 @@ class Message(Object, Update):
return await self._client.send_cached_media( return await self._client.send_cached_media(
chat_id=self.chat.id, chat_id=self.chat.id,
file_id=file_id, file_id=file_id,
file_ref=file_ref,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
disable_notification=disable_notification, disable_notification=disable_notification,
@ -1289,7 +1271,6 @@ class Message(Object, Update):
async def reply_document( async def reply_document(
self, self,
document: Union[str, BinaryIO], document: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
thumb: str = None, thumb: str = None,
caption: str = "", caption: str = "",
@ -1328,10 +1309,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get a file from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -1403,7 +1380,6 @@ class Message(Object, Update):
return await self._client.send_document( return await self._client.send_document(
chat_id=self.chat.id, chat_id=self.chat.id,
document=document, document=document,
file_ref=file_ref,
thumb=thumb, thumb=thumb,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
@ -1691,7 +1667,6 @@ class Message(Object, Update):
async def reply_photo( async def reply_photo(
self, self,
photo: Union[str, BinaryIO], photo: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -1730,10 +1705,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get a photo from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -1804,7 +1775,6 @@ class Message(Object, Update):
return await self._client.send_photo( return await self._client.send_photo(
chat_id=self.chat.id, chat_id=self.chat.id,
photo=photo, photo=photo,
file_ref=file_ref,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
ttl_seconds=ttl_seconds, ttl_seconds=ttl_seconds,
@ -1922,7 +1892,6 @@ class Message(Object, Update):
async def reply_sticker( async def reply_sticker(
self, self,
sticker: Union[str, BinaryIO], sticker: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
disable_notification: bool = None, disable_notification: bool = None,
reply_to_message_id: int = None, reply_to_message_id: int = None,
@ -1958,10 +1927,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -2017,7 +1982,6 @@ class Message(Object, Update):
return await self._client.send_sticker( return await self._client.send_sticker(
chat_id=self.chat.id, chat_id=self.chat.id,
sticker=sticker, sticker=sticker,
file_ref=file_ref,
disable_notification=disable_notification, disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id, reply_to_message_id=reply_to_message_id,
reply_markup=reply_markup, reply_markup=reply_markup,
@ -2126,7 +2090,6 @@ class Message(Object, Update):
async def reply_video( async def reply_video(
self, self,
video: Union[str, BinaryIO], video: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -2169,10 +2132,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get a video from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -2256,7 +2215,6 @@ class Message(Object, Update):
return await self._client.send_video( return await self._client.send_video(
chat_id=self.chat.id, chat_id=self.chat.id,
video=video, video=video,
file_ref=file_ref,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
duration=duration, duration=duration,
@ -2274,7 +2232,6 @@ class Message(Object, Update):
async def reply_video_note( async def reply_video_note(
self, self,
video_note: Union[str, BinaryIO], video_note: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
duration: int = 0, duration: int = 0,
length: int = 1, length: int = 1,
@ -2313,10 +2270,6 @@ class Message(Object, Update):
pass a file path as string to upload a new video note that exists on your local machine. 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -2384,7 +2337,6 @@ class Message(Object, Update):
return await self._client.send_video_note( return await self._client.send_video_note(
chat_id=self.chat.id, chat_id=self.chat.id,
video_note=video_note, video_note=video_note,
file_ref=file_ref,
duration=duration, duration=duration,
length=length, length=length,
thumb=thumb, thumb=thumb,
@ -2398,7 +2350,6 @@ class Message(Object, Update):
async def reply_voice( async def reply_voice(
self, self,
voice: Union[str, BinaryIO], voice: Union[str, BinaryIO],
file_ref: str = None,
quote: bool = None, quote: bool = None,
caption: str = "", caption: str = "",
parse_mode: Union[str, None] = object, parse_mode: Union[str, None] = object,
@ -2437,10 +2388,6 @@ class Message(Object, Update):
pass an HTTP URL as a string for Telegram to get an audio from the Internet, or 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. 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.
quote (``bool``, *optional*): quote (``bool``, *optional*):
If ``True``, the message will be sent as a reply to this message. If ``True``, the message will be sent as a reply to this message.
If *reply_to_message_id* is passed, this parameter will be ignored. If *reply_to_message_id* is passed, this parameter will be ignored.
@ -2509,7 +2456,6 @@ class Message(Object, Update):
return await self._client.send_voice( return await self._client.send_voice(
chat_id=self.chat.id, chat_id=self.chat.id,
voice=voice, voice=voice,
file_ref=file_ref,
caption=caption, caption=caption,
parse_mode=parse_mode, parse_mode=parse_mode,
duration=duration, duration=duration,
@ -2787,28 +2733,20 @@ class Message(Object, Update):
if self.photo: if self.photo:
file_id = self.photo.file_id file_id = self.photo.file_id
file_ref = self.photo.file_ref
elif self.audio: elif self.audio:
file_id = self.audio.file_id file_id = self.audio.file_id
file_ref = self.audio.file_ref
elif self.document: elif self.document:
file_id = self.document.file_id file_id = self.document.file_id
file_ref = self.document.file_ref
elif self.video: elif self.video:
file_id = self.video.file_id file_id = self.video.file_id
file_ref = self.video.file_ref
elif self.animation: elif self.animation:
file_id = self.animation.file_id file_id = self.animation.file_id
file_ref = self.animation.file_ref
elif self.voice: elif self.voice:
file_id = self.voice.file_id file_id = self.voice.file_id
file_ref = self.voice.file_ref
elif self.sticker: elif self.sticker:
file_id = self.sticker.file_id file_id = self.sticker.file_id
file_ref = self.sticker.file_ref
elif self.video_note: elif self.video_note:
file_id = self.video_note.file_id file_id = self.video_note.file_id
file_ref = self.video_note.file_ref
elif self.contact: elif self.contact:
return await self._client.send_contact( return await self._client.send_contact(
chat_id, chat_id,
@ -2857,9 +2795,9 @@ class Message(Object, Update):
raise ValueError("Unknown media type") raise ValueError("Unknown media type")
if self.sticker or self.video_note: # Sticker and VideoNote should have no caption if self.sticker or self.video_note: # Sticker and VideoNote should have no caption
return await send_media(file_id=file_id, file_ref=file_ref) return await send_media(file_id=file_id)
else: else:
return await send_media(file_id=file_id, file_ref=file_ref, caption=caption, parse_mode="html") return await send_media(file_id=file_id, caption=caption, parse_mode="html")
else: else:
raise ValueError("Can't copy this message") raise ValueError("Can't copy this message")
else: else:

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,10 +30,11 @@ class Photo(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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``): width (``int``):
Photo width. Photo width.
@ -60,7 +60,7 @@ class Photo(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
width: int, width: int,
height: int, height: int,
file_size: int, file_size: int,
@ -71,7 +71,7 @@ class Photo(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.width = width self.width = width
self.height = height self.height = height
self.file_size = file_size self.file_size = file_size
@ -82,18 +82,36 @@ class Photo(Object):
@staticmethod @staticmethod
def _parse(client, photo: "raw.types.Photo", ttl_seconds: int = None) -> "Photo": def _parse(client, photo: "raw.types.Photo", ttl_seconds: int = None) -> "Photo":
if isinstance(photo, raw.types.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( return Photo(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.PHOTO,
"<iiqqqiiii", dc_id=photo.dc_id,
2, photo.dc_id, photo.id, photo.access_hash, media_id=photo.id,
big.location.volume_id, 1, 2, ord(big.type), access_hash=photo.access_hash,
big.location.local_id file_reference=photo.file_reference,
) thumbnail_source=ThumbnailSource.THUMBNAIL,
), thumbnail_file_type=FileType.PHOTO,
file_ref=encode_file_ref(photo.file_reference), thumbnail_size=big.type,
volume_id=big.location.volume_id,
local_id=big.location.local_id
).encode(),
file_unique_id=FileUniqueId(
file_unique_type=FileUniqueType.PHOTO,
media_id=photo.id,
volume_id=big.location.volume_id,
local_id=big.location.local_id
).encode(),
width=big.w, width=big.w,
height=big.h, height=big.h,
file_size=big.size, file_size=big.size,

View File

@ -16,7 +16,6 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
from async_lru import alru_cache from async_lru import alru_cache
@ -25,7 +24,7 @@ import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram.errors import StickersetInvalid 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 from ..object import Object
@ -34,10 +33,11 @@ class Sticker(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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``): width (``int``):
Sticker width. Sticker width.
@ -77,7 +77,7 @@ class Sticker(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
width: int, width: int,
height: int, height: int,
is_animated: bool, is_animated: bool,
@ -92,7 +92,7 @@ class Sticker(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.file_name = file_name self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
@ -137,16 +137,17 @@ class Sticker(Object):
set_name = None set_name = None
return Sticker( return Sticker(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.STICKER,
"<iiqq", dc_id=sticker.dc_id,
8, media_id=sticker.id,
sticker.dc_id, access_hash=sticker.access_hash,
sticker.id, file_reference=sticker.file_reference
sticker.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(sticker.file_reference), media_id=sticker.id
).encode(),
width=image_size_attributes.w if image_size_attributes else 512, width=image_size_attributes.w if image_size_attributes else 512,
height=image_size_attributes.h if image_size_attributes else 512, height=image_size_attributes.h if image_size_attributes else 512,
is_animated=sticker.mime_type == "application/x-tgsticker", is_animated=sticker.mime_type == "application/x-tgsticker",

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import Union, List from typing import Union, List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,7 +30,11 @@ class Thumbnail(Object):
Parameters: Parameters:
file_id (``str``): 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``): width (``int``):
Photo width. Photo width.
@ -48,6 +51,7 @@ class Thumbnail(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_unique_id: str,
width: int, width: int,
height: int, height: int,
file_size: int file_size: int
@ -55,6 +59,7 @@ class Thumbnail(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_unique_id = file_unique_id
self.width = width self.width = width
self.height = height self.height = height
self.file_size = file_size self.file_size = file_size
@ -66,10 +71,8 @@ class Thumbnail(Object):
) -> Union[List[Union["types.StrippedThumbnail", "Thumbnail"]], None]: ) -> Union[List[Union["types.StrippedThumbnail", "Thumbnail"]], None]:
if isinstance(media, raw.types.Photo): if isinstance(media, raw.types.Photo):
raw_thumbnails = media.sizes[:-1] raw_thumbnails = media.sizes[:-1]
media_type = 2
elif isinstance(media, raw.types.Document): elif isinstance(media, raw.types.Document):
raw_thumbnails = media.thumbs raw_thumbnails = media.thumbs
media_type = 14
if not raw_thumbnails: if not raw_thumbnails:
return None return None
@ -78,6 +81,9 @@ class Thumbnail(Object):
thumbnails = [] thumbnails = []
file_type = FileType.PHOTO if isinstance(media, raw.types.Photo) else FileType.THUMBNAIL
thumbnail_file_type = file_type
for thumbnail in raw_thumbnails: for thumbnail in raw_thumbnails:
# TODO: Enable this # TODO: Enable this
# if isinstance(thumbnail, types.PhotoStrippedSize): # if isinstance(thumbnail, types.PhotoStrippedSize):
@ -85,14 +91,24 @@ class Thumbnail(Object):
if isinstance(thumbnail, raw.types.PhotoSize): if isinstance(thumbnail, raw.types.PhotoSize):
thumbnails.append( thumbnails.append(
Thumbnail( Thumbnail(
file_id=encode_file_id( file_id=FileId(
pack( file_type=file_type,
"<iiqqqiiii", dc_id=media.dc_id,
media_type, media.dc_id, media.id, media.access_hash, media_id=media.id,
thumbnail.location.volume_id, 1, 2, ord(thumbnail.type), access_hash=media.access_hash,
thumbnail.location.local_id file_reference=media.file_reference,
) thumbnail_file_type=thumbnail_file_type,
), thumbnail_source=ThumbnailSource.THUMBNAIL,
thumbnail_size=thumbnail.type,
volume_id=thumbnail.location.volume_id,
local_id=thumbnail.location.local_id
).encode(),
file_unique_id=FileUniqueId(
file_unique_type=FileUniqueType.PHOTO,
media_id=media.id,
volume_id=thumbnail.location.volume_id,
local_id=thumbnail.location.local_id
).encode(),
width=thumbnail.w, width=thumbnail.w,
height=thumbnail.h, height=thumbnail.h,
file_size=thumbnail.size, file_size=thumbnail.size,

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,10 +30,11 @@ class Video(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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``): width (``int``):
Video width as defined by sender. Video width as defined by sender.
@ -51,18 +51,18 @@ class Video(Object):
mime_type (``str``, *optional*): mime_type (``str``, *optional*):
Mime type of a file as defined by sender. 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 (``int``, *optional*):
File size. File size.
date (``int``, *optional*): supports_streaming (``bool``, *optional*):
Date the video was sent in Unix time. True, if the video was uploaded with streaming support.
ttl_seconds (``int``. *optional*): ttl_seconds (``int``. *optional*):
Time-to-live seconds, for secret photos. 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*): thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*):
Video thumbnails. Video thumbnails.
""" """
@ -72,31 +72,31 @@ class Video(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
width: int, width: int,
height: int, height: int,
duration: int, duration: int,
file_name: str = None, file_name: str = None,
mime_type: str = None, mime_type: str = None,
supports_streaming: bool = None,
file_size: int = None, file_size: int = None,
date: int = None, supports_streaming: bool = None,
ttl_seconds: int = None, ttl_seconds: int = None,
date: int = None,
thumbs: List["types.Thumbnail"] = None thumbs: List["types.Thumbnail"] = None
): ):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.width = width self.width = width
self.height = height self.height = height
self.duration = duration self.duration = duration
self.file_name = file_name self.file_name = file_name
self.mime_type = mime_type self.mime_type = mime_type
self.supports_streaming = supports_streaming
self.file_size = file_size self.file_size = file_size
self.date = date self.supports_streaming = supports_streaming
self.ttl_seconds = ttl_seconds self.ttl_seconds = ttl_seconds
self.date = date
self.thumbs = thumbs self.thumbs = thumbs
@staticmethod @staticmethod
@ -108,16 +108,17 @@ class Video(Object):
ttl_seconds: int = None ttl_seconds: int = None
) -> "Video": ) -> "Video":
return Video( return Video(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.VIDEO,
"<iiqq", dc_id=video.dc_id,
4, media_id=video.id,
video.dc_id, access_hash=video.access_hash,
video.id, file_reference=video.file_reference
video.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(video.file_reference), media_id=video.id
).encode(),
width=video_attributes.w, width=video_attributes.w,
height=video_attributes.h, height=video_attributes.h,
duration=video_attributes.duration, duration=video_attributes.duration,

View File

@ -16,13 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw from pyrogram import raw
from pyrogram import types 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 from ..object import Object
@ -31,10 +30,11 @@ class VideoNote(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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``): length (``int``):
Video width and height as defined by sender. Video width and height as defined by sender.
@ -60,7 +60,7 @@ class VideoNote(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
length: int, length: int,
duration: int, duration: int,
thumbs: List["types.Thumbnail"] = None, thumbs: List["types.Thumbnail"] = None,
@ -71,7 +71,7 @@ class VideoNote(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.mime_type = mime_type self.mime_type = mime_type
self.file_size = file_size self.file_size = file_size
self.date = date self.date = date
@ -86,16 +86,17 @@ class VideoNote(Object):
video_attributes: "raw.types.DocumentAttributeVideo" video_attributes: "raw.types.DocumentAttributeVideo"
) -> "VideoNote": ) -> "VideoNote":
return VideoNote( return VideoNote(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.VIDEO_NOTE,
"<iiqq", dc_id=video_note.dc_id,
13, media_id=video_note.id,
video_note.dc_id, access_hash=video_note.access_hash,
video_note.id, file_reference=video_note.file_reference
video_note.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(video_note.file_reference), media_id=video_note.id
).encode(),
length=video_attributes.w, length=video_attributes.w,
duration=video_attributes.duration, duration=video_attributes.duration,
file_size=video_note.size, file_size=video_note.size,

View File

@ -16,11 +16,9 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
import pyrogram import pyrogram
from pyrogram import raw 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 from ..object import Object
@ -29,10 +27,11 @@ class Voice(Object):
Parameters: Parameters:
file_id (``str``): 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``): file_unique_id (``str``):
Up to date file reference. 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 (``int``):
Duration of the audio in seconds as defined by sender. Duration of the audio in seconds as defined by sender.
@ -55,7 +54,7 @@ class Voice(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
file_id: str, file_id: str,
file_ref: str, file_unique_id: str,
duration: int, duration: int,
waveform: bytes = None, waveform: bytes = None,
mime_type: str = None, mime_type: str = None,
@ -65,7 +64,7 @@ class Voice(Object):
super().__init__(client) super().__init__(client)
self.file_id = file_id self.file_id = file_id
self.file_ref = file_ref self.file_unique_id = file_unique_id
self.duration = duration self.duration = duration
self.waveform = waveform self.waveform = waveform
self.mime_type = mime_type self.mime_type = mime_type
@ -75,16 +74,17 @@ class Voice(Object):
@staticmethod @staticmethod
def _parse(client, voice: "raw.types.Document", attributes: "raw.types.DocumentAttributeAudio") -> "Voice": def _parse(client, voice: "raw.types.Document", attributes: "raw.types.DocumentAttributeAudio") -> "Voice":
return Voice( return Voice(
file_id=encode_file_id( file_id=FileId(
pack( file_type=FileType.VOICE,
"<iiqq", dc_id=voice.dc_id,
3, media_id=voice.id,
voice.dc_id, access_hash=voice.access_hash,
voice.id, file_reference=voice.file_reference
voice.access_hash ).encode(),
) file_unique_id=FileUniqueId(
), file_unique_type=FileUniqueType.DOCUMENT,
file_ref=encode_file_ref(voice.file_reference), media_id=voice.id
).encode(),
duration=attributes.duration, duration=attributes.duration,
mime_type=voice.mime_type, mime_type=voice.mime_type,
file_size=voice.size, file_size=voice.size,

View File

@ -16,14 +16,12 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from struct import pack
from typing import Union from typing import Union
import pyrogram import pyrogram
from pyrogram import raw 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 ..object import Object
from ... import utils
class ChatPhoto(Object): class ChatPhoto(Object):
@ -34,9 +32,17 @@ class ChatPhoto(Object):
File identifier of small (160x160) chat photo. 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. 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``): big_file_id (``str``):
File identifier of big (640x640) chat photo. 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. 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__( def __init__(
@ -44,12 +50,17 @@ class ChatPhoto(Object):
*, *,
client: "pyrogram.Client" = None, client: "pyrogram.Client" = None,
small_file_id: str, 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) super().__init__(client)
self.small_file_id = small_file_id 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_file_id = big_file_id
self.big_photo_unique_id = big_photo_unique_id
@staticmethod @staticmethod
def _parse( def _parse(
@ -61,39 +72,40 @@ class ChatPhoto(Object):
if not isinstance(chat_photo, (raw.types.UserProfilePhoto, raw.types.ChatPhoto)): if not isinstance(chat_photo, (raw.types.UserProfilePhoto, raw.types.ChatPhoto)):
return None return None
if peer_access_hash is None: media_id = chat_photo.photo_id if isinstance(chat_photo, raw.types.UserProfilePhoto) else 0
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
return ChatPhoto( return ChatPhoto(
small_file_id=encode_file_id( small_file_id=FileId(
pack( file_type=FileType.CHAT_PHOTO,
"<iiqqqiiiqi", dc_id=chat_photo.dc_id,
1, chat_photo.dc_id, photo_id, media_id=media_id,
0, loc_small.volume_id, access_hash=0,
2, peer_id, x, peer_access_hash, loc_small.local_id volume_id=chat_photo.photo_small.volume_id,
) thumbnail_source=ThumbnailSource.CHAT_PHOTO_SMALL,
), local_id=chat_photo.photo_small.local_id,
big_file_id=encode_file_id( chat_id=peer_id,
pack( chat_access_hash=peer_access_hash
"<iiqqqiiiqi", ).encode(),
1, chat_photo.dc_id, photo_id, small_photo_unique_id=FileUniqueId(
0, loc_big.volume_id, file_unique_type=FileUniqueType.PHOTO,
3, peer_id, x, peer_access_hash, loc_big.local_id volume_id=chat_photo.photo_small.volume_id,
) local_id=chat_photo.photo_small.local_id
), ).encode(),
big_file_id=FileId(
file_type=FileType.CHAT_PHOTO,
dc_id=chat_photo.dc_id,
media_id=media_id,
access_hash=0,
volume_id=chat_photo.photo_big.volume_id,
thumbnail_source=ThumbnailSource.CHAT_PHOTO_BIG,
local_id=chat_photo.photo_big.local_id,
chat_id=peer_id,
chat_access_hash=peer_access_hash
).encode(),
big_photo_unique_id=FileUniqueId(
file_unique_type=FileUniqueType.PHOTO,
volume_id=chat_photo.photo_big.volume_id,
local_id=chat_photo.photo_big.local_id
).encode(),
client=client client=client
) )

View File

@ -29,60 +29,7 @@ from typing import Union
from pyrogram import raw from pyrogram import raw
from pyrogram import types from pyrogram import types
from pyrogram.scaffold import Scaffold from pyrogram.file_id import FileId, FileType, PHOTO_TYPES, DOCUMENT_TYPES
def decode_file_id(s: str) -> 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))
async def ainput(prompt: str = "", *, hide: bool = False): async def ainput(prompt: str = "", *, hide: bool = False):
@ -102,52 +49,38 @@ def get_offset_date(dialogs):
def get_input_media_from_file_id( def get_input_media_from_file_id(
file_id_str: str, file_id: str,
file_ref: str = None, expected_file_type: FileType = None
expected_media_type: int = None
) -> Union["raw.types.InputMediaPhoto", "raw.types.InputMediaDocument"]: ) -> Union["raw.types.InputMediaPhoto", "raw.types.InputMediaDocument"]:
try: decoded = FileId.decode(file_id)
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]
if expected_media_type is not None: file_type = decoded.file_type
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)
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): if file_type in (FileType.THUMBNAIL, FileType.CHAT_PHOTO):
raise ValueError(f"This file_id can only be used for download: {file_id_str}") raise ValueError(f"This file_id can only be used for download: {file_id}")
if media_type == 2: if file_type in PHOTO_TYPES:
unpacked = struct.unpack("<iiqqqiiii", decoded) return raw.types.InputMediaPhoto(
dc_id, file_id, access_hash, volume_id, _, _, type, local_id = unpacked[1:] id=raw.types.InputPhoto(
id=decoded.media_id,
return raw.types.InputMediaPhoto( access_hash=decoded.access_hash,
id=raw.types.InputPhoto( file_reference=decoded.file_reference
id=file_id,
access_hash=access_hash,
file_reference=decode_file_ref(file_ref)
)
) )
)
if media_type in (3, 4, 5, 8, 9, 10, 13): if file_type in DOCUMENT_TYPES:
unpacked = struct.unpack("<iiqq", decoded) return raw.types.InputMediaDocument(
dc_id, file_id, access_hash = unpacked[1:] id=raw.types.InputDocument(
id=decoded.media_id,
return raw.types.InputMediaDocument( access_hash=decoded.access_hash,
id=raw.types.InputDocument( file_reference=decoded.file_reference
id=file_id,
access_hash=access_hash,
file_reference=decode_file_ref(file_ref)
)
) )
)
raise ValueError(f"Unknown media type: {file_id_str}") raise ValueError(f"Unknown file id: {file_id}")
async def parse_messages(client, messages: "raw.types.messages.Messages", replies: int = 1) -> List["types.Message"]: async def parse_messages(client, messages: "raw.types.messages.Messages", replies: int = 1) -> List["types.Message"]: