vrmode timer, user skip voting
This commit is contained in:
7
conf/timers.json
Executable file
7
conf/timers.json
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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]"
|
||||||
|
}
|
||||||
|
]
|
||||||
55
fgfm.TODO
55
fgfm.TODO
@@ -1,42 +1,24 @@
|
|||||||
- Ability to control stream from web or twitch
|
|
||||||
- The OBS "director" and its state need to be accessible from both
|
|
||||||
- How to accomplish this? Websocket?
|
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
✔ Add cooldowns @done (18-10-02 10:16)
|
☐ Have director emit events for bots to listen to
|
||||||
☐ Silence detection
|
- show status changing
|
||||||
- If stream has been silent for more than X minutes, try skipping song
|
- video starting/ending/skipped
|
||||||
|
☐ Auto-enable vrmode timer when show starts (listen for event)
|
||||||
☐ Start/stop stream automation
|
☐ Start/stop stream automation
|
||||||
☐ Set up the queue upon init so it can be managed during startup
|
☐ Support scheduled start/stop
|
||||||
|
- instead of countdown for X seconds, use datetime argument
|
||||||
☐ Start
|
☐ Start
|
||||||
✔ Start stream @done (18-10-26 09:44)
|
|
||||||
✔ Starting Soon is shown until countdown is triggered @done (18-10-26 09:44)
|
|
||||||
- Add parameter for countdown
|
|
||||||
- Countdown for X minutes is triggered and shown
|
- Countdown for X minutes is triggered and shown
|
||||||
- Once countdown finishes, switch to intro scene and play
|
- Once countdown finishes, switch to intro scene and play
|
||||||
- Switch to fgfm once intro finishes
|
- Switch to fgfm once intro finishes
|
||||||
☐ Stop
|
|
||||||
- Parameter for how long until the stream should end
|
|
||||||
- Switch to credits with 1 minute remaining
|
|
||||||
- Fade out audio sources with 5 seconds left
|
|
||||||
- Stop Stream
|
|
||||||
☐ Fix commercial playing issue (switches back to scene early)
|
|
||||||
☐ Change $auw and $meme to queue up the videos just like the others (don't switch scenes)
|
|
||||||
☐ Don't auto-init GHOBS or FGFM, make them on-demand
|
|
||||||
☐ Decouple twitch chat from GHOBS
|
☐ Decouple twitch chat from GHOBS
|
||||||
☐ Move anything that calls director.state from app into fgfm lib
|
☐ Move anything that calls director.state from app into fgfm lib
|
||||||
☐ Restrict # of requests a user can have in the queue at once
|
☐ Restrict # of requests a user can have in the queue at once
|
||||||
☐ Move vrmode timer to this bot, delete from SLCB
|
|
||||||
☐ Room vid requests / import
|
☐ Room vid requests / import
|
||||||
☐ Improved interface for viewer requests
|
☐ Improved interface for viewer requests
|
||||||
☐ Web interface? Twitch extension?
|
☐ Web interface? Twitch extension?
|
||||||
☐ Improvements
|
☐ Improvements
|
||||||
☐ When playing a room back, loop it at slower speeds for a few iterations
|
☐ When playing a room back, loop it at slower speeds for a few iterations
|
||||||
☐ Support viewer $skip voting
|
☐ Support adding sets of videos to the queue at once (like the entire ttas or all gold segments)
|
||||||
☐ Remove currently playing video from vote choices
|
|
||||||
☐ Command to add sets of videos to the queue at once (like the entire ttas or all gold segments)
|
|
||||||
☐ Command to stop video rotation / timers (shutdown)
|
|
||||||
☐ Support for $pause (pauses queue after current video finishes)
|
|
||||||
☐ Tool to output list of video ID's / descriptions
|
☐ Tool to output list of video ID's / descriptions
|
||||||
☐ Stream alerts for chat
|
☐ Stream alerts for chat
|
||||||
☐ Rotating background images (leftside)
|
☐ Rotating background images (leftside)
|
||||||
@@ -45,6 +27,8 @@ TODO:
|
|||||||
- !bender
|
- !bender
|
||||||
- !carlton
|
- !carlton
|
||||||
- !weeb
|
- !weeb
|
||||||
|
☐ Fix commercial playing issue (switches back to scene early)
|
||||||
|
☐ Change $auw and $meme to queue up the videos just like the others (don't switch scenes)
|
||||||
|
|
||||||
Ideas:
|
Ideas:
|
||||||
☐ Web interface for viewers to issue commands -- twitch extension?!
|
☐ Web interface for viewers to issue commands -- twitch extension?!
|
||||||
@@ -62,6 +46,27 @@ StreamWebRemote:
|
|||||||
|
|
||||||
___________________
|
___________________
|
||||||
Archive:
|
Archive:
|
||||||
|
✔ Remove currently playing video from vote choices @done (18-10-30 11:51) @project(TODO)
|
||||||
|
✔ track votes for the current playing video @done (18-10-30 11:48) @project(TODO)
|
||||||
|
✔ if threshold is met, skip @done (18-10-30 11:48) @project(TODO)
|
||||||
|
✔ config item for how many votes are required to skip @done (18-10-30 11:48) @project(TODO)
|
||||||
|
✔ clear votes after video finishes @done (18-10-30 11:48) @project(TODO)
|
||||||
|
✔ Support viewer $skip voting @done (18-10-30 11:48) @project(TODO)
|
||||||
|
✔ update director showStatus to 'PAUSED' @done (18-10-30 11:33) @project(TODO)
|
||||||
|
✔ have nextVideo check for PAUSED @done (18-10-30 11:33) @project(TODO)
|
||||||
|
✔ Support for $pause (pauses queue after current video finishes) @done (18-10-30 11:33) @project(TODO)
|
||||||
|
✔ Move vrmode timer to this bot, delete from SLCB @done (18-10-30 11:20) @project(TODO)
|
||||||
|
✔ Don't auto-init GHOBS or FGFM, make them on-demand @done (18-10-30 08:26) @project(TODO)
|
||||||
|
✔ Switch to credits with 1 minute remaining @done (18-10-30 08:15) @project(TODO)
|
||||||
|
✔ Stop Stream @done (18-10-30 08:15) @project(TODO)
|
||||||
|
✔ Stop @done (18-10-30 08:15) @project(TODO)
|
||||||
|
✔ Parameter for how long until the stream should end @done (18-10-30 08:15) @project(TODO)
|
||||||
|
✔ Fade out audio sources with 5 seconds left @done (18-10-30 08:15) @project(TODO)
|
||||||
|
✔ Add parameter for countdown @done (18-10-30 08:15) @project(TODO)
|
||||||
|
✔ Set up the queue upon init so it can be managed during startup @done (18-10-30 08:14) @project(TODO)
|
||||||
|
✔ Starting Soon is shown until countdown is triggered @done (18-10-26 09:44) @project(TODO)
|
||||||
|
✔ Start stream @done (18-10-26 09:44) @project(TODO)
|
||||||
|
✔ Add cooldowns @done (18-10-02 10:16) @project(TODO)
|
||||||
✔ video length @done (18-09-28 09:33) @project(TODO)
|
✔ video length @done (18-09-28 09:33) @project(TODO)
|
||||||
✔ root folder name @done (18-09-28 09:33) @project(TODO)
|
✔ root folder name @done (18-09-28 09:33) @project(TODO)
|
||||||
✔ room ID @done (18-09-28 09:33) @project(TODO)
|
✔ room ID @done (18-09-28 09:33) @project(TODO)
|
||||||
|
|||||||
92
fgfm.js
92
fgfm.js
@@ -6,6 +6,7 @@
|
|||||||
const irc = require('irc');
|
const irc = require('irc');
|
||||||
const schedule = require('node-schedule');
|
const schedule = require('node-schedule');
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
|
const moment = require('moment');
|
||||||
|
|
||||||
// Import local packages
|
// Import local packages
|
||||||
const GHOBS = require('./lib/ghobs');
|
const GHOBS = require('./lib/ghobs');
|
||||||
@@ -18,6 +19,15 @@ let config = require('./config.json');
|
|||||||
config.vods = require(config.vodConfigFile);
|
config.vods = require(config.vodConfigFile);
|
||||||
config.rooms = require(config.roomConfigFile);
|
config.rooms = require(config.roomConfigFile);
|
||||||
let snesGames = require('./conf/snesgames.json');
|
let snesGames = require('./conf/snesgames.json');
|
||||||
|
let timersList = require('./conf/timers.json');
|
||||||
|
|
||||||
|
let activeTimers = [];
|
||||||
|
let skipVote = {
|
||||||
|
target: null,
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
|
// @TODO: Move to config
|
||||||
|
config.skipVoteThreshold = 2;
|
||||||
|
|
||||||
// Main screen turn on
|
// Main screen turn on
|
||||||
const obs = new GHOBS(config);
|
const obs = new GHOBS(config);
|
||||||
@@ -80,6 +90,7 @@ const streamInit = (config, twitch) => {
|
|||||||
|
|
||||||
init: (cmd) => {
|
init: (cmd) => {
|
||||||
let delaySeconds = cmd.args[1] || 300;
|
let delaySeconds = cmd.args[1] || 300;
|
||||||
|
|
||||||
director.startingSoon(delaySeconds);
|
director.startingSoon(delaySeconds);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -129,6 +140,49 @@ const streamInit = (config, twitch) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
timer: (cmd) => {
|
||||||
|
let timerName = cmd.args[1] || false;
|
||||||
|
if (!timerName) {
|
||||||
|
twitch.botChat.say(cmd.to, `A timer name is required!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search timers for matching name
|
||||||
|
let theTimerIndex = timersList.findIndex(e => e.name === timerName);
|
||||||
|
if (theTimerIndex === -1) {
|
||||||
|
twitch.botChat.say(cmd.to, `Invalid timer name!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let theTimer = timersList[theTimerIndex];
|
||||||
|
|
||||||
|
// look in activeTimers for current status
|
||||||
|
let currentTimerIndex = activeTimers.findIndex(e => e.name === timerName);
|
||||||
|
|
||||||
|
let timerStatus = cmd.args[2] || false;
|
||||||
|
if (!timerStatus || timerStatus !== 'on' || timerStatus !== 'off') {
|
||||||
|
// toggle by default
|
||||||
|
if (currentTimerIndex === -1) {
|
||||||
|
timerStatus = 'on';
|
||||||
|
} else {
|
||||||
|
timerStatus = 'off';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTimerIndex === -1 && timerStatus === 'on') {
|
||||||
|
let timerFunc = () => {
|
||||||
|
twitch.botChat.say(config.twitch.channel, theTimer.value);
|
||||||
|
};
|
||||||
|
let timerInterval = setInterval(timerFunc, theTimer.interval*1000);
|
||||||
|
activeTimers.push({name: theTimer.name, timer: timerInterval});
|
||||||
|
timerFunc();
|
||||||
|
} else if (timerStatus === 'off') {
|
||||||
|
clearInterval(activeTimers[currentTimerIndex].timer);
|
||||||
|
activeTimers.splice(currentTimerIndex, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
auw: (cmd) => {
|
auw: (cmd) => {
|
||||||
director.showMeme('auw');
|
director.showMeme('auw');
|
||||||
},
|
},
|
||||||
@@ -220,6 +274,16 @@ const streamInit = (config, twitch) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
pause: (cmd) => {
|
||||||
|
director.pause();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
resume: (cmd) => {
|
||||||
|
director.resume();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
clear: (cmd) => {
|
clear: (cmd) => {
|
||||||
director.clearQueue();
|
director.clearQueue();
|
||||||
},
|
},
|
||||||
@@ -374,7 +438,25 @@ const streamInit = (config, twitch) => {
|
|||||||
|
|
||||||
rngames: (cmd) => {
|
rngames: (cmd) => {
|
||||||
twitch.botChat.say(cmd.to, snesGames.sort(util.randSort).slice(0, 10).join(' | '));
|
twitch.botChat.say(cmd.to, snesGames.sort(util.randSort).slice(0, 10).join(' | '));
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// voting to skip current video
|
||||||
|
skip: (cmd) => {
|
||||||
|
// check if there is an existing vote to skip for the director.state.currentVideo
|
||||||
|
if (skipVote.target === director.state.currentVideo.id) {
|
||||||
|
// if yes, add the vote, check if threshold is met, skip if necessary
|
||||||
|
skipVote.count++;
|
||||||
|
} else {
|
||||||
|
skipVote.target = director.state.currentVideo.id;
|
||||||
|
skipVote.count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skipVote.count >= config.skipVoteThreshold) {
|
||||||
|
director.skip();
|
||||||
|
skipVote.target = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -425,6 +507,8 @@ const streamInit = (config, twitch) => {
|
|||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// @TODO: Modularize timed events
|
// @TODO: Modularize timed events
|
||||||
//console.log(`Initializing stream timers...`);
|
//console.log(`Initializing stream timers...`);
|
||||||
let userVotes = currentChoices = [];
|
let userVotes = currentChoices = [];
|
||||||
@@ -477,7 +561,7 @@ const streamInit = (config, twitch) => {
|
|||||||
// choose more random videos from config.vods.alttp (that aren't already in the queue)
|
// choose more random videos from config.vods.alttp (that aren't already in the queue)
|
||||||
// @TODO: Move into FGFM
|
// @TODO: Move into FGFM
|
||||||
let vodsNotInQueue = config.vods.alttp.filter(e => {
|
let vodsNotInQueue = config.vods.alttp.filter(e => {
|
||||||
let inQueue = director.state.videoQueue.findIndex(q => q.id === e.id) !== -1;
|
let inQueue = (director.state.videoQueue.findIndex(q => q.id === e.id) !== -1) && (director.state.currentVideo.id !== e.id);
|
||||||
return !inQueue;
|
return !inQueue;
|
||||||
});
|
});
|
||||||
currentChoices = vodsNotInQueue.sort(util.randSort).slice(0, config.videoPollSize);
|
currentChoices = vodsNotInQueue.sort(util.randSort).slice(0, config.videoPollSize);
|
||||||
@@ -496,5 +580,11 @@ const streamInit = (config, twitch) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const startTimer = (timer) => {
|
||||||
|
setInterval(() => {
|
||||||
|
|
||||||
|
}, timer.interval*1000);
|
||||||
|
};
|
||||||
|
|
||||||
// catches Promise errors
|
// catches Promise errors
|
||||||
process.on('unhandledRejection', console.error);
|
process.on('unhandledRejection', console.error);
|
||||||
|
|||||||
14
lib/fgfm.js
14
lib/fgfm.js
@@ -157,7 +157,8 @@ function FGFM(config) {
|
|||||||
// Also handles "commercial breaks" if enabled
|
// Also handles "commercial breaks" if enabled
|
||||||
this.nextVideo = () => {
|
this.nextVideo = () => {
|
||||||
// @TODO: Validate this.state.showStatus -- make sure the "show" hasn't been paused or stopped
|
// @TODO: Validate this.state.showStatus -- make sure the "show" hasn't been paused or stopped
|
||||||
if (this.state.showStatus === 'ENDING' || this.state.showStatus === 'ENDED') {
|
let ignoreStates = ['ENDING', 'ENDED', 'PAUSED'];
|
||||||
|
if (ignoreStates.includes(this.state.showStatus)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +283,16 @@ function FGFM(config) {
|
|||||||
// Clears.. the... queue
|
// Clears.. the... queue
|
||||||
this.clearQueue = () => {
|
this.clearQueue = () => {
|
||||||
this.state.videoQueue = [];
|
this.state.videoQueue = [];
|
||||||
}
|
};
|
||||||
|
|
||||||
|
this.pause = () => {
|
||||||
|
this.state.showStatus = 'PAUSED';
|
||||||
|
};
|
||||||
|
|
||||||
|
this.resume = () => {
|
||||||
|
this.state.showStatus = 'RUNNING';
|
||||||
|
this.nextVideo();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FGFM;
|
module.exports = FGFM;
|
||||||
|
|||||||
BIN
sfx/mouthfeel.mp3
Executable file
BIN
sfx/mouthfeel.mp3
Executable file
Binary file not shown.
Reference in New Issue
Block a user