cleanup base
This commit is contained in:
parent
e7031a29f9
commit
1e18875752
4 changed files with 4 additions and 369 deletions
|
@ -1,75 +1 @@
|
|||
import { FiltersName } from '../types/types';
|
||||
|
||||
const FilterList = {
|
||||
bassboost: 'bass=g=20',
|
||||
'8D': 'apulsator=hz=0.09',
|
||||
vaporwave: 'aresample=48000,asetrate=48000*0.8',
|
||||
nightcore: 'aresample=48000,asetrate=48000*1.25',
|
||||
phaser: 'aphaser=in_gain=0.4',
|
||||
tremolo: 'tremolo',
|
||||
vibrato: 'vibrato=f=6.5',
|
||||
reverse: 'areverse',
|
||||
treble: 'treble=g=5',
|
||||
normalizer: 'dynaudnorm=g=101',
|
||||
surrounding: 'surround',
|
||||
pulsator: 'apulsator=hz=1',
|
||||
subboost: 'asubboost',
|
||||
karaoke: 'stereotools=mlev=0.03',
|
||||
flanger: 'flanger',
|
||||
gate: 'agate',
|
||||
haas: 'haas',
|
||||
mcompand: 'mcompand',
|
||||
mono: 'pan=mono|c0=.5*c0+.5*c1',
|
||||
mstlr: 'stereotools=mode=ms>lr',
|
||||
mstrr: 'stereotools=mode=ms>rr',
|
||||
compressor: 'compand=points=-80/-105|-62/-80|-15.4/-15.4|0/-12|20/-7.6',
|
||||
expander: 'compand=attacks=0:points=-80/-169|-54/-80|-49.5/-64.6|-41.1/-41.1|-25.8/-15|-10.8/-4.5|0/0|20/8.3',
|
||||
softlimiter: 'compand=attacks=0:points=-80/-80|-12.4/-12.4|-6/-8|0/-6.8|20/-2.8',
|
||||
chorus: 'chorus=0.7:0.9:55:0.4:0.25:2',
|
||||
chorus2d: 'chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3',
|
||||
chorus3d: 'chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3',
|
||||
fadein: 'afade=t=in:ss=0:d=10',
|
||||
|
||||
*[Symbol.iterator](): IterableIterator<{ name: FiltersName; value: string }> {
|
||||
for (const [k, v] of Object.entries(this)) {
|
||||
if (typeof this[k as FiltersName] === 'string') yield { name: k as FiltersName, value: v as string };
|
||||
}
|
||||
},
|
||||
|
||||
get names() {
|
||||
return Object.keys(this).filter(
|
||||
(p) => !['names', 'length'].includes(p) && typeof this[p as FiltersName] !== 'function'
|
||||
);
|
||||
},
|
||||
|
||||
get length() {
|
||||
return Object.keys(this).filter(
|
||||
(p) => !['names', 'length'].includes(p) && typeof this[p as FiltersName] !== 'function'
|
||||
).length;
|
||||
},
|
||||
|
||||
toString() {
|
||||
return `${Object.values(this).join(',')}`;
|
||||
},
|
||||
|
||||
create(filter?: FiltersName[]): string {
|
||||
if (!filter || !Array.isArray(filter)) return this.toString();
|
||||
return filter
|
||||
.filter((predicate) => typeof predicate === 'string')
|
||||
.map((m) => this[m])
|
||||
.join(',');
|
||||
},
|
||||
|
||||
define(filterName: string, value: string): void {
|
||||
if (typeof this[filterName as FiltersName] && typeof this[filterName as FiltersName] === 'function') return;
|
||||
|
||||
this[filterName as FiltersName] = value;
|
||||
},
|
||||
|
||||
defineBulk(filterArray: { name: string; value: string }[]): void {
|
||||
filterArray.forEach((arr) => this.define(arr.name, arr.value));
|
||||
}
|
||||
};
|
||||
|
||||
export default FilterList;
|
||||
export { FilterList as AudioFilters };
|
||||
export { }
|
|
@ -1,41 +1 @@
|
|||
import { PlayerOptions as DP_OPTIONS } from '../types/types';
|
||||
|
||||
export enum PlayerEvents {
|
||||
BOT_DISCONNECT = 'botDisconnect',
|
||||
CHANNEL_EMPTY = 'channelEmpty',
|
||||
CONNECTION_CREATE = 'connectionCreate',
|
||||
ERROR = 'error',
|
||||
MUSIC_STOP = 'musicStop',
|
||||
NO_RESULTS = 'noResults',
|
||||
PLAYLIST_ADD = 'playlistAdd',
|
||||
PLAYLIST_PARSE_END = 'playlistParseEnd',
|
||||
PLAYLIST_PARSE_START = 'playlistParseStart',
|
||||
QUEUE_CREATE = 'queueCreate',
|
||||
QUEUE_END = 'queueEnd',
|
||||
SEARCH_CANCEL = 'searchCancel',
|
||||
SEARCH_INVALID_RESPONSE = 'searchInvalidResponse',
|
||||
SEARCH_RESULTS = 'searchResults',
|
||||
TRACK_ADD = 'trackAdd',
|
||||
TRACK_START = 'trackStart'
|
||||
}
|
||||
|
||||
export enum PlayerErrorEventCodes {
|
||||
DEFAULT = 'PlayerError',
|
||||
LIVE_VIDEO = 'LiveVideo',
|
||||
NOT_CONNECTED = 'NotConnected',
|
||||
UNABLE_TO_JOIN = 'UnableToJoin',
|
||||
NOT_PLAYING = 'NotPlaying',
|
||||
PARSE_ERROR = 'ParseError',
|
||||
VIDEO_UNAVAILABLE = 'VideoUnavailable',
|
||||
MUSIC_STARTING = 'MusicStarting'
|
||||
}
|
||||
|
||||
export const PlayerOptions: DP_OPTIONS = {
|
||||
leaveOnEnd: true,
|
||||
leaveOnStop: true,
|
||||
leaveOnEmpty: true,
|
||||
leaveOnEmptyCooldown: 0,
|
||||
setSelfDeaf: true,
|
||||
enableLive: false,
|
||||
ytdlDownloadOptions: {}
|
||||
};
|
||||
export { }
|
|
@ -1,19 +1 @@
|
|||
import { Message } from 'discord.js';
|
||||
|
||||
export default class PlayerError extends Error {
|
||||
discordMessage: Message;
|
||||
|
||||
constructor(msg: string, name?: string, message?: Message) {
|
||||
super();
|
||||
this.name = name ?? 'PlayerError';
|
||||
this.message = msg;
|
||||
this.discordMessage = message;
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
|
||||
get code() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
export { PlayerError };
|
||||
export { }
|
|
@ -1,234 +1 @@
|
|||
import { QueryType, TimeData } from '../types/types';
|
||||
import { FFmpeg } from 'prism-media';
|
||||
import YouTube from 'youtube-sr';
|
||||
import { Track } from '../Structures/Track';
|
||||
// @ts-ignore
|
||||
import { validateURL as SoundcloudValidateURL } from 'soundcloud-scraper';
|
||||
import { VoiceChannel } from 'discord.js';
|
||||
|
||||
const spotifySongRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/;
|
||||
const spotifyPlaylistRegex =
|
||||
/https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})/;
|
||||
const spotifyAlbumRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:album\/|\?uri=spotify:album:)((\w|-){22})/;
|
||||
const vimeoRegex =
|
||||
/(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|video\/|)(\d+)(?:|\/\?)/;
|
||||
const facebookRegex = /(https?:\/\/)(www\.|m\.)?(facebook|fb).com\/.*\/videos\/.*/;
|
||||
const reverbnationRegex = /https:\/\/(www.)?reverbnation.com\/(.+)\/song\/(.+)/;
|
||||
const attachmentRegex =
|
||||
/^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
|
||||
|
||||
export class Util {
|
||||
/**
|
||||
* Static Player Util class
|
||||
*/
|
||||
constructor() {
|
||||
throw new Error(`The ${this.constructor.name} class is static and cannot be instantiated!`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks FFmpeg Version
|
||||
* @param {Boolean} [force] If it should forcefully get the version
|
||||
* @returns {String}
|
||||
*/
|
||||
static getFFmpegVersion(force?: boolean): string {
|
||||
try {
|
||||
const info = FFmpeg.getInfo(Boolean(force));
|
||||
|
||||
return info.version;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks FFmpeg
|
||||
* @param {Boolean} [force] If it should forcefully get the version
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static checkFFmpeg(force?: boolean): boolean {
|
||||
const version = Util.getFFmpegVersion(force);
|
||||
return version === null ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alerts if FFmpeg is not available
|
||||
*/
|
||||
static alertFFmpeg(): void {
|
||||
const hasFFmpeg = Util.checkFFmpeg();
|
||||
|
||||
if (!hasFFmpeg)
|
||||
console.warn(
|
||||
'[Discord Player] FFmpeg/Avconv not found! Install via "npm install ffmpeg-static" or download from https://ffmpeg.org/download.html'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves query type
|
||||
* @param {String} query The query
|
||||
* @returns {QueryType}
|
||||
*/
|
||||
static getQueryType(query: string): QueryType {
|
||||
if (SoundcloudValidateURL(query) && !query.includes('/sets/')) return 'soundcloud_track';
|
||||
if (SoundcloudValidateURL(query) && query.includes('/sets/')) return 'soundcloud_playlist';
|
||||
if (spotifySongRegex.test(query)) return 'spotify_song';
|
||||
if (spotifyAlbumRegex.test(query)) return 'spotify_album';
|
||||
if (spotifyPlaylistRegex.test(query)) return 'spotify_playlist';
|
||||
if (YouTube.validate(query, 'PLAYLIST')) return 'youtube_playlist';
|
||||
if (YouTube.validate(query, 'VIDEO')) return 'youtube_video';
|
||||
if (vimeoRegex.test(query)) return 'vimeo';
|
||||
if (facebookRegex.test(query)) return 'facebook';
|
||||
if (reverbnationRegex.test(query)) return 'reverbnation';
|
||||
if (Util.isURL(query)) return 'attachment';
|
||||
|
||||
return 'youtube_search';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given string is url
|
||||
* @param {String} str URL to check
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static isURL(str: string): boolean {
|
||||
return str.length < 2083 && attachmentRegex.test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Vimeo ID
|
||||
* @param {String} query Vimeo link
|
||||
* @returns {String}
|
||||
*/
|
||||
static getVimeoID(query: string): string {
|
||||
return Util.getQueryType(query) === 'vimeo'
|
||||
? query
|
||||
.split('/')
|
||||
.filter((x) => !!x)
|
||||
.pop()
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses ms time
|
||||
* @param {Number} milliseconds Time to parse
|
||||
* @returns {TimeData}
|
||||
*/
|
||||
static parseMS(milliseconds: number): TimeData {
|
||||
const roundTowardsZero = milliseconds > 0 ? Math.floor : Math.ceil;
|
||||
|
||||
return {
|
||||
days: roundTowardsZero(milliseconds / 86400000),
|
||||
hours: roundTowardsZero(milliseconds / 3600000) % 24,
|
||||
minutes: roundTowardsZero(milliseconds / 60000) % 60,
|
||||
seconds: roundTowardsZero(milliseconds / 1000) % 60
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates simple duration string
|
||||
* @param {object} durObj Duration object
|
||||
* @returns {String}
|
||||
*/
|
||||
static durationString(durObj: object): string {
|
||||
return Object.values(durObj)
|
||||
.map((m) => (isNaN(m) ? 0 : m))
|
||||
.join(':');
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes youtube searches
|
||||
* @param {String} query The query
|
||||
* @param {any} options Options
|
||||
* @returns {Promise<Track[]>}
|
||||
*/
|
||||
static ytSearch(query: string, options?: any): Promise<Track[]> {
|
||||
return new Promise(async (resolve) => {
|
||||
await YouTube.search(query, {
|
||||
type: 'video',
|
||||
safeSearch: Boolean(options?.player.options.useSafeSearch),
|
||||
limit: options.limit ?? 10
|
||||
})
|
||||
.then((results) => {
|
||||
resolve(
|
||||
results.map(
|
||||
(r) =>
|
||||
new Track(options?.player, {
|
||||
title: r.title,
|
||||
description: r.description,
|
||||
author: r.channel.name,
|
||||
url: r.url,
|
||||
thumbnail: r.thumbnail.displayThumbnailURL(),
|
||||
duration: Util.buildTimeCode(Util.parseMS(r.duration)),
|
||||
views: r.views,
|
||||
requestedBy: options?.user,
|
||||
fromPlaylist: Boolean(options?.pl),
|
||||
source: 'youtube'
|
||||
})
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch(() => resolve([]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this system is running in replit.com
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static isRepl(): boolean {
|
||||
if ('DP_REPL_NOCHECK' in process.env) return false;
|
||||
|
||||
const REPL_IT_PROPS = [
|
||||
'REPL_SLUG',
|
||||
'REPL_OWNER',
|
||||
'REPL_IMAGE',
|
||||
'REPL_PUBKEYS',
|
||||
'REPL_ID',
|
||||
'REPL_LANGUAGE',
|
||||
'REPLIT_DB_URL'
|
||||
];
|
||||
|
||||
for (const prop of REPL_IT_PROPS) if (prop in process.env) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given voice channel is empty
|
||||
* @param {DiscordVoiceChannel} channel The voice channel
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
static isVoiceEmpty(channel: VoiceChannel): boolean {
|
||||
return channel.members.filter((member) => !member.user.bot).size === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds time code
|
||||
* @param {object} data The data to build time code from
|
||||
* @returns {String}
|
||||
*/
|
||||
static buildTimeCode(data: any): string {
|
||||
const items = Object.keys(data);
|
||||
const required = ['days', 'hours', 'minutes', 'seconds'];
|
||||
|
||||
const parsed = items.filter((x) => required.includes(x)).map((m) => (data[m] > 0 ? data[m] : ''));
|
||||
const final = parsed
|
||||
.filter((x) => !!x)
|
||||
.map((x) => x.toString().padStart(2, '0'))
|
||||
.join(':');
|
||||
return final.length <= 3 ? `0:${final.padStart(2, '0') || 0}` : final;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage CJS require
|
||||
* @param {String} id id to require
|
||||
* @returns {any}
|
||||
*/
|
||||
static require(id: string): any {
|
||||
try {
|
||||
return require(id);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Util;
|
||||
export { }
|
Loading…
Reference in a new issue