room vid automation

This commit is contained in:
Chris Ham
2018-09-26 21:37:45 -07:00
parent b9568c7362
commit fa9c40fb0f
6 changed files with 76 additions and 38 deletions

File diff suppressed because one or more lines are too long

View File

@@ -37,21 +37,21 @@
"defaultSceneName": "fgfm", "defaultSceneName": "fgfm",
"commercialSceneName": "commercial", "commercialSceneName": "commercial",
"currentActivitySceneItemName": "now-showing-txt", "currentActivitySceneItemName": "now-showing-txt",
"initialQueueSize": 1, "initialQueueSize": 3,
"recentlyPlayedMemory": 5, "recentlyPlayedMemory": 5,
"roomGrindChance": 25, "roomGrindChance": 25,
"roomGrindPlaytime": 1800, "roomGrindPlaytime": 900,
"roomShuffleChance": 85,
"roomVidPlaytime": 150,
"roomShuffleCount": 6,
"videoPollSize": 5, "videoPollSize": 5,
"videoPollIntervalMinutes": 15, "videoPollIntervalMinutes": 15,
"commercialsEnabled": false, "commercialsEnabled": false,
"commercialInterval": 3600, "commercialInterval": 3600,
"auwChance": 25, "auwChance": 25,
"defaultSRVolume": 75, "defaultSRVolume": 50,
"vodConfigFile": "./conf/vods.json", "vodConfigFile": "./conf/vods.json",
"roomConfigFile": "./conf/rooms.json", "roomConfigFile": "./conf/rooms.json",
"roomVidsBasePath": "Y:\\media\\videos\\ALttP\\my-vids\\room-vids", "roomVidsBasePath": "Y:\\media\\videos\\ALttP\\my-vids\\room-vids",
"roomVidPlaytime": 60,
"roomShuffleChance": 85,
"roomShuffleCount": 15,
"debug": false "debug": false
} }

View File

@@ -1,6 +1,10 @@
TODO: TODO:
✔ Fix queue to only return first 20 or so @done (18-09-26 12:04)
✔ Update the queue to support looping @done (18-09-26 18:28)
✔ specify # of loops in video object @done (18-09-26 18:28)
✔ change source to loop? calculate time? @done (18-09-26 18:28)
☐ Room vid requests / import ☐ Room vid requests / import
Importing Importing @done (18-09-26 08:25)
- Read the Y:\media\videos\ALttP\my-vids\room-vids directory - Read the Y:\media\videos\ALttP\my-vids\room-vids directory
- Go through each folder and get all the .mp4 files - Go through each folder and get all the .mp4 files
- Store the following as metadata: - Store the following as metadata:
@@ -10,6 +14,11 @@ TODO:
- dungeon (parse from root folder name) - dungeon (parse from root folder name)
- room ID - room ID
- video length - video length
☐ Requests
☐ Web interface? Twitch extension?
☐ Improvements
☐ When playing a room back, loop it at slower speeds for a few iterations
✔ Look into just making the video loop instead of hiding at the end @done (18-09-26 18:29)
☐ Support viewer skip voting ☐ Support viewer skip voting
☐ Remove currently playing video from vote choices ☐ 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 add sets of videos to the queue at once (like the entire ttas or all gold segments)

31
fgfm.js
View File

