remove old fgfm code, general cleanup
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -54,5 +54,3 @@ start.bat
|
|||||||
tokens.json
|
tokens.json
|
||||||
|
|
||||||
config.json
|
config.json
|
||||||
|
|
||||||
conf/vods.json
|
|
||||||
12287
conf/rooms.json
12287
conf/rooms.json
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "vr",
|
|
||||||
"interval": 1800,
|
|
||||||
"value": "Video and room requests are on! Use $vr <video-id> to request a video from this list [https://pastebin.com/qv0wDkvB] or $room <room-id> to request a specific room (looped for a few minutes) from this list [https://goo.gl/qoNmuH]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
42
discord.js
42
discord.js
@@ -1,26 +1,16 @@
|
|||||||
// Import modules
|
// Import modules
|
||||||
const { Client } = require("discord.js"),
|
const Discord = require("discord.js"),
|
||||||
fs = require("fs"),
|
fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
axios = require("axios"),
|
axios = require("axios"),
|
||||||
staticCommands = require("./lib/static-commands.js"),
|
staticCommands = require("./lib/static-commands.js"),
|
||||||
ankhbotCommands = require("./lib/ankhbot-commands.js"),
|
ankhbotCommands = require("./lib/ankhbot-commands.js"),
|
||||||
config = require("./config.json");
|
config = require("./config.json"),
|
||||||
|
{ randElement, chunkSubstr } = require("./lib/utils.js");
|
||||||
function chunkSubstr(str, size) {
|
|
||||||
const numChunks = Math.ceil(str.length / size);
|
|
||||||
const chunks = new Array(numChunks);
|
|
||||||
|
|
||||||
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
|
|
||||||
chunks[i] = str.substr(o, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(config) {
|
function init(config) {
|
||||||
// Set up Discord client
|
// Set up Discord client
|
||||||
const client = new Client();
|
const client = new Discord.Client();
|
||||||
|
|
||||||
// Set up SFX
|
// Set up SFX
|
||||||
const sfxFilePath = path.join(__dirname, "sfx");
|
const sfxFilePath = path.join(__dirname, "sfx");
|
||||||
@@ -234,6 +224,7 @@ function init(config) {
|
|||||||
// Wait for discord to be ready, handle messages
|
// Wait for discord to be ready, handle messages
|
||||||
.on("ready", () => {
|
.on("ready", () => {
|
||||||
console.log(`${config.botName} is connected and ready`);
|
console.log(`${config.botName} is connected and ready`);
|
||||||
|
client.setRandomActivity();
|
||||||
})
|
})
|
||||||
// Listen for commands for the bot to respond to across all channels
|
// Listen for commands for the bot to respond to across all channels
|
||||||
.on("message", (msg) => {
|
.on("message", (msg) => {
|
||||||
@@ -242,19 +233,16 @@ function init(config) {
|
|||||||
if (!config.discord.guilds[msg.guild.id]) {
|
if (!config.discord.guilds[msg.guild.id]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (config.discord.handleDMs === false) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the guild config for this msg, use default if no guild (DM)
|
||||||
|
let guildConfig = config.discord.guilds[msg.guild.id];
|
||||||
|
|
||||||
|
// Parse message content
|
||||||
msg.originalContent = msg.content;
|
msg.originalContent = msg.content;
|
||||||
msg.content = msg.content.toLowerCase();
|
msg.content = msg.content.toLowerCase();
|
||||||
|
|
||||||
// Find the guild config for this msg, use default if no guild (DM)
|
// Make sure the command starts with the configured prefix
|
||||||
let guildConfig = msg.guild
|
|
||||||
? config.discord.guilds[msg.guild.id]
|
|
||||||
: config.discord.guilds.default;
|
|
||||||
|
|
||||||
// Make sure it starts with the configured prefix
|
|
||||||
if (!msg.content.startsWith(guildConfig.prefix)) return;
|
if (!msg.content.startsWith(guildConfig.prefix)) return;
|
||||||
|
|
||||||
let commandNoPrefix = msg.content
|
let commandNoPrefix = msg.content
|
||||||
@@ -376,3 +364,13 @@ process.on("unhandledRejection", console.error);
|
|||||||
|
|
||||||
// Fire it up
|
// Fire it up
|
||||||
init(config);
|
init(config);
|
||||||
|
|
||||||
|
Discord.Client.prototype.setRandomActivity = function () {
|
||||||
|
if (!config.discord.master) return;
|
||||||
|
let activity = randElement(config.discord.activities);
|
||||||
|
console.log(`Setting Discord activity to: ${activity}`);
|
||||||
|
this.user.setActivity(activity, {
|
||||||
|
url: `https://twitch.tv/fgfm`,
|
||||||
|
type: "STREAMING"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
get: isOnCooldown,
|
|
||||||
set: placeOnCooldown
|
|
||||||
};
|
|
||||||
|
|
||||||
const NodeCache = require('node-cache');
|
|
||||||
const cache = new NodeCache({checkperiod: 1});
|
|
||||||
const md5 = require('md5');
|
|
||||||
const keyPrefix = 'cd';
|
|
||||||
|
|
||||||
// Given a cooldownTime in seconds and a command, returns false if the command is not on cooldown
|
|
||||||
// returns the time in seconds until the command will be ready again otherwise
|
|
||||||
function isOnCooldown(command, cooldownTime, callback)
|
|
||||||
{
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let now = Date.now();
|
|
||||||
let onCooldown = false;
|
|
||||||
let key = keyPrefix + md5(command);
|
|
||||||
|
|
||||||
cache.get(key, function(err, timeUsed) {
|
|
||||||
if (err) reject(err);
|
|
||||||
|
|
||||||
if (timeUsed !== null) {
|
|
||||||
// Command was recently used, check timestamp to see if it's on cooldown
|
|
||||||
if ((now - timeUsed) <= (cooldownTime*1000)) {
|
|
||||||
// Calculate how much longer it's on cooldown
|
|
||||||
onCooldown = ((cooldownTime*1000) - (now - timeUsed))/1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(onCooldown);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Places a command on cooldown for cooldownTime (in seconds)
|
|
||||||
function placeOnCooldown(command, cooldownTime)
|
|
||||||
{
|
|
||||||
let key = keyPrefix + md5(command);
|
|
||||||
return cache.set(key, Date.now(), cooldownTime, handleCacheSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCacheSet(error, result) {}
|
|
||||||
|
|
||||||
process.on('exit', (code) => {cache.close()});
|
|
||||||
324
lib/fgfm.js
324
lib/fgfm.js
@@ -1,324 +0,0 @@
|
|||||||
const util = require('./util'),
|
|
||||||
emitter = require('events').EventEmitter,
|
|
||||||
sysutil = require('util');
|
|
||||||
|
|
||||||
function FGFM(config) {
|
|
||||||
// Set up initial state
|
|
||||||
this.config = config.config;
|
|
||||||
this.obs = config.obs;
|
|
||||||
this.state = {
|
|
||||||
showStatus: 'IDLE',
|
|
||||||
videoQueue: [],
|
|
||||||
recentlyPlayed: [],
|
|
||||||
currentVideo: null,
|
|
||||||
videoTimer: null,
|
|
||||||
lastCommercialShownAt: Date.now(),
|
|
||||||
commercialPlaying: false
|
|
||||||
};
|
|
||||||
|
|
||||||
emitter.call(this);
|
|
||||||
|
|
||||||
this.startingSoon = (streamStartDelaySeconds, showStartDelaySeconds) => {
|
|
||||||
// @TODO: Move these defaults to config
|
|
||||||
if (typeof streamStartDelaySeconds === 'undefined') {
|
|
||||||
streamStartDelaySeconds = 1;
|
|
||||||
} else {
|
|
||||||
streamStartDelaySeconds = parseInt(streamStartDelaySeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof showStartDelaySeconds === 'undefined') {
|
|
||||||
showStartDelaySeconds = 300;
|
|
||||||
} else {
|
|
||||||
showStartDelaySeconds = parseInt(showStartDelaySeconds);
|
|
||||||
showStartDelaySeconds += streamStartDelaySeconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.showStatus = 'STARTING_SOON';
|
|
||||||
|
|
||||||
// Set up the initial queue by randomly choosing the configured amount of vods included in shuffling
|
|
||||||
this.state.videoQueue = this.config.vods.alttp.filter(e => e.includeInShuffle === true).sort(util.randSort).slice(0, this.config.initialQueueSize);
|
|
||||||
|
|
||||||
// Show the starting-soon scene
|
|
||||||
this.obs.switchToScene('starting-soon');
|
|
||||||
|
|
||||||
// Restore volume
|
|
||||||
this.obs.setVolume('headphones', 1.0);
|
|
||||||
|
|
||||||
// Start the stream after delay
|
|
||||||
console.log(`The stream will start in ${streamStartDelaySeconds} seconds!`);
|
|
||||||
setTimeout(() => {this.obs.startStream().then(() => {this.emit('STREAM_STARTED')})}, streamStartDelaySeconds*1000);
|
|
||||||
|
|
||||||
// Start the "show" after stream+show delay
|
|
||||||
// @TODO: Actually show the countdown in the scene
|
|
||||||
console.log(`The show will start in ${showStartDelaySeconds} seconds!`);
|
|
||||||
setTimeout(this.startTheShow, showStartDelaySeconds*1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set up initial queue + start playback
|
|
||||||
this.startTheShow = () => {
|
|
||||||
// Set up the initial queue by randomly choosing the configured amount of vods included in shuffling
|
|
||||||
this.state.videoQueue = this.config.vods.alttp.filter(e => e.includeInShuffle === true).sort(util.randSort).slice(0, this.config.initialQueueSize);
|
|
||||||
|
|
||||||
// Start queue playback
|
|
||||||
this.state.currentVideo = this.state.videoQueue.shift();
|
|
||||||
this.showVideo(this.state.currentVideo);
|
|
||||||
|
|
||||||
// restore volume
|
|
||||||
this.obs.setVolume('headphones', 1.0);
|
|
||||||
|
|
||||||
this.state.showStatus = 'RUNNING';
|
|
||||||
|
|
||||||
this.emit('SHOW_STARTED');
|
|
||||||
};
|
|
||||||
|
|
||||||
this.endTheShow = (creditsDelaySeconds, endDelaySeconds) => {
|
|
||||||
if (typeof creditsDelaySeconds === 'undefined' || creditsDelaySeconds === false) {
|
|
||||||
creditsDelaySeconds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof endDelaySeconds === 'undefined' || endDelaySeconds === false) {
|
|
||||||
endDelaySeconds = 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Credits will be shown in ${creditsDelaySeconds} seconds!`);
|
|
||||||
this.emit('SHOW_ENDING', creditsDelaySeconds);
|
|
||||||
|
|
||||||
let end = () => {
|
|
||||||
this.state.showStatus = 'ENDING';
|
|
||||||
|
|
||||||
// Hide current video, don't play next video
|
|
||||||
this.obs.hide(this.state.currentVideo.sceneItem, this.config.defaultSceneName)
|
|
||||||
clearTimeout(this.state.videoTimer);
|
|
||||||
|
|
||||||
this.obs.switchToScene('credits')
|
|
||||||
.then(() => {
|
|
||||||
this.emit('CREDITS_SHOWN', endDelaySeconds);
|
|
||||||
|
|
||||||
if (endDelaySeconds < 5) endDelaySeconds = 5;
|
|
||||||
console.log(`Stream will stop in ${endDelaySeconds} seconds`);
|
|
||||||
let fadeOutDelay = endDelaySeconds - 5;
|
|
||||||
|
|
||||||
// Fade out volume with 5 seconds left
|
|
||||||
setTimeout(() => {
|
|
||||||
this.obs.getVolume('headphones')
|
|
||||||
.then(currentVolume => {
|
|
||||||
console.log(`current volume of headphones: ${currentVolume}`);
|
|
||||||
let step = 0.1;
|
|
||||||
while (currentVolume > 0.1) {
|
|
||||||
currentVolume -= step;
|
|
||||||
console.log(`setting volume to: ${currentVolume}`);
|
|
||||||
this.obs.setVolume('headphones', currentVolume);
|
|
||||||
util.sleep(250);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
}, fadeOutDelay*1000);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.obs.stopStream();
|
|
||||||
this.state.showStatus = 'ENDED';
|
|
||||||
this.emit('SHOW_ENDED');
|
|
||||||
}, endDelaySeconds*1000);
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (creditsDelaySeconds > 0) {
|
|
||||||
setTimeout(end, creditsDelaySeconds*1000);
|
|
||||||
} else {
|
|
||||||
end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Shows.. a... video
|
|
||||||
this.showVideo = video => {
|
|
||||||
console.log(`Showing video: ${video.chatName}`);
|
|
||||||
|
|
||||||
this.obs.playVideoInScene(video, this.config.defaultSceneName, this.nextVideo)
|
|
||||||
.then(timer => {
|
|
||||||
// track timer so we can cancel callback later on if necessary
|
|
||||||
this.state.videoTimer = timer;
|
|
||||||
|
|
||||||
// update activity label and show/hide appropriately
|
|
||||||
if (video.hasOwnProperty('label') && video.label !== false) {
|
|
||||||
this.obs.showActivity(video.label);
|
|
||||||
} else {
|
|
||||||
this.obs.hideActivity();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Adds a gameplay vod to the queue
|
|
||||||
this.addVideo = video => {
|
|
||||||
return this.state.videoQueue.push(video);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Adds a room to the queue and handles looping setup
|
|
||||||
this.addRoomVideo = (room, loop) => {
|
|
||||||
let loops = 1;
|
|
||||||
if (typeof loop === 'undefined' || loop === true) {
|
|
||||||
loops = Math.floor(this.config.roomVidPlaytime / room.videoData.length);
|
|
||||||
}
|
|
||||||
console.log(`Adding room video for ${room.dungeonName} - ${room.roomName} to the queue (${loops} loops)`);
|
|
||||||
|
|
||||||
let video = {
|
|
||||||
filePath: `${this.config.roomVidsBasePath}${room.winPath}`,
|
|
||||||
sceneItem: (room.videoData.width === 960) ? "4x3ph" : "16x9ph",
|
|
||||||
length: room.videoData.length,
|
|
||||||
label: room.roomName,
|
|
||||||
chatName: room.roomName,
|
|
||||||
loops: loops,
|
|
||||||
requestedBy: room.requestedBy
|
|
||||||
};
|
|
||||||
|
|
||||||
this.state.videoQueue.push(video);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Picks the next video in the queue (shuffles if empty)
|
|
||||||
// Also handles "commercial breaks" if enabled
|
|
||||||
this.nextVideo = () => {
|
|
||||||
// @TODO: Validate this.state.showStatus -- make sure the "show" hasn't been paused or stopped
|
|
||||||
let ignoreStates = ['ENDING', 'ENDED', 'PAUSED'];
|
|
||||||
if (ignoreStates.includes(this.state.showStatus)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a "commercial break" if it's been long enough since the last one
|
|
||||||
let secondsSinceLastCommercial = (Date.now() - this.state.lastCommercialShownAt) / 1000;
|
|
||||||
if (this.config.commercialsEnabled === true && secondsSinceLastCommercial >= this.config.commercialInterval) {
|
|
||||||
console.log(`It has been ${secondsSinceLastCommercial} seconds since the last commercial break!`);
|
|
||||||
// Random chance for it to be "everybody wow"
|
|
||||||
let memeId = false;
|
|
||||||
if ((Math.floor(Math.random() * 100) + 1) <= this.config.auwChance) {
|
|
||||||
console.log(`Showing AUW!`);
|
|
||||||
memeId = 'auw';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showMeme(memeId)
|
|
||||||
.then(() => {
|
|
||||||
this.state.lastCommercialShownAt = Date.now();
|
|
||||||
this.nextVideo();
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep track of recently played videos
|
|
||||||
if (this.state.recentlyPlayed.length === this.config.recentlyPlayedMemory) {
|
|
||||||
this.state.recentlyPlayed.shift();
|
|
||||||
}
|
|
||||||
this.state.recentlyPlayed.push(this.state.currentVideo.id);
|
|
||||||
|
|
||||||
// If a commercial is playing, wait until it's done to switch
|
|
||||||
while (this.state.commercialPlaying === true) {}
|
|
||||||
|
|
||||||
// play the next video in the queue, or pick one at random if the queue is empty
|
|
||||||
if (this.state.videoQueue.length > 0) {
|
|
||||||
this.state.currentVideo = this.state.videoQueue.shift();
|
|
||||||
} else {
|
|
||||||
// Random chance for room grind to be played for an amount of time instead of another video be shuffled to
|
|
||||||
if ((Math.floor(Math.random() * 100) + 1) <= this.config.roomGrindChance) {
|
|
||||||
console.log(`Room grind selected!`);
|
|
||||||
// show room-grind source
|
|
||||||
this.obs.showRoomGrind(this.config.roomGrindPlaytime, () => {this.nextVideo()})
|
|
||||||
.then(timer => {
|
|
||||||
this.state.videoTimer = timer;
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Random chance for room videos to be added
|
|
||||||
if ((Math.floor(Math.random() * 100) + 1) <= this.config.roomShuffleChance) {
|
|
||||||
console.log(`Room vids selected!`);
|
|
||||||
|
|
||||||
this.addRoomVideo(this.config.rooms.sort(util.randSort).slice(0, 1).shift());
|
|
||||||
|
|
||||||
// play the first one
|
|
||||||
this.state.currentVideo = this.state.videoQueue.shift();
|
|
||||||
} else {
|
|
||||||
// filter recently played from shuffle
|
|
||||||
let freshVods = this.config.vods.alttp.filter(e => {
|
|
||||||
return e.includeInShuffle === true && !this.state.recentlyPlayed.includes(e.id);
|
|
||||||
});
|
|
||||||
this.state.currentVideo = freshVods.sort(util.randSort).slice(0, 1).shift();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showVideo(this.state.currentVideo);
|
|
||||||
};
|
|
||||||
|
|
||||||
// "Commercials"
|
|
||||||
this.showCommercial = (video, callback) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let handleFinish = () => {
|
|
||||||
console.log('commercial is finished playing...');
|
|
||||||
this.state.commercialPlaying = false;
|
|
||||||
if (typeof callback !== 'undefined') callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.obs.playVideoInScene(video, this.config.commercialSceneName, handleFinish)
|
|
||||||
.then(timer => {
|
|
||||||
this.state.commercialPlaying = true;
|
|
||||||
resolve(timer);
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Memes-By-Id
|
|
||||||
this.showMeme = id => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// find the vod in memes
|
|
||||||
let video = this.config.vods.memes.find(e => e.id === id);
|
|
||||||
if (!video) {
|
|
||||||
reject(`No meme found matching ID ${id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let handleFinish = () => {
|
|
||||||
if (id === 'auw') {
|
|
||||||
this.obs.hide("owen", this.config.commercialSceneName);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.showCommercial(video, handleFinish)
|
|
||||||
.then(videoHasStarted => {
|
|
||||||
// in the case of 'auw', show owen
|
|
||||||
if (id === 'auw') {
|
|
||||||
this.obs.show("owen", this.config.commercialSceneName);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(console.error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Skip the current video and play the next
|
|
||||||
this.skip = () => {
|
|
||||||
clearTimeout(this.state.videoTimer);
|
|
||||||
this.obs.hide(this.state.currentVideo.sceneItem, this.config.defaultSceneName).then(this.nextVideo).catch(console.error);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clears.. the... queue
|
|
||||||
this.clearQueue = () => {
|
|
||||||
this.state.videoQueue = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.pause = () => {
|
|
||||||
this.state.showStatus = 'PAUSED';
|
|
||||||
this.emit('SHOW_PAUSED');
|
|
||||||
};
|
|
||||||
|
|
||||||
this.resume = () => {
|
|
||||||
this.state.showStatus = 'RUNNING';
|
|
||||||
this.nextVideo();
|
|
||||||
this.emit('SHOW_RESUMED');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sysutil.inherits(FGFM, emitter);
|
|
||||||
|
|
||||||
module.exports = FGFM;
|
|
||||||
178
lib/ghobs.js
178
lib/ghobs.js
@@ -1,178 +0,0 @@
|
|||||||
const OBSWebSocket = require('obs-websocket-js');
|
|
||||||
|
|
||||||
function GHOBS(config) {
|
|
||||||
this.config = config;
|
|
||||||
this.websocket = new OBSWebSocket();
|
|
||||||
|
|
||||||
this.init = () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
console.log(`Connecting to OBS Websocket...`);
|
|
||||||
this.websocket.connect({ address: this.config.obs.websocket.address, password: this.config.obs.websocket.password })
|
|
||||||
.then(() => {
|
|
||||||
console.log(`Success! We're connected to OBS!`);
|
|
||||||
this.websocket.getCurrentScene().then(currentScene => this.currentScene = currentScene.name);
|
|
||||||
this.websocket.onSwitchScenes(newScene => this.currentScene = newScene.sceneName);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
|
|
||||||
// Listen for errors from OBS
|
|
||||||
// @TODO: Handle socket disconnect gracefully
|
|
||||||
/** { status: 'error',
|
|
||||||
description: 'There is no Socket connection available.',
|
|
||||||
code: 'NOT_CONNECTED',
|
|
||||||
error: 'There is no Socket connection available.' }*/
|
|
||||||
this.websocket.on('error', err => {
|
|
||||||
console.error(`OBS websocket error: ${JSON.stringify(err)}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.startStream = () => {
|
|
||||||
return this.websocket.startStreaming();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.stopStream = () => {
|
|
||||||
return this.websocket.stopStreaming();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setVolume = (source, volume) => {
|
|
||||||
return this.websocket.setVolume({source: source, volume: volume});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getVolume = (source) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.websocket.getVolume({source: source})
|
|
||||||
.then(res => {
|
|
||||||
resolve(res.volume);
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plays a video in the current scene and hides when finished
|
|
||||||
this.playVideo = (video, callback) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// @TODO Validation of video
|
|
||||||
|
|
||||||
// set the file path on the source
|
|
||||||
let sourceSettings = {
|
|
||||||
local_file: video.filePath,
|
|
||||||
looping: (typeof video.loops !== 'undefined' && video.loops > 1)
|
|
||||||
};
|
|
||||||
sourceSettings.loop = sourceSettings.looping;
|
|
||||||
|
|
||||||
this.websocket.setSourceSettings({"sourceName": video.sceneItem, "sourceSettings": sourceSettings})
|
|
||||||
// show the video scene item
|
|
||||||
.then(() => this.websocket.setSceneItemProperties({"item": video.sceneItem, "visible": true}))
|
|
||||||
// when the video is over, hide it and trigger the user callback, but resolve promise immediately with the timer
|
|
||||||
.then(() => {
|
|
||||||
// if this video is being looped, adjust timeout length to allow the requested number of loops to complete
|
|
||||||
if (sourceSettings.loop === true) {
|
|
||||||
video.length *= video.loops;
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolve Promise with a timer of when the video will finish playback
|
|
||||||
// trigger user callback when the video finishes
|
|
||||||
let timer = setTimeout(() => {
|
|
||||||
this.websocket.setSceneItemProperties({"item": video.sceneItem, "visible": false});
|
|
||||||
if (typeof callback !== 'undefined') {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}, parseInt(video.length*1000));
|
|
||||||
|
|
||||||
resolve(timer);
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shows a video in the given scene/item and then hides it and switches back to the original scene when finished
|
|
||||||
this.playVideoInScene = (video, scene, callback) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
video.scene = scene;
|
|
||||||
let originalScene = this.currentScene || false;
|
|
||||||
let handleVideoEnd = () => {
|
|
||||||
if (originalScene !== false) {
|
|
||||||
this.websocket.setCurrentScene({"scene-name": originalScene});
|
|
||||||
}
|
|
||||||
if (typeof callback !== 'undefined') {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.websocket.setCurrentScene({"scene-name": scene})
|
|
||||||
.then(() => this.playVideo(video, handleVideoEnd))
|
|
||||||
.then(timer => { resolve(timer) })
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.showActivity = (newActivity) => {
|
|
||||||
let update = {
|
|
||||||
"source": this.config.currentActivitySceneItemName,
|
|
||||||
"scene-name": this.config.defaultSceneName,
|
|
||||||
"render": true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof newActivity !== 'undefined' && newActivity.length > 0) {
|
|
||||||
update.text = newActivity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.websocket.setTextGDIPlusProperties(update);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hideActivity = () => {
|
|
||||||
return this.websocket.setSceneItemProperties({"item": this.config.currentActivitySceneItemName, "scene-name": this.config.defaultSceneName, "visible": false});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.showRoomGrind = (playTime, callback) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.websocket.setSceneItemProperties({"item": "room-grind", "scene-name": this.config.defaultSceneName, "visible": true})
|
|
||||||
.then(res => {
|
|
||||||
this.showActivity("NOW SHOWING: TTAS Room Grind !ttas");
|
|
||||||
resolve(setTimeout(() => {
|
|
||||||
// after timeout, hide room-grind and call user callback
|
|
||||||
this.websocket.setSceneItemProperties({"item": "room-grind", "scene-name": this.config.defaultSceneName, "visible": false});
|
|
||||||
if (typeof callback !== 'undefined') callback();
|
|
||||||
}, playTime*1000));
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setVisible = (item, scene, visible) => {
|
|
||||||
return this.websocket.setSceneItemProperties({"item": item, "scene-name": scene, "visible": visible});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.toggleVisible = (item) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.websocket.getSceneItemProperties({"item": item})
|
|
||||||
.then(data => {
|
|
||||||
let newVisibility = !data.visible;
|
|
||||||
this.websocket.setSceneItemProperties({"item": item, "visible": newVisibility}).then(resolve);
|
|
||||||
})
|
|
||||||
.catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.show = (item, scene) => {
|
|
||||||
return this.setVisible(item, scene, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.hide = (item, scene) => {
|
|
||||||
return this.setVisible(item, scene, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.switchToScene = (scene) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (this.currentScene === scene) {
|
|
||||||
resolve(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.websocket.setCurrentScene({"scene-name": scene}).then(resolve).catch(reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = GHOBS;
|
|
||||||
134
lib/spotify.js
134
lib/spotify.js
@@ -1,134 +0,0 @@
|
|||||||
var SpotifyWebApi = require('spotify-web-api-node');
|
|
||||||
|
|
||||||
function Spotify(config) {
|
|
||||||
// Set up initial state
|
|
||||||
this.config = config;
|
|
||||||
|
|
||||||
this.credentials = {
|
|
||||||
clientId: this.config.clientId,
|
|
||||||
clientSecret: this.config.clientSecret,
|
|
||||||
redirectUri: this.config.redirectUri
|
|
||||||
};
|
|
||||||
|
|
||||||
const spotifyApi = new SpotifyWebApi(this.credentials);
|
|
||||||
|
|
||||||
// The code that's returned as a query parameter to the redirect URI
|
|
||||||
const code = this.config.userCode;
|
|
||||||
|
|
||||||
this.init = () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// Retrieve an access token and a refresh token
|
|
||||||
spotifyApi.authorizationCodeGrant(code).then(
|
|
||||||
function(data) {
|
|
||||||
console.log('The token expires in ' + data.body['expires_in']);
|
|
||||||
console.log('The access token is ' + data.body['access_token']);
|
|
||||||
console.log('The refresh token is ' + data.body['refresh_token']);
|
|
||||||
|
|
||||||
// Set the access token on the API object to use it in later calls
|
|
||||||
spotifyApi.setAccessToken(data.body['access_token']);
|
|
||||||
spotifyApi.setRefreshToken(data.body['refresh_token']);
|
|
||||||
|
|
||||||
// clientId, clientSecret and refreshToken has been set on the api object previous to this call.
|
|
||||||
setInterval(() => {
|
|
||||||
spotifyApi.refreshAccessToken().then(
|
|
||||||
function(data) {
|
|
||||||
console.log('The access token has been refreshed!');
|
|
||||||
|
|
||||||
// Save the access token so that it's used in future calls
|
|
||||||
spotifyApi.setAccessToken(data.body['access_token']);
|
|
||||||
},
|
|
||||||
function(err) {
|
|
||||||
console.log('Could not refresh access token', err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}, data.body['expires_in']*1000);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
function(err) {
|
|
||||||
console.log('Something went wrong!', JSON.stringify(err));
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getMe = () => {
|
|
||||||
spotifyApi.getMe()
|
|
||||||
.then(function(data) {
|
|
||||||
console.log('Some information about the authenticated user', data.body);
|
|
||||||
}, function(err) {
|
|
||||||
console.log('Something went wrong!', err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getCurrentSong = () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
spotifyApi.getMyCurrentPlaybackState({}, (err, data) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let state = data.body;
|
|
||||||
resolve({
|
|
||||||
artists: state.item.artists,
|
|
||||||
name: state.item.name,
|
|
||||||
album: state.item.album.name,
|
|
||||||
url: state.item.external_urls.spotify
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getCurrentPlaylist = () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
spotifyApi.getMyCurrentPlaybackState({}, (err, data) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let state = data.body;
|
|
||||||
if (state.context) {
|
|
||||||
resolve(state.context.external_urls.spotify);
|
|
||||||
} else {
|
|
||||||
resolve(state.item.album.external_urls.spotify);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.playContext = (uri) => {
|
|
||||||
return spotifyApi.play({"context_uri": uri});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.skip = () => {
|
|
||||||
return spotifyApi.skipToNext();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.pause = () => {
|
|
||||||
return spotifyApi.pause();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.resume = () => {
|
|
||||||
return spotifyApi.play();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setVolume = (volume) => {
|
|
||||||
volume = parseInt(volume);
|
|
||||||
if (volume < 0) volume = 0;
|
|
||||||
if (volume > 100) volume = 100;
|
|
||||||
return spotifyApi.setVolume(volume);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.shuffle = (state) => {
|
|
||||||
return spotifyApi.setShuffle({"state": state});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.repeat = (state) => {
|
|
||||||
return spotifyApi.setRepeat({"state": state});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Spotify;
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
const util = require('util'),
|
|
||||||
emitter = require('events').EventEmitter;
|
|
||||||
|
|
||||||
function Timers()
|
|
||||||
{
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
emitter.call(self);
|
|
||||||
|
|
||||||
self.once = (forTimestamp, eventName) => {
|
|
||||||
// figure out ms between now and scheduled time
|
|
||||||
// setTimeout for event to be fired at that time
|
|
||||||
let diff = forTimestamp - Date.now();
|
|
||||||
if (diff < 0) return;
|
|
||||||
setTimeout(() => {self.emit(eventName)}, diff);
|
|
||||||
return self;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.repeat = (intervalSeconds, eventName) => {
|
|
||||||
setInterval(() => {self.emit(eventName)}, intervalSeconds*1000);
|
|
||||||
return self;
|
|
||||||
};
|
|
||||||
|
|
||||||
self.onceAndRepeat = (forTimestamp, intervalSeconds, eventName) => {
|
|
||||||
let diff = forTimestamp - Date.now();
|
|
||||||
if (diff < 0) return self;
|
|
||||||
setTimeout(() => {
|
|
||||||
self.emit(eventName);
|
|
||||||
self.repeat(intervalSeconds, eventName);
|
|
||||||
}, diff);
|
|
||||||
return self;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
util.inherits(Timers, emitter);
|
|
||||||
|
|
||||||
module.exports = new Timers();
|
|
||||||
60
lib/util.js
60
lib/util.js
@@ -1,60 +0,0 @@
|
|||||||
// Converts seconds to human-readable time
|
|
||||||
String.prototype.toHHMMSS = function () {
|
|
||||||
let sec_num = parseInt(this, 10); // don't forget the second param
|
|
||||||
let hours = Math.floor(sec_num / 3600);
|
|
||||||
let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
|
|
||||||
let seconds = sec_num - (hours * 3600) - (minutes * 60);
|
|
||||||
|
|
||||||
if (hours < 10) {hours = "0"+hours;}
|
|
||||||
if (minutes < 10) {minutes = "0"+minutes;}
|
|
||||||
if (seconds < 10) {seconds = "0"+seconds;}
|
|
||||||
return hours+':'+minutes+':'+seconds;
|
|
||||||
};
|
|
||||||
|
|
||||||
var exports = module.exports = {};
|
|
||||||
|
|
||||||
exports.asyncForEach = async function(array, callback) {
|
|
||||||
for (let index = 0; index < array.length; index++) {
|
|
||||||
await callback(array[index], index, array)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.range = function(start,stop) {
|
|
||||||
var result=[];
|
|
||||||
for (var idx=start.charCodeAt(0),end=stop.charCodeAt(0); idx <=end; ++idx){
|
|
||||||
result.push(String.fromCharCode(idx));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.randElement = function(arr) {
|
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.sum = function(e) {
|
|
||||||
let sum = 0;
|
|
||||||
for (let i = 0; i < e.length; i++) {
|
|
||||||
sum += parseInt(e[i], 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.average = function(e) {
|
|
||||||
let sum = exports.sum(e);
|
|
||||||
|
|
||||||
let avg = sum / e.length;
|
|
||||||
|
|
||||||
return avg;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.randSort = () => { return 0.5 - Math.random() };
|
|
||||||
|
|
||||||
exports.sleep = (milliseconds) => {
|
|
||||||
var start = new Date().getTime();
|
|
||||||
for (var i = 0; i < 1e7; i++) {
|
|
||||||
if ((new Date().getTime() - start) > milliseconds){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50
lib/utils.js
Executable file
50
lib/utils.js
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
// Converts seconds to human-readable time
|
||||||
|
String.prototype.toHHMMSS = function () {
|
||||||
|
let sec_num = parseInt(this, 10); // don't forget the second param
|
||||||
|
let hours = Math.floor(sec_num / 3600);
|
||||||
|
let minutes = Math.floor((sec_num - hours * 3600) / 60);
|
||||||
|
let seconds = sec_num - hours * 3600 - minutes * 60;
|
||||||
|
|
||||||
|
if (hours < 10) {
|
||||||
|
hours = "0" + hours;
|
||||||
|
}
|
||||||
|
if (minutes < 10) {
|
||||||
|
minutes = "0" + minutes;
|
||||||
|
}
|
||||||
|
if (seconds < 10) {
|
||||||
|
seconds = "0" + seconds;
|
||||||
|
}
|
||||||
|
return hours + ":" + minutes + ":" + seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function asyncForEach(array, callback) {
|
||||||
|
for (let index = 0; index < array.length; index++) {
|
||||||
|
await callback(array[index], index, array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function randElement(arr) {
|
||||||
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function randSort() {
|
||||||
|
return 0.5 - Math.random();
|
||||||
|
}
|
||||||
|
|
||||||
|
function chunkSubstr(str, size) {
|
||||||
|
const numChunks = Math.ceil(str.length / size);
|
||||||
|
const chunks = new Array(numChunks);
|
||||||
|
|
||||||
|
for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
|
||||||
|
chunks[i] = str.substr(o, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
asyncForEach,
|
||||||
|
randElement,
|
||||||
|
randSort,
|
||||||
|
chunkSubstr
|
||||||
|
};
|
||||||
273
package-lock.json
generated
273
package-lock.json
generated
@@ -5,14 +5,14 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "5.5.2",
|
"version": "6.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
|
||||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
"integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"co": "^4.6.0",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-deep-equal": "^1.0.0",
|
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
"json-schema-traverse": "^0.3.0"
|
"json-schema-traverse": "^0.4.1",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"asn1": {
|
"asn1": {
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||||
},
|
},
|
||||||
"async": {
|
"async": {
|
||||||
"version": "2.6.1",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||||
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
|
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"lodash": "^4.17.10"
|
"lodash": "^4.17.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"async-limiter": {
|
"async-limiter": {
|
||||||
@@ -52,9 +52,9 @@
|
|||||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||||
},
|
},
|
||||||
"aws4": {
|
"aws4": {
|
||||||
"version": "1.8.0",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
|
||||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.2",
|
||||||
@@ -94,9 +94,15 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"tweetnacl": "^0.14.3"
|
"tweetnacl": "^0.14.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||||
|
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bindings": {
|
"bindings": {
|
||||||
@@ -119,11 +125,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
|
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
|
||||||
},
|
},
|
||||||
"co": {
|
|
||||||
"version": "4.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
|
||||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
|
||||||
},
|
|
||||||
"combined-stream": {
|
"combined-stream": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
|
||||||
@@ -158,12 +159,12 @@
|
|||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||||
},
|
},
|
||||||
"cron-parser": {
|
"cron-parser": {
|
||||||
"version": "2.6.0",
|
"version": "2.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.13.0.tgz",
|
||||||
"integrity": "sha512-KGfDDTjBIx85MnVYcdhLccoJH/7jcYW+5Z/t3Wsg2QlJhmmjf+97z+9sQftS71lopOYYapjEKEvmWaCsym5Z4g==",
|
"integrity": "sha512-UWeIpnRb0eyoWPVk+pD3TDpNx3KCFQeezO224oJIkktBrcW6RoAPOx5zIKprZGfk6vcYSmA8yQXItejSaDBhbQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-nan": "^1.2.1",
|
"is-nan": "^1.2.1",
|
||||||
"moment-timezone": "^0.5.0"
|
"moment-timezone": "^0.5.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"crypt": {
|
"crypt": {
|
||||||
@@ -202,29 +203,21 @@
|
|||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||||
},
|
},
|
||||||
"discord.js": {
|
"discord.js": {
|
||||||
"version": "11.4.2",
|
"version": "11.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.6.4.tgz",
|
||||||
"integrity": "sha512-MDwpu0lMFTjqomijDl1Ed9miMQe6kB4ifKdP28QZllmLv/HVOJXhatRgjS8urp/wBlOfx+qAYSXcdI5cKGYsfg==",
|
"integrity": "sha512-cK6rH1PuGjSjpmEQbnpuTxq1Yv8B89SotyKUFcr4RhnsiZnfBfDOev7DD7v5vhtEyyj51NuMWFoRJzgy/m08Uw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"long": "^4.0.0",
|
"long": "^4.0.0",
|
||||||
"prism-media": "^0.0.3",
|
"prism-media": "^0.0.4",
|
||||||
"snekfetch": "^3.6.4",
|
"snekfetch": "^3.6.4",
|
||||||
"tweetnacl": "^1.0.0",
|
"tweetnacl": "^1.0.0",
|
||||||
"ws": "^4.0.0"
|
"ws": "^6.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tweetnacl": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ecc-jsbn": {
|
"ecc-jsbn": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"jsbn": "~0.1.0",
|
"jsbn": "~0.1.0",
|
||||||
"safer-buffer": "^2.1.0"
|
"safer-buffer": "^2.1.0"
|
||||||
@@ -241,14 +234,14 @@
|
|||||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||||
},
|
},
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "1.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
||||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
|
||||||
},
|
},
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||||
},
|
},
|
||||||
"ffmpeg-binaries": {
|
"ffmpeg-binaries": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
@@ -316,11 +309,11 @@
|
|||||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||||
},
|
},
|
||||||
"har-validator": {
|
"har-validator": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||||
"integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
|
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^5.3.0",
|
"ajv": "^6.5.5",
|
||||||
"har-schema": "^2.0.0"
|
"har-schema": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -369,11 +362,11 @@
|
|||||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||||
},
|
},
|
||||||
"is-nan": {
|
"is-nan": {
|
||||||
"version": "1.2.1",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.0.tgz",
|
||||||
"integrity": "sha1-n69ltvttskt/XAYoR16nH5iEAeI=",
|
"integrity": "sha512-z7bbREymOqt2CCaZVly8aC4ML3Xhfi0ekuOnjO2L8vKdl+CttdVoGZQhd4adMFAsxQ5VeRVwORs4tU8RH+HFtQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"define-properties": "^1.1.1"
|
"define-properties": "^1.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-typedarray": {
|
"is-typedarray": {
|
||||||
@@ -399,8 +392,7 @@
|
|||||||
"jsbn": {
|
"jsbn": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"json-schema": {
|
"json-schema": {
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
@@ -408,9 +400,9 @@
|
|||||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "0.3.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||||
},
|
},
|
||||||
"json-stringify-safe": {
|
"json-stringify-safe": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
@@ -429,9 +421,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.11",
|
"version": "4.17.15",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||||
},
|
},
|
||||||
"long": {
|
"long": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
@@ -482,14 +474,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.22.2",
|
"version": "2.25.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.25.1.tgz",
|
||||||
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
|
"integrity": "sha512-nRKMf9wDS4Fkyd0C9LXh2FFXinD+iwbJ5p/lh3CHitW9kZbRbJ8hCruiadiIXZVbeAqKZzqcTvHnK3mRhFjb6w=="
|
||||||
},
|
},
|
||||||
"moment-timezone": {
|
"moment-timezone": {
|
||||||
"version": "0.5.21",
|
"version": "0.5.28",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz",
|
||||||
"integrity": "sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A==",
|
"integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"moment": ">= 2.9.0"
|
"moment": ">= 2.9.0"
|
||||||
}
|
}
|
||||||
@@ -505,12 +497,12 @@
|
|||||||
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA=="
|
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA=="
|
||||||
},
|
},
|
||||||
"node-cache": {
|
"node-cache": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.2.1.tgz",
|
||||||
"integrity": "sha512-obRu6/f7S024ysheAjoYFEEBqqDWv4LOMNJEuO8vMeEw2AT4z+NCzO4hlc2lhI4vATzbCQv6kke9FVdx0RbCOw==",
|
"integrity": "sha512-BOb67bWg2dTyax5kdef5WfU3X8xu4wPg+zHzkvls0Q/QpYycIFRLEEIdAx9Wma43DxG6Qzn4illdZoYseKWa4A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"clone": "2.x",
|
"clone": "2.x",
|
||||||
"lodash": "4.x"
|
"lodash": "^4.17.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-icu-charset-detector": {
|
"node-icu-charset-detector": {
|
||||||
@@ -534,11 +526,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-schedule": {
|
"node-schedule": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-1.3.2.tgz",
|
||||||
"integrity": "sha512-NNwO9SUPjBwFmPh3vXiPVEhJLn4uqYmZYvJV358SRGM06BR4UoIqxJpeJwDDXB6atULsgQA97MfD1zMd5xsu+A==",
|
"integrity": "sha512-GIND2pHMHiReSZSvS6dpZcDH7pGPGFfWBIEud6S00Q8zEIzAs9ommdyRK1ZbQt8y1LyZsJYZgPnyi7gpU2lcdw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"cron-parser": "^2.4.0",
|
"cron-parser": "^2.7.3",
|
||||||
"long-timeout": "0.1.1",
|
"long-timeout": "0.1.1",
|
||||||
"sorted-array-functions": "^1.0.0"
|
"sorted-array-functions": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -549,9 +541,9 @@
|
|||||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||||
},
|
},
|
||||||
"object-keys": {
|
"object-keys": {
|
||||||
"version": "1.0.12",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
"integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
|
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
|
||||||
},
|
},
|
||||||
"obs-websocket-js": {
|
"obs-websocket-js": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -597,9 +589,9 @@
|
|||||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||||
},
|
},
|
||||||
"prism-media": {
|
"prism-media": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.4.tgz",
|
||||||
"integrity": "sha512-c9KkNifSMU/iXT8FFTaBwBMr+rdVcN+H/uNv1o+CuFeTThNZNTOrQ+RgXA1yL/DeLk098duAeRPP3QNPNbhxYQ=="
|
"integrity": "sha512-dG2w7WtovUa4SiYTdWn9H8Bd4JNdei2djtkP/Bk9fXq81j5Q15ZPHYSwhUVvBRbp5zMkGtu0Yk62HuMcly0pRw=="
|
||||||
},
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -607,14 +599,14 @@
|
|||||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||||
},
|
},
|
||||||
"psl": {
|
"psl": {
|
||||||
"version": "1.1.29",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
|
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
|
||||||
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
|
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
|
||||||
},
|
},
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "1.4.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
},
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
@@ -662,9 +654,9 @@
|
|||||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
|
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"version": "2.88.0",
|
"version": "2.88.2",
|
||||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"aws-sign2": "~0.7.0",
|
"aws-sign2": "~0.7.0",
|
||||||
"aws4": "^1.8.0",
|
"aws4": "^1.8.0",
|
||||||
@@ -673,7 +665,7 @@
|
|||||||
"extend": "~3.0.2",
|
"extend": "~3.0.2",
|
||||||
"forever-agent": "~0.6.1",
|
"forever-agent": "~0.6.1",
|
||||||
"form-data": "~2.3.2",
|
"form-data": "~2.3.2",
|
||||||
"har-validator": "~5.1.0",
|
"har-validator": "~5.1.3",
|
||||||
"http-signature": "~1.2.0",
|
"http-signature": "~1.2.0",
|
||||||
"is-typedarray": "~1.0.0",
|
"is-typedarray": "~1.0.0",
|
||||||
"isstream": "~0.1.2",
|
"isstream": "~0.1.2",
|
||||||
@@ -683,52 +675,9 @@
|
|||||||
"performance-now": "^2.1.0",
|
"performance-now": "^2.1.0",
|
||||||
"qs": "~6.5.2",
|
"qs": "~6.5.2",
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"tough-cookie": "~2.4.3",
|
"tough-cookie": "~2.5.0",
|
||||||
"tunnel-agent": "^0.6.0",
|
"tunnel-agent": "^0.6.0",
|
||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"combined-stream": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
|
|
||||||
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
|
|
||||||
"requires": {
|
|
||||||
"delayed-stream": "~1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extend": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
|
||||||
},
|
|
||||||
"form-data": {
|
|
||||||
"version": "2.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
|
|
||||||
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "1.0.6",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mime-db": {
|
|
||||||
"version": "1.35.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
|
|
||||||
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
|
|
||||||
},
|
|
||||||
"mime-types": {
|
|
||||||
"version": "2.1.19",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
|
|
||||||
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
|
|
||||||
"requires": {
|
|
||||||
"mime-db": "~1.35.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"qs": {
|
|
||||||
"version": "6.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
|
||||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
@@ -769,9 +718,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sshpk": {
|
"sshpk": {
|
||||||
"version": "1.14.2",
|
"version": "1.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
|
||||||
"integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
|
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"asn1": "~0.2.3",
|
"asn1": "~0.2.3",
|
||||||
"assert-plus": "^1.0.0",
|
"assert-plus": "^1.0.0",
|
||||||
@@ -782,6 +731,13 @@
|
|||||||
"jsbn": "~0.1.0",
|
"jsbn": "~0.1.0",
|
||||||
"safer-buffer": "^2.0.2",
|
"safer-buffer": "^2.0.2",
|
||||||
"tweetnacl": "~0.14.0"
|
"tweetnacl": "~0.14.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||||
|
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
@@ -825,12 +781,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "2.4.3",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||||
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
|
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"psl": "^1.1.24",
|
"psl": "^1.1.28",
|
||||||
"punycode": "^1.4.1"
|
"punycode": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tunnel-agent": {
|
"tunnel-agent": {
|
||||||
@@ -842,10 +798,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tweetnacl": {
|
"tweetnacl": {
|
||||||
"version": "0.14.5",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
||||||
"optional": true
|
},
|
||||||
|
"uri-js": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||||
|
"requires": {
|
||||||
|
"punycode": "^2.1.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"util-deprecate": {
|
"util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -853,9 +816,9 @@
|
|||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
},
|
},
|
||||||
"verror": {
|
"verror": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
@@ -876,19 +839,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "4.1.0",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||||
"integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==",
|
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"async-limiter": "~1.0.0",
|
"async-limiter": "~1.0.0"
|
||||||
"safe-buffer": "~5.1.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"safe-buffer": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -4,20 +4,20 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^2.6.1",
|
"async": "^2.6.3",
|
||||||
"axios": "^0.19.2",
|
"axios": "^0.19.2",
|
||||||
"discord.js": "^11.4.2",
|
"discord.js": "^11.6.4",
|
||||||
"ffmpeg-binaries": "^3.2.2",
|
"ffmpeg-binaries": "^3.2.2",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"irc": "^0.5.2",
|
"irc": "^0.5.2",
|
||||||
"md5": "^2.2.1",
|
"md5": "^2.2.1",
|
||||||
"memcache": "^0.3.0",
|
"memcache": "^0.3.0",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.25.1",
|
||||||
"node-cache": "^4.2.0",
|
"node-cache": "^4.2.1",
|
||||||
"node-opus": "^0.2.9",
|
"node-opus": "^0.2.9",
|
||||||
"node-schedule": "^1.3.0",
|
"node-schedule": "^1.3.2",
|
||||||
"obs-websocket-js": "^1.2.0",
|
"obs-websocket-js": "^1.2.0",
|
||||||
"request": "^2.88.0",
|
"request": "^2.88.2",
|
||||||
"spotify-web-api-node": "^4.0.0"
|
"spotify-web-api-node": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
|
|||||||
Reference in New Issue
Block a user