mirror of
https://github.com/Divam-dev/aynt.git
synced 2025-02-20 11:23:20 +08:00
Updated many downloaders
This commit is contained in:
parent
963ac9afed
commit
717d74f742
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2023 Divam
|
Copyright (c) 2024 Divam
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
11
config.json
Normal file
11
config.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"general": {
|
||||||
|
"delayTimeLimit": 5000,
|
||||||
|
"localServer": "",
|
||||||
|
"fileSize": "",
|
||||||
|
"about": {
|
||||||
|
"name": "@AYNT_Bot",
|
||||||
|
"support": "@DivamYT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4060
package-lock.json
generated
4060
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aynt",
|
"name": "aynt",
|
||||||
"version": "1.1.0",
|
"version": "2.0.0",
|
||||||
"description": "AYNT Bot is a Telegram bot designed to help users easily download videos from various social media platforms such as YouTube, TikTok, Instagram, and Twitter.",
|
"description": "AYNT Bot is a Telegram bot designed to help users easily download videos from various social media platforms such as YouTube, TikTok, Instagram, and Twitter.",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -25,10 +25,13 @@
|
|||||||
"ffmpeg-static": "^5.1.0",
|
"ffmpeg-static": "^5.1.0",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"node-cron": "^3.0.2",
|
"mongodb": "^6.3.0",
|
||||||
"nodemon": "^2.0.22",
|
"nodemon": "^2.0.22",
|
||||||
|
"request": "^2.88.2",
|
||||||
|
"soundcloud-scraper": "^5.0.3",
|
||||||
"telegraf": "^4.12.2",
|
"telegraf": "^4.12.2",
|
||||||
"telegraf-session-local": "^2.1.1",
|
"telegraf-session-local": "^2.1.1",
|
||||||
|
"yt-search": "^2.10.4",
|
||||||
"ytdl-core": "^4.11.5"
|
"ytdl-core": "^4.11.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
src/commands/botStatus.js
Normal file
60
src/commands/botStatus.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
module.exports = async function statusCommand(ctx) {
|
||||||
|
const statusMessage = generateStatusMessage();
|
||||||
|
|
||||||
|
await ctx.replyWithMarkdown(statusMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
function fetchDataFromDatabase() {
|
||||||
|
const users = 1000; // Example: number of users
|
||||||
|
const messages = 5000; // Example: number of messages
|
||||||
|
const downloadedGB = 10; // Example: GB downloaded
|
||||||
|
const downloadedFiles = 20; // Example: number of files downloaded
|
||||||
|
return { users, messages, downloadedGB, downloadedFiles };
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateStatusMessage() {
|
||||||
|
const { users, messages, downloadedGB, downloadedFiles } = fetchDataFromDatabase();
|
||||||
|
|
||||||
|
// Remaining code stays the same
|
||||||
|
const uptime = process.uptime();
|
||||||
|
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024;
|
||||||
|
const nodeVersion = process.version;
|
||||||
|
|
||||||
|
const osName = () => {
|
||||||
|
switch (os.platform()) {
|
||||||
|
case 'aix': return 'AIX';
|
||||||
|
case 'darwin': return 'macOS';
|
||||||
|
case 'freebsd': return 'FreeBSD';
|
||||||
|
case 'linux': return 'Linux';
|
||||||
|
case 'openbsd': return 'OpenBSD';
|
||||||
|
case 'sunos': return 'SunOS';
|
||||||
|
case 'win32': return 'Windows';
|
||||||
|
case 'android': return 'Android';
|
||||||
|
default: return os.platform();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const osVersion = os.release();
|
||||||
|
|
||||||
|
const statusMessage = `
|
||||||
|
🤖 Bot Status:
|
||||||
|
|
||||||
|
🕒 Uptime: ${formatTime(uptime)}
|
||||||
|
👥 Users: ${users}
|
||||||
|
💬 Messages: ${messages}
|
||||||
|
📁 Downloaded Files: ${downloadedFiles}
|
||||||
|
💾 Downloaded GB: ${downloadedGB}
|
||||||
|
💻 OS: ${osName()} ${osVersion}
|
||||||
|
🚀 Node.js Version: ${nodeVersion}
|
||||||
|
`;
|
||||||
|
return statusMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(seconds) {
|
||||||
|
const hours = Math.floor(seconds / 3600);
|
||||||
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
|
const remainingSeconds = Math.floor(seconds % 60);
|
||||||
|
return `${hours}h ${minutes}m ${remainingSeconds}s`;
|
||||||
|
}
|
@ -10,9 +10,15 @@
|
|||||||
"",
|
"",
|
||||||
"Currently you can download from:",
|
"Currently you can download from:",
|
||||||
" - Youtube(in developing)",
|
" - Youtube(in developing)",
|
||||||
|
" - Youtube Music",
|
||||||
|
" - Spotify",
|
||||||
|
" - SoundCloud",
|
||||||
" - Tiktok",
|
" - Tiktok",
|
||||||
" - Instagram",
|
" - Instagram",
|
||||||
" - Twitter",
|
" - Twitter (X)",
|
||||||
|
" - Facebook",
|
||||||
|
" - Pinterest",
|
||||||
|
" - Reddit",
|
||||||
"",
|
"",
|
||||||
"Feedback - @DivamYT"
|
"Feedback - @DivamYT"
|
||||||
]
|
]
|
43
src/database/mongodb.js
Normal file
43
src/database/mongodb.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const { MongoClient } = require('mongodb');
|
||||||
|
|
||||||
|
const uri = 'mongodb://localhost:27017'; // Your MongoDB URI
|
||||||
|
const client = new MongoClient(uri);
|
||||||
|
|
||||||
|
async function connectToDatabase() {
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
console.log('Connected to MongoDB');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error connecting to MongoDB:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertUserData(userData) {
|
||||||
|
const db = client.db('your_database_name');
|
||||||
|
const usersCollection = db.collection('users');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await usersCollection.insertOne(userData);
|
||||||
|
console.log('User data inserted into the database');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error inserting user data:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateLinkCount(userId) {
|
||||||
|
const db = client.db('your_database_name');
|
||||||
|
const usersCollection = db.collection('users');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await usersCollection.updateOne({ userId }, { $inc: { linksSent: 1 } });
|
||||||
|
console.log('Links count updated for user:', userId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating link count:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
connectToDatabase,
|
||||||
|
insertUserData,
|
||||||
|
updateLinkCount
|
||||||
|
};
|
BIN
src/downloaders/downloads/7322893773615140101.mp4
Normal file
BIN
src/downloaders/downloads/7322893773615140101.mp4
Normal file
Binary file not shown.
85
src/downloaders/facebook_dl.js
Normal file
85
src/downloaders/facebook_dl.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const fs = require('fs');
|
||||||
|
require('util');
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');``
|
||||||
|
|
||||||
|
const writeFileAsync = promisify(fs.writeFile);
|
||||||
|
const unlinkAsync = promisify(fs.unlink);
|
||||||
|
|
||||||
|
const parseString = (string) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(`{"text": "${string}"}`).text;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Error parsing string");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFBInfo = async (videoUrl, cookie, useragent) => {
|
||||||
|
const headers = {
|
||||||
|
"sec-fetch-mode": "navigate",
|
||||||
|
"sec-fetch-user": "?1",
|
||||||
|
"sec-ch-ua": '"Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"',
|
||||||
|
"sec-ch-ua-mobile": "?0",
|
||||||
|
"sec-fetch-site": "none",
|
||||||
|
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||||
|
"accept-language": "en-GB,en;q=0.9,tr-TR;q=0.8,tr;q=0.7,en-US;q=0.6",
|
||||||
|
authority: "www.facebook.com",
|
||||||
|
"cache-control": "max-age=0",
|
||||||
|
cookie: cookie || "sb=Rn8BYQvCEb2fpMQZjsd6L382; datr=Rn8BYbyhXgw9RlOvmsosmVNT; c_user=100003164630629; _fbp=fb.1.1629876126997.444699739; wd=1920x939; spin.r.1004812505_b.trunk_t.1638730393_s.1_v.2_; xs=28%3A8ROnP0aeVF8XcQ%3A2%3A1627488145%3A-1%3A4916%3A%3AAcWIuSjPy2mlTPuZAeA2wWzHzEDuumXI89jH8a_QIV8; fr=0jQw7hcrFdas2ZeyT.AWVpRNl_4noCEs_hb8kaZahs-jA.BhrQqa.3E.AAA.0.0.BhrQqa.AWUu879ZtCw",
|
||||||
|
"upgrade-insecure-requests": "1",
|
||||||
|
"user-agent": useragent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!videoUrl || !videoUrl.trim() || !["facebook.com", "fb.watch"].some(domain => videoUrl.includes(domain))) {
|
||||||
|
throw new Error("Please specify a valid Facebook URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(videoUrl, { headers });
|
||||||
|
|
||||||
|
const sdMatch = data.match(/(?:"browser_native_sd_url"|"playable_url"|sd_src)\s*:\s*"([^"]*)"/);
|
||||||
|
|
||||||
|
if (sdMatch && sdMatch[1]) {
|
||||||
|
return {
|
||||||
|
sd: parseString(sdMatch[1]),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error("Unable to fetch video information at this time. Please try again");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Unable to fetch video information at this time. Please try again");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadFacebookVideo = async (ctx, facebookVideoUrl, cookie, useragent) => {
|
||||||
|
try {
|
||||||
|
const videoInfo = await getFBInfo(facebookVideoUrl, cookie, useragent);
|
||||||
|
|
||||||
|
const response = await axios({
|
||||||
|
url: videoInfo.sd,
|
||||||
|
method: 'GET',
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
});
|
||||||
|
|
||||||
|
const videoFileName = `facebook_video_${Date.now()}.mp4`;
|
||||||
|
await writeFileAsync(videoFileName, response.data);
|
||||||
|
|
||||||
|
const videoFileSize = fs.statSync(videoFileName).size;
|
||||||
|
if (videoFileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The video file is too large to send.');
|
||||||
|
await unlinkAsync(videoFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.replyWithVideo({ source: videoFileName });
|
||||||
|
|
||||||
|
await unlinkAsync(videoFileName);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading Facebook video:', error);
|
||||||
|
await ctx.reply('Error downloading Facebook video');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export the functions for use in other modules
|
||||||
|
module.exports = downloadFacebookVideo;
|
110
src/downloaders/pinterest_dl.js
Normal file
110
src/downloaders/pinterest_dl.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const fs = require('fs');
|
||||||
|
const util = require('util');
|
||||||
|
util.promisify(require('child_process').exec);
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
|
|
||||||
|
const writeFileAsync = promisify(fs.writeFile);
|
||||||
|
const unlinkAsync = promisify(fs.unlink);
|
||||||
|
|
||||||
|
async function downloadPinterestPost(ctx, url) {
|
||||||
|
try {
|
||||||
|
// Transform Pinterest link
|
||||||
|
url = url.replace('https://www.pinterest.co.uk' || `https://www.ru.pinterest.com`, 'https://www.pinterest.com');
|
||||||
|
|
||||||
|
// Fetch Pinterest post details from the downloader API
|
||||||
|
const response = await axios.get(`https://pinterestdownloader.io/frontendService/DownloaderService?url=${encodeURIComponent(url)}`);
|
||||||
|
const postData = response.data;
|
||||||
|
|
||||||
|
if (!postData || !postData.source || postData.source !== 'pinterest') {
|
||||||
|
throw new Error('Invalid Pinterest post data');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postData.medias && postData.medias.length > 0) {
|
||||||
|
// Check if it's a video post
|
||||||
|
const videoMedia = postData.medias.find(media => media.videoAvailable && media.extension === 'mp4');
|
||||||
|
|
||||||
|
if (videoMedia) {
|
||||||
|
const videoUrl = videoMedia.url;
|
||||||
|
const videoFileName = `pinterest_video_${Date.now()}.mp4`;
|
||||||
|
|
||||||
|
// Download the video
|
||||||
|
const videoResponse = await axios.get(videoUrl, { responseType: 'arraybuffer' });
|
||||||
|
await writeFileAsync(videoFileName, videoResponse.data);
|
||||||
|
|
||||||
|
// Check video file size
|
||||||
|
const videoFileSize = fs.statSync(videoFileName).size;
|
||||||
|
if (videoFileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The video file is too large to send.');
|
||||||
|
await unlinkAsync(videoFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the video to the user
|
||||||
|
await ctx.replyWithVideo({ source: videoFileName });
|
||||||
|
|
||||||
|
// Remove the downloaded file
|
||||||
|
await unlinkAsync(videoFileName);
|
||||||
|
} else {
|
||||||
|
// Check if it's a GIF post
|
||||||
|
const gifMedia = postData.medias.find(media => media.videoAvailable && media.extension === 'gif');
|
||||||
|
|
||||||
|
if (gifMedia) {
|
||||||
|
const gifUrl = gifMedia.url;
|
||||||
|
const gifFileName = `pinterest_gif_${Date.now()}.gif`;
|
||||||
|
|
||||||
|
// Download the GIF
|
||||||
|
const gifResponse = await axios.get(gifUrl, { responseType: 'arraybuffer' });
|
||||||
|
await writeFileAsync(gifFileName, gifResponse.data);
|
||||||
|
|
||||||
|
// Check GIF file size
|
||||||
|
const gifFileSize = fs.statSync(gifFileName).size;
|
||||||
|
if (gifFileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The GIF file is too large to send.');
|
||||||
|
await unlinkAsync(gifFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the GIF to the user
|
||||||
|
await ctx.replyWithDocument({ source: gifFileName });
|
||||||
|
|
||||||
|
// Remove the downloaded file
|
||||||
|
await unlinkAsync(gifFileName);
|
||||||
|
} else if (postData.medias[0].url) {
|
||||||
|
// Photo post
|
||||||
|
const photoUrl = postData.medias[0].url; // Assuming the first media is the photo
|
||||||
|
const photoFileName = `pinterest_photo_${Date.now()}.jpg`;
|
||||||
|
|
||||||
|
// Download the photo
|
||||||
|
const photoResponse = await axios.get(photoUrl, { responseType: 'arraybuffer' });
|
||||||
|
await writeFileAsync(photoFileName, photoResponse.data);
|
||||||
|
|
||||||
|
// Check photo file size
|
||||||
|
const photoFileSize = fs.statSync(photoFileName).size;
|
||||||
|
if (photoFileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The photo file is too large to send.');
|
||||||
|
await unlinkAsync(photoFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the photo to the user
|
||||||
|
await ctx.replyWithPhoto({ source: photoFileName });
|
||||||
|
|
||||||
|
// Remove the downloaded file
|
||||||
|
await unlinkAsync(photoFileName);
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid media format in Pinterest post');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('No media available in the Pinterest post');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading Pinterest post:', error);
|
||||||
|
await ctx.reply('Error downloading Pinterest post');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the function for use in other modules
|
||||||
|
module.exports = downloadPinterestPost;
|
90
src/downloaders/reddit_dl.js
Normal file
90
src/downloaders/reddit_dl.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const fs = require('fs');
|
||||||
|
const util = require('util');
|
||||||
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
|
|
||||||
|
const writeFileAsync = promisify(fs.writeFile);
|
||||||
|
const unlinkAsync = promisify(fs.unlink);
|
||||||
|
|
||||||
|
// let maxVideoSize;
|
||||||
|
// if (process.env.LOCAL_SERVER) {
|
||||||
|
// // 2GB in bytes (2 * 1024 * 1024 * 1024)
|
||||||
|
// maxVideoSize = 2 * 1024 * 1024 * 1024;
|
||||||
|
// } else {
|
||||||
|
// // 50MB in bytes (50 * 1024 * 1024)
|
||||||
|
// maxVideoSize = 50 * 1024 * 1024;
|
||||||
|
// }
|
||||||
|
|
||||||
|
async function downloadRedditPost(ctx, url) {
|
||||||
|
try {
|
||||||
|
// Extract the Reddit post ID from the URL
|
||||||
|
const match = url.match(/reddit\.com\/(?:r\/[^/]+\/comments\/|[^/]+\/comments\/)([\w-]+)/i);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error('Invalid Reddit post URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
const postId = match[1];
|
||||||
|
|
||||||
|
// Fetch post details from Reddit API
|
||||||
|
const response = await axios.get(`https://api.reddit.com/api/info.json?id=t3_${postId}`);
|
||||||
|
const postData = response.data.data.children[0].data;
|
||||||
|
|
||||||
|
// Check if it's a video post
|
||||||
|
if (postData.media && postData.media.reddit_video && postData.media.reddit_video.hls_url) {
|
||||||
|
// Video post
|
||||||
|
const hlsPlaylistUrl = postData.media.reddit_video.hls_url;
|
||||||
|
const cleanHlsPlaylistUrl = hlsPlaylistUrl.split('?')[0];
|
||||||
|
|
||||||
|
const videoFileName = `reddit_video_${postId}.mp4`;
|
||||||
|
|
||||||
|
// Use ffmpeg to download and convert the video
|
||||||
|
await exec(`ffmpeg -i ${cleanHlsPlaylistUrl} -c copy ${videoFileName}`);
|
||||||
|
|
||||||
|
// Check video file size
|
||||||
|
const videoFileSize = fs.statSync(videoFileName).size;
|
||||||
|
if (videoFileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The video file is too large to send.');
|
||||||
|
await unlinkAsync(videoFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the video to the user
|
||||||
|
await ctx.replyWithVideo({ source: videoFileName });
|
||||||
|
|
||||||
|
// Remove the downloaded file
|
||||||
|
await unlinkAsync(videoFileName);
|
||||||
|
} else if (postData.url_overridden_by_dest) {
|
||||||
|
// Photo post
|
||||||
|
const photoUrl = postData.url_overridden_by_dest;
|
||||||
|
|
||||||
|
const photoFileName = `reddit_photo_${postId}.jpg`;
|
||||||
|
|
||||||
|
const photoResponse = await axios.get(photoUrl, { responseType: 'arraybuffer' });
|
||||||
|
await writeFileAsync(photoFileName, photoResponse.data);
|
||||||
|
|
||||||
|
// Check photo file size
|
||||||
|
const photoFileSize = fs.statSync(photoFileName).size;
|
||||||
|
if (photoFileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The photo file is too large to send.');
|
||||||
|
await unlinkAsync(photoFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the photo to the user
|
||||||
|
await ctx.replyWithPhoto({ source: photoFileName });
|
||||||
|
|
||||||
|
// Remove the downloaded file
|
||||||
|
await unlinkAsync(photoFileName);
|
||||||
|
} else {
|
||||||
|
throw new Error('Unsupported Reddit post type');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading Reddit post:', error);
|
||||||
|
await ctx.reply('Error downloading Reddit post');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export the function for use in other modules
|
||||||
|
module.exports = downloadRedditPost;
|
42
src/downloaders/soundcloud_dl.js
Normal file
42
src/downloaders/soundcloud_dl.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const SoundCloud = require("soundcloud-scraper");
|
||||||
|
const fs = require("fs");
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
|
const unlinkAsync = promisify(fs.unlink);
|
||||||
|
|
||||||
|
async function downloadSoundCloudMusic(ctx, url) {
|
||||||
|
try {
|
||||||
|
const client = new SoundCloud.Client();
|
||||||
|
const song = await client.getSongInfo(url);
|
||||||
|
|
||||||
|
const stream = await song.downloadProgressive();
|
||||||
|
const fileName = `./${song.title.replace(/[^\w\s]/g, '')}.mp3`;
|
||||||
|
|
||||||
|
const writeStream = fs.createWriteStream(fileName);
|
||||||
|
|
||||||
|
stream.pipe(writeStream);
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
writeStream.on('finish', resolve);
|
||||||
|
writeStream.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileSize = fs.statSync(fileName).size;
|
||||||
|
|
||||||
|
if (fileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The audio file is too large to send.');
|
||||||
|
await unlinkAsync(fileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.replyWithAudio({ source: fileName });
|
||||||
|
|
||||||
|
// Remove the downloaded file
|
||||||
|
await unlinkAsync(fileName);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading SoundCloud music:', error);
|
||||||
|
await ctx.reply('Error downloading SoundCloud music. Please try again later.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = downloadSoundCloudMusic;
|
227
src/downloaders/spotify_dl.js
Normal file
227
src/downloaders/spotify_dl.js
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
const ytdl = require('ytdl-core');
|
||||||
|
const ytSearch = require('yt-search');
|
||||||
|
const axios = require('axios');
|
||||||
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
|
const fs = require('fs');
|
||||||
|
const ffmpegPath = require('ffmpeg-static');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
|
|
||||||
|
// Spotify API credentials
|
||||||
|
const clientId = 'acc6302297e040aeb6e4ac1fbdfd62c3';
|
||||||
|
const clientSecret = '0e8439a1280a43aba9a5bc0a16f3f009';
|
||||||
|
const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
|
||||||
|
const tokenUrl = 'https://accounts.spotify.com/api/token';
|
||||||
|
|
||||||
|
const findYouTubeVideo = async (songName, artistName) => {
|
||||||
|
const searchTerms = `${songName} ${artistName}`;
|
||||||
|
const searchResults = await ytSearch(searchTerms);
|
||||||
|
|
||||||
|
if (searchResults && searchResults.videos && searchResults.videos.length > 0) {
|
||||||
|
return searchResults.videos[0].url;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadYouTubeVideo = async (videoUrl, outputFileName, artworkFileName) => {
|
||||||
|
try {
|
||||||
|
const videoInfo = await ytdl.getBasicInfo(videoUrl);
|
||||||
|
|
||||||
|
if (!videoInfo.formats || videoInfo.formats.length === 0) {
|
||||||
|
console.error('No video formats found.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ffmpegCommand = ffmpeg({ timeout: 10 * 60 })
|
||||||
|
.input(ytdl(videoUrl, { quality: 'highestaudio' }))
|
||||||
|
.audioBitrate(256)
|
||||||
|
.audioFilter('volume=0.3');
|
||||||
|
|
||||||
|
if (artworkFileName) {
|
||||||
|
ffmpegCommand.input(artworkFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ffmpegCommand
|
||||||
|
.save(outputFileName)
|
||||||
|
.format('mp3');
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
ffmpegCommand
|
||||||
|
.on('end', resolve)
|
||||||
|
.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
const stats = fs.statSync(outputFileName);
|
||||||
|
const fileSizeInBytes = stats.size;
|
||||||
|
|
||||||
|
if (fileSizeInBytes > maxVideoSize) {
|
||||||
|
console.error('Downloaded file size exceeds the maximum limit.');
|
||||||
|
|
||||||
|
// Delete the downloaded file
|
||||||
|
await fs.promises.unlink(outputFileName);
|
||||||
|
|
||||||
|
// Delete the album artwork file if it exists
|
||||||
|
if (artworkFileName && fs.existsSync(artworkFileName)) {
|
||||||
|
try {
|
||||||
|
await fs.promises.unlink(artworkFileName);
|
||||||
|
console.log('Deleted album artwork file.');
|
||||||
|
} catch (unlinkError) {
|
||||||
|
console.error('Error deleting album artwork file:', unlinkError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputFileName;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in downloadYouTubeVideo:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Spotify API function to get data
|
||||||
|
const getSpotifyTrackInfo = async (spotifyTrackUrl) => {
|
||||||
|
const trackId = extractTrackIdFromUrl(spotifyTrackUrl);
|
||||||
|
const accessToken = await getToken();
|
||||||
|
|
||||||
|
const trackUrl = `https://api.spotify.com/v1/tracks/${trackId}`;
|
||||||
|
const trackResponse = await axios.get(trackUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const albumId = trackResponse.data.album.id;
|
||||||
|
const albumInfo = await getSpotifyAlbumInfo(albumId, accessToken);
|
||||||
|
|
||||||
|
return {
|
||||||
|
songName: trackResponse.data.name,
|
||||||
|
artistName: trackResponse.data.artists[0].name,
|
||||||
|
albumName: albumInfo.name,
|
||||||
|
albumArtworkUrl: albumInfo.images.length > 0 ? albumInfo.images[0].url : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSpotifyAlbumInfo = async (albumId, accessToken) => {
|
||||||
|
const albumUrl = `https://api.spotify.com/v1/albums/${albumId}`;
|
||||||
|
const albumResponse = await axios.get(albumUrl, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return albumResponse.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const extractTrackIdFromUrl = (spotifyTrackUrl) => {
|
||||||
|
const match = spotifyTrackUrl.match(/\/track\/(\w+)/);
|
||||||
|
return match ? match[1] : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getToken = async () => {
|
||||||
|
const response = await axios.post(
|
||||||
|
tokenUrl,
|
||||||
|
'grant_type=client_credentials',
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Basic ${authString}`,
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data.access_token;
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadSpotifyMusic = async (ctx, url) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { songName, artistName, albumArtworkUrl } = await getSpotifyTrackInfo(url);
|
||||||
|
|
||||||
|
const videoUrl = await findYouTubeVideo(songName, artistName);
|
||||||
|
|
||||||
|
if (videoUrl) {
|
||||||
|
|
||||||
|
const downloadedFileName = 'song.mp3';
|
||||||
|
|
||||||
|
const artworkFileName = 'album_artwork.jpg';
|
||||||
|
if (albumArtworkUrl) {
|
||||||
|
const artworkResponse = await axios.get(albumArtworkUrl, { responseType: 'arraybuffer' });
|
||||||
|
fs.writeFileSync(artworkFileName, Buffer.from(artworkResponse.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadedFilePath = await downloadYouTubeVideo(videoUrl, downloadedFileName, artworkFileName);
|
||||||
|
|
||||||
|
if (!downloadedFilePath) {
|
||||||
|
await ctx.reply('Error: Video size exceeds the maximum limit.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Download completed.');
|
||||||
|
|
||||||
|
const outputFileName = `${songName} (${artistName}).mp3`;
|
||||||
|
|
||||||
|
const mp3FilePath = downloadedFilePath;
|
||||||
|
const imageFilePath = 'album_artwork.jpg';
|
||||||
|
const outputFilePath = outputFileName;
|
||||||
|
|
||||||
|
const ffmpegCommand = [
|
||||||
|
'-i', mp3FilePath,
|
||||||
|
'-i', imageFilePath,
|
||||||
|
'-map', '0:0',
|
||||||
|
'-map', '1:0',
|
||||||
|
'-c', 'copy',
|
||||||
|
'-id3v2_version', '3',
|
||||||
|
'-metadata:s:v', 'title=Album cover',
|
||||||
|
outputFilePath
|
||||||
|
];
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
console.log('Starting FFmpeg process...');
|
||||||
|
const ffmpegProcess = spawn(ffmpegPath, ffmpegCommand, { stdio: 'ignore' });
|
||||||
|
|
||||||
|
ffmpegProcess.on('close', (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
console.log('FFmpeg process completed.');
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
console.error(`FFmpeg process exited with code ${code}`);
|
||||||
|
reject(`FFmpeg process exited with code ${code}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ffmpegProcess.on('error', (err) => {
|
||||||
|
console.error('FFmpeg process error:', err);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`MP3 file merged with image. Output file: ${outputFilePath}`);
|
||||||
|
|
||||||
|
await ctx.replyWithAudio({ source: outputFilePath });
|
||||||
|
|
||||||
|
console.log('Sent the merged file to the user.');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.promises.unlink(mp3FilePath);
|
||||||
|
await fs.promises.unlink(imageFilePath);
|
||||||
|
await fs.promises.unlink(outputFilePath);
|
||||||
|
console.log('Removed the downloaded files.');
|
||||||
|
} catch (unlinkError) {
|
||||||
|
console.error('Error removing downloaded files:', unlinkError);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log('No video found.');
|
||||||
|
await ctx.reply('No video found.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error:', error.message);
|
||||||
|
await ctx.reply(`Error: ${error.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = downloadSpotifyMusic;
|
@ -1,6 +1,4 @@
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const { Markup } = require('telegraf');
|
|
||||||
|
|
||||||
// Adding useragent to avoid IP bans
|
// Adding useragent to avoid IP bans
|
||||||
const headers = {
|
const headers = {
|
||||||
'User-Agent': 'TikTok 26.2.0 rv:262018 (iPhone; iOS 14.4.2; en_US) Cronet'
|
'User-Agent': 'TikTok 26.2.0 rv:262018 (iPhone; iOS 14.4.2; en_US) Cronet'
|
||||||
@ -9,8 +7,7 @@ const headers = {
|
|||||||
const getVideo = async (url) => {
|
const getVideo = async (url) => {
|
||||||
const API_URL = `https://aemt.me/download/tiktokslide?url=${encodeURIComponent(url)}`;
|
const API_URL = `https://aemt.me/download/tiktokslide?url=${encodeURIComponent(url)}`;
|
||||||
const response = await axios.get(API_URL, { headers });
|
const response = await axios.get(API_URL, { headers });
|
||||||
const data = response.data;
|
return response.data;
|
||||||
return data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = function(bot) {
|
module.exports = function(bot) {
|
||||||
@ -25,10 +22,12 @@ module.exports = function(bot) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return async function downloadTikTokVideo(ctx, videoUrl) {
|
async function downloadTikTokVideo(ctx, videoUrl) {
|
||||||
try {
|
try {
|
||||||
const fullVideoUrl = `https://${videoUrl}`;
|
// const fullVideoUrl = `https://${videoUrl}`;
|
||||||
const data = await getVideo(fullVideoUrl);
|
// const data = await getVideo(fullVideoUrl);
|
||||||
|
|
||||||
|
const data = await getVideo(videoUrl);
|
||||||
|
|
||||||
const mediaUrl = data.result.data.play;
|
const mediaUrl = data.result.data.play;
|
||||||
const isAudio = mediaUrl.endsWith('.mp3');
|
const isAudio = mediaUrl.endsWith('.mp3');
|
||||||
@ -60,5 +59,7 @@ module.exports = function(bot) {
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
ctx.reply('Error downloading media');
|
ctx.reply('Error downloading media');
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
return downloadTikTokVideo;
|
||||||
};
|
};
|
@ -1,6 +1,6 @@
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
// Function to get the media information from a Twitter URL.
|
// Function to get the media information from a Twitter URL.
|
||||||
async function getTwitterMedia(url, options = {}) {
|
async function getTwitterMedia(url, options = {}) {
|
||||||
let input = {};
|
let input = {};
|
||||||
@ -65,15 +65,6 @@ async function convertXToTwitterURL(url) {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
let maxVideoSize;
|
|
||||||
if (process.env.LOCAL_SERVER) {
|
|
||||||
// 2GB in bytes (2 * 1024 * 1024 * 1024)
|
|
||||||
maxVideoSize = 2 * 1024 * 1024 * 1024;
|
|
||||||
} else {
|
|
||||||
// 50MB in bytes (50 * 1024 * 1024)
|
|
||||||
maxVideoSize = 50 * 1024 * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to download Twitter media and send it through Telegram.
|
// Function to download Twitter media and send it through Telegram.
|
||||||
async function downloadTwitterMedia(ctx, url) {
|
async function downloadTwitterMedia(ctx, url) {
|
||||||
try {
|
try {
|
||||||
|
@ -3,6 +3,7 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const ffmpeg = require('fluent-ffmpeg');
|
const ffmpeg = require('fluent-ffmpeg');
|
||||||
const ffmpegPath = require('ffmpeg-static');
|
const ffmpegPath = require('ffmpeg-static');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
|
|
||||||
ffmpeg.setFfmpegPath(ffmpegPath);
|
ffmpeg.setFfmpegPath(ffmpegPath);
|
||||||
|
|
||||||
@ -18,16 +19,6 @@ async function downloadYoutubeVideo(ctx, url) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the size of the video in bytes
|
|
||||||
let maxVideoSize;
|
|
||||||
if (process.env.LOCAL_SERVER) {
|
|
||||||
// 2GB in bytes (2 * 1024 * 1024 * 1024)
|
|
||||||
maxVideoSize = 2 * 1024 * 1024 * 1024;
|
|
||||||
} else {
|
|
||||||
// 50MB in bytes (50 * 1024 * 1024)
|
|
||||||
maxVideoSize = 50 * 1024 * 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max video size
|
// Max video size
|
||||||
const videoSize = parseInt(format.contentLength);
|
const videoSize = parseInt(format.contentLength);
|
||||||
if (videoSize > maxVideoSize) {
|
if (videoSize > maxVideoSize) {
|
||||||
|
56
src/downloaders/youtube_music_dl.js
Normal file
56
src/downloaders/youtube_music_dl.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
const ytdl = require('ytdl-core');
|
||||||
|
const fs = require('fs');
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { maxVideoSize } = require('../handlers/links_handler');
|
||||||
|
promisify(fs.writeFile);
|
||||||
|
const unlinkAsync = promisify(fs.unlink);
|
||||||
|
|
||||||
|
async function downloadYoutubeMusic(ctx, url) {
|
||||||
|
try {
|
||||||
|
const videoIdMatch = url.match(/(?:watch\?v=|\/)([\w-]{11})/);
|
||||||
|
if (!videoIdMatch) {
|
||||||
|
throw new Error('Invalid YouTube Music link');
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoId = videoIdMatch[1];
|
||||||
|
|
||||||
|
const info = await ytdl.getInfo(videoId);
|
||||||
|
const audioFormat = ytdl.chooseFormat(info.formats, { filter: 'audioonly' });
|
||||||
|
|
||||||
|
if (!audioFormat) {
|
||||||
|
await ctx.reply('Error: No audio format found for the given YouTube Music video.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const audioStream = ytdl(videoId, { format: audioFormat });
|
||||||
|
|
||||||
|
const fileName = `${info.videoDetails.title.replace(/[^\w\s]/g, '')}.mp3`;
|
||||||
|
|
||||||
|
const writeStream = fs.createWriteStream(fileName);
|
||||||
|
|
||||||
|
audioStream.pipe(writeStream);
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
writeStream.on('finish', resolve);
|
||||||
|
writeStream.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileSize = fs.statSync(fileName).size;
|
||||||
|
|
||||||
|
if (fileSize > maxVideoSize) {
|
||||||
|
await ctx.reply('Error: The audio file is too large to send.');
|
||||||
|
await unlinkAsync(fileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.replyWithAudio({ source: fileName });
|
||||||
|
|
||||||
|
//remove the downloaded file
|
||||||
|
await unlinkAsync(fileName);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error downloading YouTube Music:', error);
|
||||||
|
await ctx.reply('Error downloading YouTube Music. Please try again later.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = downloadYoutubeMusic;
|
21
src/handlers/links_handler.js
Normal file
21
src/handlers/links_handler.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const config = require("../../config.json");
|
||||||
|
let maxVideoSize;
|
||||||
|
|
||||||
|
if (!config.general.localServer) {
|
||||||
|
// If localServer is empty, set maxVideoSize to 50MB
|
||||||
|
maxVideoSize = 50 * 1024 * 1024;
|
||||||
|
} else {
|
||||||
|
// If localServer is not empty, set maxVideoSize to 2GB
|
||||||
|
maxVideoSize = 2 * 1024 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If fileSize is defined and smaller than maxVideoSize, override maxVideoSize
|
||||||
|
if (config.general.fileSize && config.general.fileSize < maxVideoSize) {
|
||||||
|
maxVideoSize = config.general.fileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
maxVideoSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
93
src/index.js
93
src/index.js
@ -1,22 +1,25 @@
|
|||||||
const { Telegraf } = require('telegraf');
|
const {Telegraf} = require('telegraf');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
const cron = require('node-cron');
|
const statusCommand = require('./commands/botStatus');
|
||||||
|
const { MongoClient } = require('mongodb');
|
||||||
|
const config = require('../config.json');
|
||||||
|
|
||||||
let bot;
|
const bot = config.general.localServer
|
||||||
if (process.env.LOCAL_SERVER) {
|
? new Telegraf(process.env.BOT_TOKEN, { telegram: { apiRoot: config.general.localServer } })
|
||||||
bot = new Telegraf(process.env.BOT_TOKEN, { telegram: { apiRoot: process.env.LOCAL_SERVER } });
|
: new Telegraf(process.env.BOT_TOKEN);
|
||||||
} else {
|
|
||||||
bot = new Telegraf(process.env.BOT_TOKEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const downloadYoutubeVideo = require('./downloaders/youtube_dl');
|
const downloadYoutubeVideo = require('./downloaders/youtube_dl');
|
||||||
const downloadTikTokVideo = require('./downloaders/tiktok_dl')(bot);
|
const downloadTikTokVideo = require('./downloaders/tiktok_dl')(bot);
|
||||||
const downloadInstagram = require('./downloaders/instagram_dl');
|
const downloadInstagram = require('./downloaders/instagram_dl');
|
||||||
const downloadTwitterVideo = require('./downloaders/twitter_dl');
|
const downloadTwitterVideo = require('./downloaders/twitter_dl');
|
||||||
const helpMessage = require('./helpMessage.json');
|
const downloadYoutubeMusic = require('./downloaders/youtube_music_dl');
|
||||||
|
const downloadRedditPost = require('./downloaders/reddit_dl');
|
||||||
const SECONDS_PER_MINUTE = 60;
|
const downloadPinterestPost = require('./downloaders/pinterest_dl');
|
||||||
|
const downloadSoundCloudMusic = require('./downloaders/soundcloud_dl');
|
||||||
|
const downloadFacebookVideo = require('./downloaders/facebook_dl');
|
||||||
|
const downloadSpotifyMusic = require('./downloaders/spotify_dl');
|
||||||
|
|
||||||
|
const helpMessage = require('./commands/helpMessage.json');
|
||||||
let isBotRunning = false;
|
let isBotRunning = false;
|
||||||
const userLastLinkTime = {};
|
const userLastLinkTime = {};
|
||||||
|
|
||||||
@ -28,62 +31,72 @@ bot.start(async (ctx) => {
|
|||||||
bot.help(async (ctx) => {
|
bot.help(async (ctx) => {
|
||||||
try {
|
try {
|
||||||
const formattedHelpMessage = helpMessage.helpMessage.join('\n');
|
const formattedHelpMessage = helpMessage.helpMessage.join('\n');
|
||||||
await ctx.reply(formattedHelpMessage, { disable_web_page_preview: true });
|
await ctx.reply(formattedHelpMessage, {disable_web_page_preview: true});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bot.command('status', statusCommand);
|
||||||
|
|
||||||
bot.on('text', async (ctx) => {
|
bot.on('text', async (ctx) => {
|
||||||
const { id: userId } = ctx.from;
|
const {id: userId} = ctx.from;
|
||||||
const { text, date: messageTime } = ctx.message;
|
const {text, date: messageTime} = ctx.message;
|
||||||
const currentTime = Math.floor(Date.now() / 1000);
|
const currentTime = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
if (currentTime - messageTime > SECONDS_PER_MINUTE) {
|
if (currentTime - messageTime > 60) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userLastLinkTime[userId] && Date.now() - userLastLinkTime[userId] < 5000) {
|
let delayTime = config.general.delayTimeLimit;
|
||||||
await ctx.reply('You can send a link once in 5 seconds');
|
|
||||||
|
if (delayTime !== 0 && userLastLinkTime[userId] && Date.now() - userLastLinkTime[userId] < delayTime) {
|
||||||
|
await ctx.reply(`You can send a link once in ${delayTime/1000} seconds`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const youtubeUrlRegex = /(https?:\/\/(?:www\.)?youtube\.com\/watch\?v=|https?:\/\/youtu\.be\/|https?:\/\/(?:www\.)?youtube\.com\/shorts\/)([\w-]{11})/gi;
|
const youtubeUrls = text.match (/(https?:\/\/(?:www\.)?youtube\.com\/watch\?v=|https?:\/\/youtu\.be\/|https?:\/\/(?:www\.)?youtube\.com\/shorts\/)([\w-]{11})/gi);
|
||||||
const tiktokUrlRegex = /(https?:\/\/(?:www\.)?tiktok\.com\/(?:@[\w.-]+\/video\/[\w-]+|@[\w.-]+)|vm\.tiktok\.com\/[\w.-]+|vt\.tiktok\.com\/[\w.-]+)/gi;
|
const tiktokUrls = text.match (/(https?:\/\/(?:www\.)?tiktok\.com\/(?:@[\w.-]+\/video\/[\w-]+|@[\w.-]+)|vm\.tiktok\.com\/[\w.-]+|vt\.tiktok\.com\/[\w.-]+)/gi);
|
||||||
const instagramUrlRegex = /https?:\/\/(?:www\.)?instagram\.com\/(?:([^\/]+)\/)?(?:p|tv|reel|reels|stories)\/([\w.-]+)/gi;
|
const instagramUrls = text.match (/https?:\/\/(?:www\.)?instagram\.com\/(?:([^\/]+)\/)?(?:p|tv|reel|reels|stories)\/([\w.-]+)/gi);
|
||||||
const twitterUrlRegex = /(https?:\/\/(?:www\.)?(?:twitter|x)\.com\/(?:[\w.-]+)\/status\/[\d]+|https?:\/\/t\.co\/[\w.-]+)/gi;
|
const twitterUrls = text.match (/(https?:\/\/(?:www\.)?(?:twitter|x)\.com\/(?:[\w.-]+)\/status\/.+|https?:\/\/t\.co\/.+)/gi);
|
||||||
|
const youtubeMusicUrls = text.match (/https?:\/\/music\.youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)(?:&(?:list|si)=([a-zA-Z0-9_-]+))?/gi);
|
||||||
|
const redditUrls = text.match(/(https?:\/\/(?:www\.)?reddit\.com\/(?:r\/[^/]+\/comments\/|[^/]+\/comments\/)[\w-]+)/gi);
|
||||||
|
const pinterestUrls= text.match (/(https?:\/\/(?:www\.)?(?:ru\.)?pinterest\.(com|co.uk)\/pin\/[\w.-]+)/gi);
|
||||||
|
const soundcloudUrls = text.match(/https?:\/\/soundcloud\.com\/[\w.-]+\/[\w.-]+/gi);
|
||||||
|
const facebookUrls = text.match(/https?:\/\/(?:www\.|)facebook\.com\/(?:watch\?v=\d+|[^\/]+\/videos\/\d+\/?|permalink\.php\?story_fbid=\d+&id=\d+|fb\.watch\/[a-zA-Z0-9_-]+\/?)\b/gi);
|
||||||
|
const spotifyUrls = text.match(/https?:\/\/open\.spotify\.com\/track\/[a-zA-Z0-9]{22}/gi);
|
||||||
|
|
||||||
|
if (redditUrls && redditUrls.length > 0) {
|
||||||
const youtubeUrls = text.match(youtubeUrlRegex);
|
await handleDownload(ctx, redditUrls, downloadRedditPost);
|
||||||
const tiktokUrls = text.match(tiktokUrlRegex);
|
} else if (youtubeMusicUrls && youtubeMusicUrls.length > 0) {
|
||||||
const instagramUrls = text.match(instagramUrlRegex);
|
await handleDownload(ctx, youtubeMusicUrls, downloadYoutubeMusic);
|
||||||
|
} else if (youtubeUrls && youtubeUrls.length > 0) {
|
||||||
const twitterUrls = [];
|
await handleDownload(ctx, youtubeUrls, downloadYoutubeVideo);
|
||||||
let match;
|
|
||||||
while ((match = twitterUrlRegex.exec(text)) !== null) {
|
|
||||||
twitterUrls.push(match[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (youtubeUrls && youtubeUrls.length > 0) {
|
|
||||||
await handleVideoDownload(ctx, youtubeUrls, downloadYoutubeVideo);
|
|
||||||
} else if (tiktokUrls && tiktokUrls.length > 0) {
|
} else if (tiktokUrls && tiktokUrls.length > 0) {
|
||||||
await handleVideoDownload(ctx, tiktokUrls, downloadTikTokVideo);
|
await handleDownload(ctx, tiktokUrls, downloadTikTokVideo);
|
||||||
} else if (instagramUrls && instagramUrls.length > 0) {
|
} else if (instagramUrls && instagramUrls.length > 0) {
|
||||||
await handleVideoDownload(ctx, instagramUrls, downloadInstagram);
|
await handleDownload(ctx, instagramUrls, downloadInstagram);
|
||||||
} else if (twitterUrls.length > 0) {
|
} else if (twitterUrls && twitterUrls.length > 0) {
|
||||||
await handleVideoDownload(ctx, twitterUrls, downloadTwitterVideo);
|
await handleDownload(ctx, twitterUrls, downloadTwitterVideo);
|
||||||
|
} else if (pinterestUrls && pinterestUrls.length > 0) {
|
||||||
|
await handleDownload(ctx, pinterestUrls, downloadPinterestPost);
|
||||||
|
} else if (soundcloudUrls && soundcloudUrls.length > 0) {
|
||||||
|
await handleDownload(ctx, soundcloudUrls, downloadSoundCloudMusic);
|
||||||
|
} else if (facebookUrls && facebookUrls.length > 0) {
|
||||||
|
await handleDownload(ctx, facebookUrls, downloadFacebookVideo);
|
||||||
|
} else if (spotifyUrls && spotifyUrls.length > 0) {
|
||||||
|
await handleDownload(ctx, spotifyUrls, downloadSpotifyMusic);
|
||||||
} else {
|
} else {
|
||||||
await ctx.reply('Unknown command');
|
await ctx.reply('Unknown command');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleVideoDownload(ctx, urls, downloaderFn) {
|
async function handleDownload(ctx, urls, downloaderFn) {
|
||||||
for (const url of urls) {
|
for (const url of urls) {
|
||||||
await downloaderFn(ctx, url);
|
await downloaderFn(ctx, url);
|
||||||
}
|
}
|
||||||
userLastLinkTime[ctx.from.id] = Date.now();
|
userLastLinkTime[ctx.from.id] = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.launch();
|
bot.launch();
|
||||||
|
|
||||||
process.once('SIGINT', () => bot.stop('SIGINT'));
|
process.once('SIGINT', () => bot.stop('SIGINT'));
|
||||||
|
0
tests/regexTest.js
Normal file
0
tests/regexTest.js
Normal file
Loading…
x
Reference in New Issue
Block a user