@@ -68,7 +68,7 @@ const twitchInit = (config) => {
botChat.addListener('error', twitchErrorHandler); botChat.addListener('error', twitchErrorHandler);
editorChat.addListener('error', twitchErrorHandler); editorChat.addListener('error', twitchErrorHandler);
resolve({"botChat": botChat, "editorChat": editorChat}); resolve({"botChat": botChat, "editorChat": editorChat, "controlRoom": controlRoom});
}); });
}; };
@@ -116,19 +116,18 @@ const streamInit = (config, twitch) => {
if (typeof loop === 'undefined' || loop === true) { if (typeof loop === 'undefined' || loop === true) {
loops = Math.floor(config.roomVidPlaytime / room.videoData.length); loops = Math.floor(config.roomVidPlaytime / room.videoData.length);
} }
console.log(`Adding ${loops} instances of room video for ${room.dungeonName} - ${room.roomName} to the queue`); console.log(`Adding room video for ${room.dungeonName} - ${room.roomName} to the queue (${loops} loops)`);
let video = { let video = {
"filePath": `${config.roomVidsBasePath}${room.winPath}`, "filePath": `${config.roomVidsBasePath}${room.winPath}`,
"sceneItem": (room.videoData.width === 960) ? "4x3ph" : "16x9ph", "sceneItem": (room.videoData.width === 960) ? "4x3ph" : "16x9ph",
"length": room.videoData.length, "length": room.videoData.length,
"label": room.roomName, "label": room.roomName,
"chatName": room.roomName "chatName": room.roomName,
"loops": loops
}; };
for (var i = 0; i < loops; i++) {
state.videoQueue.push(video); state.videoQueue.push(video);
}
}; };
// Picks the next video in the queue (shuffles if empty) // Picks the next video in the queue (shuffles if empty)
@@ -261,7 +260,7 @@ const streamInit = (config, twitch) => {
let commandNoPrefix = commandParts[0] || ''; let commandNoPrefix = commandParts[0] || '';
// ADMIN COMMANDS // ADMIN COMMANDS
if (config.twitch.admins.includes(from) || from === config.twitch.username.toLowerCase()) { if (config.twitch.admins.includes(from)) {
// SHOW/HIDE SOURCE // SHOW/HIDE SOURCE
if (commandNoPrefix === 'show' || commandNoPrefix === 'hide') { if (commandNoPrefix === 'show' || commandNoPrefix === 'hide') {
@@ -286,21 +285,25 @@ const streamInit = (config, twitch) => {
obs.toggleVisible(sceneItem).catch(console.error); obs.toggleVisible(sceneItem).catch(console.error);
// ROOM VIDS // ROOM VID REQUESTS
} else if (commandNoPrefix === 'room') { } else if (commandNoPrefix === 'room') {
let roomId = commandParts[1] || false; let roomId = commandParts[1] || false;
if (roomId.length !== 4) { let room;
twitch.botChat.say(to, `Please provide a 4-digit room ID!`);
return; if (roomId !== false) {
} let roomIndex = config.rooms.findIndex(e => e.id === parseInt(roomId));
let roomIndex = config.rooms.findIndex(e => e.dungeonId === roomId.substring(0,2) && e.roomId === roomId.substring(2,4));
if (roomIndex === -1) { if (roomIndex === -1) {
twitch.botChat.say(to, `No room found matching that ID!`); twitch.botChat.say(to, `No room found matching that ID!`);
return; return;
} }
let room = config.rooms[roomIndex]; room = config.rooms[roomIndex];
} else {
// choose a room at random
room = config.rooms.sort(util.randSort).slice(0, 1).shift();
}
addRoomVideo(room); addRoomVideo(room);
twitch.botChat.say(to, `Added ${room.dungeonName} - ${room.roomName} to the queue!`); twitch.botChat.say(to, `Added ${room.dungeonName} - ${room.roomName} to the queue!`);
@@ -436,7 +439,7 @@ const streamInit = (config, twitch) => {
// QUEUE STATUS // QUEUE STATUS
} else if (commandNoPrefix === 'queue') { } else if (commandNoPrefix === 'queue') {
if (state.videoQueue.length > 0) { if (state.videoQueue.length > 0) {
let chatQueue = state.videoQueue.map((c, i) => { let chatQueue = state.videoQueue.slice(0, 10).map((c, i) => {
return `[${i+1}] ${c.chatName}`; return `[${i+1}] ${c.chatName}`;
}); });
twitch.botChat.say(to, chatQueue.join(' | ')); twitch.botChat.say(to, chatQueue.join(' | '));

View File

@@ -12,7 +12,7 @@ function GHOBS(config) {
console.log(`Success! We're connected to OBS!`); console.log(`Success! We're connected to OBS!`);
this.websocket.getCurrentScene().then(res => this.currentScene = res.name); this.websocket.getCurrentScene().then(res => this.currentScene = res.name);
this.websocket.onSwitchScenes(data => { this.websocket.onSwitchScenes(data => {
console.log(`New Active Scene: ${data.sceneName}`); //console.log(`New Active Scene: ${data.sceneName}`);
this.currentScene = data.sceneName; this.currentScene = data.sceneName;
}); });
resolve(); resolve();
@@ -32,28 +32,51 @@ function GHOBS(config) {
this.playVideoInScene = (video, scene, callback) => { this.playVideoInScene = (video, scene, callback) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let originalScene = this.currentScene || false; let originalScene = this.currentScene || false;
console.log(`Changing scene from ${originalScene} to ${scene}`); //console.log(`Changing scene from ${originalScene} to ${scene}`);
this.websocket.setCurrentScene({"scene-name": scene}) this.websocket.setCurrentScene({"scene-name": scene})
.then(res => { .then(res => {
// set the file path on the source // set the file path on the source
console.log(`Setting file path to: ${video.filePath}`); //console.log(`Setting file path to: ${video.filePath}`);
this.websocket.setSourceSettings({"sourceName": video.sceneItem, "sourceSettings": {"local_file": video.filePath}}) let sourceSettings = {
"local_file": video.filePath,
"looping": (typeof video.loops !== 'undefined' && video.loops > 1)
};
sourceSettings.loop = sourceSettings.looping;
// @TODO support any sourceSetting
//
/*{ close_when_inactive: true,
local_file: 'Y:\\media\\videos\\ALttP\\my-vids\\room-vids\\11-mire\\38-wizzpot-rta-hook-610.mp4',
loop: true,
looping: false,
restart_on_activate: false,
speed_percent: 100 }*/
//this.websocket.getSourceSettings({"sourceName": video.sceneItem}).then(console.log);
this.websocket.setSourceSettings({"sourceName": video.sceneItem, "sourceSettings": sourceSettings})
// show the video scene item // show the video scene item
.then(data => {console.log(`Showing ${video.sceneItem}`); this.websocket.setSceneItemProperties({"item": video.sceneItem, "scene-name": scene, "visible": true})}) .then(() => this.websocket.setSceneItemProperties({"item": video.sceneItem, "scene-name": scene, "visible": true}))
// when the video is over, hide it and trigger the user callback, but resolve promise immediately with the timer // when the video is over, hide it and trigger the user callback, but resolve promise immediately with the timer
.then(data => { .then(data => {
// adjust timeout length to allow the requested number of loops to complete
if (sourceSettings.loop === true) {
video.length *= video.loops;
console.log(`Video is set to loop, adjusted length to ${video.length}`);
}
resolve(setTimeout(() => { resolve(setTimeout(() => {
console.log(`Hiding ${video.sceneItem}`); //console.log(`Hiding ${video.sceneItem}`);
this.websocket.setSceneItemProperties({"item": video.sceneItem, "scene-name": scene, "visible": false}); this.websocket.setSceneItemProperties({"item": video.sceneItem, "scene-name": scene, "visible": false});
if (originalScene) { if (originalScene) {
console.log(`Switching scene back to ${originalScene}`); //console.log(`Switching scene back to ${originalScene}`);
this.websocket.setCurrentScene({"scene-name": originalScene}); this.websocket.setCurrentScene({"scene-name": originalScene});
} }
if (typeof callback !== 'undefined') { if (typeof callback !== 'undefined') {
console.log('Triggering user callback'); //console.log('Triggering user callback');
callback(data); callback(data);
} }
}, video.length*1000)) }, parseInt(video.length*1000)))
}); });
}) })
.catch(reject); .catch(reject);

View File

@@ -18,14 +18,15 @@ populateDatabase();
async function populateDatabase() { async function populateDatabase() {
let database = []; let database = [];
await util.asyncForEach(roomVidFiles, async (file) => { await util.asyncForEach(roomVidFiles, async (file, index) => {
// @TODO: ignore anything that's not an mp4 // ignore anything that's not an mp4
let shortPath = file.replace(roomVidPath, ''); let shortPath = file.replace(roomVidPath, '');
if (!/\.mp4$/.test(shortPath)) { if (!/\.mp4$/.test(shortPath)) {
return; return;
} }
let entry = { let entry = {
id: index+1,
shortPath: shortPath, shortPath: shortPath,
winPath: shortPath.replace(/\//g, '\\') winPath: shortPath.replace(/\//g, '\\')
}; };
@@ -39,6 +40,8 @@ async function populateDatabase() {
entry.roomName = matches[4]; entry.roomName = matches[4];
} }
// @TODO support some other paths / structures
entry.videoData = await getVideoMetadata(file); entry.videoData = await getVideoMetadata(file);
database.push(entry); database.push(entry);
console.log('added entry', entry); console.log('added entry', entry);