Как сделать Telegram-бота для скачивания видео
Бот, в который приходит ссылка, а выходит видео, укладывается примерно в сорок строк — если разбор ссылки не ваша забота. Это руководство проходит весь путь: от ссылки к адресу медиа, от адреса медиа к сообщению в Telegram, и три вещи, которые ломаются в проде — закрытые посты, файлы, которые Telegram не может забрать сам, и повторная отправка одного и того же видео сто раз.
Обновлено
Установите две библиотеки
aiogram общается с Telegram, httpx делает вызов API. Больше на вашей стороне ничего не нужно: ни стека для скрапинга, ни headless-браузера, ни cookie, которые надо поддерживать живыми.
Terminalpip install aiogram httpx
Разберите ссылку
Один GET с ключом в заголовке Authorization. Эндпоинт определяет платформу по самой ссылке, поэтому бот не ветвится по домену — и reel из Instagram, и видео TikTok, и клип Likee проходят через одну и ту же функцию.
Pythonimport httpx
API = "https://api.saveapi.org/v1/download"
KEY = "sk_live_xxxx"
client = httpx.AsyncClient(timeout=30)
async def resolve(link: str) -> dict:
r = await client.get(
API,
params={"url": link},
headers={"Authorization": f"Bearer {KEY}"},
)
return r.json()Отправьте медиа обратно
Ответ сам говорит, что пришло. Проверяйте medias[0].type, а не предполагайте видео: слайд-шоу TikTok и карусель Instagram приходят картинками, а для них у бота другой метод. meta.title вполне годится как подпись.
Pythonfrom aiogram import Bot, Dispatcher, F
from aiogram.types import Message
dp = Dispatcher()
@dp.message(F.text.startswith("http"))
async def on_link(message: Message):
data = await resolve(message.text.strip())
if not data["success"]:
await message.answer(EXPLAIN.get(data["error"]["code"], "Try another link."))
return
media = data["medias"][0]
if media["type"] == "video":
await message.answer_video(media["url"], caption=data["meta"]["title"])
else:
await message.answer_photo(media["url"])Напишите тексты ошибок человеческим языком
Пользователи целыми днями присылают закрытые посты и мёртвые ссылки. Свяжите стабильные коды ошибок с понятными фразами: бот, который говорит «этот аккаунт закрыт», получит другую ссылку, а бот, который говорит «Error 403», — гневное сообщение. Закрытый пост и пост без медиа стоят 0.1 кредита вместо полных 1.5.
PythonEXPLAIN = {
"PRIVATE_CONTENT": "That account is private — I can only fetch public posts.",
"MEDIA_NOT_FOUND": "That post has no media, or it was deleted.",
"UNSUPPORTED_PLATFORM": "I do not know that site yet.",
"QUOTA_EXCEEDED": "Out of credits for today.",
"UPSTREAM_TIMEOUT": "The source was slow. Send the link again.",
}Кэшируйте file_id, а не адрес медиа
Как только Telegram получил файл, он выдаёт file_id, и повторная отправка по нему не стоит ничего и ничего не загружает. Хранить адрес медиа — ошибка: CDN источников подписывают ссылки и гасят их за часы, так что кэш адресов к утру превращается в кэш из 403.
Pythonsent = await message.answer_video(media["url"]) file_id = sent.video.file_id # BU saqlanadi, media["url"] emas # Keyingi safar o'sha post so'ralsa: await message.answer_video(file_id)
Запасной путь — загрузить байты самому
Telegram пытается забрать ссылку сам, и иногда CDN источника ему отказывает — чаще всего на Instagram и всегда в медиагруппе. Поймайте этот случай, скачайте байты и отправьте файлом. Лимит на загрузку ботом в 50 МБ при этом никуда не девается, поэтому это запасной путь, а не основной.
Pythonfrom aiogram.types import BufferedInputFile
async def send_bytes(message: Message, url: str):
r = await client.get(url, follow_redirects=True)
file = BufferedInputFile(r.content, filename="video.mp4")
await message.answer_video(file)Вопросы перед началом
- Может ли бот отправлять файлы больше 50 МБ?
- Загрузкой — нет: 50 МБ это потолок Telegram для загрузки ботом. Обычный обход — отправить адрес медиа и дать Telegram забрать его самому либо держать большие файлы в приватном канале и копировать сообщение по file_id.
- Нужен ли отдельный обработчик для каждой платформы?
- Нет. /v1/download определяет платформу по ссылке, поэтому один обработчик закрывает все поддерживаемые сайты. Отдельные эндпоинты нужны тогда, когда вы намеренно принимаете только одну платформу.
- Что будет, если пользователь пришлёт закрытый пост?
- Придёт 403 с кодом PRIVATE_CONTENT, и спишется 0.1 кредита вместо полных 1.5. Превратите это во фразу: закрытые ссылки присылают постоянно, и человек в этом не виноват.
Платформы, использованные здесь
Другие руководства
Запустите это руководство со своим ключом
Ключ за минуту. 1 000 бесплатных кредитов, без карты и без срока.