diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js
index 62f03f4..7539561 100644
--- a/src/app/channel/activeChannel.js
+++ b/src/app/channel/activeChannel.js
@@ -17,9 +17,8 @@ along with this program. If not, see .*/
//local imports
const connectedUser = require('./connectedUser');
const queue = require('./media/queue');
-const flairModel = require('../../schemas/flairSchema');
-const permissionModel = require('../../schemas/permissionSchema');
const channelModel = require('../../schemas/channel/channelSchema');
+const playlistHandler = require('./media/playlistHandler')
module.exports = class{
constructor(server, chanDB){
@@ -29,6 +28,7 @@ module.exports = class{
//Keeping these in a map was originally a vestige but it's more preformant than an array or object so :P
this.userList = new Map();
this.queue = new queue(server, chanDB, this);
+ this.playlistHandler = new playlistHandler(server, chanDB, this);
}
async handleConnection(userDB, chanDB, socket){
@@ -57,6 +57,7 @@ module.exports = class{
//Define per-channel event listeners
this.queue.defineListeners(socket);
+ this.playlistHandler.defineListeners(socket);
//Hand off the connection initiation to it's user object
await userObj.handleConnection(userDB, chanDB, socket)
diff --git a/src/app/channel/media/playlistHandler.js b/src/app/channel/media/playlistHandler.js
new file mode 100644
index 0000000..8749f50
--- /dev/null
+++ b/src/app/channel/media/playlistHandler.js
@@ -0,0 +1,87 @@
+/*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 .*/
+
+//NPM imports
+const validator = require('validator');
+
+//Local imports
+const loggerUtils = require('../../../utils/loggerUtils');
+const yanker = require('../../../utils/media/yanker');
+const channelModel = require('../../../schemas/channel/channelSchema');
+
+module.exports = class{
+ constructor(server, chanDB, channel){
+ //Set server
+ this.server = server
+ //Set channel
+ this.channel = channel;
+ }
+
+ defineListeners(socket){
+ //socket.on("queue", (data) => {this.queueURL(socket, data)});
+ socket.on("getChannelPlaylists", () => {this.getChannelPlaylists(socket)});
+ socket.on("createChannelPlaylist", (data) => {this.createChannelPlaylist(socket, data)});
+ socket.on("addToChannelPlaylist", (data) => {this.addToChannelPlaylist(socket, data)});
+ }
+
+ async getChannelPlaylists(socket, chanDB){
+ //if we wherent handed a channel document
+ if(chanDB == null){
+ //Pull it based on channel name
+ chanDB = await channelModel.findOne({name: this.channel.name});
+ }
+
+ //Return playlists
+ socket.emit('chanPlaylists', chanDB.getPlaylists());
+ }
+
+ async createChannelPlaylist(socket, data, chanDB){
+ //if we wherent handed a channel document
+ if(chanDB == null){
+ //Pull it based on channel name
+ chanDB = await channelModel.findOne({name: this.channel.name});
+ }
+
+ //Add playlist to the channel doc
+ chanDB.media.playlists.push({
+ name: data.name,
+ defaultTitles: data.defaultTitles
+ });
+
+ //Save the channel doc
+ await chanDB.save();
+
+ //Return playlists from channel doc
+ socket.emit('chanPlaylists', chanDB.getPlaylists());
+ }
+
+ async addToChannelPlaylist(socket, data, chanDB){
+ //if we wherent handed a channel document
+ if(chanDB == null){
+ //Pull it based on channel name
+ chanDB = await channelModel.findOne({name: this.channel.name});
+ }
+
+ //Pull media metadata
+ let mediaList = await yanker.yankMedia(data.url);
+
+ //Add media object to the given playlist
+ await chanDB.addToPlaylist(data.playlist, mediaList[0]);
+
+ //Return playlists from channel doc
+ socket.emit('chanPlaylists', chanDB.getPlaylists());
+ }
+}
\ No newline at end of file
diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js
index 99b0e34..6d95023 100644
--- a/src/schemas/channel/channelSchema.js
+++ b/src/schemas/channel/channelSchema.js
@@ -103,7 +103,7 @@ const channelSchema = new mongoose.Schema({
media: {
nowPlaying: queuedMediaSchema,
scheduled: [queuedMediaSchema],
- //We should consider moving archived media and channel playlists to their own collections/models for preformance sake
+ //We should consider moving archived media and channel playlists to their own collections/models for preformances sake
archived: [queuedMediaSchema],
playlists: [playlistSchema]
},
@@ -551,6 +551,73 @@ channelSchema.methods.getEmotes = function(){
return emoteList;
}
+channelSchema.methods.getPlaylists = function(){
+ //Create an empty array to hold our emote list
+ 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({
+ name: playlist.name,
+ count: playlist.media.length
+ });
+ }
+
+ //return the emote list
+ return playlists;
+}
+
+channelSchema.methods.playlistCrawl = function(cb){
+ for(let listIndex in this.media.playlists){
+ //Grab the associated playlist
+ playlist = this.media.playlists[listIndex];
+
+ //Call the callback with the playlist and list index as arguments
+ cb(playlist, listIndex);
+ }
+}
+
+channelSchema.methods.getPlaylistByName = function(name){
+ //Create null value to hold our found playlist
+ let foundPlaylist = null;
+
+ //Crawl through active playlists
+ this.playlistCrawl((playlist) => {
+ //If we found a match based on name
+ if(playlist.name == name){
+ //Keep it
+ foundPlaylist = playlist;
+ }
+ });
+
+ //return the given playlist
+ return foundPlaylist;
+}
+
+channelSchema.methods.addToPlaylist = async function(name, media){
+ //Create variable to hold found index
+ let foundIndex = null
+
+ //Crawl through active playlists
+ this.playlistCrawl((playlist, listIndex) => {
+ //If the playlist name matches
+ if(playlist.name == name){
+ //Push the given media into the found playlist
+ //this.media.playlists[listIndex].push(media);
+
+ //Make note of the found index
+ foundIndex = listIndex
+ }
+ });
+
+ this.media.playlists[foundIndex].media.push(media);
+
+ //Save the changes made to the chan doc
+ await this.save();
+}
+
channelSchema.methods.getChanBans = async function(){
//Create an empty list to hold our found bans
var banList = [];
diff --git a/src/schemas/channel/media/playlistSchema.js b/src/schemas/channel/media/playlistSchema.js
index 2dc6d0b..5644c5b 100644
--- a/src/schemas/channel/media/playlistSchema.js
+++ b/src/schemas/channel/media/playlistSchema.js
@@ -31,4 +31,4 @@ module.exports = new mongoose.Schema({
required: true,
default: []
}]
-});
+});
\ No newline at end of file
diff --git a/src/schemas/channel/media/queuedMediaSchema.js b/src/schemas/channel/media/queuedMediaSchema.js
index 85a3d88..976fb4e 100644
--- a/src/schemas/channel/media/queuedMediaSchema.js
+++ b/src/schemas/channel/media/queuedMediaSchema.js
@@ -44,7 +44,7 @@ const queuedProperties = new mongoose.Schema({
discriminatorKey: 'status'
});
-//methods
+//Methods
//Rehydrate to a full phat queued media object
queuedProperties.methods.rehydrate = function(){
return new queuedMedia(
@@ -61,4 +61,5 @@ queuedProperties.methods.rehydrate = function(){
);
}
+//Export schema under the 'queued' discriminator of mediaSchema
module.exports = mediaSchema.discriminator('queued', queuedProperties);
\ No newline at end of file