diff --git a/src/app/channel/media/playlistHandler.js b/src/app/channel/media/playlistHandler.js
index 3ad64c6..c2c6bfb 100644
--- a/src/app/channel/media/playlistHandler.js
+++ b/src/app/channel/media/playlistHandler.js
@@ -22,6 +22,7 @@ const queuedMedia = require('./queuedMedia');
const loggerUtils = require('../../../utils/loggerUtils');
const yanker = require('../../../utils/media/yanker');
const channelModel = require('../../../schemas/channel/channelSchema');
+const { userModel } = require('../../../schemas/user/userSchema');
module.exports = class{
constructor(server, chanDB, channel){
@@ -32,6 +33,7 @@ module.exports = class{
}
defineListeners(socket){
+ //Channel Playlist Listeners
socket.on("getChannelPlaylists", () => {this.getChannelPlaylists(socket)});
socket.on("createChannelPlaylist", (data) => {this.createChannelPlaylist(socket, data)});
socket.on("deleteChannelPlaylist", (data) => {this.deleteChannelPlaylist(socket, data)});
@@ -42,9 +44,14 @@ module.exports = class{
socket.on("queueFromChannelPlaylist", (data) => {this.queueFromChannelPlaylist(socket, data)});
socket.on("renameChannelPlaylist", (data) => {this.renameChannelPlaylist(socket, data)});
socket.on("changeDefaultTitlesChannelPlaylist", (data) => {this.changeDefaultTitlesChannelPlaylist(socket, data)});
+
+ //User Playlist Listeners
+ socket.on("getUserPlaylists", () => {this.getUserPlaylists(socket)});
+ socket.on("createUserPlaylist", (data) => {this.createUserPlaylist(socket, data)});
+ socket.on("deleteUserPlaylist", (data) => {this.deleteUserPlaylist(socket, data)});
}
- //--- USER-FACING PLAYLIST FUNCTIONS ---
+ //Get playlist functions
async getChannelPlaylists(socket, chanDB){
try{
//if we wherent handed a channel document
@@ -60,6 +67,52 @@ module.exports = class{
}
}
+ async getUserPlaylists(socket, userDB){
+ try{
+ //if we wherent handed a user document
+ if(userDB == null){
+ //Find the user in the Database
+ userDB = await userModel.findOne({user: socket.request.session.user.user});
+ }
+
+ //Return playlists
+ socket.emit('userPlaylists', userDB.getPlaylists());
+ }catch(err){
+ return loggerUtils.socketExceptionHandler(socket, err);
+ }
+ }
+
+ //Create playlist functions
+ createPlaylistValidator(socket, data){
+ //Create empty array to hold titles
+ const safeTitles = [];
+
+ //If the title is too long
+ if(!validator.isLength(data.playlist, {min: 1, max:30})){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, "Playlist name too long!", "validation");
+ //and ignore it!
+ return;
+ }
+
+ if(data.defaultTitles != null){
+ //For each default title passed by the data
+ for(let title of data.defaultTitles){
+ //If the title isn't too long
+ if(validator.isLength(title, {min:1, max:30})){
+ //Add it to the safe title list
+ safeTitles.push(validator.escape(validator.trim(title)))
+ }
+ }
+ }
+
+ //Escape/trim the playlist name
+ return {
+ playlist: validator.escape(validator.trim(data.playlist)),
+ defaultTitles: safeTitles
+ }
+ }
+
async createChannelPlaylist(socket, data, chanDB){
try{
//if we wherent handed a channel document
@@ -69,41 +122,27 @@ module.exports = class{
}
if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
- //If the title is too long
- if(!validator.isLength(data.playlist, {max:30})){
- //Bitch, moan, complain...
- loggerUtils.socketErrorHandler(socket, "Playlist name too long!", "validation");
- //and ignore it!
+ //Validate Data
+ const validData = this.createPlaylistValidator(socket, data);
+
+ //If we got bad data
+ if(validData == null){
+ //Do nothing
return;
}
- //Escape/trim the playlist name
- const name = validator.escape(validator.trim(data.playlist));
-
//If the channel already exists
- if(chanDB.getPlaylistByName(name) != null){
+ if(chanDB.getPlaylistByName(validData.playlist) != null){
//Bitch, moan, complain...
- loggerUtils.socketErrorHandler(socket, `Playlist named '${name}' already exists!`, "validation");
+ loggerUtils.socketErrorHandler(socket, `Playlist named '${validData.playlist}' already exists!`, "validation");
//and ignore it!
return;
- }
-
- //Create empty array to hold titles
- const safeTitles = [];
-
- //For each default title passed by the data
- for(let title of data.defaultTitles){
- //If the title isn't too long
- if(validator.isLength(title, {min:1, max:30})){
- //Add it to the safe title list
- safeTitles.push(validator.escape(validator.trim(title)))
- }
- }
+ }
//Add playlist to the channel doc
chanDB.media.playlists.push({
- name,
- defaultTitles: safeTitles
+ name: validData.playlist,
+ defaultTitles: validData.defaultTitles
});
//Save the channel doc
@@ -117,6 +156,48 @@ module.exports = class{
}
}
+ async createUserPlaylist(socket, data, userDB){
+ try{
+ //if we wherent handed a user document
+ if(userDB == null){
+ //Find the user in the Database
+ userDB = await userModel.findOne({user: socket.request.session.user.user});
+ }
+
+ //Validate Data
+ const validData = this.createPlaylistValidator(socket, data);
+
+ //If we got bad data
+ if(validData == null){
+ //Do nothing
+ return;
+ }
+
+ //If the channel already exists
+ if(userDB.getPlaylistByName(validData.playlist) != null){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, `Playlist named '${validData.playlist}' already exists!`, "validation");
+ //and ignore it!
+ return;
+ }
+
+ //Add playlist to the channel doc
+ userDB.playlists.push({
+ name: validData.playlist,
+ defaultTitles: validData.defaultTitles
+ });
+
+ //Save the channel doc
+ await userDB.save();
+
+ //Return playlists from channel doc
+ this.getUserPlaylists(socket, userDB);
+ }catch(err){
+ return loggerUtils.socketExceptionHandler(socket, err);
+ }
+ }
+
+ //Delete playlist functions
async deleteChannelPlaylist(socket, data, chanDB){
try{
//if we wherent handed a channel document
@@ -125,6 +206,14 @@ module.exports = class{
chanDB = await channelModel.findOne({name: this.channel.name});
}
+ //If the channel doesn't exist
+ if(chanDB.getPlaylistByName(data.playlist) == null){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, `Playlist named '${data.playlist}' doesn't exist!`, "validation");
+ //and ignore it!
+ return;
+ }
+
if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
//Delete playlist name
await chanDB.deletePlaylistByName(data.playlist);
@@ -137,6 +226,33 @@ module.exports = class{
}
}
+ async deleteUserPlaylist(socket, data, userDB){
+ try{
+ //if we wherent handed a user document
+ if(userDB == null){
+ //Find the user in the Database
+ userDB = await userModel.findOne({user: socket.request.session.user.user});
+ }
+
+ //If the channel doesn't exist
+ if(userDB.getPlaylistByName(data.playlist) == null){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, `Playlist named '${data.playlist}' doesn't exist!`, "validation");
+ //and ignore it!
+ return;
+ }
+
+ //Delete playlist name
+ await userDB.deletePlaylistByName(data.playlist);
+
+ //Return playlists from channel doc
+ this.getUserPlaylists(socket, userDB);
+ }catch(err){
+ return loggerUtils.socketExceptionHandler(socket, err);
+ }
+ }
+
+ //Add Media Functions
async addToChannelPlaylist(socket, data, chanDB){
try{
//if we wherent handed a channel document
@@ -198,6 +314,7 @@ module.exports = class{
}
}
+ //Queuing Functions
async queueChannelPlaylist(socket, data, chanDB){
try{
//if we wherent handed a channel document
@@ -334,6 +451,7 @@ module.exports = class{
}
}
+ //Rename Channel Playlist
async renameChannelPlaylist(socket, data, chanDB){
try{
//if we wherent handed a channel document
@@ -387,6 +505,7 @@ module.exports = class{
}
}
+ //Change Default Title Functions
async changeDefaultTitlesChannelPlaylist(socket, data, chanDB){
try{
//if we wherent handed a channel document
@@ -433,6 +552,7 @@ module.exports = class{
}
}
+ //Delete Playlist Functions
async deleteChannelPlaylistMedia(socket, data, chanDB){
try{
//if we wherent handed a channel document
diff --git a/src/app/channel/tokebot.js b/src/app/channel/tokebot.js
index 421605e..fe0444f 100644
--- a/src/app/channel/tokebot.js
+++ b/src/app/channel/tokebot.js
@@ -160,10 +160,6 @@ module.exports = class tokebot{
//we need to wait for this so we don't send used tokes pre-maturely
await userModel.tattooToke(tokers);
-
-
-
-
}
cooldown(){
diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js
index 8ab4925..42fe614 100644
--- a/src/schemas/channel/channelSchema.js
+++ b/src/schemas/channel/channelSchema.js
@@ -556,7 +556,6 @@ channelSchema.methods.getPlaylists = function(){
const playlists = [];
//For each channel emote
- //this.media.playlists.forEach((playlist) => {
for(let playlist of this.media.playlists){
//Push an object with select information from the emote to the emote list
playlists.push(playlist.dehydrate());
diff --git a/src/schemas/user/userSchema.js b/src/schemas/user/userSchema.js
index d1cc9e2..f98a137 100644
--- a/src/schemas/user/userSchema.js
+++ b/src/schemas/user/userSchema.js
@@ -29,6 +29,7 @@ const flairModel = require('../flairSchema');
const permissionModel = require('../permissionSchema');
const emoteModel = require('../emoteSchema');
const emailChangeModel = require('./emailChangeSchema');
+const playlistSchema = require('../channel/media/playlistSchema');
//Utils
const hashUtil = require('../../utils/hashUtils');
const mailUtil = require('../../utils/mailUtils');
@@ -141,7 +142,8 @@ const userSchema = new mongoose.Schema({
alts:[{
type: mongoose.SchemaTypes.ObjectID,
ref: "user"
- }]
+ }],
+ playlists: [playlistSchema]
});
//This is one of those places where you really DON'T want to use an arrow function over an anonymous one!
@@ -535,6 +537,60 @@ userSchema.methods.deleteEmote = async function(name){
}
}
+userSchema.methods.getPlaylists = function(){
+ //Create an empty array to hold our emote list
+ const playlists = [];
+
+ //For each channel emote
+ for(let playlist of this.playlists){
+ //Push an object with select information from the emote to the emote list
+ playlists.push(playlist.dehydrate());
+ }
+
+ //return the emote list
+ return playlists;
+}
+
+userSchema.methods.playlistCrawl = function(cb){
+ for(let listIndex in this.playlists){
+ //Grab the associated playlist
+ playlist = this.playlists[listIndex];
+
+ //Call the callback with the playlist and list index as arguments
+ cb(playlist, listIndex);
+ }
+}
+
+userSchema.methods.getPlaylistByName = function(name){
+ //Create null value to hold our found playlist
+ let foundPlaylist = null;
+
+ //Crawl through active playlists
+ this.playlistCrawl((playlist, listIndex) => {
+ //If we found a match based on name
+ if(playlist.name == name){
+ //Keep it
+ foundPlaylist = playlist;
+ //Pass down the list index
+ foundPlaylist.listIndex = listIndex;
+ }
+ });
+
+ //return the given playlist
+ return foundPlaylist;
+}
+
+userSchema.methods.deletePlaylistByName = async function(name){
+ //Find the playlist
+ const playlist = this.getPlaylistByName(name);
+
+ //splice out the given playlist
+ this.playlists.splice(playlist.listIndex, 1);
+
+ //save the channel document
+ await this.save();
+}
+
userSchema.methods.tattooIPRecord = async function(ip){
//Hash the users ip
const ipHash = hashUtil.hashIP(ip);
diff --git a/src/views/channel.ejs b/src/views/channel.ejs
index 8bdea7a..5deb6bb 100644
--- a/src/views/channel.ejs
+++ b/src/views/channel.ejs
@@ -49,8 +49,8 @@ along with this program. If not, see . %>
<%# panels %>
-
+
<%# main client %>
diff --git a/www/js/channel/panels/queuePanel/playlistManager.js b/www/js/channel/panels/queuePanel/playlistManager.js
index 2bceb96..6d6d51c 100644
--- a/www/js/channel/panels/queuePanel/playlistManager.js
+++ b/www/js/channel/panels/queuePanel/playlistManager.js
@@ -33,11 +33,14 @@ class playlistManager{
docSwitch(){
//Grab menus
this.channelPlaylistDiv = this.panelDocument.querySelector("#queue-channel-playlist-div");
+ this.userPlaylistDiv = this.panelDocument.querySelector("#queue-user-playlist-div");
//Grab controls
this.createPlaylistSpan = this.panelDocument.querySelector('#queue-add-playlist-span');
this.channelPlaylistLabel = this.panelDocument.querySelector('#queue-channel-playlist-span');
this.channelPlaylistCaret = this.panelDocument.querySelector('#queue-channel-playlist-toggle');
+ this.userPlaylistLabel = this.panelDocument.querySelector('#queue-user-playlist-span');
+ this.userPlaylistCaret = this.panelDocument.querySelector('#queue-user-playlist-toggle');
//Force playlist re-render to fix controls
this.client.socket.emit('getChannelPlaylists');
@@ -49,6 +52,7 @@ class playlistManager{
setupInput(){
this.createPlaylistSpan.addEventListener('click', (event)=>{new newPlaylistPopup(event, this.client, this.queuePanel.ownerDoc)})
this.channelPlaylistLabel.addEventListener('click', this.toggleChannelPlaylists.bind(this));
+ this.userPlaylistLabel.addEventListener('click', this.toggleUserPlaylists.bind(this));
}
/* queue control button functions */
@@ -71,6 +75,26 @@ class playlistManager{
}
}
+ /* queue control button functions */
+ toggleUserPlaylists(event){
+ //If the div is hidden
+ if(this.userPlaylistDiv.style.display == 'none'){
+ //Light up the button
+ this.userPlaylistLabel.classList.add('positive');
+ //Flip the caret
+ this.userPlaylistCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
+ //Show the div
+ this.userPlaylistDiv.style.display = '';
+ }else{
+ //Unlight the button
+ this.userPlaylistLabel.classList.remove('positive');
+ //Flip the caret
+ this.userPlaylistCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
+ //Hide the div
+ this.userPlaylistDiv.style.display = 'none';
+ }
+ }
+
checkOpenPlaylists(){
//If open map is a string, indicating we just renamed a playlist with it's media open
if(typeof this.openMap == 'string'){
diff --git a/www/js/channel/panels/queuePanel.js b/www/js/channel/panels/queuePanel/queuePanel.js
similarity index 100%
rename from www/js/channel/panels/queuePanel.js
rename to www/js/channel/panels/queuePanel/queuePanel.js