diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1687d79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +config.json diff --git a/COMMANDS.md b/COMMANDS.md new file mode 100644 index 0000000..cfe7ca3 --- /dev/null +++ b/COMMANDS.md @@ -0,0 +1,111 @@ +# Command Help + +### help +*Available to all permissions* +Shows this help message +**Example** +``` +/help +``` +--- +### ping +*Available to all permissions* +Pong! +**Example** +``` +/ping +``` +--- +### grant (userId, permission) +*Available to permission "admin" only* +Grant someone a specific permission of either +- *moderator* +- *admin* + +**Example** +``` +/grant 122143660027412480 admin +``` +--- +### revoke (userId, permission) +*Available to permission "admin" only* +Revoke someone's permissions +**Example** +``` +/revoke 122143660027412480 +``` +--- +### set (key, value) +*Available to permission "admin" only* +Assign a specific value to a key, which may be one of the following: +- *voiceChannel* - Set the default voice channel to connect to +- *onlyListenIn* - Set the channel to accept commands from exclusively + +**Example** +``` +/set voiceChannel 369768568931221508 +/set onlyListenIn 369768568931221506 +``` +--- +### play (subject) +*Available to all permissions* +Play something according to the subject of either +- *YouTube Link* +- *Soundcloud Link* +- *Generic search term to be lookup up on YouTube* + +**Example** +``` +/play https://www.youtube.com/watch?v=DLzxrzFCyOs +/play https://soundcloud.com/rick-astley-official/never-gonna-give-you-up +/play never gonna give you up +``` +--- +### pause +*Available to all permissions* +Pause playback of current song +**Example** +``` +/pause +``` +--- +### resume +*Available to all permissions* +Resume playback of current song +**Example** +``` +/resume +``` +--- +### skip +*Available to all permissions, requires vote under permission "moderator"* +Skip playback of current song +**Example** +``` +/skip +``` +--- +### clear +*Available to all permissions, requires vote under permission "moderator"* +Clear the playlist +**Example** +``` +/clear +``` +--- +### vol +*Available to all permissions* +Sets current playback volume, defaults to 20. Limited to **100** +**Example** +``` +/vol 30 +``` +--- +### queue +*Available to all permissions* +Shows current playlist. +**Example** +``` +/queue +``` +--- diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..9a5e310 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, sKiLdUsT +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9933b7f --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# awesomebot + +[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square)](https://standardjs.com) + +Simple and fast Discord music bot using [discord.js](https://discord.js.org) + +### How to use + +- clone this repository +- run `npm install` +- copy `config.example.json` to `config.json` and fill it in + +And you're done! Use `node app` to run the bot. See [COMMANDS.md](/COMMANDS.md) for command usage help. + +### License + +BSD 3-Clause License diff --git a/app.js b/app.js new file mode 100644 index 0000000..ec549fb --- /dev/null +++ b/app.js @@ -0,0 +1,397 @@ +'use strict' +const Discord = require('discord.js') +const ytdl = require('youtube-dl') +const opn = require('opn') +const fs = require('fs') +const cache = require('./lib/cache') +const log = require('./lib/log') +const config = require('./config.json') +const pjson = require('./package.json') +const client = new Discord.Client() + +log.info(`${pjson.name} Version ${pjson.version}, loading...`) + +function guid () { + function s4 () { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1) + } + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + + s4() + '-' + s4() + s4() + s4() +} + +function enqueueSong (url, message) { + /* eslint-disable no-cond-assign */ + let vid + let options = [] + let author = 'Youtube' + let color = 0xff0000 + if (vid = url.match(/(?:http:\/\/|https:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?([^#&?]*).*/)) { + vid = 'https://youtube.com/watch?v=' + vid[1] + options.push('-f 140') + } else if (vid = url.match(/(?:http:\/\/|https:\/\/)(?:www\.)?soundcloud\.com\/(\w+)\/((?!sets).+)/)) { + vid = `https://soundcloud.com/${vid[1]}/${vid[2]}` + author = 'Soundcloud' + color = 0xff7700 + } else if (url.match(/(?:\w+:\/\/).+/)) { + message.channel.send('❌ Invalid URL!') + return + } else { + vid = 'ytsearch:' + url + options.push('-f 140') + } + message.channel.startTyping() + const filename = 'cache/' + guid() + let videoInfo + let video = ytdl(vid, options) + video + .on('info', info => { + if (info._duration_raw > 900) { + video.unresolve() + video = undefined + message.channel.send('❌ Media longer than 15 minutes!') + message.channel.stopTyping() + return + } + info.description = info.description.replace(/((?:http|https):\/\/\S{16})(\S+)/g, '[$1...]($1$2)') + if (info.description.length > 900) { + info.description = info.description.replace(/^([^]{900}[^\s]*)?([^]+)/, '$1 ...') + } + message.channel.send(`✅ Enqueued ${info.fulltitle}!`, {embed: { + title: info.fulltitle, + fields: [{ + name: 'Description', + value: info.description.length === 0 ? 'No description provided' : info.description + }], + author: { + name: author + }, + thumbnail: { + url: info.thumbnail + }, + footer: { + text: info.uploader + }, + timestamp: new Date(info.upload_date.replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3')), + url: info.webpage_url, + color + }}) + videoInfo = info + }) + .on('end', () => { + cache.guilds[message.channel.guild.id].songQueue.push({channel: message.channel.id, author: message.author.id, filename, videoInfo}) + if (message.channel.guild.dispatcher === undefined || message.channel.guild.dispatcher.destroyed) player(message.channel.guild.id) + message.channel.stopTyping() + }) + .on('error', e => { + message.channel.send('❌ Something went wrong!\n```' + e.stack.replace(__dirname, '') + '```') + video.unresolve() + video = undefined + message.channel.stopTyping() + }) + video.pipe(fs.createWriteStream(filename)) +} + +function player (guildID) { + /* eslint-disable no-inner-declarations */ + if (cache.guilds[guildID].songQueue.length > 0) { + let connection + let guild = client.guilds.get(guildID) + if (guild.voiceConnection) { + connection = guild.voiceConnection + play() + } else { + guild.channels.get(cache.guilds[guildID].voiceChannel).join() + .then(newConn => { + connection = newConn + play() + }) + } + function play () { + let song = cache.guilds[guild.id].songQueue.shift() + if (guild.dispatcher !== undefined) guild.dispatcher.end() + guild.dispatcher = connection.playFile(song.filename) + guild.dispatcher.setVolume(cache.guilds[guildID].volume) + guild.dispatcher.setBitrate(128) + guild.dispatcher.duration = song.videoInfo._duration_raw + guild.dispatcher + .on('end', () => { + setTimeout(() => fs.unlinkSync(song.filename), 5000) + player(guildID) + }) + guild.channels.get(song.channel).send(`ℹ <@${song.author}> your song "${song.videoInfo.fulltitle}" is now playing in ${connection.channel.name}!`) + client.user.setPresence({ + game: { + name: song.videoInfo.fulltitle, + url: null + } + }) + } + } else { + client.user.setPresence({game: null}) + client.guilds.get(guildID).voiceConnection.disconnect() + } +} + +function secondsToTimeString (duration) { + let hours = Math.floor(duration / 1200) + let minutes = Math.floor(duration / 60) + let seconds = duration - (hours * 1200) - (minutes * 60) + + hours = hours >= 10 ? hours : '0' + hours + minutes = minutes >= 10 ? minutes : '0' + minutes + seconds = seconds >= 10 ? seconds : '0' + seconds + return `${hours > 0 ? hours + ':' : ''}${minutes}:${seconds}` +} + +function selfCleanup (e) { + if (e) console.error(e) + else log.warn('Caught interrupt signal, cleaning...') + client.destroy().then(() => { + cache.saveSync() + process.exit() + }) +} + +process + .on('SIGINT', selfCleanup) + .on('SIGTERM', selfCleanup) + .on('SIGHUP', selfCleanup) + .on('uncaughtException', selfCleanup) + +client.on('ready', () => { + if (client.guilds.size === 0) { + log.warn(`No guilds found. You can add this bot with this link: https://discordapp.com/oauth2/authorize?&client_id=${client.user.id}&scope=bot&permissions=0`) + // opn(`https://discordapp.com/oauth2/authorize?&client_id=${client.user.id}&scope=bot&permissions=0`) + // Silently handle error + // .error(() => {}) + if (cache.guilds !== undefined) delete cache.guilds + } else { + Array.from(client.guilds.values()).forEach((guild) => { + if (cache.guilds === undefined) cache.guilds = {} + if (cache.guilds[guild.id] === undefined) { + cache.guilds[guild.id] = { + permissions: { + [config.Discord.adminId]: 2 + }, + songQueue: [], + volume: 0.2 + } + } + Array.from(guild.members.values()).forEach(user => { + if (user.id === client.user.id) return + if (cache.guilds[guild.id].permissions[user.id] === undefined) cache.guilds[guild.id].permissions[user.id] = 0 + }) + if (cache.guilds[guild.id].songQueue.length > 0) player(guild.id) + }) + } + log.info('Ready!') +}) +.on('guildCreate', guild => { + log.info(`Joining new guild "${guild.name}"`) + if (cache.guilds === undefined) cache.guilds = {} + if (cache.guilds[guild.id] === undefined) { + cache.guilds[guild.id] = { + permissions: { + [config.Discord.adminId]: 2 + }, + songQueue: [], + volume: 0.2 + } + Array.from(guild.members.values()).forEach(user => { + if (user.id === client.user.id) return + if (cache.guilds[guild.id].permissions[user.id] === undefined) cache.guilds[guild.id].permissions[user.id] = 0 + }) + } +}) +.on('guildDelete', guild => { + log.warn(`Removed from guild "${guild.name}"`) + delete cache.guilds[guild.id] +}) +.on('guildMemberAdd', member => { + cache.guilds[member.guild.id].permissions[member.id] = 0 +}) +.on('guildmemberRemove', member => { + delete cache.guilds[member.guild.id].permissions[member.id] +}) +.on('message', message => { + if (!message.author.bot && message.content.indexOf(config.App.commandPrefix) === 0) { + if (message.channel.type === 'dm' && !(message.content === '.help' || message.content === '.invite')) { + message.reply('You can\'t use this bot in private messages') + return + } + if (cache.guilds[message.guild.id].onlyListenIn !== undefined && cache.guilds[message.guild.id].onlyListenIn !== message.channel.id) return + let args = message.content.split(/ +/g) + args[0] = args[0].slice(config.App.commandPrefix.length) + switch (args[0]) { + case 'ping': + message.channel.send('pong!') + break + case 'invite': + if (message.author.id !== config.Discord.adminId) { + message.channel.send('❌ Unauthorized!') + return + } + message.channel.send(`https://discordapp.com/oauth2/authorize?&client_id=${client.user.id}&scope=bot&permissions=0`) + break + case 'help': + let fields = [] + fs.readFileSync('COMMANDS.md').toString().match(/###[\s\S]+?---/g).forEach(command => { + fields.push({ + name: command.match(/### (.+)/)[1], + value: command.match(/\n([\s\S]+)?---/)[1].replace(/\/(\w+)\s/g, config.App.commandPrefix + '$1 ') + }) + }) + message.channel.send({embed: {title: 'Commands', fields}}) + break + case 'grant': + case 'revoke': + if (cache.guilds[message.channel.guild.id].permissions[message.author.id] !== 2) { + message.channel.send('❌ Unauthorized!') + return + } + if (args[1] === undefined) { + message.channel.send('❌ No user given!') + return + } + if (args[0] === 'grant' && args[2] === undefined) { + message.channel.send('❌ No permission group given!') + return + } + let searchUser = args[1].split('#') + let targetUser + let permission + message.channel.guild.members.array().forEach(user => { + user = user.user + if (user.username === searchUser[0] && user.discriminator === searchUser[1]) targetUser = user + }) + if (targetUser !== undefined) { + if (args[0] === 'grant') { + switch (args[2]) { + case 'moderator': + permission = 1 + break + case 'admin': + permission = 2 + break + default: + message.channel.send('❌ Unknown permission!') + return + } + } else { + permission = 0 + } + cache.guilds[message.channel.guild.id].permissions[targetUser.id] = permission + if (args[0] === 'grant') message.channel.send(`✅ Granted ${args[1]} permission ${args[2]}`) + else message.channel.send(`✅ Revoked permissions for ${args[1]}`) + } else { + message.channel.send('❌ User not found!') + } + break + case 'play': + if (args[1] === undefined) message.channel.send('❌ No URL given!') + if (cache.guilds[message.guild.id].voiceChannel === undefined) { + message.channel.send(`❌ You must define a voice channel first! (see \`${config.App.commandPrefix}help set\`)`) + return + } + enqueueSong(message.content.replace(config.App.commandPrefix + 'play', ''), message) + break + case 'pause': + if (message.channel.guild.dispatcher !== undefined && !message.channel.guild.dispatcher.destroyed) message.channel.guild.dispatcher.pause() + else message.channel.send('❌ Nothing is playing at the moment!') + break + case 'resume': + if (message.channel.guild.dispatcher !== undefined && !message.channel.guild.dispatcher.destroyed) message.channel.guild.dispatcher.resume() + else message.channel.send('❌ Nothing is playing at the moment!') + break + case 'skip': + if (message.channel.guild.dispatcher !== undefined && !message.channel.guild.dispatcher.destroyed) message.channel.guild.dispatcher.end() + else message.channel.send('❌ Nothing is playing at the moment!') + break + case 'clear': + if (cache.guilds[message.channel.guild.id].permissions[message.author.id] === 0) { + message.channel.send('❌ Unauthorized!') + return + } + if (cache.guilds[message.channel.guild.id].songQueue.length === 0) message.channel.send('❌ Playlist is empty!') + else { + cache.guilds[message.channel.guild.id].songQueue = [] + message.channel.send('✅ Playlist cleared!') + } + break + case 'vol': + cache.guilds[message.channel.guild.id].volume = (args[1] > 100 ? 100 : args[1]) / 100 + if (message.channel.guild.dispatcher !== undefined && !message.channel.guild.dispatcher.destroyed) { + message.channel.guild.dispatcher.setVolume(cache.guilds[message.channel.guild.id].volume) + } + break + case 'queue': + if (cache.guilds[message.channel.guild.id].songQueue.length > 0) { + let fields = [] + let duration = 0 + cache.guilds[message.channel.guild.id].songQueue.forEach((song, index) => { + song = song.videoInfo + song.description = song.description.replace(/((?:http|https):\/\/\S{16})(\S+)/g, '[$1...]($1$2)') + if (song.description.length > 120) { + song.description = song.description.replace(/^([^]{120}[^\s]*)?([^]+)/, '$1 ...') + } + fields.push({ + name: `${index + 1} - "${song.fulltitle}"`, + value: `Duration: ${secondsToTimeString(song._duration_raw)}` + }) + duration = duration + song._duration_raw + }) + let untilNext = message.channel.guild.dispatcher.duration - Math.floor((new Date() - message.channel.guild.dispatcher.player.streamingData.startTime) / 1000) + fields.push({ + name: 'Time until next song', + value: `${secondsToTimeString(untilNext)}` + }) + + message.channel.send('', {embed: { + fields, + author: { + name: 'Queue' + }, + footer: { + text: `Runtime: ${secondsToTimeString(duration + untilNext)}` + }, + color: 0xc3c3c3 + }}) + } else message.channel.send('❌ Queue is empty!') + break + case 'set': + if (cache.guilds[message.channel.guild.id].permissions[message.author.id] !== 2) { + message.channel.send('❌ Unauthorized!') + return + } + if (args[2] === undefined) { + message.channel.send('❌ Missing value!') + return + } + switch (args[1]) { + case 'voiceChannel': + if (!message.guild.channels.has(args[2])) { + message.channel.send('❌ Invalid value!') + return + } + break + case 'onlyListenIn': + if (!message.guild.channels.has(args[2])) { + message.channel.send('❌ Invalid value!') + return + } + break + default: + message.channel.send('❌ Unknown key!') + return + } + cache.guilds[message.guild.id][args[1]] = args[2] + message.channel.send('✅ Set sucessfully!') + break + default: + break + } + } +}) +.login(config.Discord.token) diff --git a/cache/.gitignore b/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..ca26642 --- /dev/null +++ b/config.example.json @@ -0,0 +1,10 @@ +{ + "App" : { + "commandPrefix" : ".", + "logLevel" : 2 + }, + "Discord": { + "token" : "", + "adminId" : "" + } +} diff --git a/lib/cache.js b/lib/cache.js new file mode 100644 index 0000000..7d67a72 --- /dev/null +++ b/lib/cache.js @@ -0,0 +1,42 @@ +'use strict' +const fs = require('fs') +const log = require('./log') + +class Cache { + constructor () { + if (fs.existsSync('cache/cache.bin')) { + let restore = JSON.parse(fs.readFileSync('cache/cache.bin')) + for (let key in restore) { + this[key] = restore[key] + } + log.debug('Instance restored') + } else { + fs.closeSync(fs.openSync('cache/cache.bin', 'w')) + log.debug('Instance cache created') + } + setInterval(() => this.save(), 30000) + } + save () { + let toSave = {} + for (let key in this) { + if (!this.hasOwnProperty(key)) continue + if (typeof this[key] === 'function') continue + toSave[key] = this[key] + } + fs.writeFile('cache/cache.bin', JSON.stringify(toSave), () => { + log.debug('Instance saved') + }) + } + saveSync () { + let toSave = {} + for (let key in this) { + if (!this.hasOwnProperty(key)) continue + if (typeof this[key] === 'function') continue + toSave[key] = this[key] + } + fs.writeFileSync('cache/cache.bin', JSON.stringify(toSave)) + log.debug('Instance saved') + } +} + +module.exports = new Cache() diff --git a/lib/core.js b/lib/core.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/log.js b/lib/log.js new file mode 100644 index 0000000..3eed43b --- /dev/null +++ b/lib/log.js @@ -0,0 +1,39 @@ +'use strict' +const config = require('../config.json') +const colors = require('colors') +colors.setTheme({ + info: 'green', + warn: 'yellow', + debug: 'blue', + error: 'red' +}) +module.exports = { + date () { + let date = new Date() + let monthNames = [ + 'Jan', 'Feb', 'Mar', + 'Apr', 'May', 'Jun', 'Jul', + 'Aug', 'Sep', 'Oct', + 'Nov', 'Dec' + ] + let day = date.getDate() + let monthIndex = date.getMonth() + let hours = date.getHours() >= 10 ? date.getHours() : '0' + date.getHours() + let minutes = date.getMinutes() >= 10 ? date.getMinutes() : '0' + date.getMinutes() + let seconds = date.getSeconds() >= 10 ? date.getSeconds() : '0' + date.getSeconds() + let time = `${hours}:${minutes}:${seconds}` + return `${monthNames[monthIndex]} ${day} ${time}` + }, + debug (string) { + if (config.App.logLevel <= 1) console.log(`${this.date()} ${colors.debug('[DEBUG]')} ${string}`) + }, + info (string) { + if (config.App.logLevel <= 2) console.log(`${this.date()} ${colors.info('[INFO]')} ${string}`) + }, + warn (string) { + if (config.App.logLevel <= 3) console.log(`${this.date()} ${colors.warn('[WARN]')} ${string}`) + }, + error (string) { + if (config.App.logLevel <= 4) console.log(`${this.date()} ${colors.error('[ERROR]')} ${string}`) + } +} diff --git a/log b/log new file mode 100644 index 0000000..838601d --- /dev/null +++ b/log @@ -0,0 +1,4 @@ +Nov 7 02:03:45 [DEBUG] Instance restored +Nov 7 02:03:45 [INFO] Awesomebot Version 0.3.20171023, loading... +Nov 7 02:03:45 [WARN] No guilds found. You can add this bot with this link: https://discordapp.com/oauth2/authorize?&client_id=377257062352027648&scope=bot&permissions=0 +Nov 7 02:03:45 [DEBUG] Instance saved diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f3bdc4d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,857 @@ +{ + "name": "Awesomebot", + "version": "0.3.20171023", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + } + } + }, + "bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "2.0.3" + } + }, + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "cookiejar": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", + "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "discord.js": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.2.1.tgz", + "integrity": "sha512-8Mor+IREVWHinjRd6Bu6OwRfT+ET/WEoLWMl8crFvBVcTFmaO/TSwP39C8QIGCB2YMVMYMdljjX/w17AUMemqg==", + "requires": { + "long": "3.2.0", + "prism-media": "0.0.1", + "snekfetch": "3.5.2", + "tweetnacl": "1.0.0", + "ws": "3.2.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "ffmpeg-binaries": { + "version": "3.2.2-3", + "resolved": "https://registry.npmjs.org/ffmpeg-binaries/-/ffmpeg-binaries-3.2.2-3.tgz", + "integrity": "sha1-nKM7aM0wTs8Qwz5tz3HiuT637hQ=", + "requires": { + "superagent": "3.6.3", + "tar.gz": "1.0.5" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.2.3", + "har-schema": "2.0.0" + } + }, + "hashish": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/hashish/-/hashish-0.0.4.tgz", + "integrity": "sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ=", + "requires": { + "traverse": "0.6.6" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.0.2" + } + }, + "hh-mm-ss": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hh-mm-ss/-/hh-mm-ss-1.2.0.tgz", + "integrity": "sha512-f4I9Hz1dLpX/3mrEs7yq30+FiuO3tt5NWAqAGeBTaoeoBfB8vhcQ3BphuDc5DjZb/K809agqrAaFlP0jhEU/8w==", + "requires": { + "zero-fill": "2.2.3" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mout": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/mout/-/mout-0.11.1.tgz", + "integrity": "sha1-ujYR318OWx/7/QEWa48C0fX6K5k=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=" + }, + "node-opus": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/node-opus/-/node-opus-0.2.7.tgz", + "integrity": "sha1-W3JuKXlbCxJ7TIfmYtTegWhAV5w=", + "requires": { + "bindings": "1.2.1", + "commander": "2.11.0", + "nan": "2.7.0", + "ogg-packet": "1.0.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "ogg-packet": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ogg-packet/-/ogg-packet-1.0.0.tgz", + "integrity": "sha1-RbiFchrI991c8iOR1CEGrlM6xng=", + "optional": true, + "requires": { + "ref-struct": "1.1.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "opn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", + "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "requires": { + "is-wsl": "1.1.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "prism-media": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.1.tgz", + "integrity": "sha1-o0JcnKvVDRxsAuVDlBoRiVZnvRA=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "ref": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ref/-/ref-1.3.5.tgz", + "integrity": "sha512-2cBCniTtxcGUjDpvFfVpw323a83/0RLSGJJY5l5lcomZWhYpU2cuLdsvYqMixvsdLJ9+sTdzEkju8J8ZHDM2nA==", + "optional": true, + "requires": { + "bindings": "1.2.1", + "debug": "2.6.9", + "nan": "2.7.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "ref-struct": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ref-struct/-/ref-struct-1.1.0.tgz", + "integrity": "sha1-XV7mWtQc78Olxf60BYcmHkee3BM=", + "optional": true, + "requires": { + "debug": "2.6.9", + "ref": "1.3.5" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "snekfetch": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.5.2.tgz", + "integrity": "sha512-UZ6NxkSHhXSDZT0p0hhDapFWEPAb1mtuR0VX+B7V5nDEizH+3ZkIAL/2xJLrKygx7Sc/j8E5012xcj1e/6W2aQ==" + }, + "sntp": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", + "requires": { + "hoek": "4.2.0" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + } + } + }, + "streamify": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/streamify/-/streamify-0.2.9.tgz", + "integrity": "sha512-8pUxeLEef9UO1FxtTt5iikAiyzGI4SZRnGuJ3sz8axZ5Xk+/7ezEV5kuJQsMEFxw7AKYw3xp0Ow+20mmSaJbQQ==", + "requires": { + "hashish": "0.0.4" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "superagent": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.6.3.tgz", + "integrity": "sha512-GjsfCFijfjqoz2tRiStSOoTdy7gNZOcK3ar4zONP9D8dXQWE+Qg7cbePHimRpapo06WUvoU3dmgi2e4q+sab5A==", + "requires": { + "component-emitter": "1.2.1", + "cookiejar": "2.1.1", + "debug": "3.1.0", + "extend": "3.0.1", + "form-data": "2.3.1", + "formidable": "1.1.1", + "methods": "1.1.2", + "mime": "1.4.1", + "qs": "6.5.1", + "readable-stream": "2.3.3" + } + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar.gz": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tar.gz/-/tar.gz-1.0.5.tgz", + "integrity": "sha1-4a2n5F7yJBtLHuWBI8j0C108G8Q=", + "requires": { + "bluebird": "2.11.0", + "commander": "2.11.0", + "fstream": "1.0.11", + "mout": "0.11.1", + "tar": "2.2.1" + } + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "ultron": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", + "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.2.0.tgz", + "integrity": "sha512-hTS3mkXm/j85jTQOIcwVz3yK3up9xHgPtgEhDBOH3G18LDOZmSAG1omJeXejLKJakx+okv8vS1sopgs7rw0kVw==", + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.0" + } + }, + "youtube-dl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/youtube-dl/-/youtube-dl-1.12.2.tgz", + "integrity": "sha512-TDGmUxzEsQCp1Ux3IEkEhJ2LfRlUjBo5AaaGmW5Hqm8uX8jd2sB+Rq37S9vy505qnFhpy05uUSQsBtpvBuQBYA==", + "requires": { + "hh-mm-ss": "1.2.0", + "mkdirp": "0.5.1", + "request": "2.83.0", + "streamify": "0.2.9" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + } + } + }, + "zero-fill": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/zero-fill/-/zero-fill-2.2.3.tgz", + "integrity": "sha1-o97wa6XjmuZEhQu0yirUEStIVek=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5e38aee --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "Awesomebot", + "description": "An awesome bot for Discord", + "author": "sKiL (https://skildust.com)", + "version": "0.3.20171023", + "repository": "https://git.skildust.com/sKiL/awesomebot", + "license": "MIT", + "keywords": [ + "bot", + "discord", + "music" + ], + "main": "app.js", + "dependencies": { + "colors": "^1.1.2", + "discord.js": "^11.2.1", + "ffmpeg-binaries": "^3.2.2-3", + "node-opus": "^0.2.7", + "opn": "^5.1.0", + "youtube-dl": "^1.12.2" + } +}