Как после FFmpeg отправить видео в телеграм с правильным соотношением ширины и высоты?
не получается подобрать нужный формат при отправки видео в телеграм.
Суть такова, есть код, который скачивает видео с ютуба, обычным yt_dlp
Но после работы ffmpeg когда видео отправляется в телеграм, оно на телефонной версии отображается вот так (Формат квадратный, и видео растянуто или наоборот сплющено) / Сорри за пример, но это было первое видео длительностью 3 минуты для теста))
но если я скачиваю это видео на устройство, то оно отображается нормально, и более того, если я этоже видео отправляю в бот, то оно также отображается нормально
Так вот, проблема в следующем, как только не пытался ее решить... Но видео после скачивания и/или обработки ffmpeg при отправке в телеграм, не приобретает нужный формат.
Вот собственно сам код
import os
import yt_dlp
import uuid
import logging
from telebot.apihelper import ApiTelegramException
import subprocess
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("youtube_downloader")
class MyLogger:
def debug(self, msg):
if msg.startswith('[debug] '):
logger.debug(msg)
else:
logger.info(msg)
def info(self, msg):
logger.info(msg)
def warning(self, msg):
logger.warning(msg)
def error(self, msg):
logger.error(msg)
def download_youtube_video(url: str, progress_callback=None, download_folder: str = "downloads") -> tuple[str, str]:
"""
1) Скачиваем видео в H.264 (если доступно) по приоритету:
(1080p itag=137 + audio=140) / (720p=136 + audio=140) / (720p=22) / (360p=18) / best
2) Ремуксим без перекодирования, чтобы получить MP4.
3) Сбрасываем rotate=0 и выставляем aspect=16:9 (помогает Телеграму корректно показывать).
4) Извлекаем аудио в OGG.
5) Возвращаем (video_path, audio_path).
"""
os.makedirs(download_folder, exist_ok=True)
file_id = str(uuid.uuid4())
raw_video_path = os.path.join(download_folder, f"{file_id}.mp4")
fixed_video_path = os.path.join(download_folder, f"{file_id}_fixed.mp4")
audio_path = os.path.join(download_folder, f"{file_id}.ogg")
def download_progress(d):
if not progress_callback:
return
if d['status'] == 'downloading':
try:
total_bytes = d.get('total_bytes') or d.get('total_bytes_estimate', 0)
downloaded_bytes = d.get('downloaded_bytes', 0)
if total_bytes > 0:
percent = (downloaded_bytes / total_bytes) * 100
important_stages = [0, 20, 40, 60, 80, 90, 95, 100]
current_stage = min(important_stages, key=lambda x: abs(x - percent))
if percent >= current_stage and d.get('_last_stage', -1) != current_stage:
try:
progress_callback({
'status': 'downloading',
'percent': f"{current_stage}%",
'speed': d.get('speed_str', 'N/A'),
'eta': d.get('eta_str', 'N/A')
})
d['_last_stage'] = current_stage
except ApiTelegramException as e:
if e.error_code == 429:
pass
else:
raise
except Exception as e:
logger.error(f"Ошибка в progress_callback: {e}")
elif d['status'] == 'finished':
if progress_callback:
progress_callback({'status': 'merging'})
# Шаблон: (1080p + 140) / (720p + 140) / 22 / 18 / best
ydl_opts = {
'format': '(137+140)/(136+140)/22/18/best',
'outtmpl': raw_video_path,
'logger': MyLogger(),
'progress_hooks': [download_progress],
# Если придёт видео/аудио отдельно — ремуксим в MP4:
'postprocessors': [{
'key': 'FFmpegVideoRemuxer',
'preferedformat': 'mp4'
}],
'merge_output_format': 'mp4',
'prefer_ffmpeg': True,
'keepvideo': False
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
logger.info(f"Начинаю скачивание: {url}")
ydl.download([url])
logger.info(f"Видео загружено: {raw_video_path}")
cmd_fix = [
'ffmpeg',
'-i', raw_video_path,
'-c', 'copy',
'-metadata:s:v:0', 'rotate=0',
'-aspect', '16:9',
'-y',
fixed_video_path
]
logger.info("Правим DAR и убираем rotate...")
subprocess.run(cmd_fix, check=True)
# Можно удалить исходный файл, заменить на зафиксированный
os.remove(raw_video_path) # удаляем старый
video_path = fixed_video_path # теперь работаем с 'исправленным' файлом
cmd_audio = [
'ffmpeg',
'-i', video_path,
'-vn',
'-acodec', 'libvorbis',
'-q:a', '4',
'-y',
audio_path
]
logger.info(f"Извлечение аудио -> {audio_path}")
subprocess.run(cmd_audio, check=True)
if not os.path.exists(video_path):
raise FileNotFoundError("Видео файл не найден после фиксации.")
if not os.path.exists(audio_path):
raise FileNotFoundError("Аудио файл не найден после извлечения.")
logger.info("Готово! Возвращаем пути к видео и аудио.")
return video_path, audio_path
except Exception as e:
logger.error(f"Ошибка при скачивании/обработке: {e}")
raise
собирал все это дело с чатом гпт. может кто сталкивался с похожей ситуацией?