saveapi.org

Telegram-бот для скачивания видео на grammY

grammY — современный Node.js-фреймворк для Telegram-ботов, и бот «ссылка → видео» на нём — около тридцати строк, когда разрешение — это HTTP-вызов. Это руководство — фильтр entity, ловящий ссылки, методы ответа, принимающие URL напрямую, понятные пользователю фразы ошибок и единственное, что стоит кешировать.

Обновлено

Установка

Только grammY; fetch встроен в Node 18+. Никакого стека скрейпинга и браузера, который нужно держать живым.

Terminal
npm install grammy

Разрешите ссылку

Один GET с ключом в заголовке Authorization. AbortSignal.timeout не даёт медленному источнику держать ваш обработчик. Эндпоинт определяет платформу по URL, бот не ветвится по домену.

JavaScript
const API = "https://api.saveapi.org/v1/download";

async function resolve(link) {
  const res = await fetch(API + "?url=" + encodeURIComponent(link), {
    headers: { Authorization: "Bearer sk_live_xxxx" },
    signal: AbortSignal.timeout(30_000),
  });
  return res.json();
}

Ловите ссылки и отвечайте медиа

message::url срабатывает на любое сообщение с entity типа URL; ctx.entities("url") отдаёт текст. replyWithVideo и replyWithPhoto принимают URL медиа напрямую — Telegram скачает сам. Проверяйте medias[0].type: слайдшоу или карусель — изображения, не видео.

JavaScript
import { Bot } from "grammy";

const bot = new Bot(process.env.BOT_TOKEN);

bot.on("message::url", async (ctx) => {
  const link = ctx.entities("url")[0].text;
  const data = await resolve(link);

  if (!data.success) {
    return ctx.reply(EXPLAIN[data.error.code] ?? "Try another link.");
  }

  const media = data.medias[0];
  return media.type === "video"
    ? ctx.replyWithVideo(media.url, { caption: data.meta?.title ?? "" })
    : ctx.replyWithPhoto(media.url);
});

bot.start();

Объясняйте ошибки, с которыми люди сталкиваются

Пользователи целый день вставляют закрытые посты и мёртвые ссылки. Сопоставьте стабильные коды с фразами: бот, говорящий «этот аккаунт закрыт», получает другую ссылку, бот, говорящий «ошибка», — злое сообщение. Закрытые и отсутствующие стоят 0.1 кредита, а не полные 1.5.

JavaScript
const EXPLAIN = {
  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.",
  UPSTREAM_TIMEOUT: "The source was slow. Send the link again.",
};

Кешируйте file_id Telegram, а не URL медиа

После первой отправки Telegram даёт file_id; его повторная отправка ничего не загружает и не тратит кредиты. URL медиа хранить не стоит — ссылки CDN подписаны и истекают за часы.

Вопросы перед началом

Бот может отправлять файлы больше 50 МБ?
Не загрузкой; 50 МБ — потолок Telegram для загрузки ботом. Передача URL медиа позволяет Telegram забрать файл самому, а повторная отправка по file_id не зависит от размера.
Работает с webhook?
Да — обработчик тот же; меняется только bot.start() на webhookCallback. Сохраните таймаут fetch: у webhook-обработчика тоже есть дедлайн.
А если Telegram отказывается забирать URL?
Скачайте байты сами и отправьте как InputFile. Чаще всего это Instagram и всегда — медиагруппы; оставьте это запасным путём, а не основным.

Платформы, использованные здесь

Другие руководства

Запустите это руководство со своим ключом

Ключ за минуту. 1 000 бесплатных кредитов, без карты и без срока.

Получить ключ и попробоватьПолный справочник API