Livestream Database Handling for Overwrite mode complete. Schedule goes back to pre-stream state if server crashes/stops.
This commit is contained in:
parent
85c1258bb6
commit
8c8b2a6f0b
|
|
@ -49,6 +49,8 @@ module.exports = class{
|
||||||
this.preSwitchTimer = null;
|
this.preSwitchTimer = null;
|
||||||
//Create variable to hold currently playing media object
|
//Create variable to hold currently playing media object
|
||||||
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)
|
||||||
|
this.liveRemainder = 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;
|
||||||
|
|
@ -267,8 +269,15 @@ module.exports = class{
|
||||||
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
|
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Capture currently playing object
|
//If something is playing
|
||||||
const wasPlaying = this.nowPlaying;
|
if(this.nowPlaying != null){
|
||||||
|
//Capture currently playing object
|
||||||
|
this.liveRemainder = this.nowPlaying;
|
||||||
|
chanDB.media.liveRemainder = this.nowPlaying.uuid;
|
||||||
|
|
||||||
|
//Save the chanDB
|
||||||
|
await chanDB.save();
|
||||||
|
}
|
||||||
|
|
||||||
//Kill schedule timers to prevent items from starting during the stream
|
//Kill schedule timers to prevent items from starting during the stream
|
||||||
await this.stopScheduleTimers();
|
await this.stopScheduleTimers();
|
||||||
|
|
@ -309,13 +318,6 @@ module.exports = class{
|
||||||
//Throw stream lock
|
//Throw stream lock
|
||||||
this.streamLock = true;
|
this.streamLock = true;
|
||||||
|
|
||||||
//If something was playing
|
|
||||||
if(wasPlaying != null){
|
|
||||||
//Force it back into the schedule w/ saveLate enabled from nowPlaying, since it was ended with noArchive, effectively deleting it
|
|
||||||
//This is also the easiest way to bring nowPlaying media back into the schedule, since end wants to archive it :P
|
|
||||||
await this.scheduleMedia([wasPlaying], socket, chanDB, true, false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Broadcast new media object to users
|
//Broadcast new media object to users
|
||||||
this.sendMedia();
|
this.sendMedia();
|
||||||
}catch(err){
|
}catch(err){
|
||||||
|
|
@ -326,7 +328,7 @@ module.exports = class{
|
||||||
//--- INTERNAL USE ONLY QUEUEING FUNCTIONS ---
|
//--- INTERNAL USE ONLY QUEUEING FUNCTIONS ---
|
||||||
async stopScheduleTimers(noArchive = true){
|
async stopScheduleTimers(noArchive = true){
|
||||||
//End any currently playing media media w/o archiving
|
//End any currently playing media media w/o archiving
|
||||||
await this.end(false, noArchive);
|
await this.stop();
|
||||||
|
|
||||||
//Clear sync timer
|
//Clear sync timer
|
||||||
clearTimeout(this.syncTimer);
|
clearTimeout(this.syncTimer);
|
||||||
|
|
@ -417,7 +419,7 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeRange(start = new Date().getTime() - 60 * 1000, end = new Date().getTime(), socket){
|
async removeRange(start = new Date().getTime() - 60 * 1000, end = new Date().getTime(), socket, noUnfinished = 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
|
||||||
|
|
@ -430,7 +432,7 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
|
|
||||||
//Find items within given range
|
//Find items within given range
|
||||||
const foundItems = this.getItemsBetweenEpochs(start, end);
|
const foundItems = this.getItemsBetweenEpochs(start, end, noUnfinished);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
//DO everything ourselves since we don't have a fance end() function to do it
|
//DO everything ourselves since we don't have a fance end() function to do it
|
||||||
|
|
@ -969,7 +971,7 @@ module.exports = class{
|
||||||
//If we're ending an HLS Livestream
|
//If we're ending an HLS Livestream
|
||||||
if(wasPlaying.type == "livehls"){
|
if(wasPlaying.type == "livehls"){
|
||||||
//Redirect to the endLivestream function
|
//Redirect to the endLivestream function
|
||||||
return this.endLivestream(chanDB);
|
return this.endLivestream(wasPlaying, chanDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we're not in volatile mode and we're not ending a livestream
|
//If we're not in volatile mode and we're not ending a livestream
|
||||||
|
|
@ -987,7 +989,7 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
|
|
||||||
//If we haven't changed 'nowPlaying' in the play list
|
//If we haven't changed 'nowPlaying' in the play list
|
||||||
if(chanDB.media.nowPlaying.uuid == wasPlaying.uuid){
|
if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.uuid == wasPlaying.uuid){
|
||||||
//Take it out
|
//Take it out
|
||||||
await chanDB.media.nowPlaying.deleteOne();
|
await chanDB.media.nowPlaying.deleteOne();
|
||||||
}
|
}
|
||||||
|
|
@ -1016,29 +1018,7 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async endLivestream(chanDB){
|
async endLivestream(wasPlaying, chanDB){
|
||||||
try{
|
|
||||||
//Disable stream lock
|
|
||||||
this.streamLock = false;
|
|
||||||
|
|
||||||
//Refresh next timer
|
|
||||||
this.refreshNextTimer();
|
|
||||||
|
|
||||||
//This is where I'd stick the IF statetement I'd add to switch between overwrite
|
|
||||||
await this.livestreamOverwriteSchedule(chanDB)
|
|
||||||
|
|
||||||
//Broadcast Queue
|
|
||||||
this.broadcastQueue();
|
|
||||||
//ACK
|
|
||||||
}catch(err){
|
|
||||||
//Broadcast queue
|
|
||||||
this.broadcastQueue();
|
|
||||||
//Handle the error
|
|
||||||
loggerUtils.localExceptionHandler(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async livestreamOverwriteSchedule(chanDB){
|
|
||||||
try{
|
try{
|
||||||
//If we wheren't handed a channel
|
//If we wheren't handed a channel
|
||||||
if(chanDB == null){
|
if(chanDB == null){
|
||||||
|
|
@ -1051,14 +1031,117 @@ module.exports = class{
|
||||||
//FUCK
|
//FUCK
|
||||||
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
|
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
|
||||||
}
|
}
|
||||||
|
//Disable stream lock
|
||||||
|
this.streamLock = false;
|
||||||
|
|
||||||
|
//We don't have to here since someone else will do it for us :)
|
||||||
|
chanDB.media.liveRemainder = null;
|
||||||
|
|
||||||
|
//This is where I'd stick the IF statetement I'd add to switch between overwrite
|
||||||
|
await this.livestreamOverwriteSchedule(wasPlaying, chanDB)
|
||||||
|
|
||||||
|
//Refresh next timer
|
||||||
|
this.refreshNextTimer();
|
||||||
|
|
||||||
|
//Broadcast Queue
|
||||||
|
this.broadcastQueue();
|
||||||
|
//ACK
|
||||||
}catch(err){
|
}catch(err){
|
||||||
|
//Broadcast queue
|
||||||
|
this.broadcastQueue();
|
||||||
|
//Handle the error
|
||||||
|
loggerUtils.localExceptionHandler(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async livestreamOverwriteSchedule(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");
|
||||||
|
}
|
||||||
|
|
||||||
|
//mark overwrite job as finished so we don't run two sets of logic, as one needs to do a null check before it can run it's conditional
|
||||||
|
//while the other needs to run regardless of this.liveRemainders definition
|
||||||
|
let finished = false;
|
||||||
|
|
||||||
|
//Set duration from start and end time
|
||||||
|
wasPlaying.duration = (now - wasPlaying.startTime) / 1000;
|
||||||
|
|
||||||
|
//Throw the livestream into the archive
|
||||||
|
chanDB.media.archived.push(wasPlaying);
|
||||||
|
|
||||||
|
//Save the DB
|
||||||
|
await chanDB.save();
|
||||||
|
|
||||||
|
//If we have a live remainder
|
||||||
|
if(this.liveRemainder != null){
|
||||||
|
//If the item hasn't ended
|
||||||
|
if(finished = (this.liveRemainder.getEndTime(true) > now)){
|
||||||
|
//Rip out early end
|
||||||
|
this.liveRemainder.earlyEnd = undefined;
|
||||||
|
|
||||||
|
//regenerate UUID to differentiate between this and the original item
|
||||||
|
this.liveRemainder.genUUID();
|
||||||
|
|
||||||
|
//Re-schedule the remainder
|
||||||
|
await this.scheduleMedia([this.liveRemainder], undefined, chanDB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if "THIS ISN'T OVER, PUNK!"
|
||||||
|
if(!finished){
|
||||||
|
//Pull item from end
|
||||||
|
const wasPlayingDuringEnd = this.getItemAtEpoch(now);
|
||||||
|
|
||||||
|
//If we ended in the middle of something
|
||||||
|
if(wasPlayingDuringEnd != null){
|
||||||
|
const difference = (now - wasPlayingDuringEnd.startTime);
|
||||||
|
|
||||||
|
//Take item out
|
||||||
|
await this.removeMedia(wasPlayingDuringEnd.uuid, null, chanDB);
|
||||||
|
|
||||||
|
//Push the item up to match the difference
|
||||||
|
wasPlayingDuringEnd.startTime += difference;
|
||||||
|
|
||||||
|
//re-set start time stamp based on media start and stream end
|
||||||
|
wasPlayingDuringEnd.startTimeStamp = Math.round(difference / 1000);
|
||||||
|
|
||||||
|
//Make unique, true
|
||||||
|
wasPlayingDuringEnd.genUUID();
|
||||||
|
|
||||||
|
//Re-schedule media now that it's been cut
|
||||||
|
await this.scheduleMedia([wasPlayingDuringEnd], null, chanDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove all the in-betweeners
|
||||||
|
await this.removeRange(wasPlaying.startTime, now, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Null out live remainder for the next stream
|
||||||
|
this.liveRemainder = null;
|
||||||
|
}catch(err){
|
||||||
|
//Null out live remainder for the next stream
|
||||||
|
this.liveRemainder = null;
|
||||||
|
|
||||||
//Handle the error
|
//Handle the error
|
||||||
loggerUtils.localExceptionHandler(err);
|
loggerUtils.localExceptionHandler(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(){
|
stop(socket){
|
||||||
//If we're not currently playing anything
|
//If we're not currently playing anything
|
||||||
if(this.nowPlaying == null){
|
if(this.nowPlaying == null){
|
||||||
//If an originating socket was provided for this request
|
//If an originating socket was provided for this request
|
||||||
|
|
@ -1073,14 +1156,17 @@ module.exports = class{
|
||||||
//Stop playing
|
//Stop playing
|
||||||
const stoppedMedia = this.nowPlaying;
|
const stoppedMedia = this.nowPlaying;
|
||||||
|
|
||||||
//Get difference between current time and start time and set as early end
|
//Ignore early end for livestreams
|
||||||
stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
|
if(this.nowPlaying.type != 'livehls'){
|
||||||
|
//Get difference between current time and start time and set as early end
|
||||||
|
stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
//End the media
|
//End the media
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
getItemsBetweenEpochs(start, end){
|
getItemsBetweenEpochs(start, end, noUnfinished = false){
|
||||||
//Create an empty array to hold found items
|
//Create an empty array to hold found items
|
||||||
const foundItems = [];
|
const foundItems = [];
|
||||||
|
|
||||||
|
|
@ -1088,8 +1174,11 @@ module.exports = class{
|
||||||
for(let item of this.schedule){
|
for(let item of this.schedule){
|
||||||
//If the item starts after our start date and before our end date
|
//If the item starts after our start date and before our end date
|
||||||
if(item[0] >= start && item[0] <= end ){
|
if(item[0] >= start && item[0] <= end ){
|
||||||
//Add the current item to the list
|
//If we're allowed to add unifnished items, or the item has finished
|
||||||
foundItems.push(item[1]);
|
if(!noUnfinished || item[1].getEndTime() <= end){
|
||||||
|
//Add the current item to the list
|
||||||
|
foundItems.push(item[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1207,6 +1296,12 @@ module.exports = class{
|
||||||
|
|
||||||
//If the media started within the last 24 hours
|
//If the media started within the last 24 hours
|
||||||
if(media.startTime > yesterday){
|
if(media.startTime > yesterday){
|
||||||
|
//If we're sending out the live remainder during a live stream
|
||||||
|
if(this.liveRemainder != null && media.uuid.toString() == this.liveRemainder.uuid.toString()){
|
||||||
|
//Throw out the early end before sending it off, so it looks like it hasn't been cut off yet (smoke n mirrors :P)
|
||||||
|
media.earlyEnd = null;
|
||||||
|
}
|
||||||
|
|
||||||
//Add it to the schedule array as if it where part of the actual schedule map
|
//Add it to the schedule array as if it where part of the actual schedule map
|
||||||
schedule.push([media.startTime, media]);
|
schedule.push([media.startTime, media]);
|
||||||
//Otherwise if it's older
|
//Otherwise if it's older
|
||||||
|
|
@ -1277,7 +1372,7 @@ module.exports = class{
|
||||||
//Add record to new schedule
|
//Add record to new schedule
|
||||||
newSched.push(record);
|
newSched.push(record);
|
||||||
|
|
||||||
//Re-Schedule it in RAM
|
//Re-Schedule it in RAM, with the start function running w/ DB transactions enabled, since it won't happen right away
|
||||||
await this.scheduleMedia([mediaObj], null, chanDB, true, true, false);
|
await this.scheduleMedia([mediaObj], null, chanDB, true, true, false);
|
||||||
}else{
|
}else{
|
||||||
//If the media should be playing now
|
//If the media should be playing now
|
||||||
|
|
@ -1285,7 +1380,7 @@ module.exports = class{
|
||||||
//Save record to nowPlaying in the DB
|
//Save record to nowPlaying in the DB
|
||||||
chanDB.media.nowPlaying = record;
|
chanDB.media.nowPlaying = record;
|
||||||
|
|
||||||
//Re-Schedule it in RAM
|
//Schedule the fucker in RAM, w/ the start function also running in RAM-Only mode
|
||||||
await this.scheduleMedia([mediaObj], null, chanDB, true, true, true);
|
await this.scheduleMedia([mediaObj], null, chanDB, true, true, true);
|
||||||
//If it's been ended
|
//If it's been ended
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -1295,6 +1390,39 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//If we have a remainder from a livestream
|
||||||
|
if(chanDB.media.liveRemainder){
|
||||||
|
//Iterate backwards through the archive to pull the newest first, since that's probably where this fucker is
|
||||||
|
for(let archiveIndex = (chanDB.media.archived.length - 1); archiveIndex > 0; archiveIndex--){
|
||||||
|
//Grab the current media object
|
||||||
|
const archivedMedia = chanDB.media.archived[archiveIndex];
|
||||||
|
|
||||||
|
//If the current object matches our remainder UUID
|
||||||
|
if((archivedMedia.uuid.toString() == chanDB.media.liveRemainder.toString())){
|
||||||
|
//Null out any early end
|
||||||
|
archivedMedia.earlyEnd = null;
|
||||||
|
|
||||||
|
//Re-hydrate the item
|
||||||
|
const archivedMediaObject = archivedMedia.rehydrate();
|
||||||
|
|
||||||
|
//if we still have a video to finish
|
||||||
|
if(archivedMediaObject.getEndTime() > now){
|
||||||
|
//Set the fucker as now playing
|
||||||
|
chanDB.media.nowPlaying = archivedMediaObject;
|
||||||
|
|
||||||
|
//Schedule the fucker in RAM, w/ the start function also running in RAM-Only mode
|
||||||
|
this.scheduleMedia([archivedMediaObject], null, chanDB, true, true, true);
|
||||||
|
|
||||||
|
//Splice the fucker out of the archive
|
||||||
|
chanDB.media.archived.splice(archiveIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Break out of the loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Update schedule to only contain what hasn't been played yet
|
//Update schedule to only contain what hasn't been played yet
|
||||||
chanDB.media.scheduled = newSched;
|
chanDB.media.scheduled = newSched;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
const media = require('./media');
|
const media = require('./media');
|
||||||
|
|
||||||
module.exports = class extends media{
|
module.exports = class extends media{
|
||||||
constructor(title, fileName, url, id, type, duration, rawLink, startTime, startTimeStamp, earlyEnd, uuid){
|
constructor(title, fileName, url, id, type, duration, rawLink, startTime, startTimeStamp = 0, earlyEnd, uuid){
|
||||||
//Call derived constructor
|
//Call derived constructor
|
||||||
super(title, fileName, url, id, type, duration, rawLink);
|
super(title, fileName, url, id, type, duration, rawLink);
|
||||||
//Set media start time
|
//Set media start time
|
||||||
|
|
@ -77,9 +77,9 @@ module.exports = class extends media{
|
||||||
this.uuid = crypto.randomUUID();
|
this.uuid = crypto.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
getEndTime(){
|
getEndTime(fullTime = false){
|
||||||
//If we have an early ending
|
//If we have an early ending
|
||||||
if(this.earlyEnd == null){
|
if(this.earlyEnd == null || fullTime){
|
||||||
//Calculate our ending
|
//Calculate our ending
|
||||||
return this.startTime + ((this.duration - this.startTimeStamp) * 1000);
|
return this.startTime + ((this.duration - this.startTimeStamp) * 1000);
|
||||||
}else{
|
}else{
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,11 @@ const channelSchema = new mongoose.Schema({
|
||||||
scheduled: [queuedMediaSchema],
|
scheduled: [queuedMediaSchema],
|
||||||
//We should consider moving archived media and channel playlists to their own collections/models for preformances sake
|
//We should consider moving archived media and channel playlists to their own collections/models for preformances sake
|
||||||
archived: [queuedMediaSchema],
|
archived: [queuedMediaSchema],
|
||||||
playlists: [playlistSchema]
|
playlists: [playlistSchema],
|
||||||
|
liveRemainder: {
|
||||||
|
type: mongoose.SchemaTypes.UUID,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
//Thankfully we don't have to keep track of alts, ips, or deleted users so this should be a lot easier than site-wide bans :P
|
//Thankfully we don't have to keep track of alts, ips, or deleted users so this should be a lot easier than site-wide bans :P
|
||||||
banList: [channelBanSchema]
|
banList: [channelBanSchema]
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,11 @@ div.queue-entry{
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.queue-entry.live{
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
div.queue-entry p{
|
div.queue-entry p{
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
--danger0-alt2: rgb(242, 189, 189);
|
--danger0-alt2: rgb(242, 189, 189);
|
||||||
--danger-glow0: 2px 2px 3px var(--danger0), -2px 2px 3px var(--danger0), 2px -2px 3px var(--danger0), -2px -2px 3px var(--danger0);
|
--danger-glow0: 2px 2px 3px var(--danger0), -2px 2px 3px var(--danger0), 2px -2px 3px var(--danger0), -2px -2px 3px var(--danger0);
|
||||||
--danger-glow0-alt1: 2px 2px 3px var(--danger0-alt1), -2px 2px 3px var(--danger0-alt1), 2px -2px 3px var(--danger0-alt1), -2px -2px 3px var(--danger0-alt1);
|
--danger-glow0-alt1: 2px 2px 3px var(--danger0-alt1), -2px 2px 3px var(--danger0-alt1), 2px -2px 3px var(--danger0-alt1), -2px -2px 3px var(--danger0-alt1);
|
||||||
|
--danger-glow0-smol: 2px 2px -1px var(--danger0), -2px 2px -1px var(--danger0), 2px -2px -1px var(--danger0), -2px -2px -1px var(--danger0);
|
||||||
|
|
||||||
--timer-glow: -2px 1px 3px var(--danger0-alt1), 2px -1px 3px var(--danger0-alt1);
|
--timer-glow: -2px 1px 3px var(--danger0-alt1), 2px -1px 3px var(--danger0-alt1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -616,8 +616,8 @@ class queuePanel extends panelObj{
|
||||||
menuMap.set("Play now", ()=>{this.client.socket.emit('move', {uuid: entry[1].uuid})});
|
menuMap.set("Play now", ()=>{this.client.socket.emit('move', {uuid: entry[1].uuid})});
|
||||||
//Add 'Move To...' option to context menu
|
//Add 'Move To...' option to context menu
|
||||||
menuMap.set("Move To...", (event)=>{new reschedulePopup(event, this.client, entry[1], null, this.ownerDoc)});
|
menuMap.set("Move To...", (event)=>{new reschedulePopup(event, this.client, entry[1], null, this.ownerDoc)});
|
||||||
//Otherwise, if the item is currently playing
|
//Otherwise, if the item is currently playing (confirm with UUID since time might not always be reliable, such as during livestreams)
|
||||||
}else if(this.getMediaEnd(entry[1]) > now.getTime()){
|
}else if(entry[1].uuid == this.client.player.mediaHandler.nowPlaying.uuid){
|
||||||
//Add 'Stop' option to context menu
|
//Add 'Stop' option to context menu
|
||||||
menuMap.set("Stop", ()=>{this.client.socket.emit('stop')});
|
menuMap.set("Stop", ()=>{this.client.socket.emit('stop')});
|
||||||
//Add the Now Playing glow, not the prettiest place to add this, but why let a good conditional go to waste?
|
//Add the Now Playing glow, not the prettiest place to add this, but why let a good conditional go to waste?
|
||||||
|
|
@ -1068,8 +1068,8 @@ class queuePanel extends panelObj{
|
||||||
const entryTitle = document.createElement('p');
|
const entryTitle = document.createElement('p');
|
||||||
entryTitle.textContent = utils.unescapeEntities(nowPlaying.title);
|
entryTitle.textContent = utils.unescapeEntities(nowPlaying.title);
|
||||||
|
|
||||||
//Set entry div bottom-border location based on current time
|
//Set entry div bottom-border location based on current time, round to match time marker
|
||||||
entryDiv.style.bottom = `${this.offsetByDate(date, true)}px`
|
entryDiv.style.bottom = `${Math.round(this.offsetByDate(date, true))}px`
|
||||||
|
|
||||||
//Assembly entryDiv
|
//Assembly entryDiv
|
||||||
entryDiv.appendChild(entryTitle);
|
entryDiv.appendChild(entryTitle);
|
||||||
|
|
@ -1100,8 +1100,8 @@ class queuePanel extends panelObj{
|
||||||
//Append entry div to queue container
|
//Append entry div to queue container
|
||||||
this.queueContainer.appendChild(entryDiv);
|
this.queueContainer.appendChild(entryDiv);
|
||||||
}else{
|
}else{
|
||||||
//Update existing entry
|
//Update existing entry, round offset to match time marker
|
||||||
staleEntry.style.bottom = `${this.offsetByDate(date, true)}px`
|
staleEntry.style.bottom = `${Math.round(this.offsetByDate(date, true))}px`
|
||||||
}
|
}
|
||||||
|
|
||||||
//Keep tooltip date seperate so it re-calculates live duration properly
|
//Keep tooltip date seperate so it re-calculates live duration properly
|
||||||
|
|
@ -1206,6 +1206,7 @@ class queuePanel extends panelObj{
|
||||||
}
|
}
|
||||||
|
|
||||||
getMediaEnd(media){
|
getMediaEnd(media){
|
||||||
|
console.log(media);
|
||||||
//If we have an early end
|
//If we have an early end
|
||||||
if(media.earlyEnd != null){
|
if(media.earlyEnd != null){
|
||||||
return media.startTime + (media.earlyEnd * 1000);
|
return media.startTime + (media.earlyEnd * 1000);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue