2022-08-28 17:03:15 +02:00
|
|
|
|
import { SlashCommandBuilder } from 'discord.js';
|
2022-06-17 07:31:58 +02:00
|
|
|
|
import utils from '../../utils/videos.js';
|
2022-06-17 01:25:35 +02:00
|
|
|
|
import fs from 'node:fs';
|
|
|
|
|
import os from 'node:os';
|
|
|
|
|
import path from 'node:path';
|
|
|
|
|
import { exec } from 'node:child_process';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)),
|
2022-08-28 17:03:15 +02:00
|
|
|
|
category: 'utility',
|
|
|
|
|
async execute(interaction, args) {
|
2022-06-17 01:25:35 +02:00
|
|
|
|
await interaction.deferReply({ ephemeral: false });
|
2022-09-01 01:43:59 +02:00
|
|
|
|
const url = args.url;
|
2022-06-17 01:25:35 +02:00
|
|
|
|
|
2022-06-20 08:34:18 +02:00
|
|
|
|
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 });
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-17 01:25:35 +02:00
|
|
|
|
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');
|
|
|
|
|
|
2022-06-17 02:14:14 +02:00
|
|
|
|
// 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);
|
2022-06-17 01:25:35 +02:00
|
|
|
|
|
|
|
|
|
const fileStat = fs.statSync(gifsicleOutput);
|
|
|
|
|
const fileSize = fileStat.size / 1000000.0;
|
|
|
|
|
|
|
|
|
|
if (fileSize > 100) {
|
|
|
|
|
await interaction.deleteReply();
|
2022-07-01 21:24:39 +02:00
|
|
|
|
await interaction.followUp('❌ Uh oh! The video once converted is too big!', { ephemeral: true });
|
2022-06-17 01:25:35 +02:00
|
|
|
|
}
|
|
|
|
|
else if (fileSize > 8) {
|
|
|
|
|
const fileURL = await utils.upload(gifsicleOutput)
|
|
|
|
|
.catch(err => {
|
|
|
|
|
console.error(err);
|
|
|
|
|
});
|
2022-07-01 21:24:39 +02:00
|
|
|
|
await interaction.editReply({ content: `ℹ️ File was bigger than 8 mb. It has been uploaded to an external site.\n${fileURL}`, ephemeral: false });
|
2022-06-17 01:25:35 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
await interaction.editReply({ files: [gifsicleOutput], ephemeral: false });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
async function gifski(output, input) {
|
|
|
|
|
return await new Promise((resolve, reject) => {
|
2022-06-20 08:34:18 +02:00
|
|
|
|
exec(`gifski --quality 70 -o ${output} ${input}`, (err, stdout, stderr) => {
|
2022-06-17 01:25:35 +02:00
|
|
|
|
if (err) {
|
|
|
|
|
reject(stderr);
|
|
|
|
|
}
|
|
|
|
|
if (stderr) {
|
|
|
|
|
console.error(stderr);
|
|
|
|
|
}
|
2022-09-12 11:33:25 +02:00
|
|
|
|
resolve();
|
2022-06-17 01:25:35 +02:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function gifsicle(input, output) {
|
|
|
|
|
return await new Promise((resolve, reject) => {
|
2022-06-20 08:34:18 +02:00
|
|
|
|
exec(`gifsicle --colors 256 -i ${input} -o ${output}`, (err, stdout, stderr) => {
|
2022-06-17 01:25:35 +02:00
|
|
|
|
if (err) {
|
|
|
|
|
reject(stderr);
|
|
|
|
|
}
|
|
|
|
|
if (stderr) {
|
|
|
|
|
console.error(stderr);
|
|
|
|
|
}
|
2022-09-12 11:33:25 +02:00
|
|
|
|
resolve();
|
2022-06-17 01:25:35 +02:00
|
|
|
|
});
|
|
|
|
|
});
|
2022-06-20 08:34:18 +02:00
|
|
|
|
}
|