Started work on playlist management UI
This commit is contained in:
parent
65b5ae9371
commit
1723e8ebd0
|
|
@ -32,16 +32,17 @@ module.exports = class{
|
|||
}
|
||||
|
||||
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("deleteChannelPlaylist", (data) => {this.deleteChannelPlaylist(socket, data)});
|
||||
socket.on("addToChannelPlaylist", (data) => {this.addToChannelPlaylist(socket, data)});
|
||||
socket.on("queueChannelPlaylist", (data) => {this.queueChannelPlaylist(socket, data)});
|
||||
socket.on("renameChannelPlaylist", (data) => {this.renameChannelPlaylist(socket, data)});
|
||||
}
|
||||
|
||||
//--- USER-FACING PLAYLIST FUNCTIONS ---
|
||||
async getChannelPlaylists(socket, chanDB){
|
||||
try{
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
|
|
@ -50,18 +51,33 @@ module.exports = class{
|
|||
|
||||
//Return playlists
|
||||
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
async createChannelPlaylist(socket, data, chanDB){
|
||||
try{
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
chanDB = await channelModel.findOne({name: this.channel.name});
|
||||
}
|
||||
|
||||
//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!
|
||||
return;
|
||||
}
|
||||
|
||||
//Escape/trim the playlist name
|
||||
const name = validator.escape(validator.trim(data.playlist));
|
||||
|
||||
//Add playlist to the channel doc
|
||||
chanDB.media.playlists.push({
|
||||
name: data.playlist,
|
||||
name,
|
||||
defaultTitles: data.defaultTitles
|
||||
});
|
||||
|
||||
|
|
@ -70,9 +86,13 @@ module.exports = class{
|
|||
|
||||
//Return playlists from channel doc
|
||||
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteChannelPlaylist(socket, data, chanDB){
|
||||
try{
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
|
|
@ -84,26 +104,58 @@ module.exports = class{
|
|||
|
||||
//Return playlists from channel doc
|
||||
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
async addToChannelPlaylist(socket, data, chanDB){
|
||||
try{
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
chanDB = await channelModel.findOne({name: this.channel.name});
|
||||
}
|
||||
|
||||
let url = data.url
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
|
||||
//Pull media metadata
|
||||
let mediaList = await yanker.yankMedia(data.url);
|
||||
let mediaList = await yanker.yankMedia(url);
|
||||
|
||||
//If we didn't get any media
|
||||
if(mediaList.length == 0 || mediaList == null){
|
||||
//Bitch, moan, complain...
|
||||
loggerUtils.socketErrorHandler(socket, "No media found!", "queue");
|
||||
//and ignore it!
|
||||
return;
|
||||
}
|
||||
|
||||
//Add media object to the given playlist
|
||||
await chanDB.addToPlaylist(data.playlist, mediaList[0]);
|
||||
|
||||
//Return playlists from channel doc
|
||||
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
async queueChannelPlaylist(socket, data, chanDB){
|
||||
try{
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
|
|
@ -133,5 +185,43 @@ module.exports = class{
|
|||
|
||||
//Convert array of standard media objects to queued media objects, and push to schedule
|
||||
this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray(mediaList, start), socket, chanDB);
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
async renameChannelPlaylist(socket, data, chanDB){
|
||||
try{
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
chanDB = await channelModel.findOne({name: this.channel.name});
|
||||
}
|
||||
|
||||
//If the title is too long
|
||||
if(!validator.isLength(data.name, {max:30})){
|
||||
//Bitch, moan, complain...
|
||||
loggerUtils.socketErrorHandler(socket, "Playlist name too long!", "validation");
|
||||
//and ignore it!
|
||||
return;
|
||||
}
|
||||
|
||||
//Escape/trim the playlist name
|
||||
const name = validator.escape(validator.trim(data.name));
|
||||
|
||||
//Find playlist
|
||||
let playlist = chanDB.getPlaylistByName(data.playlist);
|
||||
|
||||
//Change playlist name
|
||||
chanDB.media.playlists[playlist.listIndex].name = name;
|
||||
|
||||
//Save channel document
|
||||
await chanDB.save();
|
||||
|
||||
//Return playlists from channel doc
|
||||
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -626,7 +626,7 @@ module.exports = class{
|
|||
}
|
||||
|
||||
//If we fucked with the DB during the main loop
|
||||
if(chanDB == null && !volatile){
|
||||
if(chanDB != null && !volatile){
|
||||
try{
|
||||
//Save the database
|
||||
chanDB.save();
|
||||
|
|
|
|||
|
|
@ -559,10 +559,7 @@ channelSchema.methods.getPlaylists = function(){
|
|||
//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
|
||||
});
|
||||
playlists.push(playlist.dehydrate());
|
||||
}
|
||||
|
||||
//return the emote list
|
||||
|
|
@ -584,11 +581,13 @@ channelSchema.methods.getPlaylistByName = function(name){
|
|||
let foundPlaylist = null;
|
||||
|
||||
//Crawl through active playlists
|
||||
this.playlistCrawl((playlist) => {
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -597,45 +596,25 @@ channelSchema.methods.getPlaylistByName = function(name){
|
|||
}
|
||||
|
||||
channelSchema.methods.deletePlaylistByName = async function(name){
|
||||
//Create null value to hold our found playlist
|
||||
let foundIndex = null;
|
||||
|
||||
//Crawl through active playlists
|
||||
this.playlistCrawl((playlist, listIndex) => {
|
||||
//If we found a match based on name
|
||||
if(playlist.name == name){
|
||||
//Yoink it's index
|
||||
foundIndex = listIndex;
|
||||
}
|
||||
});
|
||||
//Find the playlist
|
||||
let playlist = this.getPlaylistByName(name);
|
||||
|
||||
//splice out the given playlist
|
||||
this.media.playlists.splice(foundIndex, 1);
|
||||
this.media.playlists.splice(playlist.listIndex, 1);
|
||||
|
||||
//save the channel document
|
||||
await this.save();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
//Make note of the found index
|
||||
foundIndex = listIndex
|
||||
}
|
||||
});
|
||||
//Find the playlist
|
||||
let playlist = this.getPlaylistByName(name);
|
||||
|
||||
//Set media status schema discriminator
|
||||
media.status = 'saved';
|
||||
|
||||
//Add the media to the playlist
|
||||
this.media.playlists[foundIndex].media.push(media);
|
||||
this.media.playlists[playlist.listIndex].media.push(media);
|
||||
|
||||
//Save the changes made to the chan doc
|
||||
await this.save();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ const playlistSchema = new mongoose.Schema({
|
|||
name: {
|
||||
type: mongoose.SchemaTypes.String,
|
||||
required: true,
|
||||
unique: true
|
||||
},
|
||||
media: [playlistMediaSchema],
|
||||
defaultTitles:[{
|
||||
|
|
@ -33,8 +34,26 @@ const playlistSchema = new mongoose.Schema({
|
|||
}]
|
||||
});
|
||||
|
||||
playlistSchema.methods.test = function(){
|
||||
console.log(this.name);
|
||||
//methods
|
||||
playlistSchema.methods.dehydrate = function(){
|
||||
//Create empty array to hold media
|
||||
const mediaArray = [];
|
||||
|
||||
//Fill media array
|
||||
for(let media of this.media){
|
||||
mediaArray.push({
|
||||
title: media.title,
|
||||
url: media.url,
|
||||
duration: media.duration
|
||||
});
|
||||
}
|
||||
|
||||
//return dehydrated playlist
|
||||
return {
|
||||
name: this.name,
|
||||
media: mediaArray,
|
||||
defaultTitles: this.defaultTitles
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = playlistSchema;
|
||||
|
|
@ -41,6 +41,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<button id="queue-at-button" class="positive-button">Queue At...</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="queue-playlist-prompts" style="display: none;">
|
||||
<span class="queue-playlist-label-span interactive" id="queue-add-playlist-span">
|
||||
<i class="bi-plus" id="queue-add-playlist-icon"></i>
|
||||
<p id="queue-add-playlist-label">Create Playlist</p>
|
||||
</span>
|
||||
<span class="queue-playlist-label-span interactive" id="queue-channel-playlist-span">
|
||||
<i class="bi-caret-right-fill" id="queue-channel-playlist-toggle"></i>
|
||||
<p id="queue-channel-playlist-label">Channel Playlists</p>
|
||||
</span>
|
||||
<div style="display: none;" id="queue-channel-playlist-div" class="queue-playlists-div"></div>
|
||||
<span class="queue-playlist-label-span interactive" id="queue-user-playlist-span">
|
||||
<i class="bi-caret-right-fill" id="queue-user-playlist-toggle"></i>
|
||||
<p id="queue-user-playlist-label">User Playlists</p>
|
||||
</span>
|
||||
<div style="display: none;" id="queue-user-playlist-div" class="queue-playlists-div"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="queue-control-offset"></div>
|
||||
<div id="queue">
|
||||
|
|
|
|||
28
src/views/partial/popup/newPlaylist.ejs
Normal file
28
src/views/partial/popup/newPlaylist.ejs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<%# 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/>. %>
|
||||
<h3 class="popup-title">Create Playlist</h3>
|
||||
<div id="queue-create-playlist-popup-div">
|
||||
<input id="queue-create-playlist-popup-name" placeholder="Name">
|
||||
<textarea id="queue-create-playlist-popup-default-titles" placeholder="Default Titles"></textarea>
|
||||
<span>
|
||||
<label for="location">Save To:</label>
|
||||
<select name="location" id="queue-create-playlist-popup-location">
|
||||
<option value="channel">Channel</option>
|
||||
<option value="user">Account</option>
|
||||
</select>
|
||||
</span>
|
||||
<button id="queue-create-playlist-popup-save" class="positive-button">Create Playlist</button>
|
||||
</div>
|
||||
|
|
@ -25,7 +25,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|||
left: 0;
|
||||
right: 0;
|
||||
z-index: 4;
|
||||
padding: 0.15em 0.3em;
|
||||
}
|
||||
|
||||
#queue-control-offset{
|
||||
|
|
@ -38,6 +37,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin: 0.15em 0.3em;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -133,6 +133,82 @@ div.dragging-queue-entry{
|
|||
}
|
||||
|
||||
/* queue controls */
|
||||
/* media prompts */
|
||||
#queue-media-prompts{
|
||||
margin: 0.15em 0.3em;
|
||||
}
|
||||
|
||||
/* playlist manager */
|
||||
.queue-playlist-label-span{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: fit-content;
|
||||
margin-left: 0.15em;
|
||||
}
|
||||
|
||||
.queue-playlist-label-span p{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.queue-playlists-div{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.queue-playlist-span, .queue-playlist-labels-span{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
|
||||
.queue-playlist-span{
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.queue-playlist-div{
|
||||
padding: 0 0.15em;
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
|
||||
.queue-playlist-control{
|
||||
border-radius: 0;
|
||||
padding: 0.2em 0.1em;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.queue-playlist-span p{
|
||||
margin: 0 0.15em;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.queue-playlist-count{
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#queue-create-playlist-popup-div{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#queue-create-playlist-popup-div span{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
|
||||
#queue-create-playlist-popup-div span select{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
#queue-create-playlist-popup-div *{
|
||||
margin: 0.1em;
|
||||
}
|
||||
|
||||
#queue-create-playlist-popup-default-titles{
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/* date */
|
||||
#queue-control-date{
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -539,6 +539,25 @@ div.archived p{
|
|||
color: var(--bg2-alt1);
|
||||
}
|
||||
|
||||
.queue-playlists-div{
|
||||
background-color: var(--bg1);
|
||||
color: var(--accent1);
|
||||
border-block: var(--accent1) solid 1px;
|
||||
}
|
||||
|
||||
.not-first-queue-playlist-div{
|
||||
border-top: var(--bg1-alt0) solid 1px;
|
||||
}
|
||||
|
||||
.queue-playlist-count{
|
||||
color: var(--accent1-alt0);
|
||||
}
|
||||
|
||||
.queue-playlist-control:not(.danger-button):not(:hover){
|
||||
background-color: var(--bg1-alt0);
|
||||
color: var(--accent1);
|
||||
}
|
||||
|
||||
/* altcha theming*/
|
||||
div.altcha{
|
||||
box-shadow: 4px 4px 1px var(--bg1-alt0) inset;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ class queuePanel extends panelObj{
|
|||
//Autoscroll boolean
|
||||
this.autoscroll = true;
|
||||
|
||||
//Setup child classes
|
||||
this.playlistManager = new playlistManager(client, panelDocument, this);
|
||||
|
||||
//Define non-input event listeners
|
||||
this.defineListeners();
|
||||
}
|
||||
|
|
@ -43,13 +46,15 @@ class queuePanel extends panelObj{
|
|||
//Get main control buttons
|
||||
this.addMediaButton = this.panelDocument.querySelector('#queue-add-media');
|
||||
this.scrollLockButton = this.panelDocument.querySelector('#queue-scroll-lock');
|
||||
this.queueDateButton = this.panelDocument.querySelector('#queue-date')
|
||||
this.queueDateButton = this.panelDocument.querySelector('#queue-date');
|
||||
this.playlistMenuButton = this.panelDocument.querySelector("#queue-playlists");
|
||||
this.clearMediaButton = this.panelDocument.querySelector('#queue-clear');
|
||||
this.queueLockButton = this.panelDocument.querySelector('#queue-lock');
|
||||
|
||||
//Get control divs
|
||||
this.addMediaDiv = this.panelDocument.querySelector('#queue-media-prompts');
|
||||
this.queueDateDiv = this.panelDocument.querySelector('#queue-control-date');
|
||||
this.playlistDiv = this.panelDocument.querySelector('#queue-playlist-prompts');
|
||||
|
||||
//Get control div elements
|
||||
//Add Media
|
||||
|
|
@ -70,6 +75,10 @@ class queuePanel extends panelObj{
|
|||
|
||||
//Setup panel input
|
||||
this.setupInput();
|
||||
|
||||
//Pass the new panelDoc and docSwitch() call down to child classes
|
||||
this.playlistManager.panelDocument = this.panelDocument;
|
||||
this.playlistManager.docSwitch();
|
||||
}
|
||||
|
||||
closer(){
|
||||
|
|
@ -99,6 +108,7 @@ class queuePanel extends panelObj{
|
|||
this.addMediaButton.addEventListener('click', this.toggleAddMedia.bind(this));
|
||||
this.scrollLockButton.addEventListener('click', this.lockScroll.bind(this));
|
||||
this.queueDateButton.addEventListener('click', this.toggleDateControl.bind(this));
|
||||
this.playlistMenuButton.addEventListener('click', this.togglePlaylistDiv.bind(this));
|
||||
this.clearMediaButton.addEventListener('click', this.clearMedia.bind(this));
|
||||
this.queueLockButton.addEventListener('click', this.lockSchedule.bind(this));
|
||||
|
||||
|
|
@ -203,6 +213,24 @@ class queuePanel extends panelObj{
|
|||
}
|
||||
}
|
||||
|
||||
togglePlaylistDiv(event){
|
||||
//If the div is hidden
|
||||
if(this.playlistDiv.style.display == 'none'){
|
||||
//Query playlists
|
||||
client.socket.emit('getChannelPlaylists');
|
||||
|
||||
//Light up the button
|
||||
this.playlistMenuButton.classList.add('positive-button');
|
||||
//Show the div
|
||||
this.playlistDiv.style.display = '';
|
||||
}else{
|
||||
//Unlight the button
|
||||
this.playlistMenuButton.classList.remove('positive-button');
|
||||
//Hide the div
|
||||
this.playlistDiv.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
clearMedia(event){
|
||||
//Call up the popup
|
||||
new clearPopup(event, this.client, null, this.ownerDoc);
|
||||
|
|
@ -1003,6 +1031,233 @@ class queuePanel extends panelObj{
|
|||
}
|
||||
}
|
||||
|
||||
class playlistManager{
|
||||
constructor(client, panelDocument, queuePanel){
|
||||
//Set client
|
||||
this.client = client;
|
||||
//Set panel document
|
||||
this.panelDocument = panelDocument;
|
||||
//Set parent queue panel
|
||||
this.queuePanel = queuePanel;
|
||||
|
||||
//Define Listeners
|
||||
this.defineListeners();
|
||||
}
|
||||
|
||||
defineListeners(){
|
||||
this.client.socket.on("chanPlaylists", this.renderChannelPlaylists.bind(this));
|
||||
}
|
||||
|
||||
docSwitch(){
|
||||
//Grab menus
|
||||
this.channelPlaylistDiv = this.panelDocument.querySelector("#queue-channel-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');
|
||||
|
||||
//Setup Input
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
setupInput(){
|
||||
this.createPlaylistSpan.addEventListener('click', (event)=>{new newPlaylistPopup(event, this.client, this.queuePanel.ownerDoc)})
|
||||
this.channelPlaylistLabel.addEventListener('click', this.toggleChannelPlaylists.bind(this));
|
||||
}
|
||||
|
||||
/* queue control button functions */
|
||||
toggleChannelPlaylists(event){
|
||||
//If the div is hidden
|
||||
if(this.channelPlaylistDiv.style.display == 'none'){
|
||||
//Light up the button
|
||||
this.channelPlaylistLabel.classList.add('positive');
|
||||
//Flip the caret
|
||||
this.channelPlaylistCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
|
||||
//Show the div
|
||||
this.channelPlaylistDiv.style.display = '';
|
||||
}else{
|
||||
//Unlight the button
|
||||
this.channelPlaylistLabel.classList.remove('positive');
|
||||
//Flip the caret
|
||||
this.channelPlaylistCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
|
||||
//Hide the div
|
||||
this.channelPlaylistDiv.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
renderChannelPlaylists(data){
|
||||
//Clear channel playlist div
|
||||
this.channelPlaylistDiv.innerHTML = '';
|
||||
|
||||
//For every playlist sent down from the server
|
||||
for(let playlistIndex in data){
|
||||
//Get playlist from data
|
||||
const playlist = data[playlistIndex];
|
||||
|
||||
//--Create Base Structure---
|
||||
//Create a new playlist div
|
||||
const playlistDiv = document.createElement('div');
|
||||
//Set it's class
|
||||
playlistDiv.classList.add('queue-playlist-div');
|
||||
|
||||
//Set playlist div dataset
|
||||
playlistDiv.dataset.name = playlist.name;
|
||||
|
||||
//If this isn't our first rodeo
|
||||
if(playlistIndex != 0){
|
||||
//make note
|
||||
playlistDiv.classList.add('not-first-queue-playlist-div');
|
||||
}
|
||||
|
||||
//Create span to hold playlist entry line contents
|
||||
const playlistSpan = document.createElement('span');
|
||||
//Set classes
|
||||
playlistSpan.classList.add('queue-playlist-span');
|
||||
|
||||
//--Create Labels---
|
||||
//Create playlist label span
|
||||
const playlistLabels = document.createElement('span');
|
||||
//Set it's class
|
||||
playlistLabels.classList.add('queue-playlist-labels-span');
|
||||
|
||||
//Create playlist title label
|
||||
const playlistTitle = document.createElement('p');
|
||||
//Set it's class
|
||||
playlistTitle.classList.add('queue-playlist-title');
|
||||
|
||||
//Create playlist count label
|
||||
const playlistCount = document.createElement('p');
|
||||
//Set it's class
|
||||
playlistCount.classList.add('queue-playlist-count');
|
||||
//List video count
|
||||
playlistCount.innerText = `Count: ${playlist.media.length}`;
|
||||
|
||||
//--Create Controls--
|
||||
//Create playlist control span
|
||||
const playlistControls = document.createElement('span');
|
||||
//Set it's class
|
||||
playlistControls.classList.add('queue-playlist-control-span');
|
||||
//Unescape Sanatized Enteties and safely inject as plaintext
|
||||
playlistTitle.innerText = utils.unescapeEntities(playlist.name);
|
||||
|
||||
//Create queue all button
|
||||
const playlistQueueRandomButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistQueueRandomButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control');
|
||||
//Inject text content
|
||||
playlistQueueRandomButton.textContent = 'Queue Random';
|
||||
|
||||
//Create queue all button
|
||||
const playlistQueueAllButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistQueueAllButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control');
|
||||
//Inject text content
|
||||
playlistQueueAllButton.textContent = 'Queue All';
|
||||
|
||||
//Create delete button
|
||||
const playlistDeleteButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistDeleteButton.classList.add('queue-playlist-delete-button', 'queue-playlist-control', 'danger-button', 'bi-trash-fill');
|
||||
|
||||
//--Create Media Elements--
|
||||
//Create Media Container Div
|
||||
const mediaDiv = renderMedia();
|
||||
|
||||
//Append items to playlist labels span
|
||||
playlistLabels.appendChild(playlistTitle);
|
||||
playlistLabels.appendChild(playlistCount);
|
||||
|
||||
//Append items to playlist control span
|
||||
playlistControls.appendChild(playlistQueueRandomButton);
|
||||
playlistControls.appendChild(playlistQueueAllButton);
|
||||
playlistControls.appendChild(playlistDeleteButton);
|
||||
|
||||
//Append items to playlist span
|
||||
playlistSpan.appendChild(playlistLabels);
|
||||
playlistSpan.appendChild(playlistControls);
|
||||
|
||||
//Append items to playlist div
|
||||
playlistDiv.appendChild(playlistSpan);
|
||||
playlistDiv.appendChild(mediaDiv);
|
||||
|
||||
//Append current playlist span to the channel playlist div
|
||||
this.channelPlaylistDiv.appendChild(playlistDiv);
|
||||
|
||||
//Define input event listeners
|
||||
playlistQueueAllButton.addEventListener('click', queueAll);
|
||||
playlistDeleteButton.addEventListener('click', deletePlaylist);
|
||||
|
||||
//aux rendering functions
|
||||
function renderMedia(){
|
||||
//Create media container div
|
||||
const mediaContainer = document.createElement('div');
|
||||
//Set classes
|
||||
mediaContainer.classList.add('queue-playlist-media-div');
|
||||
|
||||
//return media container
|
||||
return mediaContainer;
|
||||
}
|
||||
|
||||
//playlist control functions
|
||||
function queueAll(){
|
||||
client.socket.emit('queueChannelPlaylist', {playlist: playlist.name});
|
||||
}
|
||||
|
||||
function deletePlaylist(){
|
||||
client.socket.emit('deleteChannelPlaylist', {playlist: playlist.name});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class newPlaylistPopup{
|
||||
constructor(event, client, doc){
|
||||
//Set Client
|
||||
this.client = client;
|
||||
|
||||
//Create media popup and call async constructor when done
|
||||
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
|
||||
this.popup = new canopyUXUtils.popup('/newPlaylist', true, this.asyncConstructor.bind(this), doc);
|
||||
}
|
||||
|
||||
asyncConstructor(){
|
||||
this.name = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-name');
|
||||
this.defaultTitles = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-default-titles');
|
||||
this.location = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-location');
|
||||
this.saveButton = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-save');
|
||||
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
setupInput(){
|
||||
//Setup input
|
||||
this.saveButton.addEventListener('click', this.createPlaylist.bind(this));
|
||||
this.popup.popupDiv.addEventListener('keydown', this.createPlaylist.bind(this));
|
||||
}
|
||||
|
||||
createPlaylist(event){
|
||||
//If we clicked or hit enter
|
||||
if(event.key == null || event.key == "Enter"){
|
||||
|
||||
//If we're saving to the channel
|
||||
if(this.location.value == 'channel'){
|
||||
//Tell the server to create a new channel playlist
|
||||
this.client.socket.emit('createChannelPlaylist', {
|
||||
playlist: this.name.value,
|
||||
defaultTitles: this.defaultTitles.value.split('\n')
|
||||
})
|
||||
}
|
||||
|
||||
//Close the popup
|
||||
this.popup.closePopup();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class schedulePopup{
|
||||
constructor(event, client, url, title, cb, doc){
|
||||
//Set Client
|
||||
|
|
|
|||
Loading…
Reference in a new issue