Added schedule clearing and scroll to drag to schedule panel.
This commit is contained in:
parent
56ab5a16ec
commit
c04edb6691
8 changed files with 466 additions and 120 deletions
|
|
@ -49,6 +49,7 @@ module.exports = class{
|
|||
socket.on("queue", (data) => {this.queueURL(socket, data)});
|
||||
socket.on("delete", (data => {this.deleteMedia(socket, data)}));
|
||||
socket.on("move", (data => {this.moveMedia(socket, data)}));
|
||||
socket.on("clear", (data => {this.deleteRange(socket, data)}));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -57,8 +58,6 @@ module.exports = class{
|
|||
//Set url
|
||||
var url = data.url;
|
||||
|
||||
//pull URL and start time from data
|
||||
//let {url, start, title} = data;
|
||||
//If we where given a bad URL
|
||||
if(!validator.isURL(url)){
|
||||
//Attempt to fix the situation by encoding it
|
||||
|
|
@ -122,6 +121,30 @@ module.exports = class{
|
|||
}
|
||||
}
|
||||
|
||||
deleteRange(socket, data){
|
||||
try{
|
||||
//If start time isn't an integer
|
||||
if(data.start != null && !validator.isInt(String(data.start))){
|
||||
//Bitch, moan, complain...
|
||||
loggerUtils.socketErrorHandler(socket, "Bad start date!", "queue");
|
||||
//and ignore it!
|
||||
return;
|
||||
}
|
||||
|
||||
//If end time isn't an integer
|
||||
if(data.end != null && !validator.isInt(String(data.end))){
|
||||
//Bitch, moan, complain...
|
||||
loggerUtils.socketErrorHandler(socket, "Bad end date!", "queue");
|
||||
//and ignore it!
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeRange(data.start, data.end, socket);
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
deleteMedia(socket, data){
|
||||
try{
|
||||
//If we don't have a valid UUID
|
||||
|
|
@ -150,9 +173,9 @@ module.exports = class{
|
|||
}
|
||||
|
||||
//If start time isn't an integer after the current epoch
|
||||
if(data.start != null && !validator.isInt(String(data.start), new Date().getTime())){
|
||||
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 = null;
|
||||
data.start = undefined;
|
||||
}
|
||||
|
||||
//Move media by UUID
|
||||
|
|
@ -177,17 +200,35 @@ module.exports = class{
|
|||
|
||||
//If we have no next item
|
||||
if(nextItem == null){
|
||||
//Fuck off and die
|
||||
return;
|
||||
//Get current item
|
||||
const currentItem = this.getItemAtEpoch()
|
||||
|
||||
//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));
|
||||
}
|
||||
//otherwise if we have an item
|
||||
}else{
|
||||
//Calculate the amount of time in ms that the next item will start in
|
||||
const startsIn = nextItem.startTime - new Date().getTime();
|
||||
|
||||
//Clear out any item that might be up next
|
||||
clearTimeout(this.nextTimer);
|
||||
//Set the next timer
|
||||
this.nextTimer = setTimeout(()=>{this.start(nextItem)}, startsIn);
|
||||
}
|
||||
}
|
||||
|
||||
//Calculate the amount of time in ms that the next item will start in
|
||||
const startsIn = nextItem.startTime - new Date().getTime();
|
||||
removeRange(start = new Date().getTime() - 60 * 1000, end = new Date().getTime(), socket){
|
||||
//Find items within given range
|
||||
const foundItems = this.getItemsBetweenEpochs(start, end);
|
||||
|
||||
//Clear out any item that might be up next
|
||||
clearTimeout(this.nextTimer);
|
||||
//Set the next timer
|
||||
this.nextTimer = setTimeout(()=>{this.start(nextItem)}, startsIn);
|
||||
//For each item
|
||||
for(let item of foundItems){
|
||||
//Remove media
|
||||
this.removeMedia(item.uuid, socket);
|
||||
}
|
||||
}
|
||||
|
||||
rescheduleMedia(uuid, start = new Date().getTime() + 50, socket){
|
||||
|
|
@ -205,11 +246,21 @@ module.exports = class{
|
|||
return;
|
||||
}
|
||||
|
||||
//Grab the old start time for safe keeping
|
||||
const oldStart = media.startTime;
|
||||
|
||||
//Set media time
|
||||
media.startTime = start;
|
||||
|
||||
//Re-schedule the media for the given time
|
||||
this.scheduleMedia(media, socket);
|
||||
//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;
|
||||
|
||||
//Schedule in old slot
|
||||
this.scheduleMedia(media, socket);
|
||||
}
|
||||
}
|
||||
|
||||
removeMedia(uuid, socket){
|
||||
|
|
@ -224,7 +275,7 @@ module.exports = class{
|
|||
loggerUtils.socketErrorHandler(socket, "Cannot delete non-existant item!", "queue");
|
||||
}
|
||||
//Ignore it
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
//If we're currently playing the requested item.
|
||||
|
|
@ -264,11 +315,11 @@ module.exports = class{
|
|||
that, no matter what, re-ordering the schedule map would've required us to iterate through and convert it to an array and back anyways...
|
||||
|
||||
|
||||
Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them as seconds.
|
||||
Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds.
|
||||
This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC)
|
||||
Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P
|
||||
|
||||
If for some reason they haven't we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication
|
||||
If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication
|
||||
|
||||
Further Reading:
|
||||
https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays
|
||||
|
|
@ -276,14 +327,14 @@ module.exports = class{
|
|||
*/
|
||||
|
||||
//If there's already something queued right now
|
||||
if(this.getItemAtEpoch(mediaObj.startTime) != null){
|
||||
if(this.getItemAtEpoch(mediaObj.startTime) != null || this.getItemAtEpoch(mediaObj.startTime + (mediaObj.duration * 1000))){
|
||||
//If an originating socket was provided for this request
|
||||
if(socket != null){
|
||||
//Yell at the user for being an asshole
|
||||
loggerUtils.socketErrorHandler(socket, "This time slot has already been taken in the queue!", "queue");
|
||||
}
|
||||
//Ignore it
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -315,14 +366,17 @@ module.exports = class{
|
|||
|
||||
//Refresh the next timer to ensure whatever comes on next is right
|
||||
this.refreshNextTimer();
|
||||
|
||||
//return media object for use
|
||||
return mediaObj;
|
||||
}
|
||||
|
||||
start(mediaObj){
|
||||
start(mediaObj, timestamp = 0){
|
||||
//Silently end the media
|
||||
this.end(true);
|
||||
|
||||
//reset current timestamp
|
||||
this.timestamp = 0;
|
||||
this.timestamp = timestamp;
|
||||
|
||||
//Set current playing media
|
||||
this.nowPlaying = mediaObj;
|
||||
|
|
@ -335,6 +389,9 @@ module.exports = class{
|
|||
|
||||
//Setup the next video
|
||||
this.refreshNextTimer();
|
||||
|
||||
//return media object for use
|
||||
return mediaObj;
|
||||
}
|
||||
|
||||
sync(){
|
||||
|
|
@ -377,6 +434,23 @@ module.exports = class{
|
|||
}
|
||||
}
|
||||
|
||||
getItemsBetweenEpochs(start, end){
|
||||
//Create an empty array to hold found items
|
||||
const foundItems = [];
|
||||
|
||||
//Loop through scheduled items
|
||||
for(let item of this.schedule){
|
||||
//If the item starts after our start date and before our end date
|
||||
if(item[0] >= start && item[0] <= end ){
|
||||
//Add the current item to the list
|
||||
foundItems.push(item[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//Return any found items
|
||||
return foundItems;
|
||||
}
|
||||
|
||||
getItemAtEpoch(epoch = new Date().getTime()){
|
||||
//Loop through scheduled items
|
||||
for(let item of this.schedule){
|
||||
|
|
|
|||
28
src/views/partial/popup/clearMedia.ejs
Normal file
28
src/views/partial/popup/clearMedia.ejs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<%# Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
||||
<link rel="stylesheet" type="text/css" href="/css/popup/clearMedia.css">
|
||||
<h3 class="popup-title">Clear Media</h3>
|
||||
<div class="clear-media-popup-div">
|
||||
<span class="clear-media-input-span">
|
||||
<label for="clear-media-popup-start-time-prompt">Start:</label>
|
||||
<input name="clear-media-popup-start-time-prompt" type="datetime-local" id="clear-media-popup-start-time-prompt">
|
||||
</span>
|
||||
<span class="clear-media-input-span">
|
||||
<label for="clear-media-popup-end-time-prompt">End:</label>
|
||||
<input name="clear-media-popup-end-time-prompt" type="datetime-local" id="clear-media-popup-end-time-prompt">
|
||||
</span>
|
||||
<button class="danger-button" id="clear-media-popup-clear-button">Clear</button>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue