diff --git a/src/app/channel/connectedUser.js b/src/app/channel/connectedUser.js
index a7248c9..1b4406a 100644
--- a/src/app/channel/connectedUser.js
+++ b/src/app/channel/connectedUser.js
@@ -139,8 +139,11 @@ module.exports = class{
//Get schedule as a temporary array
const queue = Array.from(this.channel.queue.schedule);
+ //Get schedule lock status
+ const queueLock = this.channel.queue.locked;
+
//Send off the metadata to our user's clients
- this.emit("clientMetadata", {user: userObj, flairList, queue});
+ this.emit("clientMetadata", {user: userObj, flairList, queue, queueLock});
}
async sendSiteEmotes(){
diff --git a/src/app/channel/media/queue.js b/src/app/channel/media/queue.js
index 9b859c4..987a722 100644
--- a/src/app/channel/media/queue.js
+++ b/src/app/channel/media/queue.js
@@ -21,6 +21,7 @@ const validator = require('validator');
const queuedMedia = require('./queuedMedia');
const yanker = require('../../../utils/media/yanker');
const loggerUtils = require('../../../utils/loggerUtils');
+const channelModel = require('../../../schemas/channel/channelSchema');
module.exports = class{
constructor(server, channel){
@@ -43,145 +44,182 @@ module.exports = class{
this.nextTimer = null;
//Create variable to hold currently playing media object
this.nowPlaying = null;
+
+ //create boolean to hold schedule lock
+ this.locked = false;
}
defineListeners(socket){
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)}));
+ socket.on("delete", (data) => {this.deleteMedia(socket, data)});
+ socket.on("move", (data) => {this.moveMedia(socket, data)});
+ socket.on("clear", (data) => {this.deleteRange(socket, data)});
+ socket.on("lock", (data) => {this.toggleLock(socket)});
}
-
async queueURL(socket, data){
- try{
- //Set url
- var url = data.url;
+ //Get the current channel from the database
+ const chanDB = await channelModel.findOne({name: socket.chan});
- //If we where given a bad URL
- if(!validator.isURL(url)){
- //Attempt to fix the situation by encoding it
- url = encodeURI(url);
+ if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+ try{
+ //Set url
+ var url = data.url;
- //If it's still bad
+ //If we where given a bad URL
if(!validator.isURL(url)){
+ //Attempt to fix the situation by encoding it
+ url = encodeURI(url);
+
+ //If it's still bad
+ if(!validator.isURL(url)){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, "Bad URL!", "validation");
+ //and ignore it!
+ return;
+ }
+ }
+
+ //If the title is too long
+ if(!validator.isLength(data.title, {max:30})){
//Bitch, moan, complain...
- loggerUtils.socketErrorHandler(socket, "Bad URL!", "validation");
+ loggerUtils.socketErrorHandler(socket, "Title too long!", "validation");
//and ignore it!
return;
}
- }
+
+ //Set title
+ const title = validator.escape(validator.trim(data.title));
+ //set start
+ var start = data.start;
- //If the title is too long
- if(!validator.isLength(data.title, {max:30})){
- //Bitch, moan, complain...
- loggerUtils.socketErrorHandler(socket, "Title too long!", "validation");
- //and ignore it!
- return;
- }
-
- //Set title
- const title = validator.escape(validator.trim(data.title));
- //set start
- var start = data.start;
-
- //If start time isn't an integer after the current epoch
- if(start != null &&!validator.isInt(String(start), (new Date().getTime()))){
- //Null out time to tell the later parts of the function to start it now
- start = null;
- }
-
- //Pull media list
- const mediaList = await yanker.yankMedia(url, title);
-
- //If we didn't find any media
- if(mediaList == null || mediaList.length <= 0){
- //Bitch, moan, complain...
- 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;
+ //If start time isn't an integer after the current epoch
+ if(start != null &&!validator.isInt(String(start), (new Date().getTime()))){
+ //Null out time to tell the later parts of the function to start it now
+ start = null;
}
- }
- //Queue the first media object given
- this.queueMedia(mediaList[0], start, socket);
- }catch(err){
- return loggerUtils.socketExceptionHandler(socket, err);
+ //Pull media list
+ const mediaList = await yanker.yankMedia(url, title);
+
+ //If we didn't find any media
+ if(mediaList == null || mediaList.length <= 0){
+ //Bitch, moan, complain...
+ 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);
+ }catch(err){
+ return loggerUtils.socketExceptionHandler(socket, err);
+ }
}
}
- 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;
- }
+ async deleteRange(socket, data){
+ //Get the current channel from the database
+ const chanDB = await channelModel.findOne({name: socket.chan});
- //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;
- }
+ if((!this.locked && await chanDB.permCheck(socket.user, 'clearSchedule')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+ 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;
+ }
- this.removeRange(data.start, data.end, socket);
- }catch(err){
- return loggerUtils.socketExceptionHandler(socket, err);
+ //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
- if(!validator.isUUID(data.uuid)){
- //Bitch, moan, complain...
- loggerUtils.socketErrorHandler(socket, "Bad UUID!", "validation");
- //and ignore it!
- return;
- }
+ async deleteMedia(socket, data){
+ //Get the current channel from the database
+ const chanDB = await channelModel.findOne({name: socket.chan});
- //Remove media by UUID
- this.removeMedia(data.uuid, socket);
- }catch(err){
- return loggerUtils.socketExceptionHandler(socket, err);
+ if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+ try{
+ //If we don't have a valid UUID
+ if(!validator.isUUID(data.uuid)){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, "Bad UUID!", "validation");
+ //and ignore it!
+ return;
+ }
+
+ //Remove media by UUID
+ this.removeMedia(data.uuid, socket);
+ }catch(err){
+ return loggerUtils.socketExceptionHandler(socket, err);
+ }
}
}
- moveMedia(socket, data){
- try{
- //If we don't have a valid UUID
- if(!validator.isUUID(data.uuid)){
- //Bitch, moan, complain...
- loggerUtils.socketErrorHandler(socket, "Bad UUID!", "validation");
- //and ignore it!
- return;
- }
+ async moveMedia(socket, data){
+ //Get the current channel from the database
+ const chanDB = await channelModel.findOne({name: socket.chan});
- //If start time isn't an integer after the current epoch
- 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;
- }
+ if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+ try{
+ //If we don't have a valid UUID
+ if(!validator.isUUID(data.uuid)){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, "Bad UUID!", "validation");
+ //and ignore it!
+ return;
+ }
- //Move media by UUID
- this.rescheduleMedia(data.uuid, data.start, socket);
- }catch(err){
- return loggerUtils.socketExceptionHandler(socket, err);
+ //If start time isn't an integer after the current epoch
+ 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;
+ }
+
+ //Move media by UUID
+ this.rescheduleMedia(data.uuid, data.start, socket);
+ }catch(err){
+ return loggerUtils.socketExceptionHandler(socket, err);
+ }
+ }
+ }
+
+ async toggleLock(socket){
+ //Get the current channel from the database
+ const chanDB = await channelModel.findOne({name: socket.chan});
+
+ //If the user is a schedule admin
+ if(await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+ //Toggle the schedule lock
+ this.locked = !this.locked;
+
+ //Update schedule lock status for everyone in the channel
+ this.server.io.in(this.channel.name).emit("lock", {locked: this.locked});
}
}
diff --git a/src/schemas/channel/channelPermissionSchema.js b/src/schemas/channel/channelPermissionSchema.js
index 1185fa1..561f982 100644
--- a/src/schemas/channel/channelPermissionSchema.js
+++ b/src/schemas/channel/channelPermissionSchema.js
@@ -82,6 +82,24 @@ const channelPermissionSchema = new mongoose.Schema({
default: "admin",
required: true
},
+ scheduleMedia: {
+ type: mongoose.SchemaTypes.String,
+ enum: rankEnum,
+ default: "admin",
+ required: true
+ },
+ clearSchedule:{
+ type: mongoose.SchemaTypes.String,
+ enum: rankEnum,
+ default: "admin",
+ required: true
+ },
+ scheduleAdmin:{
+ type: mongoose.SchemaTypes.String,
+ enum: rankEnum,
+ default: "admin",
+ required: true
+ },
deleteChannel: {
type: mongoose.SchemaTypes.String,
enum: rankEnum,
diff --git a/src/views/partial/panels/queue.ejs b/src/views/partial/panels/queue.ejs
index 470ac2b..5b5b7d3 100644
--- a/src/views/partial/panels/queue.ejs
+++ b/src/views/partial/panels/queue.ejs
@@ -17,13 +17,13 @@ along with this program. If not, see