discord-player-play-dl/src/utils/Util.ts

151 lines
5.8 KiB
TypeScript
Raw Normal View History

2021-04-06 17:58:46 +05:00
import { PlayerOptions, QueryType } from '../types/types';
import { FFmpeg } from 'prism-media';
import YouTube from 'youtube-sr';
2021-04-06 20:38:17 +05:00
import { Track } from '../Structures/Track';
2021-04-06 17:55:29 +05:00
// @ts-ignore
2021-04-06 17:58:46 +05:00
import { validateURL as SoundcloudValidateURL } from 'soundcloud-scraper';
2021-04-06 17:55:29 +05:00
2021-04-06 17:58:46 +05:00
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\/(.+)/;
2021-04-06 17:55:29 +05:00
2021-04-06 20:38:17 +05:00
export class Util {
2021-04-06 17:55:29 +05:00
constructor() {
throw new Error(`The ${this.constructor.name} class is static and cannot be instantiated!`);
}
static get DefaultPlayerOptions() {
return {
leaveOnEnd: true,
leaveOnStop: true,
leaveOnEmpty: true,
leaveOnEmptyCooldown: 0,
autoSelfDeaf: true,
enableLive: false,
ytdlDownloadOptions: {}
} as PlayerOptions;
}
static checkFFmpeg(force?: boolean) {
try {
FFmpeg.getInfo(Boolean(force));
return true;
} catch {
return false;
}
}
static alertFFmpeg() {
const hasFFmpeg = Util.checkFFmpeg();
if (!hasFFmpeg)
console.warn(
2021-04-06 17:58:46 +05:00
'[Discord Player] FFmpeg/Avconv not found! Install via "npm install ffmpeg-static" or download from https://ffmpeg.org/download.html'
2021-04-06 17:55:29 +05:00
);
}
static getQueryType(query: string): QueryType {
2021-04-06 17:58:46 +05:00
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';
2021-04-07 19:05:35 +05:00
if (YouTube.validate(query, 'VIDEO')) return 'youtube_video';
2021-04-06 17:58:46 +05:00
if (vimeoRegex.test(query)) return 'vimeo';
if (facebookRegex.test(query)) return 'facebook';
if (reverbnationRegex.test(query)) return 'reverbnation';
if (Util.isURL(query)) return 'attachment';
2021-04-06 17:55:29 +05:00
2021-04-06 17:58:46 +05:00
return 'youtube_search';
2021-04-06 17:55:29 +05:00
}
static isURL(str: string) {
2021-04-06 17:58:46 +05:00
const urlRegex =
'^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-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,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$';
2021-04-06 17:55:29 +05:00
const url = new RegExp(urlRegex, 'i');
return str.length < 2083 && url.test(str);
}
static getVimeoID(query: string) {
2021-04-06 17:58:46 +05:00
return Util.getQueryType(query) === 'vimeo'
? query
.split('/')
.filter((x) => !!x)
.pop()
: null;
2021-04-06 17:55:29 +05:00
}
static parseMS(milliseconds: number) {
// taken from ms package :: https://github.com/sindresorhus/parse-ms/blob/main/index.js
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
};
}
static durationString(durObj: object) {
2021-04-06 17:58:46 +05:00
return Object.values(durObj)
.map((m) => (isNaN(m) ? 0 : m))
.join(':');
2021-04-06 17:55:29 +05:00
}
static ytSearch(query: string, options?: any): Promise<Track[]> {
return new Promise(async (resolve) => {
await YouTube.search(query, {
2021-04-06 17:58:46 +05:00
type: 'video',
2021-04-07 19:05:35 +05:00
safeSearch: Boolean(options?.player.options.useSafeSearch),
limit: options.limit ?? 10
2021-04-06 17:55:29 +05:00
})
2021-04-06 17:58:46 +05:00
.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: r.durationFormatted,
views: r.views,
requestedBy: options?.user,
2021-04-07 19:05:35 +05:00
fromPlaylist: Boolean(options?.pl),
2021-04-06 17:58:46 +05:00
source: 'youtube'
})
)
);
2021-04-06 17:55:29 +05:00
})
.catch(() => resolve([]));
});
}
2021-04-07 19:25:45 +05:00
static isRepl() {
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;
}
2021-04-06 17:55:29 +05:00
}
2021-04-06 20:38:17 +05:00
export default Util;