Initial commit.
This commit is contained in:
commit
f0c91b4e55
78 changed files with 5054 additions and 0 deletions
47
www/js/channel/channel.js
Normal file
47
www/js/channel/channel.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 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/>.*/
|
||||
|
||||
class channel{
|
||||
constructor(){
|
||||
//Establish connetion to the server via socket.io
|
||||
this.connect();
|
||||
//Define socket listeners
|
||||
this.defineListeners();
|
||||
|
||||
//Scrape channel name off URL
|
||||
this.channelName = window.location.pathname.split('/c/')[`1`];
|
||||
|
||||
//Create the Video Player Object
|
||||
this.player = new player(this);
|
||||
//Create the Chat Box Object
|
||||
this.chatBox = new chatBox(this);
|
||||
//Create the User List Object
|
||||
this.userList = new userList(this);
|
||||
}
|
||||
|
||||
connect(){
|
||||
this.socket = io();
|
||||
}
|
||||
|
||||
defineListeners(){
|
||||
//This function should serve mostly to glue functions from channel and it's children to it's socket's listeners.
|
||||
this.socket.on("connect", () => {
|
||||
document.title = `${this.channelName} - Connected`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const client = new channel();
|
||||
149
www/js/channel/chat.js
Normal file
149
www/js/channel/chat.js
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 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/>.*/
|
||||
|
||||
class chatBox{
|
||||
constructor(client){
|
||||
//Client Object
|
||||
this.client = client
|
||||
|
||||
//Booleans
|
||||
this.aspectLock = true;
|
||||
|
||||
//clickDragger object
|
||||
this.clickDragger = new canopyUXUtils.clickDragger("#chat-panel-drag-handle", "#chat-panel-div", "#chat-panel-user-count");
|
||||
|
||||
//Element Nodes
|
||||
this.chatPanel = document.querySelector("#chat-panel-div");
|
||||
this.chatBuffer = document.querySelector("#chat-panel-buffer-div");
|
||||
this.chatPrompt = document.querySelector("#chat-panel-prompt");
|
||||
this.sendButton = document.querySelector("#chat-panel-send-button");
|
||||
this.highLevel = document.querySelector("#chat-panel-high-level-select");
|
||||
//Seems weird to stick this in here, but the split is dictated by chat width :P
|
||||
this.aspectLockIcon = document.querySelector("#media-panel-aspect-lock-icon");
|
||||
this.hideChatIcon = document.querySelector("#chat-panel-div-hide");
|
||||
this.showChatIcon = document.querySelector("#media-panel-show-chat-icon");
|
||||
|
||||
//Setup functions
|
||||
this.setupInput();
|
||||
this.defineListeners();
|
||||
this.sizeToAspect();
|
||||
}
|
||||
|
||||
setupInput(){
|
||||
//Chat bar
|
||||
this.chatPrompt.addEventListener("keydown", this.send.bind(this));
|
||||
this.sendButton.addEventListener("click", this.send.bind(this));
|
||||
|
||||
//Header icons
|
||||
this.aspectLockIcon.addEventListener("click", this.lockAspect.bind(this));
|
||||
this.showChatIcon.addEventListener("click", ()=>{this.toggleUI()});
|
||||
this.hideChatIcon.addEventListener("click", ()=>{this.toggleUI()});
|
||||
|
||||
//Clickdragger/Resize
|
||||
this.clickDragger.handle.addEventListener("mousedown", this.unlockAspect.bind(this));
|
||||
window.addEventListener("resize", this.resizeAspect.bind(this));
|
||||
}
|
||||
|
||||
defineListeners(){
|
||||
this.client.socket.on("chat-message", (data) => {
|
||||
this.displayChat(data);
|
||||
});
|
||||
}
|
||||
|
||||
lockAspect(event){
|
||||
//prevent the user from breaking shit :P
|
||||
if(this.chatPanel.style.display != "none"){
|
||||
this.aspectLock = true;
|
||||
this.aspectLockIcon.style.display = "none";
|
||||
this.sizeToAspect();
|
||||
}
|
||||
}
|
||||
|
||||
unlockAspect(event){
|
||||
this.aspectLock = false;
|
||||
this.aspectLockIcon.style.display = "inline";
|
||||
}
|
||||
|
||||
resizeAspect(event){
|
||||
if(this.aspectLock){
|
||||
this.sizeToAspect();
|
||||
}
|
||||
}
|
||||
|
||||
sizeToAspect(){
|
||||
if(this.chatPanel.style.display != "none"){
|
||||
var targetVidWidth = this.client.player.getRatio() * this.chatPanel.getBoundingClientRect().height;
|
||||
|
||||
this.chatPanel.style.width = `${(document.body.getBoundingClientRect().width - targetVidWidth)}px`;
|
||||
|
||||
//Fix busted layout
|
||||
var pageBreak = document.body.scrollWidth - document.body.getBoundingClientRect().width;
|
||||
this.chatPanel.style.width = `${this.chatPanel.getBoundingClientRect().width + pageBreak}px`;
|
||||
}
|
||||
}
|
||||
|
||||
toggleUI(show = this.chatPanel.style.display == "none"){
|
||||
if(show){
|
||||
this.chatPanel.style.display = "flex";
|
||||
this.showChatIcon.style.display = "none";
|
||||
this.client.player.hideVideoIcon.style.display = "flex";
|
||||
}else{
|
||||
this.chatPanel.style.display = "none";
|
||||
this.showChatIcon.style.display = "flex";
|
||||
this.client.player.hideVideoIcon.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
displayChat(chat){
|
||||
//Create chat-entry span
|
||||
var chatEntry = document.createElement('span');
|
||||
chatEntry.classList.add("chat-panel-buffer","chat-entry",`chat-entry-${chat.user}`);
|
||||
|
||||
//Create high-level label
|
||||
var highLevel = document.createElement('p');
|
||||
highLevel.classList.add("chat-panel-buffer","chat-entry-high-level");
|
||||
highLevel.innerHTML = `${chat.high}`;
|
||||
chatEntry.appendChild(highLevel);
|
||||
|
||||
//Create username label
|
||||
var userLabel = document.createElement('p');
|
||||
userLabel.classList.add("chat-panel-buffer","chat-entry-username");
|
||||
|
||||
//Create color span
|
||||
var colorSpan = document.createElement('span');
|
||||
colorSpan.classList.add(this.client.userList.colorMap.get(chat.user));
|
||||
colorSpan.innerHTML = `${chat.user}`;
|
||||
userLabel.innerHTML = `${colorSpan.outerHTML}: `;
|
||||
|
||||
chatEntry.appendChild(userLabel);
|
||||
|
||||
//Create chat body
|
||||
var chatBody = document.createElement('p');
|
||||
chatBody.classList.add("chat-panel-buffer","chat-entry-body");
|
||||
chatBody.innerHTML = chat.msg;
|
||||
chatEntry.appendChild(chatBody);
|
||||
|
||||
this.chatBuffer.appendChild(chatEntry);
|
||||
}
|
||||
|
||||
async send(event){
|
||||
if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
|
||||
this.client.socket.emit("chat-message",{msg: this.chatPrompt.value, high: this.highLevel.value});
|
||||
this.chatPrompt.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
97
www/js/channel/player.js
Normal file
97
www/js/channel/player.js
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 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/>.*/
|
||||
|
||||
class player{
|
||||
constructor (client){
|
||||
//client obj
|
||||
this.client = client;
|
||||
|
||||
//booleans
|
||||
this.onUI = false;
|
||||
|
||||
//timers
|
||||
this.uiTimer = setTimeout(this.toggleUI.bind(this), 1500, false);
|
||||
|
||||
//elements
|
||||
this.playerDiv = document.querySelector("#media-panel-div");
|
||||
this.navBar = document.querySelector("#navbar");
|
||||
this.video = document.querySelector("#media-panel-video");
|
||||
this.uiBar = document.querySelector("#media-panel-head-div");
|
||||
this.showVideoIcon = document.querySelector("#chat-panel-show-video-icon");
|
||||
this.hideVideoIcon = document.querySelector("#media-panel-div-toggle-icon");
|
||||
this.cinemaModeIcon = document.querySelector("#media-panel-cinema-mode-icon");
|
||||
|
||||
//run setup functions
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
setupInput(){
|
||||
//UIBar Movement Detection
|
||||
this.playerDiv.addEventListener("mousemove", this.popUI.bind(this));
|
||||
this.uiBar.addEventListener("mouseenter", ()=>{this.setOnUI(true)});
|
||||
this.uiBar.addEventListener("mouseleave", ()=>{this.setOnUI(false)});
|
||||
|
||||
//UIBar/header icons
|
||||
this.showVideoIcon.addEventListener("click", ()=>{this.toggleVideo()});
|
||||
this.hideVideoIcon.addEventListener("click", ()=>{this.toggleVideo()});
|
||||
this.cinemaModeIcon.addEventListener("click", ()=>{this.toggleCinemaMode()});
|
||||
}
|
||||
|
||||
popUI(event){
|
||||
this.toggleUI(true);
|
||||
clearTimeout(this.uiTimer);
|
||||
if(!this.onUI){
|
||||
this.uiTimer = setTimeout(this.toggleUI.bind(this), 1500, false);
|
||||
}
|
||||
}
|
||||
|
||||
toggleUI(show = this.uiBar.style.display == "none"){
|
||||
this.uiBar.style.display = show ? "flex" : "none";
|
||||
}
|
||||
|
||||
toggleVideo(show = this.playerDiv.style.display == "none"){
|
||||
if(show){
|
||||
this.playerDiv.style.display = "flex";
|
||||
this.showVideoIcon.style.display = "none";
|
||||
this.client.chatBox.hideChatIcon.style.display = "flex";
|
||||
//Lock the chat to aspect ratio of the video, to make sure the chat width isn't breaking shit
|
||||
this.client.chatBox.lockAspect();
|
||||
}else{
|
||||
this.playerDiv.style.display = "none";
|
||||
this.showVideoIcon.style.display = "flex";
|
||||
this.client.chatBox.hideChatIcon.style.display = "none";
|
||||
//Need to clear the width from the split, or else it doesn't display properly
|
||||
this.client.chatBox.chatPanel.style.width = "100%";
|
||||
}
|
||||
}
|
||||
|
||||
toggleCinemaMode(cinema = this.navBar.style.display == "none"){
|
||||
if(cinema){
|
||||
this.navBar.style.display = "flex";
|
||||
}else{
|
||||
this.navBar.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
setOnUI(onUI){
|
||||
this.onUI = onUI;
|
||||
this.popUI();
|
||||
}
|
||||
|
||||
getRatio(){
|
||||
return this.video.videoWidth / this.video.videoHeight;
|
||||
}
|
||||
}
|
||||
107
www/js/channel/userlist.js
Normal file
107
www/js/channel/userlist.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*Canopy - The next generation of stoner streaming software
|
||||
Copyright (C) 2024 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/>.*/
|
||||
|
||||
class userList{
|
||||
constructor(client){
|
||||
//Client object
|
||||
this.client = client
|
||||
|
||||
//Click Dragger Object
|
||||
this.clickDragger = new canopyUXUtils.clickDragger("#chat-panel-users-drag-handle", "#chat-panel-users-div");
|
||||
|
||||
//Strings
|
||||
this.userColors = [
|
||||
"userlist-color0",
|
||||
"userlist-color1",
|
||||
"userlist-color2",
|
||||
"userlist-color3",
|
||||
"userlist-color4",
|
||||
"userlist-color5",
|
||||
"userlist-color6"];
|
||||
|
||||
//Maps
|
||||
this.colorMap = new Map();
|
||||
|
||||
//Element Nodes
|
||||
this.userDiv = document.querySelector("#chat-panel-users-div");
|
||||
this.userList = document.querySelector("#chat-panel-users-list-div");
|
||||
this.userCount = document.querySelector("#chat-panel-user-count");
|
||||
this.toggleIcon = document.querySelector("#chat-panel-users-toggle");
|
||||
|
||||
//Call setup functions
|
||||
this.setupInput();
|
||||
this.defineListeners();
|
||||
}
|
||||
|
||||
//Setup functions
|
||||
setupInput(){
|
||||
this.toggleIcon.addEventListener("click", ()=>{this.toggleUI()});
|
||||
this.userCount.addEventListener("click", ()=>{this.toggleUI()});
|
||||
}
|
||||
|
||||
defineListeners(){
|
||||
this.client.socket.on('user-list', (data) => {
|
||||
this.updateList(data);
|
||||
});
|
||||
}
|
||||
|
||||
updateList(list){
|
||||
//Clear list and set user count
|
||||
this.userCount.textContent = list.length == 1 ? '1 User' : `${list.length} Users`;
|
||||
this.userList.innerHTML = null;
|
||||
|
||||
//create a new map
|
||||
var newMap = new Map();
|
||||
|
||||
//for each user
|
||||
list.forEach((user) => {
|
||||
//randomly pick a color
|
||||
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
|
||||
|
||||
//if this user was in the previous colormap
|
||||
if(this.colorMap.get(user) != null){
|
||||
//Override with previous color
|
||||
color = this.colorMap.get(user);
|
||||
}
|
||||
|
||||
newMap.set(user, color);
|
||||
this.renderUser(user, color);
|
||||
});
|
||||
|
||||
this.colorMap = newMap;
|
||||
}
|
||||
|
||||
renderUser(user, color){
|
||||
var userEntry = document.createElement('p');
|
||||
|
||||
userEntry.innerText = user;
|
||||
userEntry.id = `user-entry-${user}`;
|
||||
userEntry.classList.add("chat-panel-users","user-entry",color);
|
||||
|
||||
this.userList.appendChild(userEntry);
|
||||
}
|
||||
|
||||
toggleUI(show = this.userDiv.style.display == "none"){
|
||||
if(show){
|
||||
this.userDiv.style.display = "flex";
|
||||
this.toggleIcon.classList.replace("bi-caret-left-fill","bi-caret-down-fill");
|
||||
}else{
|
||||
this.userDiv.style.display = "none";
|
||||
this.toggleIcon.classList.replace("bi-caret-down-fill","bi-caret-left-fill");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue