Merge pull request #421 from Androz2091/develop

v4.0.8
This commit is contained in:
MegaPixel 2021-05-13 16:22:36 +05:45 committed by GitHub
commit 9295ed6098
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 302 additions and 178 deletions

View file

@ -1,4 +1,4 @@
# How to add custom audio filters
# How to add custom audio filters?
Audio filters in **Discord Player** are **[FFmpeg audio filters](http://ffmpeg.org/ffmpeg-all.html#Audio-Filters)**. You can add your own audio filter like this:

View file

@ -1,4 +1,4 @@
# How to play live videos
# How to play live videos?
You cannot play live videos by default. If you need to play the live video, just add this option:

View file

@ -1,6 +1,6 @@
{
"name": "discord-player",
"version": "4.0.7",
"version": "4.0.8",
"description": "Complete framework to facilitate music commands using discord.js",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -51,9 +51,9 @@
"homepage": "https://discord-player.js.org",
"dependencies": {
"discord-ytdl-core": "^5.0.3",
"soundcloud-scraper": "^4.0.4",
"soundcloud-scraper": "^5.0.0",
"spotify-url-info": "^2.2.0",
"youtube-sr": "^4.0.6",
"youtube-sr": "^4.0.7",
"ytdl-core": "^4.7.0"
},
"devDependencies": {
@ -61,7 +61,7 @@
"@babel/core": "^7.13.16",
"@babel/preset-env": "^7.13.15",
"@babel/preset-typescript": "^7.13.0",
"@discord-player/extractor": "^2.0.0",
"@discord-player/extractor": "^3.0.0",
"@discordjs/opus": "^0.5.0",
"@types/node": "^14.14.41",
"@types/ws": "^7.4.1",

View file

@ -185,16 +185,42 @@ export class Player extends EventEmitter {
/https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/
);
if (matchSpotifyURL) {
const spotifyData = await spotify.getPreview(query).catch(() => {});
const spotifyData = await spotify.getData(query).catch(() => {});
if (spotifyData) {
const searchString = this.options.disableArtistSearch
? spotifyData.title
: `${spotifyData.artist} - ${spotifyData.title}`;
tracks = await Util.ytSearch(searchString, {
user: message.author,
player: this,
limit: 1
const spotifyTrack = new Track(this, {
title: spotifyData.name,
description: spotifyData.description ?? '',
author: spotifyData.artists[0]?.name ?? 'Unknown Artist',
url: spotifyData.external_urls?.spotify ?? query,
thumbnail:
spotifyData.album?.images[0]?.url ?? spotifyData.preview_url?.length
? `https://i.scdn.co/image/${spotifyData.preview_url?.split('?cid=')[1]}`
: 'https://www.scdn.co/i/_global/twitter_card-default.jpg',
duration: Util.buildTimeCode(Util.parseMS(spotifyData.duration_ms)),
views: 0,
requestedBy: message.author,
fromPlaylist: false,
source: 'spotify'
});
if (this.options.fetchBeforeQueued) {
const searchQueryString = this.options.disableArtistSearch
? spotifyTrack.title
: `${spotifyTrack.title}${' - ' + spotifyTrack.author}`;
const ytv = await YouTube.search(searchQueryString, {
limit: 1,
type: 'video'
}).catch((e) => {});
if (ytv && ytv[0])
Util.define({
target: spotifyTrack,
prop: 'backupLink',
value: ytv[0].url
});
}
tracks = [spotifyTrack];
}
}
}
@ -207,33 +233,88 @@ export class Player extends EventEmitter {
if (!playlist) return void this.emit(PlayerEvents.NO_RESULTS, message, query);
// tslint:disable-next-line:no-shadowed-variable
let tracks = await Promise.all<Track>(
playlist.tracks.items.map(async (item: any) => {
const sq =
queryType === 'spotify_album'
? `${
this.options.disableArtistSearch
? item.artists[0].name
: `${item.artists[0].name} - `
}${item.name ?? item.track.name}`
: `${
this.options.disableArtistSearch
? item.track.artists[0].name
: `${item.track.artists[0].name} - `
}${item.name ?? item.track.name}`;
let tracks: Track[] = [];
const data = await Util.ytSearch(sq, {
limit: 1,
player: this,
user: message.author,
pl: true
});
if (playlist.type !== 'playlist')
tracks = await Promise.all(
playlist.tracks.items.map(async (m: any) => {
const data = new Track(this, {
title: m.name ?? '',
description: m.description ?? '',
author: m.artists[0]?.name ?? 'Unknown Artist',
url: m.external_urls?.spotify ?? query,
thumbnail:
playlist.images[0]?.url ?? m.preview_url?.length
? `https://i.scdn.co/image/${m.preview_url?.split('?cid=')[1]}`
: 'https://www.scdn.co/i/_global/twitter_card-default.jpg',
duration: Util.buildTimeCode(Util.parseMS(m.duration_ms)),
views: 0,
requestedBy: message.author,
fromPlaylist: true,
source: 'spotify'
});
if (data.length) return data[0];
})
);
if (this.options.fetchBeforeQueued) {
const searchQueryString = this.options.disableArtistSearch
? data.title
: `${data.title}${' - ' + data.author}`;
const ytv = await YouTube.search(searchQueryString, {
limit: 1,
type: 'video'
}).catch((e) => {});
if (ytv && ytv[0])
Util.define({
target: data,
prop: 'backupLink',
value: ytv[0].url
});
}
return data;
})
);
else {
tracks = await Promise.all(
playlist.tracks.items.map(async (m: any) => {
const data = new Track(this, {
title: m.track.name ?? '',
description: m.track.description ?? '',
author: m.track.artists[0]?.name ?? 'Unknown Artist',
url: m.track.external_urls?.spotify ?? query,
thumbnail:
playlist.images[0]?.url ?? m.track.preview_url?.length
? `https://i.scdn.co/image/${m.track.preview_url?.split('?cid=')[1]}`
: 'https://www.scdn.co/i/_global/twitter_card-default.jpg',
duration: Util.buildTimeCode(Util.parseMS(m.track.duration_ms)),
views: 0,
requestedBy: message.author,
fromPlaylist: true,
source: 'spotify'
});
if (this.options.fetchBeforeQueued) {
const searchQueryString = this.options.disableArtistSearch
? data.title
: `${data.title}${' - ' + data.author}`;
const ytv = await YouTube.search(searchQueryString, {
limit: 1,
type: 'video'
}).catch((e) => {});
if (ytv && ytv[0])
Util.define({
target: data,
prop: 'backupLink',
value: ytv[0].url
});
}
return data;
})
);
}
tracks = tracks.filter((f) => !!f);
if (!tracks.length) return void this.emit(PlayerEvents.NO_RESULTS, message, query);
const pl = {
@ -250,7 +331,7 @@ export class Player extends EventEmitter {
const queue = this._addTracksToQueue(message, tracks);
this.emit(PlayerEvents.PLAYLIST_ADD, message, queue, pl);
} else {
const track = tracks.shift();
const track = tracks[0];
const queue = (await this._createQueue(message, track).catch(
(e) => void this.emit(PlayerEvents.ERROR, e, message)
)) as Queue;
@ -306,7 +387,7 @@ export class Player extends EventEmitter {
const queue = this._addTracksToQueue(message, tracks);
this.emit(PlayerEvents.PLAYLIST_ADD, message, queue, playlist);
} else {
const track = tracks.shift();
const track = tracks[0];
const queue = (await this._createQueue(message, track).catch(
(e) => void this.emit(PlayerEvents.ERROR, e, message)
)) as Queue;
@ -361,7 +442,7 @@ export class Player extends EventEmitter {
const queue = this._addTracksToQueue(message, res.tracks);
this.emit(PlayerEvents.PLAYLIST_ADD, message, queue, res);
} else {
const track = res.tracks.shift();
const track = res.tracks[0];
const queue = (await this._createQueue(message, track).catch(
(e) => void this.emit(PlayerEvents.ERROR, e, message)
)) as Queue;
@ -475,7 +556,7 @@ export class Player extends EventEmitter {
author: data.author,
views: data.views,
engine: data.engine,
source: 'arbitrary',
source: data.source ?? 'arbitrary',
fromPlaylist: false,
requestedBy: message.author,
url: data.url
@ -959,7 +1040,7 @@ export class Player extends EventEmitter {
const extractor = Util.require('@discord-player/extractor');
if (!extractor) throw new PlayerError("Cannot call 'Player.lyrics()' without '@discord-player/extractor'");
const data = await extractor.Lyrics(query);
const data = await extractor.Lyrics.init().search(query);
if (Array.isArray(data)) return null;
return data;
@ -1054,7 +1135,7 @@ export class Player extends EventEmitter {
if (!oldState.channelID || newState.channelID) {
const emptyTimeout = this._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
// @todo: stage channels
// @todo: make stage channels stable
const channelEmpty = Util.isVoiceEmpty(queue.voiceConnection.channel as VoiceChannel);
if (!channelEmpty && emptyTimeout) {
clearTimeout(emptyTimeout);
@ -1254,8 +1335,32 @@ export class Player extends EventEmitter {
}
let newStream: any;
if (queue.playing.raw.source === 'youtube') {
newStream = ytdl(queue.playing.url, {
// modify spotify
if (queue.playing.raw.source === 'spotify' && !(queue.playing as any).backupLink) {
const searchQueryString = this.options.disableArtistSearch
? queue.playing.title
: `${queue.playing.title}${' - ' + queue.playing.author}`;
const yteqv = await YouTube.search(searchQueryString, { type: 'video', limit: 1 }).catch(() => {});
if (!yteqv || !yteqv.length)
return void this.emit(
PlayerEvents.ERROR,
PlayerErrorEventCodes.VIDEO_UNAVAILABLE,
queue.firstMessage,
queue.playing,
new PlayerError('Could not find alternative track on youtube!', 'SpotifyTrackError')
);
Util.define({
target: queue.playing,
prop: 'backupLink',
value: yteqv[0].url
});
}
if (queue.playing.raw.source === 'youtube' || queue.playing.raw.source === 'spotify') {
newStream = ytdl((queue.playing as any).backupLink ?? queue.playing.url, {
opusEncoded: true,
encoderArgs: queue.playing.raw.live ? [] : encoderArgs,
seek: seekTime / 1000,
@ -1281,8 +1386,7 @@ export class Player extends EventEmitter {
queue.stream = newStream;
queue.voiceConnection.play(newStream, {
type: 'opus',
bitrate: 'auto',
volume: Util.isRepl() ? false : undefined
bitrate: 'auto'
});
if (seekTime) {
@ -1443,6 +1547,7 @@ export default Player;
* @property {Boolean} [useSafeSearch=false] If it should use `safe search` method for youtube searches
* @property {Boolean} [disableAutoRegister=false] If it should disable auto-registeration of `@discord-player/extractor`
* @property {Boolean} [disableArtistSearch=false] If it should disable artist search for spotify
* @property {Boolean} [fetchBeforeQueued=false] If it should fetch all songs loaded from spotify before playing
*/
/**
@ -1518,7 +1623,7 @@ export default Player;
* @property {String} thumbnail The thumbnail
* @property {String} image The image
* @property {String} url The url
* @property {Object} artist The artust info
* @property {Object} artist The artist info
* @property {String} [artist.name] The name of the artist
* @property {Number} [artist.id] The ID of the artist
* @property {String} [artist.url] The profile link of the artist

View file

@ -167,7 +167,7 @@ export class Queue extends EventEmitter {
/**
* Sets audio filters in this player
* @param {QueueFilters} filters Audio filters to set
* @type {Promise<void>}
* @returns {Promise<void>}
*/
setFilters(filters: QueueFilters): Promise<void> {
return this.player.setFilters(this.firstMessage, filters);
@ -175,7 +175,7 @@ export class Queue extends EventEmitter {
/**
* Returns array of all enabled filters
* @type {String[]}
* @returns {String[]}
*/
getFiltersEnabled(): string[] {
const filters: string[] = [];
@ -189,7 +189,7 @@ export class Queue extends EventEmitter {
/**
* Returns all disabled filters
* @type {String[]}
* @returns {String[]}
*/
getFiltersDisabled(): string[] {
const enabled = this.getFiltersEnabled();
@ -197,6 +197,14 @@ export class Queue extends EventEmitter {
return Object.keys(this.filters).filter((f) => !enabled.includes(f));
}
/**
* Destroys this queue
* @returns {Boolean}
*/
destroy() {
return this.player.stop(this.firstMessage);
}
/**
* String representation of this Queue
* @returns {String}

View file

@ -134,6 +134,14 @@ export class Track {
.reduce((a, c) => a + c, 0);
}
/**
* Returns source of this track
* @type {TrackSource}
*/
get source() {
return this.raw.source ?? 'arbitrary';
}
/**
* String representation of this track
* @returns {String}

View file

@ -14,11 +14,12 @@ export interface PlayerOptions {
useSafeSearch?: boolean;
disableAutoRegister?: boolean;
disableArtistSearch?: boolean;
fetchBeforeQueued?: boolean;
}
export type FiltersName = keyof QueueFilters;
export type TrackSource = 'soundcloud' | 'youtube' | 'arbitrary';
export type TrackSource = 'soundcloud' | 'youtube' | 'spotify' | 'arbitrary';
export interface TrackData {
title: string;
@ -91,6 +92,7 @@ export interface ExtractorModelData {
url: string;
version?: string;
important?: boolean;
source?: TrackSource;
}
export interface PlayerProgressbarOptions {

View file

@ -65,8 +65,8 @@ export class Util {
* @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 (SoundcloudValidateURL(query, 'track')) return 'soundcloud_track';
if (SoundcloudValidateURL(query, 'playlist') || 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';
@ -166,28 +166,6 @@ export class Util {
});
}
/**
* 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
@ -226,6 +204,22 @@ export class Util {
return null;
}
}
/**
* Defines a property in the given object
* @param {any} target The target
* @param {any} prop The property to define
* @param {any} value The value
* @returns {void}
*/
static define(ops: { target: any; prop: any; value: any; enumerate?: boolean }) {
Object.defineProperty(ops.target, ops.prop, {
value: ops.value,
writable: true,
enumerable: Boolean(ops.enumerate),
configurable: true
});
}
}
export default Util;

209
yarn.lock
View file

@ -871,13 +871,13 @@
"@babel/helper-validator-identifier" "^7.12.11"
to-fast-properties "^2.0.0"
"@discord-player/extractor@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@discord-player/extractor/-/extractor-2.0.0.tgz#3879e51d64b72d4dcee9338bdece5251d006c746"
integrity sha512-qNyF0dkLNRYvtVtLLO022RV8DzToCPJqbuAOqSWCSdkXiKSGoqTdKcZI9I/Lb87mchYuuakOXyPRvRwkAruX6w==
"@discord-player/extractor@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@discord-player/extractor/-/extractor-3.0.0.tgz#2baa733da054b991f83417054cad1575cf57c4ab"
integrity sha512-6A2QmrbQXTpv1oequiAYQMnWzvv1fu9Yg0GJwAMoLUXZjvb5Yoak2lnohsDI1Hc14LW//Z5xyLGtmFivTWTXDQ==
dependencies:
genius-lyrics "^4.2.7"
jsdom "^16.5.2"
genius-lyrics "^4.2.9"
jsdom "^16.5.3"
node-fetch "^2.6.1"
reverbnation-scraper "^2.0.0"
@ -940,6 +940,14 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
"@types/node-fetch@^2.5.10":
version "2.5.10"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132"
integrity sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==
dependencies:
"@types/node" "*"
form-data "^3.0.0"
"@types/node@*", "@types/node@^14.14.41":
version "14.14.41"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615"
@ -1405,29 +1413,29 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
cheerio-select-tmp@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz#55bbef02a4771710195ad736d5e346763ca4e646"
integrity sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==
cheerio-select@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.4.0.tgz#3a16f21e37a2ef0f211d6d1aa4eff054bb22cdc9"
integrity sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==
dependencies:
css-select "^3.1.2"
css-what "^4.0.0"
domelementtype "^2.1.0"
domhandler "^4.0.0"
domutils "^2.4.4"
css-select "^4.1.2"
css-what "^5.0.0"
domelementtype "^2.2.0"
domhandler "^4.2.0"
domutils "^2.6.0"
cheerio@^1.0.0-rc.3:
version "1.0.0-rc.5"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.5.tgz#88907e1828674e8f9fee375188b27dadd4f0fa2f"
integrity sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==
cheerio@^1.0.0-rc.9:
version "1.0.0-rc.9"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.9.tgz#a3ae6b7ce7af80675302ff836f628e7cb786a67f"
integrity sha512-QF6XVdrLONO6DXRF5iaolY+odmhj2CLj+xzNod7INPWMi/x9X4SOylH0S/vaPpX+AUU6t04s34SQNh7DbkuCng==
dependencies:
cheerio-select-tmp "^0.1.0"
dom-serializer "~1.2.0"
domhandler "^4.0.0"
entities "~2.1.0"
htmlparser2 "^6.0.0"
parse5 "^6.0.0"
parse5-htmlparser2-tree-adapter "^6.0.0"
cheerio-select "^1.4.0"
dom-serializer "^1.3.1"
domhandler "^4.2.0"
htmlparser2 "^6.1.0"
parse5 "^6.0.1"
parse5-htmlparser2-tree-adapter "^6.0.1"
tslib "^2.2.0"
chokidar@^3.4.0:
version "3.5.1"
@ -1648,21 +1656,21 @@ cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
css-select@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8"
integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==
css-select@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.2.tgz#8b52b6714ed3a80d8221ec971c543f3b12653286"
integrity sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==
dependencies:
boolbase "^1.0.0"
css-what "^4.0.0"
domhandler "^4.0.0"
domutils "^2.4.3"
css-what "^5.0.0"
domhandler "^4.2.0"
domutils "^2.6.0"
nth-check "^2.0.0"
css-what@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233"
integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A==
css-what@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.0.tgz#f0bf4f8bac07582722346ab243f6a35b512cfc47"
integrity sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==
cssom@^0.4.4:
version "0.4.4"
@ -1841,7 +1849,7 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dom-serializer@^1.0.1, dom-serializer@~1.2.0:
dom-serializer@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1"
integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==
@ -1850,7 +1858,16 @@ dom-serializer@^1.0.1, dom-serializer@~1.2.0:
domhandler "^4.0.0"
entities "^2.0.0"
domelementtype@^2.0.1, domelementtype@^2.1.0, domelementtype@^2.2.0:
dom-serializer@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.1.tgz#d845a1565d7c041a95e5dab62184ab41e3a519be"
integrity sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
entities "^2.0.0"
domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
@ -1862,21 +1879,28 @@ domexception@^2.0.1:
dependencies:
webidl-conversions "^5.0.0"
domhandler@^4.0.0, domhandler@^4.1.0:
domhandler@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.1.0.tgz#c1d8d494d5ec6db22de99e46a149c2a4d23ddd43"
integrity sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==
dependencies:
domelementtype "^2.2.0"
domutils@^2.4.3, domutils@^2.4.4:
version "2.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.5.1.tgz#9b8e84b5d9f788499ae77506ea832e9b4f9aa1c0"
integrity sha512-hO1XwHMGAthA/1KL7c83oip/6UWo3FlUNIuWiWKltoiQ5oCOiqths8KknvY2jpOohUoUgnwa/+Rm7UpwpSbY/Q==
domhandler@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
dependencies:
domelementtype "^2.2.0"
domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.6.0.tgz#2e15c04185d43fb16ae7057cb76433c6edb938b7"
integrity sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
domhandler "^4.1.0"
domhandler "^4.2.0"
ecc-jsbn@~0.1.1:
version "0.1.2"
@ -1911,11 +1935,6 @@ entities@~2.0.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
entities@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -2225,6 +2244,15 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@ -2292,13 +2320,13 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
genius-lyrics@^4.2.7:
version "4.2.7"
resolved "https://registry.yarnpkg.com/genius-lyrics/-/genius-lyrics-4.2.7.tgz#e85f65eb2de4ea2c0af1e11b13dda11e0c9744a9"
integrity sha512-laoeF2/P+Ed4uewuG6OeqymKTNdfGuymkCohMHIgr3g2DwziW49USXcEGCog1vnEDCpf2LhznNi3WOeLeSmAww==
genius-lyrics@^4.2.9:
version "4.2.9"
resolved "https://registry.yarnpkg.com/genius-lyrics/-/genius-lyrics-4.2.9.tgz#87d12946589d3e96df4e100c51805aa5046de2c7"
integrity sha512-BQm/gmaXEckLAc/Z9ZsGNWxh4CHudx0G1Key8Rnv0xFcqmrxIvssJIDBgDPJLqB6dpVas3uj6LQng1yMFtxfNA==
dependencies:
axios "^0.21.1"
node-html-parser "^3.0.4"
cheerio "^1.0.0-rc.9"
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
@ -2458,11 +2486,6 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
he@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
himalaya@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/himalaya/-/himalaya-1.1.0.tgz#31724ae9d35714cd7c6f4be94888953f3604606a"
@ -2475,14 +2498,14 @@ html-encoding-sniffer@^2.0.1:
dependencies:
whatwg-encoding "^1.0.5"
htmlparser2@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.0.1.tgz#422521231ef6d42e56bd411da8ba40aa36e91446"
integrity sha512-GDKPd+vk4jvSuvCbyuzx/unmXkk090Azec7LovXP8as1Hn8q9p3hbjmDGbUqqhknw0ajwit6LiiWqfiTUPMK7w==
htmlparser2@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
domutils "^2.4.4"
domutils "^2.5.2"
entities "^2.0.0"
http-proxy-agent@^4.0.1:
@ -2724,11 +2747,6 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
iso8601-duration@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/iso8601-duration/-/iso8601-duration-1.3.0.tgz#29d7b69e0574e4acdee50c5e5e09adab4137ba5a"
integrity sha512-K4CiUBzo3YeWk76FuET/dQPH03WE04R94feo5TSKQCXpoXQt9E4yx2CnY737QZnSAI3PI4WlKo/zfqizGx52QQ==
isobject@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
@ -2844,7 +2862,7 @@ jsdoc@^3.6.3:
taffydb "2.6.2"
underscore "~1.10.2"
jsdom@^16.5.2:
jsdom@^16.5.3:
version "16.5.3"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.3.tgz#13a755b3950eb938b4482c407238ddf16f0d2136"
integrity sha512-Qj1H+PEvUsOtdPJ056ewXM4UJPCi4hhLA8wpiz9F2YvsRBhuFsXxtrIFAgGBDynQA9isAMGE91PfUYbdMPXuTA==
@ -3014,7 +3032,7 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
m3u8stream@^0.8.0, m3u8stream@^0.8.3:
m3u8stream@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/m3u8stream/-/m3u8stream-0.8.3.tgz#c4624e92b4240eb356d040c4a5e155586cf58108"
integrity sha512-0nAcdrF8YJKUkb6PzWdvGftTPyCVWgoiot1AkNVbPKTeIGsWs6DrOjifrJ0Zi8WQfQmD2SuVCjkYIOip12igng==
@ -3230,14 +3248,6 @@ node-fetch@2.6.1, node-fetch@^2.6.0, node-fetch@^2.6.1:
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
node-html-parser@^3.0.4:
version "3.1.5"
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-3.1.5.tgz#ffb62f2a336b6b634f41f3315487fe446fb9d7b5"
integrity sha512-/XKKdWbSUymlXTjtNBcDlmM7Jp8S/BqGMzLx7r2bd2NMjTXz+ofuLcz0Bl3VT0vTvVzF+N511FNLrZt4HVitXA==
dependencies:
css-select "^3.1.2"
he "1.2.0"
node-releases@^1.1.71:
version "1.1.71"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
@ -3404,14 +3414,14 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse5-htmlparser2-tree-adapter@^6.0.0:
parse5-htmlparser2-tree-adapter@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
dependencies:
parse5 "^6.0.1"
parse5@6.0.1, parse5@^6.0.0, parse5@^6.0.1:
parse5@6.0.1, parse5@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
@ -3856,14 +3866,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
simple-youtube-api@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/simple-youtube-api/-/simple-youtube-api-5.2.1.tgz#d1f6efb941ce404f50ce56e0c5e6bff249fcac6a"
integrity sha512-vmndP9Bkh35tifn2OwY+th2imSsfYtmDqczgdOW5yEARFzvSoR8VSQFsivJnctfV5QHQUL6VrOpNdbmDRLh9Bg==
dependencies:
iso8601-duration "^1.2.0"
node-fetch "^2.6.0"
slash@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
@ -3917,13 +3919,13 @@ sort-array@^2.0.0:
object-get "^2.1.0"
typical "^2.6.0"
soundcloud-scraper@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/soundcloud-scraper/-/soundcloud-scraper-4.0.4.tgz#dfd6a45dc6e63fac7d6b31f2ba1d23a199ca4fb6"
integrity sha512-ei3KuPsVZRiq9j2GN580gQwVGZUWMdkmDAANSPm8qweUa4/UnKAnYiUsc/6volZsQiGsnJAP9+8HECDxNcTg6A==
soundcloud-scraper@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/soundcloud-scraper/-/soundcloud-scraper-5.0.0.tgz#3f4e9d9fc9ee79cbaf6cdd64f462ad6803e25ac1"
integrity sha512-8Rt7WbW85AqiFoKkemF5BKsGAThLGnhOi13ztctAI0Y/wso/iuR97yiVXK1eYRc2YqaD8gkpKUAjEY7bOxLxnw==
dependencies:
cheerio "^1.0.0-rc.3"
m3u8stream "^0.8.0"
cheerio "^1.0.0-rc.9"
m3u8stream "^0.8.3"
node-fetch "^2.6.1"
source-map-resolve@^0.5.0:
@ -4262,6 +4264,11 @@ tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
tslint-config-prettier@^1.18.0:
version "1.18.0"
resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37"
@ -4627,13 +4634,13 @@ yargs@^14.0.0:
y18n "^4.0.0"
yargs-parser "^15.0.1"
youtube-sr@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/youtube-sr/-/youtube-sr-4.0.6.tgz#e27c8fadb51361a6223ba0552b300f131c903fe9"
integrity sha512-nRrqgWl0xYfMhwLTqjF7G6s+36IHIdOMtZaSrz0Cpk4uSIqoeKEJgLiAZrYIGWGNYtS8/mzZYRzYxaIA/gW1Ig==
youtube-sr@^4.0.7:
version "4.0.7"
resolved "https://registry.yarnpkg.com/youtube-sr/-/youtube-sr-4.0.7.tgz#156137713a5df2d02c0698fd819fca2249f3a9f3"
integrity sha512-s05pA+NgD0iPw97XtRXiy5GaEbYyIVsfArmGO5UfvSO5etrG6DxAs1uKqTFbQH4IGTqMsb82M14iB5ohkOD2Mw==
dependencies:
"@types/node-fetch" "^2.5.10"
node-fetch "^2.6.1"
simple-youtube-api "^5.2.1"
ytdl-core@^4.7.0:
version "4.7.0"