const { Command } = require('discord-akairo'); const fs = require('fs'); const youtubedl = require('youtube-dl'); const hbjs = require('handbrake-js'); const os = require('os'); const filetype = require('file-type'); class DownloadCommand extends Command { constructor() { super('download', { aliases: ['download', 'dl'], category: 'utility', clientPermissions: ['SEND_MESSAGES', 'EMBED_LINKS', 'ATTACH_FILES'], args: [ { id: 'link', type: 'string', prompt: { start: 'Send the link of which video you want to download', } }, { id: 'caption', type: 'string', match: 'rest' }, { id: 'spoiler', match: 'flag', flag: ['--spoil', '--spoiler', '-s'] } ], description: { content: 'Download videos from different website from the link you provided, use "-s" to make the vid a spoiler', usage: '[link] [caption]', examples: ['https://www.youtube.com/watch?v=6n3pFFPSlW4 Look at this funny gnome'] } }); } async exec(message, args) { if (args.caption == null) args.caption = ''; let link = args.link; let fileName; if (args.spoiler) { fileName = `SPOILER_${message.id}_video`; } else { fileName = `${message.id}_video`; } const Embed = this.client.util.embed() .setColor(message.member ? message.member.displayHexColor : 'NAVY') .setAuthor(`Downloaded by ${message.author.username}`, message.author.displayAvatarURL(), link) .setDescription(args.caption) .setFooter(`You can get the original video by clicking on the "downloaded by ${message.author.username}" message!`); let compressEmbed = this.client.util.embed() .setColor(message.member ? message.member.displayHexColor : 'NAVY') .setTitle('This one will need compression!') .setDescription('Starting compression now!') .setFooter('Want it to go faster? Donate to the dev with the donate command, so i can get a better server and do it faster!'); if (link.includes('http') || link.includes('www')) { let loadingmsg = await message.channel.send('Downloading '); if (fs.existsSync(`${os.tmpdir()}/${fileName}`)) { fs.unlink(`${os.tmpdir()}/${fileName}`, (err) => { if (err) console.error(err); }); } return youtubedl.exec(link, ['--rm-cache-dir', '-o', `${os.tmpdir()}/${fileName}`], {}, async function(err) { if (err) { console.error(err.toString()); loadingmsg.delete(); if (err.toString().includes('HTTP Error 429') || err.toString().includes('HTTP Error 403')) { return message.channel.send('An error has occured, I can\'t download from the link you provided because the website has blocked the bot. Please try again later.'); } else { return message.channel.send('An error has occured, I can\'t download from the link you provided.'); } } let ext = 'mp4'; if (fs.existsSync(`${os.tmpdir()}/${fileName}`)) { ext = await filetype.fromFile(`${os.tmpdir()}/${fileName}`); ext = ext.ext; // This look stupid but hey, it work if (ext === '3gp') ext = 'mp4'; // Change 3gp file extension to mp4 so discord show the video ( and to stop people from complaining ) fs.renameSync(`${os.tmpdir()}/${fileName}`, `${os.tmpdir()}/${fileName}.${ext}`); } else if (fs.existsSync(`${os.tmpdir()}/${fileName}.mkv`)) { // If it can't find the video assume it got merged and end with mkv fs.renameSync(`${os.tmpdir()}/${fileName}.mkv`, `${os.tmpdir()}/${fileName}.mp4`); // Discord play mkv just fine but it need to end with mp4 } else if (fs.existsSync(`${os.tmpdir()}/${fileName}.webm`)) { // Same as mkv ext = 'webm'; } let file = fs.statSync(`${os.tmpdir()}/${fileName}.${ext}`); let fileSize = file.size / 1000000.0; //Compress vid if bigger than 8MB if (fileSize > 8) { let compressmsg = await message.channel.send(compressEmbed); loadingmsg.delete(); const options = { input: `${os.tmpdir()}/${fileName}.${ext}`, output: `${os.tmpdir()}/${fileName}compressed.${ext}`, preset: 'Web/Discord Tiny 5 Minutes 240p30' }; let handbrake = hbjs.spawn(options); handbrake.on('error', err => { console.error(err); compressmsg.delete(); return message.channel.send('An error has occured while compressing the video'); }); let percentComplete; let eta; handbrake.on('progress', progress => { percentComplete = progress.percentComplete; eta = progress.eta; console.log(`Percent complete: ${progress.percentComplete}, ETA: ${progress.eta}`); }); // Every 5 seconds update the compress message with the % let editmsg = setInterval(() => { compressEmbed.setDescription(`Ready in ${eta === '' ? 'soon enough' : eta}. ${percentComplete}% complete.`); compressmsg.edit(compressEmbed); }, 5000); handbrake.on('end', async function () { clearInterval(editmsg); file = fs.statSync(`${os.tmpdir()}/${fileName}compressed.${ext}`); fileSize = file.size / 1000000.0; compressmsg.delete(); message.delete(); if (fileSize > 8) { return message.channel.send('File too big!'); } return message.channel.send({embed: Embed, files: [`${os.tmpdir()}/${fileName}compressed.${ext}`]}) .catch(err => { console.error(err); return message.channel.send('File too big'); }) .then(() => { // Delete file after it have been sent fs.unlinkSync(`${os.tmpdir()}/${fileName}.${ext}`); }); }); } else { loadingmsg.delete(); message.delete(); message.channel.send({embed: Embed, files: [`${os.tmpdir()}/${fileName}.${ext}`]}) .catch(err => { console.error(err); message.channel.send('File too big'); }) .then(() => { // Delete file after it have been sent fs.unlinkSync(`${os.tmpdir()}/${fileName}.${ext}`); }); } }); } return message.channel.send('You need to input a valid link'); } } module.exports = DownloadCommand;