Re-scheduling currently playing item now stops currnet playback, and re-schedules a clone. Allowing for DB-Friendly schedule2scrub functionality.

This commit is contained in:
rainbow napkin 2025-09-09 08:19:46 -04:00
parent 92659929b9
commit 9eeed591ad
4 changed files with 112 additions and 58 deletions

View file

@ -596,7 +596,7 @@ class queue{
} }
//Find our media, don't remove it yet since we want to do some more testing first //Find our media, don't remove it yet since we want to do some more testing first
const media = this.getItemByUUID(uuid); let media = this.getItemByUUID(uuid);
//If we got a bad request //If we got a bad request
if(media == null){ if(media == null){
@ -611,27 +611,31 @@ class queue{
//If someone is trying to re-schedule something that starts in the past //If someone is trying to re-schedule something that starts in the past
if(media.startTime < new Date().getTime()){ if(media.startTime < new Date().getTime()){
//If an originating socket was provided for this request //If the item is currently playing
if(socket != null){ if(media.getEndTime() > new Date().getTime()){
//If the item is currently playing //Dupe media for the rest of the function
if(media.getEndTime() > new Date().getTime()){ media = media.clone();
//Yell at the user for being an asshole
loggerUtils.socketErrorHandler(socket, "You cannot move an actively playing video!", "queue"); //Stop current item
//Otherwise, if it's already ended await this.stop(socket, chanDB);
}else{
//Otherwise, if it's already ended
}else{
//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 alter the past!", "queue"); loggerUtils.socketErrorHandler(socket, "You cannot alter the past!", "queue");
} }
//Ignore it
return;
} }
//If the item has yet to be played
}else{
//Ignore it //Remove the media from the schedule
return; await this.removeMedia(uuid, socket, chanDB);
} }
//Remove the media from the schedule
await this.removeMedia(uuid, socket, chanDB);
//Grab the old start time for safe keeping //Grab the old start time for safe keeping
const oldStart = media.startTime; const oldStart = media.startTime;
@ -1438,9 +1442,10 @@ class queue{
/** /**
* Stops currently playing media item * Stops currently playing media item
* @param {Socket} socket - Requesting Socket * @param {Socket} socket - Requesting Socket
* @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
* @returns returns false if there is nothing to stop * @returns returns false if there is nothing to stop
*/ */
stop(socket){ async stop(socket, chanDB){
//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
@ -1462,7 +1467,7 @@ class queue{
} }
//End the media //End the media
this.end(); await this.end(false, false, false, chanDB);
} }
/** /**

View file

@ -119,6 +119,25 @@ class queuedMedia extends media{
this.uuid = crypto.randomUUID(); this.uuid = crypto.randomUUID();
} }
/**
* Generates a unique clone of a given media object
* @returns unique clone of media object
*/
clone(){
return new queuedMedia(
this.title,
this.fileName,
this.url,
this.id,
this.type,
this.duration,
this.rawLink,
this.startTime,
this.startTimeStamp,
this.earlyEnd
);
}
/** /**
* return the end time of a given queuedMedia object * return the end time of a given queuedMedia object
* @param {boolean} fullTime - Overrides early ends * @param {boolean} fullTime - Overrides early ends

View file

@ -956,16 +956,25 @@ class queuePanel extends panelObj{
//Get current start time //Get current start time
const start = this.dateByOffset(target.offsetTop); const start = this.dateByOffset(target.offsetTop);
const end = new Date(start.getTime() + (target.dataset['duration'] * 1000));
//Position timetip //Position timetip
timetip.moveToMouse(event); timetip.moveToMouse(event);
//Inject timetip label //Normally wouldn't do innerHTML but these values are calculated serverside and it saves us making a <br> dom node
//Normally wouldn't do innerHTML but these values are calculated serverside and it saves us making a <br> element let timetipContents = [
timetip.tooltip.innerHTML = [
`Start Time: ${utils.ux.timeStringFromDate(start, true)}`, `Start Time: ${utils.ux.timeStringFromDate(start, true)}`,
`End Time: ${utils.ux.timeStringFromDate(new Date(start.getTime() + (target.dataset['duration'] * 1000)), true)}` `End Time: ${utils.ux.timeStringFromDate(end, true)}`
].join('<br>'); ];
//If the current time is after the start date, but before the end (we're scheduling to start now)
if(start.getTime() < date.getTime() && end.getTime() > date.getTime()){
//Add start timestamp to item
timetipContents.push(`Start Timestamp: ${utils.ux.humieFriendlyDuration((date.getTime() - start.getTime()) / 1000, true)}`);
}
//Inject timetip label
timetip.tooltip.innerHTML = timetipContents.join('<br>')
//Calculate offset from rest of window //Calculate offset from rest of window
const windowOffset = this.queueContainer.offsetTop + this.ownerDoc.defaultView.scrollY; const windowOffset = this.queueContainer.offsetTop + this.ownerDoc.defaultView.scrollY;

View file

@ -99,7 +99,7 @@ class canopyUXUtils{
return outString; return outString;
} }
humieFriendlyDuration(seconds){ humieFriendlyDuration(seconds, compact = false){
//If we have an invalid duration //If we have an invalid duration
if(seconds <= 0){ if(seconds <= 0){
//bitch, moan, and complain! //bitch, moan, and complain!
@ -119,41 +119,62 @@ class canopyUXUtils{
//Remove recorded minutes //Remove recorded minutes
seconds -= minutes * 60; seconds -= minutes * 60;
//If we have an hour //If we're rendering compact, alarm-clock style duration
if(hours == 1){ if(compact){
//Add the string if(hours > 0){
timeStrings.push('1 Hour'); //Push hours, pad start with 0
//If we have hours timeStrings.push(String(hours).padStart(2, '0'));
}else if(hours > 0){ }
//Add the string
timeStrings.push(`${hours} Hours`); if(hours > 0 || minutes > 0){
//Push minutes, pad start with 0
timeStrings.push(String(minutes).padStart(2, '0'));
}
if(hours > 0 || minutes > 0 || seconds > 0){
//Push seconds, pre-fix a 00: if hours and minutes are empty, round to nearest int and pad start with 0
timeStrings.push(`${(hours == 0 && minutes == 0) ? '00:' : ''}${String(Math.round(seconds)).padStart(2, '0')}`);
}
return timeStrings.join(':');
//If we're rendering out using our words
}else{
//If we have an hour
if(hours == 1){
//Add the string
timeStrings.push('1 Hour');
//If we have hours
}else if(hours > 0){
//Add the string
timeStrings.push(`${hours} Hours`);
}
//If we have a minute
if(minutes == 1){
//Add the string
timeStrings.push('1 Minute');
//If we have minutes
}else if(minutes > 0){
//Add the string
timeStrings.push(`${minutes} Minutes`);
}
//Add the 'and ' if we need it
const secondsPrefix = timeStrings.length > 0 ? 'and ' : '';
//If we have a second
if(seconds == 1){
//Add the string
timeStrings.push(`${secondsPrefix}1 Second`);
//If we have more than a second
}else if(seconds > 1){
//Add the string
timeStrings.push(`${secondsPrefix}${Math.round(seconds)} Seconds`);
}
//Join the time strings together
return timeStrings.join(', ');
} }
//If we have a minute
if(minutes == 1){
//Add the string
timeStrings.push('1 Minute');
//If we have minutes
}else if(minutes > 0){
//Add the string
timeStrings.push(`${minutes} Minutes`);
}
//Add the 'and ' if we need it
const secondsPrefix = timeStrings.length > 0 ? 'and ' : '';
//If we have a second
if(seconds == 1){
//Add the string
timeStrings.push(`${secondsPrefix}1 Second`);
//If we have more than a second
}else if(seconds > 1){
//Add the string
timeStrings.push(`${secondsPrefix}${Math.round(seconds)} Seconds`);
}
//Join the time strings together
return timeStrings.join(', ');
} }
//Update this and popup class to use nodes //Update this and popup class to use nodes