Compare commits

...

3 commits

9 changed files with 166 additions and 15 deletions

View file

@ -197,8 +197,6 @@ class connectedUser{
chanDB = await channelModel.findOne({name: this.channel.name});
}
//If our perm map is un-initiated
//can't set this in constructor easily since it's asyncornous
//need to wait for it to complete before sending this off, but shouldnt re-do the wait for later connections
if(this.permMap == null){
//Grab perm map
@ -238,7 +236,7 @@ class connectedUser{
const chatBuffer = this.channel.chatBuffer.buffer;
//Send off the metadata to our user's clients
this.emit("clientMetadata", {user: userObj, flairList, queueLock, chatBuffer});
this.emit("clientMetadata", {user: userObj, flairList, queueLock, chatBuffer, streamType: chanDB.settings.streamType});
}
/**

View file

@ -120,6 +120,7 @@ class queue{
socket.on("move", (data) => {this.moveMedia(socket, data)});
socket.on("lock", () => {this.toggleLock(socket)});
socket.on("goLive", (data) => {this.goLive(socket, data)});
socket.on("getStreamType", (data) => {this.getStreamType(socket)});
//If debug mode is enabled
if(config.debug){
@ -357,6 +358,18 @@ class queue{
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
}
//If the user doesn't have permission to be doing this shit
if(!((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin'))){
//Fuggettabouttit!
return;
}
if(chanDB.settings.streamType == "webrtc"){
console.log("WEBRTC ENABLED, BAILING!");
return;
}
//If something is playing
if(this.nowPlaying != null){
//Capture currently playing object
@ -403,7 +416,7 @@ class queue{
);
//Validate mode input, and default to overwrite
this.liveMode = (data.mode == "pushback") ? "pushback" : "overwrite";
this.liveMode = (data != null && data.mode == "pushback") ? "pushback" : "overwrite";
//Throw stream lock
this.streamLock = true;
@ -415,6 +428,22 @@ class queue{
}
}
/**
* Returns current channel stream type upon request
* @param {Socket} socket - Socket we received the request from
*/
async getStreamType(socket){
try{
//Get the current channel from the database
const chanDB = await channelModel.findOne({name: socket.chan});
//Send streamtype back down to user (Not perm checking for something someone can figure out by looking at a running livestream)
socket.emit("streamType", {streamType: chanDB.settings.streamType});
}catch(err){
return loggerUtils.socketExceptionHandler(socket, err);
}
}
async dumpQueue(socket, data){
//If we somehow got here while config.debug is disabled, or the user isn't allowed to preform server-side debugging
if(!(config.debug && await permissionModel.permCheck(socket.user, "debug"))){

View file

@ -35,6 +35,11 @@ const chatSchema = require('./chatSchema');
//Utils
const { exceptionHandler, errorHandler } = require('../../utils/loggerUtils');
/**
* "Enum" for emote type property
*/
const streamMethodEnum = ["webrtc","hls"];
/**
* DB Schema for Documents containing de-hydrated representations of Canopy Stream/Chat Channels
*/
@ -71,6 +76,12 @@ const channelSchema = new mongoose.Schema({
streamURL: {
type: mongoose.SchemaTypes.String,
default: ''
},
streamType: {
type: mongoose.SchemaTypes.String,
enum: streamMethodEnum,
default: streamMethodEnum[0]
}
},
permissions: {

View file

@ -20,15 +20,6 @@ const { checkSchema, checkExact } = require('express-validator');
//local imports
const accountValidator = require('./accountValidator');
module.exports = {
settingsMap: () => checkExact(checkSchema({
'settingsMap.hidden': {
optional: true,
isBoolean: true,
} }))
}
module.exports.name = function(field = 'name'){
return checkSchema({
[field]: {
@ -89,6 +80,13 @@ module.exports.settingsMap = function(){
}
},
errorMessage: "Invalid Stream URL"
},
'settingsMap.streamType': {
optional: true,
errorMessage: "Invalid Stream Type",
matches: {
options: [/\b(?:webrtc|hls)\b/]
}
}
})
);

View file

@ -17,7 +17,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
<h3>Channel Preferences:</h3>
<div class="dynamic-container">
<form action="javascript:" class="admin-list-field">
<% Object.keys(channel.settings).forEach((key) => { %>
<% for(key of Object.keys(channel.settings)){
//Ignore keys w/ custom HTML
if(key == "streamURL" || key == "streamType"){
break;
}%>
<span class="admin-list-field-container">
<label class="admin-list-label"><%= key %>:</label>
<% switch(typeof channel.settings[key]){
@ -29,7 +33,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
<% break;
} %>
</span>
<% }); %>
<% }; %>
<span class="admin-list-field-container">
<p>Livestream Type:</p>
<span id="channel-preference-list-stream-settings-grid">
<span>
<input type="radio" name="streamType" id="channel-preference-list-stream-type-webrtc" value="webrtc" <% if(channel.settings["streamType"] == "webrtc"){ %> checked <% }%> >
<label for="channel-preference-list-stream-type-webrtc">Peer-to-Peer (WebRTC/STUN)</label>
</span>
<span>
<input type="radio" name="streamType" id="channel-preference-list-stream-type-hls" value="hls" <% if(channel.settings["streamType"] == "hls"){ %> checked <% }%> >
<label for="channel-preference-list-stream-type-hls">Self-Hosted (HLS)</label>
</span>
<input <% if(channel.settings["streamType"] != "hls"){ %> disabled <%}%> id="channel-preference-list-stream-url" placeholder="Stream URL" value="<%= channel.settings["streamURL"] %>">
</span>
</span>
</form>
</div>
</div>

View file

@ -139,6 +139,16 @@ img.admin-list-entry-item{
width: 8em;
}
#channel-preference-list-stream-settings-grid{
display: grid;
grid-template-columns: auto auto;
row-gap: 0.5em;
}
#channel-preference-list-stream-url {
grid-column: 2;
}
div.toke-command-list{
display: grid;
grid-template-columns: repeat(auto-fit, minmax(15em, 1fr));

View file

@ -117,6 +117,10 @@ class channel{
this.queueLock = data.locked;
});
this.socket.on("streamType", (data) => {
this.streamType = data.streamType;
});
this.queueBroadcastSocket.on("queue", (data) => {
this.queue = new Map(data.queue);
});
@ -146,6 +150,9 @@ class channel{
//Store queue lock status
this.queueLock = data.queueLock;
//Store streamType
this.streamType = data.streamType;
}
/**

View file

@ -54,6 +54,8 @@ class queuePanel extends panelObj{
*/
this.playlistManager = new playlistManager(client, panelDocument, this);
this.streamType = "";
//Define non-input event listeners
this.defineListeners();
}
@ -65,6 +67,9 @@ class queuePanel extends panelObj{
//Call derived doc switch function
super.docSwitch();
//Request Channel Stream Type
this.client.socket.emit('getStreamType');
//Get queue div
this.queue = this.panelDocument.querySelector('#queue');
//Get queue container
@ -243,6 +248,10 @@ class queuePanel extends panelObj{
}
}
handleStreamType(data){
}
/* queue control button functions */
/**
@ -269,6 +278,9 @@ class queuePanel extends panelObj{
* @param {Event} event - Event passed down from Event Listener
*/
toggleGoLive(event){
//Request stream type from the server Just-InCase™
client.socket.emit('getStreamType');
//If we're not livestreaming
if(client.player.mediaHandler.type != "livehls"){
//If the div is hidden

View file

@ -24,6 +24,7 @@ class channelSettingsPage{
this.banList = new banList(this.channel);
this.permList = new permList(this.channel);
this.prefrenceList = new prefrenceList(this.channel);
this.livestreamPreferences = new livestreamPreferences(this.channel);
this.tokeCommandList = new tokeCommandList(this.channel);
this.emoteList = new emoteList(this.channel);
this.deleteBtn = new deleteBtn(this.channel);
@ -364,6 +365,72 @@ class prefrenceList{
}
}
class livestreamPreferences{
constructor(channel){
this.channel = channel;
//Grab inputs
this.webRTCButton = document.querySelector("#channel-preference-list-stream-type-webrtc");
this.hlsButton = document.querySelector("#channel-preference-list-stream-type-hls");
this.streamURL = document.querySelector("#channel-preference-list-stream-url");
//Setup Input
this.setupInput();
}
setupInput(){
//Add event listeners
this.webRTCButton.addEventListener("change", this.submitTypeUpdate.bind(this));
this.hlsButton.addEventListener("change", this.submitTypeUpdate.bind(this));
this.streamURL.addEventListener("change",this.submitURLUpdate.bind(this));
}
async submitURLUpdate(event){
//Grab value from event target
const value = event.target.value;
//Send setting change request to server, and store update once its received
const update = await utils.ajax.setChannelSetting(this.channel, new Map([["streamURL", value]]));
//If we we're given a good update
if(update != null && update.streamURL != null){
//Display the new streamURL in the input (I'm not making a dedicated method for a fuckin' one-liner)
this.streamURL.value = update.streamURL
}
}
async submitTypeUpdate(event){
//Grab value from event target
const value = event.target.value;
//Send setting change request to server, and store update once its received
const update = await utils.ajax.setChannelSetting(this.channel, new Map([["streamType", value]]));
//Pass update to the handleUpdate method
this.handleTypeUpdate(update);
}
handleTypeUpdate(data){
//If the stream type is HLS
if(data.streamType == "hls"){
//Ensure the hls button is checked
this.hlsButton.checked = true;
//Ensure the stream url input is enabled
this.streamURL.disabled = false;
//Otherwise
}else{
//Ensure the stream url input is disabled
this.streamURL.disabled = true;
}
//If the stream type is webrtc
if(data.streamType == "webrtc"){
//Ensure the webrtc button is checked
this.webRTCButton.checked = true;
}
}
}
class permList{
constructor(channel){
this.channel = channel