Skip to content

Instantly share code, notes, and snippets.

@mistershubhamkumar
Forked from weskerty/dla.js
Created April 22, 2025 00:45
Show Gist options
  • Select an option

  • Save mistershubhamkumar/31433d2bfad0b83763e385efe32ebaca to your computer and use it in GitHub Desktop.

Select an option

Save mistershubhamkumar/31433d2bfad0b83763e385efe32ebaca to your computer and use it in GitHub Desktop.
Download Everything, YT-DLP and CURL - DownLoadAll.
// MR. De la Comunidad para la Comunidad. Prohibida su Venta.
// El Software se proporciona bajo los términos de la Licencia MIT, excepto que usted no puede:
// 1. Vender, revender o arrendar el Software.
// 2. Cobrar a otros por el acceso, la distribución o cualquier otro uso comercial del Software.
// 3. Usar el Software como parte de un producto comercial o una oferta de servicio.
// v19 Limite Playlist en MP3. Change curl t wget
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
const { promisify } = require('util');
const { exec: execCallback } = require('child_process');
const { bot, isUrl } = require('../lib');
require('dotenv').config();
const exec = promisify(execCallback);
const FILE_TYPES = {
video: {
extensions: new Set(['mp4', 'mkv', 'avi', 'webm', 'mov', 'flv', 'm4v']),
mimetype: 'video/mp4',
},
image: {
extensions: new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'tiff', 'svg']),
mimetype: 'image/jpeg',
},
document: {
extensions: new Set(['pdf', 'epub', 'docx', 'txt', 'apk', 'apks', 'zip', 'rar', 'iso', 'ini', 'cbr', 'cbz', 'torrent', 'json', 'xml', 'html', 'css', 'js', 'csv', 'xls', 'xlsx', 'ppt', 'pptx']),
mimetypes: new Map([
['pdf', 'application/pdf'],
['epub', 'application/epub+zip'],
['docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['txt', 'text/plain'],
['apk', 'application/vnd.android.package-archive'],
['apks', 'application/vnd.android.package-archive'],
['zip', 'application/zip'],
['rar', 'application/x-rar-compressed'],
['iso', 'application/x-iso9660-image'],
['ini', 'text/plain'],
['cbr', 'application/x-cbr'],
['cbz', 'application/x-cbz'],
['torrent', 'application/x-bittorrent'],
['json', 'application/json'],
['xml', 'application/xml'],
['html', 'text/html'],
['css', 'text/css'],
['js', 'application/javascript'],
['csv', 'text/csv'],
['xls', 'application/vnd.ms-excel'],
['xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
['ppt', 'application/vnd.ms-powerpoint'],
['pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
]),
defaultMimetype: 'application/octet-stream',
},
audio: {
extensions: new Set(['mp3', 'wav', 'ogg', 'flac', 'm4a', 'aac', 'wma']),
mimetype: 'audio/mpeg',
},
};
function getFileDetails(filePath) {
const ext = path.extname(filePath).slice(1).toLowerCase();
for (const [category, typeInfo] of Object.entries(FILE_TYPES)) {
if (typeInfo.extensions.has(ext)) {
return {
category,
mimetype: category === 'document'
? typeInfo.mimetypes.get(ext) || typeInfo.defaultMimetype
: typeInfo.mimetype,
};
}
}
return {
category: 'document',
mimetype: FILE_TYPES.document.defaultMimetype,
};
}
class DownloadQueue {
constructor(maxConcurrent = 2) {
this.queue = [];
this.activeDownloads = 0;
this.maxConcurrent = maxConcurrent;
}
async add(task) {
return new Promise((resolve, reject) => {
this.queue.push({ task, resolve, reject });
this.processNext();
});
}
async processNext() {
if (this.activeDownloads >= this.maxConcurrent || this.queue.length === 0) {
return;
}
this.activeDownloads++;
const { task, resolve, reject } = this.queue.shift();
try {
const result = await task();
resolve(result);
} catch (error) {
reject(error);
} finally {
this.activeDownloads--;
this.processNext();
}
}
}
class MediaDownloader {
constructor() {
this.config = {
tempDir: process.env.TEMP_DOWNLOAD_DIR || path.join(process.cwd(), 'tmp'),
maxFileSize: (parseInt(process.env.MAX_UPLOAD, 10) * 1048576) || 1500000000,
ytDlpPath: path.join(process.cwd(), 'media', 'bin'),
maxConcurrent: parseInt(process.env.MAXSOLICITUD, 10) || 2,
playlistLimit: parseInt(process.env.PLAYLIST_LIMIT, 10) || 10 // limite playlist mp3
};
this.downloadQueue = new DownloadQueue(this.config.maxConcurrent);
this.ytDlpBinaries = new Map([
['win32-x64', 'yt-dlp.exe'],
['win32-ia32', 'yt-dlp_x86.exe'],
['darwin', 'yt-dlp_macos'],
['linux-x64', 'yt-dlp_linux'],
['linux-arm64', 'yt-dlp_linux_aarch64'],
['linux-arm', 'yt-dlp_linux_armv7l'],
['default', 'yt-dlp'],
]);
}
generateSafeFileName(originalName) {
const ext = path.extname(originalName);
const timestamp = Date.now();
return `download_${timestamp}${ext}`;
}
async safeExecute(command, silentError = false) {
try {
const result = await exec(command);
return result;
} catch (error) {
if (!silentError) {
console.error(`Execution failed: ${error.message}`);
}
throw new Error('Execution failed');
}
}
async isYtDlpAvailable() {
try {
await exec('yt-dlp --version', { stdio: 'ignore' });
return true;
} catch {
return false;
}
}
detectYtDlpBinaryName() {
const platform = os.platform();
const arch = os.arch();
const key = `${platform}-${arch}`;
return this.ytDlpBinaries.get(key) || this.ytDlpBinaries.get('default');
}
async ensureDirectories() {
await Promise.all([
fs.mkdir(this.config.tempDir, { recursive: true }),
fs.mkdir(this.config.ytDlpPath, { recursive: true }),
]);
}
async detectYtDlpBinary(message) {
if (await this.isYtDlpAvailable()) {
return 'yt-dlp';
}
const fileName = this.detectYtDlpBinaryName();
const filePath = path.join(this.config.ytDlpPath, fileName);
try {
await fs.access(filePath);
return filePath;
} catch {
return message ? await this.downloadYtDlp(message) : null;
}
}
async downloadYtDlp(message) {
await this.ensureDirectories();
const fileName = this.detectYtDlpBinaryName();
const downloadUrl = `https://github.com/yt-dlp/yt-dlp/releases/latest/download/${fileName}`;
const filePath = path.join(this.config.ytDlpPath, fileName);
try {
await this.safeExecute(`wget -O "${filePath}" "${downloadUrl}"`);
if (os.platform() !== 'win32') {
await fs.chmod(filePath, '755');
}
return filePath;
} catch (error) {
// node-fetch fallback
const fetch = (await import('node-fetch')).default;
const response = await fetch(downloadUrl);
if (!response.ok) throw new Error(`Download failed: ${response.statusText}`);
const buffer = Buffer.from(await response.arrayBuffer());
await fs.writeFile(filePath, buffer);
if (os.platform() !== 'win32') {
await fs.chmod(filePath, '755');
}
return filePath;
}
}
async processDownloadedFile(message, filePath, originalFileName, outputDir) {
const { mimetype, category } = getFileDetails(filePath);
const fileBuffer = await fs.readFile(filePath);
const safeFileName = this.generateSafeFileName(originalFileName);
await message.send(
fileBuffer,
{ fileName: safeFileName, mimetype, quoted: message.data },
category
);
await fs.unlink(filePath).catch(() => {});
}
async downloadWithWget(message, url, options = '') {
return this.downloadQueue.add(async () => {
const sessionId = `wget_${Date.now()}`;
const outputDir = path.join(this.config.tempDir, sessionId);
await this.ensureDirectories();
await fs.mkdir(outputDir, { recursive: true });
const originalFileName = path.basename(new URL(url).pathname) || 'download';
const safeFileName = this.generateSafeFileName(originalFileName);
const outputFilePath = path.join(outputDir, safeFileName);
try {
await this.safeExecute(
`wget ${options} -O "${outputFilePath}" "${url}"`
);
await this.processDownloadedFile(message, outputFilePath, originalFileName, outputDir);
} catch (error) {
console.error(`Wget download failed: ${error.message}`);
} finally {
await fs.rm(outputDir, { recursive: true, force: true }).catch(() => {});
}
});
}
async downloadWithYtDlp(message, urls, options = '', enablePlaylist = false) {
return this.downloadQueue.add(async () => {
const ytDlpPath = await this.detectYtDlpBinary(message);
const sessionId = `yt-dlp_${Date.now()}`;
const outputDir = path.join(this.config.tempDir, sessionId);
await this.ensureDirectories();
await fs.mkdir(outputDir, { recursive: true });
for (const url of urls) {
const safePattern = path.join(outputDir, '%(title)s.%(ext)s');
let playlistFlag = enablePlaylist ? '--yes-playlist' : '--no-playlist';
let playlistItemsFlag = '';
if (enablePlaylist) {
playlistItemsFlag = `--playlist-items 1:${this.config.playlistLimit}`;
}
const baseCommand = `${ytDlpPath} --max-filesize ${this.config.maxFileSize} -o "${safePattern}" ${playlistFlag} ${playlistItemsFlag} "${url}"`;
const downloadCommand = `${baseCommand} ${options}`;
let downloadSuccess = false;
try {
await this.safeExecute(downloadCommand, true);
downloadSuccess = true;
} catch (error) {
console.error(`Failed with full options: ${error.message}`);
try {
await this.safeExecute(baseCommand, true);
downloadSuccess = true;
} catch (fallbackError) {
console.error(`Fallback also failed: ${fallbackError.message}`);
try {
await this.updateYtDlp(message, true);
} catch (updateError) {
console.error(`Update failed: ${updateError.message}`);
}
}
}
if (downloadSuccess) {
try {
const files = await fs.readdir(outputDir);
for (const file of files) {
try {
await this.processDownloadedFile(
message,
path.join(outputDir, file),
file,
outputDir
);
} catch (processError) {
console.error(`Failed to process file ${file}: ${processError.message}`);
}
}
} catch (error) {
console.error(`Failed to read output directory: ${error.message}`);
}
}
}
await fs.rm(outputDir, { recursive: true, force: true }).catch(() => {});
});
}
async updateYtDlp(message, silent = false) {
try {
if (await this.isYtDlpAvailable()) {
await this.safeExecute('pip install -U --pre "yt-dlp[default]" ');
if (!silent) {
await message.send('✅ yt-dlp Updated pip', { quoted: message.data });
}
} else {
const filePath = await this.downloadYtDlp(message);
if (!silent) {
await message.send(`✅ yt-dlp Updated Bin _${filePath}_`, { quoted: message.data });
}
}
} catch (error) {
if (!silent) {
await message.send(`✅ yt-dlp Update attempted`, { quoted: message.data });
}
}
}
async searchAndDownload(message, searchQuery, isVideo = false) {
return this.downloadQueue.add(async () => {
const sessionId = `yt-dlp_${Date.now()}`;
const outputDir = path.join(this.config.tempDir, sessionId);
await this.ensureDirectories();
await fs.mkdir(outputDir, { recursive: true });
const safePattern = path.join(outputDir, 'download.%(ext)s');
const ytDlpPath = await this.detectYtDlpBinary(message);
const searchSources = [
{ source: 'ytsearch', name: 'YouTube' },
...(isVideo ? [] : [
{ source: 'scsearch', name: 'SoundCloud' },
{ source: 'nicosearch', name: 'NicoNico' }
])
];
let success = false;
for (const { source, name } of searchSources) {
if (success) break;
try {
const baseCommand = `${ytDlpPath} --max-filesize ${this.config.maxFileSize} --playlist-items 1 -o "${safePattern}" --ignore-errors --no-abort-on-error`;
const videoOptions = isVideo ? '-f "bestvideo[height<=720][ext=mp4][vcodec=h264]+bestaudio[acodec=aac]/best[height<=720][vcodec=h264]/best[ext=mp4]/best" --merge-output-format mp4 ' : '-x --audio-format mp3';
const command = `${baseCommand} ${videoOptions} "${source}10:${searchQuery}"`;
try {
await this.safeExecute(command, true);
} catch (error) {
await this.safeExecute(`${baseCommand} "${source}10:${searchQuery}"`, true);
}
const files = await fs.readdir(outputDir);
if (files.length > 0) {
await Promise.all(
files.map(file => this.processDownloadedFile(
message,
path.join(outputDir, file),
file,
outputDir
))
);
success = true;
break;
}
} catch (error) {
await fs.rm(outputDir, { recursive: true, force: true }).catch(() => {});
await fs.mkdir(outputDir, { recursive: true });
}
}
if (!success) {
console.error(`No results found for ${searchQuery}`);
}
await fs.rm(outputDir, { recursive: true, force: true }).catch(() => {});
});
}
}
const mediaDownloader = new MediaDownloader();
bot(
{
pattern: 'dla ?(.*)',
fromMe: true,
desc: 'Download All Media Web Site.',
type: 'download',
},
async (message, match) => {
const input = match.trim() || message.reply_message?.text || '';
if (!input) {
await message.send(
'> 🎶Search and Download Song:\n`dla` <query>\n' +
'> 🎥Search and Download Video:\n`dla vd` <query>\n' +
'> ⬇️Download All Media: \n`dla` <url> _YT-DLP FLAGS_ \n' +
'> 🎵Download All Audio from Playlist: \n`dla mp3` <url> \n' +
'> 📂Download Direct Generic File\n`dla wget` <url> _WGET FLAGS_ \n' +
'> 🆙Fail Download? Update YT-DLP: \n`dla update` \n' +
'> 🌐More Info:\ngithub.com/yt-dlp/yt-dlp/blob/master/README.md#usage-and-options',
{ quoted: message.data }
);
return;
}
try {
const args = input.match(/[^\s"]+|"([^"]*)"/g)?.map(arg =>
arg.startsWith('"') && arg.endsWith('"') ? arg.slice(1, -1) : arg
) || [];
const command = args[0];
const remainingArgs = args.slice(1);
const urls = remainingArgs.filter(arg => isUrl(arg));
if (!urls.length && command !== 'update') {
if (input.includes('://')) {
const inputUrl = input.match(/(https?:\/\/[^\s]+)/)?.[1];
if (inputUrl) {
const options = input.replace(inputUrl, '').trim();
await mediaDownloader.downloadWithYtDlp(message, [inputUrl], `-f "bestvideo[height<=720][ext=mp4][vcodec=h264]+bestaudio[acodec=aac]/best[height<=720][vcodec=h264]/best[ext=mp4]/best" --merge-output-format mp4 ${options}`);
return;
}
}
if (command === 'vd') {
await mediaDownloader.searchAndDownload(message, remainingArgs.join(' '), true);
} else {
await mediaDownloader.searchAndDownload(message, input, false);
}
return;
}
switch (command) {
case 'update':
await mediaDownloader.updateYtDlp(message);
break;
case 'wget':
if (urls.length) {
const options = remainingArgs
.filter(arg => !isUrl(arg))
.join(' ');
await Promise.all(urls.map(url =>
mediaDownloader.downloadWithWget(message, url, options)
));
}
break;
case 'mp3':
if (urls.length) {
const options = remainingArgs
.filter(arg => !isUrl(arg))
.join(' ');
await mediaDownloader.downloadWithYtDlp(
message,
urls,
`-x --audio-format mp3 ${options}`,
true
);
}
break;
default:
const options = remainingArgs
.filter(arg => !isUrl(arg))
.join(' ');
await mediaDownloader.downloadWithYtDlp(
message,
urls,
`-f "bestvideo[height<=720][ext=mp4][vcodec=h264]+bestaudio[acodec=aac]/best[height<=720][vcodec=h264]/best[ext=mp4]/best" --merge-output-format mp4 ${options}`
);
break;
}
} catch (error) {
console.error(`Error in dla command: ${error.message}`);
}
}
);
module.exports = { mediaDownloader };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment