Started work on channel-wide playlists.

This commit is contained in:
rainbow napkin 2025-03-23 22:30:10 -04:00
parent 59f097db39
commit 72a89ae5ff
5 changed files with 161 additions and 5 deletions

View file

@ -17,9 +17,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
//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)

View file

@ -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 <https://www.gnu.org/licenses/>.*/
//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());
}
}

View file

@ -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 = [];

View file

@ -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);