import { SlashCommandBuilder } from 'discord.js'; import utils from '../../utils/videos.js'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { exec } from 'node:child_process'; const { NODE_ENV } = process.env; export default { data: new SlashCommandBuilder() .setName('vid2gif') .setDescription('Convert your video into a gif.') .addStringOption(option => option.setName('url') .setDescription('URL of the video you want to convert') .setRequired(true)), category: 'utility', async execute(interaction, args) { await interaction.deferReply({ ephemeral: false }); const url = args.url; if (!await utils.stringIsAValidurl(url)) { console.error(`Not a url!!! ${url}`); return interaction.editReply({ content: '❌ This does not look like a valid url!', ephemeral: true }); } utils.downloadVideo(url, interaction.id) .then(async () => { const file = fs.readdirSync(os.tmpdir()).filter(fn => fn.startsWith(interaction.id)); const output = `${os.tmpdir()}/${file}`; const gifskiOutput = output.replace(path.extname(output), '.gif'); const gifsicleOutput = output.replace(path.extname(output), 'gifsicle.gif'); // Extract every frame for gifski await utils.ffmpeg(`-i ${output} ${os.tmpdir()}/frame${interaction.id}%04d.png`); // Make it look better await gifski(gifskiOutput, `${os.tmpdir()}/frame${interaction.id}*`); // Optimize it await gifsicle(gifskiOutput, gifsicleOutput); const fileStat = fs.statSync(gifsicleOutput); const fileSize = fileStat.size / 1000000.0; if (fileSize > 100) { await interaction.deleteReply(); await interaction.followUp('❌ Uh oh! The video once converted is too big!', { ephemeral: true }); } else if (fileSize > await utils.getMaxFileSize(interaction.guild)) { const fileURL = await utils.upload(gifsicleOutput) .catch(err => { console.error(err); }); await interaction.editReply({ content: `ℹī¸ File was bigger than 8 mb. It has been uploaded to an external site.\n${fileURL}`, ephemeral: false }); } else { await interaction.editReply({ files: [gifsicleOutput], ephemeral: false }); } }); }, }; async function gifski(output, input) { return await new Promise((resolve, reject) => { exec(`gifski --quality 70 -o ${output} ${input}`, (err, stdout, stderr) => { if (err) { reject(stderr); } if (stderr) { console.error(stderr); } console.log(NODE_ENV === 'development' ? stdout : null); resolve(); }); }); } async function gifsicle(input, output) { return await new Promise((resolve, reject) => { exec(`gifsicle --colors 256 -i ${input} -o ${output}`, (err, stdout, stderr) => { if (err) { reject(stderr); } if (stderr) { console.error(stderr); } console.log(NODE_ENV === 'development' ? stdout : null); resolve(); }); }); }