2022-06-17 01:25:43 +02:00
|
|
|
import os from 'node:os';
|
2024-02-02 03:28:46 +01:00
|
|
|
import { execFile } from 'node:child_process';
|
2024-02-04 03:31:09 +01:00
|
|
|
const { NODE_ENV, ytdlpMaxResolution } = process.env;
|
2022-06-17 01:25:43 +02:00
|
|
|
|
|
|
|
export default {
|
|
|
|
downloadVideo,
|
|
|
|
upload,
|
2022-06-17 02:14:14 +02:00
|
|
|
ffmpeg,
|
2022-06-20 08:34:18 +02:00
|
|
|
stringIsAValidurl,
|
2022-08-22 20:23:27 +02:00
|
|
|
compressVideo,
|
2023-03-20 03:55:53 +01:00
|
|
|
getVideoCodec,
|
2023-04-11 20:16:18 +02:00
|
|
|
getVideoSize,
|
2023-04-11 14:34:19 +02:00
|
|
|
getMaxFileSize,
|
2024-07-07 01:05:48 +02:00
|
|
|
autoCrop,
|
2022-06-17 01:25:43 +02:00
|
|
|
};
|
2024-01-30 00:28:27 +01:00
|
|
|
async function downloadVideo(urlArg, output, format = `bestvideo[height<=?${ytdlpMaxResolution}]+bestaudio/best`) {
|
2022-06-17 01:25:43 +02:00
|
|
|
await new Promise((resolve, reject) => {
|
2024-02-02 03:28:46 +01:00
|
|
|
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) => {
|
2022-06-17 01:25:43 +02:00
|
|
|
if (err) {
|
2024-01-30 00:28:27 +01:00
|
|
|
return reject(stderr);
|
2022-06-17 01:25:43 +02:00
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
2024-01-30 00:28:27 +01:00
|
|
|
// Should already be rejected at that points
|
|
|
|
return reject(stderr);
|
2022-06-17 01:25:43 +02:00
|
|
|
}
|
2022-09-14 11:32:01 +02:00
|
|
|
console.log(NODE_ENV === 'development' ? stdout : null);
|
2024-01-30 00:28:27 +01:00
|
|
|
return resolve();
|
2022-06-17 01:25:43 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function upload(file) {
|
|
|
|
return await new Promise((resolve, reject) => {
|
2024-02-02 03:28:46 +01:00
|
|
|
execFile('./bin/upload.sh', [file], (err, stdout, stderr) => {
|
2022-06-17 01:25:43 +02:00
|
|
|
if (err) {
|
|
|
|
reject(stderr);
|
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
|
|
|
}
|
|
|
|
resolve(stdout);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ffmpeg(command) {
|
|
|
|
return await new Promise((resolve, reject) => {
|
2024-02-02 03:28:46 +01:00
|
|
|
execFile('ffmpeg', ['-hide_banner', ...command], (err, stdout, stderr) => {
|
2022-06-17 01:25:43 +02:00
|
|
|
if (err) {
|
|
|
|
reject(stderr);
|
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
|
|
|
}
|
2022-09-14 11:32:01 +02:00
|
|
|
console.log(NODE_ENV === 'development' ? stdout : null);
|
2022-09-12 11:33:25 +02:00
|
|
|
resolve();
|
2022-06-17 01:25:43 +02:00
|
|
|
});
|
|
|
|
});
|
2022-06-20 08:34:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async function stringIsAValidurl(s) {
|
|
|
|
try {
|
|
|
|
new URL(s);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (err) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-07-06 18:52:44 +02:00
|
|
|
}
|
2022-08-22 20:23:27 +02:00
|
|
|
|
|
|
|
async function compressVideo(input, output, preset) {
|
|
|
|
await new Promise((resolve, reject) => {
|
2024-07-07 01:05:48 +02:00
|
|
|
execFile('./bin/HandBrakeCLI', ['-i', input, '-Z', preset, '--turbo', '--optimize', '-o', `${os.tmpdir()}/${output}`], (err, stdout, stderr) => {
|
2022-08-22 20:23:27 +02:00
|
|
|
if (err) {
|
|
|
|
reject(stderr);
|
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
|
|
|
}
|
2022-09-14 11:32:01 +02:00
|
|
|
console.log(NODE_ENV === 'development' ? stdout : null);
|
2022-09-12 11:33:25 +02:00
|
|
|
resolve();
|
2022-08-22 20:23:27 +02:00
|
|
|
});
|
|
|
|
});
|
2023-03-20 03:55:53 +01:00
|
|
|
}
|
|
|
|
async function getVideoCodec(input) {
|
|
|
|
return await new Promise((resolve, reject) => {
|
2024-02-02 03:28:46 +01:00
|
|
|
execFile('ffprobe', ['-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=codec_name', '-of', 'default=noprint_wrappers=1:nokey=1', input], (err, stdout, stderr) => {
|
2023-03-20 03:55:53 +01:00
|
|
|
if (err) {
|
|
|
|
reject(stderr);
|
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
|
|
|
}
|
|
|
|
resolve(stdout.trim());
|
|
|
|
});
|
|
|
|
});
|
2023-04-11 14:34:19 +02:00
|
|
|
}
|
|
|
|
|
2024-01-30 00:28:27 +01:00
|
|
|
async function getVideoSize(urlArg, format = `bestvideo[height<=?${ytdlpMaxResolution}]+bestaudio/best`) {
|
2023-04-11 14:34:19 +02:00
|
|
|
return await new Promise((resolve, reject) => {
|
2024-02-02 03:28:46 +01:00
|
|
|
execFile('./bin/yt-dlp', [urlArg, '-f', format, '--no-warnings', '-O', '%(filesize,filesize_approx)s'], (err, stdout, stderr) => {
|
2023-04-11 20:16:18 +02:00
|
|
|
if (err) {
|
|
|
|
reject(stderr);
|
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
|
|
|
}
|
|
|
|
resolve(stdout / 1000000.0);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getMaxFileSize(guild) {
|
|
|
|
return await new Promise((resolve) => {
|
2024-06-12 00:51:24 +02:00
|
|
|
if (!guild) {
|
|
|
|
resolve(25);
|
|
|
|
}
|
|
|
|
|
2023-04-11 14:34:19 +02:00
|
|
|
const tier = guild.premiumTier;
|
|
|
|
switch (tier) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
2023-04-19 16:58:42 +02:00
|
|
|
resolve(25);
|
2023-04-11 14:34:19 +02:00
|
|
|
break;
|
|
|
|
case 2:
|
2023-04-19 16:58:42 +02:00
|
|
|
resolve(50);
|
2023-04-11 14:34:19 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
2023-04-19 16:58:42 +02:00
|
|
|
resolve(100);
|
2023-04-11 14:34:19 +02:00
|
|
|
break;
|
|
|
|
default:
|
2023-04-19 16:58:42 +02:00
|
|
|
resolve(25);
|
2023-04-11 14:34:19 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2024-07-07 01:05:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async function autoCrop(input, output) {
|
|
|
|
return await new Promise((resolve, reject) => {
|
|
|
|
let ffprobeInput = input;
|
|
|
|
if (process.platform === 'win32') {
|
|
|
|
// ffprobe 'movie=' options does not like windows absolute path
|
|
|
|
ffprobeInput = input.replace(/\\/g, '/').replace(/\:/g, '\\\\:');
|
|
|
|
}
|
|
|
|
|
|
|
|
execFile('ffprobe',
|
|
|
|
['-f', 'lavfi', '-i', `movie=${ffprobeInput},cropdetect`, '-show_entries',
|
|
|
|
'packet_tags=lavfi.cropdetect.x1,lavfi.cropdetect.x2,lavfi.cropdetect.y1,lavfi.cropdetect.y2,lavfi.cropdetect.w,lavfi.cropdetect.h,lavfi.cropdetect.x,lavfi.cropdetect.y',
|
|
|
|
'-read_intervals', '%+#10', '-hide_banner', '-print_format', 'json'], async (err, stdout, stderr) => {
|
|
|
|
if (err) {
|
|
|
|
reject(stderr);
|
|
|
|
}
|
|
|
|
if (stderr) {
|
|
|
|
console.error(stderr);
|
|
|
|
}
|
|
|
|
const packets = JSON.parse(stdout).packets;
|
|
|
|
|
|
|
|
for (let i = 0; i < packets.length; i++) {
|
|
|
|
const element = packets[i];
|
|
|
|
|
|
|
|
if (element.tags) {
|
|
|
|
const cropdetect = element.tags;
|
|
|
|
await ffmpeg(['-i', input, '-vf', `crop=${cropdetect['lavfi.cropdetect.w']}:${cropdetect['lavfi.cropdetect.h']}:${cropdetect['lavfi.cropdetect.x']}:${cropdetect['lavfi.cropdetect.y']}`, '-vcodec', 'libx264', '-acodec', 'aac', output])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(NODE_ENV === 'development' ? stdout : null);
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|