Compare commits
4 commits
2afbca10ec
...
4cf0d0bac1
Author | SHA1 | Date | |
---|---|---|---|
4cf0d0bac1 | |||
77a5ac6137 | |||
a92b16fba4 | |||
c3fd22f02f |
5 changed files with 77 additions and 27 deletions
|
@ -25,11 +25,15 @@ export default {
|
||||||
.setRequired(false))
|
.setRequired(false))
|
||||||
.addBooleanOption(option =>
|
.addBooleanOption(option =>
|
||||||
option.setName('compress')
|
option.setName('compress')
|
||||||
.setDescription('Compress the video?')
|
.setDescription('Compress the video.')
|
||||||
|
.setRequired(false))
|
||||||
|
.addBooleanOption(option =>
|
||||||
|
option.setName('autocrop')
|
||||||
|
.setDescription('Autocrop borders on videos. Ignored when using compress option.')
|
||||||
.setRequired(false))
|
.setRequired(false))
|
||||||
.addBooleanOption(option =>
|
.addBooleanOption(option =>
|
||||||
option.setName('description')
|
option.setName('description')
|
||||||
.setDescription('Include the video description?')
|
.setDescription('Include the video description.')
|
||||||
.setRequired(false)),
|
.setRequired(false)),
|
||||||
category: 'utility',
|
category: 'utility',
|
||||||
alias: ['dl'],
|
alias: ['dl'],
|
||||||
|
@ -41,6 +45,7 @@ export default {
|
||||||
const format = args.format;
|
const format = args.format;
|
||||||
maxFileSize = await utils.getMaxFileSize(interaction.guild);
|
maxFileSize = await utils.getMaxFileSize(interaction.guild);
|
||||||
interaction.doCompress = args.compress;
|
interaction.doCompress = args.compress;
|
||||||
|
interaction.doAutocrop = args.autocrop;
|
||||||
|
|
||||||
await interaction.deferReply({ ephemeral: false });
|
await interaction.deferReply({ ephemeral: false });
|
||||||
|
|
||||||
|
@ -187,14 +192,21 @@ async function download(url, interaction, originalInteraction, format = undefine
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the video format is not one compatible with Discord, reencode it.
|
// If the video format is not one compatible with Discord, reencode it unless autocrop is choosen in which case it gets reencoded anyway.
|
||||||
const bannedFormats = ['hevc'];
|
if (!interaction.doAutocrop) {
|
||||||
const codec = await utils.getVideoCodec(output);
|
const bannedFormats = ['hevc'];
|
||||||
|
const codec = await utils.getVideoCodec(output);
|
||||||
if (bannedFormats.includes(codec)) {
|
|
||||||
|
if (bannedFormats.includes(codec)) {
|
||||||
|
const oldOutput = output;
|
||||||
|
output = `${os.tmpdir()}/264${file}`;
|
||||||
|
await utils.ffmpeg(['-i', oldOutput, '-vcodec', 'libx264', '-acodec', 'aac', output]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (interaction.doAutocrop && !compressInteraction.doCompress) {
|
||||||
const oldOutput = output;
|
const oldOutput = output;
|
||||||
output = `${os.tmpdir()}/264${file}`;
|
output = `${os.tmpdir()}/autocrop${file}`;
|
||||||
await utils.ffmpeg(['-i', oldOutput, '-vcodec', 'libx264', '-acodec', 'aac', output]);
|
await utils.autoCrop(oldOutput, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileStat = fs.statSync(output);
|
const fileStat = fs.statSync(output);
|
||||||
|
|
|
@ -9,6 +9,19 @@ export default {
|
||||||
// Init global variables.
|
// Init global variables.
|
||||||
global.boards = {};
|
global.boards = {};
|
||||||
|
|
||||||
|
const commandSize = client.commands.size;
|
||||||
|
const clientTag = client.user.username;
|
||||||
|
const guildSize = client.guilds.cache.size;
|
||||||
|
const channelSize = client.channels.cache.size;
|
||||||
|
const clientID = client.user.id;
|
||||||
|
|
||||||
|
console.log('===========[ READY ]===========');
|
||||||
|
console.log(`\x1b[32mLogged in as \x1b[34m${clientTag}\x1b[0m! (\x1b[33m${clientID}\x1b[0m)`);
|
||||||
|
console.log(`Ready to serve in \x1b[33m${channelSize}\x1b[0m channels on \x1b[33m${guildSize}\x1b[0m servers.`);
|
||||||
|
console.log(`${client.readyAt}`);
|
||||||
|
console.log(`There is \x1b[33m${commandSize}\x1b[0m command loaded.`);
|
||||||
|
console.log(`Running Discord.js \x1b[33m${version}\x1b[0m`);
|
||||||
|
|
||||||
const ytdlpVersion = await new Promise((resolve, reject) => {
|
const ytdlpVersion = await new Promise((resolve, reject) => {
|
||||||
execFile('./bin/yt-dlp', ['--version'], (err, stdout, stderr) => {
|
execFile('./bin/yt-dlp', ['--version'], (err, stdout, stderr) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -21,19 +34,7 @@ export default {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const commandSize = client.commands.size;
|
|
||||||
const clientTag = client.user.username;
|
|
||||||
const guildSize = client.guilds.cache.size;
|
|
||||||
const channelSize = client.channels.cache.size;
|
|
||||||
const clientID = client.user.id;
|
|
||||||
|
|
||||||
console.log('===========[ READY ]===========');
|
|
||||||
console.log(`\x1b[32mLogged in as \x1b[34m${clientTag}\x1b[0m! (\x1b[33m${clientID}\x1b[0m)`);
|
|
||||||
console.log(`Ready to serve in \x1b[33m${channelSize}\x1b[0m channels on \x1b[33m${guildSize}\x1b[0m servers.`);
|
|
||||||
console.log(`${client.readyAt}`);
|
|
||||||
console.log(`There is \x1b[33m${commandSize}\x1b[0m command loaded.`);
|
|
||||||
console.log(`Running yt-dlp \x1b[33m${ytdlpVersion.replace('\n', '')}\x1b[0m`);
|
console.log(`Running yt-dlp \x1b[33m${ytdlpVersion.replace('\n', '')}\x1b[0m`);
|
||||||
console.log(`Running Discord.js \x1b[33m${version}\x1b[0m`);
|
|
||||||
console.log('===========[ READY ]===========');
|
console.log('===========[ READY ]===========');
|
||||||
|
|
||||||
// If stats channel settings exist, send bot stats to it
|
// If stats channel settings exist, send bot stats to it
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node .",
|
"start": "node .",
|
||||||
"deploy": "node deploy-commands.cjs",
|
"deploy": "node scripts/deploy-commands.js",
|
||||||
"deployGlobally": "node deploy-commands.cjs global",
|
"deployGlobally": "node scripts/deploy-commands.js global",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lintfix": "eslint . --fix",
|
"lintfix": "eslint . --fix",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { REST } from '@discordjs/rest';
|
||||||
import { Routes } from 'discord-api-types/v9';
|
import { Routes } from 'discord-api-types/v9';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
const { clientId, guildId, token } = process.env;
|
const { clientId, guildId, token } = process.env;
|
||||||
|
@ -17,7 +17,7 @@ for (let i = 0; i < categoryPath.length; i++) {
|
||||||
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
|
||||||
for (const file of commandFiles) {
|
for (const file of commandFiles) {
|
||||||
const filePath = path.join(commandsPath, file);
|
const filePath = path.join(commandsPath, file);
|
||||||
const command = await import(filePath);
|
const command = await import(pathToFileURL(filePath));
|
||||||
|
|
||||||
if (command.default.integration_types) {
|
if (command.default.integration_types) {
|
||||||
Object.assign(command.default.data, { integration_types: command.default.integration_types });
|
Object.assign(command.default.data, { integration_types: command.default.integration_types });
|
||||||
|
|
|
@ -11,6 +11,7 @@ export default {
|
||||||
getVideoCodec,
|
getVideoCodec,
|
||||||
getVideoSize,
|
getVideoSize,
|
||||||
getMaxFileSize,
|
getMaxFileSize,
|
||||||
|
autoCrop,
|
||||||
};
|
};
|
||||||
async function downloadVideo(urlArg, output, format = `bestvideo[height<=?${ytdlpMaxResolution}]+bestaudio/best`) {
|
async function downloadVideo(urlArg, output, format = `bestvideo[height<=?${ytdlpMaxResolution}]+bestaudio/best`) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
|
@ -70,7 +71,7 @@ async function stringIsAValidurl(s) {
|
||||||
|
|
||||||
async function compressVideo(input, output, preset) {
|
async function compressVideo(input, output, preset) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
execFile('./bin/HandBrakeCLI', ['-i', input, '-Z', preset, '-o', `${os.tmpdir()}/${output}`], (err, stdout, stderr) => {
|
execFile('./bin/HandBrakeCLI', ['-i', input, '-Z', preset, '--turbo', '--optimize', '-o', `${os.tmpdir()}/${output}`], (err, stdout, stderr) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(stderr);
|
reject(stderr);
|
||||||
}
|
}
|
||||||
|
@ -133,4 +134,40 @@ async function getMaxFileSize(guild) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue