jericho-player
Version:
LightWeight Framework for discord.js v14 Music Bots and Radio Bots with fast moderation with commands and no memory leak mode
275 lines (256 loc) • 9.61 kB
JavaScript
const { User } = require('discord.js');
const { playdl, playdlQuick } = require('playdl-music-extractor');
const player = require('../core/player');
const queue = require('../core/queue');
const { downloaderOptions } = require('../misc/enums');
const { scanDeps } = require('../utils/miscUtils');
const eventEmitter = require('../utils/eventEmitter');
const packets = require('./packets');
class downloader {
/**
* @constructor
* @param {packets} packet Packet Instance for moderating backend manupulation and request handlers and handle massive functions and events
* @param {downloaderOptions} options Downloader Options for extractor's scrapping Options
*/
constructor(packet, options = downloaderOptions) {
/**
* Packet Instance for moderating backend manupulation and request handlers and handle massive functions and events
* @type {packets}
* @readonly
*/
this.packet = packet;
/**
* Queue data for Guild Moderation with Voice Channels/Connections
* @type {queue}
* @readonly
*/
this.queue = packet?.queue;
/**
* Actual Jericho-Player's Class Instance for sup=properties requirements and usage
* @type {player}
*/
this.player = packet?.player;
/**
* Event Emitters for Error Management and Event Emitting with proper meanings
* @type {eventEmitter}
*/
this.eventEmitter = packet?.eventEmitter;
/**
* options Downloader Options for extractor's scrapping Options
* @type {downloaderOptions}
* @readonly
*/
this.options = options;
/**
* Play-dl Class Instance for making solid and proper tunneled request inter-exchange
* @type {playdl}
*/
this.playdl = new playdl(options);
this.playdl.on('album', (playlist) => (playlist ? this.packet?.__playlistMod(playlist) : undefined));
this.playdl.on(
'track',
async (extractor, playlist, rawTrack, extractorData, metadata) => await this.packet.__tracksMod(
extractor,
playlist,
rawTrack,
extractorData,
metadata,
),
);
if (scanDeps('video-extractor')) {
const { youtubedl } = require('video-extractor');
this.youtubedl = new youtubedl(options);
this.youtubedl.on('album', (playlist) => (playlist ? this.packet?.__playlistMod(playlist) : undefined));
this.youtubedl.on(
'track',
async (extractor, playlist, rawTrack, extractorData, metadata) => await this.packet.__tracksMod(
extractor,
playlist,
rawTrack,
extractorData,
metadata,
),
);
}
}
/**
* @method get Get Tracks Data or triggering track event for Tracks Mod
* @param {string} rawQuery String Value for fetching/Parsing with the help of extractors
* @param {User} requestedSource requested By Source Data for checks and avoid the further edits on it by some stranger to protect the integrity
* @param {downloaderOptions} options options Downloader Options for extractor's scrapping Options
* @returns {Promise<Boolean | undefined>} Returns Raw Extractor Data on completion of processing and extracting
*/
async get(rawQuery, requestedSource, options = downloaderOptions) {
if (!(rawQuery && typeof rawQuery === 'string' && rawQuery !== ''))
return undefined;
else if (options?.extractor?.toLowerCase()?.trim() === 'youtubedl')
return await this.getYoutubedl(rawQuery, requestedSource, options);
else return await this.getPlaydl(rawQuery, requestedSource, options);
}
/**
* @method getPlaydl Play-dl extractor Function with repsect to internal functions to support the cause of usage
* @param {string} rawQuery String Value for fetching/Parsing with the help of extractors
* @param {User} requestedSource requested By Source Data for checks and avoid the further edits on it by some stranger to protect the integrity
* @param {downloaderOptions} options options Downloader Options for extractor's scrapping Options
* @returns {Promise<Boolean | undefined>} Returns Raw Extractor Data on completion of processing and extracting
*/
async getPlaydl(rawQuery, requestedSource, options = downloaderOptions) {
this.eventEmitter.emitDebug(
'playdl - Extractor',
'Making Request to playdl extractors for parsing and fetch required Track Data',
{
rawQuery,
requestedSource,
downloaderOptions: options,
},
);
const extractorData = await this.playdl.exec(rawQuery, {
...options,
playersCompatibility: true,
waitForPromise: false,
eventReturn: {
...options?.eventReturn,
metadata: {
...options?.eventReturn?.metadata,
__privateCaches: { downloaderOptions: options, requestedSource },
},
},
streamDownload: true,
});
extractorData.on('tracks', (tracks, playlist, metadata) => this.packet.extractorDataManager(
{ rawTracks: tracks, playlist },
'parseTracks',
));
return true;
}
/**
* @method getYoutubedl Youtube-dl extractor Function with repsect to internal functions to support the cause of usage
* @param {string} rawQuery String Value for fetching/Parsing with the help of extractors
* @param {User} requestedSource requested By Source Data for checks and avoid the further edits on it by some stranger to protect the integrity
* @param {downloaderOptions} options options Downloader Options for extractor's scrapping Options
* @returns {Promise<Boolean | undefined>} Returns Raw Extractor Data on completion of processing and extracting
*/
async getYoutubedl(rawQuery, requestedSource, options = downloaderOptions) {
this.eventEmitter.emitDebug(
'youtubedl - Extractor',
'Making Request to youtubedl extractors for parsing and fetch required Track Data',
{
rawQuery,
requestedSource,
downloaderOptions: options,
},
);
let extractorData = await this.youtubedl.exec(rawQuery, {
...options,
playersCompatibility: true,
waitForPromise: false,
eventReturn: {
...options?.eventReturn,
metadata: {
...options?.eventReturn?.metadata,
__privateCaches: { downloaderOptions: options, requestedSource },
},
},
streamDownload: true,
});
if (!extractorData?.tracks) {
extractorData = await this.playdl.exec(rawQuery, {
...options,
playersCompatibility: true,
waitForPromise: false,
eventReturn: {
...options?.eventReturn,
metadata: {
...options?.eventReturn?.metadata,
__privateCaches: { downloaderOptions: options, requestedSource },
},
},
streamDownload: true,
});
} else return undefined;
extractorData.on('tracks', (tracks, playlist, metadata) => this.packet.extractorDataManager(
{ rawTracks: tracks, playlist },
'parseTracks',
));
return true;
}
static async getNonEventExtractor(
rawQuery,
metadataCaches = {},
options = downloaderOptions,
) {
if (!(rawQuery && typeof rawQuery === 'string' && rawQuery !== ''))
return undefined;
else if (
options?.extractor?.toLowerCase()?.trim() === 'youtubedl' &&
scanDeps('video-extractor')
) {
const { youtubedlQuick } = require('video-extractor');
return await youtubedlQuick.exec(rawQuery, {
...options,
playersCompatibility: true,
eventReturn: {
...options?.eventReturn,
metadata: {
...options?.eventReturn?.metadata,
__privateCaches: { ...metadataCaches, downloaderOptions: options },
},
},
streamDownload: true,
});
} else
return await playdlQuick.exec(rawQuery, {
...options,
playersCompatibility: true,
eventReturn: {
...options?.eventReturn,
metadata: {
...options?.eventReturn?.metadata,
__privateCaches: { ...metadataCaches, downloaderOptions: options },
},
},
streamDownload: true,
});
}
/**
* @method __queryFilter Query Filter for the Song Urls checks
* @param {String[]} fitlers Query checking Filters from the User
* @returns {Boolean | false} Returns Boolean value as true
*/
__queryFilter(rawQuery, filters = ['all']) {
if (!(rawQuery && typeof rawQuery === 'string' && rawQuery !== ''))
return undefined;
const isValidUrl = (urlString) => {
try {
return Boolean(new URL(urlString));
} catch (e) {
return false;
}
};
const isValidYoutube = (url) => {
const p =
/^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
return Boolean(url.match(p)?.[1]);
};
const isValidSpotify = (url) => {
const p =
/^(?:spotify:|(?:https?:\/\/(?:open|play)\.spotify\.com\/))(?:embed)?\/?(album|podcasts|track)(?::|\/)((?:[0-9a-zA-Z]){22})/;
};
if (filters?.includes('all')) return true;
else if (filters?.includes('query') && !isValidUrl(rawQuery)) return true;
else if (
filters?.includes('youtube') &&
isValidUrl(rawQuery) &&
isValidYoutube(rawQuery)
)
return true;
else if (
filters?.includes('spotify') &&
isValidUrl(rawQuery) &&
isValidSpotify(rawQuery)
)
return true;
else return false;
}
}
module.exports = downloader;