Started work on channel-wide playlists.
This commit is contained in:
parent
59f097db39
commit
72a89ae5ff
|
|
@ -17,9 +17,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
//local imports
|
//local imports
|
||||||
const connectedUser = require('./connectedUser');
|
const connectedUser = require('./connectedUser');
|
||||||
const queue = require('./media/queue');
|
const queue = require('./media/queue');
|
||||||
const flairModel = require('../../schemas/flairSchema');
|
|
||||||
const permissionModel = require('../../schemas/permissionSchema');
|
|
||||||
const channelModel = require('../../schemas/channel/channelSchema');
|
const channelModel = require('../../schemas/channel/channelSchema');
|
||||||
|
const playlistHandler = require('./media/playlistHandler')
|
||||||
|
|
||||||
module.exports = class{
|
module.exports = class{
|
||||||
constructor(server, chanDB){
|
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
|
//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.userList = new Map();
|
||||||
this.queue = new queue(server, chanDB, this);
|
this.queue = new queue(server, chanDB, this);
|
||||||
|
this.playlistHandler = new playlistHandler(server, chanDB, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleConnection(userDB, chanDB, socket){
|
async handleConnection(userDB, chanDB, socket){
|
||||||
|
|
@ -57,6 +57,7 @@ module.exports = class{
|
||||||
|
|
||||||
//Define per-channel event listeners
|
//Define per-channel event listeners
|
||||||
this.queue.defineListeners(socket);
|
this.queue.defineListeners(socket);
|
||||||
|
this.playlistHandler.defineListeners(socket);
|
||||||
|
|
||||||
//Hand off the connection initiation to it's user object
|
//Hand off the connection initiation to it's user object
|
||||||
await userObj.handleConnection(userDB, chanDB, socket)
|
await userObj.handleConnection(userDB, chanDB, socket)
|
||||||
|
|
|
||||||
87
src/app/channel/media/playlistHandler.js
Normal file
87
src/app/channel/media/playlistHandler.js
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -103,7 +103,7 @@ const channelSchema = new mongoose.Schema({
|
||||||
media: {
|
media: {
|
||||||
nowPlaying: queuedMediaSchema,
|
nowPlaying: queuedMediaSchema,
|
||||||
scheduled: [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],
|
archived: [queuedMediaSchema],
|
||||||
playlists: [playlistSchema]
|
playlists: [playlistSchema]
|
||||||
},
|
},
|
||||||
|
|
@ -551,6 +551,73 @@ channelSchema.methods.getEmotes = function(){
|
||||||
return emoteList;
|
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(){
|
channelSchema.methods.getChanBans = async function(){
|
||||||
//Create an empty list to hold our found bans
|
//Create an empty list to hold our found bans
|
||||||
var banList = [];
|
var banList = [];
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ const queuedProperties = new mongoose.Schema({
|
||||||
discriminatorKey: 'status'
|
discriminatorKey: 'status'
|
||||||
});
|
});
|
||||||
|
|
||||||
//methods
|
//Methods
|
||||||
//Rehydrate to a full phat queued media object
|
//Rehydrate to a full phat queued media object
|
||||||
queuedProperties.methods.rehydrate = function(){
|
queuedProperties.methods.rehydrate = function(){
|
||||||
return new queuedMedia(
|
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);
|
module.exports = mediaSchema.discriminator('queued', queuedProperties);
|
||||||
Loading…
Reference in a new issue