From e79b0216b2d027d382cbc3af821565fe1e5c2e59 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Fri, 26 Dec 2025 16:44:12 +0300 Subject: [PATCH] feat: enhance error handling and add limits for video downloads --- apps/bot/locales/en.ftl | 6 ++++++ apps/bot/locales/ru.ftl | 6 ++++++ apps/bot/src/bot/features/download.ts | 31 +++++++++++++++++---------- apps/bot/src/constants/limits.ts | 1 + apps/bot/src/utils/instagram.ts | 2 +- apps/bot/src/utils/tiktok.ts | 2 +- apps/bot/src/utils/youtube.ts | 7 +++--- 7 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 apps/bot/src/constants/limits.ts diff --git a/apps/bot/locales/en.ftl b/apps/bot/locales/en.ftl index c97e12e..67e9d52 100644 --- a/apps/bot/locales/en.ftl +++ b/apps/bot/locales/en.ftl @@ -24,5 +24,11 @@ err-invalid-download-urls = 🔍 Download links not found. The video might be de err-generic = ⚠️ Something went wrong. Please try again in a few seconds err-limit-exceeded = 🚫 Too many requests! Please wait +err-invalid-tiktok-response = 🔍 Invalid TikTok response. The video might be deleted or unavailable +err-invalid-instagram-response = 🔍 Invalid Instagram response. The post might be deleted or unavailable +err-invalid-youtube-response = 🔍 Invalid YouTube response. The video might be deleted or unavailable +err-youtube-duration-exceeded = 🚫 Video duration exceeds limit +err-youtube-no-quality = 🔍 No suitable quality found for this video + msg-welcome = Welcome! I can download TikTok, Instagram or YouTube videos and images for you without watermark. Just send me the link (for example: https://vt.tiktok.com/ or https://www.instagram.com/p/ or https://www.youtube.com/) \ No newline at end of file diff --git a/apps/bot/locales/ru.ftl b/apps/bot/locales/ru.ftl index a8b9233..1e9b8bd 100644 --- a/apps/bot/locales/ru.ftl +++ b/apps/bot/locales/ru.ftl @@ -24,5 +24,11 @@ err-invalid-download-urls = 🔍 Не удалось найти ссылки д err-generic = ⚠️ Что-то пошло не так. Попробуйте еще раз через несколько секунд err-limit-exceeded = 🚫 Слишком много запросов! Подождите немного +err-invalid-tiktok-response = 🔍 Некорректный ответ от TikTok. Видео может быть удалено или недоступно +err-invalid-instagram-response = 🔍 Некорректный ответ от Instagram. Запись может быть удалена или недоступна +err-invalid-youtube-response = 🔍 Некорректный ответ от YouTube. Видео может быть удалено или недоступно +err-youtube-duration-exceeded = 🚫 Длительность видео превышает лимит +err-youtube-no-quality = 🔍 Не найдено подходящее качество для этого видео + msg-welcome = Добро пожаловать! Я могу скачать для вас видео и изображения из TikTok, Instagram или YouTube без водяного знака. Для этого просто отправьте мне ссылку (например: https://vt.tiktok.com/, https://www.instagram.com/p/ или https://www.youtube.com/watch?v=) \ No newline at end of file diff --git a/apps/bot/src/bot/features/download.ts b/apps/bot/src/bot/features/download.ts index 67df91a..fb1be43 100644 --- a/apps/bot/src/bot/features/download.ts +++ b/apps/bot/src/bot/features/download.ts @@ -34,17 +34,26 @@ feature.on('message:text', logHandle('download-message'), async (context) => { let imagesUrls: string[] | undefined; let videoUrl: string | undefined; - if (isTikTok) { - const result = await getTiktokDownloadUrl(url); - imagesUrls = result.images; - videoUrl = result.play; - } else if (isInstagram) { - const result = await getInstagramDownloadUrl(url); - imagesUrls = result.images; - videoUrl = result.play; - } else if (isYoutube) { - const result = await getYoutubeDownloadUrl(url); - videoUrl = result.play; + try { + if (isTikTok) { + const result = await getTiktokDownloadUrl(url); + imagesUrls = result.images; + videoUrl = result.play; + } else if (isInstagram) { + const result = await getInstagramDownloadUrl(url); + imagesUrls = result.images; + videoUrl = result.play; + } else if (isYoutube) { + const result = await getYoutubeDownloadUrl(url); + videoUrl = result.play; + } + } catch (err: any) { + const message = err?.message ?? String(err); + if (typeof message === 'string' && message.startsWith('err-')) { + return context.reply(context.t(message)); + } + + return context.reply(context.t('err-generic')); } if (!videoUrl && !imagesUrls?.length) { diff --git a/apps/bot/src/constants/limits.ts b/apps/bot/src/constants/limits.ts new file mode 100644 index 0000000..85c6701 --- /dev/null +++ b/apps/bot/src/constants/limits.ts @@ -0,0 +1 @@ +export const MAX_VIDEO_DURATION_SECONDS = 180; // 3 minutes \ No newline at end of file diff --git a/apps/bot/src/utils/instagram.ts b/apps/bot/src/utils/instagram.ts index 9f8235b..ba33454 100644 --- a/apps/bot/src/utils/instagram.ts +++ b/apps/bot/src/utils/instagram.ts @@ -27,7 +27,7 @@ export async function getInstagramDownloadUrl(url: string) { url, }); - if (!data) throw new Error('Invalid Instagram response'); + if (!data) throw new Error('err-invalid-instagram-response'); const isVideo = data.type === 'video' || !data.carouselItems.length; diff --git a/apps/bot/src/utils/tiktok.ts b/apps/bot/src/utils/tiktok.ts index 3a570a8..f27ea96 100644 --- a/apps/bot/src/utils/tiktok.ts +++ b/apps/bot/src/utils/tiktok.ts @@ -39,7 +39,7 @@ export async function getTiktokDownloadUrl(url: string) { const res = await axios.get(`https://tikwm.com/api/?url=${encodeURIComponent(url)}`); const { data } = res.data as Root; - if (!data) throw new Error('Invalid TikTok response'); + if (!data) throw new Error('err-invalid-tiktok-response'); return data; } diff --git a/apps/bot/src/utils/youtube.ts b/apps/bot/src/utils/youtube.ts index 787da78..c905320 100644 --- a/apps/bot/src/utils/youtube.ts +++ b/apps/bot/src/utils/youtube.ts @@ -1,3 +1,4 @@ +import { MAX_VIDEO_DURATION_SECONDS } from '@/constants/limits'; import axios from 'axios'; import { wrapper } from 'axios-cookiejar-support'; import * as tough from 'tough-cookie'; @@ -64,8 +65,8 @@ export async function getYoutubeDownloadUrl(url: string) { }, ); - if (!infoData?.medias.length) throw new Error('Invalid YouTube response'); - if (infoData.duration > 120) throw new Error('Video duration exceeds limit'); + if (!infoData?.medias.length) throw new Error('err-invalid-youtube-response'); + if (infoData.duration > MAX_VIDEO_DURATION_SECONDS) throw new Error('err-youtube-duration-exceeded'); let quality: string | undefined; @@ -80,7 +81,7 @@ export async function getYoutubeDownloadUrl(url: string) { } } - if (!quality) throw new Error('No suitable quality found'); + if (!quality) throw new Error('err-youtube-no-quality'); // fetch download link const { data: downloadData } = await client.post(