From 5549b7d49bc007c8bec036f60f0abfe21c5eb3c6 Mon Sep 17 00:00:00 2001 From: exostring Date: Wed, 9 Sep 2026 19:15:01 +0500 Subject: [PATCH] Fix videos posting as downloadable documents instead of playable videos Root cause of a real report (Russia Airsoft Awards post): none of the five send_video/InputMediaVideo call sites in tg_poster.py set supports_streaming=True. Without it, Telegram doesn't prepare the upload for progressive/inline playback - showing "00:00" duration with a plain download prompt on desktop, and, when it does play on mobile, audio with a black video (same underlying cause as the faststart fix, but that only handles the local moov-atom position; Telegram's own server-side handling of the upload needs the flag regardless). The real post went through the rich-message/file_id path (upload_media_for_file_ids -> sendRichMessage): a file_id bakes in whatever attributes the video was uploaded with, so fixing that call site fixes every future post reusing the id. Also pass width/height/duration explicitly everywhere instead of relying on Telegram's own probing, and carry those through the plain-caption/media-group fallback paths for consistency. Co-Authored-By: Claude Sonnet 5 --- src/tg_poster.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/tg_poster.py b/src/tg_poster.py index 961d13d..b59833b 100644 --- a/src/tg_poster.py +++ b/src/tg_poster.py @@ -161,7 +161,10 @@ class TelegramPoster: if item.media_type == "photo": group.append(InputMediaPhoto(media=fs)) else: - group.append(InputMediaVideo(media=fs)) + group.append(InputMediaVideo( + media=fs, supports_streaming=True, + width=item.width, height=item.height, duration=item.duration_sec, + )) if not group: return file_ids @@ -178,7 +181,14 @@ class TelegramPoster: file_ids[item.attachment_id] = msg.photo[-1].file_id else: msg = await self.tg_retry_media( - lambda: self.bot.send_video(video=fs, **self.chat_kwargs(chat_id, thread_id, use_storage)) + lambda: self.bot.send_video( + video=fs, + supports_streaming=True, + width=item.width, + height=item.height, + duration=item.duration_sec, + **self.chat_kwargs(chat_id, thread_id, use_storage), + ) ) if msg.video: file_ids[item.attachment_id] = msg.video.file_id @@ -307,7 +317,10 @@ class TelegramPoster: if item.media_type == "photo": input_media.append({"type": "photo", "media": val}) else: - input_media.append({"type": "video", "media": val}) + input_media.append({ + "type": "video", "media": val, + "width": item.width, "height": item.height, "duration": item.duration_sec, + }) if not input_media: # Text only post @@ -341,6 +354,10 @@ class TelegramPoster: video=item["media"], caption=first_caption or None, parse_mode="HTML", + supports_streaming=True, + width=item.get("width"), + height=item.get("height"), + duration=item.get("duration"), **self.chat_kwargs(chat_id, thread_id), ) ) @@ -352,7 +369,10 @@ class TelegramPoster: if item["type"] == "photo": group.append(InputMediaPhoto(media=item["media"], caption=cap, parse_mode="HTML")) else: - group.append(InputMediaVideo(media=item["media"], caption=cap, parse_mode="HTML")) + group.append(InputMediaVideo( + media=item["media"], caption=cap, parse_mode="HTML", supports_streaming=True, + width=item.get("width"), height=item.get("height"), duration=item.get("duration"), + )) msgs = await self.tg_retry_media( lambda: self.bot.send_media_group(media=group, **self.chat_kwargs(chat_id, thread_id)) ) @@ -365,7 +385,10 @@ class TelegramPoster: g = [ InputMediaPhoto(media=item["media"]) if item["type"] == "photo" - else InputMediaVideo(media=item["media"]) + else InputMediaVideo( + media=item["media"], supports_streaming=True, + width=item.get("width"), height=item.get("height"), duration=item.get("duration"), + ) for item in chunk ] msgs = await self.tg_retry_media(