diff --git a/README.md b/README.md index d1eb6ca..d5f500d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Next-Downloader-Bot -A Telegram bot for downloading TikTok videos and images without watermarks. Built with TypeScript, Grammy.js, and Redis for caching. +A Telegram bot for downloading TikTok and Instagram videos and images without watermarks. Built with TypeScript, Grammy.js, and Redis for caching. ## 🤖 Try the Bot @@ -8,12 +8,13 @@ A Telegram bot for downloading TikTok videos and images without watermarks. Buil 👉 **[Start Next Downloader Bot](https://t.me/next_downloader_bot)** -Simply send a TikTok video or image URL to the bot and it will download the content without watermarks for you. +Simply send a TikTok or Instagram video or image URL to the bot and it will download the content without watermarks for you. ## 🚀 Features - **TikTok Video Download**: Download TikTok videos without watermarks -- **Image Support**: Download TikTok image collections +- **Instagram Video Download**: Download Instagram Reels, posts, and IGTV videos without watermarks +- **Image/Photo Support**: Download TikTok and Instagram image collections - **Caching**: Redis-based caching to avoid re-downloading the same content - **Rate Limiting**: Built-in rate limiting to prevent abuse - **Internationalization**: Multi-language support (English, Russian) @@ -106,7 +107,7 @@ docker-compose -f docker-compose.dev.yml up -d ### Using the Live Bot 1. **[Start the bot](https://t.me/next_downloader_bot)** on Telegram -2. Send a TikTok video or image URL +2. Send a TikTok or Instagram video or image URL 3. The bot will download and send you the content without watermarks ### Self-Hosting @@ -114,14 +115,13 @@ docker-compose -f docker-compose.dev.yml up -d If you want to run your own instance: 1. Start a conversation with your bot on Telegram -2. Send a TikTok video or image URL +2. Send a TikTok or Instagram video or image URL 3. The bot will download and send you the content without watermarks ### Supported URL Formats -- TikTok video URLs: `https://www.tiktok.com/@username/video/1234567890` -- TikTok image URLs: `https://www.tiktok.com/@username/photo/1234567890` - Short TikTok URLs: `https://vt.tiktok.com/ZSHs35NpuL1nt-mE2tD` +- Instagram post URLs: `https://www.instagram.com/p/SHORTCODE/` ## 🏗️ Project Structure @@ -229,7 +229,7 @@ The bot includes comprehensive logging using Pino: 1. Fork the repository 2. Create a feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add some amazing feature'`) -4. Push to the branch (`git push origin feature/amazing-feature`) +4. Push to the branch (`git push origin feature/amazing-feature'`) 5. Open a Pull Request ## 📄 License @@ -238,7 +238,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file ## ⚠️ Disclaimer -This bot is for educational purposes only. Please respect TikTok's terms of service and copyright laws. Users are responsible for ensuring they have the right to download and use the content. +This bot is for educational purposes only. Please respect TikTok's and Instagram's terms of service and copyright laws. Users are responsible for ensuring they have the right to download and use the content. ## 🆘 Support @@ -254,3 +254,4 @@ If you encounter any issues: - [Telegram Bot API](https://core.telegram.org/bots/api) - [TikTok API DL](https://github.com/tobyg74/tiktok-api-dl) - [Redis Documentation](https://redis.io/documentation) +- [Instagram Platform Documentation](https://developers.facebook.com/docs/instagram) diff --git a/apps/bot/locales/en.ftl b/apps/bot/locales/en.ftl index 9144188..1c31271 100644 --- a/apps/bot/locales/en.ftl +++ b/apps/bot/locales/en.ftl @@ -3,12 +3,13 @@ description = This bot allows you to quickly download videos and images from popular platforms directly to Telegram. 🟢 **Currently supported:** - - TikTok (without watermark) + - TikTok + - Instagram ⚡ Simply send the video link, and the bot will download it for you. short-description = - Download TikTok videos (without watermark). + Download TikTok, Instagram videos and images. For any questions: @v_dev_support @@ -17,10 +18,10 @@ start = .description = Start the bot -err-invalid-url = ❌ Invalid URL! Please send a valid TikTok link (e.g., https://vt.tiktok.com/...) +err-invalid-url = ❌ Invalid URL! Please send a valid TikTok or Instagram link (e.g., https://vt.tiktok.com/ or https://www.instagram.com/p/) err-invalid-download-urls = 🔍 Download links not found. The video might be deleted or unavailable err-generic = ⚠️ Something went wrong. Please try again in a few seconds err-limit-exceeded = 🚫 Too many requests! Please wait -msg-welcome = Welcome! I can download TikTok videos and images for you without watermark. Just send me the link (for example: https://vt.tiktok.com/...) \ No newline at end of file +msg-welcome = Welcome! I can download TikTok or Instagram videos and images for you without watermark. Just send me the link (for example: https://vt.tiktok.com/ or https://www.instagram.com/p/) \ No newline at end of file diff --git a/apps/bot/locales/ru.ftl b/apps/bot/locales/ru.ftl index 547f2a4..82fb860 100644 --- a/apps/bot/locales/ru.ftl +++ b/apps/bot/locales/ru.ftl @@ -3,12 +3,13 @@ description = Этот бот позволяет быстро скачивать видео и изображения из популярных платформ прямо в Telegram. 🟢 **Текущая поддержка:** - - TikTok (без водяного знака) + - TikTok + - Instagram ⚡ Просто отправьте ссылку на видео и изображения, и бот сразу скачает его для вас! short-description = - Скачивай видео и изображения из TikTok (без водяного знака). + Скачивай видео и изображения из TikTok и Instagram. По всем вопросам: @v_dev_support @@ -17,10 +18,10 @@ start = .description = Запуск бота -err-invalid-url = ❌ Неверная ссылка! Отправьте корректную ссылку TikTok (например: https://vt.tiktok.com/...) +err-invalid-url = ❌ Неверная ссылка! Отправьте корректную ссылку TikTok или Instagram (например: https://vt.tiktok.com/ или https://www.instagram.com/p/) err-invalid-download-urls = 🔍 Не удалось найти ссылки для скачивания. Возможно, видео и изображения удалено или недоступно err-generic = ⚠️ Что-то пошло не так. Попробуйте еще раз через несколько секунд err-limit-exceeded = 🚫 Слишком много запросов! Подождите немного -msg-welcome = Добро пожаловать! Я могу скачать для вас видео и изображения из TikTok без водяного знака. Для этого просто отправьте мне ссылку (например: https://vt.tiktok.com/...) \ No newline at end of file +msg-welcome = Добро пожаловать! Я могу скачать для вас видео и изображения из TikTok или Instagram без водяного знака. Для этого просто отправьте мне ссылку (например: https://vt.tiktok.com/ или https://www.instagram.com/p/) \ No newline at end of file diff --git a/apps/bot/package.json b/apps/bot/package.json index 07685f6..e7cf4ba 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -14,6 +14,7 @@ "telegram", "bot", "tiktok", + "instagram", "video", "download" ], diff --git a/apps/bot/src/bot/features/download.ts b/apps/bot/src/bot/features/download.ts index dbd3404..a9dd65b 100644 --- a/apps/bot/src/bot/features/download.ts +++ b/apps/bot/src/bot/features/download.ts @@ -4,7 +4,8 @@ import { logHandle } from '../helpers/logging'; import { TTL_URLS } from '@/config/redis'; import { getRedisInstance } from '@/utils/redis'; import { getTiktokDownloadUrl } from '@/utils/tiktok'; -import { validateTikTokUrl } from '@/utils/urls'; +import { getInstagramDownloadUrl } from '@/utils/instagram'; +import { validateTikTokUrl, validateInstagramUrl } from '@/utils/urls'; import { Composer, InputFile } from 'grammy'; import { cluster } from 'radashi'; @@ -16,7 +17,10 @@ const redis = getRedisInstance(); feature.on('message:text', logHandle('download-message'), async (context) => { const url = context.message.text.trim(); - if (!validateTikTokUrl(url)) { + const isTikTok = validateTikTokUrl(url); + const isInstagram = validateInstagramUrl(url); + + if (!isTikTok && !isInstagram) { return context.reply(context.t('err-invalid-url')); } @@ -25,7 +29,18 @@ feature.on('message:text', logHandle('download-message'), async (context) => { return context.replyWithVideo(cachedFileId); } - const { images: imagesUrls, play: videoUrl } = await getTiktokDownloadUrl(url); + 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; + } if (!videoUrl && !imagesUrls?.length) { return context.reply(context.t('err-invalid-download-urls')); diff --git a/apps/bot/src/constants/regex.ts b/apps/bot/src/constants/regex.ts index 9c46c5c..adc5271 100644 --- a/apps/bot/src/constants/regex.ts +++ b/apps/bot/src/constants/regex.ts @@ -1,3 +1,6 @@ /* eslint-disable sonarjs/regex-complexity */ export const TIKTOK_URL_REGEX = /https:\/\/(?:m|t|www|vm|vt|lite)?\.?tiktok\.com\/(.*\b(?:(?:usr|v|embed|user|video|photo)\/|\?shareId=|&item_id=)(\d+)|\w+)/u; + +export const INSTAGRAM_URL_REGEX = + /https?:\/\/(www\.)?instagram\.com\/(p|reel|tv|stories)\/([a-zA-Z0-9_-]+)(\/)?(\?utm_source=ig_web_copy_link&igshid=[a-z0-9]+)?/u; diff --git a/apps/bot/src/utils/instagram.ts b/apps/bot/src/utils/instagram.ts new file mode 100644 index 0000000..9f8235b --- /dev/null +++ b/apps/bot/src/utils/instagram.ts @@ -0,0 +1,45 @@ +import axios from 'axios'; + +export interface Root { + type: string; + id: number; + url: string; + username: string; + mediaUrls: string[]; + carouselItems: CarouselItem[]; + authorInfo: AuthorInfo; +} + +export interface CarouselItem { + url: string; + type: string; +} + +export interface AuthorInfo { + id: number; + username: string; + nickname: string; + avatar: string; +} + +export async function getInstagramDownloadUrl(url: string) { + const { data } = await axios.post('https://thesocialcat.com/api/instagram-download', { + url, + }); + + if (!data) throw new Error('Invalid Instagram response'); + + const isVideo = data.type === 'video' || !data.carouselItems.length; + + if (isVideo) { + return { + play: data.mediaUrls.at(0), + images: [], + }; + } + + return { + images: data.mediaUrls, + play: undefined, + }; +} diff --git a/apps/bot/src/utils/urls.ts b/apps/bot/src/utils/urls.ts index f96e42a..5c8b0b5 100644 --- a/apps/bot/src/utils/urls.ts +++ b/apps/bot/src/utils/urls.ts @@ -1,5 +1,9 @@ -import { TIKTOK_URL_REGEX } from '@/constants/regex'; +import { INSTAGRAM_URL_REGEX, TIKTOK_URL_REGEX } from '@/constants/regex'; export function validateTikTokUrl(url: string) { return TIKTOK_URL_REGEX.test(url); } + +export function validateInstagramUrl(url: string) { + return INSTAGRAM_URL_REGEX.test(url); +}