Merge branch 'dev'
This commit is contained in:
commit
584dcf1ac7
13 changed files with 176 additions and 22 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -10,3 +10,4 @@ server.cert
|
||||||
server.key
|
server.key
|
||||||
www/nonfree/*
|
www/nonfree/*
|
||||||
migration/*
|
migration/*
|
||||||
|
www/hrt.zip
|
||||||
|
|
@ -9,7 +9,7 @@ Canopy
|
||||||
<a href="https://git.ourfore.st/rainbownapkin/canopy/issues" target="_blank"><img src="https://git.ourfore.st/rainbownapkin/canopy/badges/issues/closed.svg"></a>
|
<a href="https://git.ourfore.st/rainbownapkin/canopy/issues" target="_blank"><img src="https://git.ourfore.st/rainbownapkin/canopy/badges/issues/closed.svg"></a>
|
||||||
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank"><img src="https://img.shields.io/badge/License-AGPL_v3-663366.svg"></a>
|
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank"><img src="https://img.shields.io/badge/License-AGPL_v3-663366.svg"></a>
|
||||||
|
|
||||||
0.1-Alpha (Panama Red) - Hotfix 1
|
0.1-Alpha (Panama Red) - Hotfix 2
|
||||||
=========
|
=========
|
||||||
|
|
||||||
Canopy - /ˈkæ.nə.pi/:
|
Canopy - /ˈkæ.nə.pi/:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "canopy-of-alpha",
|
"name": "canopy-of-alpha",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"canopyDisplayVersion": "0.1-Alpha (Panama Red) - Hotfix 1",
|
"canopyDisplayVersion": "0.1-Alpha (Panama Red) - Hotfix 2",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "^7.1.1",
|
"@braintree/sanitize-url": "^7.1.1",
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,12 @@ class chatHandler{
|
||||||
* @param {chat} chat - Chat Object representing the message to broadcast to the given channel
|
* @param {chat} chat - Chat Object representing the message to broadcast to the given channel
|
||||||
*/
|
*/
|
||||||
relayChatObject(chan, chat){
|
relayChatObject(chan, chat){
|
||||||
|
//If we have an empty chat
|
||||||
|
if(chat.msg.length <= 0){
|
||||||
|
//Drop it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Send out chat
|
//Send out chat
|
||||||
this.server.io.in(chan).emit("chatMessage", chat);
|
this.server.io.in(chan).emit("chatMessage", chat);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,15 @@ class tokebot{
|
||||||
|
|
||||||
//Add the toking user to the tokers map
|
//Add the toking user to the tokers map
|
||||||
this.tokers.set(commandObj.socket.user.user, commandObj.argumentArray[0].toLowerCase());
|
this.tokers.set(commandObj.socket.user.user, commandObj.argumentArray[0].toLowerCase());
|
||||||
|
|
||||||
|
if(this.tokeCounter <= 3){
|
||||||
|
//Drop the toke timer
|
||||||
|
clearTimeout(this.tokeTimer);
|
||||||
|
//Roll the toke counter back to 3
|
||||||
|
this.tokeCounter = 3;
|
||||||
|
//Re-start the toke timer
|
||||||
|
this.tokeTimer = setTimeout(this.countdown.bind(this), 1000);
|
||||||
|
}
|
||||||
//If the user is already in the toke
|
//If the user is already in the toke
|
||||||
}else{
|
}else{
|
||||||
//Tell them to fuck off
|
//Tell them to fuck off
|
||||||
|
|
@ -210,7 +219,7 @@ class tokebot{
|
||||||
//Decrement toke time
|
//Decrement toke time
|
||||||
this.tokeCounter--;
|
this.tokeCounter--;
|
||||||
//try again in another second
|
//try again in another second
|
||||||
this.tokeTimer = setTimeout(this.countdown.bind(this), 1000)
|
this.tokeTimer = setTimeout(this.countdown.bind(this), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
28
src/controllers/hrtController.js
Normal file
28
src/controllers/hrtController.js
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/>.*/
|
||||||
|
|
||||||
|
//Config
|
||||||
|
const config = require('../../config.json');
|
||||||
|
const package = require('../../package.json');
|
||||||
|
|
||||||
|
//Local Imports
|
||||||
|
const csrfUtils = require('../utils/csrfUtils');
|
||||||
|
|
||||||
|
//register page functions
|
||||||
|
module.exports.get = async function(req, res){
|
||||||
|
//Render page
|
||||||
|
return res.render('hrt', {instance: config.instanceName, user: req.session.user, csrfToken: csrfUtils.generateToken(req)});
|
||||||
|
}
|
||||||
34
src/routers/hrtRouter.js
Normal file
34
src/routers/hrtRouter.js
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*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 { Router } = require('express');
|
||||||
|
|
||||||
|
|
||||||
|
//local imports
|
||||||
|
const hrtController = require("../controllers/hrtController");
|
||||||
|
const presenceUtils = require("../utils/presenceUtils");
|
||||||
|
|
||||||
|
//globals
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
//Use presence middleware
|
||||||
|
router.use(presenceUtils.presenceMiddleware);
|
||||||
|
|
||||||
|
//routing functions
|
||||||
|
router.get('/', hrtController.get);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
@ -55,6 +55,7 @@ const fileNotFoundController = require('./controllers/404Controller');
|
||||||
//Humie-Friendly
|
//Humie-Friendly
|
||||||
const indexRouter = require('./routers/indexRouter');
|
const indexRouter = require('./routers/indexRouter');
|
||||||
const aboutRouter = require('./routers/aboutRouter');
|
const aboutRouter = require('./routers/aboutRouter');
|
||||||
|
const hrtRouter = require('./routers/hrtRouter');
|
||||||
const registerRouter = require('./routers/registerRouter');
|
const registerRouter = require('./routers/registerRouter');
|
||||||
const loginRouter = require('./routers/loginRouter');
|
const loginRouter = require('./routers/loginRouter');
|
||||||
const profileRouter = require('./routers/profileRouter');
|
const profileRouter = require('./routers/profileRouter');
|
||||||
|
|
@ -179,6 +180,7 @@ app.use(sessionUtils.rememberMeMiddleware);
|
||||||
//Humie-Friendly
|
//Humie-Friendly
|
||||||
app.use('/', indexRouter);
|
app.use('/', indexRouter);
|
||||||
app.use('/about', aboutRouter);
|
app.use('/about', aboutRouter);
|
||||||
|
app.use('/hrt', hrtRouter);
|
||||||
app.use('/register', registerRouter);
|
app.use('/register', registerRouter);
|
||||||
app.use('/login', loginRouter);
|
app.use('/login', loginRouter);
|
||||||
app.use('/profile', profileRouter);
|
app.use('/profile', profileRouter);
|
||||||
|
|
|
||||||
56
src/views/hrt.ejs
Normal file
56
src/views/hrt.ejs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
<%# 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/>. %>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<%- include('partial/styles', {instance, user}); %>
|
||||||
|
<%- include('partial/csrfToken', {csrfToken}); %>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/about.css">
|
||||||
|
<title><%= instance %> - DIY HRT Archive</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('partial/navbar', {user}); %>
|
||||||
|
<div id="about-div">
|
||||||
|
<h1>Bowie's DIY HRT Archive</h1>
|
||||||
|
<div class="dynamic-container" id="about-text">
|
||||||
|
<br>
|
||||||
|
This page is an attempt at putting together everything I know about DIY HRT.
|
||||||
|
<br><br>
|
||||||
|
So far I have used Homebrew Sublingual Oil from Open Gate Labs with great results, and have received a small batch of raw estradoil from Dragon Ordnance.
|
||||||
|
<br><br>
|
||||||
|
I am currently in the process of figuring out brewing my own sublingual oil.
|
||||||
|
<br><br>
|
||||||
|
<a href="/hrt.zip"><h3>This zip file contains everything I know.</h3></a>
|
||||||
|
<br>
|
||||||
|
<span>You should probably use <a href="https://www.torproject.org/">TOR</a> or a <a href="https://mullvad.net">decent VPN</a> in either an <a href="https://tails.net">amnesiac OS</a> or <a href="https://qubes-os.org">dispoable VM.</a> Everything paid w/ either <a href="https://www.getmonero.org/">XMR</a> or <a href="https://mullvad.net/en/blog/sending-cash-use-our-new-address">cash by mail</a>.</span>
|
||||||
|
<br><br>
|
||||||
|
<span class="critical-danger-text">
|
||||||
|
This page is not intended to be a replacement for professional medical advice, merely an attempt at harm reduction for my friends.
|
||||||
|
It should be used at most as a starting point for research. Everyone's HRT experience, and really transition, are unique and individual journeys.
|
||||||
|
Take the time to do the best research you can, to make sure you're starting and continuing yours correctly.
|
||||||
|
</span>
|
||||||
|
<br><br>
|
||||||
|
Much love, and remember to take your meds!
|
||||||
|
<br><br>
|
||||||
|
-rainbownapkin <3
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<%- include('partial/scripts', {user}); %>
|
||||||
|
</footer>
|
||||||
|
</html>
|
||||||
|
|
@ -140,10 +140,11 @@ class chatPostprocessor{
|
||||||
this.messageArray = [];
|
this.messageArray = [];
|
||||||
|
|
||||||
//Unescape any sanatized char codes as we use .textContent for double-safety, and to prevent splitting of char codes
|
//Unescape any sanatized char codes as we use .textContent for double-safety, and to prevent splitting of char codes
|
||||||
//Split string by word-boundries on words and non-word boundries around whitespace, with negative lookaheads to exclude file seperators so we don't split link placeholders, and dashes so we dont split usernames and other things
|
//Split string by word-boundries on words and non-word boundries around whitespace,
|
||||||
|
//with negative lookaheads to exclude file seperators so we don't split link placeholders, dashes so we dont split usernames and other things, and accented characters to keep those from splitting boundries too
|
||||||
//Also split by any invisble whitespace as a crutch to handle mushed links/emotes
|
//Also split by any invisble whitespace as a crutch to handle mushed links/emotes
|
||||||
//If we can one day figure out how to split non-repeating special chars instead of special chars with whitespace, that would be perf, unfortunately my brain hasn't rotted enough to understand regex like that just yet.
|
//If we can one day figure out how to split non-repeating special chars instead of special chars with whitespace, that would be perf, unfortunately my brain hasn't rotted enough to understand regex like that just yet.
|
||||||
const splitString = utils.unescapeEntities(this.rawData.msg).split(/(?<!-)(?<!␜)(?=\w)\b|(?!-)(?<=\w)\b|(?=\s)\B|(?<=\s)\B|ㅤ/g);
|
const splitString = utils.unescapeEntities(this.rawData.msg).split(/(?<!-)(?<!␜)(?=\w)\b|(?!-|[\u00C0-\u017F])(?<=\w)\b|(?=\s)\B|(?<=\s)\B|ㅤ/g);
|
||||||
|
|
||||||
//for each word in the splitstring
|
//for each word in the splitstring
|
||||||
splitString.forEach((string) => {
|
splitString.forEach((string) => {
|
||||||
|
|
@ -259,7 +260,7 @@ class chatPostprocessor{
|
||||||
link.textContent = wordObj.command;
|
link.textContent = wordObj.command;
|
||||||
|
|
||||||
//Add chatbox functionality
|
//Add chatbox functionality
|
||||||
link.addEventListener('click', () => {this.client.chatBox.commandPreprocessor.preprocess(wordObj.command)});
|
link.addEventListener('click', () => {this.client.chatBox.transmit(wordObj.command)});
|
||||||
|
|
||||||
//We don't have to worry about injecting this into whitespace since there shouldn't be any here.
|
//We don't have to worry about injecting this into whitespace since there shouldn't be any here.
|
||||||
injectionArray.push(link);
|
injectionArray.push(link);
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,8 @@ class commandPreprocessor{
|
||||||
usernames:{
|
usernames:{
|
||||||
prefix: '',
|
prefix: '',
|
||||||
postfix: '',
|
postfix: '',
|
||||||
cmds: injectPerms(Array.from(client.userList.colorMap.keys()))
|
//cmds: injectPerms(Array.from(client.userList.colorMap.keys()))
|
||||||
|
cmds: injectPerms(client.userList.getOnlineUserNames())
|
||||||
},
|
},
|
||||||
emotes:{
|
emotes:{
|
||||||
prefix:'[',
|
prefix:'[',
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,12 @@ class userList{
|
||||||
*/
|
*/
|
||||||
this.clickDragger = new canopyUXUtils.clickDragger("#chat-panel-users-drag-handle", "#chat-panel-users-div", true, this.client.chatBox.clickDragger);
|
this.clickDragger = new canopyUXUtils.clickDragger("#chat-panel-users-drag-handle", "#chat-panel-users-div", true, this.client.chatBox.clickDragger);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of currently connected users
|
||||||
|
*/
|
||||||
|
this.userList = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Userlist color array (Maps to css classes)
|
* Userlist color array (Maps to css classes)
|
||||||
*/
|
*/
|
||||||
|
|
@ -46,7 +52,7 @@ class userList{
|
||||||
"userlist-color6"];
|
"userlist-color6"];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of usernames to assigned username color
|
* Map of connected and buffered usernames to assigned username color/flair
|
||||||
*/
|
*/
|
||||||
this.colorMap = new Map();
|
this.colorMap = new Map();
|
||||||
|
|
||||||
|
|
@ -58,7 +64,7 @@ class userList{
|
||||||
/**
|
/**
|
||||||
* userlist div
|
* userlist div
|
||||||
*/
|
*/
|
||||||
this.userList = document.querySelector("#chat-panel-users-list-div");
|
this.userListDiv = document.querySelector("#chat-panel-users-list-div");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* user count label
|
* user count label
|
||||||
|
|
@ -103,28 +109,28 @@ class userList{
|
||||||
updateList(list){
|
updateList(list){
|
||||||
//Clear list and set user count
|
//Clear list and set user count
|
||||||
this.userCount.textContent = list.length == 1 ? '1 User' : `${list.length} Users`;
|
this.userCount.textContent = list.length == 1 ? '1 User' : `${list.length} Users`;
|
||||||
this.userList.innerHTML = null;
|
this.userListDiv.innerHTML = null;
|
||||||
|
|
||||||
//create a new map
|
//Set userlist array to received list
|
||||||
var newMap = new Map();
|
this.userList = list;
|
||||||
|
|
||||||
//for each user
|
//for each user
|
||||||
list.forEach((user) => {
|
list.forEach((user) => {
|
||||||
//randomly pick a color
|
//randomly pick a color
|
||||||
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
|
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
|
||||||
|
|
||||||
//if this user was in the previous colormap
|
//if this user wasn't in the previous colormap
|
||||||
if(this.colorMap.get(user.user) != null){
|
if(this.colorMap.get(user.user) == null){
|
||||||
//Override with previous color
|
//Store new randomly selected color
|
||||||
|
this.colorMap.set(user.user, color);
|
||||||
|
}else{
|
||||||
|
//Use color from previous entry
|
||||||
color = this.colorMap.get(user.user);
|
color = this.colorMap.get(user.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
newMap.set(user.user, color);
|
|
||||||
this.renderUser(user, color);
|
this.renderUser(user, color);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.colorMap = newMap;
|
|
||||||
|
|
||||||
//Make sure we're not cutting the ux off
|
//Make sure we're not cutting the ux off
|
||||||
this.clickDragger.fixCutoff();
|
this.clickDragger.fixCutoff();
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +174,7 @@ class userList{
|
||||||
userSpan.addEventListener('click', renderContextMenu.bind(this));
|
userSpan.addEventListener('click', renderContextMenu.bind(this));
|
||||||
userSpan.addEventListener('contextmenu', renderContextMenu.bind(this));
|
userSpan.addEventListener('contextmenu', renderContextMenu.bind(this));
|
||||||
|
|
||||||
this.userList.appendChild(userSpan);
|
this.userListDiv.appendChild(userSpan);
|
||||||
|
|
||||||
function renderContextMenu(event){
|
function renderContextMenu(event){
|
||||||
//Setup menu map
|
//Setup menu map
|
||||||
|
|
@ -211,4 +217,14 @@ class userList{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//returns list of strings containing all currently online users
|
||||||
|
getOnlineUserNames(){
|
||||||
|
var names = [];
|
||||||
|
|
||||||
|
for(let user of this.userList){
|
||||||
|
names.push(user.user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +198,7 @@ class rankList{
|
||||||
imgNode.src = user.img;
|
imgNode.src = user.img;
|
||||||
|
|
||||||
//If the listed user rank is equal or higher than the signed-in user
|
//If the listed user rank is equal or higher than the signed-in user
|
||||||
if(rankEnum.indexOf(user.rank) >= rankEnum.indexOf(curUser.rank)){
|
if(curUser != null && rankEnum.indexOf(user.rank) >= rankEnum.indexOf(curUser.rank)){
|
||||||
var rankContent = user.rank;
|
var rankContent = user.rank;
|
||||||
}else{
|
}else{
|
||||||
//Create rank select
|
//Create rank select
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue