Pyrofork: Fix video cover

Signed-off-by: Yasir Aris <git@yasir.id>
This commit is contained in:
Yasir Aris M 2025-02-25 11:18:02 +07:00 committed by wulan17
parent 8528eea303
commit c31d41e3d3
No known key found for this signature in database
GPG key ID: 318CD6CD3A6AC0A5
3 changed files with 83 additions and 22 deletions

View file

@ -23,10 +23,7 @@ from datetime import datetime
from typing import Union, BinaryIO, List, Optional, Callable from typing import Union, BinaryIO, List, Optional, Callable
import pyrogram import pyrogram
from pyrogram import StopTransmission, enums from pyrogram import StopTransmission, enums, raw, types, utils
from pyrogram import raw
from pyrogram import types
from pyrogram import utils
from pyrogram.errors import FilePartMissing from pyrogram.errors import FilePartMissing
from pyrogram.file_id import FileType from pyrogram.file_id import FileType
@ -55,7 +52,7 @@ class SendVideo:
reply_to_chat_id: Union[int, str] = None, reply_to_chat_id: Union[int, str] = None,
quote_text: str = None, quote_text: str = None,
quote_entities: List["types.MessageEntity"] = None, quote_entities: List["types.MessageEntity"] = None,
cover: Optional[Union[str, "io.BytesIO"]] = None, cover: Union[str, BinaryIO] = None,
start_timestamp: int = None, start_timestamp: int = None,
schedule_date: datetime = None, schedule_date: datetime = None,
protect_content: bool = None, protect_content: bool = None,
@ -161,8 +158,12 @@ class SendVideo:
List of special entities that appear in quote_text, which can be specified instead of *parse_mode*. List of special entities that appear in quote_text, which can be specified instead of *parse_mode*.
for reply_to_message only. for reply_to_message only.
cover (``str`` | :obj:`io.BytesIO`, *optional*): cover (``str`` | ``BinaryIO``, *optional*):
Cover of the video; pass None to skip cover uploading. Video cover.
Pass a file_id as string to attach a photo that exists on the Telegram servers,
pass a HTTP URL as a string for Telegram to get a video from the Internet,
pass a file path as string to upload a new photo civer that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads.
start_timestamp (``int``, *optional*): start_timestamp (``int``, *optional*):
Timestamp from which the video playing must start, in seconds. Timestamp from which the video playing must start, in seconds.
@ -224,6 +225,9 @@ class SendVideo:
# Send self-destructing video # Send self-destructing video
await app.send_video("me", "video.mp4", ttl_seconds=10) await app.send_video("me", "video.mp4", ttl_seconds=10)
# Add video_cover to the video
await app.send_video(channel_id, "video.mp4", video_cover="coverku.jpg")
# Keep track of the progress while uploading # Keep track of the progress while uploading
async def progress(current, total): async def progress(current, total):
print(f"{current * 100 / total:.1f}%") print(f"{current * 100 / total:.1f}%")
@ -231,6 +235,9 @@ class SendVideo:
await app.send_video("me", "video.mp4", progress=progress) await app.send_video("me", "video.mp4", progress=progress)
""" """
file = None file = None
vidcover_file = None
vidcover_media = None
peer = await self.resolve_peer(chat_id)
reply_to = await utils.get_reply_to( reply_to = await utils.get_reply_to(
client=self, client=self,
@ -245,6 +252,45 @@ class SendVideo:
) )
try: try:
if cover is not None:
if isinstance(cover, str):
if os.path.isfile(cover):
vidcover_media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=peer,
media=raw.types.InputMediaUploadedPhoto(
file=await self.save_file(cover)
)
)
)
elif re.match("^https?://", cover):
vidcover_media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=peer,
media=raw.types.InputMediaPhotoExternal(
url=cover
)
)
)
else:
vidcover_file = utils.get_input_media_from_file_id(cover, FileType.PHOTO).id
else:
vidcover_media = await self.invoke(
raw.functions.messages.UploadMedia(
peer=peer,
media=raw.types.InputMediaUploadedPhoto(
file=await self.save_file(cover)
)
)
)
if vidcover_media:
vidcover_file = raw.types.InputPhoto(
id=vidcover_media.photo.id,
access_hash=vidcover_media.photo.access_hash,
file_reference=vidcover_media.photo.file_reference
)
if isinstance(video, str): if isinstance(video, str):
if os.path.isfile(video): if os.path.isfile(video):
thumb = await self.save_file(thumb) thumb = await self.save_file(thumb)
@ -264,7 +310,7 @@ class SendVideo:
), ),
raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video)) raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video))
], ],
video_cover=await self.save_file(cover) if cover else None, video_cover=vidcover_file,
video_timestamp=start_timestamp video_timestamp=start_timestamp
) )
elif re.match("^https?://", video): elif re.match("^https?://", video):
@ -272,7 +318,7 @@ class SendVideo:
url=video, url=video,
ttl_seconds=ttl_seconds, ttl_seconds=ttl_seconds,
spoiler=has_spoiler, spoiler=has_spoiler,
video_cover=await self.save_file(cover) if cover else None, video_cover=vidcover_file,
video_timestamp=start_timestamp video_timestamp=start_timestamp
) )
else: else:
@ -296,14 +342,14 @@ class SendVideo:
), ),
raw.types.DocumentAttributeFilename(file_name=file_name or video.name) raw.types.DocumentAttributeFilename(file_name=file_name or video.name)
], ],
video_cover=await self.save_file(cover) if cover else None, video_cover=vidcover_file,
video_timestamp=start_timestamp video_timestamp=start_timestamp
) )
while True: while True:
try: try:
rpc = raw.functions.messages.SendMedia( rpc = raw.functions.messages.SendMedia(
peer=await self.resolve_peer(chat_id), peer=peer,
media=media, media=media,
silent=disable_notification or None, silent=disable_notification or None,
reply_to=reply_to, reply_to=reply_to,

View file

@ -23,9 +23,7 @@ from functools import partial
from typing import List, Match, Union, BinaryIO, Optional, Callable from typing import List, Match, Union, BinaryIO, Optional, Callable
import pyrogram import pyrogram
from pyrogram import raw, enums from pyrogram import enums, raw, types, utils
from pyrogram import types
from pyrogram import utils
from pyrogram.errors import ChannelPrivate, MessageIdsEmpty, PeerIdInvalid from pyrogram.errors import ChannelPrivate, MessageIdsEmpty, PeerIdInvalid
from pyrogram.parser import utils as parser_utils, Parser from pyrogram.parser import utils as parser_utils, Parser
from ..object import Object from ..object import Object
@ -1115,7 +1113,7 @@ class Message(Object, Update):
video_note = types.VideoNote._parse(client, doc, video_attributes) video_note = types.VideoNote._parse(client, doc, video_attributes)
media_type = enums.MessageMediaType.VIDEO_NOTE media_type = enums.MessageMediaType.VIDEO_NOTE
else: else:
video = types.Video._parse(client, doc, video_attributes, file_name, media.ttl_seconds) video = types.Video._parse(client, doc, video_attributes, file_name, media.ttl_seconds, media.video_cover, media.video_timestamp)
media_type = enums.MessageMediaType.VIDEO media_type = enums.MessageMediaType.VIDEO
has_media_spoiler = media.spoiler has_media_spoiler = media.spoiler
@ -3600,7 +3598,7 @@ class Message(Object, Update):
quote_entities: List["types.MessageEntity"] = None, quote_entities: List["types.MessageEntity"] = None,
allow_paid_broadcast: bool = None, allow_paid_broadcast: bool = None,
message_effect_id: int = None, message_effect_id: int = None,
cover: Optional[Union[str, "io.BytesIO"]] = None, cover: Union[str, BinaryIO] = None,
start_timestamp: int = None, start_timestamp: int = None,
schedule_date: datetime = None, schedule_date: datetime = None,
invert_media: bool = None, invert_media: bool = None,
@ -3707,8 +3705,12 @@ class Message(Object, Update):
allow_paid_broadcast (``bool``, *optional*): allow_paid_broadcast (``bool``, *optional*):
Pass True to allow the message to ignore regular broadcast limits for a small fee; for bots. Pass True to allow the message to ignore regular broadcast limits for a small fee; for bots.
cover (``str`` | :obj:`io.BytesIO`, *optional*): cover (``str`` | ``BinaryIO``, *optional*):
Cover of the video; pass None to skip cover uploading. Video cover.
Pass a file_id as string to attach a photo that exists on the Telegram servers,
pass a HTTP URL as a string for Telegram to get a video from the Internet,
pass a file path as string to upload a new photo civer that exists on your local machine, or
pass a binary file-like object with its attribute ".name" set for in-memory uploads.
start_timestamp (``int``, *optional*): start_timestamp (``int``, *optional*):
Timestamp from which the video playing must start, in seconds. Timestamp from which the video playing must start, in seconds.

View file

@ -21,8 +21,7 @@ from datetime import datetime
from typing import List from typing import List
import pyrogram import pyrogram
from pyrogram import raw, utils from pyrogram import raw, types, utils
from pyrogram import types
from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource
from ..object import Object from ..object import Object
@ -67,6 +66,12 @@ class Video(Object):
thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*):
Video thumbnails. Video thumbnails.
cover (:obj:`~pyrogram.types.Photo`, *optional*):
Video cover.
start_timestamp (``int``, *optional*):
Video startpoint, in seconds.
""" """
def __init__( def __init__(
@ -84,7 +89,9 @@ class Video(Object):
supports_streaming: bool = None, supports_streaming: bool = None,
ttl_seconds: int = None, ttl_seconds: int = None,
date: datetime = None, date: datetime = None,
thumbs: List["types.Thumbnail"] = None thumbs: List["types.Thumbnail"] = None,
cover: "types.Photo" = None,
start_timestamp: int = None,
): ):
super().__init__(client) super().__init__(client)
@ -100,6 +107,8 @@ class Video(Object):
self.ttl_seconds = ttl_seconds self.ttl_seconds = ttl_seconds
self.date = date self.date = date
self.thumbs = thumbs self.thumbs = thumbs
self.cover = cover
self.start_timestamp = start_timestamp
@staticmethod @staticmethod
def _parse( def _parse(
@ -107,7 +116,9 @@ class Video(Object):
video: "raw.types.Document", video: "raw.types.Document",
video_attributes: "raw.types.DocumentAttributeVideo", video_attributes: "raw.types.DocumentAttributeVideo",
file_name: str, file_name: str,
ttl_seconds: int = None ttl_seconds: int = None,
cover = None,
start_timestamp: int = None
) -> "Video": ) -> "Video":
return Video( return Video(
file_id=FileId( file_id=FileId(
@ -131,5 +142,7 @@ class Video(Object):
date=utils.timestamp_to_datetime(video.date), date=utils.timestamp_to_datetime(video.date),
ttl_seconds=ttl_seconds, ttl_seconds=ttl_seconds,
thumbs=types.Thumbnail._parse(client, video), thumbs=types.Thumbnail._parse(client, video),
cover=types.Photo._parse(client, cover),
start_timestamp=start_timestamp,
client=client client=client
) )