Pushback Schedule mode now works when ending livestreams.
This commit is contained in:
parent
92edd74aaa
commit
b5e54afe99
|
|
@ -51,6 +51,8 @@ module.exports = class{
|
||||||
this.nowPlaying = null;
|
this.nowPlaying = null;
|
||||||
//Create variable to hold item that was playing during the last liveStream (can't check against full duration since it might've been stopped for other reasons)
|
//Create variable to hold item that was playing during the last liveStream (can't check against full duration since it might've been stopped for other reasons)
|
||||||
this.liveRemainder = null;
|
this.liveRemainder = null;
|
||||||
|
//Create variable to hold current live mode
|
||||||
|
this.liveMode = null;
|
||||||
|
|
||||||
//Create variable to lock standard queuing functions during livestreams
|
//Create variable to lock standard queuing functions during livestreams
|
||||||
this.streamLock = false;
|
this.streamLock = false;
|
||||||
|
|
@ -314,6 +316,8 @@ module.exports = class{
|
||||||
new Date().getTime()
|
new Date().getTime()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Validate mode input, and default to overwrite
|
||||||
|
this.liveMode = (data.mode == "pushback") ? "pushback" : "overwrite";
|
||||||
|
|
||||||
//Throw stream lock
|
//Throw stream lock
|
||||||
this.streamLock = true;
|
this.streamLock = true;
|
||||||
|
|
@ -463,7 +467,7 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async rescheduleMedia(uuid, start = new Date().getTime(), socket){
|
async rescheduleMedia(uuid, start = new Date().getTime(), socket, chanDB){
|
||||||
//If we're streamlocked
|
//If we're streamlocked
|
||||||
if(this.streamLock){
|
if(this.streamLock){
|
||||||
//If an originating socket was provided for this request
|
//If an originating socket was provided for this request
|
||||||
|
|
@ -475,68 +479,92 @@ module.exports = class{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Find our media, don't remove it yet since we want to do some more testing first
|
try{
|
||||||
const media = this.getItemByUUID(uuid);
|
//If we wheren't handed a channel
|
||||||
|
if(chanDB == null){
|
||||||
//If we got a bad request
|
//DO everything ourselves since we don't have a fance end() function to do it
|
||||||
if(media == null){
|
chanDB = await channelModel.findOne({name:this.channel.name});
|
||||||
//If an originating socket was provided for this request
|
|
||||||
if(socket != null){
|
|
||||||
//Yell at the user for being an asshole
|
|
||||||
loggerUtils.socketErrorHandler(socket, "Cannot move non-existant item!", "queue");
|
|
||||||
}
|
}
|
||||||
//Ignore it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If someone is trying to re-schedule something that starts in the past
|
//If we couldn't find the channel
|
||||||
if(media.startTime < new Date().getTime()){
|
if(chanDB == null){
|
||||||
//If an originating socket was provided for this request
|
//FUCK
|
||||||
if(socket != null){
|
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
|
||||||
|
}
|
||||||
|
|
||||||
//If the item is currently playing
|
//Find our media, don't remove it yet since we want to do some more testing first
|
||||||
if(media.getEndTime() > new Date().getTime()){
|
const media = this.getItemByUUID(uuid);
|
||||||
|
|
||||||
|
//If we got a bad request
|
||||||
|
if(media == null){
|
||||||
|
//If an originating socket was provided for this request
|
||||||
|
if(socket != null){
|
||||||
//Yell at the user for being an asshole
|
//Yell at the user for being an asshole
|
||||||
loggerUtils.socketErrorHandler(socket, "You cannot move an actively playing video!", "queue");
|
loggerUtils.socketErrorHandler(socket, "Cannot move non-existant item!", "queue");
|
||||||
//Otherwise, if it's already ended
|
|
||||||
}else{
|
|
||||||
//Yell at the user for being an asshole
|
|
||||||
loggerUtils.socketErrorHandler(socket, "You cannot alter the past!", "queue");
|
|
||||||
}
|
}
|
||||||
|
//Ignore it
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If someone is trying to re-schedule something that starts in the past
|
||||||
|
if(media.startTime < new Date().getTime()){
|
||||||
|
//If an originating socket was provided for this request
|
||||||
|
if(socket != null){
|
||||||
|
//If the item is currently playing
|
||||||
|
if(media.getEndTime() > new Date().getTime()){
|
||||||
|
//Yell at the user for being an asshole
|
||||||
|
loggerUtils.socketErrorHandler(socket, "You cannot move an actively playing video!", "queue");
|
||||||
|
//Otherwise, if it's already ended
|
||||||
|
}else{
|
||||||
|
//Yell at the user for being an asshole
|
||||||
|
loggerUtils.socketErrorHandler(socket, "You cannot alter the past!", "queue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Ignore it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Remove the media from the schedule
|
//Ignore it
|
||||||
await this.removeMedia(uuid);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Grab the old start time for safe keeping
|
//Remove the media from the schedule
|
||||||
const oldStart = media.startTime;
|
await this.removeMedia(uuid, socket, chanDB);
|
||||||
|
|
||||||
//Set media time
|
//Grab the old start time for safe keeping
|
||||||
media.startTime = start;
|
const oldStart = media.startTime;
|
||||||
|
|
||||||
//Reset the start time stamp for re-calculation
|
//Set media time
|
||||||
media.startTimeStamp = 0;
|
media.startTime = start;
|
||||||
|
|
||||||
//Attempt to schedule media at given time
|
|
||||||
//Otherwise, if it returns false for fuckup
|
|
||||||
if(!(await this.scheduleMedia([media], socket))){
|
|
||||||
//Reset start time
|
|
||||||
media.startTime = oldStart;
|
|
||||||
|
|
||||||
//Reset the start time stamp for re-calculation
|
//Reset the start time stamp for re-calculation
|
||||||
media.startTimeStamp = 0;
|
media.startTimeStamp = 0;
|
||||||
|
|
||||||
//Schedule in old slot
|
//Attempt to schedule media at given time
|
||||||
this.scheduleMedia([media], socket, null, true);
|
//Otherwise, if it returns false for fuckup, with noSave enabled
|
||||||
|
if(!(await this.scheduleMedia([media], socket, chanDB))){
|
||||||
|
//Reset start time
|
||||||
|
media.startTime = oldStart;
|
||||||
|
|
||||||
|
//Reset the start time stamp for re-calculation
|
||||||
|
media.startTimeStamp = 0;
|
||||||
|
|
||||||
|
//Schedule in old slot with noSave enabled
|
||||||
|
await this.scheduleMedia([media], socket, chanDB, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
//If this was originated by someone
|
||||||
|
if(socket != null){
|
||||||
|
//Bitch at them
|
||||||
|
loggerUtils.socketExceptionHandler(socket, err);
|
||||||
|
//If not
|
||||||
|
}else{
|
||||||
|
//Bitch to the console
|
||||||
|
loggerUtils.localExceptionHandler(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeMedia(uuid, socket, chanDB){
|
async removeMedia(uuid, socket, chanDB, noScheduling = false){
|
||||||
//If we're streamlocked
|
//If we're streamlocked
|
||||||
if(this.streamLock){
|
if(this.streamLock){
|
||||||
//If an originating socket was provided for this request
|
//If an originating socket was provided for this request
|
||||||
|
|
@ -585,7 +613,6 @@ module.exports = class{
|
||||||
}else{
|
}else{
|
||||||
//Broadcast changes
|
//Broadcast changes
|
||||||
this.broadcastQueue(chanDB);
|
this.broadcastQueue(chanDB);
|
||||||
|
|
||||||
//Save changes to the DB
|
//Save changes to the DB
|
||||||
await chanDB.save();
|
await chanDB.save();
|
||||||
}
|
}
|
||||||
|
|
@ -608,13 +635,18 @@ module.exports = class{
|
||||||
//Take the item out of the schedule map
|
//Take the item out of the schedule map
|
||||||
this.schedule.delete(media.startTime);
|
this.schedule.delete(media.startTime);
|
||||||
|
|
||||||
//Refresh next timer
|
if(!noScheduling){
|
||||||
this.refreshNextTimer();
|
//Refresh next timer
|
||||||
|
this.refreshNextTimer();
|
||||||
|
}
|
||||||
|
|
||||||
//If we're currently playing the requested item.
|
//If we're currently playing the requested item.
|
||||||
if(this.nowPlaying != null && this.nowPlaying.uuid == uuid){
|
if(this.nowPlaying != null && this.nowPlaying.uuid == uuid){
|
||||||
//End playback
|
//If scheduling is enabled
|
||||||
this.end(false, true);
|
if(!noScheduling){
|
||||||
|
//End playback
|
||||||
|
this.end(false, true);
|
||||||
|
}
|
||||||
//otherwise
|
//otherwise
|
||||||
}else{
|
}else{
|
||||||
try{
|
try{
|
||||||
|
|
@ -635,7 +667,10 @@ module.exports = class{
|
||||||
return record.uuid != uuid;
|
return record.uuid != uuid;
|
||||||
});
|
});
|
||||||
|
|
||||||
await chanDB.save();
|
//If saving is enabled (seperate from all DB transactions since caller function may want modifications but handle saving on its own)
|
||||||
|
if(!noScheduling){
|
||||||
|
await chanDB.save();
|
||||||
|
}
|
||||||
|
|
||||||
//Broadcast the channel
|
//Broadcast the channel
|
||||||
this.broadcastQueue(chanDB);
|
this.broadcastQueue(chanDB);
|
||||||
|
|
@ -660,7 +695,7 @@ module.exports = class{
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
async scheduleMedia(media, socket, chanDB, force = false, volatile = false, startVolatile = false, saveLate = false){
|
async scheduleMedia(media, socket, chanDB, force = false, volatile = false, startVolatile = false, saveLate = false, noSave = false){
|
||||||
/* This is a fun method and I think it deserves it's own little explination...
|
/* This is a fun method and I think it deserves it's own little explination...
|
||||||
Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option
|
Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option
|
||||||
I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass.
|
I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass.
|
||||||
|
|
@ -811,8 +846,11 @@ module.exports = class{
|
||||||
//If we fucked with the DB during the main loop
|
//If we fucked with the DB during the main loop
|
||||||
if(chanDB != null && !volatile){
|
if(chanDB != null && !volatile){
|
||||||
try{
|
try{
|
||||||
//Save the database
|
//If saving is enabled (seperate from all DB transactions since caller function may want modifications but handle saving on its own)
|
||||||
chanDB.save();
|
if(!noSave){
|
||||||
|
//Save the database
|
||||||
|
await chanDB.save();
|
||||||
|
}
|
||||||
//If something fucked up
|
//If something fucked up
|
||||||
}catch(err){
|
}catch(err){
|
||||||
//If this was originated by someone
|
//If this was originated by someone
|
||||||
|
|
@ -877,7 +915,7 @@ module.exports = class{
|
||||||
const chanDB = await channelModel.findOne({name: this.channel.name});
|
const chanDB = await channelModel.findOne({name: this.channel.name});
|
||||||
|
|
||||||
//If nowPlaying isn't null and isn't what we're about to throw on
|
//If nowPlaying isn't null and isn't what we're about to throw on
|
||||||
if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.uuid.toString != mediaObj.uuid){
|
if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.uuid.toString() != mediaObj.uuid){
|
||||||
//Archive whats already in there since we're about to clobber the fuck out of it
|
//Archive whats already in there since we're about to clobber the fuck out of it
|
||||||
chanDB.media.archived.push(chanDB.media.nowPlaying);
|
chanDB.media.archived.push(chanDB.media.nowPlaying);
|
||||||
}
|
}
|
||||||
|
|
@ -1034,15 +1072,30 @@ module.exports = class{
|
||||||
//Disable stream lock
|
//Disable stream lock
|
||||||
this.streamLock = false;
|
this.streamLock = false;
|
||||||
|
|
||||||
//We don't have to here since someone else will do it for us :)
|
//We don't have to save here since someone else will do it for us :)
|
||||||
chanDB.media.liveRemainder = null;
|
chanDB.media.liveRemainder = null;
|
||||||
|
|
||||||
//This is where I'd stick the IF statetement I'd add to switch between overwrite
|
//Get current epoch
|
||||||
await this.livestreamOverwriteSchedule(wasPlaying, chanDB)
|
const now = new Date().getTime()
|
||||||
|
|
||||||
|
//Set duration from start and end time
|
||||||
|
wasPlaying.duration = (now - wasPlaying.startTime) / 1000;
|
||||||
|
|
||||||
|
//If we're in pushback mode
|
||||||
|
if(this.liveMode == "pushback"){
|
||||||
|
await this.livestreamPushbackSchedule(wasPlaying, chanDB);
|
||||||
|
//Otherwise
|
||||||
|
}else{
|
||||||
|
//This is where I'd stick the IF statetement I'd add to switch between overwrite
|
||||||
|
await this.livestreamOverwriteSchedule(wasPlaying, chanDB)
|
||||||
|
}
|
||||||
|
|
||||||
//Refresh next timer
|
//Refresh next timer
|
||||||
this.refreshNextTimer();
|
this.refreshNextTimer();
|
||||||
|
|
||||||
|
//Null out live mode
|
||||||
|
this.liveMode = null;
|
||||||
|
|
||||||
//Broadcast Queue
|
//Broadcast Queue
|
||||||
this.broadcastQueue();
|
this.broadcastQueue();
|
||||||
//ACK
|
//ACK
|
||||||
|
|
@ -1075,9 +1128,6 @@ module.exports = class{
|
||||||
//while the other needs to run regardless of this.liveRemainders definition
|
//while the other needs to run regardless of this.liveRemainders definition
|
||||||
let finished = false;
|
let finished = false;
|
||||||
|
|
||||||
//Set duration from start and end time
|
|
||||||
wasPlaying.duration = (now - wasPlaying.startTime) / 1000;
|
|
||||||
|
|
||||||
//Throw the livestream into the archive
|
//Throw the livestream into the archive
|
||||||
chanDB.media.archived.push(wasPlaying);
|
chanDB.media.archived.push(wasPlaying);
|
||||||
|
|
||||||
|
|
@ -1141,6 +1191,87 @@ module.exports = class{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async livestreamPushbackSchedule(wasPlaying, chanDB){
|
||||||
|
try{
|
||||||
|
//Get current epoch
|
||||||
|
const now = new Date().getTime()
|
||||||
|
|
||||||
|
//If we wheren't handed a channel
|
||||||
|
if(chanDB == null){
|
||||||
|
//Now that everything is clean, we can take our time with the DB :P
|
||||||
|
chanDB = await channelModel.findOne({name:this.channel.name});
|
||||||
|
}
|
||||||
|
|
||||||
|
//If we couldn't find the channel
|
||||||
|
if(chanDB == null){
|
||||||
|
//FUCK
|
||||||
|
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Throw the livestream into the archive
|
||||||
|
chanDB.media.archived.push(wasPlaying);
|
||||||
|
|
||||||
|
//Set the current place to schedule items at 5ms after the end of the live stream
|
||||||
|
let curPlace = wasPlaying.getEndTime() + 5;
|
||||||
|
const newSched = [];
|
||||||
|
|
||||||
|
//if we have a live remainder
|
||||||
|
if(this.liveRemainder != null){
|
||||||
|
//Set item to continue where it left off
|
||||||
|
this.liveRemainder.startTimeStamp = this.liveRemainder.earlyEnd;
|
||||||
|
|
||||||
|
//Rip out the early end so it finish up
|
||||||
|
this.liveRemainder.earlyEnd = null;
|
||||||
|
|
||||||
|
//Generate new UUID for uniqueness
|
||||||
|
this.liveRemainder.genUUID();
|
||||||
|
|
||||||
|
//Set start time to the end of the stream
|
||||||
|
this.liveRemainder.startTime = curPlace;
|
||||||
|
|
||||||
|
//Reset starter time to end of current item + 5ms
|
||||||
|
curPlace = this.liveRemainder.getEndTime(true) + 5;
|
||||||
|
|
||||||
|
//Throw live remainder into the new schedule
|
||||||
|
newSched.push(this.liveRemainder);
|
||||||
|
|
||||||
|
//Null out live remainder for the next stream
|
||||||
|
this.liveRemainder = null;
|
||||||
|
chanDB.liveRemainder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Iterate through objects in schedule
|
||||||
|
for(const entry of this.schedule){
|
||||||
|
//Pull media object from map entry
|
||||||
|
const mediaObj = entry[1];
|
||||||
|
|
||||||
|
//Remove media from queue without calling chanDB.save() to make room before we move everything
|
||||||
|
await this.removeMedia(mediaObj.uuid, null, chanDB, true);
|
||||||
|
|
||||||
|
mediaObj.genUUID();
|
||||||
|
|
||||||
|
//Change start time to current starter place
|
||||||
|
mediaObj.startTime = curPlace;
|
||||||
|
|
||||||
|
//Throw item into the temp sched
|
||||||
|
newSched.push(mediaObj);
|
||||||
|
|
||||||
|
//Set cur place to 5ms after the item we just queued
|
||||||
|
curPlace = mediaObj.getEndTime() + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Schedule the moved schedule, letting scheduleMedia save our changes for us, starting w/o saves to prevent over-saving
|
||||||
|
await this.scheduleMedia(newSched, null, chanDB);
|
||||||
|
}catch(err){
|
||||||
|
//Null out live remainder for the next stream
|
||||||
|
this.liveRemainder = null;
|
||||||
|
|
||||||
|
//Handle the error
|
||||||
|
loggerUtils.localExceptionHandler(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
stop(socket){
|
stop(socket){
|
||||||
//If we're not currently playing anything
|
//If we're not currently playing anything
|
||||||
if(this.nowPlaying == null){
|
if(this.nowPlaying == null){
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue