mirror of
https://github.com/BluemediaGER/muse.git
synced 2024-11-12 21:05:29 +01:00
Use IoC, impliment queue
This commit is contained in:
parent
8eb4c8a6c0
commit
17ba78f7b7
21
package.json
21
package.json
|
@ -25,11 +25,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/bluebird": "^3.5.30",
|
||||
"@types/node": "^13.9.0",
|
||||
"@types/node": "^13.9.1",
|
||||
"@types/spotify-web-api-node": "^4.0.1",
|
||||
"@types/validator": "^12.0.1",
|
||||
"@types/ws": "^7.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "^2.22.0",
|
||||
"@typescript-eslint/parser": "^2.22.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.23.0",
|
||||
"@typescript-eslint/parser": "^2.23.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-xo": "^0.29.1",
|
||||
"eslint-config-xo-typescript": "^0.26.0",
|
||||
|
@ -62,14 +63,24 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@discordjs/opus": "^0.1.0",
|
||||
"discord.js": "^12.0.1",
|
||||
"delay": "^4.3.0",
|
||||
"discord.js": "^12.0.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"got": "^10.6.0",
|
||||
"hasha": "^5.2.0",
|
||||
"inversify": "^5.0.1",
|
||||
"iso8601-duration": "^1.2.0",
|
||||
"make-dir": "^3.0.2",
|
||||
"node-emoji": "^1.10.0",
|
||||
"p-limit": "^2.2.2",
|
||||
"prism-media": "^1.2.1",
|
||||
"sequelize": "^5.21.5",
|
||||
"sequelize-typescript": "^1.1.0",
|
||||
"spotify-uri": "^2.0.0",
|
||||
"spotify-web-api-node": "^4.0.0",
|
||||
"sqlite3": "^4.1.1",
|
||||
"ytdl-core": "^2.0.0"
|
||||
"youtube.ts": "^0.1.0",
|
||||
"ytdl-core": "^2.0.0",
|
||||
"ytsr": "^0.1.11"
|
||||
}
|
||||
}
|
||||
|
|
86
src/bot.ts
Normal file
86
src/bot.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import makeDir from 'make-dir';
|
||||
import {Client, Message, Collection} from 'discord.js';
|
||||
import {inject, injectable} from 'inversify';
|
||||
import {TYPES} from './types';
|
||||
import {Settings} from './models';
|
||||
import {sequelize} from './utils/db';
|
||||
import handleGuildCreate from './events/guild-create';
|
||||
import container from './inversify.config';
|
||||
import Command from './commands';
|
||||
|
||||
@injectable()
|
||||
export default class {
|
||||
private readonly client: Client;
|
||||
private readonly token: string;
|
||||
private readonly clientId: string;
|
||||
private readonly dataDir: string;
|
||||
private readonly cacheDir: string;
|
||||
private readonly commands!: Collection<string, Command>;
|
||||
|
||||
constructor(@inject(TYPES.Client) client: Client, @inject(TYPES.Config.DISCORD_TOKEN) token: string, @inject(TYPES.Config.DISCORD_CLIENT_ID) clientId: string, @inject(TYPES.Config.DATA_DIR) dataDir: string, @inject(TYPES.Config.CACHE_DIR) cacheDir: string) {
|
||||
this.client = client;
|
||||
this.token = token;
|
||||
this.clientId = clientId;
|
||||
this.dataDir = dataDir;
|
||||
this.cacheDir = cacheDir;
|
||||
this.commands = new Collection();
|
||||
}
|
||||
|
||||
public async listen(): Promise<string> {
|
||||
// Load in commands
|
||||
container.getAll<Command>(TYPES.Command).forEach(command => {
|
||||
this.commands.set(command.name, command);
|
||||
});
|
||||
|
||||
this.client.on('message', async (msg: Message) => {
|
||||
// Get guild settings
|
||||
if (!msg.guild) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = await Settings.findByPk(msg.guild.id);
|
||||
|
||||
if (!settings) {
|
||||
// Got into a bad state, send owner welcome message
|
||||
return this.client.emit('guildCreate', msg.guild);
|
||||
}
|
||||
|
||||
const {prefix, channel} = settings;
|
||||
|
||||
if (!msg.content.startsWith(prefix) || msg.author.bot || msg.channel.id !== channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const args = msg.content.slice(prefix.length).split(/ +/);
|
||||
const command = args.shift()!.toLowerCase();
|
||||
|
||||
if (!this.commands.has(command)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const handler = this.commands.get(command);
|
||||
|
||||
handler!.execute(msg, args);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
msg.reply('there was an error trying to execute that command!');
|
||||
}
|
||||
});
|
||||
|
||||
this.client.on('ready', async () => {
|
||||
// Create directory if necessary
|
||||
await makeDir(this.dataDir);
|
||||
await makeDir(this.cacheDir);
|
||||
|
||||
await sequelize.sync({});
|
||||
|
||||
console.log(`Ready! Invite the bot with https://discordapp.com/oauth2/authorize?client_id=${this.clientId}&scope=bot`);
|
||||
});
|
||||
|
||||
// Register event handlers
|
||||
this.client.on('guildCreate', handleGuildCreate);
|
||||
|
||||
return this.client.login(this.token);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
import {TextChannel} from 'discord.js';
|
||||
import {CommandHandler} from '../interfaces';
|
||||
import {TextChannel, Message} from 'discord.js';
|
||||
import {injectable} from 'inversify';
|
||||
import {Settings} from '../models';
|
||||
import Command from '.';
|
||||
|
||||
const config: CommandHandler = {
|
||||
name: 'config',
|
||||
description: 'Change various bot settings.',
|
||||
execute: async (msg, args) => {
|
||||
@injectable()
|
||||
export default class implements Command {
|
||||
public name = 'config';
|
||||
public description = 'changes various bot settings';
|
||||
|
||||
public async execute(msg: Message, args: string []): Promise<void> {
|
||||
if (args.length === 0) {
|
||||
// Show current settings
|
||||
const settings = await Settings.findByPk(msg.guild!.id);
|
||||
|
@ -58,6 +61,4 @@ const config: CommandHandler = {
|
|||
await msg.channel.send('🚫 I\'ve never met this setting in my life');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
}
|
||||
|
|
7
src/commands/index.ts
Normal file
7
src/commands/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import {Message} from 'discord.js';
|
||||
|
||||
export default interface Command {
|
||||
name: string;
|
||||
description: string;
|
||||
execute: (msg: Message, args: string[]) => Promise<void>;
|
||||
}
|
|
@ -1,21 +1,205 @@
|
|||
import {CommandHandler} from '../interfaces';
|
||||
import {TextChannel, Message} from 'discord.js';
|
||||
import YouTube from 'youtube.ts';
|
||||
import Spotify from 'spotify-web-api-node';
|
||||
import {URL} from 'url';
|
||||
import ytsr from 'ytsr';
|
||||
import pLimit from 'p-limit';
|
||||
import spotifyURI from 'spotify-uri';
|
||||
import got from 'got';
|
||||
import {parse, toSeconds} from 'iso8601-duration';
|
||||
import {TYPES} from '../types';
|
||||
import {inject, injectable} from 'inversify';
|
||||
import Queue, {QueuedSong, QueuedPlaylist} from '../services/queue';
|
||||
import Player from '../services/player';
|
||||
import {getMostPopularVoiceChannel} from '../utils/channels';
|
||||
import getYouTubeStream from '../utils/get-youtube-stream';
|
||||
import LoadingMessage from '../utils/loading-message';
|
||||
import Command from '.';
|
||||
|
||||
const play: CommandHandler = {
|
||||
name: 'play',
|
||||
description: 'plays a song',
|
||||
execute: async (msg, args) => {
|
||||
const url = args[0];
|
||||
@injectable()
|
||||
export default class implements Command {
|
||||
public name = 'play';
|
||||
public description = 'plays a song';
|
||||
private readonly queue: Queue;
|
||||
private readonly player: Player;
|
||||
private readonly youtube: YouTube;
|
||||
private readonly youtubeKey: string;
|
||||
private readonly spotify: Spotify;
|
||||
|
||||
constructor(@inject(TYPES.Services.Queue) queue: Queue, @inject(TYPES.Services.Player) player: Player, @inject(TYPES.Lib.YouTube) youtube: YouTube, @inject(TYPES.Config.YOUTUBE_API_KEY) youtubeKey: string, @inject(TYPES.Lib.Spotify) spotify: Spotify) {
|
||||
this.queue = queue;
|
||||
this.player = player;
|
||||
this.youtube = youtube;
|
||||
this.youtubeKey = youtubeKey;
|
||||
this.spotify = spotify;
|
||||
}
|
||||
|
||||
public async execute(msg: Message, args: string []): Promise<void> {
|
||||
const newSongs: QueuedSong[] = [];
|
||||
|
||||
const res = new LoadingMessage(msg.channel as TextChannel, 'hold on a sec');
|
||||
await res.start();
|
||||
|
||||
const addSingleSong = async (source: string): Promise<void> => {
|
||||
const videoDetails = await this.youtube.videos.get(source);
|
||||
|
||||
newSongs.push({title: videoDetails.snippet.title, length: toSeconds(parse(videoDetails.contentDetails.duration)), url: videoDetails.id, playlist: null});
|
||||
};
|
||||
|
||||
// Test if it's a complete URL
|
||||
try {
|
||||
const url = new URL(args[0]);
|
||||
|
||||
const YOUTUBE_HOSTS = ['www.youtube.com', 'youtu.be', 'youtube.com'];
|
||||
|
||||
if (YOUTUBE_HOSTS.includes(url.host)) {
|
||||
// YouTube source
|
||||
if (url.searchParams.get('list')) {
|
||||
// YouTube playlist
|
||||
const playlist = await this.youtube.playlists.get(url.searchParams.get('list') as string);
|
||||
const {items} = await this.youtube.playlists.items(url.searchParams.get('list') as string, {maxResults: '50'});
|
||||
|
||||
// Unfortunately, package doesn't provide a method for this
|
||||
const res: any = await got('https://www.googleapis.com/youtube/v3/videos', {searchParams: {
|
||||
part: 'contentDetails',
|
||||
id: items.map(item => item.contentDetails.videoId).join(','),
|
||||
key: this.youtubeKey
|
||||
}}).json();
|
||||
|
||||
const queuedPlaylist = {title: playlist.snippet.title, source: playlist.id};
|
||||
|
||||
items.forEach(video => {
|
||||
const length = toSeconds(parse(res.items.find((i: any) => i.id === video.contentDetails.videoId).contentDetails.duration));
|
||||
|
||||
newSongs.push({title: video.snippet.title, length, url: video.contentDetails.videoId, playlist: queuedPlaylist});
|
||||
});
|
||||
} else {
|
||||
// Single video
|
||||
try {
|
||||
await addSingleSong(url.href);
|
||||
} catch (error) {
|
||||
await res.stop('that doesn\'t exist');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (url.protocol === 'spotify:' || url.host === 'open.spotify.com') {
|
||||
// Spotify source
|
||||
const parsed = spotifyURI.parse(args[0]);
|
||||
|
||||
const tracks: SpotifyApi.TrackObjectSimplified[] = [];
|
||||
|
||||
let playlist: QueuedPlaylist | null = null;
|
||||
|
||||
switch (parsed.type) {
|
||||
case 'album': {
|
||||
const uri = parsed as spotifyURI.Album;
|
||||
|
||||
const [{body: album}, {body: {items}}] = await Promise.all([this.spotify.getAlbum(uri.id), this.spotify.getAlbumTracks(uri.id, {limit: 50})]);
|
||||
|
||||
tracks.push(...items);
|
||||
|
||||
playlist = {title: album.name, source: album.href};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'playlist': {
|
||||
const uri = parsed as spotifyURI.Playlist;
|
||||
|
||||
let [{body: playlistResponse}, {body: tracksResponse}] = await Promise.all([this.spotify.getPlaylist(uri.id), this.spotify.getPlaylistTracks(uri.id, {limit: 1})]);
|
||||
|
||||
playlist = {title: playlistResponse.name, source: playlistResponse.href};
|
||||
|
||||
tracks.push(...tracksResponse.items.map(playlistItem => playlistItem.track));
|
||||
|
||||
while (tracksResponse.next) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
({body: tracksResponse} = await this.spotify.getPlaylistTracks(uri.id, {
|
||||
limit: parseInt(new URL(tracksResponse.next).searchParams.get('limit') ?? '1', 10),
|
||||
offset: parseInt(new URL(tracksResponse.next).searchParams.get('offset') ?? '0', 10)
|
||||
}));
|
||||
|
||||
tracks.push(...tracksResponse.items.map(playlistItem => playlistItem.track));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'track': {
|
||||
const uri = parsed as spotifyURI.Track;
|
||||
|
||||
const {body} = await this.spotify.getTrack(uri.id);
|
||||
|
||||
tracks.push(body);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'artist': {
|
||||
await res.stop('ope, can\'t add a whole artist');
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
await res.stop('huh?');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Search YouTube for each track
|
||||
const searchForTrack = async (track: any): Promise<QueuedSong|null> => {
|
||||
try {
|
||||
const {items: [video]} = await ytsr(`${track.name as string} ${track.artists[0].name as string} offical`, {limit: 1});
|
||||
|
||||
return {title: video.title, length: track.duration_ms / 1000, url: video.link, playlist};
|
||||
} catch (_) {
|
||||
// TODO: handle error
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Limit concurrency so hopefully we don't get banned
|
||||
const limit = pLimit(3);
|
||||
let songs = await Promise.all(tracks.map(async track => limit(async () => searchForTrack(track))));
|
||||
|
||||
// Get rid of null values
|
||||
songs = songs.reduce((accum: QueuedSong[], song) => {
|
||||
if (song) {
|
||||
accum.push(song);
|
||||
}
|
||||
|
||||
return accum;
|
||||
}, []);
|
||||
|
||||
newSongs.push(...(songs as QueuedSong[]));
|
||||
}
|
||||
} catch (_) {
|
||||
// Not a URL, must search YouTube
|
||||
const query = args.join(' ');
|
||||
|
||||
try {
|
||||
const {items: [video]} = await this.youtube.videos.search({q: query, maxResults: 1, type: 'video'});
|
||||
|
||||
await addSingleSong(video.id.videoId);
|
||||
} catch (_) {
|
||||
await res.stop('that doesn\'t exist');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (newSongs.length === 0) {
|
||||
// TODO: better response
|
||||
await res.stop('huh?');
|
||||
return;
|
||||
}
|
||||
|
||||
newSongs.forEach(song => this.queue.add(msg.guild!.id, song));
|
||||
|
||||
// TODO: better response
|
||||
await res.stop('song(s) queued');
|
||||
|
||||
const channel = getMostPopularVoiceChannel(msg.guild!);
|
||||
|
||||
const conn = await channel.join();
|
||||
// TODO: don't connect if already connected.
|
||||
await this.player.connect(msg.guild!.id, channel);
|
||||
|
||||
const stream = await getYouTubeStream(url);
|
||||
|
||||
conn.play(stream, {type: 'webm/opus'});
|
||||
await this.player.play(msg.guild!.id);
|
||||
}
|
||||
};
|
||||
|
||||
export default play;
|
||||
}
|
||||
|
|
22
src/commands/queue.ts
Normal file
22
src/commands/queue.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import {Message} from 'discord.js';
|
||||
import {TYPES} from '../types';
|
||||
import {inject, injectable} from 'inversify';
|
||||
import Queue from '../services/queue';
|
||||
import Command from '.';
|
||||
|
||||
@injectable()
|
||||
export default class implements Command {
|
||||
public name = 'queue';
|
||||
public description = 'shows current queue';
|
||||
private readonly queue: Queue;
|
||||
|
||||
constructor(@inject(TYPES.Services.Queue) queue: Queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public async execute(msg: Message, _: string []): Promise<void> {
|
||||
const queue = this.queue.get(msg.guild!.id);
|
||||
|
||||
await msg.channel.send('`' + JSON.stringify(queue.slice(0, 10)) + '`');
|
||||
}
|
||||
}
|
75
src/index.ts
75
src/index.ts
|
@ -1,68 +1,15 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import makeDir from 'make-dir';
|
||||
import Discord from 'discord.js';
|
||||
import {DISCORD_TOKEN, DISCORD_CLIENT_ID, DATA_DIR, CACHE_DIR} from './utils/config';
|
||||
import {Settings} from './models';
|
||||
import {sequelize} from './utils/db';
|
||||
import {CommandHandler} from './interfaces';
|
||||
import handleGuildCreate from './events/guild-create';
|
||||
import container from './inversify.config';
|
||||
import Spotify from 'spotify-web-api-node';
|
||||
import {TYPES} from './types';
|
||||
import Bot from './bot';
|
||||
|
||||
const client = new Discord.Client();
|
||||
const commands = new Discord.Collection();
|
||||
let bot = container.get<Bot>(TYPES.Bot);
|
||||
const spotify = container.get<Spotify>(TYPES.Lib.Spotify);
|
||||
|
||||
// Load in commands
|
||||
const commandFiles = fs.readdirSync(path.join(__dirname, 'commands')).filter(file => file.endsWith('.js'));
|
||||
(async () => {
|
||||
const auth = await spotify.clientCredentialsGrant();
|
||||
|
||||
for (const file of commandFiles) {
|
||||
const command = require(`./commands/${file}`).default;
|
||||
spotify.setAccessToken(auth.body.access_token);
|
||||
|
||||
commands.set(command.name, command);
|
||||
}
|
||||
|
||||
// Generic message handler
|
||||
client.on('message', async (msg: Discord.Message) => {
|
||||
// Get guild settings
|
||||
const settings = await Settings.findByPk(msg.guild!.id);
|
||||
|
||||
if (!settings) {
|
||||
// Got into a bad state, send owner welcome message
|
||||
return client.emit('guildCreate', msg.guild);
|
||||
}
|
||||
|
||||
const {prefix, channel} = settings;
|
||||
|
||||
if (!msg.content.startsWith(prefix) || msg.author.bot || msg.channel.id !== channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const args = msg.content.slice(prefix.length).split(/ +/);
|
||||
const command = args.shift()!.toLowerCase();
|
||||
|
||||
if (!commands.has(command)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const handler = commands.get(command) as CommandHandler;
|
||||
|
||||
handler.execute(msg, args);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
msg.reply('there was an error trying to execute that command!');
|
||||
}
|
||||
});
|
||||
|
||||
client.on('ready', async () => {
|
||||
// Create directory if necessary
|
||||
await makeDir(DATA_DIR);
|
||||
await makeDir(CACHE_DIR);
|
||||
|
||||
await sequelize.sync({});
|
||||
|
||||
console.log(`Ready! Invite the bot with https://discordapp.com/oauth2/authorize?client_id=${DISCORD_CLIENT_ID}&scope=bot`);
|
||||
});
|
||||
|
||||
client.on('guildCreate', handleGuildCreate);
|
||||
|
||||
client.login(DISCORD_TOKEN);
|
||||
bot.listen();
|
||||
})();
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import {Message} from 'discord.js';
|
||||
|
||||
export interface CommandHandler {
|
||||
name: string;
|
||||
description: string;
|
||||
execute: (msg: Message, args: string[]) => void;
|
||||
}
|
54
src/inversify.config.ts
Normal file
54
src/inversify.config.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import 'reflect-metadata';
|
||||
import {Container} from 'inversify';
|
||||
import {TYPES} from './types';
|
||||
import Bot from './bot';
|
||||
import {Client} from 'discord.js';
|
||||
import YouTube from 'youtube.ts';
|
||||
import Spotify from 'spotify-web-api-node';
|
||||
import {
|
||||
DISCORD_TOKEN,
|
||||
DISCORD_CLIENT_ID,
|
||||
YOUTUBE_API_KEY,
|
||||
SPOTIFY_CLIENT_ID,
|
||||
SPOTIFY_CLIENT_SECRET,
|
||||
DATA_DIR,
|
||||
CACHE_DIR
|
||||
} from './utils/config';
|
||||
|
||||
// Services
|
||||
import Queue from './services/queue';
|
||||
import Player from './services/player';
|
||||
|
||||
// Comands
|
||||
import Command from './commands';
|
||||
import Config from './commands/config';
|
||||
import Play from './commands/play';
|
||||
import QueueCommad from './commands/queue';
|
||||
|
||||
let container = new Container();
|
||||
|
||||
// Bot
|
||||
container.bind<Bot>(TYPES.Bot).to(Bot).inSingletonScope();
|
||||
container.bind<Client>(TYPES.Client).toConstantValue(new Client());
|
||||
|
||||
// Services
|
||||
container.bind<Player>(TYPES.Services.Player).to(Player).inSingletonScope();
|
||||
container.bind<Queue>(TYPES.Services.Queue).to(Queue).inSingletonScope();
|
||||
|
||||
// Commands
|
||||
container.bind<Command>(TYPES.Command).to(Config).inSingletonScope();
|
||||
container.bind<Command>(TYPES.Command).to(Play).inSingletonScope();
|
||||
container.bind<Command>(TYPES.Command).to(QueueCommad).inSingletonScope();
|
||||
|
||||
// Config values
|
||||
container.bind<string>(TYPES.Config.DISCORD_TOKEN).toConstantValue(DISCORD_TOKEN);
|
||||
container.bind<string>(TYPES.Config.DISCORD_CLIENT_ID).toConstantValue(DISCORD_CLIENT_ID);
|
||||
container.bind<string>(TYPES.Config.YOUTUBE_API_KEY).toConstantValue(YOUTUBE_API_KEY);
|
||||
container.bind<string>(TYPES.Config.DATA_DIR).toConstantValue(DATA_DIR);
|
||||
container.bind<string>(TYPES.Config.CACHE_DIR).toConstantValue(CACHE_DIR);
|
||||
|
||||
// Static libraries
|
||||
container.bind<YouTube>(TYPES.Lib.YouTube).toConstantValue(new YouTube(YOUTUBE_API_KEY));
|
||||
container.bind<Spotify>(TYPES.Lib.Spotify).toConstantValue(new Spotify({clientId: SPOTIFY_CLIENT_ID, clientSecret: SPOTIFY_CLIENT_SECRET}));
|
||||
|
||||
export default container;
|
1
src/packages.d.ts
vendored
1
src/packages.d.ts
vendored
|
@ -1 +1,2 @@
|
|||
declare module 'node-emoji';
|
||||
declare module 'ytsr';
|
||||
|
|
88
src/services/player.ts
Normal file
88
src/services/player.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import {inject, injectable} from 'inversify';
|
||||
import {VoiceConnection, VoiceChannel} from 'discord.js';
|
||||
import {TYPES} from '../types';
|
||||
import Queue from './queue';
|
||||
import getYouTubeStream from '../utils/get-youtube-stream';
|
||||
|
||||
export enum Status {
|
||||
Playing,
|
||||
Paused,
|
||||
Disconnected
|
||||
}
|
||||
|
||||
export interface GuildPlayer {
|
||||
status: Status;
|
||||
voiceConnection: VoiceConnection | null;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export default class {
|
||||
private readonly guildPlayers = new Map<string, GuildPlayer>();
|
||||
private readonly queue: Queue;
|
||||
|
||||
constructor(@inject(TYPES.Services.Queue) queue: Queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
async connect(guildId: string, channel: VoiceChannel): Promise<void> {
|
||||
this.initGuild(guildId);
|
||||
|
||||
const guildPlayer = this.guildPlayers.get(guildId);
|
||||
|
||||
const conn = await channel.join();
|
||||
|
||||
guildPlayer!.voiceConnection = conn;
|
||||
|
||||
this.guildPlayers.set(guildId, guildPlayer!);
|
||||
}
|
||||
|
||||
disconnect(guildId: string): void {
|
||||
this.initGuild(guildId);
|
||||
|
||||
const guildPlayer = this.guildPlayers.get(guildId);
|
||||
|
||||
if (guildPlayer?.voiceConnection) {
|
||||
guildPlayer.voiceConnection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
async play(guildId: string): Promise<void> {
|
||||
const guildPlayer = this.get(guildId);
|
||||
if (guildPlayer.voiceConnection === null) {
|
||||
throw new Error('Not connected to a voice channel.');
|
||||
}
|
||||
|
||||
if (guildPlayer.status === Status.Playing) {
|
||||
// Already playing, return
|
||||
return;
|
||||
}
|
||||
|
||||
const songs = this.queue.get(guildId);
|
||||
|
||||
if (songs.length === 0) {
|
||||
throw new Error('Queue empty.');
|
||||
}
|
||||
|
||||
const song = songs[0];
|
||||
|
||||
const stream = await getYouTubeStream(song.url);
|
||||
|
||||
this.get(guildId).voiceConnection!.play(stream, {type: 'webm/opus'});
|
||||
|
||||
guildPlayer.status = Status.Playing;
|
||||
|
||||
this.guildPlayers.set(guildId, guildPlayer);
|
||||
}
|
||||
|
||||
get(guildId: string): GuildPlayer {
|
||||
this.initGuild(guildId);
|
||||
|
||||
return this.guildPlayers.get(guildId) as GuildPlayer;
|
||||
}
|
||||
|
||||
private initGuild(guildId: string): void {
|
||||
if (!this.guildPlayers.get(guildId)) {
|
||||
this.guildPlayers.set(guildId, {status: Status.Disconnected, voiceConnection: null});
|
||||
}
|
||||
}
|
||||
}
|
89
src/services/queue.ts
Normal file
89
src/services/queue.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
import {injectable} from 'inversify';
|
||||
|
||||
export interface QueuedPlaylist {
|
||||
title: string;
|
||||
source: string;
|
||||
}
|
||||
|
||||
export interface QueuedSong {
|
||||
title: string;
|
||||
url: string;
|
||||
length: number;
|
||||
playlist: QueuedPlaylist | null;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export default class {
|
||||
private readonly guildQueues = new Map<string, QueuedSong[]>();
|
||||
private readonly queuePositions = new Map<string, number>();
|
||||
|
||||
forward(guildId: string): void {
|
||||
const currentPosition = this.queuePositions.get(guildId);
|
||||
|
||||
if (currentPosition && currentPosition + 1 <= this.size(guildId)) {
|
||||
this.queuePositions.set(guildId, currentPosition + 1);
|
||||
} else {
|
||||
throw new Error('No songs in queue to forward to.');
|
||||
}
|
||||
}
|
||||
|
||||
back(guildId: string): void {
|
||||
const currentPosition = this.queuePositions.get(guildId);
|
||||
|
||||
if (currentPosition && currentPosition - 1 >= 0) {
|
||||
this.queuePositions.set(guildId, currentPosition - 1);
|
||||
} else {
|
||||
throw new Error('No songs in queue to go back to.');
|
||||
}
|
||||
}
|
||||
|
||||
get(guildId: string): QueuedSong[] {
|
||||
const currentPosition = this.queuePositions.get(guildId);
|
||||
|
||||
if (currentPosition === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const guildQueue = this.guildQueues.get(guildId);
|
||||
|
||||
if (!guildQueue) {
|
||||
throw new Error('Bad state. Queue for guild exists but position does not.');
|
||||
}
|
||||
|
||||
return guildQueue.slice(currentPosition);
|
||||
}
|
||||
|
||||
add(guildId: string, song: QueuedSong): void {
|
||||
if (!this.guildQueues.get(guildId)) {
|
||||
this.guildQueues.set(guildId, []);
|
||||
this.queuePositions.set(guildId, 0);
|
||||
}
|
||||
|
||||
if (song.playlist) {
|
||||
// Add to end of queue
|
||||
this.guildQueues.set(guildId, [...this.guildQueues.get(guildId)!, song]);
|
||||
} else if (this.guildQueues.get(guildId)!.length === 0) {
|
||||
// Queue is currently empty
|
||||
this.guildQueues.set(guildId, [song]);
|
||||
} else {
|
||||
// Not from playlist, add immediately
|
||||
let insertAt = 0;
|
||||
|
||||
// Loop until playlist song
|
||||
this.guildQueues.get(guildId)!.some(song => {
|
||||
if (song.playlist) {
|
||||
return true;
|
||||
}
|
||||
|
||||
insertAt++;
|
||||
return false;
|
||||
});
|
||||
|
||||
this.guildQueues.set(guildId, [...this.guildQueues.get(guildId)!.slice(0, insertAt), song, ...this.guildQueues.get(guildId)!.slice(insertAt)]);
|
||||
}
|
||||
}
|
||||
|
||||
size(guildId: string): number {
|
||||
return this.get(guildId).length;
|
||||
}
|
||||
}
|
20
src/types.ts
Normal file
20
src/types.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
export const TYPES = {
|
||||
Bot: Symbol('Bot'),
|
||||
Client: Symbol('Client'),
|
||||
Config: {
|
||||
DISCORD_TOKEN: Symbol('DISCORD_TOKEN'),
|
||||
DISCORD_CLIENT_ID: Symbol('DISCORD_CLIENT_ID'),
|
||||
YOUTUBE_API_KEY: Symbol('YOUTUBE_API_KEY'),
|
||||
DATA_DIR: Symbol('DATA_DIR'),
|
||||
CACHE_DIR: Symbol('CACHE_DIR')
|
||||
},
|
||||
Command: Symbol('Command'),
|
||||
Services: {
|
||||
Player: Symbol('Player'),
|
||||
Queue: Symbol('Queue')
|
||||
},
|
||||
Lib: {
|
||||
YouTube: Symbol('YouTube'),
|
||||
Spotify: Symbol('Spotify')
|
||||
}
|
||||
};
|
|
@ -4,5 +4,8 @@ dotenv.config();
|
|||
|
||||
export const DISCORD_TOKEN: string = process.env.DISCORD_TOKEN ? process.env.DISCORD_TOKEN : '';
|
||||
export const DISCORD_CLIENT_ID: string = process.env.DISCORD_CLIENT_ID ? process.env.DISCORD_CLIENT_ID : '';
|
||||
export const YOUTUBE_API_KEY: string = process.env.YOUTUBE_API_KEY ? process.env.YOUTUBE_API_KEY : '';
|
||||
export const SPOTIFY_CLIENT_ID: string = process.env.SPOTIFY_CLIENT_ID ? process.env.SPOTIFY_CLIENT_ID : '';
|
||||
export const SPOTIFY_CLIENT_SECRET: string = process.env.SPOTIFY_CLIENT_SECRET ? process.env.SPOTIFY_CLIENT_SECRET : '';
|
||||
export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data');
|
||||
export const CACHE_DIR = path.join(DATA_DIR, 'cache');
|
||||
|
|
|
@ -3,6 +3,7 @@ import {Readable, PassThrough} from 'stream';
|
|||
import path from 'path';
|
||||
import hasha from 'hasha';
|
||||
import ytdl from 'ytdl-core';
|
||||
import prism from 'prism-media';
|
||||
import {CACHE_DIR} from './config';
|
||||
|
||||
const nextBestFormat = (formats: ytdl.videoFormat[]): ytdl.videoFormat => {
|
||||
|
@ -24,9 +25,11 @@ export default async (url: string): Promise<Readable> => {
|
|||
const filter = (format: ytdl.videoFormat): boolean => format.codecs === 'opus' && format.container === 'webm' && format.audioSampleRate !== undefined && parseInt(format.audioSampleRate, 10) === 48000;
|
||||
|
||||
let format = formats.find(filter);
|
||||
let canDirectPlay = true;
|
||||
|
||||
if (!format) {
|
||||
format = nextBestFormat(info.formats);
|
||||
canDirectPlay = false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -46,6 +49,30 @@ export default async (url: string): Promise<Readable> => {
|
|||
await fs.rename(cacheTempPath, cachedPath);
|
||||
});
|
||||
|
||||
return ytdl.downloadFromInfo(info, {format}).pipe(pass);
|
||||
if (canDirectPlay) {
|
||||
return ytdl.downloadFromInfo(info, {format}).pipe(pass);
|
||||
}
|
||||
|
||||
const transcoder = new prism.FFmpeg({
|
||||
args: [
|
||||
'-reconnect',
|
||||
'1',
|
||||
'-reconnect_streamed',
|
||||
'1',
|
||||
'-reconnect_delay_max',
|
||||
'5',
|
||||
'-i',
|
||||
format.url,
|
||||
'-loglevel',
|
||||
'verbose',
|
||||
'-vn',
|
||||
'-acodec',
|
||||
'libopus',
|
||||
'-f',
|
||||
'webm'
|
||||
]
|
||||
});
|
||||
|
||||
return transcoder.pipe(pass);
|
||||
}
|
||||
};
|
||||
|
|
67
src/utils/loading-message.ts
Normal file
67
src/utils/loading-message.ts
Normal file
|
@ -0,0 +1,67 @@
|
|||
import {TextChannel, Message} from 'discord.js';
|
||||
import delay from 'delay';
|
||||
|
||||
export default class {
|
||||
private readonly channel: TextChannel;
|
||||
private readonly text: string;
|
||||
private msg!: Message;
|
||||
private isStopped: boolean = false;
|
||||
|
||||
constructor(channel: TextChannel, text: string) {
|
||||
this.channel = channel;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
this.msg = await this.channel.send(this.text);
|
||||
|
||||
const period = 500;
|
||||
|
||||
const icons = ['⚪', '🔵', '⚫'];
|
||||
|
||||
const reactions = [];
|
||||
|
||||
let i = 0;
|
||||
let isRemoving = false;
|
||||
(async () => {
|
||||
while (!this.isStopped) {
|
||||
if (reactions.length === icons.length) {
|
||||
isRemoving = true;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await delay(period);
|
||||
|
||||
if (isRemoving) {
|
||||
const reactionToRemove = reactions.shift();
|
||||
|
||||
if (reactionToRemove) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await reactionToRemove.remove();
|
||||
} else {
|
||||
isRemoving = false;
|
||||
}
|
||||
} else {
|
||||
if (!this.isStopped) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
reactions.push(await this.msg.react(icons[i % icons.length]));
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
async stop(str?: string): Promise<Message> {
|
||||
this.isStopped = true;
|
||||
|
||||
if (str) {
|
||||
await Promise.all([this.msg.reactions.removeAll(), this.msg.edit(str)]);
|
||||
} else {
|
||||
await this.msg.reactions.removeAll();
|
||||
}
|
||||
|
||||
return this.msg;
|
||||
}
|
||||
}
|
412
yarn.lock
412
yarn.lock
|
@ -38,11 +38,33 @@
|
|||
node-addon-api "^2.0.0"
|
||||
node-pre-gyp "^0.14.0"
|
||||
|
||||
"@sindresorhus/is@^2.0.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-2.1.0.tgz#6ad4ca610f696098e92954ab431ff83bea0ce13f"
|
||||
integrity sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==
|
||||
|
||||
"@szmarczak/http-timer@^4.0.0":
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152"
|
||||
integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==
|
||||
dependencies:
|
||||
defer-to-connect "^2.0.0"
|
||||
|
||||
"@types/bluebird@^3.5.30":
|
||||
version "3.5.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.30.tgz#ee034a0eeea8b84ed868b1aa60d690b08a6cfbc5"
|
||||
integrity sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw==
|
||||
|
||||
"@types/cacheable-request@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
|
||||
integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
|
||||
dependencies:
|
||||
"@types/http-cache-semantics" "*"
|
||||
"@types/keyv" "*"
|
||||
"@types/node" "*"
|
||||
"@types/responselike" "*"
|
||||
|
||||
"@types/color-name@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
||||
|
@ -53,21 +75,57 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||
integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
|
||||
|
||||
"@types/http-cache-semantics@*":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
|
||||
integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
|
||||
|
||||
"@types/json-schema@^7.0.3":
|
||||
version "7.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
|
||||
integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
|
||||
|
||||
"@types/node@*", "@types/node@^13.9.0":
|
||||
"@types/keyv@*":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
|
||||
integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@^13.5.3":
|
||||
version "13.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"
|
||||
integrity sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ==
|
||||
|
||||
"@types/node@^13.9.1":
|
||||
version "13.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.1.tgz#96f606f8cd67fb018847d9b61e93997dabdefc72"
|
||||
integrity sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||
|
||||
"@types/responselike@*":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
|
||||
integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/spotify-api@*":
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/spotify-api/-/spotify-api-0.0.2.tgz#83bccd04fbc00de01d515418d77d658f277ef6f5"
|
||||
integrity sha512-6WlUsg2xaSyxHZShTy+KNe4Hm8foDtaEVLe6+ID5DGOoByhcSKioCV2kPN6E8swgf2IHn+1o9knlbryYmoL0fw==
|
||||
|
||||
"@types/spotify-web-api-node@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/spotify-web-api-node/-/spotify-web-api-node-4.0.1.tgz#0a2b85a1d40ae312de37deeb3c7e85bf7f4e6812"
|
||||
integrity sha512-uxoz7DcSj/v2URDo54FjzctIfdQdEFvmUreHrR26G/Vf0Qm5S0lbt7LdKJeW2EoWUzzfjetYV3TcfMxRm1bWIw==
|
||||
dependencies:
|
||||
"@types/spotify-api" "*"
|
||||
|
||||
"@types/validator@^12.0.1":
|
||||
version "12.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/validator/-/validator-12.0.1.tgz#73dbc7f5f730ff7131754bca682824eb3c260b79"
|
||||
|
@ -80,40 +138,40 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^2.22.0":
|
||||
version "2.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.22.0.tgz#218ce6d4aa0244c6a40baba39ca1e021b26bb017"
|
||||
integrity sha512-BvxRLaTDVQ3N+Qq8BivLiE9akQLAOUfxNHIEhedOcg8B2+jY8Rc4/D+iVprvuMX1AdezFYautuGDwr9QxqSxBQ==
|
||||
"@typescript-eslint/eslint-plugin@^2.23.0":
|
||||
version "2.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.23.0.tgz#aa7133bfb7b685379d9eafe4ae9e08b9037e129d"
|
||||
integrity sha512-8iA4FvRsz8qTjR0L/nK9RcRUN3QtIHQiOm69FzV7WS3SE+7P7DyGGwh3k4UNR2JBbk+Ej2Io+jLAaqKibNhmtw==
|
||||
dependencies:
|
||||
"@typescript-eslint/experimental-utils" "2.22.0"
|
||||
"@typescript-eslint/experimental-utils" "2.23.0"
|
||||
eslint-utils "^1.4.3"
|
||||
functional-red-black-tree "^1.0.1"
|
||||
regexpp "^3.0.0"
|
||||
tsutils "^3.17.1"
|
||||
|
||||
"@typescript-eslint/experimental-utils@2.22.0":
|
||||
version "2.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.22.0.tgz#4d00c91fbaaa68e56e7869be284999a265707f85"
|
||||
integrity sha512-sJt1GYBe6yC0dWOQzXlp+tiuGglNhJC9eXZeC8GBVH98Zv9jtatccuhz0OF5kC/DwChqsNfghHx7OlIDQjNYAQ==
|
||||
"@typescript-eslint/experimental-utils@2.23.0":
|
||||
version "2.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.23.0.tgz#5d2261c8038ec1698ca4435a8da479c661dc9242"
|
||||
integrity sha512-OswxY59RcXH3NNPmq+4Kis2CYZPurRU6mG5xPcn24CjFyfdVli5mySwZz/g/xDbJXgDsYqNGq7enV0IziWGXVQ==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.3"
|
||||
"@typescript-eslint/typescript-estree" "2.22.0"
|
||||
"@typescript-eslint/typescript-estree" "2.23.0"
|
||||
eslint-scope "^5.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^2.22.0":
|
||||
version "2.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.22.0.tgz#8eeb6cb6de873f655e64153397d4790898e149d0"
|
||||
integrity sha512-FaZKC1X+nvD7qMPqKFUYHz3H0TAioSVFGvG29f796Nc5tBluoqfHgLbSFKsh7mKjRoeTm8J9WX2Wo9EyZWjG7w==
|
||||
"@typescript-eslint/parser@^2.23.0":
|
||||
version "2.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.23.0.tgz#f3d4e2928ff647fe77fc2fcef1a3534fee6a3212"
|
||||
integrity sha512-k61pn/Nepk43qa1oLMiyqApC6x5eP5ddPz6VUYXCAuXxbmRLqkPYzkFRKl42ltxzB2luvejlVncrEpflgQoSUg==
|
||||
dependencies:
|
||||
"@types/eslint-visitor-keys" "^1.0.0"
|
||||
"@typescript-eslint/experimental-utils" "2.22.0"
|
||||
"@typescript-eslint/typescript-estree" "2.22.0"
|
||||
"@typescript-eslint/experimental-utils" "2.23.0"
|
||||
"@typescript-eslint/typescript-estree" "2.23.0"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
"@typescript-eslint/typescript-estree@2.22.0":
|
||||
version "2.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.22.0.tgz#a16ed45876abf743e1f5857e2f4a1c3199fd219e"
|
||||
integrity sha512-2HFZW2FQc4MhIBB8WhDm9lVFaBDy6h9jGrJ4V2Uzxe/ON29HCHBTj3GkgcsgMWfsl2U5as+pTOr30Nibaw7qRQ==
|
||||
"@typescript-eslint/typescript-estree@2.23.0":
|
||||
version "2.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.23.0.tgz#d355960fab96bd550855488dcc34b9a4acac8d36"
|
||||
integrity sha512-pmf7IlmvXdlEXvE/JWNNJpEvwBV59wtJqA8MLAxMKLXNKVRC3HZBXR/SlZLPWTCcwOSg9IM7GeRSV3SIerGVqw==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
@ -274,6 +332,13 @@ aws4@^1.8.0:
|
|||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
|
||||
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
|
||||
|
||||
axios@^0.19.0:
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
|
@ -329,6 +394,26 @@ buffer-from@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||
|
||||
cacheable-lookup@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-2.0.0.tgz#33b1e56f17507f5cf9bb46075112d65473fb7713"
|
||||
integrity sha512-s2piO6LvA7xnL1AR03wuEdSx3BZT3tIJpZ56/lcJwzO/6DTJZlTs7X3lrvPxk6d1PlDe6PrVe2TjlUIZNFglAQ==
|
||||
dependencies:
|
||||
keyv "^4.0.0"
|
||||
|
||||
cacheable-request@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58"
|
||||
integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==
|
||||
dependencies:
|
||||
clone-response "^1.0.2"
|
||||
get-stream "^5.1.0"
|
||||
http-cache-semantics "^4.0.0"
|
||||
keyv "^4.0.0"
|
||||
lowercase-keys "^2.0.0"
|
||||
normalize-url "^4.1.0"
|
||||
responselike "^2.0.0"
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
|
@ -418,6 +503,13 @@ cli-width@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
|
||||
integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
|
||||
|
||||
clone-response@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
|
||||
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
|
||||
dependencies:
|
||||
mimic-response "^1.0.0"
|
||||
|
||||
cls-bluebird@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cls-bluebird/-/cls-bluebird-2.1.0.tgz#37ef1e080a8ffb55c2f4164f536f1919e7968aee"
|
||||
|
@ -467,6 +559,11 @@ compare-versions@^3.5.1:
|
|||
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62"
|
||||
integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==
|
||||
|
||||
component-emitter@^1.2.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
|
@ -494,6 +591,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
|
||||
|
||||
cookiejar@^2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c"
|
||||
integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
@ -549,6 +651,13 @@ dashdash@^1.12.0:
|
|||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^2.2.0:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
|
@ -556,7 +665,7 @@ debug@^2.2.0:
|
|||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.2.6:
|
||||
debug@^3.1.0, debug@^3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
|
@ -570,6 +679,13 @@ debug@^4.0.1, debug@^4.1.1:
|
|||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decompress-response@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-5.0.0.tgz#7849396e80e3d1eba8cb2f75ef4930f76461cb0f"
|
||||
integrity sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==
|
||||
dependencies:
|
||||
mimic-response "^2.0.0"
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
|
@ -580,6 +696,16 @@ deep-is@~0.1.3:
|
|||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||
|
||||
defer-to-connect@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1"
|
||||
integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==
|
||||
|
||||
delay@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/delay/-/delay-4.3.0.tgz#efeebfb8f545579cb396b3a722443ec96d14c50e"
|
||||
integrity sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
|
@ -600,10 +726,10 @@ diff@^4.0.1:
|
|||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||
|
||||
discord.js@^12.0.1:
|
||||
version "12.0.1"
|
||||
resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-12.0.1.tgz#58574c0c9acc598095f943d6b14da4725d37b8b9"
|
||||
integrity sha512-lUlrkAWSb5YTB1WpSZHjeUXxGlHK8VDjrlHLEP4lJj+etFAellURpmRYl29OPJ/7arQWB879pP4rvhhzpdOF7w==
|
||||
discord.js@^12.0.2:
|
||||
version "12.0.2"
|
||||
resolved "https://registry.yarnpkg.com/discord.js/-/discord.js-12.0.2.tgz#c4d68f1363d7fc05ed71a42dba6b930966ed8602"
|
||||
integrity sha512-iZiEA4Y61gqq/EjFfLXnkRK9pLapnax/vTVDUhs/mAhyqozAy0GOlk/MZI9rSa1iIoKTWRq6P9CRKhLNT2wUnA==
|
||||
dependencies:
|
||||
"@discordjs/collection" "^0.1.5"
|
||||
abort-controller "^3.0.0"
|
||||
|
@ -661,6 +787,13 @@ emoji-regex@^8.0.0:
|
|||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||
|
||||
end-of-stream@^1.1.0:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
|
||||
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
|
||||
dependencies:
|
||||
once "^1.4.0"
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
|
@ -804,7 +937,7 @@ execa@^0.7.0:
|
|||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
extend@~3.0.2:
|
||||
extend@^3.0.0, extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
@ -893,11 +1026,27 @@ flatted@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
|
||||
integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
|
||||
|
||||
follow-redirects@1.5.10:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@^2.3.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4"
|
||||
integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
|
||||
|
@ -916,6 +1065,11 @@ form-data@~2.3.2:
|
|||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@^1.2.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9"
|
||||
integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==
|
||||
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
|
||||
|
@ -957,6 +1111,13 @@ get-stream@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||
|
||||
get-stream@^5.0.0, get-stream@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
|
||||
integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
|
||||
dependencies:
|
||||
pump "^3.0.0"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
|
@ -1009,6 +1170,27 @@ globals@^12.1.0:
|
|||
dependencies:
|
||||
type-fest "^0.8.1"
|
||||
|
||||
got@^10.6.0:
|
||||
version "10.6.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-10.6.0.tgz#ac3876261a4d8e5fc4f81186f79955ce7b0501dc"
|
||||
integrity sha512-3LIdJNTdCFbbJc+h/EH0V5lpNpbJ6Bfwykk21lcQvQsEcrzdi/ltCyQehFHLzJ/ka0UMH4Slg0hkYvAZN9qUDg==
|
||||
dependencies:
|
||||
"@sindresorhus/is" "^2.0.0"
|
||||
"@szmarczak/http-timer" "^4.0.0"
|
||||
"@types/cacheable-request" "^6.0.1"
|
||||
cacheable-lookup "^2.0.0"
|
||||
cacheable-request "^7.0.1"
|
||||
decompress-response "^5.0.0"
|
||||
duplexer3 "^0.1.4"
|
||||
get-stream "^5.0.0"
|
||||
lowercase-keys "^2.0.0"
|
||||
mimic-response "^2.1.0"
|
||||
p-cancelable "^2.0.0"
|
||||
p-event "^4.0.0"
|
||||
responselike "^2.0.0"
|
||||
to-readable-stream "^2.0.0"
|
||||
type-fest "^0.10.0"
|
||||
|
||||
got@^6.7.1:
|
||||
version "6.7.1"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
|
||||
|
@ -1072,6 +1254,11 @@ html-entities@^1.1.3:
|
|||
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
|
||||
integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
|
||||
|
||||
http-cache-semantics@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
|
||||
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
|
@ -1181,6 +1368,11 @@ inquirer@^7.0.0:
|
|||
strip-ansi "^6.0.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inversify@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/inversify/-/inversify-5.0.1.tgz#500d709b1434896ce5a0d58915c4a4210e34fb6e"
|
||||
integrity sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==
|
||||
|
||||
is-arrayish@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
|
@ -1304,6 +1496,11 @@ 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.2.0"
|
||||
resolved "https://registry.yarnpkg.com/iso8601-duration/-/iso8601-duration-1.2.0.tgz#5fa6fc180a8fe95ad6a6721c9bdd9069cb59e80e"
|
||||
integrity sha512-ErTBd++b17E8nmWII1K1uZtBgD1E8RjyvwmxlCjPHNqHMD7gmcMHOw0E8Ro/6+QT4PhHRSnnMo7bxa1vFPkwhg==
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
|
@ -1327,6 +1524,11 @@ jsbn@~0.1.0:
|
|||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
json-buffer@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
|
||||
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
|
||||
|
||||
json-parse-better-errors@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
|
||||
|
@ -1362,6 +1564,13 @@ jsprim@^1.2.2:
|
|||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
keyv@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.0.tgz#2d1dab694926b2d427e4c74804a10850be44c12f"
|
||||
integrity sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==
|
||||
dependencies:
|
||||
json-buffer "3.0.1"
|
||||
|
||||
latest-version@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
|
||||
|
@ -1404,6 +1613,11 @@ lowercase-keys@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
|
||||
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
|
||||
|
||||
lowercase-keys@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
|
||||
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
|
||||
|
||||
lru-cache@^4.0.1:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||
|
@ -1439,6 +1653,11 @@ make-error@^1.1.1:
|
|||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
|
||||
methods@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||
|
||||
mime-db@1.43.0:
|
||||
version "1.43.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
||||
|
@ -1451,11 +1670,26 @@ mime-types@^2.1.12, mime-types@~2.1.19:
|
|||
dependencies:
|
||||
mime-db "1.43.0"
|
||||
|
||||
mime@^1.4.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
mimic-response@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
|
||||
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
|
||||
|
||||
mimic-response@^2.0.0, mimic-response@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
|
||||
integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
|
||||
|
||||
miniget@^1.6.0, miniget@^1.6.1:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/miniget/-/miniget-1.7.0.tgz#a29eb79ebff479e9efafd271616981c603987875"
|
||||
|
@ -1636,6 +1870,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
normalize-url@^4.1.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
|
||||
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
|
||||
|
||||
npm-bundled@^1.0.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b"
|
||||
|
@ -1689,7 +1928,7 @@ object-assign@^4.1.0:
|
|||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
once@^1.3.0:
|
||||
once@^1.3.0, once@^1.3.1, once@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
|
@ -1738,12 +1977,24 @@ osenv@^0.1.4:
|
|||
os-homedir "^1.0.0"
|
||||
os-tmpdir "^1.0.0"
|
||||
|
||||
p-cancelable@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
|
||||
integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
|
||||
|
||||
p-event@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.1.0.tgz#e92bb866d7e8e5b732293b1c8269d38e9982bf8e"
|
||||
integrity sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==
|
||||
dependencies:
|
||||
p-timeout "^2.0.1"
|
||||
|
||||
p-finally@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
|
||||
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
||||
|
||||
p-limit@^2.2.0:
|
||||
p-limit@^2.2.0, p-limit@^2.2.2:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
|
||||
integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==
|
||||
|
@ -1757,6 +2008,13 @@ p-locate@^4.1.0:
|
|||
dependencies:
|
||||
p-limit "^2.2.0"
|
||||
|
||||
p-timeout@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038"
|
||||
integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==
|
||||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
|
||||
p-try@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
|
||||
|
@ -1853,7 +2111,7 @@ prepend-http@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
||||
|
||||
prism-media@^1.2.0:
|
||||
prism-media@^1.0.1, prism-media@^1.2.0, prism-media@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.2.1.tgz#168f323712bcaacb1d70ae613bf9d9dc44cf43d4"
|
||||
integrity sha512-R3EbKwJiYlTvGwcG1DpUt+06DsxOGS5W4AMEHT7oVOjG93MjpdhGX1whHyjnqknylLMupKAsKMEXcTNRbPe6Vw==
|
||||
|
@ -1883,11 +2141,24 @@ pstree.remy@^1.1.7:
|
|||
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3"
|
||||
integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==
|
||||
|
||||
pump@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
|
||||
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
|
||||
dependencies:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qs@^6.5.1:
|
||||
version "6.9.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9"
|
||||
integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
|
@ -1903,7 +2174,7 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
|
|||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
readable-stream@^2.0.6:
|
||||
readable-stream@^2.0.6, readable-stream@^2.3.5:
|
||||
version "2.3.7"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
|
||||
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
|
||||
|
@ -1989,6 +2260,13 @@ resolve-from@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
responselike@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
|
||||
integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
|
||||
dependencies:
|
||||
lowercase-keys "^2.0.0"
|
||||
|
||||
restore-cursor@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
|
||||
|
@ -2171,6 +2449,18 @@ source-map@^0.6.0:
|
|||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
spotify-uri@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/spotify-uri/-/spotify-uri-2.0.0.tgz#01c4cb1696d3eb803bf7054720efda9e66b8d553"
|
||||
integrity sha512-GmEDCx74boSaJFgyUGEKVnVTinCNF5f8RMIUsM8MKJSSaeQ/qonipY42NFct4pFbUT3MS5A19z/Dduy1dHdvaQ==
|
||||
|
||||
spotify-web-api-node@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/spotify-web-api-node/-/spotify-web-api-node-4.0.0.tgz#55f060975220cdac18efc0e781f84130b12004c0"
|
||||
integrity sha512-FQAX4qiP9xfjmJpkSfF5PEVr7RVorUZiLvcdVTlhVFLYAmQ8VSsZlyb0yTK0GExKhAcgJy9GfWxqjSB2r9SrjA==
|
||||
dependencies:
|
||||
superagent "^3.7.0"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
|
@ -2285,6 +2575,22 @@ strip-json-comments@~2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
|
||||
superagent@^3.7.0:
|
||||
version "3.8.3"
|
||||
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
|
||||
integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==
|
||||
dependencies:
|
||||
component-emitter "^1.2.0"
|
||||
cookiejar "^2.1.0"
|
||||
debug "^3.1.0"
|
||||
extend "^3.0.0"
|
||||
form-data "^2.3.1"
|
||||
formidable "^1.2.0"
|
||||
methods "^1.1.1"
|
||||
mime "^1.4.1"
|
||||
qs "^6.5.1"
|
||||
readable-stream "^2.3.5"
|
||||
|
||||
supports-color@^5.3.0, supports-color@^5.5.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
|
@ -2351,6 +2657,11 @@ tmp@^0.0.33:
|
|||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
to-readable-stream@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-2.1.0.tgz#82880316121bea662cdc226adb30addb50cb06e8"
|
||||
integrity sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
|
@ -2425,6 +2736,11 @@ type-check@~0.3.2:
|
|||
dependencies:
|
||||
prelude-ls "~1.1.2"
|
||||
|
||||
type-fest@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.10.0.tgz#7f06b2b9fbfc581068d1341ffabd0349ceafc642"
|
||||
integrity sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==
|
||||
|
||||
type-fest@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1"
|
||||
|
@ -2609,6 +2925,33 @@ yn@3.1.1:
|
|||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
|
||||
|
||||
youtube.ts@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/youtube.ts/-/youtube.ts-0.1.0.tgz#9925c59dadf1b9dcf0916aec247667d6cefff6de"
|
||||
integrity sha512-1JB3w8oCv2nrTv332cs2VZ5X2tWLJrVlq2m7REMGCQmHLxxr7y0yCFbM+69MzmItCgQ6ThijMYb1w2vDmzq7Uw==
|
||||
dependencies:
|
||||
axios "^0.19.0"
|
||||
ytdl-core-discord "^1.1.0"
|
||||
|
||||
ytdl-core-discord@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ytdl-core-discord/-/ytdl-core-discord-1.1.0.tgz#1276ef3895b773a3eafa4fe323495b41b715b9e1"
|
||||
integrity sha512-uiaZWa9UG+he1F9p7Si9H6Tieyxd9dEhLi4958mHuebudQSEEPaaJHUEbFikcpB++5ogzynVOcvdeC+LFJGgEw==
|
||||
dependencies:
|
||||
"@types/node" "^13.5.3"
|
||||
prism-media "^1.0.1"
|
||||
ytdl-core "^1.0.3"
|
||||
|
||||
ytdl-core@^1.0.3:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/ytdl-core/-/ytdl-core-1.0.9.tgz#938d5bf5f2baf901b04ffe41d4444fba72ba283a"
|
||||
integrity sha512-HhFeLfjXU34h0FNHmSkSpKygdaYijSt8VNsC770VYBRFb+dyUKcm11cIKxu2MUSwT9znISZ0k1wFdaV/N5VW+Q==
|
||||
dependencies:
|
||||
html-entities "^1.1.3"
|
||||
m3u8stream "^0.6.3"
|
||||
miniget "^1.6.0"
|
||||
sax "^1.1.3"
|
||||
|
||||
ytdl-core@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ytdl-core/-/ytdl-core-2.0.0.tgz#09bafc2beeab1eb9c69ceb9ca8f406be12396613"
|
||||
|
@ -2618,3 +2961,10 @@ ytdl-core@^2.0.0:
|
|||
m3u8stream "^0.6.3"
|
||||
miniget "^1.6.0"
|
||||
sax "^1.1.3"
|
||||
|
||||
ytsr@^0.1.11:
|
||||
version "0.1.11"
|
||||
resolved "https://registry.yarnpkg.com/ytsr/-/ytsr-0.1.11.tgz#223041db1f610b9c4453e4be63764a775e0c74ba"
|
||||
integrity sha512-f7RILud27ufqsw3+Zi0J5itQ7qOt7BzN2EhqQARFhZq9HdxrlSfwvymiO/wvzFALCR2bgyxfz/cJhWyjUlokCA==
|
||||
dependencies:
|
||||
html-entities "^1.1.3"
|
||||
|
|
Loading…
Reference in a new issue