jericho-player
Version:
LightWeight Framework for discord.js v14 Music Bots and Radio Bots with fast moderation with commands and no memory leak mode
316 lines (292 loc) • 9.75 kB
JavaScript
const { Client, IntentsBitField } = require('discord.js');
const { resolve, dirname } = require('path');
const { FFmpeg } = require('prism-media');
const prettyMs = require('pretty-mslux');
class miscUtils {
/**
* scanDeps() -> Scanning Dependencies in package.json or node_modules for package or versions list
* @param {String|void} packageName Package name for publishing it versions in project
* @returns {String|void} Publish Data which was requested for like checks and versions
*/
static scanDeps(packageName) {
if (!packageName) {
const report = [];
const addVersion = (name) => report.push(
`- ${name}: ${miscUtils.__findPkgVersion(name) ?? 'not found'}`,
);
// general
report.push('Core Dependencies');
addVersion('@discordjs/voice');
addVersion('prism-media');
report.push('');
// opus
report.push('Opus Libraries');
addVersion('@discordjs/opus');
addVersion('opusscript');
report.push('');
// encryption
report.push('Encryption Libraries');
addVersion('sodium');
addVersion('libsodium-wrappers');
addVersion('tweetnacl');
report.push('');
// ffmpeg
report.push('FFmpeg');
try {
const info = FFmpeg.getInfo();
report.push(`- version: ${info.version}`);
report.push(
`- libopus: ${
info.output.includes('--enable-libopus') ? 'yes' : 'no'
}`,
);
} catch (err) {
report.push('- not found');
}
addVersion('ffmpeg-static');
report.push('');
// Extractors
report.push('Extractors');
addVersion('playdl-music-extractor');
addVersion('video-extractor');
return ['-'.repeat(50), ...report, '-'.repeat(50)].join('\n');
}
return (
miscUtils.__findPkgVersion(packageName) ??
miscUtils.__findPkgVersion(packageName.toLowerCase().trim())
);
}
/**
* @private __findPkgVersion() -> Searching Versions of Packages
* @param {String} name NPM Package Name
* @returns {String|void} Returns Package Version
*/
static __findPkgVersion(name) {
try {
const pkg =
name === '@discordjs/voice'
? require('../../package.json')
: miscUtils.__searchPackageJson(
dirname(require.resolve(name)),
name,
8,
);
return pkg?.version ?? undefined;
} catch (err) {
return undefined;
}
}
/**
* @private __searchPackageJson() -> Searching Every package.json with deps
* @param {String} dir Directory name | value
* @param {String} packageName NPM Package Name
* @param {Number} depth Depth to go in Directories or outward
* @returns {Object} pacakge.json file with accurate versions
*/
static __searchPackageJson(dir, packageName, depth) {
if (depth === 0) return undefined;
const attemptedPath = resolve(dir, './package.json');
try {
const pkg = require(attemptedPath);
if (pkg.name !== packageName)
throw new Error('package.json does not match');
return pkg;
} catch (err) {
return miscUtils.__searchPackageJson(
resolve(dir, '..'),
packageName,
depth - 1,
);
}
}
static __initialBuildChecks(discordClient, playerInstance) {
let FmpeggGarbage;
let LibopusGarbage;
const MissingDeps = [' '];
MissingDeps.push(
'--[ Missing Dependencies from package.json | Do - "npm i packageName" ]--',
);
try {
const GarbageInfo = FFmpeg.getInfo();
FmpeggGarbage = !!`- version: ${GarbageInfo.version}`;
LibopusGarbage = !!`- libopus: ${
GarbageInfo.output.includes('--enable-libopus') ? 'yes' : 'no'
}`;
} catch (err) {
LibopusGarbage = FmpeggGarbage = undefined;
}
!miscUtils.scanDeps('@discordjs/voice')
? MissingDeps.push(`${MissingDeps.length - 1}) "@discordjs/voice"`)
: undefined;
!miscUtils.scanDeps('prism-media')
? MissingDeps.push(`${MissingDeps.length - 1}) "prism-media"`)
: undefined;
!miscUtils.scanDeps('@discordjs/opus') && !miscUtils.scanDeps('opusscript')
? MissingDeps.push(
`${MissingDeps.length - 1}) "@discordjs/opus" OR "opusscript"`,
)
: undefined;
!miscUtils.scanDeps('tweetnacl') &&
!(miscUtils.scanDeps('libsodium-wrapper') && miscUtils.scanDeps('sodium'))
? MissingDeps.push(
`${
MissingDeps.length - 1
}) "tweetnacl" OR ("libsodium-wrapper" And "sodium")`,
)
: undefined;
!miscUtils.scanDeps('ffmpeg-static') && !(LibopusGarbage && FmpeggGarbage)
? MissingDeps.push(
`${
MissingDeps.length - 1
}) "ffmpeg-static" OR "Ffmpeg from [https://www.ffmpeg.org/download.html]"`,
)
: undefined;
!miscUtils.scanDeps('playdl-music-extractor') &&
!miscUtils.scanDeps('video-extractor')
? MissingDeps.push(
`${
MissingDeps.length - 1
}) "playdl-music-extractor" OR "video-extractor"`,
)
: undefined;
if (MissingDeps[2]) {
setTimeout(() => {
playerInstance.emit(
'error',
playerInstance,
new Error(
[
'-'.repeat(50),
...MissingDeps,
'--[ queue value will be undefined By-default as it will trigger as -> player.on("error",errorMessage) => {} ]--',
'-'.repeat(50),
].join('\n'),
),
{ discordClient },
'miscUtils.#__initialBuildChecks()',
);
}, 2 * 1000);
}
if (!(discordClient && discordClient instanceof Client)) {
throw Error(
'Invalid Discord Client has been Detected! | And get some Voice and Channel Intents too',
);
}
setTimeout(() => {
if (
!new IntentsBitField(discordClient.options.intents).has(
IntentsBitField.Flags.GuildVoiceStates,
) &&
!new IntentsBitField(discordClient.options.intents).has(
IntentsBitField.Flags.Guilds,
)
) {
throw SyntaxError(
'Missing Intents in Discord Client\n - IntentsBitField.Flags.GuildVoiceStates\n - - IntentsBitField.Flags.Guilds',
);
} else if (
!new IntentsBitField(discordClient.options.intents).has(
IntentsBitField.Flags.GuildVoiceStates,
)
) {
throw SyntaxError(
'Missing Intents in Discord Client\n - IntentsBitField.Flags.GuildVoiceStates',
);
} else if (
!new IntentsBitField(discordClient.options.intents).has(
IntentsBitField.Flags.Guilds,
)
) {
throw SyntaxError(
'Missing Intents in Discord Client\n -IntentsBitField.Flags.Guilds',
);
} else return undefined;
}, 45 * 1000);
}
/**
* @static
* Wait for Milliseconds for Delay between processes
* @param {Number|String|void} Milliseconds Time in Milliseconds
* @returns {Promise<void>} return undefined for no return
*/
static async TimeWait(Milliseconds = 1000) {
return await new Promise((resolve) => setTimeout(resolve, Number(Milliseconds)));
}
/**
* @static
* Checks for Valid Url and returns Boolean Results
* @param {String} Url Raw url for Url Checks
* @return {Promise<Boolean>} returns undefined on completion
*/
static async isUriCheck(Url) {
if (!Url || (Url && typeof Url !== 'string')) {
return false;
}
const ProtocolAndDomainRegEx = /^(?:\w+:)?\/\/(\S+)$/;
const LocalHostDomainRegEx = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
const NonLocalHostDomainRegEx = /^[^\s\.]+\.\S{2,}$/;
const SearchMatchResults = Url.match(ProtocolAndDomainRegEx);
if (!SearchMatchResults || (SearchMatchResults && !SearchMatchResults[1])) {
return false;
}
if (
LocalHostDomainRegEx.test(SearchMatchResults[1]) ||
NonLocalHostDomainRegEx.test(SearchMatchResults[1])
) {
return true;
}
return false;
}
/**
* @static
* @method watchDestroyed Watch Destroyed Function for NodeJS.Timeout Value if any
* @param {object} queue Queue Instance for destroyed checks
* @returns {Boolean} Returns Boolean Value for if statement or checker
*/
static watchDestroyed = (queue) => {
if (!queue) return true
else if (queue?.destroyed && typeof queue?.destroyed === 'number') {
clearTimeout(queue?.destroyed);
queue.destroyed = false;
return false;
} else
return Boolean(queue?.destroyed);
};
/**
* @static @method readableTime convert milliseconds to human-readable format
* @param {number} rawData Time as milliseconds
* @param {string} type String type for switch case for types of converting
* @returns {string | undefined} String Value or undefined on converting
*/
static readableTime(rawData, type = 'colon') {
if (
!(
((rawData && !isNaN(Number(rawData))) || parseInt(rawData) === 0) &&
parseInt(rawData) >= 0 &&
type &&
typeof type === 'string' &&
type?.trim() !== ''
)
)
return undefined;
switch (type?.toLowerCase()?.trim()) {
case 'colon':
return prettyMs(rawData, {
colonNotation: true,
keepDecimalsOnWholeSeconds: false,
});
case 'small':
return prettyMs(rawData);
case 'big':
return prettyMs(rawData, { verbose: true });
case 'compact':
return prettyMs(rawData, {
compact: true,
keepDecimalsOnWholeSeconds: false,
});
default:
return undefined;
}
}
}
module.exports = miscUtils;