diff --git a/commands/fun/audio2image.js b/commands/fun/audio2image.js index 69899b0a..6eebc616 100644 --- a/commands/fun/audio2image.js +++ b/commands/fun/audio2image.js @@ -36,8 +36,8 @@ export default { if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.'); await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${args.audio.name}`)); - await utils.ffmpeg(`-i ${os.tmpdir()}/${args.audio.name} -sample_rate 44100 -ac 1 -f s16le -acodec pcm_s16le ${os.tmpdir()}/${args.audio.name}.sw`); - await utils.ffmpeg(`-pixel_format rgb24 -video_size 128x128 -f rawvideo -i ${os.tmpdir()}/${args.audio.name}.sw -frames:v 1 ${os.tmpdir()}/${args.audio.name}.png`); + await utils.ffmpeg(['-i', `${os.tmpdir()}/${args.audio.name}`, '-sample_rate', '44100', '-ac', '1', '-f', 's16le', '-acodec', 'pcm_s16le', `${os.tmpdir()}/${args.audio.name}.sw`]); + await utils.ffmpeg(['-pixel_format', 'rgb24', '-video_size', '128x128', '-f', 'rawvideo', '-i', `${os.tmpdir()}/${args.audio.name}.sw`, '-frames:v', '1', `${os.tmpdir()}/${args.audio.name}.png`]); const file = fs.statSync(`${os.tmpdir()}/${args.audio.name}.png`); const fileSize = (file.size / 1000000.0).toFixed(2); diff --git a/commands/fun/image2audio.js b/commands/fun/image2audio.js index 9410bcb1..c89ef8a7 100644 --- a/commands/fun/image2audio.js +++ b/commands/fun/image2audio.js @@ -35,8 +35,8 @@ export default { if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.'); await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${args.img.name}`)); - await utils.ffmpeg(`-i ${os.tmpdir()}/${args.img.name} -f rawvideo ${os.tmpdir()}/1${args.img.name}`); - await utils.ffmpeg(`-sample_rate 44100 -ac 1 -f s16le -i ${os.tmpdir()}/1${args.img.name} ${os.tmpdir()}/${args.img.name}.mp3`); + await utils.ffmpeg(['-i', `${os.tmpdir()}/${args.img.name}`, '-f', 'rawvideo', `${os.tmpdir()}/1${args.img.name}`]); + await utils.ffmpeg(['-sample_rate', '44100', '-ac', '1', '-f', 's16le', '-i', `${os.tmpdir()}/1${args.img.name}`, `${os.tmpdir()}/${args.img.name}.mp3`]); const file = fs.statSync(`${os.tmpdir()}/${args.img.name}.mp3`); const fileSize = (file.size / 1000000.0).toFixed(2); diff --git a/commands/utility/about.js b/commands/utility/about.js index 813b5c24..e43ee6ca 100644 --- a/commands/utility/about.js +++ b/commands/utility/about.js @@ -1,6 +1,6 @@ import { SlashCommandBuilder } from 'discord.js'; import { EmbedBuilder } from 'discord.js'; -import { exec } from 'node:child_process'; +import { execFile } from 'node:child_process'; import db from '../../models/index.js'; const donator = db.donator; @@ -40,7 +40,7 @@ export default { // description += '\nThanks to Jetbrains for providing their IDE!'; - exec('git rev-parse --short HEAD', (err, stdout) => { + execFile('git', ['rev-parse', '--short', 'HEAD'], (err, stdout) => { const aboutEmbed = new EmbedBuilder() .setColor(interaction.member ? interaction.member.displayHexColor : 'Navy') .setAuthor({ name: client.user.username, iconURL: client.user.displayAvatarURL(), url: 'https://libtar.de' }) diff --git a/commands/utility/download.js b/commands/utility/download.js index 22644772..3ccda3a4 100644 --- a/commands/utility/download.js +++ b/commands/utility/download.js @@ -1,5 +1,5 @@ import { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, StringSelectMenuBuilder } from 'discord.js'; -import { exec } from 'node:child_process'; +import { execFile } from 'node:child_process'; import fs from 'node:fs'; import os from 'node:os'; import utils from '../../utils/videos.js'; @@ -50,7 +50,7 @@ export default { if (format) { let qualitys = await new Promise((resolve, reject) => { - exec(`./bin/yt-dlp "${url}" --print "%()j"`, (err, stdout, stderr) => { + execFile('./bin/yt-dlp', [url, '--print', '%()j'], (err, stdout, stderr) => { if (err) { reject(stderr); } @@ -137,7 +137,7 @@ async function download(url, interaction, originalInteraction, format = undefine const compressInteraction = originalInteraction ? originalInteraction : interaction; if (compressInteraction.doCompress) { - const presets = [ 'Social 8 MB 3 Minutes 360p30', 'Social 50 MB 10 Minutes 480p30', 'Social 50 MB 5 Minutes 720p30', 'Social 100 MB 5 Minutes 1080p30' ]; + const presets = [ 'Social 25 MB 5 Minutes 360p60', 'Social 50 MB 10 Minutes 480p30', 'Social 50 MB 5 Minutes 720p30', 'Social 100 MB 5 Minutes 1080p30' ]; const options = []; presets.forEach(p => { @@ -176,7 +176,7 @@ async function download(url, interaction, originalInteraction, format = undefine if (bannedFormats.includes(codec)) { const oldOutput = output; output = `${os.tmpdir()}/264${file}`; - await utils.ffmpeg(`-i ${oldOutput} -vcodec libx264 -acodec aac ${output}`); + await utils.ffmpeg(['-i', oldOutput, '-vcodec', 'libx264', '-acodec', 'aac', output]); } const fileStat = fs.statSync(output); diff --git a/commands/utility/vid2gif.js b/commands/utility/vid2gif.js index 9ee49b57..13c9aedf 100644 --- a/commands/utility/vid2gif.js +++ b/commands/utility/vid2gif.js @@ -3,7 +3,7 @@ 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'; +import { execFile } from 'node:child_process'; const { NODE_ENV } = process.env; @@ -50,7 +50,7 @@ export default { 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`); + await utils.ffmpeg(['-i', output, `${os.tmpdir()}/frame${interaction.id}%04d.png`]); // Make it look better await gifski(gifskiOutput, `${os.tmpdir()}/frame${interaction.id}*`, quality); // Optimize it @@ -79,7 +79,8 @@ export default { async function gifski(output, input, quality) { return await new Promise((resolve, reject) => { - exec(`gifski --quality ${quality ? quality : 70} -o ${output} ${input}`, (err, stdout, stderr) => { + // Shell: true should be fine as no user input is being passed + execFile('gifski', ['--quality', quality ? quality : 70, '-o', output, input], { shell: true }, (err, stdout, stderr) => { if (err) { reject(stderr); } @@ -94,7 +95,8 @@ async function gifski(output, input, quality) { async function gifsicle(input, output, loop = false) { return await new Promise((resolve, reject) => { - exec(`gifsicle --colors 256 ${loop ? '--no-loopcount' : ''} -i ${input} -o ${output}`, (err, stdout, stderr) => { + // Shell: true should be fine as no user input is being passed + execFile('gifsicle', ['--colors', '256', loop ? '--no-loopcount' : '', '-i', input, '-o', output], { shell: true }, (err, stdout, stderr) => { if (err) { reject(stderr); } diff --git a/events/client/ready.js b/events/client/ready.js index cbd1f8e8..93963296 100644 --- a/events/client/ready.js +++ b/events/client/ready.js @@ -1,4 +1,4 @@ -import { exec } from 'node:child_process'; +import { execFile } from 'node:child_process'; const { statusChannel, NODE_ENV } = process.env; import { version } from 'discord.js'; @@ -10,7 +10,7 @@ export default { global.boards = {}; const ytdlpVersion = await new Promise((resolve, reject) => { - exec('./bin/yt-dlp --version', (err, stdout, stderr) => { + execFile('./bin/yt-dlp', ['--version'], (err, stdout, stderr) => { if (err) { reject(stderr); } diff --git a/utils/videos.js b/utils/videos.js index 1b26608b..d68ae4d8 100644 --- a/utils/videos.js +++ b/utils/videos.js @@ -1,5 +1,5 @@ import os from 'node:os'; -import { exec } from 'node:child_process'; +import { execFile } from 'node:child_process'; const { NODE_ENV } = process.env; const ytdlpMaxResolution = 2160; @@ -15,7 +15,7 @@ export default { }; async function downloadVideo(urlArg, output, format = `bestvideo[height<=?${ytdlpMaxResolution}]+bestaudio/best`) { await new Promise((resolve, reject) => { - exec(`./bin/yt-dlp -f "${format}" "${urlArg}" -o "${os.tmpdir()}/${output}.%(ext)s" --force-overwrites --no-playlist --remux-video=mp4/webm/mov --no-warnings`, (err, stdout, stderr) => { + execFile('./bin/yt-dlp', ['-f', format, urlArg, '-o', `${os.tmpdir()}/${output}.%(ext)s`, '--force-overwrites', '--no-playlist', '--remux-video=mp4/webm/mov', '--no-warnings'], (err, stdout, stderr) => { if (err) { return reject(stderr); } @@ -32,7 +32,7 @@ async function downloadVideo(urlArg, output, format = `bestvideo[height<=?${ytdl async function upload(file) { return await new Promise((resolve, reject) => { - exec(`./bin/upload.sh ${file}`, (err, stdout, stderr) => { + execFile('./bin/upload.sh', [file], (err, stdout, stderr) => { if (err) { reject(stderr); } @@ -46,7 +46,7 @@ async function upload(file) { async function ffmpeg(command) { return await new Promise((resolve, reject) => { - exec(`ffmpeg -hide_banner ${command}`, (err, stdout, stderr) => { + execFile('ffmpeg', ['-hide_banner', ...command], (err, stdout, stderr) => { if (err) { reject(stderr); } @@ -71,7 +71,7 @@ async function stringIsAValidurl(s) { async function compressVideo(input, output, preset) { await new Promise((resolve, reject) => { - exec(`./bin/HandBrakeCLI -i "${input}" -Z "${preset}" -o "${os.tmpdir()}/${output}"`, (err, stdout, stderr) => { + execFile('./bin/HandBrakeCLI', ['-i', input, '-Z', preset, '-o', `${os.tmpdir()}/${output}`], (err, stdout, stderr) => { if (err) { reject(stderr); } @@ -85,7 +85,7 @@ async function compressVideo(input, output, preset) { } async function getVideoCodec(input) { return await new Promise((resolve, reject) => { - exec(`ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "${input}"`, (err, stdout, stderr) => { + execFile('ffprobe', ['-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=codec_name', '-of', 'default=noprint_wrappers=1:nokey=1', input], (err, stdout, stderr) => { if (err) { reject(stderr); } @@ -99,7 +99,7 @@ async function getVideoCodec(input) { async function getVideoSize(urlArg, format = `bestvideo[height<=?${ytdlpMaxResolution}]+bestaudio/best`) { return await new Promise((resolve, reject) => { - exec(`./bin/yt-dlp "${urlArg}" -f "${format}" --no-warnings -O "%(filesize,filesize_approx)s"`, (err, stdout, stderr) => { + execFile('./bin/yt-dlp', [urlArg, '-f', format, '--no-warnings', '-O', '%(filesize,filesize_approx)s'], (err, stdout, stderr) => { if (err) { reject(stderr); }