Added proper handling of items that begin late and end early.
This commit is contained in:
parent
330c4c275b
commit
179a10fb72
5 changed files with 286 additions and 69 deletions
|
|
@ -51,6 +51,7 @@ module.exports = class{
|
|||
|
||||
defineListeners(socket){
|
||||
socket.on("queue", (data) => {this.queueURL(socket, data)});
|
||||
socket.on("stop", (data) => {this.stopMedia(socket)});
|
||||
socket.on("delete", (data) => {this.deleteMedia(socket, data)});
|
||||
socket.on("move", (data) => {this.moveMedia(socket, data)});
|
||||
socket.on("clear", (data) => {this.deleteRange(socket, data)});
|
||||
|
|
@ -108,19 +109,7 @@ module.exports = class{
|
|||
loggerUtils.socketErrorHandler(socket, "No media found!", "queue");
|
||||
//and ignore it!
|
||||
return;
|
||||
}
|
||||
|
||||
//If we have an invalid time
|
||||
if(start == null || start < (new Date).getTime()){
|
||||
//Get last item from schedule
|
||||
const lastItem = (Array.from(this.schedule)[this.schedule.size - 1]);
|
||||
|
||||
//if we have a last item
|
||||
if(lastItem != null){
|
||||
//Throw it on five ms after the last item
|
||||
start = lastItem[1].startTime + (lastItem[1].duration * 1000) + 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Queue the first media object given
|
||||
this.queueMedia(mediaList[0], start, socket);
|
||||
|
|
@ -143,7 +132,6 @@ module.exports = class{
|
|||
//and ignore it!
|
||||
return;
|
||||
}
|
||||
|
||||
//If end time isn't an integer
|
||||
if(data.end != null && !validator.isInt(String(data.end))){
|
||||
//Bitch, moan, complain...
|
||||
|
|
@ -195,7 +183,7 @@ module.exports = class{
|
|||
return;
|
||||
}
|
||||
|
||||
//If start time isn't an integer after the current epoch
|
||||
//If start time isn't an integer
|
||||
if(data.start != null && !validator.isInt(String(data.start))){
|
||||
//Null out time to tell the later parts of the function to start it now
|
||||
data.start = undefined;
|
||||
|
|
@ -224,9 +212,32 @@ module.exports = class{
|
|||
}
|
||||
|
||||
//Default start time to now + half a second to give everyone time to process shit
|
||||
queueMedia(inputMedia, start = new Date().getTime() + 50, socket){
|
||||
queueMedia(inputMedia, start, socket){
|
||||
//If we have an invalid time
|
||||
if(start == null || start < (new Date).getTime()){
|
||||
//Get last item from schedule
|
||||
const lastItem = (Array.from(this.schedule)[this.schedule.size - 1]);
|
||||
|
||||
const now = new Date().getTime()
|
||||
|
||||
//if we have a last item
|
||||
if(lastItem != null){
|
||||
//If the last item has ended
|
||||
if(lastItem[1].getEndTime() < now){
|
||||
start = now + 5;
|
||||
//If it hasn't started yet
|
||||
}else{
|
||||
//Throw it on five ms after the last item
|
||||
start = lastItem[1].getEndTime() + 5;
|
||||
}
|
||||
}else{
|
||||
//Throw it on five ms after the last item
|
||||
start = now + 5;
|
||||
}
|
||||
}
|
||||
|
||||
//Create a new media queued object, set start time to now
|
||||
const mediaObj = queuedMedia.fromMedia(inputMedia, start);
|
||||
const mediaObj = queuedMedia.fromMedia(inputMedia, start, 0);
|
||||
|
||||
//schedule the media
|
||||
this.scheduleMedia(mediaObj, socket);
|
||||
|
|
@ -244,7 +255,7 @@ module.exports = class{
|
|||
//If we have a current item and it isn't currently playing
|
||||
if(currentItem != null && (this.nowPlaying == null || currentItem.uuid != this.nowPlaying.uuid)){
|
||||
//Start the found item at w/ a pre-calculated time stamp to reflect the given start time
|
||||
this.start(currentItem, Math.round((new Date().getTime() - currentItem.startTime) / 1000));
|
||||
this.start(currentItem, Math.round((new Date().getTime() - currentItem.startTime) / 1000) + currentItem.startTimeStamp);
|
||||
}
|
||||
//otherwise if we have an item
|
||||
}else{
|
||||
|
|
@ -254,7 +265,7 @@ module.exports = class{
|
|||
//Clear out any item that might be up next
|
||||
clearTimeout(this.nextTimer);
|
||||
//Set the next timer
|
||||
this.nextTimer = setTimeout(()=>{this.start(nextItem)}, startsIn);
|
||||
this.nextTimer = setTimeout(()=>{this.start(nextItem, nextItem.startTimeStamp)}, startsIn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,9 +280,9 @@ module.exports = class{
|
|||
}
|
||||
}
|
||||
|
||||
rescheduleMedia(uuid, start = new Date().getTime() + 50, socket){
|
||||
//Find and remove media from the schedule by UUID
|
||||
const media = this.removeMedia(uuid);
|
||||
rescheduleMedia(uuid, start = new Date().getTime() + 5, socket){
|
||||
//Find our media, don't remove it yet since we want to do some more testing first
|
||||
const media = this.getItemByUUID(uuid);
|
||||
|
||||
//If we got a bad request
|
||||
if(media == null){
|
||||
|
|
@ -284,20 +295,50 @@ module.exports = class{
|
|||
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
|
||||
this.removeMedia(uuid);
|
||||
|
||||
//Grab the old start time for safe keeping
|
||||
const oldStart = media.startTime;
|
||||
|
||||
//Set media time
|
||||
media.startTime = start;
|
||||
|
||||
//Reset the start time stamp for re-calculation
|
||||
media.startTimeStamp = 0;
|
||||
|
||||
//Attempt to schedule media at given time
|
||||
//Otherwise, if it returns false for fuckup
|
||||
if(!this.scheduleMedia(media, socket)){
|
||||
//Reset start time
|
||||
media.startTime = oldStart;
|
||||
|
||||
//Reset the start time stamp for re-calculation
|
||||
media.startTimeStamp = 0;
|
||||
|
||||
//Schedule in old slot
|
||||
this.scheduleMedia(media, socket);
|
||||
this.scheduleMedia(media, socket, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +376,33 @@ module.exports = class{
|
|||
return media;
|
||||
}
|
||||
|
||||
scheduleMedia(mediaObj, socket){
|
||||
stopMedia(socket){
|
||||
//If we're not currently playing anything
|
||||
if(this.nowPlaying == null){
|
||||
//If an originating socket was provided for this request
|
||||
if(socket != null){
|
||||
//Yell at the user for being an asshole
|
||||
loggerUtils.socketErrorHandler(socket, "No media playing!", "queue");
|
||||
}
|
||||
|
||||
//Ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
//Stop playing
|
||||
const stoppedMedia = this.nowPlaying;
|
||||
|
||||
//End the media
|
||||
this.end();
|
||||
|
||||
//Get difference between current time and start time and set as early end
|
||||
stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
|
||||
|
||||
//Broadcast the channel queue
|
||||
this.broadcastQueue();
|
||||
}
|
||||
|
||||
scheduleMedia(mediaObj, socket, force = false){
|
||||
/* 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
|
||||
I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass.
|
||||
|
|
@ -364,8 +431,26 @@ module.exports = class{
|
|||
https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it
|
||||
*/
|
||||
|
||||
//If someone is trying to schedule something that starts and ends in the past
|
||||
if((mediaObj.getEndTime() < new Date().getTime()) && !force){
|
||||
//If an originating socket was provided for this request
|
||||
if(socket != null){
|
||||
//Yell at the user for being an asshole
|
||||
loggerUtils.socketErrorHandler(socket, "You cannot alter the past!", "queue");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//If the item has already started and it's not being forced
|
||||
if((mediaObj.startTime < new Date().getTime())){
|
||||
//Set time stamp to existing timestamp plus the difference between the orginal start-date and now
|
||||
mediaObj.startTimeStamp = mediaObj.startTimeStamp + ((new Date().getTime() - mediaObj.startTime) / 1000)
|
||||
//Start the item now
|
||||
mediaObj.startTime = new Date().getTime() + 5;
|
||||
}
|
||||
|
||||
//If there's already something queued right now
|
||||
if(this.getItemAtEpoch(mediaObj.startTime) != null || this.getItemAtEpoch(mediaObj.startTime + (mediaObj.duration * 1000))){
|
||||
if(this.getItemAtEpoch(mediaObj.startTime) != null || this.getItemAtEpoch(mediaObj.getEndTime())){
|
||||
//If an originating socket was provided for this request
|
||||
if(socket != null){
|
||||
//Yell at the user for being an asshole
|
||||
|
|
@ -373,8 +458,7 @@ module.exports = class{
|
|||
}
|
||||
//Ignore it
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Create an empty temp array to sparsley populate with our schedule
|
||||
const tempSchedule = [];
|
||||
|
|
@ -409,7 +493,7 @@ module.exports = class{
|
|||
return mediaObj;
|
||||
}
|
||||
|
||||
start(mediaObj, timestamp = 0){
|
||||
start(mediaObj, timestamp = mediaObj.startTimeStamp){
|
||||
//Silently end the media
|
||||
this.end(true);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|||
const media = require('./media');
|
||||
|
||||
module.exports = class extends media{
|
||||
constructor(title, fileName, url, id, type, duration, startTime){
|
||||
constructor(title, fileName, url, id, type, duration, startTime, startTimeStamp){
|
||||
//Call derived constructor
|
||||
super(title, fileName, url, id, type, duration);
|
||||
//Set media start time
|
||||
this.startTime = startTime;
|
||||
//Set the media start time stamp
|
||||
this.startTimeStamp = startTimeStamp;
|
||||
//Create empty variable to hold early end if media is stopped early
|
||||
this.earlyEnd = null;
|
||||
|
||||
//Generate id unique to this specific entry of this specific file within this specific channel's queue
|
||||
//That way even if we have six copies of the same video queued, we can still uniquely idenitify each instance
|
||||
|
|
@ -30,9 +34,17 @@ module.exports = class extends media{
|
|||
}
|
||||
|
||||
//statics
|
||||
static fromMedia(media, startTime){
|
||||
static fromMedia(media, startTime, startTimeStamp){
|
||||
//Create and return queuedMedia object from given media object and arguments
|
||||
return new this(media.title, media.fileName, media.url, media.id, media.type, media.duration, startTime);
|
||||
return new this(
|
||||
media.title,
|
||||
media.fileName,
|
||||
media.url,
|
||||
media.id,
|
||||
media.type,
|
||||
media.duration,
|
||||
startTime,
|
||||
startTimeStamp);
|
||||
}
|
||||
|
||||
//methods
|
||||
|
|
@ -41,6 +53,13 @@ module.exports = class extends media{
|
|||
}
|
||||
|
||||
getEndTime(){
|
||||
return this.startTime + (this.duration * 1000);
|
||||
//If we have an early ending
|
||||
if(this.earlyEnd == null){
|
||||
//Calculate our ending
|
||||
return this.startTime + ((this.duration - this.startTimeStamp) * 1000);
|
||||
}else{
|
||||
//Return our early end
|
||||
return this.startTime + (this.earlyEnd * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue