various updates.

This commit is contained in:
Khyretos 2023-12-28 16:25:52 +01:00
parent 914cf831c4
commit 525cb6116e
45 changed files with 5022 additions and 5277 deletions

9
.editorconfig Normal file
View file

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

5
.eslintignore Normal file
View file

@ -0,0 +1,5 @@
node_modules
docs
dist
out
build

16
.eslintrc.js Normal file
View file

@ -0,0 +1,16 @@
module.exports = {
root: true,
env: {
es6: true,
node: true
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 2021
},
extends: ['eslint:recommended', '@electron-internal', '@electron-toolkit'],
rules: {
'space-before-function-paren': 'off',
vendorPrefix: 'off'
}
};

5
.prettierrc.yaml Normal file
View file

@ -0,0 +1,5 @@
singleQuote: true
semi: true
printWidth: 140
trailingComma: none
arrowParens: avoid

View file

@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"axios": "^1.4.0", "axios": "^1.4.0",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"emoji-picker-element": "^1.21.0",
"express": "^4.18.2", "express": "^4.18.2",
"ini": "^2.0.0", "ini": "^2.0.0",
"kill-process-by-name": "^1.0.5", "kill-process-by-name": "^1.0.5",
@ -38,6 +39,12 @@
"@electron-forge/maker-squirrel": "^6.2.1", "@electron-forge/maker-squirrel": "^6.2.1",
"@electron-forge/maker-zip": "^6.2.1", "@electron-forge/maker-zip": "^6.2.1",
"@electron-forge/plugin-auto-unpack-natives": "^6.2.1", "@electron-forge/plugin-auto-unpack-natives": "^6.2.1",
"electron": "^25.9.8" "@electron-internal/eslint-config": "^1.0.1",
"@electron-toolkit/eslint-config": "^1.0.2",
"electron": "^25.9.8",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.2",
"prettier": "^3.1.1"
} }
} }

View file

@ -1,7 +1,15 @@
# from wsgiref.simple_server import WSGIServer
from flask import Flask, Response, jsonify, request from flask import Flask, Response, jsonify, request
import gevent import gevent
import re
import gevent.monkey import gevent.monkey
import json import json
from waitress import serve
import logging
logger = logging.getLogger("waitress")
logger.setLevel(logging.INFO)
gevent.monkey.patch_all() gevent.monkey.patch_all()
import gevent.queue import gevent.queue
@ -40,6 +48,7 @@ q = queue.Queue()
# gobal functions # gobal functions
# classes # classes
class LanguageDetection: class LanguageDetection:
def __init__(self): def __init__(self):
@ -55,10 +64,8 @@ class LanguageDetection:
language_detection_model = os.path.join( language_detection_model = os.path.join(
resources_folder, "language_detection_model", f"lid.176.bin" resources_folder, "language_detection_model", f"lid.176.bin"
) )
language_detection_model = ( language_detection_model = rf"{language_detection_model}"
rf"{language_detection_model}"
)
self.model = fasttext.load_model(language_detection_model) self.model = fasttext.load_model(language_detection_model)
def predict_lang(self, text): def predict_lang(self, text):
@ -69,6 +76,7 @@ class LanguageDetection:
return language_codes return language_codes
class STT: class STT:
samplerate = None samplerate = None
args = "" args = ""
@ -92,9 +100,7 @@ class STT:
resources_folder, "speech_to_text_models", settings["STT"]["LANGUAGE"] resources_folder, "speech_to_text_models", settings["STT"]["LANGUAGE"]
) )
self.model = Model( self.model = Model(rf"{vosk_model}")
rf"{vosk_model}"
)
self.dump_fn = None self.dump_fn = None
self.q = gevent.queue.Queue() self.q = gevent.queue.Queue()
@ -180,6 +186,7 @@ text_to_speech_service = TTS()
# endpoints # endpoints
@app.route("/stream", methods=["GET"]) @app.route("/stream", methods=["GET"])
def stream_recognition(): def stream_recognition():
def generate(): def generate():
@ -239,9 +246,14 @@ def trigger_backend_event():
try: try:
request_data = request.json request_data = request.json
message = request_data.get("message", "") message = request_data.get("message", "")
filteredMessage = re.sub(
r"https?://(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)",
"a link",
message,
)
voice = request_data.get("voice") voice = request_data.get("voice")
count = request_data.get("count") count = request_data.get("count")
text_to_speech_service.say(message, voice, count) text_to_speech_service.say(filteredMessage, voice, count)
except Exception as e: except Exception as e:
return jsonify({"error": "An error occurred"}), 500 return jsonify({"error": "An error occurred"}), 500
return jsonify({"message": "Audio triggered"}), 200 return jsonify({"message": "Audio triggered"}), 200
@ -257,14 +269,14 @@ def get_voices():
if __name__ == "__main__": if __name__ == "__main__":
LANGUAGE = LanguageDetection() # LANGUAGE = LanguageDetection()
lang = LANGUAGE.predict_lang("hola cómo estás") # lang = LANGUAGE.predict_lang("hola cómo estás")
print(lang) # print(lang)
text = "Keep it up. You are awesome" # text = "Keep it up. You are awesome"
translated = MyMemoryTranslator( # translated = MyMemoryTranslator(
source="english", target="spanish latin america" # source="english", target="spanish latin america"
).translate(text) # ).translate(text)
print(translated) # print(translated)
if len(sys.argv) > 1: if len(sys.argv) > 1:
settings.read(settingsPath) settings.read(settingsPath)
port = int(settings["GENERAL"]["PORT"]) port = int(settings["GENERAL"]["PORT"])
@ -273,5 +285,4 @@ if __name__ == "__main__":
port = 9000 port = 9000
stream_recognition() stream_recognition()
app.run(host="127.0.0.1", port=port) serve(app, host="0.0.0.0", port=port)
app.terminate()

View file

@ -1,462 +1,469 @@
@font-face { @font-face {
font-family: 'FRAMDCN'; font-family: 'FRAMDCN';
src: url(../fonts/FRAMCDN/FRAMDCN.woff);
} }
h1 { h1 {
font-family: 'FRAMDCN'; font-family: 'FRAMDCN';
} }
.message-window { .message-window {
height: calc(100% - 60px); height: calc(100% - 60px);
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
background-color: var(--mid-section); background-color: var(--mid-section);
padding-left: 50px; padding-left: 50px;
padding-right: 50px; padding-right: 50px;
font-family: 'FRAMDCN'; font-family: 'FRAMDCN';
position: relative; position: relative;
z-index: 1; z-index: 1;
} }
.input-box { .input-box {
display: flex; display: flex;
border: none; border: none;
width: 100%; width: 100%;
height: 30px; height: 30px;
font-size: 16px; font-size: 16px;
} }
.userText { .userText {
color: var(--chat-bubble-message); color: var(--chat-bubble-message);
font-family: Helvetica; font-family: Helvetica;
font-size: 16px; font-size: 16px;
text-align: right; text-align: right;
clear: both; clear: both;
} }
.userText span { .userText span {
line-height: 1.5em; line-height: 1.5em;
display: inline-block; display: inline-block;
background: #5ca6fa; background: #5ca6fa;
padding: 10px; padding: 10px;
border-radius: 8px; border-radius: 8px;
border-bottom-right-radius: 2px; border-bottom-right-radius: 2px;
max-width: 80%; max-width: 80%;
margin-right: 10px; margin-right: 10px;
animation: floatup 0.5s forwards; animation: floatup 0.5s forwards;
} }
.botText { .botText {
color: #000; color: #000;
font-family: Helvetica; font-family: Helvetica;
font-weight: normal; font-weight: normal;
font-size: 16px; font-size: 16px;
text-align: left; text-align: left;
} }
.botText span { .botText span {
line-height: 1.5em; line-height: 1.5em;
display: inline-block; display: inline-block;
background: #e0e0e0; background: #e0e0e0;
padding: 10px; padding: 10px;
border-radius: 8px; border-radius: 8px;
border-bottom-left-radius: 2px; border-bottom-left-radius: 2px;
max-width: 80%; max-width: 80%;
margin-left: 10px; margin-left: 10px;
animation: floatup 0.5s forwards; animation: floatup 0.5s forwards;
} }
@keyframes floatup { @keyframes floatup {
from { from {
transform: translateY(14px); transform: translateY(14px);
opacity: 0; opacity: 0;
} }
to { to {
transform: translateY(0px); transform: translateY(0px);
opacity: 1; opacity: 1;
} }
} }
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
.full-chat-block { .full-chat-block {
width: 100%; width: 100%;
border-radius: 0px; border-radius: 0px;
} }
.chat-bar-collapsible { .chat-bar-collapsible {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
right: 0; right: 0;
width: 100%; width: 100%;
} }
.collapsible { .collapsible {
width: 100%; width: 100%;
border: 0px; border: 0px;
border-radius: 0px; border-radius: 0px;
} }
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 4px; width: 4px;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: #4c4c6a; background-color: #4c4c6a;
border-radius: 2px; border-radius: 2px;
} }
.chatBox { .chatBox {
width: 300px; width: 300px;
height: 400px; height: 400px;
max-height: 400px; max-height: 400px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
box-shadow: 0 0 4px var(--main-color4); box-shadow: 0 0 4px var(--main-color4);
} }
.chat-window { .chat-window {
flex: auto; flex: auto;
max-height: calc(100% - 60px); max-height: calc(100% - 60px);
background: #2f323b; background: #2f323b;
overflow: auto; overflow: auto;
} }
.chat-input { .chat-input {
height: 30px; height: 30px;
display: flex; display: flex;
flex: 0 0 auto; flex: 0 0 auto;
height: 60px; height: 60px;
background: var(--main-color3); background: var(--main-color3);
} }
.chat-input input { .chat-input input {
height: 59px; height: 59px;
line-height: 60px; line-height: 60px;
outline: 0 none; outline: 0 none;
border: none; border: none;
width: calc(100% - 60px); width: calc(100% - 60px);
color: var(--chat-bubble-message); color: var(--chat-bubble-message);
text-indent: 10px; text-indent: 10px;
font-size: 12pt; font-size: 12pt;
padding: 0; padding: 0;
background: var(--main-color3); background: var(--main-color3);
} }
.chat-input button { .chat-input button {
float: right; float: right;
outline: 0 none; outline: 0 none;
border: none; border: none;
background: var(--main-color3); background: var(--main-color3);
height: 40px; height: 40px;
width: 40px; width: 40px;
border-radius: 50%; border-radius: 50%;
padding: 2px 0 0 0; padding: 2px 0 0 0;
margin: 10px; margin: 10px;
} }
.chat-input input[good] + button { .chat-input input[good] + button {
box-shadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); box-shadow:
0 0 2px rgba(0, 0, 0, 0.12),
0 2px 4px rgba(0, 0, 0, 0.24);
} }
.chat-input input[good] + button:hover { .chat-input input[good] + button:hover {
box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); box-shadow:
/* filter: brightness(150%); */ 0 8px 17px 0 rgba(0, 0, 0, 0.2),
0 6px 20px 0 rgba(0, 0, 0, 0.19);
/* filter: brightness(150%); */
} }
.chat-input input[good] + button path { .chat-input input[good] + button path {
fill: var(--chat-bubble-message); fill: var(--chat-bubble-message);
} }
.msg-container { .msg-container {
direction: ltr; direction: ltr;
position: static; position: static;
width: 100%; width: 100%;
padding: 10px 0px 0px 0px; padding: 10px 0px 0px 0px;
display: grid; display: grid;
grid-template: 1fr / 1fr; grid-template: 1fr / 1fr;
align-self: start; align-self: start;
} }
.msg-container > * { .msg-container > * {
grid-column: 1 / 1; grid-column: 1 / 1;
grid-row: 1 / 1; grid-row: 1 / 1;
} }
.msg-container.sender { .msg-container.sender {
place-items: self-start; place-items: self-start;
} }
.msg-container.user { .msg-container.user {
place-items: self-end; place-items: self-end;
} }
.msg-box { .msg-box {
background: var(--chat-bubble); background: var(--chat-bubble);
color: white; color: white;
min-width: 100px; min-width: 100px;
border-radius: 5px; border-radius: 5px;
padding: 18px 5px 5px 5px; padding: 18px 5px 5px 5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); box-shadow:
width: fit-content; 0 0 2px rgba(0, 0, 0, 0.12),
position: relative; 0 2px 4px rgba(0, 0, 0, 0.24);
align-self: start; width: fit-content;
position: relative;
align-self: start;
} }
.msg-box.sender { .msg-box.sender {
margin: 25px 25px 0px 35px; margin: 25px 25px 0px 35px;
} }
.msg-box.user { .msg-box.user {
text-align: left; text-align: left;
margin: 25px 35px 0px 0px; margin: 25px 35px 0px 0px;
} }
.msg-box-user-temp { .msg-box-user-temp {
background: var(--chat-bubble-temp); background: var(--chat-bubble-temp);
} }
.user-img { .user-img {
display: inline-block; display: inline-block;
position: relative; position: relative;
border-radius: 50%; border-radius: 50%;
height: 50px; height: 50px;
width: 50px; width: 50px;
z-index: 5; z-index: 5;
align-self: start; align-self: start;
} }
.messages.user { .messages.user {
margin-right: 20px; margin-right: 20px;
} }
.msg { .msg {
font-size: 12pt; font-size: 12pt;
color: var(--chat-bubble-message); color: var(--chat-bubble-message);
margin: 0 0 0 0; margin: 0 0 0 0;
} }
.msg-temp { .msg-temp {
color: var(--chat-bubble-message-temp); color: var(--chat-bubble-message-temp);
} }
.timestamp { .timestamp {
color: var(--chat-bubble-header); color: var(--chat-bubble-header);
font-size: 10pt; font-size: 10pt;
align-items: center; align-items: center;
font-family: 'xxii_avenmedium'; font-family: 'xxii_avenmedium';
} }
.timestamp-temp { .timestamp-temp {
color: var(--chat-bubble-header-temp); color: var(--chat-bubble-header-temp);
} }
.username { .username {
background-color: var(--main-color4); background-color: var(--main-color4);
color: white; color: white;
position: relative; position: relative;
border-radius: 5px; border-radius: 5px;
z-index: 3; z-index: 3;
align-self: start; align-self: start;
} }
.username.sender { .username.sender {
padding: 0px 5px 5px 30px; padding: 0px 5px 5px 30px;
margin: 20px 5px 5px 30px; margin: 20px 5px 5px 30px;
} }
.username.user { .username.user {
padding: 0px 30px 5px 5px; padding: 0px 30px 5px 5px;
margin: 20px 30px 5px 5px; margin: 20px 30px 5px 5px;
} }
.username-temp { .username-temp {
color: var(--chat-bubble-header-temp); color: var(--chat-bubble-header-temp);
} }
.post-time { .post-time {
font-size: 8pt; font-size: 8pt;
color: white; color: white;
display: inline-block; display: inline-block;
background-color: var(--main-color4); background-color: var(--main-color4);
position: relative; position: relative;
z-index: 2; z-index: 2;
border-radius: 5px; border-radius: 5px;
align-self: start; align-self: start;
} }
.post-time.sender { .post-time.sender {
padding: 5px 5px 0px 15px; padding: 5px 5px 0px 15px;
margin: 0px 0px 0px 50px; margin: 0px 0px 0px 50px;
} }
.post-time.user { .post-time.user {
padding: 5px 15px 0px 5px; padding: 5px 15px 0px 5px;
margin: 0px 50px 0px 0px; margin: 0px 50px 0px 0px;
} }
.mmg { .mmg {
display: flex; display: flex;
} }
.img { .img {
height: 100%; height: 100%;
width: 100%; width: 100%;
border-radius: 50%; border-radius: 50%;
} }
.status-circle { .status-circle {
width: 20px; width: 20px;
border-radius: 50%; border-radius: 50%;
z-index: 6; z-index: 6;
position: relative; position: relative;
align-self: start; align-self: start;
} }
.status-circle.sender { .status-circle.sender {
margin-left: 40px; margin-left: 40px;
} }
.status-circle.user { .status-circle.user {
margin-right: 40px; margin-right: 40px;
} }
.menu-select { .menu-select {
font-size: 0.9rem; font-size: 0.9rem;
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background-color: var(--main-color3); background-color: var(--main-color3);
color: var(--main-color2); color: var(--main-color2);
align-items: center; align-items: center;
border: 0px; border: 0px;
padding-left: 10px; padding-left: 10px;
width: 300px; width: 300px;
font-size: 100%; font-size: 100%;
padding: 10px; padding: 10px;
padding-right: 25px; padding-right: 25px;
outline: none; outline: none;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg fill='white' height='34' viewBox='0 0 24 24' width='32' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>"); background-image: url("data:image/svg+xml;utf8,<svg fill='white' height='34' viewBox='0 0 24 24' width='32' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position-x: 100%; background-position-x: 100%;
background-position-y: 5px; background-position-y: 5px;
} }
.top-select { .top-select {
width: auto; width: auto;
height: 24px; height: 24px;
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
background-color: transparent; background-color: transparent;
color: white; color: white;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
border: none; border: none;
} }
.info-image { .info-image {
width: 50px; width: 50px;
height: 50px; height: 50px;
} }
.top-select option { .top-select option {
margin: 40px; margin: 40px;
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.3);
color: #fff; color: #fff;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4); text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
background-color: var(--top-bar); background-color: var(--top-bar);
} }
.AdvancedMenu { .AdvancedMenu {
border: 1px var(--main-color2) solid; border: 1px var(--main-color2) solid;
margin-top: 10px; margin-top: 10px;
min-width: 555px; min-width: 555px;
border-radius: 5px; border-radius: 5px;
border-radius: 5px; border-radius: 5px;
} }
.legendStyle { .legendStyle {
margin-left: 1em; margin-left: 1em;
padding: 0.2em 0.8em; padding: 0.2em 0.8em;
display: flex; display: flex;
align-items: center; align-items: center;
} }
.AdvancedMenuRow { .AdvancedMenuRow {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
justify-content: left; justify-content: left;
margin-bottom: 10px; margin-bottom: 10px;
} }
.AdvancedMenuLabel { .AdvancedMenuLabel {
font-size: 10pt; font-size: 10pt;
padding-right: 5px; padding-right: 5px;
margin-left: 10px; margin-left: 10px;
width: 125px; width: 125px;
} }
.AdvancedMenuLabel2 { .AdvancedMenuLabel2 {
font-size: 10pt; font-size: 10pt;
padding-right: 5px; padding-right: 5px;
margin-left: 10px; margin-left: 10px;
} }
.AdvancedMenuLabel3 { .AdvancedMenuLabel3 {
font-size: 12pt; font-size: 12pt;
padding-right: 5px; padding-right: 5px;
margin-left: 10px; margin-left: 10px;
} }
#SaveAdvancedSettingsButton { #SaveAdvancedSettingsButton {
margin-left: 10px; margin-left: 10px;
} }
.toggle { .toggle {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 60px; width: 60px;
height: 40px; height: 40px;
background-color: var(--main-color3); background-color: var(--main-color3);
border-radius: 20px; border-radius: 20px;
} }
/* After slide changes */ /* After slide changes */
.toggle:after { .toggle:after {
content: ''; content: '';
position: absolute; position: absolute;
width: 30px; width: 30px;
height: 30px; height: 30px;
border-radius: 50%; border-radius: 50%;
background-color: var(--main-color2); background-color: var(--main-color2);
left: 5px; left: 5px;
top: 5px; top: 5px;
} }
/* Checkbox checked effect */ /* Checkbox checked effect */
.checkbox:checked + .toggle::after { .checkbox:checked + .toggle::after {
left: 25px; left: 25px;
} }
/* Checkbox checked toggle label bg color */ /* Checkbox checked toggle label bg color */
.checkbox:checked + .toggle { .checkbox:checked + .toggle {
background-color: var(--main-color1); background-color: var(--main-color1);
} }
/* Checkbox vanished */ /* Checkbox vanished */
.checkbox { .checkbox {
display: none; display: none;
} }
/* Small toggle */ /* Small toggle */
@ -464,36 +471,45 @@ h1 {
/* toggle in label designing */ /* toggle in label designing */
.toggle-small { .toggle-small {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 30px; width: 30px;
height: 20px; height: 20px;
background-color: var(--main-color3); background-color: var(--main-color3);
border-radius: 10px; border-radius: 10px;
margin-left: 10px; margin-left: 10px;
} }
/* After slide changes */ /* After slide changes */
.toggle-small:after { .toggle-small:after {
content: ''; content: '';
position: absolute; position: absolute;
width: 15px; width: 15px;
height: 15px; height: 15px;
border-radius: 50%; border-radius: 50%;
background-color: white; background-color: white;
left: 2px; left: 2px;
top: 2px; top: 2px;
} }
/* Checkbox checked effect */ /* Checkbox checked effect */
.checkbox:checked + .toggle-small::after { .checkbox:checked + .toggle-small::after {
left: 13px; left: 13px;
} }
/* Checkbox checked toggle label bg color */ /* Checkbox checked toggle label bg color */
.checkbox:checked + .toggle-small { .checkbox:checked + .toggle-small {
background-color: var(--main-color1); background-color: var(--main-color1);
}
.emoji-picker {
margin-left: auto;
visibility: hidden;
bottom: 50px;
left: 0px;
position: absolute;
z-index: 1;
} }

View file

@ -1,62 +1,62 @@
input[type="radio"]:checked { input[type='radio']:checked {
visibility: hidden; visibility: hidden;
position: absolute; position: absolute;
} }
input[type="radio"] { input[type='radio'] {
visibility: hidden; visibility: hidden;
position: absolute; position: absolute;
} }
label.btn span { label.btn span {
font-size: 1.5em; font-size: 1.5em;
} }
label input[type="radio"]~i.fa.fa-square { label input[type='radio'] ~ i.fa.fa-square {
color: var(--main-color3); color: var(--main-color3);
display: inline; display: inline;
} }
label input[type="radio"]~i.fa.fa-check-square { label input[type='radio'] ~ i.fa.fa-check-square {
display: none; display: none;
} }
label input[type="radio"]:checked~i.fa.fa-square { label input[type='radio']:checked ~ i.fa.fa-square {
display: none; display: none;
} }
label input[type="radio"]:checked~i.fa.fa-check-square { label input[type='radio']:checked ~ i.fa.fa-check-square {
display: inline; display: inline;
color: var(--main-color2); color: var(--main-color2);
} }
label:hover input[type="radio"]~i.fa { label:hover input[type='radio'] ~ i.fa {
color: var(--main-color1); color: var(--main-color1);
/* filter: brightness(150%); */ /* filter: brightness(150%); */
} }
div[data-toggle="buttons"] label { div[data-toggle='buttons'] label {
display: inline-block; display: inline-block;
padding: 3px 12px; padding: 3px 12px;
margin-bottom: 0; margin-bottom: 0;
font-size: 20px; font-size: 20px;
font-weight: normal; font-weight: normal;
line-height: 2em; line-height: 2em;
text-align: left; text-align: left;
white-space: nowrap; white-space: nowrap;
vertical-align: top; vertical-align: top;
cursor: pointer; cursor: pointer;
background-color: none; background-color: none;
border-radius: 3px; border-radius: 3px;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
-o-user-select: none; -o-user-select: none;
user-select: none; user-select: none;
} }
div[data-toggle="buttons"] label:active, div[data-toggle='buttons'] label:active,
div[data-toggle="buttons"] label.active { div[data-toggle='buttons'] label.active {
-webkit-box-shadow: none; -webkit-box-shadow: none;
box-shadow: none; box-shadow: none;
} }

View file

@ -1,253 +1,273 @@
/* Basic styling */ /* Basic styling */
:root { :root {
overflow: hidden; overflow: hidden;
--main-color1: #6e2c8c; --main-color1: #6e2c8c;
--main-color1-temp: #6e2c8c; --main-color1-temp: #6e2c8c;
/*Left bar and top right bar*/ /*Left bar and top right bar*/
--main-color2: white; --main-color2: white;
--main-color2-temp: white; --main-color2-temp: white;
/*Icons and text*/ /*Icons and text*/
--main-color3: #211e1e; --main-color3: #211e1e;
--main-color3-temp: #211e1e; --main-color3-temp: #211e1e;
/*Buttons and input*/ /*Buttons and input*/
--main-color4: #2f2c34; --main-color4: #2f2c34;
--main-color4-temp: #2f2c34; --main-color4-temp: #2f2c34;
--top-bar: #100b12; --top-bar: #100b12;
--top-bar-temp: #100b12; --top-bar-temp: #100b12;
--mid-section: #352d3d; --mid-section: #352d3d;
--mid-section-temp: #352d3d; --mid-section-temp: #352d3d;
--chat-bubble: #7a6d7f; --chat-bubble: #7a6d7f;
--chat-bubble-header: #141414; --chat-bubble-header: #141414;
--chat-bubble-username: white; --chat-bubble-username: white;
--chat-bubble-message: white; --chat-bubble-message: white;
--chat-bubble-temp: #7a6d7f; --chat-bubble-temp: #7a6d7f;
--chat-bubble-header-temp: #141414; --chat-bubble-header-temp: #141414;
--chat-bubble-message-temp: white; --chat-bubble-message-temp: white;
} }
html { html {
box-sizing: border-box; box-sizing: border-box;
} }
*, *,
*:before, *:before,
*:after { *:after {
box-sizing: inherit; box-sizing: inherit;
} }
html, html,
body { body {
height: 100%; height: 100%;
margin: 0; margin: 0;
/* border-top-left-radius: 20px; */ /* border-top-left-radius: 20px; */
/* border-top-right-radius: 20px; */ /* border-top-right-radius: 20px; */
overflow-x: hidden; overflow-x: hidden;
} }
body { body {
font-family: 'Segoe UI', sans-serif; font-family: 'Segoe UI', sans-serif;
background: transparent; background: transparent;
} }
/* Styling of window frame and titlebar */ /* Styling of window frame and titlebar */
body { body {
/* border: 1px solid #48545c; */ /* border: 1px solid #48545c; */
overflow-y: hidden; overflow-y: hidden;
} }
#titlebar { #titlebar {
display: block; display: block;
/* position: fixed; */ /* position: fixed; */
height: 32px; height: 32px;
width: calc(100%); width: calc(100%);
background-color: var(--top-bar); background-color: var(--top-bar);
/* border-top-left-radius: 20px; /* border-top-left-radius: 20px;
border-top-right-radius: 20px; */ border-top-right-radius: 20px; */
} }
.maximized #titlebar { .maximized #titlebar {
width: 100%; width: 100%;
padding: 0; padding: 0;
} }
#main { #main {
height: calc(100% - 32px); height: calc(100% - 32px);
margin-top: 32px; margin-top: 32px;
padding: 20px; padding: 20px;
overflow-y: auto; overflow-y: auto;
display: flex; display: flex;
} }
#titlebar { #titlebar {
padding: 4px; padding: 4px;
} }
#titlebar #drag-region { #titlebar #drag-region {
width: 100%; width: 100%;
height: 100%; height: 100%;
-webkit-app-region: drag; -webkit-app-region: drag;
display: inline-flex; display: inline-flex;
} }
#titlebar { #titlebar {
color: var(--main-color2); color: var(--main-color2);
} }
#window-title { #window-title {
grid-column: 1; grid-column: 1;
display: flex; display: flex;
align-items: center; align-items: center;
margin-left: 8px; margin-left: 8px;
overflow: hidden; overflow: hidden;
font-family: 'Segoe UI', sans-serif; font-family: 'Segoe UI', sans-serif;
font-size: 12px; font-size: 12px;
} }
.maximized #window-title { .maximized #window-title {
margin-left: 12px; margin-left: 12px;
} }
#window-title span { #window-title span {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
line-height: 1.5; line-height: 1.5;
} }
#window-controls { #window-controls {
display: grid; display: grid;
grid-template-columns: repeat(3, 46px); grid-template-columns: repeat(3, 46px);
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
height: 32px; height: 32px;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }
#window-controls .button { #window-controls .button {
grid-row: 1 / span 1; grid-row: 1 / span 1;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 100%; width: 100%;
height: 32px; height: 32px;
} }
@media (-webkit-device-pixel-ratio: 1.5), @media (-webkit-device-pixel-ratio: 1.5),
(device-pixel-ratio: 1.5), (device-pixel-ratio: 1.5),
(-webkit-device-pixel-ratio: 2), (-webkit-device-pixel-ratio: 2),
(device-pixel-ratio: 2), (device-pixel-ratio: 2),
(-webkit-device-pixel-ratio: 3), (-webkit-device-pixel-ratio: 3),
(device-pixel-ratio: 3) { (device-pixel-ratio: 3) {
#window-controls .icon { #window-controls .icon {
width: 10px; width: 10px;
height: 10px; height: 10px;
} }
} }
#window-controls .button { #window-controls .button {
user-select: none; user-select: none;
} }
#window-controls .button:hover { #window-controls .button:hover {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
/* filter: brightness(150%); */ /* filter: brightness(150%); */
} }
#window-controls .button:active { #window-controls .button:active {
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
} }
#close-button:hover { #close-button:hover {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
/* border-top-right-radius: 20px; */ /* border-top-right-radius: 20px; */
background: #f1707a !important; background: #f1707a !important;
} }
#close-button:active { #close-button:active {
background: #f1707a !important; background: #f1707a !important;
} }
#close-button:active .icon { #close-button:active .icon {
filter: invert(1); filter: invert(1);
background: #f1707a !important; background: #f1707a !important;
} }
#min-button { #min-button {
grid-column: 1; grid-column: 1;
} }
#max-button, #max-button,
#restore-button { #restore-button {
grid-column: 2; grid-column: 2;
} }
#close-button { #close-button {
grid-column: 3; grid-column: 3;
} }
#restore-button { #restore-button {
display: none !important; display: none !important;
} }
.maximized #restore-button { .maximized #restore-button {
display: flex !important; display: flex !important;
} }
.maximized #max-button { .maximized #max-button {
display: none; display: none;
} }
.active-mic { .active-mic {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
} }
.about { .about {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
position: absolute; position: absolute;
left: 0; left: 0;
width: 32px; width: 32px;
text-align: -webkit-center; text-align: -webkit-center;
} }
.language-selector { .language-selector {
position: absolute; position: absolute;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
display: inline-block; display: inline-block;
background-color: transparent; background-color: transparent;
cursor: pointer; cursor: pointer;
font-family: 'NotoColorEmojiLimited', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, font-family:
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; 'NotoColorEmojiLimited',
left: 50%; -apple-system,
transform: translateX(-50%); BlinkMacSystemFont,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol';
left: 50%;
transform: translateX(-50%);
} }
.language-dropdown { .language-dropdown {
display: none; display: none;
position: absolute; position: absolute;
background-color: #fff; background-color: #fff;
width: 55px; width: 55px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 2; z-index: 2;
font-family: 'NotoColorEmojiLimited', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, font-family:
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; 'NotoColorEmojiLimited',
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Helvetica,
Arial,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol';
} }
.language-item { .language-item {
padding: 5px; padding: 5px;
cursor: pointer; cursor: pointer;
background-color: var(--top-bar); background-color: var(--top-bar);
} }
.language-item:hover { /* .language-item:hover {
/* filter: brightness(150%); */ filter: brightness(150%);
} } */
@font-face { @font-face {
font-family: NotoColorEmojiLimited; font-family: NotoColorEmojiLimited;
unicode-range: U+1F1E6-1F1FF; unicode-range: U+1F1E6-1F1FF;
src: url(https://raw.githack.com/googlefonts/noto-emoji/main/fonts/NotoColorEmoji.ttf); src: url(https://raw.githack.com/googlefonts/noto-emoji/main/fonts/NotoColorEmoji.ttf);
} }

View file

@ -1,34 +1,34 @@
table { table {
margin-left: 10px; margin-left: 10px;
background-color: white; background-color: white;
border-collapse: collapse; border-collapse: collapse;
width: 100%; width: 100%;
margin-top: 60px; margin-top: 60px;
} }
th, th,
td { td {
border: 1px solid black; border: 1px solid black;
padding: 8px; padding: 8px;
text-align: left; text-align: left;
} }
.info { .info {
background-color: lightblue !important; background-color: lightblue !important;
} }
.warn { .warn {
background-color: #f39c12 !important; background-color: #f39c12 !important;
} }
.error { .error {
background-color: #e74c3c !important; background-color: #e74c3c !important;
} }
#logTable { #logTable {
width: 95%; width: 95%;
} }
#Logs { #Logs {
overflow: auto; overflow: auto;
} }

View file

@ -1,226 +1,230 @@
.container { .container {
display: flex; display: flex;
height: calc(100vh - 32px); height: calc(100vh - 32px);
width: 100%; width: 100%;
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
display: flex; display: flex;
/* will contain if #first is longer than #second */ /* will contain if #first is longer than #second */
} }
.mid { .mid {
flex: 3; flex: 3;
display: block; display: block;
position: relative; position: relative;
} }
.OptionPanel { .OptionPanel {
/* visibility: hidden; */ /* visibility: hidden; */
background-color: var(--mid-section); background-color: var(--mid-section);
flex: 3; flex: 3;
display: none; display: none;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.OptionPanel.show { .OptionPanel.show {
display: block; display: block;
overflow: auto; overflow: auto;
} }
.menu { .menu {
height: 100%; height: 100%;
display: block; display: block;
width: 100%; width: 100%;
background: var(--main-color1); background: var(--main-color1);
z-index: 1; z-index: 1;
position: relative; position: relative;
} }
.menu .items { .menu .items {
list-style: none; list-style: none;
margin: auto; margin: auto;
padding: 0; padding: 0;
} }
#rpe { #rpe {
font-size: 8pt; font-size: 8pt;
margin: 2px 0px 0px 0px; margin: 2px 0px 0px 0px;
} }
.menu .items .item { .menu .items .item {
width: 100%; width: 100%;
height: 50px; height: 50px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: var(--main-color1); background: var(--main-color1);
color: var(--main-color2); color: var(--main-color2);
} }
.hdp:hover { .hdp:hover {
position: fixed; position: fixed;
/* filter: brightness(150%); */ /* filter: brightness(150%); */
} }
.menu .items .item-active { .menu .items .item-active {
background: -webkit-linear-gradient(left, var(--main-color2) 10%, var(--main-color2), var(--main-color1) 10%, var(--main-color1) 10%); background: -webkit-linear-gradient(left, var(--main-color2) 10%, var(--main-color2), var(--main-color1) 10%, var(--main-color1) 10%);
color: var(--main-color2); color: var(--main-color2);
filter: brightness(90%); filter: brightness(90%);
} }
.menu .items .item:hover { .menu .items .item:hover {
cursor: pointer; cursor: pointer;
color: var(--main-color2); color: var(--main-color2);
filter: brightness(120%); filter: brightness(120%);
} }
.sidepanel-left { .sidepanel-left {
position: relative; position: relative;
width: 50px; width: 50px;
font-size: 1.5em; font-size: 1.5em;
line-height: 1.5em; line-height: 1.5em;
font-family: Helvetica; font-family: Helvetica;
text-align: center; text-align: center;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px; box-shadow:
transition: 0.3s ease-in-out; rgba(0, 0, 0, 0.16) 0px 3px 6px,
rgba(0, 0, 0, 0.23) 0px 3px 6px;
transition: 0.3s ease-in-out;
} }
.sidepanel-right { .sidepanel-right {
position: relative; position: relative;
width: 200px; width: 200px;
font-size: 1.5em; font-size: 1.5em;
line-height: 1.5em; line-height: 1.5em;
font-family: Helvetica; font-family: Helvetica;
text-align: center; text-align: center;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px; box-shadow:
transition: 0.3s ease-in-out; rgba(0, 0, 0, 0.16) 0px 3px 6px,
rgba(0, 0, 0, 0.23) 0px 3px 6px;
transition: 0.3s ease-in-out;
} }
.collapse-menu-left { .collapse-menu-left {
margin-left: -50px; margin-left: -50px;
} }
.collapse-menu-right { .collapse-menu-right {
margin-right: -200px; margin-right: -200px;
} }
.sidepanel-left span { .sidepanel-left span {
position: relative; position: relative;
display: block; display: block;
} }
.sidepanel-right span { .sidepanel-right span {
position: relative; position: relative;
display: block; display: block;
} }
.circle-left { .circle-left {
position: absolute; position: absolute;
width: 50px; width: 50px;
height: 50px; height: 50px;
-webkit-clip-path: polygon(100% 0, 0 0, 0 100%); -webkit-clip-path: polygon(100% 0, 0 0, 0 100%);
clip-path: ellipse(68% 50% at 6% 50%); clip-path: ellipse(68% 50% at 6% 50%);
font-size: 20px; font-size: 20px;
background-color: var(--main-color3); background-color: var(--main-color3);
color: var(--main-color2); color: var(--main-color2);
justify-content: left; justify-content: left;
top: 32px; top: 32px;
left: 50px; left: 50px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
z-index: 2; z-index: 2;
transition: 0.3s ease-in-out; transition: 0.3s ease-in-out;
} }
.collapse-circle-left { .collapse-circle-left {
left: 0px; left: 0px;
} }
.circle-right { .circle-right {
position: absolute; position: absolute;
width: 50px; width: 50px;
height: 50px; height: 50px;
-webkit-clip-path: polygon(100% 100%, 0 0, 100% 0); -webkit-clip-path: polygon(100% 100%, 0 0, 100% 0);
clip-path: ellipse(68% 50% at 94% 50%); clip-path: ellipse(68% 50% at 94% 50%);
font-size: 20px; font-size: 20px;
background-color: var(--main-color3); background-color: var(--main-color3);
color: var(--main-color2); color: var(--main-color2);
justify-content: right; justify-content: right;
top: 32px; top: 32px;
right: 199px; right: 199px;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
z-index: 1; z-index: 1;
transition: 0.3s ease-in-out; transition: 0.3s ease-in-out;
} }
.collapse-circle-right { .collapse-circle-right {
right: 0px; right: 0px;
} }
.fa-cog { .fa-cog {
align-items: center; align-items: center;
align-self: center; align-self: center;
margin-left: 7px; margin-left: 7px;
} }
.fa-eye { .fa-eye {
align-self: center; align-self: center;
margin-right: 7px; margin-right: 7px;
} }
#min-button { #min-button {
grid-column: 1; grid-column: 1;
} }
#max-button, #max-button,
#restore-button { #restore-button {
grid-column: 2; grid-column: 2;
} }
#close-button { #close-button {
grid-column: 3; grid-column: 3;
} }
#mini-container { #mini-container {
width: 100%; width: 100%;
height: 300px; height: 300px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 25px; margin-bottom: 25px;
} }
#mini-main { #mini-main {
display: flex; display: flex;
height: 100%; height: 100%;
flex-direction: row; flex-direction: row;
} }
#mini-top-bar { #mini-top-bar {
height: 30px; height: 30px;
background-color: var(--top-bar-temp); background-color: var(--top-bar-temp);
/* border-top-left-radius: 20px; /* border-top-left-radius: 20px;
border-top-right-radius: 20px; */ border-top-right-radius: 20px; */
} }
#mini-left { #mini-left {
flex: 1; flex: 1;
background-color: var(--main-color1-temp); background-color: var(--main-color1-temp);
height: 100%; height: 100%;
} }
#mini-mid { #mini-mid {
flex: 8; flex: 8;
background-color: var(--mid-section-temp); background-color: var(--mid-section-temp);
height: 100%; height: 100%;
} }
#mini-right { #mini-right {
flex: 2; flex: 2;
background-color: var(--main-color4-temp); background-color: var(--main-color4-temp);
height: 100%; height: 100%;
} }

View file

@ -1,179 +1,195 @@
/*generated with Input range slider CSS style generator (version 20211225) /*generated with Input range slider CSS style generator (version 20211225)
https://toughengineer.github.io/demo/slider-styler*/ https://toughengineer.github.io/demo/slider-styler*/
input[type='range'].styled-slider { input[type='range'].styled-slider {
/* height: 500px; */ /* height: 500px; */
background: transparent; background: transparent;
-webkit-appearance: none; -webkit-appearance: none;
width: 300px; width: 300px;
} }
/*progress support*/ /*progress support*/
input[type='range'].styled-slider.slider-progress1 { input[type='range'].styled-slider.slider-progress1 {
--range: calc(var(--max) - var(--min)); --range: calc(var(--max) - var(--min));
--ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range)); --ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range));
--sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em)); --sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em));
} }
input[type='range'].styled-slider.slider-progress2 { input[type='range'].styled-slider.slider-progress2 {
--range: calc(var(--max) - var(--min)); --range: calc(var(--max) - var(--min));
--ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range)); --ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range));
--sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em)); --sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em));
} }
input[type='range'].styled-slider.slider-progress3 { input[type='range'].styled-slider.slider-progress3 {
--range: calc(var(--max) - var(--min)); --range: calc(var(--max) - var(--min));
--ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range)); --ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range));
--sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em)); --sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em));
} }
input[type='range'].styled-slider.slider-progress4 { input[type='range'].styled-slider.slider-progress4 {
--range: calc(var(--max) - var(--min)); --range: calc(var(--max) - var(--min));
--ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range)); --ratio: calc((var(--tiempotemporal) - var(--min)) / var(--range));
--sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em)); --sx: calc(0.5 * 2em + var(--ratio) * (100% - 2em));
} }
/*webkit*/ /*webkit*/
input[type='range'].styled-slider::-webkit-slider-thumb { input[type='range'].styled-slider::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
width: 2em; width: 2em;
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background: #ffffff; background: #ffffff;
border: none; border: none;
box-shadow: 0 0 2px black; box-shadow: 0 0 2px black;
margin-top: calc(2em * 0.5 - 2em * 0.5); margin-top: calc(2em * 0.5 - 2em * 0.5);
} }
input[type='range'].styled-slider::-webkit-slider-runnable-track { input[type='range'].styled-slider::-webkit-slider-runnable-track {
height: 40px; height: 40px;
border: none; border: none;
border-radius: 20px; border-radius: 20px;
background: #1a1a1a; background: #1a1a1a;
box-shadow: none; box-shadow: none;
} }
input[type='range'].styled-slider.slider-progress1::-webkit-slider-runnable-track { input[type='range'].styled-slider.slider-progress1::-webkit-slider-runnable-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #1a1a1a; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#1a1a1a;
} }
input[type='range'].styled-slider.slider-progress2::-webkit-slider-runnable-track { input[type='range'].styled-slider.slider-progress2::-webkit-slider-runnable-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #1a1a1a; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#1a1a1a;
} }
input[type='range'].styled-slider.slider-progress3::-webkit-slider-runnable-track { input[type='range'].styled-slider.slider-progress3::-webkit-slider-runnable-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #1a1a1a; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#1a1a1a;
} }
input[type='range'].styled-slider.slider-progress4::-webkit-slider-runnable-track { input[type='range'].styled-slider.slider-progress4::-webkit-slider-runnable-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #1a1a1a; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#1a1a1a;
} }
/*mozilla*/ /*mozilla*/
input[type='range'].styled-slider::-moz-range-thumb { input[type='range'].styled-slider::-moz-range-thumb {
width: 2em; width: 2em;
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background: #ffffff; background: #ffffff;
border: none; border: none;
box-shadow: 0 0 2px black; box-shadow: 0 0 2px black;
} }
input[type='range'].styled-slider::-moz-range-track { input[type='range'].styled-slider::-moz-range-track {
height: 40px; height: 40px;
border: none; border: none;
border-radius: 20px; border-radius: 20px;
background: var(--main-color3); background: var(--main-color3);
box-shadow: none; box-shadow: none;
} }
input[type='range'].styled-slider.slider-progress1::-moz-range-track { input[type='range'].styled-slider.slider-progress1::-moz-range-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #464646; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#464646;
} }
input[type='range'].styled-slider.slider-progress2::-moz-range-track { input[type='range'].styled-slider.slider-progress2::-moz-range-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #464646; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#464646;
} }
input[type='range'].styled-slider.slider-progress3::-moz-range-track { input[type='range'].styled-slider.slider-progress3::-moz-range-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #464646; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#464646;
} }
input[type='range'].styled-slider.slider-progress4::-moz-range-track { input[type='range'].styled-slider.slider-progress4::-moz-range-track {
background: linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat, #464646; background:
linear-gradient(var(--main-color1), var(--main-color1)) 0 / var(--sx) 100% no-repeat,
#464646;
} }
/*ms*/ /*ms*/
input[type='range'].styled-slider::-ms-fill-upper { input[type='range'].styled-slider::-ms-fill-upper {
background: transparent; background: transparent;
border-color: transparent; border-color: transparent;
} }
input[type='range'].styled-slider::-ms-fill-lower { input[type='range'].styled-slider::-ms-fill-lower {
background: transparent; background: transparent;
border-color: transparent; border-color: transparent;
} }
input[type='range'].styled-slider::-ms-thumb { input[type='range'].styled-slider::-ms-thumb {
width: 2em; width: 2em;
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background: #ffffff; background: #ffffff;
border: none; border: none;
box-shadow: 0 0 2px black; box-shadow: 0 0 2px black;
margin-top: 0; margin-top: 0;
box-sizing: border-box; box-sizing: border-box;
} }
input[type='range'].styled-slider::-ms-track { input[type='range'].styled-slider::-ms-track {
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background: var(--main-color3); background: var(--main-color3);
border: none; border: none;
box-shadow: none; box-shadow: none;
box-sizing: border-box; box-sizing: border-box;
} }
input[type='range'].styled-slider.slider-progress1::-ms-fill-lower { input[type='range'].styled-slider.slider-progress1::-ms-fill-lower {
height: 40px; height: 40px;
border-radius: 1em 0 0 1em; border-radius: 1em 0 0 1em;
margin: -undefined 0 -undefined -undefined; margin: -undefined 0 -undefined -undefined;
background: var(--main-color1); background: var(--main-color1);
border: none; border: none;
border-right-width: 0; border-right-width: 0;
} }
input[type='range'].styled-slider.slider-progress2::-ms-fill-lower { input[type='range'].styled-slider.slider-progress2::-ms-fill-lower {
height: 40px; height: 40px;
border-radius: 1em 0 0 1em; border-radius: 1em 0 0 1em;
margin: -undefined 0 -undefined -undefined; margin: -undefined 0 -undefined -undefined;
background: var(--main-color1); background: var(--main-color1);
border: none; border: none;
border-right-width: 0; border-right-width: 0;
} }
input[type='range'].styled-slider.slider-progress3::-ms-fill-lower { input[type='range'].styled-slider.slider-progress3::-ms-fill-lower {
height: 40px; height: 40px;
border-radius: 1em 0 0 1em; border-radius: 1em 0 0 1em;
margin: -undefined 0 -undefined -undefined; margin: -undefined 0 -undefined -undefined;
background: var(--main-color1); background: var(--main-color1);
border: none; border: none;
border-right-width: 0; border-right-width: 0;
} }
input[type='range'].styled-slider.slider-progress4::-ms-fill-lower { input[type='range'].styled-slider.slider-progress4::-ms-fill-lower {
height: 40px; height: 40px;
border-radius: 1em 0 0 1em; border-radius: 1em 0 0 1em;
margin: -undefined 0 -undefined -undefined; margin: -undefined 0 -undefined -undefined;
background: var(--main-color1); background: var(--main-color1);
border: none; border: none;
border-right-width: 0; border-right-width: 0;
} }
.inputBox { .inputBox {
border: none; border: none;
width: 38px; width: 38px;
border-radius: 10px; border-radius: 10px;
text-align: center; text-align: center;
font-size: 14pt; font-size: 14pt;
font-weight: bold; font-weight: bold;
} }

View file

@ -1,394 +1,398 @@
.viewer-list { .viewer-list {
background-color: var(--main-color4); background-color: var(--main-color4);
height: 100%; height: 100%;
flex: 1; flex: 1;
font-size: 14px; font-size: 14px;
height: 100%; height: 100%;
display: block; display: block;
} }
ul.no-bullets { ul.no-bullets {
list-style-type: none; list-style-type: none;
list-style-position: outside; list-style-position: outside;
margin: 0%; margin: 0%;
padding: 0%; padding: 0%;
padding-left: 5px; padding-left: 5px;
text-align: left; text-align: left;
} }
li { li {
line-height: 1em; line-height: 1em;
} }
h1.titles { h1.titles {
margin: 0px; margin: 0px;
padding: 0%; padding: 0%;
text-align: left; text-align: left;
padding-left: 5px; padding-left: 5px;
} }
main { main {
background: var(--main-color1); background: var(--main-color1);
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2);
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
height: 32px; height: 32px;
} }
main label { main label {
text-align: center; text-align: center;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
p { p {
font-size: 13px; font-size: 13px;
} }
main input { main input {
display: none; display: none;
} }
section { section {
clear: both; clear: both;
padding-top: 10px; padding-top: 10px;
display: none; display: none;
height: calc(100% - 60px); height: calc(100% - 60px);
} }
.Basiclabel { .Basiclabel {
font-weight: bold; font-weight: bold;
font-size: 14px; font-size: 14px;
display: block; display: block;
float: left; float: left;
flex: auto; flex: auto;
font-size: 20px; font-size: 20px;
padding: 0px 10px; padding: 0px 10px;
width: 50px; width: 50px;
align-self: baseline; align-self: baseline;
text-align: center; text-align: center;
} }
.scale { .scale {
height: 2em; height: 2em;
width: 2em; width: 2em;
vertical-align: bottom; vertical-align: bottom;
} }
.tab { .tab {
/* filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(350deg) brightness(104%) contrast(101%); */ /* filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(350deg) brightness(104%) contrast(101%); */
align-items: flex-start; align-items: flex-start;
margin: auto; margin: auto;
cursor: pointer; cursor: pointer;
} }
input:checked + label { input:checked + label {
border-top-color: #ffb03d; border-top-color: #ffb03d;
border-right-color: #ddd; border-right-color: #ddd;
border-left-color: #ddd; border-left-color: #ddd;
border-bottom-color: transparent; border-bottom-color: transparent;
text-decoration: none; text-decoration: none;
} }
/* --------------------------------- */ /* --------------------------------- */
.radius { .radius {
border-radius: 5px; border-radius: 5px;
} }
.radius .tabx:active::before { .radius .tabx:active::before {
border-radius: 5px !important; border-radius: 5px !important;
} }
.tabx-bar { .tabx-bar {
background-color: var(--main-color1); background-color: var(--main-color1);
/* padding: 5px; */ /* padding: 5px; */
box-shadow: 1px 4px 20px rgba(0, 0, 0, 0.2); box-shadow: 1px 4px 20px rgba(0, 0, 0, 0.2);
display: flex; display: flex;
/* margin: 10px; */ /* margin: 10px; */
color: black; color: black;
height: 50px; height: 50px;
} }
.tabx-bar .tabx { .tabx-bar .tabx {
box-sizing: border-box; box-sizing: border-box;
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
width: 70px; width: 70px;
height: 50px; height: 50px;
background: inherit; background: inherit;
display: inherit; display: inherit;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: relative; position: relative;
transition: all 0.3s; transition: all 0.3s;
} }
.tabx-bar .tabx::before { .tabx-bar .tabx::before {
position: absolute; position: absolute;
content: ''; content: '';
width: 26%; width: 26%;
height: 13%; height: 13%;
border-top-left-radius: 200px; border-top-left-radius: 200px;
border-top-right-radius: 200px; border-top-right-radius: 200px;
border-bottom: none; border-bottom: none;
background-color: #607d8b; background-color: #607d8b;
/* bottom: -8px; */ /* bottom: -8px; */
opacity: 0; opacity: 0;
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
} }
.tabx-bar .tabx:active::before { .tabx-bar .tabx:active::before {
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: #5fef8d; background-color: #5fef8d;
border-radius: 0; border-radius: 0;
} }
.tabx-bar .tabx:hover::before { .tabx-bar .tabx:hover::before {
opacity: 1; opacity: 1;
bottom: 0px; bottom: 0px;
} }
.tabx-bar .tabx::after { /* .tabx-bar .tabx::after {
} } */
.tabx-bar .tabx:hover { .tabx-bar .tabx:hover {
padding-bottom: 10px; padding-bottom: 10px;
} }
.tabx-bar .tabx:hover::after { .tabx-bar .tabx:hover::after {
opacity: 1; opacity: 1;
top: 6px; top: 6px;
} }
.tabx-bar .tabx.selected { .tabx-bar .tabx.selected {
background-color: rgba(0, 0, 0, 0.1); background-color: rgba(0, 0, 0, 0.1);
border-radius: inherit; border-radius: inherit;
padding-top: 0px; padding-top: 0px;
} }
.tabx-bar .tabx.selected::after { .tabx-bar .tabx.selected::after {
opacity: 1; opacity: 1;
top: -10px; top: -10px;
} }
.tabx-bar .tabx.selected::before { .tabx-bar .tabx.selected::before {
opacity: 1; opacity: 1;
bottom: 0px; bottom: 0px;
} }
.tabx-bar .tabx .icon { .tabx-bar .tabx .icon {
color: inherit; color: inherit;
font-size: 24px; font-size: 24px;
display: inherit; display: inherit;
} }
.tabx-bar .tabx .icon img { .tabx-bar .tabx .icon img {
margin: auto; margin: auto;
height: 32 px; height: 32 px;
} }
.language { .language {
width: 80px; width: 80px;
text-align: center; text-align: center;
} }
#AdvancedMenu_mask { #AdvancedMenu_mask {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
margin-top: 0px; margin-top: 0px;
width: 100%; width: 100%;
height: 100%; height: 100%;
visibility: hidden; visibility: hidden;
overflow: auto; overflow: auto;
overflow-x: hidden; overflow-x: hidden;
background-color: var(--mid-section); background-color: var(--mid-section);
font-family: 'xxii_avenmedium'; font-family: 'xxii_avenmedium';
padding-left: 50px; padding-left: 50px;
padding-right: 50px; padding-right: 50px;
} }
#ThemeCreator_mask { #ThemeCreator_mask {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
margin-top: 0px; margin-top: 0px;
width: 100%; width: 100%;
height: 100%; height: 100%;
visibility: hidden; visibility: hidden;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
overflow: auto; overflow: auto;
overflow-x: hidden; overflow-x: hidden;
background-color: var(--mid-section); background-color: var(--mid-section);
font-family: 'xxii_avenmedium'; font-family: 'xxii_avenmedium';
padding-left: 50px; padding-left: 50px;
padding-right: 50px; padding-right: 50px;
} }
.fname { .fname {
background: var(--main-color3); background: var(--main-color3);
border: none; border: none;
height: 40px; height: 40px;
border-radius: 40px; border-radius: 40px;
width: 300px; width: 300px;
outline: none; outline: none;
color: var(--main-color2); color: var(--main-color2);
font-size: 10pt; font-size: 10pt;
padding-left: 10px; padding-left: 10px;
} }
input[type='password'] { input[type='password'] {
background: var(--main-color3); background: var(--main-color3);
border: none; border: none;
height: 40px; height: 40px;
border-radius: 40px; border-radius: 40px;
width: 300px; width: 300px;
outline: none; outline: none;
color: var(--main-color2); color: var(--main-color2);
font-size: 10pt; font-size: 10pt;
padding-left: 10px; padding-left: 10px;
padding-right: 40px; padding-right: 40px;
/* To make space for the reveal button */ /* To make space for the reveal button */
} }
input[type='url'] { input[type='url'] {
background: var(--main-color3); background: var(--main-color3);
border: none; border: none;
height: 40px; height: 40px;
border-radius: 40px; border-radius: 40px;
width: 260px; width: 260px;
outline: none; outline: none;
color: var(--main-color2); color: var(--main-color2);
font-size: 10pt; font-size: 10pt;
margin-left: 10px; margin-left: 10px;
} }
input[type='lol'] { input[type='lol'] {
background: var(--main-color3); background: var(--main-color3);
border: none; border: none;
height: 40px; height: 40px;
border-radius: 40px; border-radius: 40px;
width: 300px; width: 300px;
outline: none; outline: none;
color: var(--main-color2); color: var(--main-color2);
font-size: 10pt; font-size: 10pt;
padding-left: 10px; padding-left: 10px;
padding-right: 40px; padding-right: 40px;
/* To make space for the reveal button */ /* To make space for the reveal button */
} }
/* Style for the reveal button */ /* Style for the reveal button */
.password-toggle-btn { .password-toggle-btn {
position: absolute; position: absolute;
background-color: transparent; background-color: transparent;
border: none; border: none;
cursor: pointer; cursor: pointer;
left: 450px; left: 450px;
} }
/* Hide the default appearance of the button */ /* Hide the default appearance of the button */
.password-toggle-btn::-moz-focus-inner { .password-toggle-btn::-moz-focus-inner {
border: 0; border: 0;
} }
/* Style the reveal icon (you can use your preferred icon or font) */ /* Style the reveal icon (you can use your preferred icon or font) */
.password-toggle-icon { .password-toggle-icon {
font-size: 16px; font-size: 16px;
color: var(--main-color2); color: var(--main-color2);
} }
#toasts { #toasts {
position: absolute; position: absolute;
bottom: 20px; bottom: 20px;
/* Adjust the distance from the bottom of the screen */ /* Adjust the distance from the bottom of the screen */
right: 0%; right: 0%;
/* Center the toasts horizontally */ /* Center the toasts horizontally */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
z-index: 999; z-index: 999;
} }
.toast { .toast {
background-color: #333; background-color: #333;
color: white; color: white;
border-radius: 5px; border-radius: 5px;
padding: 1rem 2rem; padding: 1rem 2rem;
margin: 0.5rem; margin: 0.5rem;
opacity: 0; opacity: 0;
transform: translateY(100%); transform: translateY(100%);
animation: toastAnimation 0.5s ease-in-out forwards, toastDisappear 0.5s ease-in-out 9s forwards; animation:
toastAnimation 0.5s ease-in-out forwards,
toastDisappear 0.5s ease-in-out 9s forwards;
} }
/* Apply different colors based on the toast type */ /* Apply different colors based on the toast type */
.info { .info {
background-color: lightblue !important; background-color: lightblue !important;
} }
.success { .success {
background-color: #2ecc71 !important; background-color: #2ecc71 !important;
} }
.warning { .warning {
background-color: #f39c12 !important; background-color: #f39c12 !important;
} }
.error { .error {
background-color: #e74c3c !important; background-color: #e74c3c !important;
} }
/* CSS animation for the toast appearance */ /* CSS animation for the toast appearance */
@keyframes toastAnimation { @keyframes toastAnimation {
from { from {
opacity: 0; opacity: 0;
transform: translateY(100%); transform: translateY(100%);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
} }
} }
/* CSS animation for the toast disappearance */ /* CSS animation for the toast disappearance */
@keyframes toastDisappear { @keyframes toastDisappear {
from { from {
opacity: 1; opacity: 1;
} }
to { to {
opacity: 0; opacity: 0;
} }
} }
.menu-icon { .menu-icon {
font-size: 17pt; font-size: 17pt;
} }
.tooltip { .tooltip {
position: absolute; position: absolute;
display: inline-block; display: inline-block;
visibility: hidden; visibility: hidden;
font-size: 12px; font-size: 12px;
line-height: 20px; line-height: 20px;
padding: 5px; padding: 5px;
background: var(--main-color3); background: var(--main-color3);
border-radius: 5px; border-radius: 5px;
visibility: hidden; visibility: hidden;
opacity: 1; opacity: 1;
box-shadow: -2px 2px 5px rgba(0, 0, 0, 0.2); box-shadow: -2px 2px 5px rgba(0, 0, 0, 0.2);
transition: opacity 0.3s, visibility 0s; transition:
color: var(--main-color2); opacity 0.3s,
font-family: 'xxii_avenmedium'; visibility 0s;
z-index: 999; color: var(--main-color2);
font-family: 'xxii_avenmedium';
z-index: 999;
} }
/* .tooltip .tooltiptext { /* .tooltip .tooltiptext {
@ -413,29 +417,29 @@ input[type='lol'] {
} */ } */
div[type='text']:disabled { div[type='text']:disabled {
background: #4b4b4b; background: #4b4b4b;
display: none; display: none;
} }
input[type='text']:disabled { input[type='text']:disabled {
background: #4b4b4b; background: #4b4b4b;
} }
button[type='text']:disabled { button[type='text']:disabled {
background: #4b4b4b; background: #4b4b4b;
display: none; display: none;
} }
input[type2='text']:disabled { input[type2='text']:disabled {
background: #4b4b4b; background: #4b4b4b;
} }
div:disabled { div:disabled {
background: #4b4b4b; background: #4b4b4b;
filter: brightness(200%); filter: brightness(200%);
} }
div:disabled { div:disabled {
background: #4b4b4b; background: #4b4b4b;
filter: brightness(200%); filter: brightness(200%);
} }

View file

@ -1,161 +1,169 @@
#tstx { #tstx {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin-left: 40px; margin-left: 40px;
} }
.optionrow { .optionrow {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
justify-content: left; justify-content: left;
margin-bottom: 10px; margin-bottom: 10px;
} }
.LabelText { .LabelText {
margin-bottom: 5px; margin-bottom: 5px;
color: var(--main-color2); color: var(--main-color2);
margin: 0px 0px 5px 0px; margin: 0px 0px 5px 0px;
} }
#volume-icon { #volume-icon {
color: var(--main-color2); color: var(--main-color2);
scale: 0.75; scale: 0.75;
cursor: pointer; cursor: pointer;
text-align: center; text-align: center;
align-self: center; align-self: center;
} }
#image { #image {
width: 100px; width: 100px;
height: 100px; height: 100px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.TTSVolume { .TTSVolume {
color: var(--main-color2); color: var(--main-color2);
font-size: 12pt; font-size: 12pt;
text-align: center; text-align: center;
} }
#SoundVolume { #SoundVolume {
color: var(--main-color2); color: var(--main-color2);
font-size: 12pt; font-size: 12pt;
} }
.testLabel { .testLabel {
color: var(--main-color2); color: var(--main-color2);
font-size: 12pt; font-size: 12pt;
} }
textarea { textarea {
height: 60px; height: 60px;
padding: 5px; padding: 5px;
width: 300px; width: 300px;
resize: none; resize: none;
border-radius: 5px; border-radius: 5px;
background: var(--main-color3); background: var(--main-color3);
color: var(--main-color2); color: var(--main-color2);
font-family: 'xxii_avenmedium'; font-family: 'xxii_avenmedium';
border: none; border: none;
} }
.SaveConfig { .SaveConfig {
align-content: center; align-content: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
color: var(--main-color2); color: var(--main-color2);
margin-bottom: 10px; margin-bottom: 10px;
} }
.SmallButton { .SmallButton {
color: var(--main-color2); color: var(--main-color2);
width: 50px; width: 50px;
cursor: pointer; cursor: pointer;
text-shadow: 0 0 5px #070607, 0 0 5px #070607, 0 0 5px #070607; text-shadow:
/* transition: all 0.15s ease-in-out; */ 0 0 5px #070607,
text-align: center; 0 0 5px #070607,
0 0 5px #070607;
/* transition: all 0.15s ease-in-out; */
text-align: center;
} }
.SmallButton:hover { .SmallButton:hover {
/* color: var(--main-color1); */ /* color: var(--main-color1); */
width: 50px; width: 50px;
cursor: pointer; cursor: pointer;
/* filter: brightness(150%); */ /* filter: brightness(150%); */
} }
.SmallButton:active { .SmallButton:active {
color: var(--main-color1); color: var(--main-color1);
transform: translateY(4px); transform: translateY(4px);
text-shadow: 0 0 5px #000, 0 0 5px #000, 0 0 5px #000; text-shadow:
0 0 5px #000,
0 0 5px #000,
0 0 5px #000;
} }
.AdvancedMenuButton { .AdvancedMenuButton {
width: 300px; width: 300px;
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background-color: var(--main-color3); background-color: var(--main-color3);
color: var(--main-color2); color: var(--main-color2);
padding: 0; padding: 0;
border: none; border: none;
font-family: 'xxii_avenmedium'; font-family: 'xxii_avenmedium';
font-size: 14pt; font-size: 14pt;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: box-shadow 0.3s ease, background-color 0.3s ease; transition:
/* Add a smooth transition for box-shadow and background-color */ box-shadow 0.3s ease,
background-color 0.3s ease;
/* Add a smooth transition for box-shadow and background-color */
} }
.AdvancedMenuButton:hover { .AdvancedMenuButton:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
background-color: var(--main-color3); background-color: var(--main-color3);
filter: brightness(150%); filter: brightness(150%);
/* Darken the background color on hover */ /* Darken the background color on hover */
cursor: pointer; cursor: pointer;
} }
.AdvancedMenuButton:active { .AdvancedMenuButton:active {
transform: translateY(2px); transform: translateY(2px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
background-color: var(--main-color3); background-color: var(--main-color3);
/* Reset the background color on click */ /* Reset the background color on click */
} }
.AdvancedMenuIcon { .AdvancedMenuIcon {
filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(350deg) brightness(104%) contrast(101%); filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(350deg) brightness(104%) contrast(101%);
align-items: flex-start; align-items: flex-start;
margin: auto; margin: auto;
height: 24px; height: 24px;
width: 24px; width: 24px;
} }
.AdvancedMenuIcon2 { .AdvancedMenuIcon2 {
align-items: flex-start; align-items: flex-start;
margin: auto; margin: auto;
height: 24px; height: 24px;
width: 24px; width: 24px;
} }
input:hover { input:hover {
filter: brightness(120%); filter: brightness(120%);
} }
select:hover { select:hover {
filter: brightness(120%); filter: brightness(120%);
} }
textarea:hover { textarea:hover {
filter: brightness(120%); filter: brightness(120%);
} }
label:hover { label:hover {
filter: brightness(120%); filter: brightness(120%);
} }
.circle-right:hover { .circle-right:hover {
filter: brightness(120%); filter: brightness(120%);
} }
.circle-left:hover { .circle-left:hover {
filter: brightness(120%); filter: brightness(120%);
} }

View file

@ -1,87 +1,87 @@
.middle { .middle {
width: 100%; width: 100%;
height: 50px; height: 50px;
border-radius: 10px; border-radius: 10px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
.slider-container { .slider-container {
width: 300px; width: 300px;
height: 100%; height: 100%;
position: relative; position: relative;
} }
.slider-container .bar { .slider-container .bar {
display: block; display: block;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 10px; border-radius: 10px;
background-color: var(--main-color3); background-color: var(--main-color3);
} }
.slider-container .bar .fill { .slider-container .bar .fill {
display: block; display: block;
width: 50%; width: 50%;
height: 100%; height: 100%;
border-radius: inherit; border-radius: inherit;
background-color: var(--main-color1); background-color: var(--main-color1);
} }
.slider-container .slider { .slider-container .slider {
position: absolute; position: absolute;
top: 50%; top: 50%;
-webkit-appearance: none; -webkit-appearance: none;
margin: 0; margin: 0;
width: 100%; width: 100%;
height: 0; height: 0;
border-radius: 5px; border-radius: 5px;
outline: none; outline: none;
background-color: transparent; background-color: transparent;
} }
.slider-container .slider::-webkit-slider-thumb { .slider-container .slider::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
width: 30px; width: 30px;
height: 30px; height: 30px;
background-color: var(--main-color2); background-color: var(--main-color2);
border-top-left-radius: 50%; border-top-left-radius: 50%;
border-top-right-radius: 50%; border-top-right-radius: 50%;
border-bottom-right-radius: 50%; border-bottom-right-radius: 50%;
border-bottom-left-radius: 50%; border-bottom-left-radius: 50%;
transform: rotate(-45deg) translate(0%, 0%); transform: rotate(-45deg) translate(0%, 0%);
cursor: pointer; cursor: pointer;
outline: none; outline: none;
/* box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); */ /* box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); */
box-shadow: 0 0 3px rgb(0 0 0 / 10%); box-shadow: 0 0 3px rgb(0 0 0 / 10%);
/* transition: .3s ease-in-out; */ /* transition: .3s ease-in-out; */
} }
.slider-container .slider:active::-webkit-slider-thumb, .slider-container .slider:active::-webkit-slider-thumb,
.slider-container .slider::-webkit-slider-thumb:hover { .slider-container .slider::-webkit-slider-thumb:hover {
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
transform: rotate(-45deg) translate(50%, -50%); transform: rotate(-45deg) translate(50%, -50%);
} }
.slider-container .slider:active::-webkit-slider-thumb { .slider-container .slider:active::-webkit-slider-thumb {
box-shadow: 0 0 0 3px rgba(255, 255, 255, 1); box-shadow: 0 0 0 3px rgba(255, 255, 255, 1);
} }
.option-icon-container { .option-icon-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/* justify-content: center; */ /* justify-content: center; */
align-items: center; align-items: center;
/* width: 78px; */ /* width: 78px; */
/* float: right; */ /* float: right; */
flex-grow: 1; flex-grow: 1;
} }
.brush-icon-container { .brush-icon-container {
margin-left: -20px; margin-left: -20px;
font-size: 20pt; font-size: 20pt;
} }
.icon { .icon {
fill: var(--main-color2); fill: var(--main-color2);
} }

File diff suppressed because it is too large Load diff

View file

@ -1,118 +1,118 @@
/* global settings, callback, addVoiceService, amazonVoices, */
const https = require('https'); const https = require('https');
const querystring = require('querystring'); const querystring = require('querystring');
const aws4 = require('aws4'); const aws4 = require('aws4');
function getAmazonVoices() { function getAmazonVoices() {
if (!settings.AMAZON.USE_AMAZON) { if (!settings.AMAZON.USE_AMAZON) {
callback(); callback();
return; return;
} }
addVoiceService('Amazon'); addVoiceService('Amazon');
let primaryVoice = document.querySelector('#primaryAmazonVoice'); const primaryVoice = document.querySelector('#primaryAmazonVoice');
let secondaryVoice = document.querySelector('#secondaryAmazonVoice'); const secondaryVoice = document.querySelector('#secondaryAmazonVoice');
function setVoicesinSelect(voiceSelect) { function setVoicesinSelect(voiceSelect) {
const voices = Object.values(amazonVoices); const voices = Object.values(amazonVoices);
voices.forEach((voice) => { voices.forEach(voice => {
const option = document.createElement('option'); const option = document.createElement('option');
option.classList.add('option'); option.classList.add('option');
option.value = voice; option.value = voice;
option.innerHTML = voice; option.innerHTML = voice;
voiceSelect.appendChild(option); voiceSelect.appendChild(option);
}); });
} }
setVoicesinSelect(primaryVoice); setVoicesinSelect(primaryVoice);
primaryVoice.value = settings.AMAZON.PRIMARY_VOICE; primaryVoice.value = settings.AMAZON.PRIMARY_VOICE;
setVoicesinSelect(secondaryVoice); setVoicesinSelect(secondaryVoice);
secondaryVoice.value = settings.AMAZON.SECONDARY_VOICE; secondaryVoice.value = settings.AMAZON.SECONDARY_VOICE;
} }
if (settings.AMAZON.USE_AMAZON) { if (settings.AMAZON.USE_AMAZON) {
getAmazonVoices(); getAmazonVoices();
} }
class PollyTTS { class PollyTTS {
constructor() {} textToSpeech(options, callback) {
if (!options) {
return callback(new Error('Options are missing'));
}
textToSpeech(options, callback) { const qs = {
if (!options) { Text: options.text,
return callback(new Error('Options are missing')); TextType: options.textType || 'text',
VoiceId: options.voiceId || 'Mia',
SampleRate: options.sampleRate || 22050,
OutputFormat: options.outputFormat || 'mp3',
Engine: options.engine || 'neural'
};
const opts = {
service: 'polly',
region: options.region || 'us-east-1',
path: `/v1/speech?${querystring.stringify(qs)}`,
signQuery: true
};
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
aws4.sign(opts, this.credentials);
https
.get(opts, res => {
if (res.statusCode !== 200) {
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
}
callback(null, res);
return true;
})
.on('error', e => {
callback(e);
});
return null;
}
describeVoices(callback, credentials) {
this.credentials = credentials;
const qs = {
Engine: 'neural'
};
const opts = {
service: 'polly',
region: 'us-east-1',
path: `/v1/voices?${querystring.stringify(qs)}`,
signQuery: true
};
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
aws4.sign(opts, this.credentials);
https
.get(opts, res => {
if (res.statusCode !== 200) {
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
} }
const qs = { let body = '';
Text: options.text, res.on('readable', () => {
TextType: options.textType || 'text', body += res.read();
VoiceId: options.voiceId || 'Mia', });
SampleRate: options.sampleRate || 22050, res.on('end', () => {
OutputFormat: options.outputFormat || 'mp3', callback(null, body);
Engine: options.engine || 'neural', });
};
const opts = { return undefined;
service: 'polly', })
region: options.region || 'us-east-1', .on('error', e => {
path: `/v1/speech?${querystring.stringify(qs)}`, callback(e);
signQuery: true, });
};
// you can also pass AWS credentials in explicitly (otherwise taken from process.env) return null;
aws4.sign(opts, this.credentials); }
https
.get(opts, (res) => {
if (res.statusCode !== 200) {
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
}
callback(null, res);
return true;
})
.on('error', (e) => {
callback(e);
});
return null;
}
describeVoices(callback, credentials) {
this.credentials = credentials;
const qs = {
Engine: 'neural',
};
const opts = {
service: 'polly',
region: 'us-east-1',
path: `/v1/voices?${querystring.stringify(qs)}`,
signQuery: true,
};
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
aws4.sign(opts, this.credentials);
https
.get(opts, (res) => {
if (res.statusCode !== 200) {
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
}
let body = '';
res.on('readable', () => {
body += res.read();
});
res.on('end', () => {
callback(null, body);
});
return undefined;
})
.on('error', (e) => {
callback(e);
});
return null;
}
} }
const pollyTTS = new PollyTTS(); const pollyTTS = new PollyTTS();

View file

@ -1,103 +1,217 @@
/* global settings, fs, settingsPath, ini, shell, options, axios */
const twitchAuthentication = () => const twitchAuthentication = () =>
new Promise((resolve) => { new Promise(resolve => {
const http = require('http'); const http = require('http');
const redirectUri = 'http://localhost:1989/auth'; const redirectUri = 'http://localhost:1989/auth';
const scopes = ['chat:edit', 'chat:read']; const scopes = ['chat:edit', 'chat:read'];
const express = require('express'); const express = require('express');
let tempAuthServer = express(); const tempAuthServer = express();
const port = 1989; const port = 1989;
const { parse: parseQueryString } = require('querystring'); const { parse: parseQueryString } = require('querystring');
tempAuthServer.use(function (req, res, next) { tempAuthServer.use(function (req, res, next) {
if (req.url !== '/auth') { if (req.url !== '/auth') {
let token = parseQueryString(req.query.auth); const token = parseQueryString(req.query.auth);
settings.TWITCH.OAUTH_TOKEN = token['#access_token']; settings.TWITCH.OAUTH_TOKEN = token['#access_token'];
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
resolve(token['#access_token']); resolve(token['#access_token']);
stopServer(); stopServer();
} }
next(); next();
});
function stopServer() {
tempAuthServer.close();
}
const htmlString = `
<!DOCTYPE html>
<html>
<head>
<title>Authentication</title>
</head>
<body>
<h1>Authentication successful! You can close this window now.</h1>
<form name="auth" "action="auth" method="get" >
<input type="text" id="auth" name="auth"/>
</form>
</body>
</html>
<script>
function onSubmitComplete() {
close();
}
document.querySelector("#auth").style.display="none";
document.querySelector("#auth").value = document.location.hash;
document.auth.submit();
setTimeout(onSubmitComplete, 500);
</script>
`;
tempAuthServer.get('/auth', (req, res) => {
res.send(htmlString);
});
tempAuthServer.post('/auth', (req, res) => {
res.render('authentication', { name: req.body.name });
});
const server = http.createServer(tempAuthServer);
server.listen(port, () => {
const authURL = `https://id.twitch.tv/oauth2/authorize?client_id=${settings.TWITCH.CLIENT_ID}&redirect_uri=${encodeURIComponent(
redirectUri,
)}&response_type=token&scope=${scopes.join(' ')}`;
shell.openExternal(authURL);
});
function stopServer() {
server.close(() => {});
}
}); });
// function stopServer() {
// tempAuthServer.close();
// }
const htmlString = `
<!DOCTYPE html>
<html>
<head>
<title>Authentication</title>
</head>
<body>
<h1>Authentication successful! You can close this window now.</h1>
<form name="auth" "action="auth" method="get" >
<input type="text" id="auth" name="auth"/>
</form>
</body>
</html>
<script>
function onSubmitComplete() {
close();
}
document.querySelector("#auth").style.display="none";
document.querySelector("#auth").value = document.location.hash;
document.auth.submit();
setTimeout(onSubmitComplete, 500);
</script>
`;
tempAuthServer.get('/auth', (req, res) => {
res.send(htmlString);
});
tempAuthServer.post('/auth', (req, res) => {
res.render('authentication', { name: req.body.name });
});
const server = http.createServer(tempAuthServer);
server.listen(port, () => {
const authURL = `https://id.twitch.tv/oauth2/authorize?client_id=${settings.TWITCH.CLIENT_ID}&redirect_uri=${encodeURIComponent(
redirectUri
)}&response_type=token&scope=${scopes.join(' ')}`;
shell.openExternal(authURL);
});
function stopServer() {
server.close(() => {});
}
});
function getTwitchUserId() { function getTwitchUserId() {
// Get user Logo with access token // Get user Logo with access token
options = { options = {
method: 'GET', method: 'GET',
url: `https://api.twitch.tv/helix/users`, url: 'https://api.twitch.tv/helix/users',
headers: { 'Client-ID': settings.TWITCH.CLIENT_ID, Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}` }, headers: {
}; 'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios axios
.request(options) .request(options)
.then((responseLogoUrl) => { .then(responseLogoUrl => {
console.log(responseLogoUrl.data.data[0]); console.log(responseLogoUrl.data.data[0]);
settings.TWITCH.USERNAME = responseLogoUrl.data.data[0].display_name; settings.TWITCH.USERNAME = responseLogoUrl.data.data[0].display_name;
settings.TWITCH.USER_LOGO_URL = responseLogoUrl.data.data[0].profile_image_url; settings.TWITCH.USER_LOGO_URL = responseLogoUrl.data.data[0].profile_image_url;
settings.TWITCH.USER_ID = responseLogoUrl.data.data[0].id; settings.TWITCH.USER_ID = responseLogoUrl.data.data[0].id;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
}) })
.catch((error) => { .catch(error => {
console.error(error); console.error(error);
});
}
function getTwitchOauthToken() {
return twitchAuthentication().then((res) => {
getTwitchUserId();
return res;
}); });
} }
function getTwitchSubscriptions(channelId) {
// Get user Logo with access token
options = {
method: 'GET',
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelId}`,
headers: {
'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(responseLogoUrl => {
console.log(responseLogoUrl);
})
.catch(error => {
console.error(error);
});
}
function getTwitchChannelEmotes(channelId) {
// Get user Logo with access token
options = {
method: 'GET',
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelId}`,
headers: {
'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(responseLogoUrl => {
console.log(responseLogoUrl);
})
.catch(error => {
console.error(error);
});
}
function getTwitchChannelFollows(channelId) {
// Get user Logo with access token
options = {
method: 'GET',
url: 'https://api.twitch.tv/helix/streams/followed',
headers: {
'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(responseLogoUrl => {
console.log(responseLogoUrl);
})
.catch(error => {
console.error(error);
});
}
function getTwitchChannelSubscriptions(channelId) {
// Get user Logo with access token
options = {
method: 'GET',
url: `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelId}`,
headers: {
'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(responseLogoUrl => {
console.log(responseLogoUrl);
})
.catch(error => {
console.error(error);
});
}
function getTwitchChannelId() {
// Get user Logo with access token
options = {
method: 'GET',
url: 'https://api.twitch.tv/helix/users?login=MelvyCoral',
headers: {
'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(responseLogoUrl => {
// console.log(responseLogoUrl);
getTwitchChannelEmotes(responseLogoUrl.data.data[0].id);
})
.catch(error => {
console.error(error);
});
}
function getTwitchOauthToken() {
// getTwitchChannelId();
getTwitchGLobalEmotes();
// return twitchAuthentication().then(res => {
// getTwitchUserId();
// return res;
// });
}
module.exports = { getTwitchOauthToken }; module.exports = { getTwitchOauthToken };

View file

@ -1,167 +1,178 @@
/* global settings, addVoiceService, internalVoices, ttsRequestCount, main, path, pythonPath, settingsPath, ipcRenderer */
const spawn = require('child_process').spawn; const spawn = require('child_process').spawn;
var kill = require('kill-process-by-name'); const kill = require('kill-process-by-name');
let python; let python;
async function getInstalledVoices() { async function getInstalledVoices() {
if (!settings.TTS.USE_TTS) { if (!settings.TTS.USE_TTS) {
return; return;
}
addVoiceService('Internal');
try {
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/voices`, { method: 'GET' });
if (response.ok) {
const responseData = await response.json();
console.log('Response:', responseData);
internalVoices = responseData;
} else {
console.error('Failed to send termination signal to Flask server.');
} }
addVoiceService('Internal'); } catch (error) {
console.error('Error sending termination signal:', error);
}
try { const primaryVoice = document.querySelector('#primaryVoice');
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/voices`, { method: 'GET' }); const secondaryVoice = document.querySelector('#secondaryVoice');
if (response.ok) {
const responseData = await response.json();
console.log('Response:', responseData);
internalVoices = responseData;
} else {
console.error('Failed to send termination signal to Flask server.');
}
} catch (error) {
console.error('Error sending termination signal:', error);
}
let primaryVoice = document.querySelector('#primaryVoice'); function setVoicesinSelect(voiceSelect) {
let secondaryVoice = document.querySelector('#secondaryVoice'); const voices = Object.values(internalVoices.voices);
voices.forEach(voice => {
const option = document.createElement('option');
option.classList.add('option');
function setVoicesinSelect(voiceSelect) { option.value = voice;
const voices = Object.values(internalVoices.voices); option.innerHTML = voice;
voices.forEach((voice) => {
const option = document.createElement('option');
option.classList.add('option');
option.value = voice; voiceSelect.appendChild(option);
option.innerHTML = voice; });
}
voiceSelect.appendChild(option); setVoicesinSelect(primaryVoice);
}); primaryVoice.value = settings.TTS.PRIMARY_VOICE;
} setVoicesinSelect(secondaryVoice);
setVoicesinSelect(primaryVoice); secondaryVoice.value = settings.TTS.SECONDARY_VOICE;
primaryVoice.value = settings.TTS.PRIMARY_VOICE;
setVoicesinSelect(secondaryVoice);
secondaryVoice.value = settings.TTS.SECONDARY_VOICE;
} }
async function getBackendServerStatus() { async function getBackendServerStatus() {
try { console.log('getting status');
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/status`, { method: 'GET' }); try {
if (response.ok) { const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/status`, { method: 'GET' });
const responseData = await response.json(); if (response.ok) {
console.log('Response:', responseData); const responseData = await response.json();
} else { console.log('Response:', responseData);
console.error('Failed to send termination signal to Flask server.'); } else {
} console.error('Failed to send termination signal to Flask server.');
} catch (error) {
console.error('Error sending termination signal:', error);
} }
} catch (error) {
console.error('Error sending termination signal:', error);
}
} }
function startSTT() { function startSTT() {
const eventSource = new EventSource('http://127.0.0.1:9000/stream'); const eventSource = new EventSource('http://127.0.0.1:9000/stream');
eventSource.addEventListener('message', (event) => { eventSource.addEventListener('message', event => {
const result = event.data; const result = event.data;
console.log(result); // Log the received data console.log(result); // Log the received data
}); });
eventSource.addEventListener('error', (event) => { eventSource.addEventListener('error', event => {
console.error('EventSource failed:', event); console.error('EventSource failed:', event);
eventSource.close(); eventSource.close();
}); });
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
eventSource.close(); eventSource.close();
}); });
} }
async function getInternalTTSAudio(requestData) { async function getInternalTTSAudio(requestData) {
ttsRequestCount++; ttsRequestCount++;
requestData.count = ttsRequestCount; requestData.count = ttsRequestCount;
const requestOptions = { const requestOptions = {
method: 'POST', // HTTP method method: 'POST', // HTTP method
headers: { headers: {
'Content-Type': 'application/json', // Specify the content type 'Content-Type': 'application/json' // Specify the content type
}, },
body: JSON.stringify(requestData), // Convert the data to JSON and include it in the request body body: JSON.stringify(requestData) // Convert the data to JSON and include it in the request body
}; };
try { try {
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/audio`, requestOptions); const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/audio`, requestOptions);
if (response.ok) { if (response.ok) {
const responseData = await response.json(); const responseData = await response.json();
console.log('Response:', responseData); console.log('Response:', responseData);
return ttsRequestCount; return ttsRequestCount;
} else { } else {
console.error('Failed to send termination signal to Flask server.'); console.error('Failed to send termination signal to Flask server.');
}
} catch (error) {
console.error('Error sending termination signal:', error);
} }
} catch (error) {
console.error('Error sending termination signal:', error);
}
} }
const createBackendServer = () => const createBackendServer = () =>
new Promise((resolve) => { new Promise(resolve => {
if (main.isPackaged) { if (main.isPackaged) {
python = spawn(path.join(pythonPath, './loquendoBot_backend.exe'), [settingsPath, 'prod']); python = spawn(path.join(pythonPath, './loquendoBot_backend.exe'), [settingsPath, 'prod']);
} else { } else {
python = spawn('python', ['-u', path.join(pythonPath, './loquendoBot_backend.py'), settingsPath, 'dev']); python = spawn('python', ['-u', path.join(pythonPath, './loquendoBot_backend.py'), settingsPath, 'dev']);
} }
// Capture the stdout of the Python process // Capture the stdout of the Python process
python.stdout.on('data', (data) => { python.stdout.on('data', data => {
console.info(`${data}`); console.info(`${data}`);
}); if (data.toString().startsWith('kees')) {
console.log('yess');
// Capture the stderr of the Python process // getBackendServerStatus();
python.stderr.on('data', (data) => { }
console.error(`${data}`);
resolve('finished'); // cannot get it to resolve with stdout
});
// Listen for the Python process to exit
python.on('close', (code) => {
console.log(`Python process exited with code ${code}`);
});
if (typeof python.pid !== 'number') {
console.log('failed');
} else {
console.log(`Spawned subprocess correctly!, PID = ${python.pid}`);
}
}); });
async function initiateBackend() { // Capture the stderr of the Python process
try { python.stderr.on('data', data => {
createBackendServer().then(() => { // console.error(`${data}`);
getBackendServerStatus(); if (data.toString().startsWith('INFO:waitress:Serving on')) {
getInstalledVoices(); resolve('finished');
if (settings.STT.USE_STT) { } else {
startSTT(); console.error(`${data}`);
} }
}); });
} catch (error) {
console.error('Error during backend initialization:', error); // Listen for the Python process to exit
python.on('close', code => {
console.log(`Python process exited with code ${code}`);
});
if (typeof python.pid !== 'number') {
console.log('failed');
} else {
// console.log(`Spawned subprocess correctly!, PID = ${python.pid}`);
} }
});
async function initiateBackend() {
try {
createBackendServer().then(() => {
getBackendServerStatus();
getInstalledVoices();
if (settings.STT.USE_STT) {
startSTT();
}
});
} catch (error) {
console.error('Error during backend initialization:', error);
}
} }
initiateBackend(); initiateBackend();
//TODO: convert to restartServer function // TODO: convert to restartServer function
ipcRenderer.on('quit-event', async () => { ipcRenderer.on('quit-event', async () => {
try { try {
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/terminate`, { method: 'GET' }); const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/terminate`, { method: 'GET' });
if (response.ok) { if (response.ok) {
const responseData = await response.json(); const responseData = await response.json();
console.log('Response:', responseData); console.log('Response:', responseData);
kill('loquendoBot_backend'); kill('loquendoBot_backend');
} else { } else {
console.error('Failed to send termination signal to Flask server.'); console.error('Failed to send termination signal to Flask server.');
kill('loquendoBot_backend'); kill('loquendoBot_backend');
}
} catch (error) {
console.error('Error sending termination signal:', error);
kill('loquendoBot_backend');
} }
} catch (error) {
console.error('Error sending termination signal:', error);
kill('loquendoBot_backend');
}
}); });
module.exports = { getInternalTTSAudio }; module.exports = { getInternalTTSAudio };

View file

@ -1,54 +1,76 @@
function getResponse() { /* global messageTemplates, emojiPicker, settings, getPostTime, showChatMessage, twitch */
const userText = document.querySelector('#textInput').value;
// If nothing is written don't do anything async function getResponse() {
if (userText === '') { const userText = document.querySelector('#textInput').value;
return;
}
// Create chat message from received data // If nothing is written don't do anything
const article = document.createElement('article'); if (userText === '') {
article.className = 'msg-container user'; return;
}
article.innerHTML = messageTemplates.userTemplate; // Create chat message from received data
const article = document.createElement('article');
article.className = 'msg-container user';
const userImg = article.querySelector('.user-img'); article.innerHTML = messageTemplates.userTemplate;
if (userImg) {
userImg.src = settings.TWITCH.USER_LOGO_URL;
}
const postTime = article.querySelector('.post-time'); const userImg = article.querySelector('.user-img');
if (userImg) {
userImg.src = settings.TWITCH.USER_LOGO_URL;
}
if (postTime) { const postTime = article.querySelector('.post-time');
postTime.innerText = getPostTime();
}
article.appendChild(postTime); if (postTime) {
postTime.innerText = getPostTime();
}
const msg = article.querySelector('.msg-box'); article.appendChild(postTime);
if (msg) {
msg.innerText = userText;
}
// Appends the message to the main chat box (shows the message) const msg = article.querySelector('.msg-box');
showChatMessage(article, true); if (msg) {
console.log(0);
await replaceChatMessageWithCustomEmojis(userText).then(data => {
// console.log(data);
msg.innerHTML = data;
twitch.sendMessage(userText); // Appends the message to the main chat box (shows the message)
showChatMessage(article);
// Empty input box after sending message twitch.sendMessage(userText);
document.body.querySelector('#textInput').value = '';
// Empty input box after sending message
document.body.querySelector('#textInput').value = '';
});
}
} }
const replaceChatMessageWithCustomEmojis = message =>
new Promise(resolve => {
const words = message.split(' ');
words.forEach(async word => {
if (word !== '') {
await emojiPicker.database.getEmojiByUnicodeOrName(word).then(data => {
if (data && data.name === word) {
const url = `<img src="${data.url}">`;
message = message.replace(word, url);
}
});
resolve(message);
}
});
});
// Function that will execute when you press 'enter' in the message box // Function that will execute when you press 'enter' in the message box
document.body.querySelector('#textInput').addEventListener('keydown', (e) => { document.body.querySelector('#textInput').addEventListener('keydown', e => {
if (e.which === 13) { if (e.which === 13) {
getResponse(); getResponse();
} }
}); });
// Function that will execute when you click the 'send' button // Function that will execute when you click the 'send' button
document.body.querySelector('#SendButton').addEventListener('click', () => { document.body.querySelector('#SendButton').addEventListener('click', () => {
getResponse(); getResponse();
}); });
// #endregion // #endregion
@ -57,21 +79,21 @@ document.body.querySelector('#SendButton').addEventListener('click', () => {
// Left panel // Left panel
document.body.querySelector('.circle-left').addEventListener('click', () => { document.body.querySelector('.circle-left').addEventListener('click', () => {
const menu = document.body.querySelector('.sidepanel-left'); const menu = document.body.querySelector('.sidepanel-left');
if (menu.classList.contains('collapse-menu-left')) { if (menu.classList.contains('collapse-menu-left')) {
menu.classList.remove('collapse-menu-left'); menu.classList.remove('collapse-menu-left');
} else { } else {
menu.classList.add('collapse-menu-left'); menu.classList.add('collapse-menu-left');
} }
const leftCircle = document.body.querySelector('.circle-left'); const leftCircle = document.body.querySelector('.circle-left');
if (leftCircle.classList.contains('collapse-circle-left')) { if (leftCircle.classList.contains('collapse-circle-left')) {
leftCircle.classList.remove('collapse-circle-left'); leftCircle.classList.remove('collapse-circle-left');
} else { } else {
leftCircle.classList.add('collapse-circle-left'); leftCircle.classList.add('collapse-circle-left');
} }
}); });
// #region Show panels // #region Show panels
@ -80,27 +102,26 @@ document.body.querySelector('.circle-left').addEventListener('click', () => {
// TODO : optimize show panels // TODO : optimize show panels
// Function that shows and hides the option panels. (TTS, Configuration, Commands) // Function that shows and hides the option panels. (TTS, Configuration, Commands)
const displayPanel = (panelSelectorClass, panelSelectorID, btnSelectorID) => { const displayPanel = (panelSelectorClass, panelSelectorID, btnSelectorID) => {
const btn = document.querySelector(btnSelectorID); const btn = document.querySelector(btnSelectorID);
const panel = document.querySelector(panelSelectorID); const panel = document.querySelector(panelSelectorID);
const panels = document.querySelectorAll(panelSelectorClass); const panels = document.querySelectorAll(panelSelectorClass);
btn.addEventListener( btn.addEventListener(
'click', 'click',
(event) => { event => {
event.stopPropagation(); event.stopPropagation();
panels.forEach((el) => { panels.forEach(el => {
if (el === panel) return; if (el === panel) return;
el.classList.remove('show'); el.classList.remove('show');
}); });
if (panel.classList.contains('show')) { if (!panel.classList.contains('show')) {
} else { panel.classList.add('show');
panel.classList.add('show'); }
} },
}, {
{ capture: true
capture: true, }
}, );
);
}; };
displayPanel('.OptionPanel', '#Configuration', '#btnConfiguration'); displayPanel('.OptionPanel', '#Configuration', '#btnConfiguration');
@ -113,27 +134,26 @@ displayPanel('.OptionPanel', '#ChatCreator', '#btnChatCreator');
// #endregion // #endregion
const displayPanelX = (panelSelectorClass, panelSelectorID, btnSelectorID) => { const displayPanelX = (panelSelectorClass, panelSelectorID, btnSelectorID) => {
const btn = document.querySelector(btnSelectorID); const btn = document.querySelector(btnSelectorID);
const panel = document.querySelector(panelSelectorID); const panel = document.querySelector(panelSelectorID);
const panels = document.querySelectorAll(panelSelectorClass); const panels = document.querySelectorAll(panelSelectorClass);
btn.addEventListener( btn.addEventListener(
'click', 'click',
(event) => { event => {
event.stopPropagation(); event.stopPropagation();
panels.forEach((el) => { panels.forEach(el => {
if (el === panel) return; if (el === panel) return;
el.classList.remove('item-active'); el.classList.remove('item-active');
}); });
if (panel.classList.contains('item-active')) { if (!panel.classList.contains('item-active')) {
} else { panel.classList.add('item-active');
panel.classList.add('item-active'); }
} },
}, {
{ capture: true
capture: true, }
}, );
);
}; };
displayPanelX('.item', '#btnChat', '#btnChat'); displayPanelX('.item', '#btnChat', '#btnChat');

9
src/js/customEmojis.js Normal file
View file

@ -0,0 +1,9 @@
const customEmojis = [
{
name: 'sakuraestaKleefeliz',
shortcodes: ['sakuraestaKleefeliz'],
url: 'https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_0cb536ddb6e143ab87ffeccb160a4d45/default/dark/1.0'
}
];
module.exports = { customEmojis };

View file

@ -1,31 +1,33 @@
/* global settings, addVoiceService, googleVoices */
function getGoogleVoices() { function getGoogleVoices() {
if (!settings.GOOGLE.USE_GOOGLE) { if (!settings.GOOGLE.USE_GOOGLE) {
return; return;
} }
addVoiceService('Google'); addVoiceService('Google');
let primaryVoice = document.querySelector('#primaryGoogleVoice'); const primaryVoice = document.querySelector('#primaryGoogleVoice');
let secondaryVoice = document.querySelector('#secondaryGoogleVoice'); const secondaryVoice = document.querySelector('#secondaryGoogleVoice');
function setVoicesinSelect(voiceSelect) { function setVoicesinSelect(voiceSelect) {
const voices = Object.values(googleVoices); const voices = Object.values(googleVoices);
voices.forEach((voice) => { voices.forEach(voice => {
const option = document.createElement('option'); const option = document.createElement('option');
option.classList.add('option'); option.classList.add('option');
option.value = voice; option.value = voice;
option.innerHTML = voice; option.innerHTML = voice;
voiceSelect.appendChild(option); voiceSelect.appendChild(option);
}); });
} }
setVoicesinSelect(primaryVoice); setVoicesinSelect(primaryVoice);
primaryVoice.value = settings.GOOGLE.PRIMARY_VOICE; primaryVoice.value = settings.GOOGLE.PRIMARY_VOICE;
setVoicesinSelect(secondaryVoice); setVoicesinSelect(secondaryVoice);
secondaryVoice.value = settings.GOOGLE.SECONDARY_VOICE; secondaryVoice.value = settings.GOOGLE.SECONDARY_VOICE;
} }
if (settings.GOOGLE.USE_GOOGLE) { if (settings.GOOGLE.USE_GOOGLE) {
getGoogleVoices(); getGoogleVoices();
} }

View file

@ -1,331 +1,332 @@
// TODO: Enable STT: // TODO: Enable STT:
// Output STT to TTS? *TTS service selection* (for now, later add the option to choose a specific voice with mega dropdowns) // Output STT to TTS? *TTS service selection* (for now, later add the option to choose a specific voice with mega dropdowns)
// *automatic translation: make an translation.js and add ALL the texts and have it translated if user chooses a language in top bar // *automatic translation: make an translation.js and add ALL the texts and have it translated if user chooses a language in top bar
// *info page with credits, version and more info // *info page with credits, version and more info
const languages = { const languages = {
acehnese: { IETF: 'ace-ID', 'ISO-639': 'ace' }, none: { IETF: 'none', 'ISO-639': 'none' },
afrikaans: { IETF: 'af-ZA', 'ISO-639': 'af' }, acehnese: { IETF: 'ace-ID', 'ISO-639': 'ace' },
akan: { IETF: 'ak-GH', 'ISO-639': 'ak' }, afrikaans: { IETF: 'af-ZA', 'ISO-639': 'af' },
albanian: { IETF: 'sq-AL', 'ISO-639': 'sq' }, akan: { IETF: 'ak-GH', 'ISO-639': 'ak' },
amharic: { IETF: 'am-ET', 'ISO-639': 'am' }, albanian: { IETF: 'sq-AL', 'ISO-639': 'sq' },
'antigua and barbuda creole english': { IETF: 'aig-AG', 'ISO-639': 'aig' }, amharic: { IETF: 'am-ET', 'ISO-639': 'am' },
arabic: { IETF: 'ar-SA', 'ISO-639': 'ar' }, 'antigua and barbuda creole english': { IETF: 'aig-AG', 'ISO-639': 'aig' },
'arabic egyptian': { IETF: 'ar-EG', 'ISO-639': 'ar' }, arabic: { IETF: 'ar-SA', 'ISO-639': 'ar' },
aragonese: { IETF: 'an-ES', 'ISO-639': 'an' }, 'arabic egyptian': { IETF: 'ar-EG', 'ISO-639': 'ar' },
armenian: { IETF: 'hy-AM', 'ISO-639': 'hy' }, aragonese: { IETF: 'an-ES', 'ISO-639': 'an' },
assamese: { IETF: 'as-IN', 'ISO-639': 'as' }, armenian: { IETF: 'hy-AM', 'ISO-639': 'hy' },
asturian: { IETF: 'ast-ES', 'ISO-639': 'ast' }, assamese: { IETF: 'as-IN', 'ISO-639': 'as' },
'austrian german': { IETF: 'de-AT', 'ISO-639': 'de' }, asturian: { IETF: 'ast-ES', 'ISO-639': 'ast' },
awadhi: { IETF: 'awa-IN', 'ISO-639': 'awa' }, 'austrian german': { IETF: 'de-AT', 'ISO-639': 'de' },
'ayacucho quechua': { IETF: 'quy-PE', 'ISO-639': 'quy' }, awadhi: { IETF: 'awa-IN', 'ISO-639': 'awa' },
azerbaijani: { IETF: 'az-AZ', 'ISO-639': 'az' }, 'ayacucho quechua': { IETF: 'quy-PE', 'ISO-639': 'quy' },
'bahamas creole english': { IETF: 'bah-BS', 'ISO-639': 'bah' }, azerbaijani: { IETF: 'az-AZ', 'ISO-639': 'az' },
bajan: { IETF: 'bjs-BB', 'ISO-639': 'bjs' }, 'bahamas creole english': { IETF: 'bah-BS', 'ISO-639': 'bah' },
balinese: { IETF: 'ban-ID', 'ISO-639': 'ban' }, bajan: { IETF: 'bjs-BB', 'ISO-639': 'bjs' },
'balkan gipsy': { IETF: 'rm-RO', 'ISO-639': 'rm' }, balinese: { IETF: 'ban-ID', 'ISO-639': 'ban' },
bambara: { IETF: 'bm-ML', 'ISO-639': 'bm' }, 'balkan gipsy': { IETF: 'rm-RO', 'ISO-639': 'rm' },
banjar: { IETF: 'bjn-ID', 'ISO-639': 'bjn' }, bambara: { IETF: 'bm-ML', 'ISO-639': 'bm' },
bashkir: { IETF: 'ba-RU', 'ISO-639': 'ba' }, banjar: { IETF: 'bjn-ID', 'ISO-639': 'bjn' },
basque: { IETF: 'eu-ES', 'ISO-639': 'eu' }, bashkir: { IETF: 'ba-RU', 'ISO-639': 'ba' },
belarusian: { IETF: 'be-BY', 'ISO-639': 'be' }, basque: { IETF: 'eu-ES', 'ISO-639': 'eu' },
'belgian french': { IETF: 'fr-BE', 'ISO-639': 'fr' }, belarusian: { IETF: 'be-BY', 'ISO-639': 'be' },
bemba: { IETF: 'bem-ZM', 'ISO-639': 'bem' }, 'belgian french': { IETF: 'fr-BE', 'ISO-639': 'fr' },
bengali: { IETF: 'bn-IN', 'ISO-639': 'bn' }, bemba: { IETF: 'bem-ZM', 'ISO-639': 'bem' },
bhojpuri: { IETF: 'bho-IN', 'ISO-639': 'bho' }, bengali: { IETF: 'bn-IN', 'ISO-639': 'bn' },
bihari: { IETF: 'bh-IN', 'ISO-639': 'bh' }, bhojpuri: { IETF: 'bho-IN', 'ISO-639': 'bho' },
bislama: { IETF: 'bi-VU', 'ISO-639': 'bi' }, bihari: { IETF: 'bh-IN', 'ISO-639': 'bh' },
borana: { IETF: 'gax-KE', 'ISO-639': 'gax' }, bislama: { IETF: 'bi-VU', 'ISO-639': 'bi' },
bosnian: { IETF: 'bs-BA', 'ISO-639': 'bs' }, borana: { IETF: 'gax-KE', 'ISO-639': 'gax' },
'bosnian (cyrillic)': { IETF: 'bs-Cyrl-BA', 'ISO-639': 'bs' }, bosnian: { IETF: 'bs-BA', 'ISO-639': 'bs' },
breton: { IETF: 'br-FR', 'ISO-639': 'br' }, 'bosnian (cyrillic)': { IETF: 'bs-Cyrl-BA', 'ISO-639': 'bs' },
buginese: { IETF: 'bug-ID', 'ISO-639': 'bug' }, breton: { IETF: 'br-FR', 'ISO-639': 'br' },
bulgarian: { IETF: 'bg-BG', 'ISO-639': 'bg' }, buginese: { IETF: 'bug-ID', 'ISO-639': 'bug' },
burmese: { IETF: 'my-MM', 'ISO-639': 'my' }, bulgarian: { IETF: 'bg-BG', 'ISO-639': 'bg' },
catalan: { IETF: 'ca-ES', 'ISO-639': 'ca' }, burmese: { IETF: 'my-MM', 'ISO-639': 'my' },
'catalan valencian': { IETF: 'cav-ES', 'ISO-639': 'cav' }, catalan: { IETF: 'ca-ES', 'ISO-639': 'ca' },
cebuano: { IETF: 'ceb-PH', 'ISO-639': 'ceb' }, 'catalan valencian': { IETF: 'cav-ES', 'ISO-639': 'cav' },
'central atlas tamazight': { IETF: 'tzm-MA', 'ISO-639': 'tzm' }, cebuano: { IETF: 'ceb-PH', 'ISO-639': 'ceb' },
'central aymara': { IETF: 'ayr-BO', 'ISO-639': 'ayr' }, 'central atlas tamazight': { IETF: 'tzm-MA', 'ISO-639': 'tzm' },
'central kanuri (latin script)': { IETF: 'knc-NG', 'ISO-639': 'knc' }, 'central aymara': { IETF: 'ayr-BO', 'ISO-639': 'ayr' },
'chadian arabic': { IETF: 'shu-TD', 'ISO-639': 'shu' }, 'central kanuri (latin script)': { IETF: 'knc-NG', 'ISO-639': 'knc' },
chamorro: { IETF: 'ch-GU', 'ISO-639': 'ch' }, 'chadian arabic': { IETF: 'shu-TD', 'ISO-639': 'shu' },
cherokee: { IETF: 'chr-US', 'ISO-639': 'chr' }, chamorro: { IETF: 'ch-GU', 'ISO-639': 'ch' },
chhattisgarhi: { IETF: 'hne-IN', 'ISO-639': 'hne' }, cherokee: { IETF: 'chr-US', 'ISO-639': 'chr' },
'chinese simplified': { IETF: 'zh-CN', 'ISO-639': 'zh' }, chhattisgarhi: { IETF: 'hne-IN', 'ISO-639': 'hne' },
'chinese trad. (hong kong)': { IETF: 'zh-HK', 'ISO-639': 'zh' }, 'chinese simplified': { IETF: 'zh-CN', 'ISO-639': 'zh' },
'chinese traditional': { IETF: 'zh-TW', 'ISO-639': 'zh' }, 'chinese trad. (hong kong)': { IETF: 'zh-HK', 'ISO-639': 'zh' },
'chinese traditional macau': { IETF: 'zh-MO', 'ISO-639': 'zh' }, 'chinese traditional': { IETF: 'zh-TW', 'ISO-639': 'zh' },
chittagonian: { IETF: 'ctg-BD', 'ISO-639': 'ctg' }, 'chinese traditional macau': { IETF: 'zh-MO', 'ISO-639': 'zh' },
chokwe: { IETF: 'cjk-AO', 'ISO-639': 'cjk' }, chittagonian: { IETF: 'ctg-BD', 'ISO-639': 'ctg' },
'classical greek': { IETF: 'grc-GR', 'ISO-639': 'grc' }, chokwe: { IETF: 'cjk-AO', 'ISO-639': 'cjk' },
'comorian ngazidja': { IETF: 'zdj-KM', 'ISO-639': 'zdj' }, 'classical greek': { IETF: 'grc-GR', 'ISO-639': 'grc' },
coptic: { IETF: 'cop-EG', 'ISO-639': 'cop' }, 'comorian ngazidja': { IETF: 'zdj-KM', 'ISO-639': 'zdj' },
'crimean tatar': { IETF: 'crh-RU', 'ISO-639': 'crh' }, coptic: { IETF: 'cop-EG', 'ISO-639': 'cop' },
'crioulo upper guinea': { IETF: 'pov-GW', 'ISO-639': 'pov' }, 'crimean tatar': { IETF: 'crh-RU', 'ISO-639': 'crh' },
croatian: { IETF: 'hr-HR', 'ISO-639': 'hr' }, 'crioulo upper guinea': { IETF: 'pov-GW', 'ISO-639': 'pov' },
czech: { IETF: 'cs-CZ', 'ISO-639': 'cs' }, croatian: { IETF: 'hr-HR', 'ISO-639': 'hr' },
danish: { IETF: 'da-DK', 'ISO-639': 'da' }, czech: { IETF: 'cs-CZ', 'ISO-639': 'cs' },
dari: { IETF: 'prs-AF', 'ISO-639': 'prs' }, danish: { IETF: 'da-DK', 'ISO-639': 'da' },
dimli: { IETF: 'diq-TR', 'ISO-639': 'diq' }, dari: { IETF: 'prs-AF', 'ISO-639': 'prs' },
dutch: { IETF: 'nl-NL', 'ISO-639': 'nl' }, dimli: { IETF: 'diq-TR', 'ISO-639': 'diq' },
dyula: { IETF: 'dyu-CI', 'ISO-639': 'dyu' }, dutch: { IETF: 'nl-NL', 'ISO-639': 'nl' },
dzongkha: { IETF: 'dz-BT', 'ISO-639': 'dz' }, dyula: { IETF: 'dyu-CI', 'ISO-639': 'dyu' },
'eastern yiddish': { IETF: 'ydd-US', 'ISO-639': 'ydd' }, dzongkha: { IETF: 'dz-BT', 'ISO-639': 'dz' },
emakhuwa: { IETF: 'vmw-MZ', 'ISO-639': 'vmw' }, 'eastern yiddish': { IETF: 'ydd-US', 'ISO-639': 'ydd' },
english: { IETF: 'en-GB', 'ISO-639': 'en' }, emakhuwa: { IETF: 'vmw-MZ', 'ISO-639': 'vmw' },
'english australia': { IETF: 'en-AU', 'ISO-639': 'en' }, english: { IETF: 'en-GB', 'ISO-639': 'en' },
'english canada': { IETF: 'en-CA', 'ISO-639': 'en' }, 'english australia': { IETF: 'en-AU', 'ISO-639': 'en' },
'english india': { IETF: 'en-IN', 'ISO-639': 'en' }, 'english canada': { IETF: 'en-CA', 'ISO-639': 'en' },
'english ireland': { IETF: 'en-IE', 'ISO-639': 'en' }, 'english india': { IETF: 'en-IN', 'ISO-639': 'en' },
'english new zealand': { IETF: 'en-NZ', 'ISO-639': 'en' }, 'english ireland': { IETF: 'en-IE', 'ISO-639': 'en' },
'english singapore': { IETF: 'en-SG', 'ISO-639': 'en' }, 'english new zealand': { IETF: 'en-NZ', 'ISO-639': 'en' },
'english south africa': { IETF: 'en-ZA', 'ISO-639': 'en' }, 'english singapore': { IETF: 'en-SG', 'ISO-639': 'en' },
'english us': { IETF: 'en-US', 'ISO-639': 'en' }, 'english south africa': { IETF: 'en-ZA', 'ISO-639': 'en' },
esperanto: { IETF: 'eo-EU', 'ISO-639': 'eo' }, 'english us': { IETF: 'en-US', 'ISO-639': 'en' },
estonian: { IETF: 'et-EE', 'ISO-639': 'et' }, esperanto: { IETF: 'eo-EU', 'ISO-639': 'eo' },
ewe: { IETF: 'ee-GH', 'ISO-639': 'ee' }, estonian: { IETF: 'et-EE', 'ISO-639': 'et' },
fanagalo: { IETF: 'fn-FNG', 'ISO-639': 'fn' }, ewe: { IETF: 'ee-GH', 'ISO-639': 'ee' },
faroese: { IETF: 'fo-FO', 'ISO-639': 'fo' }, fanagalo: { IETF: 'fn-FNG', 'ISO-639': 'fn' },
fijian: { IETF: 'fj-FJ', 'ISO-639': 'fj' }, faroese: { IETF: 'fo-FO', 'ISO-639': 'fo' },
filipino: { IETF: 'fil-PH', 'ISO-639': 'fil' }, fijian: { IETF: 'fj-FJ', 'ISO-639': 'fj' },
finnish: { IETF: 'fi-FI', 'ISO-639': 'fi' }, filipino: { IETF: 'fil-PH', 'ISO-639': 'fil' },
flemish: { IETF: 'nl-BE', 'ISO-639': 'nl' }, finnish: { IETF: 'fi-FI', 'ISO-639': 'fi' },
fon: { IETF: 'fon-BJ', 'ISO-639': 'fon' }, flemish: { IETF: 'nl-BE', 'ISO-639': 'nl' },
french: { IETF: 'fr-FR', 'ISO-639': 'fr' }, fon: { IETF: 'fon-BJ', 'ISO-639': 'fon' },
'french canada': { IETF: 'fr-CA', 'ISO-639': 'fr' }, french: { IETF: 'fr-FR', 'ISO-639': 'fr' },
'french swiss': { IETF: 'fr-CH', 'ISO-639': 'fr' }, 'french canada': { IETF: 'fr-CA', 'ISO-639': 'fr' },
friulian: { IETF: 'fur-IT', 'ISO-639': 'fur' }, 'french swiss': { IETF: 'fr-CH', 'ISO-639': 'fr' },
fula: { IETF: 'ff-FUL', 'ISO-639': 'ff' }, friulian: { IETF: 'fur-IT', 'ISO-639': 'fur' },
galician: { IETF: 'gl-ES', 'ISO-639': 'gl' }, fula: { IETF: 'ff-FUL', 'ISO-639': 'ff' },
gamargu: { IETF: 'mfi-NG', 'ISO-639': 'mfi' }, galician: { IETF: 'gl-ES', 'ISO-639': 'gl' },
garo: { IETF: 'grt-IN', 'ISO-639': 'grt' }, gamargu: { IETF: 'mfi-NG', 'ISO-639': 'mfi' },
georgian: { IETF: 'ka-GE', 'ISO-639': 'ka' }, garo: { IETF: 'grt-IN', 'ISO-639': 'grt' },
german: { IETF: 'de-DE', 'ISO-639': 'de' }, georgian: { IETF: 'ka-GE', 'ISO-639': 'ka' },
gilbertese: { IETF: 'gil-KI', 'ISO-639': 'gil' }, german: { IETF: 'de-DE', 'ISO-639': 'de' },
glavda: { IETF: 'glw-NG', 'ISO-639': 'glw' }, gilbertese: { IETF: 'gil-KI', 'ISO-639': 'gil' },
greek: { IETF: 'el-GR', 'ISO-639': 'el' }, glavda: { IETF: 'glw-NG', 'ISO-639': 'glw' },
'grenadian creole english': { IETF: 'gcl-GD', 'ISO-639': 'gcl' }, greek: { IETF: 'el-GR', 'ISO-639': 'el' },
guarani: { IETF: 'gn-PY', 'ISO-639': 'gn' }, 'grenadian creole english': { IETF: 'gcl-GD', 'ISO-639': 'gcl' },
gujarati: { IETF: 'gu-IN', 'ISO-639': 'gu' }, guarani: { IETF: 'gn-PY', 'ISO-639': 'gn' },
'guyanese creole english': { IETF: 'gyn-GY', 'ISO-639': 'gyn' }, gujarati: { IETF: 'gu-IN', 'ISO-639': 'gu' },
'haitian creole french': { IETF: 'ht-HT', 'ISO-639': 'ht' }, 'guyanese creole english': { IETF: 'gyn-GY', 'ISO-639': 'gyn' },
'halh mongolian': { IETF: 'khk-MN', 'ISO-639': 'khk' }, 'haitian creole french': { IETF: 'ht-HT', 'ISO-639': 'ht' },
hausa: { IETF: 'ha-NE', 'ISO-639': 'ha' }, 'halh mongolian': { IETF: 'khk-MN', 'ISO-639': 'khk' },
hawaiian: { IETF: 'haw-US', 'ISO-639': 'haw' }, hausa: { IETF: 'ha-NE', 'ISO-639': 'ha' },
hebrew: { IETF: 'he-IL', 'ISO-639': 'he' }, hawaiian: { IETF: 'haw-US', 'ISO-639': 'haw' },
higi: { IETF: 'hig-NG', 'ISO-639': 'hig' }, hebrew: { IETF: 'he-IL', 'ISO-639': 'he' },
hiligaynon: { IETF: 'hil-PH', 'ISO-639': 'hil' }, higi: { IETF: 'hig-NG', 'ISO-639': 'hig' },
'hill mari': { IETF: 'mrj-RU', 'ISO-639': 'mrj' }, hiligaynon: { IETF: 'hil-PH', 'ISO-639': 'hil' },
hindi: { IETF: 'hi-IN', 'ISO-639': 'hi' }, 'hill mari': { IETF: 'mrj-RU', 'ISO-639': 'mrj' },
hmong: { IETF: 'hmn-CN', 'ISO-639': 'hmn' }, hindi: { IETF: 'hi-IN', 'ISO-639': 'hi' },
hungarian: { IETF: 'hu-HU', 'ISO-639': 'hu' }, hmong: { IETF: 'hmn-CN', 'ISO-639': 'hmn' },
icelandic: { IETF: 'is-IS', 'ISO-639': 'is' }, hungarian: { IETF: 'hu-HU', 'ISO-639': 'hu' },
'igbo ibo': { IETF: 'ibo-NG', 'ISO-639': 'ibo' }, icelandic: { IETF: 'is-IS', 'ISO-639': 'is' },
'igbo ig': { IETF: 'ig-NG', 'ISO-639': 'ig' }, 'igbo ibo': { IETF: 'ibo-NG', 'ISO-639': 'ibo' },
ilocano: { IETF: 'ilo-PH', 'ISO-639': 'ilo' }, 'igbo ig': { IETF: 'ig-NG', 'ISO-639': 'ig' },
indonesian: { IETF: 'id-ID', 'ISO-639': 'id' }, ilocano: { IETF: 'ilo-PH', 'ISO-639': 'ilo' },
'inuktitut greenlandic': { IETF: 'kl-GL', 'ISO-639': 'kl' }, indonesian: { IETF: 'id-ID', 'ISO-639': 'id' },
'irish gaelic': { IETF: 'ga-IE', 'ISO-639': 'ga' }, 'inuktitut greenlandic': { IETF: 'kl-GL', 'ISO-639': 'kl' },
italian: { IETF: 'it-IT', 'ISO-639': 'it' }, 'irish gaelic': { IETF: 'ga-IE', 'ISO-639': 'ga' },
'italian swiss': { IETF: 'it-CH', 'ISO-639': 'it' }, italian: { IETF: 'it-IT', 'ISO-639': 'it' },
'jamaican creole english': { IETF: 'jam-JM', 'ISO-639': 'jam' }, 'italian swiss': { IETF: 'it-CH', 'ISO-639': 'it' },
japanese: { IETF: 'ja-JP', 'ISO-639': 'ja' }, 'jamaican creole english': { IETF: 'jam-JM', 'ISO-639': 'jam' },
javanese: { IETF: 'jv-ID', 'ISO-639': 'jv' }, japanese: { IETF: 'ja-JP', 'ISO-639': 'ja' },
jingpho: { IETF: 'kac-MM', 'ISO-639': 'kac' }, javanese: { IETF: 'jv-ID', 'ISO-639': 'jv' },
"k'iche'": { IETF: 'quc-GT', 'ISO-639': 'quc' }, jingpho: { IETF: 'kac-MM', 'ISO-639': 'kac' },
'kabiy<69>': { IETF: 'kbp-TG', 'ISO-639': 'kbp' }, "k'iche'": { IETF: 'quc-GT', 'ISO-639': 'quc' },
kabuverdianu: { IETF: 'kea-CV', 'ISO-639': 'kea' }, 'kabiy<69>': { IETF: 'kbp-TG', 'ISO-639': 'kbp' },
kabylian: { IETF: 'kab-DZ', 'ISO-639': 'kab' }, kabuverdianu: { IETF: 'kea-CV', 'ISO-639': 'kea' },
kalenjin: { IETF: 'kln-KE', 'ISO-639': 'kln' }, kabylian: { IETF: 'kab-DZ', 'ISO-639': 'kab' },
kamba: { IETF: 'kam-KE', 'ISO-639': 'kam' }, kalenjin: { IETF: 'kln-KE', 'ISO-639': 'kln' },
kannada: { IETF: 'kn-IN', 'ISO-639': 'kn' }, kamba: { IETF: 'kam-KE', 'ISO-639': 'kam' },
kanuri: { IETF: 'kr-KAU', 'ISO-639': 'kr' }, kannada: { IETF: 'kn-IN', 'ISO-639': 'kn' },
karen: { IETF: 'kar-MM', 'ISO-639': 'kar' }, kanuri: { IETF: 'kr-KAU', 'ISO-639': 'kr' },
'kashmiri (devanagari script)': { IETF: 'ks-IN', 'ISO-639': 'ks' }, karen: { IETF: 'kar-MM', 'ISO-639': 'kar' },
'kashmiri (arabic script)': { IETF: 'kas-IN', 'ISO-639': 'kas' }, 'kashmiri (devanagari script)': { IETF: 'ks-IN', 'ISO-639': 'ks' },
kazakh: { IETF: 'kk-KZ', 'ISO-639': 'kk' }, 'kashmiri (arabic script)': { IETF: 'kas-IN', 'ISO-639': 'kas' },
khasi: { IETF: 'kha-IN', 'ISO-639': 'kha' }, kazakh: { IETF: 'kk-KZ', 'ISO-639': 'kk' },
khmer: { IETF: 'km-KH', 'ISO-639': 'km' }, khasi: { IETF: 'kha-IN', 'ISO-639': 'kha' },
'kikuyu kik': { IETF: 'kik-KE', 'ISO-639': 'kik' }, khmer: { IETF: 'km-KH', 'ISO-639': 'km' },
'kikuyu ki': { IETF: 'ki-KE', 'ISO-639': 'ki' }, 'kikuyu kik': { IETF: 'kik-KE', 'ISO-639': 'kik' },
kimbundu: { IETF: 'kmb-AO', 'ISO-639': 'kmb' }, 'kikuyu ki': { IETF: 'ki-KE', 'ISO-639': 'ki' },
kinyarwanda: { IETF: 'rw-RW', 'ISO-639': 'rw' }, kimbundu: { IETF: 'kmb-AO', 'ISO-639': 'kmb' },
kirundi: { IETF: 'rn-BI', 'ISO-639': 'rn' }, kinyarwanda: { IETF: 'rw-RW', 'ISO-639': 'rw' },
kisii: { IETF: 'guz-KE', 'ISO-639': 'guz' }, kirundi: { IETF: 'rn-BI', 'ISO-639': 'rn' },
kongo: { IETF: 'kg-CG', 'ISO-639': 'kg' }, kisii: { IETF: 'guz-KE', 'ISO-639': 'guz' },
konkani: { IETF: 'kok-IN', 'ISO-639': 'kok' }, kongo: { IETF: 'kg-CG', 'ISO-639': 'kg' },
korean: { IETF: 'ko-KR', 'ISO-639': 'ko' }, konkani: { IETF: 'kok-IN', 'ISO-639': 'kok' },
'northern kurdish': { IETF: 'kmr-TR', 'ISO-639': 'kmr' }, korean: { IETF: 'ko-KR', 'ISO-639': 'ko' },
'kurdish sorani': { IETF: 'ckb-IQ', 'ISO-639': 'ckb' }, 'northern kurdish': { IETF: 'kmr-TR', 'ISO-639': 'kmr' },
kyrgyz: { IETF: 'ky-KG', 'ISO-639': 'ky' }, 'kurdish sorani': { IETF: 'ckb-IQ', 'ISO-639': 'ckb' },
lao: { IETF: 'lo-LA', 'ISO-639': 'lo' }, kyrgyz: { IETF: 'ky-KG', 'ISO-639': 'ky' },
latgalian: { IETF: 'ltg-LV', 'ISO-639': 'ltg' }, lao: { IETF: 'lo-LA', 'ISO-639': 'lo' },
latin: { IETF: 'la-XN', 'ISO-639': 'la' }, latgalian: { IETF: 'ltg-LV', 'ISO-639': 'ltg' },
latvian: { IETF: 'lv-LV', 'ISO-639': 'lv' }, latin: { IETF: 'la-XN', 'ISO-639': 'la' },
ligurian: { IETF: 'lij-IT', 'ISO-639': 'lij' }, latvian: { IETF: 'lv-LV', 'ISO-639': 'lv' },
limburgish: { IETF: 'li-NL', 'ISO-639': 'li' }, ligurian: { IETF: 'lij-IT', 'ISO-639': 'lij' },
lingala: { IETF: 'ln-LIN', 'ISO-639': 'ln' }, limburgish: { IETF: 'li-NL', 'ISO-639': 'li' },
lithuanian: { IETF: 'lt-LT', 'ISO-639': 'lt' }, lingala: { IETF: 'ln-LIN', 'ISO-639': 'ln' },
lombard: { IETF: 'lmo-IT', 'ISO-639': 'lmo' }, lithuanian: { IETF: 'lt-LT', 'ISO-639': 'lt' },
'luba-kasai': { IETF: 'lua-CD', 'ISO-639': 'lua' }, lombard: { IETF: 'lmo-IT', 'ISO-639': 'lmo' },
luganda: { IETF: 'lg-UG', 'ISO-639': 'lg' }, 'luba-kasai': { IETF: 'lua-CD', 'ISO-639': 'lua' },
luhya: { IETF: 'luy-KE', 'ISO-639': 'luy' }, luganda: { IETF: 'lg-UG', 'ISO-639': 'lg' },
luo: { IETF: 'luo-KE', 'ISO-639': 'luo' }, luhya: { IETF: 'luy-KE', 'ISO-639': 'luy' },
luxembourgish: { IETF: 'lb-LU', 'ISO-639': 'lb' }, luo: { IETF: 'luo-KE', 'ISO-639': 'luo' },
maa: { IETF: 'mas-KE', 'ISO-639': 'mas' }, luxembourgish: { IETF: 'lb-LU', 'ISO-639': 'lb' },
macedonian: { IETF: 'mk-MK', 'ISO-639': 'mk' }, maa: { IETF: 'mas-KE', 'ISO-639': 'mas' },
magahi: { IETF: 'mag-IN', 'ISO-639': 'mag' }, macedonian: { IETF: 'mk-MK', 'ISO-639': 'mk' },
maithili: { IETF: 'mai-IN', 'ISO-639': 'mai' }, magahi: { IETF: 'mag-IN', 'ISO-639': 'mag' },
malagasy: { IETF: 'mg-MG', 'ISO-639': 'mg' }, maithili: { IETF: 'mai-IN', 'ISO-639': 'mai' },
malay: { IETF: 'ms-MY', 'ISO-639': 'ms' }, malagasy: { IETF: 'mg-MG', 'ISO-639': 'mg' },
malayalam: { IETF: 'ml-IN', 'ISO-639': 'ml' }, malay: { IETF: 'ms-MY', 'ISO-639': 'ms' },
maldivian: { IETF: 'dv-MV', 'ISO-639': 'dv' }, malayalam: { IETF: 'ml-IN', 'ISO-639': 'ml' },
maltese: { IETF: 'mt-MT', 'ISO-639': 'mt' }, maldivian: { IETF: 'dv-MV', 'ISO-639': 'dv' },
mandara: { IETF: 'mfi-CM', 'ISO-639': 'mfi' }, maltese: { IETF: 'mt-MT', 'ISO-639': 'mt' },
manipuri: { IETF: 'mni-IN', 'ISO-639': 'mni' }, mandara: { IETF: 'mfi-CM', 'ISO-639': 'mfi' },
'manx gaelic': { IETF: 'gv-IM', 'ISO-639': 'gv' }, manipuri: { IETF: 'mni-IN', 'ISO-639': 'mni' },
maori: { IETF: 'mi-NZ', 'ISO-639': 'mi' }, 'manx gaelic': { IETF: 'gv-IM', 'ISO-639': 'gv' },
marathi: { IETF: 'mr-IN', 'ISO-639': 'mr' }, maori: { IETF: 'mi-NZ', 'ISO-639': 'mi' },
margi: { IETF: 'mrt-NG', 'ISO-639': 'mrt' }, marathi: { IETF: 'mr-IN', 'ISO-639': 'mr' },
mari: { IETF: 'mhr-RU', 'ISO-639': 'mhr' }, margi: { IETF: 'mrt-NG', 'ISO-639': 'mrt' },
marshallese: { IETF: 'mh-MH', 'ISO-639': 'mh' }, mari: { IETF: 'mhr-RU', 'ISO-639': 'mhr' },
mende: { IETF: 'men-SL', 'ISO-639': 'men' }, marshallese: { IETF: 'mh-MH', 'ISO-639': 'mh' },
meru: { IETF: 'mer-KE', 'ISO-639': 'mer' }, mende: { IETF: 'men-SL', 'ISO-639': 'men' },
mijikenda: { IETF: 'nyf-KE', 'ISO-639': 'nyf' }, meru: { IETF: 'mer-KE', 'ISO-639': 'mer' },
minangkabau: { IETF: 'min-ID', 'ISO-639': 'min' }, mijikenda: { IETF: 'nyf-KE', 'ISO-639': 'nyf' },
mizo: { IETF: 'lus-IN', 'ISO-639': 'lus' }, minangkabau: { IETF: 'min-ID', 'ISO-639': 'min' },
mongolian: { IETF: 'mn-MN', 'ISO-639': 'mn' }, mizo: { IETF: 'lus-IN', 'ISO-639': 'lus' },
montenegrin: { IETF: 'sr-ME', 'ISO-639': 'sr' }, mongolian: { IETF: 'mn-MN', 'ISO-639': 'mn' },
morisyen: { IETF: 'mfe-MU', 'ISO-639': 'mfe' }, montenegrin: { IETF: 'sr-ME', 'ISO-639': 'sr' },
'moroccan arabic': { IETF: 'ar-MA', 'ISO-639': 'ar' }, morisyen: { IETF: 'mfe-MU', 'ISO-639': 'mfe' },
mossi: { IETF: 'mos-BF', 'ISO-639': 'mos' }, 'moroccan arabic': { IETF: 'ar-MA', 'ISO-639': 'ar' },
ndau: { IETF: 'ndc-MZ', 'ISO-639': 'ndc' }, mossi: { IETF: 'mos-BF', 'ISO-639': 'mos' },
ndebele: { IETF: 'nr-ZA', 'ISO-639': 'nr' }, ndau: { IETF: 'ndc-MZ', 'ISO-639': 'ndc' },
nepali: { IETF: 'ne-NP', 'ISO-639': 'ne' }, ndebele: { IETF: 'nr-ZA', 'ISO-639': 'nr' },
'nigerian fulfulde': { IETF: 'fuv-NG', 'ISO-639': 'fuv' }, nepali: { IETF: 'ne-NP', 'ISO-639': 'ne' },
niuean: { IETF: 'niu-NU', 'ISO-639': 'niu' }, 'nigerian fulfulde': { IETF: 'fuv-NG', 'ISO-639': 'fuv' },
'north azerbaijani': { IETF: 'azj-AZ', 'ISO-639': 'azj' }, niuean: { IETF: 'niu-NU', 'ISO-639': 'niu' },
sesotho: { IETF: 'nso-ZA', 'ISO-639': 'nso' }, 'north azerbaijani': { IETF: 'azj-AZ', 'ISO-639': 'azj' },
'northern uzbek': { IETF: 'uzn-UZ', 'ISO-639': 'uzn' }, sesotho: { IETF: 'nso-ZA', 'ISO-639': 'nso' },
'norwegian bokm<6B>l': { IETF: 'nb-NO', 'ISO-639': 'nb' }, 'northern uzbek': { IETF: 'uzn-UZ', 'ISO-639': 'uzn' },
'norwegian nynorsk': { IETF: 'nn-NO', 'ISO-639': 'nn' }, 'norwegian bokm<6B>l': { IETF: 'nb-NO', 'ISO-639': 'nb' },
nuer: { IETF: 'nus-SS', 'ISO-639': 'nus' }, 'norwegian nynorsk': { IETF: 'nn-NO', 'ISO-639': 'nn' },
nyanja: { IETF: 'ny-MW', 'ISO-639': 'ny' }, nuer: { IETF: 'nus-SS', 'ISO-639': 'nus' },
occitan: { IETF: 'oc-FR', 'ISO-639': 'oc' }, nyanja: { IETF: 'ny-MW', 'ISO-639': 'ny' },
'occitan aran': { IETF: 'oc-ES', 'ISO-639': 'oc' }, occitan: { IETF: 'oc-FR', 'ISO-639': 'oc' },
odia: { IETF: 'or-IN', 'ISO-639': 'or' }, 'occitan aran': { IETF: 'oc-ES', 'ISO-639': 'oc' },
oriya: { IETF: 'ory-IN', 'ISO-639': 'ory' }, odia: { IETF: 'or-IN', 'ISO-639': 'or' },
urdu: { IETF: 'ur-PK', 'ISO-639': 'ur' }, oriya: { IETF: 'ory-IN', 'ISO-639': 'ory' },
palauan: { IETF: 'pau-PW', 'ISO-639': 'pau' }, urdu: { IETF: 'ur-PK', 'ISO-639': 'ur' },
pali: { IETF: 'pi-IN', 'ISO-639': 'pi' }, palauan: { IETF: 'pau-PW', 'ISO-639': 'pau' },
pangasinan: { IETF: 'pag-PH', 'ISO-639': 'pag' }, pali: { IETF: 'pi-IN', 'ISO-639': 'pi' },
papiamentu: { IETF: 'pap-CW', 'ISO-639': 'pap' }, pangasinan: { IETF: 'pag-PH', 'ISO-639': 'pag' },
pashto: { IETF: 'ps-PK', 'ISO-639': 'ps' }, papiamentu: { IETF: 'pap-CW', 'ISO-639': 'pap' },
persian: { IETF: 'fa-IR', 'ISO-639': 'fa' }, pashto: { IETF: 'ps-PK', 'ISO-639': 'ps' },
pijin: { IETF: 'pis-SB', 'ISO-639': 'pis' }, persian: { IETF: 'fa-IR', 'ISO-639': 'fa' },
'plateau malagasy': { IETF: 'plt-MG', 'ISO-639': 'plt' }, pijin: { IETF: 'pis-SB', 'ISO-639': 'pis' },
polish: { IETF: 'pl-PL', 'ISO-639': 'pl' }, 'plateau malagasy': { IETF: 'plt-MG', 'ISO-639': 'plt' },
portuguese: { IETF: 'pt-PT', 'ISO-639': 'pt' }, polish: { IETF: 'pl-PL', 'ISO-639': 'pl' },
'portuguese brazil': { IETF: 'pt-BR', 'ISO-639': 'pt' }, portuguese: { IETF: 'pt-PT', 'ISO-639': 'pt' },
potawatomi: { IETF: 'pot-US', 'ISO-639': 'pot' }, 'portuguese brazil': { IETF: 'pt-BR', 'ISO-639': 'pt' },
punjabi: { IETF: 'pa-IN', 'ISO-639': 'pa' }, potawatomi: { IETF: 'pot-US', 'ISO-639': 'pot' },
'punjabi (pakistan)': { IETF: 'pnb-PK', 'ISO-639': 'pnb' }, punjabi: { IETF: 'pa-IN', 'ISO-639': 'pa' },
quechua: { IETF: 'qu-PE', 'ISO-639': 'qu' }, 'punjabi (pakistan)': { IETF: 'pnb-PK', 'ISO-639': 'pnb' },
rohingya: { IETF: 'rhg-MM', 'ISO-639': 'rhg' }, quechua: { IETF: 'qu-PE', 'ISO-639': 'qu' },
rohingyalish: { IETF: 'rhl-MM', 'ISO-639': 'rhl' }, rohingya: { IETF: 'rhg-MM', 'ISO-639': 'rhg' },
romanian: { IETF: 'ro-RO', 'ISO-639': 'ro' }, rohingyalish: { IETF: 'rhl-MM', 'ISO-639': 'rhl' },
romansh: { IETF: 'roh-CH', 'ISO-639': 'roh' }, romanian: { IETF: 'ro-RO', 'ISO-639': 'ro' },
rundi: { IETF: 'run-BI', 'ISO-639': 'run' }, romansh: { IETF: 'roh-CH', 'ISO-639': 'roh' },
russian: { IETF: 'ru-RU', 'ISO-639': 'ru' }, rundi: { IETF: 'run-BI', 'ISO-639': 'run' },
'saint lucian creole french': { IETF: 'acf-LC', 'ISO-639': 'acf' }, russian: { IETF: 'ru-RU', 'ISO-639': 'ru' },
samoan: { IETF: 'sm-WS', 'ISO-639': 'sm' }, 'saint lucian creole french': { IETF: 'acf-LC', 'ISO-639': 'acf' },
sango: { IETF: 'sg-CF', 'ISO-639': 'sg' }, samoan: { IETF: 'sm-WS', 'ISO-639': 'sm' },
sanskrit: { IETF: 'sa-IN', 'ISO-639': 'sa' }, sango: { IETF: 'sg-CF', 'ISO-639': 'sg' },
santali: { IETF: 'sat-IN', 'ISO-639': 'sat' }, sanskrit: { IETF: 'sa-IN', 'ISO-639': 'sa' },
sardinian: { IETF: 'sc-IT', 'ISO-639': 'sc' }, santali: { IETF: 'sat-IN', 'ISO-639': 'sat' },
'scots gaelic': { IETF: 'gd-GB', 'ISO-639': 'gd' }, sardinian: { IETF: 'sc-IT', 'ISO-639': 'sc' },
sena: { IETF: 'seh-ZW', 'ISO-639': 'seh' }, 'scots gaelic': { IETF: 'gd-GB', 'ISO-639': 'gd' },
'serbian cyrillic': { IETF: 'sr-Cyrl-RS', 'ISO-639': 'sr' }, sena: { IETF: 'seh-ZW', 'ISO-639': 'seh' },
'serbian latin': { IETF: 'sr-Latn-RS', 'ISO-639': 'sr' }, 'serbian cyrillic': { IETF: 'sr-Cyrl-RS', 'ISO-639': 'sr' },
'seselwa creole french': { IETF: 'crs-SC', 'ISO-639': 'crs' }, 'serbian latin': { IETF: 'sr-Latn-RS', 'ISO-639': 'sr' },
'setswana (south africa)': { IETF: 'tn-ZA', 'ISO-639': 'tn' }, 'seselwa creole french': { IETF: 'crs-SC', 'ISO-639': 'crs' },
shan: { IETF: 'shn-MM', 'ISO-639': 'shn' }, 'setswana (south africa)': { IETF: 'tn-ZA', 'ISO-639': 'tn' },
shona: { IETF: 'sn-ZW', 'ISO-639': 'sn' }, shan: { IETF: 'shn-MM', 'ISO-639': 'shn' },
sicilian: { IETF: 'scn-IT', 'ISO-639': 'scn' }, shona: { IETF: 'sn-ZW', 'ISO-639': 'sn' },
silesian: { IETF: 'szl-PL', 'ISO-639': 'szl' }, sicilian: { IETF: 'scn-IT', 'ISO-639': 'scn' },
'sindhi snd': { IETF: 'snd-PK', 'ISO-639': 'snd' }, silesian: { IETF: 'szl-PL', 'ISO-639': 'szl' },
'sindhi sd': { IETF: 'sd-PK', 'ISO-639': 'sd' }, 'sindhi snd': { IETF: 'snd-PK', 'ISO-639': 'snd' },
sinhala: { IETF: 'si-LK', 'ISO-639': 'si' }, 'sindhi sd': { IETF: 'sd-PK', 'ISO-639': 'sd' },
slovak: { IETF: 'sk-SK', 'ISO-639': 'sk' }, sinhala: { IETF: 'si-LK', 'ISO-639': 'si' },
slovenian: { IETF: 'sl-SI', 'ISO-639': 'sl' }, slovak: { IETF: 'sk-SK', 'ISO-639': 'sk' },
somali: { IETF: 'so-SO', 'ISO-639': 'so' }, slovenian: { IETF: 'sl-SI', 'ISO-639': 'sl' },
'sotho southern': { IETF: 'st-LS', 'ISO-639': 'st' }, somali: { IETF: 'so-SO', 'ISO-639': 'so' },
'south azerbaijani': { IETF: 'azb-AZ', 'ISO-639': 'azb' }, 'sotho southern': { IETF: 'st-LS', 'ISO-639': 'st' },
'southern pashto': { IETF: 'pbt-PK', 'ISO-639': 'pbt' }, 'south azerbaijani': { IETF: 'azb-AZ', 'ISO-639': 'azb' },
'southwestern dinka': { IETF: 'dik-SS', 'ISO-639': 'dik' }, 'southern pashto': { IETF: 'pbt-PK', 'ISO-639': 'pbt' },
spanish: { IETF: 'es-ES', 'ISO-639': 'es' }, 'southwestern dinka': { IETF: 'dik-SS', 'ISO-639': 'dik' },
'spanish argentina': { IETF: 'es-AR', 'ISO-639': 'es' }, spanish: { IETF: 'es-ES', 'ISO-639': 'es' },
'spanish colombia': { IETF: 'es-CO', 'ISO-639': 'es' }, 'spanish argentina': { IETF: 'es-AR', 'ISO-639': 'es' },
'spanish latin america': { IETF: 'es-419', 'ISO-639': 'es' }, 'spanish colombia': { IETF: 'es-CO', 'ISO-639': 'es' },
'spanish mexico': { IETF: 'es-MX', 'ISO-639': 'es' }, 'spanish latin america': { IETF: 'es-419', 'ISO-639': 'es' },
'spanish united states': { IETF: 'es-US', 'ISO-639': 'es' }, 'spanish mexico': { IETF: 'es-MX', 'ISO-639': 'es' },
'sranan tongo': { IETF: 'srn-SR', 'ISO-639': 'srn' }, 'spanish united states': { IETF: 'es-US', 'ISO-639': 'es' },
'standard latvian': { IETF: 'lvs-LV', 'ISO-639': 'lvs' }, 'sranan tongo': { IETF: 'srn-SR', 'ISO-639': 'srn' },
'standard malay': { IETF: 'zsm-MY', 'ISO-639': 'zsm' }, 'standard latvian': { IETF: 'lvs-LV', 'ISO-639': 'lvs' },
sundanese: { IETF: 'su-ID', 'ISO-639': 'su' }, 'standard malay': { IETF: 'zsm-MY', 'ISO-639': 'zsm' },
swahili: { IETF: 'sw-KE', 'ISO-639': 'sw' }, sundanese: { IETF: 'su-ID', 'ISO-639': 'su' },
swati: { IETF: 'ss-SZ', 'ISO-639': 'ss' }, swahili: { IETF: 'sw-KE', 'ISO-639': 'sw' },
swedish: { IETF: 'sv-SE', 'ISO-639': 'sv' }, swati: { IETF: 'ss-SZ', 'ISO-639': 'ss' },
'swiss german': { IETF: 'de-CH', 'ISO-639': 'de' }, swedish: { IETF: 'sv-SE', 'ISO-639': 'sv' },
'syriac (aramaic)': { IETF: 'syc-TR', 'ISO-639': 'syc' }, 'swiss german': { IETF: 'de-CH', 'ISO-639': 'de' },
tagalog: { IETF: 'tl-PH', 'ISO-639': 'tl' }, 'syriac (aramaic)': { IETF: 'syc-TR', 'ISO-639': 'syc' },
tahitian: { IETF: 'ty-PF', 'ISO-639': 'ty' }, tagalog: { IETF: 'tl-PH', 'ISO-639': 'tl' },
tajik: { IETF: 'tg-TJ', 'ISO-639': 'tg' }, tahitian: { IETF: 'ty-PF', 'ISO-639': 'ty' },
'tamashek (tuareg)': { IETF: 'tmh-DZ', 'ISO-639': 'tmh' }, tajik: { IETF: 'tg-TJ', 'ISO-639': 'tg' },
tamasheq: { IETF: 'taq-ML', 'ISO-639': 'taq' }, 'tamashek (tuareg)': { IETF: 'tmh-DZ', 'ISO-639': 'tmh' },
'tamil india': { IETF: 'ta-IN', 'ISO-639': 'ta' }, tamasheq: { IETF: 'taq-ML', 'ISO-639': 'taq' },
'tamil sri lanka': { IETF: 'ta-LK', 'ISO-639': 'ta' }, 'tamil india': { IETF: 'ta-IN', 'ISO-639': 'ta' },
taroko: { IETF: 'trv-TW', 'ISO-639': 'trv' }, 'tamil sri lanka': { IETF: 'ta-LK', 'ISO-639': 'ta' },
tatar: { IETF: 'tt-RU', 'ISO-639': 'tt' }, taroko: { IETF: 'trv-TW', 'ISO-639': 'trv' },
telugu: { IETF: 'te-IN', 'ISO-639': 'te' }, tatar: { IETF: 'tt-RU', 'ISO-639': 'tt' },
tetum: { IETF: 'tet-TL', 'ISO-639': 'tet' }, telugu: { IETF: 'te-IN', 'ISO-639': 'te' },
thai: { IETF: 'th-TH', 'ISO-639': 'th' }, tetum: { IETF: 'tet-TL', 'ISO-639': 'tet' },
tibetan: { IETF: 'bo-CN', 'ISO-639': 'bo' }, thai: { IETF: 'th-TH', 'ISO-639': 'th' },
tigrinya: { IETF: 'ti-ET', 'ISO-639': 'ti' }, tibetan: { IETF: 'bo-CN', 'ISO-639': 'bo' },
'tok pisin': { IETF: 'tpi-PG', 'ISO-639': 'tpi' }, tigrinya: { IETF: 'ti-ET', 'ISO-639': 'ti' },
tokelauan: { IETF: 'tkl-TK', 'ISO-639': 'tkl' }, 'tok pisin': { IETF: 'tpi-PG', 'ISO-639': 'tpi' },
tongan: { IETF: 'to-TO', 'ISO-639': 'to' }, tokelauan: { IETF: 'tkl-TK', 'ISO-639': 'tkl' },
'tosk albanian': { IETF: 'als-AL', 'ISO-639': 'als' }, tongan: { IETF: 'to-TO', 'ISO-639': 'to' },
tsonga: { IETF: 'ts-ZA', 'ISO-639': 'ts' }, 'tosk albanian': { IETF: 'als-AL', 'ISO-639': 'als' },
tswa: { IETF: 'tsc-MZ', 'ISO-639': 'tsc' }, tsonga: { IETF: 'ts-ZA', 'ISO-639': 'ts' },
tswana: { IETF: 'tn-BW', 'ISO-639': 'tn' }, tswa: { IETF: 'tsc-MZ', 'ISO-639': 'tsc' },
tumbuka: { IETF: 'tum-MW', 'ISO-639': 'tum' }, tswana: { IETF: 'tn-BW', 'ISO-639': 'tn' },
turkish: { IETF: 'tr-TR', 'ISO-639': 'tr' }, tumbuka: { IETF: 'tum-MW', 'ISO-639': 'tum' },
turkmen: { IETF: 'tk-TM', 'ISO-639': 'tk' }, turkish: { IETF: 'tr-TR', 'ISO-639': 'tr' },
tuvaluan: { IETF: 'tvl-TV', 'ISO-639': 'tvl' }, turkmen: { IETF: 'tk-TM', 'ISO-639': 'tk' },
twi: { IETF: 'tw-GH', 'ISO-639': 'tw' }, tuvaluan: { IETF: 'tvl-TV', 'ISO-639': 'tvl' },
udmurt: { IETF: 'udm-RU', 'ISO-639': 'udm' }, twi: { IETF: 'tw-GH', 'ISO-639': 'tw' },
ukrainian: { IETF: 'uk-UA', 'ISO-639': 'uk' }, udmurt: { IETF: 'udm-RU', 'ISO-639': 'udm' },
uma: { IETF: 'ppk-ID', 'ISO-639': 'ppk' }, ukrainian: { IETF: 'uk-UA', 'ISO-639': 'uk' },
umbundu: { IETF: 'umb-AO', 'ISO-639': 'umb' }, uma: { IETF: 'ppk-ID', 'ISO-639': 'ppk' },
'uyghur uig': { IETF: 'uig-CN', 'ISO-639': 'uig' }, umbundu: { IETF: 'umb-AO', 'ISO-639': 'umb' },
'uyghur ug': { IETF: 'ug-CN', 'ISO-639': 'ug' }, 'uyghur uig': { IETF: 'uig-CN', 'ISO-639': 'uig' },
uzbek: { IETF: 'uz-UZ', 'ISO-639': 'uz' }, 'uyghur ug': { IETF: 'ug-CN', 'ISO-639': 'ug' },
venetian: { IETF: 'vec-IT', 'ISO-639': 'vec' }, uzbek: { IETF: 'uz-UZ', 'ISO-639': 'uz' },
vietnamese: { IETF: 'vi-VN', 'ISO-639': 'vi' }, venetian: { IETF: 'vec-IT', 'ISO-639': 'vec' },
'vincentian creole english': { IETF: 'svc-VC', 'ISO-639': 'svc' }, vietnamese: { IETF: 'vi-VN', 'ISO-639': 'vi' },
'virgin islands creole english': { IETF: 'vic-US', 'ISO-639': 'vic' }, 'vincentian creole english': { IETF: 'svc-VC', 'ISO-639': 'svc' },
wallisian: { IETF: 'wls-WF', 'ISO-639': 'wls' }, 'virgin islands creole english': { IETF: 'vic-US', 'ISO-639': 'vic' },
'waray (philippines)': { IETF: 'war-PH', 'ISO-639': 'war' }, wallisian: { IETF: 'wls-WF', 'ISO-639': 'wls' },
welsh: { IETF: 'cy-GB', 'ISO-639': 'cy' }, 'waray (philippines)': { IETF: 'war-PH', 'ISO-639': 'war' },
'west central oromo': { IETF: 'gaz-ET', 'ISO-639': 'gaz' }, welsh: { IETF: 'cy-GB', 'ISO-639': 'cy' },
'western persian': { IETF: 'pes-IR', 'ISO-639': 'pes' }, 'west central oromo': { IETF: 'gaz-ET', 'ISO-639': 'gaz' },
wolof: { IETF: 'wo-SN', 'ISO-639': 'wo' }, 'western persian': { IETF: 'pes-IR', 'ISO-639': 'pes' },
xhosa: { IETF: 'xh-ZA', 'ISO-639': 'xh' }, wolof: { IETF: 'wo-SN', 'ISO-639': 'wo' },
yiddish: { IETF: 'yi-YD', 'ISO-639': 'yi' }, xhosa: { IETF: 'xh-ZA', 'ISO-639': 'xh' },
yoruba: { IETF: 'yo-NG', 'ISO-639': 'yo' }, yiddish: { IETF: 'yi-YD', 'ISO-639': 'yi' },
zulu: { IETF: 'zu-ZA', 'ISO-639': 'zu' }, yoruba: { IETF: 'yo-NG', 'ISO-639': 'yo' },
zulu: { IETF: 'zu-ZA', 'ISO-639': 'zu' }
}; };
module.exports = { languages }; module.exports = { languages };

View file

@ -6,73 +6,75 @@ const path = require('path');
const consoleloggerLevel = process.env.WINSTON_LOGGER_LEVEL || 'info'; const consoleloggerLevel = process.env.WINSTON_LOGGER_LEVEL || 'info';
const consoleFormat = format.combine( const consoleFormat = format.combine(
format.colorize(), format.colorize(),
format.timestamp(), format.timestamp(),
format.align(), format.align(),
format.printf((info) => `${info.timestamp} - ${info.level}: ${info.message} ${JSON.stringify(info.metadata)}`), format.printf(info => `${info.timestamp} - ${info.level}: ${info.message} ${JSON.stringify(info.metadata)}`)
); );
const fileFormat = format.combine( const fileFormat = format.combine(
format.timestamp(), format.timestamp(),
format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }), format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }),
format.json(), format.json()
); );
const logger = createLogger({ const logger = createLogger({
level: 'info', level: 'info',
format: fileFormat, format: fileFormat,
transports: [ transports: [
new transports.File({ new transports.File({
filename: path.join(__dirname, '../logs/error.log'), filename: path.join(__dirname, '../logs/error.log'),
level: 'error', level: 'error'
}), }),
new transports.File({ new transports.File({
filename: path.join(__dirname, '../logs/activity.log'), filename: path.join(__dirname, '../logs/activity.log'),
maxsize: 5242880, maxsize: 5242880,
maxFiles: 5, maxFiles: 5
}), })
], ]
}); });
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
logger.add( logger.add(
new transports.Console({ new transports.Console({
level: consoleloggerLevel, level: consoleloggerLevel,
format: consoleFormat, format: consoleFormat
}), })
); );
} }
fetch(path.join(__dirname, '../logs/activity.log')) fetch(path.join(__dirname, '../logs/activity.log'))
.then((response) => response.text()) .then(response => response.text())
.then((logData) => { .then(logData => {
const logLines = logData.trim().split('\n'); const logLines = logData.trim().split('\n');
const tableBody = document.getElementById('logContent'); const tableBody = document.getElementById('logContent');
logLines.forEach((logLine) => { logLines.forEach(logLine => {
const logObject = JSON.parse(logLine); const logObject = JSON.parse(logLine);
const row = document.createElement('tr'); const row = document.createElement('tr');
const levelCell = document.createElement('td'); const levelCell = document.createElement('td');
levelCell.textContent = logObject.level; levelCell.textContent = logObject.level;
levelCell.classList.add(logObject.level); // Add class for styling levelCell.classList.add(logObject.level); // Add class for styling
row.appendChild(levelCell); row.appendChild(levelCell);
const messageCell = document.createElement('td'); const messageCell = document.createElement('td');
messageCell.textContent = logObject.message; messageCell.textContent = logObject.message;
row.appendChild(messageCell); row.appendChild(messageCell);
const metadataCell = document.createElement('td'); const metadataCell = document.createElement('td');
metadataCell.textContent = JSON.stringify(logObject.metadata, null, 2); metadataCell.textContent = JSON.stringify(logObject.metadata, null, 2);
row.appendChild(metadataCell); row.appendChild(metadataCell);
const timestampCell = document.createElement('td'); const timestampCell = document.createElement('td');
timestampCell.textContent = logObject.timestamp; timestampCell.textContent = logObject.timestamp;
row.appendChild(timestampCell); row.appendChild(timestampCell);
tableBody.appendChild(row); tableBody.appendChild(row);
}); });
}) })
.catch((error) => {}); .catch(error => {
console.error(error);
});
module.exports = logger; module.exports = logger;

View file

@ -1,49 +1,51 @@
let micSelect = document.querySelector('#microphone'); /* global settings, */
const micSelect = document.querySelector('#microphone');
let selectedMic; let selectedMic;
function getAvailableMediaDevices(type) { function getAvailableMediaDevices(type) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
navigator.mediaDevices navigator.mediaDevices
.enumerateDevices() .enumerateDevices()
.then((devices) => { .then(devices => {
const microphones = devices.filter((device) => device.kind === type); const microphones = devices.filter(device => device.kind === type);
resolve(microphones); resolve(microphones);
}) })
.catch((error) => { .catch(error => {
reject(error); reject(error);
}); });
}); });
} }
// Microphones // Microphones
getAvailableMediaDevices('audioinput') getAvailableMediaDevices('audioinput')
.then((microphones) => { .then(microphones => {
let i = 0; let i = 0;
let tempname = ''; let tempname = '';
for (let mic of microphones) { for (const mic of microphones) {
if (mic.deviceId === 'default') { if (mic.deviceId === 'default') {
tempname = mic.label.slice(10); // remove "default -" from the label to get the default device name. tempname = mic.label.slice(10); // remove "default -" from the label to get the default device name.
} }
if (mic.deviceId === 'communications' || mic.label === tempname) { if (mic.deviceId === 'communications' || mic.label === tempname) {
continue; continue;
} }
const option = document.createElement('option'); const option = document.createElement('option');
// Set the options value and text. // Set the options value and text.
option.value = i; option.value = i;
option.innerHTML = `${mic.label}`; option.innerHTML = `${mic.label}`;
// Add the option to the voice selector. // Add the option to the voice selector.
micSelect.appendChild(option); micSelect.appendChild(option);
if (i === microphones.length - 1) { if (i === microphones.length - 1) {
document.getElementById('microphone').value = settings.STT.SELECTED_MICROPHONE; document.getElementById('microphone').value = settings.STT.SELECTED_MICROPHONE;
} }
i++; i++;
} }
}) })
.catch((error) => { .catch(error => {
console.error('Error retrieving microphones:', error); console.error('Error retrieving microphones:', error);
}); });

View file

@ -1,26 +1,26 @@
const twitchTemplate = ` const twitchTemplate = `
<img class="user-img" src="" /> <img class="user-img" src="" />
<img class="status-circle sender" src="./images/twitch-icon.png" /> <img class="status-circle sender" src="./images/twitch-icon.png" />
<span class="post-time sender"></span> <span class="post-time sender"></span>
<span class="username sender"></span> <span class="username sender"></span>
<div class="msg-box sender"></div> <div class="msg-box sender"></div>
`.trim(); `.trim();
const userTemplate = ` const userTemplate = `
<img class="user-img" src="https://gravatar.com/avatar/56234674574535734573000000000001?d=retro" /> <img class="user-img" src="https://gravatar.com/avatar/56234674574535734573000000000001?d=retro" />
<img class="status-circle user" src="./images/twitch-icon.png" /> <img class="status-circle user" src="./images/twitch-icon.png" />
<span class="post-time user"></span> <span class="post-time user"></span>
<span class="username user">You</span> <span class="username user">You</span>
<div class="msg-box user"></div> <div class="msg-box user"></div>
`.trim(); `.trim();
const messageTemplate = ` const messageTemplate = `
<article class="msg-container user" id="msg-0"> <article class="msg-container user" id="msg-0">
<img class="user-img" src="https://gravatar.com/avatar/56234674574535734573000000000001?d=retro" /> <img class="user-img" src="https://gravatar.com/avatar/56234674574535734573000000000001?d=retro" />
<img class="status-circle user" src="./images/twitch-icon.png" /> <img class="status-circle user" src="./images/twitch-icon.png" />
<span class="post-time user"> 12:00 PM</span> <span class="post-time user"> 12:00 PM</span>
<span class="username user">You</span> <span class="username user">You</span>
<div class="msg-box user">Hello there</div> <div class="msg-box user">Hello there</div>
</article> </article>
`.trim(); `.trim();

View file

@ -3,7 +3,7 @@ const ini = require('ini');
const path = require('path'); // get directory path const path = require('path'); // get directory path
const axios = require('axios'); const axios = require('axios');
const { ipcRenderer, shell } = require('electron'); // necessary electron libraries to send data to the app const { webFrame, ipcRenderer, shell } = require('electron'); // necessary electron libraries to send data to the app
const io = require('socket.io-client'); const io = require('socket.io-client');
const util = require('util'); const util = require('util');
@ -17,8 +17,8 @@ const { Socket } = require('socket.io-client');
const main = ipcRenderer.sendSync('environment'); const main = ipcRenderer.sendSync('environment');
const resourcesPath = main.resourcesPath; const resourcesPath = main.resourcesPath;
let settingsPath = main.settingsPath.toString(); const settingsPath = main.settingsPath.toString();
let pythonPath = main.pythonPath.toString(); const pythonPath = main.pythonPath.toString();
const settings = main.settings; const settings = main.settings;
// TODO: remove gooogle voices txt and use api instead // TODO: remove gooogle voices txt and use api instead
@ -35,6 +35,8 @@ const devicesDropdown = document.querySelector('#devicesDropdown');
const notificationSound = document.querySelector('#notification'); // obtain the html reference of the sound comboBox const notificationSound = document.querySelector('#notification'); // obtain the html reference of the sound comboBox
const sttModel = document.querySelector('#sttModel'); // obtain the html reference of the sound comboBox const sttModel = document.querySelector('#sttModel'); // obtain the html reference of the sound comboBox
const ttsAudioDevices = document.querySelector('#ttsAudioDevice'); // obtain the html reference of the installedTTS comboBox const ttsAudioDevices = document.querySelector('#ttsAudioDevice'); // obtain the html reference of the installedTTS comboBox
const notificationSoundAudioDevices = document.querySelector('#notificationSoundAudioDevice'); // obtain the html reference of the installedTTS comboBox
const emojiPicker = document.body.querySelector('emoji-picker');
// laod local javascript files // laod local javascript files
const chat = require(path.join(__dirname, './js/chat')); const chat = require(path.join(__dirname, './js/chat'));
@ -47,18 +49,18 @@ const config = require(path.join(__dirname, './js/settings'));
const mediaDevices = require(path.join(__dirname, './js/mediaDevices')); const mediaDevices = require(path.join(__dirname, './js/mediaDevices'));
let notificationSounds = path.join(__dirname, './sounds/notifications'); const notificationSounds = path.join(__dirname, './sounds/notifications');
let sttModels = path.join(__dirname, '../speech_to_text_models'); const sttModels = path.join(__dirname, '../speech_to_text_models');
function reset() { function reset() {
ipcRenderer.send('restart'); ipcRenderer.send('restart');
} }
let server = require(path.join(__dirname, './js/server')); const server = require(path.join(__dirname, './js/server'));
const backend = require(path.join(__dirname, './js/backend')); const backend = require(path.join(__dirname, './js/backend'));
let socket = io(`http://localhost:${settings.GENERAL.PORT}`); // Connect to your Socket.IO server const socket = io(`http://localhost:${settings.GENERAL.PORT}`); // Connect to your Socket.IO server
let twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './js/twitch')) : ''; const twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './js/twitch')) : '';
const Polly = settings.AMAZON.USE_AMAZON ? require(path.join(__dirname, './js/amazon')) : ''; const Polly = settings.AMAZON.USE_AMAZON ? require(path.join(__dirname, './js/amazon')) : '';
const google = settings.GOOGLE.USE_GOOGLE ? require(path.join(__dirname, './js/google')) : ''; const google = settings.GOOGLE.USE_GOOGLE ? require(path.join(__dirname, './js/google')) : '';
@ -66,6 +68,9 @@ const theme = require(path.join(__dirname, './js/theme'));
const auth = require(path.join(__dirname, './js/auth')); const auth = require(path.join(__dirname, './js/auth'));
let ttsRequestCount = 0; let ttsRequestCount = 0;
ttsRequestCount = 0;
let customEmojis = [];
customEmojis = [];
// initialize values // initialize values
config.getGeneralSettings(); config.getGeneralSettings();
@ -77,83 +82,93 @@ const StartDateAndTime = Date.now();
const speakButton = document.querySelector('#speakBtn'); const speakButton = document.querySelector('#speakBtn');
const amazonCredentials = { const amazonCredentials = {
accessKeyId: settings.AMAZON.ACCESS_KEY, accessKeyId: settings.AMAZON.ACCESS_KEY,
secretAccessKey: settings.AMAZON.ACCESS_SECRET, secretAccessKey: settings.AMAZON.ACCESS_SECRET
}; };
// Check for installed sounds // Check for installed sounds
fs.readdir(notificationSounds, (err, files) => { fs.readdir(notificationSounds, (err, files) => {
files.forEach((file, i) => { if (err) {
// Create a new option element. console.error(err);
const option = document.createElement('option'); }
// Set the options value and text. files.forEach((file, i) => {
option.value = i; // Create a new option element.
option.innerHTML = file; const option = document.createElement('option');
// Add the option to the sound selector. // Set the options value and text.
notificationSound.appendChild(option); option.value = i;
}); option.innerHTML = file;
// set the saved notification sound // Add the option to the sound selector.
notificationSound.selectedIndex = settings.AUDIO.NOTIFICATION_SOUND; notificationSound.appendChild(option);
});
// set the saved notification sound
notificationSound.selectedIndex = settings.AUDIO.NOTIFICATION_SOUND;
}); });
// Check for installed stt models // Check for installed stt models
fs.readdir(sttModels, (err, files) => { fs.readdir(sttModels, (err, files) => {
for (let file of files) { if (err) {
if (file.includes('.txt')) { console.error(err);
continue; }
}
// Create a new option element.
const option = document.createElement('option');
// Set the options value and text. for (const file of files) {
option.value = file; if (file.includes('.txt')) {
option.innerHTML = file; continue;
// Add the option to the sound selector.
sttModel.appendChild(option);
} }
// Create a new option element.
const option = document.createElement('option');
// set the saved notification sound // Set the options value and text.
sttModel.value = settings.STT.LANGUAGE; option.value = file;
option.innerHTML = file;
// Add the option to the sound selector.
sttModel.appendChild(option);
}
// set the saved notification sound
sttModel.value = settings.STT.LANGUAGE;
}); });
async function getAudioDevices() { async function getAudioDevices() {
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) { if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
return; return;
} }
const devices = await navigator.mediaDevices.enumerateDevices(); const devices = await navigator.mediaDevices.enumerateDevices();
const audioOutputDevices = devices.filter((device) => device.kind === 'audiooutput'); const audioOutputDevices = devices.filter(device => device.kind === 'audiooutput');
audioOutputDevices.forEach((device) => { audioOutputDevices.forEach(device => {
const option = document.createElement('option'); const option = document.createElement('option');
option.text = device.label || `Output ${device.deviceId}`; option.text = device.label || `Output ${device.deviceId}`;
option.value = device.deviceId; option.value = device.deviceId;
ttsAudioDevices.appendChild(option); ttsAudioDevices.appendChild(option);
}); notificationSoundAudioDevices.appendChild(option);
});
ttsAudioDevices.selectedIndex = settings.AUDIO.SELECTED_TTS_AUDIO_DEVICE; ttsAudioDevices.selectedIndex = settings.AUDIO.SELECTED_TTS_AUDIO_DEVICE;
notificationSoundAudioDevices.selectedIndex = settings.AUDIO.SELECTED_NOTIFICATION_AUDIO_DEVICE;
} }
getAudioDevices(); getAudioDevices();
function setLanguagesinSelect(languageSelector, setting) { function setLanguagesinSelect(languageSelector, setting) {
let languageSelect = document.querySelector(languageSelector); // obtain the html reference of the google voices comboBox const languageSelect = document.querySelector(languageSelector); // obtain the html reference of the google voices comboBox
for (const language in languageObject.languages) { for (const language in languageObject.languages) {
if (languageObject.languages.hasOwnProperty(language)) { if (Object.prototype.hasOwnProperty.call(languageObject.languages, language)) {
const iso639 = languageObject.languages[language]['ISO-639']; const iso639 = languageObject.languages[language]['ISO-639'];
const option = document.createElement('option'); const option = document.createElement('option');
option.value = iso639; option.value = iso639;
option.innerHTML = `${iso639} - ${language}`; option.innerHTML = `${iso639} - ${language}`;
languageSelect.appendChild(option); languageSelect.appendChild(option);
}
} }
}
languageSelect.selectedIndex = setting; languageSelect.selectedIndex = setting;
} }
setLanguagesinSelect('#language', settings.GENERAL.LANGUAGE); setLanguagesinSelect('#language', settings.GENERAL.LANGUAGE);
@ -161,95 +176,122 @@ setLanguagesinSelect('#defaultLanguage', settings.TTS.PRIMARY_TTS_LANGUAGE_INDEX
setLanguagesinSelect('#secondaryLanguage', settings.TTS.SECONDARY_TTS_LANGUAGE_INDEX); setLanguagesinSelect('#secondaryLanguage', settings.TTS.SECONDARY_TTS_LANGUAGE_INDEX);
function addVoiceService(name) { function addVoiceService(name) {
function addToselect(select) { function addToselect(select) {
let ttsService = document.querySelector(select); const ttsService = document.querySelector(select);
const option = document.createElement('option'); const option = document.createElement('option');
ttsService.appendChild(option); ttsService.appendChild(option);
option.value = name; option.value = name;
option.innerHTML = name; option.innerHTML = name;
} }
addToselect('#primaryTTSService'); addToselect('#primaryTTSService');
addToselect('#secondaryTTSService'); addToselect('#secondaryTTSService');
} }
// Small tooltip // Small tooltip
Array.from(document.body.querySelectorAll('[tip]')).forEach((el) => { Array.from(document.body.querySelectorAll('[tip]')).forEach(el => {
const tip = document.createElement('div'); const tip = document.createElement('div');
const body = document.querySelector('.container'); const body = document.querySelector('.container');
const element = el; const element = el;
tip.classList.add('tooltip'); tip.classList.add('tooltip');
tip.classList.add('tooltiptext'); tip.classList.add('tooltiptext');
tip.innerText = el.getAttribute('tip'); tip.innerText = el.getAttribute('tip');
tip.style.transform = `translate(${el.hasAttribute('tip-left') ? 'calc(-100% - 5px)' : '15px'}, ${ tip.style.transform = `translate(${el.hasAttribute('tip-left') ? 'calc(-100% - 5px)' : '15px'}, ${
el.hasAttribute('tip-top') ? '-100%' : '15px' el.hasAttribute('tip-top') ? '-100%' : '15px'
})`; })`;
body.appendChild(tip); body.appendChild(tip);
element.onmousemove = (e) => { element.onmousemove = e => {
tip.style.left = `${e.x}px`; tip.style.left = `${e.x}px`;
tip.style.top = `${e.y}px`; tip.style.top = `${e.y}px`;
tip.style.zIndex = 1; tip.style.zIndex = 1;
tip.style.visibility = 'visible'; tip.style.visibility = 'visible';
}; };
element.onmouseleave = (e) => { element.onmouseleave = e => {
tip.style.visibility = 'hidden'; tip.style.visibility = 'hidden';
}; };
}); });
function showChatMessage(article, isUser) { function showChatMessage(article) {
document.querySelector('#chatBox').appendChild(article); document.querySelector('#chatBox').appendChild(article);
let usernameHtml;
let msg;
let messages = Array.from(document.body.querySelectorAll('.msg-container'));
if (isUser) { const messages = Array.from(document.body.querySelectorAll('.msg-container'));
usernameHtml = article.querySelector('.username-user');
msg = article.querySelector('.msg-box-user');
} else {
usernameHtml = article.querySelector('.username');
msg = article.querySelector('.msg-box');
}
// var style = getComputedStyle(usernameHtml); const lastMessage = messages[messages.length - 1];
// var style2 = getComputedStyle(usernameHtml); lastMessage.scrollIntoView({ behavior: 'smooth' });
const lastMessage = messages[messages.length - 1];
lastMessage.scrollIntoView({ behavior: 'smooth' });
} }
function getPostTime() { function getPostTime() {
const date = new Date(); const date = new Date();
document.body.querySelectorAll('.container').innerHTML = date.getHours(); document.body.querySelectorAll('.container').innerHTML = date.getHours();
const hours = date.getHours(); const hours = date.getHours();
var ampm = hours >= 12 ? 'PM' : 'AM'; const ampm = hours >= 12 ? 'PM' : 'AM';
const minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); const minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes();
const time = `${hours}:${minutes} ${ampm}`; const time = `${hours}:${minutes} ${ampm}`;
return time; return time;
} }
function showPreviewChatMessage() { function showPreviewChatMessage() {
const message = messageTemplates.messageTemplate; const message = messageTemplates.messageTemplate;
document.querySelector('#mini-mid').innerHTML += message; document.querySelector('#mini-mid').innerHTML += message;
const messages = Array.from(document.body.querySelectorAll('#mini-mid')); const messages = Array.from(document.body.querySelectorAll('#mini-mid'));
const lastMessage = messages[messages.length - 1]; const lastMessage = messages[messages.length - 1];
lastMessage.scrollIntoView({ behavior: 'smooth' }); lastMessage.scrollIntoView({ behavior: 'smooth' });
} }
showPreviewChatMessage(); showPreviewChatMessage();
function hideText(button, field) { function hideText(button, field) {
document.body.querySelector(button).addEventListener('click', () => { document.body.querySelector(button).addEventListener('click', () => {
const passwordInput = document.querySelector(field); const passwordInput = document.querySelector(field);
if (passwordInput.type === 'password') { if (passwordInput.type === 'password') {
passwordInput.type = 'lol'; passwordInput.type = 'lol';
} else { } else {
passwordInput.type = 'password'; passwordInput.type = 'password';
} }
}); });
} }
hideText('.password-toggle-btn1', '#TWITCH_OAUTH_TOKEN'); hideText('.password-toggle-btn1', '#TWITCH_OAUTH_TOKEN');
hideText('.password-toggle-btn4', '#AMAZON_ACCESS_KEY'); hideText('.password-toggle-btn4', '#AMAZON_ACCESS_KEY');
hideText('.password-toggle-btn5', '#AMAZON_ACCESS_SECRET'); hideText('.password-toggle-btn5', '#AMAZON_ACCESS_SECRET');
hideText('.password-toggle-btn6', '#GOOGLE_API_KEY'); hideText('.password-toggle-btn6', '#GOOGLE_API_KEY');
function setZoomLevel(currentZoom, zoomIn) {
let newZoom = currentZoom.toFixed(2);
if (zoomIn === true && currentZoom < 4.95) {
newZoom = (currentZoom + 0.05).toFixed(2);
}
if (zoomIn === false && currentZoom > 0.25) {
newZoom = (currentZoom - 0.05).toFixed(2);
}
webFrame.setZoomFactor(parseFloat(newZoom));
settings.GENERAL.ZOOMLEVEL = newZoom;
fs.writeFileSync(settingsPath, ini.stringify(settings));
document.body.querySelector('#ZOOMLEVEL').value = (settings.GENERAL.ZOOMLEVEL * 100).toFixed(0);
}
// const customEmojix = [
// {
// name: 'sakuraestaKleefeliz',
// shortcodes: ['sakuraestaKleefeliz'],
// url: 'https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_0cb536ddb6e143ab87ffeccb160a4d45/default/dark/1.0',
// category: 'Sakura'
// }
// ];
// const customEmojiy = [
// {
// name: 'sakuraestaKleefeliz',
// shortcodes: ['sakuraestaKleefeliz'],
// url: 'https://static-cdn.jtvnw.net/emoticons/v2/emotesv2_0cb536ddb6e143ab87ffeccb160a4d45/default/dark/1.0',
// category: 'Sakurax'
// }
// ];
// emojiPicker.customEmoji = customEmojix;
// emojiPicker.customEmoji = customEmojiy;
// console.log(emojiPicker.database.getEmojiBySearchQuery('Kappa'));

View file

@ -1,18 +1,21 @@
function getBotResponse(input) { function getBotResponse(input) {
// rock paper scissors // rock paper scissors
if (input === 'rock') { if (input === 'rock') {
return 'paper'; return 'paper';
} if (input === 'paper') { }
return 'scissors'; if (input === 'paper') {
} if (input === 'scissors') { return 'scissors';
return 'rock'; }
} if (input === 'scissors') {
return 'rock';
}
// Simple responses // Simple responses
if (input === 'hello') { if (input === 'hello') {
return 'Hello there!'; return 'Hello there!';
} if (input === 'goodbye') { }
return 'Talk to you later!'; if (input === 'goodbye') {
} return 'Talk to you later!';
return 'Try asking something else!'; }
return 'Try asking something else!';
} }

View file

@ -1,3 +1,5 @@
/* global settings */
const express = require('express'); const express = require('express');
const app = express(); const app = express();
const path = require('path'); const path = require('path');
@ -5,42 +7,42 @@ const http = require('http');
const localServer = http.createServer(app); const localServer = http.createServer(app);
const io = require('socket.io')(localServer); const io = require('socket.io')(localServer);
let requestCount = 0; const requestCount = 0;
function startVtuberModule() { function startVtuberModule() {
if (!settings.MODULES.USE_VTUBER) { if (!settings.MODULES.USE_VTUBER) {
return; return;
} }
app.use('/vtuber', express.static(path.join(__dirname, '../modules/vtuber/'))); app.use('/vtuber', express.static(path.join(__dirname, '../modules/vtuber/')));
let vtuber = document.body.querySelector('#BrowsersourceVtuber'); const vtuber = document.body.querySelector('#BrowsersourceVtuber');
let vtuberframe = document.createElement('iframe'); const vtuberframe = document.createElement('iframe');
vtuberframe.class = 'frame'; vtuberframe.class = 'frame';
vtuberframe.src = `http://localhost:${settings.GENERAL.PORT}/vtuber`; vtuberframe.src = `http://localhost:${settings.GENERAL.PORT}/vtuber`;
vtuberframe.style.width = '100%'; vtuberframe.style.width = '100%';
vtuberframe.style.height = '100%'; vtuberframe.style.height = '100%';
vtuberframe.frameBorder = 0; vtuberframe.frameBorder = 0;
vtuber.appendChild(vtuberframe); vtuber.appendChild(vtuberframe);
} }
startVtuberModule(); startVtuberModule();
function startChatBubbleModule() { function startChatBubbleModule() {
if (!settings.MODULES.USE_CHATBUBBLE) { if (!settings.MODULES.USE_CHATBUBBLE) {
return; return;
} }
app.use('/chat', express.static(path.join(__dirname, '../modules/chat'))); app.use('/chat', express.static(path.join(__dirname, '../modules/chat')));
let chat = document.body.querySelector('#BrowsersourceChat'); const chat = document.body.querySelector('#BrowsersourceChat');
let chatframe = document.createElement('iframe'); const chatframe = document.createElement('iframe');
chatframe.class = 'frame'; chatframe.class = 'frame';
chatframe.src = `http://localhost:${settings.GENERAL.PORT}/chat`; chatframe.src = `http://localhost:${settings.GENERAL.PORT}/chat`;
chatframe.style.width = '100%'; chatframe.style.width = '100%';
chatframe.style.height = '100%'; chatframe.style.height = '100%';
chatframe.frameBorder = 0; chatframe.frameBorder = 0;
chat.appendChild(chatframe); chat.appendChild(chatframe);
} }
startChatBubbleModule(); startChatBubbleModule();
@ -49,34 +51,31 @@ function startSTT() {}
// Middleware to conditionally serve routes // Middleware to conditionally serve routes
app.use((req, res, next) => { app.use((req, res, next) => {
if (!settings.MODULES.USE_VTUBER && req.path === '/vtuber') { if (!settings.MODULES.USE_VTUBER && req.path === '/vtuber') {
res.sendStatus(404); // Return a 404 status for /vtuber when it's disabled res.sendStatus(404); // Return a 404 status for /vtuber when it's disabled
} else if (!settings.MODULES.USE_CHATBUBBLE && req.path === '/chat') { } else if (!settings.MODULES.USE_CHATBUBBLE && req.path === '/chat') {
res.sendStatus(404); // Return a 404 status for /chat when it's disabled res.sendStatus(404); // Return a 404 status for /chat when it's disabled
} else { } else {
next(); // Proceed to the next middleware or route handler next(); // Proceed to the next middleware or route handler
} }
}); });
localServer.listen(settings.GENERAL.PORT, () => { localServer.listen(settings.GENERAL.PORT, () => {
startVtuberModule(); startVtuberModule();
startChatBubbleModule(); startChatBubbleModule();
if (settings.TTS.USE_TTS) {
}
}); });
// Handle socket connections // Handle socket connections
io.on('connection', (socket) => { io.on('connection', socket => {
// Receive data from the client // Receive data from the client
socket.on('message', (data) => {}); socket.on('message', data => {});
// Receive data from the client // Receive data from the client
socket.on('xxx', (logoUrl, username, message) => { socket.on('xxx', (logoUrl, username, message) => {
socket.broadcast.emit('message', logoUrl, username, message); socket.broadcast.emit('message', logoUrl, username, message);
}); });
socket.on('disconnect', () => {}); socket.on('disconnect', () => {});
}); });
module.exports = { startVtuberModule, startChatBubbleModule }; module.exports = { startVtuberModule, startChatBubbleModule };

File diff suppressed because it is too large Load diff

View file

@ -1,120 +1,139 @@
/* global ttsAudioFile, path, resourcesPath, settings, fs, notificationSound, backend, socket, requestData */
let trueMessage = ''; let trueMessage = '';
let currentLogoUrl = ''; let currentLogoUrl = '';
let currentUsername = ''; let currentUsername = '';
let voiceSoundArray = []; const voiceSoundArray = [];
let status = 0; let status = 0;
let counter = 0; const counter = 0;
const playTTS = (data) => const playTTS = data =>
new Promise((resolve) => { new Promise(resolve => {
ttsAudioFile = path.join(resourcesPath, `./sounds/tts/${data.service}_${data.count}.mp3`); ttsAudioFile = path.join(resourcesPath, `./sounds/tts/${data.service}_${data.count}.mp3`);
const tts = new Audio(ttsAudioFile); const tts = new Audio(ttsAudioFile);
console.log(settings.AUDIO.TTS_AUDIO_DEVICE); // console.log(settings.AUDIO.TTS_AUDIO_DEVICE);
tts.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE); tts.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE);
tts.addEventListener('ended', () => { tts.addEventListener('ended', () => {
console.log('ended'); // console.log('ended');
fs.unlink(ttsAudioFile, (err) => { fs.unlink(ttsAudioFile, err => {
if (err) { if (err) {
console.error('TEST'); console.error(err);
resolve('finished');
resolve('finished'); return;
return; }
} resolve('finished');
resolve('finished'); });
});
});
tts.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE)
.then(() => {
console.log('playing');
tts.volume = settings.AUDIO.TTS_VOLUME / 100;
tts.play().catch((error) => {
resolve('finished');
});
})
.catch((error) => {
console.error('Failed to set audio output device:', error);
resolve('finished');
});
}); });
tts
.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE)
.then(() => {
// console.log('playing');
tts.volume = settings.AUDIO.TTS_VOLUME / 100;
tts.play().catch(error => {
if (error) {
console.error(error);
}
resolve('finished');
});
})
.catch(error => {
console.error('Failed to set audio output device:', error);
resolve('finished');
});
});
async function shiftVoice() { async function shiftVoice() {
status = 1; status = 1;
while (voiceSoundArray.length > 0) { while (voiceSoundArray.length > 0) {
await playTTS(voiceSoundArray.shift()); await playTTS(voiceSoundArray.shift());
} }
status = 0; status = 0;
} }
function add(data) { function add(data) {
voiceSoundArray.push(data); voiceSoundArray.push(data);
if (status === 0) { if (status === 0) {
shiftVoice(); shiftVoice();
} }
} }
function playNotificationSound() { function playNotificationSound() {
if (settings.AUDIO.USE_NOTIFICATION_SOUNDS) { if (settings.AUDIO.USE_NOTIFICATION_SOUNDS) {
let notfication = new Audio( const notfication = new Audio(
path.join(resourcesPath, `./sounds/notifications/${notificationSound.options[settings.AUDIO.NOTIFICATION_SOUND].text}`), path.join(resourcesPath, `./sounds/notifications/${notificationSound.options[settings.AUDIO.NOTIFICATION_SOUND].text}`)
); );
notfication
.setSinkId(settings.AUDIO.SELECTED_NOTIFICATION_AUDIO_DEVICE)
.then(() => {
// console.log('playing');
notfication.volume = settings.AUDIO.NOTIFICATION_VOLUME / 100; notfication.volume = settings.AUDIO.NOTIFICATION_VOLUME / 100;
notfication.play(); notfication.play().catch(error => {
} if (error) {
console.error(error);
}
});
})
.catch(error => {
console.error('Failed to set audio output device:', error);
});
}
} }
// Play sound function // Play sound function
function playAudio(data) { function playAudio(data) {
if (data.service !== '') { if (data.service !== '') {
add(data); add(data);
} }
} }
async function playVoice(filteredMessage, logoUrl, username, message) { async function playVoice(filteredMessage, logoUrl, username, message) {
trueMessage = filteredMessage; trueMessage = filteredMessage;
currentLogoUrl = logoUrl; currentLogoUrl = logoUrl;
currentUsername = username; currentUsername = username;
let textObject = { filtered: filteredMessage, formatted: message }; const textObject = { filtered: filteredMessage, formatted: message };
let voice; let voice;
textObject.filtered = `${username}: ${filteredMessage}`; textObject.filtered = `${username}: ${filteredMessage}`;
// if ( // if (
// settings.TTS.PRIMARY_TTS_LANGUAGE.toLowerCase() !== settings.TTS.SECONDARY_TTS_LANGUAGE.toLowerCase() && // settings.TTS.PRIMARY_TTS_LANGUAGE.toLowerCase() !== settings.TTS.SECONDARY_TTS_LANGUAGE.toLowerCase() &&
// language[0].lang === settings.TTS.SECONDARY_TTS_LANGUAGE.toLowerCase() // language[0].lang === settings.TTS.SECONDARY_TTS_LANGUAGE.toLowerCase()
// ) { // ) {
// voice = settings.TTS.SECONDARY_TTS_NAME; // voice = settings.TTS.SECONDARY_TTS_NAME;
// textObject.filtered = `${username}: ${filteredMessage}`; // textObject.filtered = `${username}: ${filteredMessage}`;
// } else { // } else {
// voice = settings.TTS.PRIMARY_TTS_NAME; // voice = settings.TTS.PRIMARY_TTS_NAME;
// textObject.filtered = `${username}: ${filteredMessage}`; // textObject.filtered = `${username}: ${filteredMessage}`;
// } // }
const service = document.getElementById('primaryTTSService').value; const service = document.getElementById('primaryTTSService').value;
switch (service) { switch (service) {
case 'Internal': case 'Internal': {
const requestData = { const requestData = {
message: textObject.filtered, message: textObject.filtered,
voice: settings.TTS.PRIMARY_VOICE, voice: settings.TTS.PRIMARY_VOICE
}; };
let count = await backend.getInternalTTSAudio(requestData); const count = await backend.getInternalTTSAudio(requestData);
playAudio({ service, message: textObject, count }); playAudio({ service, message: textObject, count });
break; break;
case 'Amazon':
// playAudio({ service: 'Amazon', message: textObject, count });
break;
case 'Google':
// playAudio({ service: 'Google', message: textObject, count });
break;
} }
case 'Amazon':
// playAudio({ service: 'Amazon', message: textObject, count });
break;
case 'Google':
// playAudio({ service: 'Google', message: textObject, count });
break;
}
if (settings.MODULES.USE_CHATBUBBLE) { if (settings.MODULES.USE_CHATBUBBLE) {
socket.emit('xxx', currentLogoUrl, currentUsername, textObject); socket.emit('xxx', currentLogoUrl, currentUsername, textObject);
} }
playNotificationSound(); playNotificationSound();
} }
module.exports = { playAudio, playVoice, playNotificationSound }; module.exports = { playAudio, playVoice, playNotificationSound };

View file

@ -1,145 +1,143 @@
/* global settings, root, fs, settingsPath, ini */
function changeColor(section, setting, tempSection) { function changeColor(section, setting, tempSection) {
document.querySelector(section).value = setting; document.querySelector(section).value = setting;
const value = document.querySelector(section).value; const value = document.querySelector(section).value;
root.style.setProperty(tempSection, value); root.style.setProperty(tempSection, value);
} }
function setCurrentTheme(adjustTemp = false) { function setCurrentTheme(adjustTemp = false) {
changeColor('#MAIN_COLOR_1', settings.THEME.MAIN_COLOR_1, adjustTemp ? '--main-color1-temp' : '--main-color1'); changeColor('#MAIN_COLOR_1', settings.THEME.MAIN_COLOR_1, adjustTemp ? '--main-color1-temp' : '--main-color1');
changeColor('#MAIN_COLOR_2', settings.THEME.MAIN_COLOR_2, adjustTemp ? '--main-color2-temp' : '--main-color2'); changeColor('#MAIN_COLOR_2', settings.THEME.MAIN_COLOR_2, adjustTemp ? '--main-color2-temp' : '--main-color2');
changeColor('#MAIN_COLOR_3', settings.THEME.MAIN_COLOR_3, adjustTemp ? '--main-color3-temp' : '--main-color3'); changeColor('#MAIN_COLOR_3', settings.THEME.MAIN_COLOR_3, adjustTemp ? '--main-color3-temp' : '--main-color3');
changeColor('#MAIN_COLOR_4', settings.THEME.MAIN_COLOR_4, adjustTemp ? '--main-color4-temp' : '--main-color4'); changeColor('#MAIN_COLOR_4', settings.THEME.MAIN_COLOR_4, adjustTemp ? '--main-color4-temp' : '--main-color4');
changeColor('#TOP_BAR', settings.THEME.TOP_BAR, adjustTemp ? '--top-bar-temp' : '--top-bar'); changeColor('#TOP_BAR', settings.THEME.TOP_BAR, adjustTemp ? '--top-bar-temp' : '--top-bar');
changeColor('#MID_SECTION', settings.THEME.MID_SECTION, adjustTemp ? '--mid-section-temp' : '--mid-section'); changeColor('#MID_SECTION', settings.THEME.MID_SECTION, adjustTemp ? '--mid-section-temp' : '--mid-section');
changeColor('#CHAT_BUBBLE_BG', settings.THEME.CHAT_BUBBLE_BG, adjustTemp ? '--chat-bubble-temp' : '--chat-bubble'); changeColor('#CHAT_BUBBLE_BG', settings.THEME.CHAT_BUBBLE_BG, adjustTemp ? '--chat-bubble-temp' : '--chat-bubble');
changeColor( changeColor('#CHAT_BUBBLE_HEADER', settings.THEME.CHAT_BUBBLE_HEADER, adjustTemp ? '--chat-bubble-header-temp' : '--chat-bubble-header');
'#CHAT_BUBBLE_HEADER', changeColor(
settings.THEME.CHAT_BUBBLE_HEADER, '#CHAT_BUBBLE_MESSAGE',
adjustTemp ? '--chat-bubble-header-temp' : '--chat-bubble-header', settings.THEME.CHAT_BUBBLE_MESSAGE,
); adjustTemp ? '--chat-bubble-message-temp' : '--chat-bubble-message'
changeColor( );
'#CHAT_BUBBLE_MESSAGE',
settings.THEME.CHAT_BUBBLE_MESSAGE,
adjustTemp ? '--chat-bubble-message-temp' : '--chat-bubble-message',
);
} }
setCurrentTheme(true); setCurrentTheme(true);
function setTheme() { function setTheme() {
if (settings.THEME.USE_CUSTOM_THEME) { if (settings.THEME.USE_CUSTOM_THEME) {
setCurrentTheme(); setCurrentTheme();
} else { } else {
root.style.setProperty('--main-color1', '#6e2c8c'); root.style.setProperty('--main-color1', '#6e2c8c');
root.style.setProperty('--main-color2', 'white'); root.style.setProperty('--main-color2', 'white');
root.style.setProperty('--main-color3', '#211E1E'); root.style.setProperty('--main-color3', '#211E1E');
root.style.setProperty('--main-color4', '#2f2c34'); root.style.setProperty('--main-color4', '#2f2c34');
root.style.setProperty('--top-bar', '#100B12'); root.style.setProperty('--top-bar', '#100B12');
root.style.setProperty('--mid-section', '#352d3d'); root.style.setProperty('--mid-section', '#352d3d');
root.style.setProperty('--chat-bubble', ' #7A6D7F'); root.style.setProperty('--chat-bubble', ' #7A6D7F');
root.style.setProperty('--chat-bubble-header', '#141414'); root.style.setProperty('--chat-bubble-header', '#141414');
root.style.setProperty('--chat-bubble-message', 'white'); root.style.setProperty('--chat-bubble-message', 'white');
} }
} }
document.body.querySelector('#MAIN_COLOR_1').addEventListener('input', () => { document.body.querySelector('#MAIN_COLOR_1').addEventListener('input', () => {
const x = document.getElementById('MAIN_COLOR_1').value; const x = document.getElementById('MAIN_COLOR_1').value;
root.style.setProperty('--main-color1-temp', x); root.style.setProperty('--main-color1-temp', x);
console.log(x); console.log(x);
}); });
document.body.querySelector('#MAIN_COLOR_1').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_1').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_1 = document.getElementById('MAIN_COLOR_1').value; settings.THEME.MAIN_COLOR_1 = document.getElementById('MAIN_COLOR_1').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#MAIN_COLOR_1', settings.THEME.MAIN_COLOR_1, '--main-color1'); changeColor('#MAIN_COLOR_1', settings.THEME.MAIN_COLOR_1, '--main-color1');
}); });
document.body.querySelector('#MAIN_COLOR_2').addEventListener('input', () => { document.body.querySelector('#MAIN_COLOR_2').addEventListener('input', () => {
const x = document.getElementById('MAIN_COLOR_2').value; const x = document.getElementById('MAIN_COLOR_2').value;
root.style.setProperty('--main-color2-temp', x); root.style.setProperty('--main-color2-temp', x);
}); });
document.body.querySelector('#MAIN_COLOR_2').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_2').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_2 = document.getElementById('MAIN_COLOR_2').value; settings.THEME.MAIN_COLOR_2 = document.getElementById('MAIN_COLOR_2').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#MAIN_COLOR_2', settings.THEME.MAIN_COLOR_2, '--main-color2'); changeColor('#MAIN_COLOR_2', settings.THEME.MAIN_COLOR_2, '--main-color2');
}); });
document.body.querySelector('#MAIN_COLOR_3').addEventListener('input', () => { document.body.querySelector('#MAIN_COLOR_3').addEventListener('input', () => {
const x = document.getElementById('MAIN_COLOR_3').value; const x = document.getElementById('MAIN_COLOR_3').value;
root.style.setProperty('--main-color3-temp', x); root.style.setProperty('--main-color3-temp', x);
}); });
document.body.querySelector('#MAIN_COLOR_3').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_3').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_3 = document.getElementById('MAIN_COLOR_3').value; settings.THEME.MAIN_COLOR_3 = document.getElementById('MAIN_COLOR_3').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#MAIN_COLOR_3', settings.THEME.MAIN_COLOR_3, '--main-color3'); changeColor('#MAIN_COLOR_3', settings.THEME.MAIN_COLOR_3, '--main-color3');
}); });
document.body.querySelector('#MAIN_COLOR_4').addEventListener('input', () => { document.body.querySelector('#MAIN_COLOR_4').addEventListener('input', () => {
const x = document.getElementById('MAIN_COLOR_4').value; const x = document.getElementById('MAIN_COLOR_4').value;
root.style.setProperty('--main-color4-temp', x); root.style.setProperty('--main-color4-temp', x);
}); });
document.body.querySelector('#MAIN_COLOR_4').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_4').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_4 = document.getElementById('MAIN_COLOR_4').value; settings.THEME.MAIN_COLOR_4 = document.getElementById('MAIN_COLOR_4').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#MAIN_COLOR_4', settings.THEME.MAIN_COLOR_4, '--main-color4'); changeColor('#MAIN_COLOR_4', settings.THEME.MAIN_COLOR_4, '--main-color4');
}); });
document.body.querySelector('#TOP_BAR').addEventListener('input', () => { document.body.querySelector('#TOP_BAR').addEventListener('input', () => {
const x = document.getElementById('TOP_BAR').value; const x = document.getElementById('TOP_BAR').value;
root.style.setProperty('--top-bar-temp', x); root.style.setProperty('--top-bar-temp', x);
}); });
document.body.querySelector('#TOP_BAR').addEventListener('change', () => { document.body.querySelector('#TOP_BAR').addEventListener('change', () => {
settings.THEME.TOP_BAR = document.getElementById('TOP_BAR').value; settings.THEME.TOP_BAR = document.getElementById('TOP_BAR').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#TOP_BAR', settings.THEME.TOP_BAR, '--top-bar'); changeColor('#TOP_BAR', settings.THEME.TOP_BAR, '--top-bar');
}); });
document.body.querySelector('#MID_SECTION').addEventListener('input', () => { document.body.querySelector('#MID_SECTION').addEventListener('input', () => {
const x = document.getElementById('MID_SECTION').value; const x = document.getElementById('MID_SECTION').value;
root.style.setProperty('--mid-section-temp', x); root.style.setProperty('--mid-section-temp', x);
}); });
document.body.querySelector('#MID_SECTION').addEventListener('change', () => { document.body.querySelector('#MID_SECTION').addEventListener('change', () => {
settings.THEME.MID_SECTION = document.getElementById('MID_SECTION').value; settings.THEME.MID_SECTION = document.getElementById('MID_SECTION').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#MID_SECTION', settings.THEME.MID_SECTION, '--mid-section'); changeColor('#MID_SECTION', settings.THEME.MID_SECTION, '--mid-section');
}); });
document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('input', () => { document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('input', () => {
const x = document.getElementById('CHAT_BUBBLE_BG').value; const x = document.getElementById('CHAT_BUBBLE_BG').value;
root.style.setProperty('--chat-bubble-temp', x); root.style.setProperty('--chat-bubble-temp', x);
}); });
document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('change', () => { document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('change', () => {
settings.THEME.CHAT_BUBBLE_BG = document.getElementById('CHAT_BUBBLE_BG').value; settings.THEME.CHAT_BUBBLE_BG = document.getElementById('CHAT_BUBBLE_BG').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#CHAT_BUBBLE_BG', settings.THEME.CHAT_BUBBLE_BG, '--chat-bubble'); changeColor('#CHAT_BUBBLE_BG', settings.THEME.CHAT_BUBBLE_BG, '--chat-bubble');
}); });
document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('input', () => { document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('input', () => {
const x = document.getElementById('CHAT_BUBBLE_HEADER').value; const x = document.getElementById('CHAT_BUBBLE_HEADER').value;
root.style.setProperty('--chat-bubble-header-temp', x); root.style.setProperty('--chat-bubble-header-temp', x);
}); });
document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('change', () => { document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('change', () => {
settings.THEME.CHAT_BUBBLE_HEADER = document.getElementById('CHAT_BUBBLE_HEADER').value; settings.THEME.CHAT_BUBBLE_HEADER = document.getElementById('CHAT_BUBBLE_HEADER').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#CHAT_BUBBLE_HEADER', settings.THEME.CHAT_BUBBLE_HEADER, '--chat-bubble-header'); changeColor('#CHAT_BUBBLE_HEADER', settings.THEME.CHAT_BUBBLE_HEADER, '--chat-bubble-header');
}); });
document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('input', () => { document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('input', () => {
const x = document.getElementById('CHAT_BUBBLE_MESSAGE').value; const x = document.getElementById('CHAT_BUBBLE_MESSAGE').value;
root.style.setProperty('--chat-bubble-message-temp', x); root.style.setProperty('--chat-bubble-message-temp', x);
}); });
document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('change', () => { document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('change', () => {
settings.THEME.CHAT_BUBBLE_MESSAGE = document.getElementById('CHAT_BUBBLE_MESSAGE').value; settings.THEME.CHAT_BUBBLE_MESSAGE = document.getElementById('CHAT_BUBBLE_MESSAGE').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, ini.stringify(settings));
changeColor('#CHAT_BUBBLE_MESSAGE', settings.THEME.CHAT_BUBBLE_MESSAGE, '--chat-bubble-message'); changeColor('#CHAT_BUBBLE_MESSAGE', settings.THEME.CHAT_BUBBLE_MESSAGE, '--chat-bubble-message');
}); });
module.exports = { setTheme }; module.exports = { setTheme };

View file

@ -1,144 +1,186 @@
/* global client, customEmojis, emojiPicker, settings, options, sound, showChatMessage, messageTemplates, getPostTime */
const tmi = require('tmi.js'); const tmi = require('tmi.js');
const axios = require('axios'); const axios = require('axios');
let client; let client = null;
let logoUrl = null;
function sendMessage(message) { function sendMessage(message) {
client.say(settings.TWITCH.CHANNEL_NAME, message).catch(console.error); client.say(settings.TWITCH.CHANNEL_NAME, message).catch(console.error);
} }
client = new tmi.Client({ client = new tmi.Client({
options: { options: {
skipUpdatingEmotesets: true, skipUpdatingEmotesets: true
}, },
identity: { identity: {
username: settings.TWITCH.USERNAME, username: settings.TWITCH.USERNAME,
password: settings.TWITCH.OAUTH_TOKEN, password: settings.TWITCH.OAUTH_TOKEN
}, },
channels: [settings.TWITCH.CHANNEL_NAME], channels: [settings.TWITCH.CHANNEL_NAME]
}); });
client client
.connect() .connect()
.then((data) => {}) .then(data => {})
.catch(console.error); .catch(console.error);
function ping(element) { function ping(element) {
let value = document.body.querySelector(element); const value = document.body.querySelector(element);
client client
.ping() .ping()
.then((data) => { .then(data => {
value.classList.add('success'); value.classList.add('success');
value.innerText = 'Success!'; value.innerText = 'Success!';
}) })
.catch((e) => { .catch(e => {
value.classList.add('error'); value.classList.add('error');
value.innerText = 'Failed!'; value.innerText = 'Failed!';
}); });
} }
function displayTwitchMessage(logoUrl, username, messageObject, fileteredMessage) { function displayTwitchMessage(logoUrl, username, messageObject, fileteredMessage) {
const article = document.createElement('article'); const article = document.createElement('article');
article.className = 'msg-container sender'; article.className = 'msg-container sender';
article.innerHTML = messageTemplates.twitchTemplate; article.innerHTML = messageTemplates.twitchTemplate;
const userImg = article.querySelector('.user-img'); const userImg = article.querySelector('.user-img');
if (userImg) { if (userImg) {
userImg.src = logoUrl; userImg.src = logoUrl;
} }
const usernameHtml = article.querySelector('.username'); const usernameHtml = article.querySelector('.username');
if (usernameHtml) { if (usernameHtml) {
usernameHtml.innerText = username; usernameHtml.innerText = username;
} }
const postTime = article.querySelector('.post-time'); const postTime = article.querySelector('.post-time');
if (postTime) { if (postTime) {
postTime.innerText = getPostTime(); postTime.innerText = getPostTime();
} }
article.appendChild(postTime); article.appendChild(postTime);
const msg = article.querySelector('.msg-box'); const msg = article.querySelector('.msg-box');
if (msg) { if (msg) {
messageObject.forEach((entry) => { messageObject.forEach(entry => {
if (entry.text) { if (entry.text) {
msg.innerHTML += entry.text; msg.innerHTML += entry.text;
} else { } else {
msg.innerHTML += entry.html; msg.innerHTML += entry.html;
} }
}); });
} }
// Appends the message to the main chat box (shows the message) // Appends the message to the main chat box (shows the message)
showChatMessage(article, false); showChatMessage(article);
if (fileteredMessage) { if (fileteredMessage) {
sound.playVoice(fileteredMessage, logoUrl, username, msg); sound.playVoice(fileteredMessage, logoUrl, username, msg);
} }
window.article = article; window.article = article;
} }
function getProfileImage(userid, username, message, fileteredMessage) { function getProfileImage(userid, username, message, fileteredMessage) {
// Get user Logo with access token // Get user Logo with access token
options = { options = {
method: 'GET', method: 'GET',
url: `https://api.twitch.tv/helix/users?id=${userid}`, url: `https://api.twitch.tv/helix/users?id=${userid}`,
headers: { 'Client-ID': settings.TWITCH.CLIENT_ID, Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}` }, headers: { 'Client-ID': settings.TWITCH.CLIENT_ID, Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}` }
}; };
axios axios
.request(options) .request(options)
.then((responseLogoUrl) => { .then(responseLogoUrl => {
const logoUrl = responseLogoUrl.data.data[0].profile_image_url; logoUrl = responseLogoUrl.data.data[0].profile_image_url;
displayTwitchMessage(logoUrl, username, message, fileteredMessage); displayTwitchMessage(logoUrl, username, message, fileteredMessage);
}) })
.catch((error) => { .catch(error => {
console.error(error); console.error(error);
}); });
} }
function parseString(inputString) { function parseString(inputString) {
const regex = /(<img.*?\/>)|([^<]+)/g; const regex = /(<img.*?\/>)|([^<]+)/g;
const matches = inputString.match(regex) || []; const matches = inputString.match(regex) || [];
const result = []; const result = [];
for (let i = 0; i < matches.length; i++) { for (let i = 0; i < matches.length; i++) {
const match = matches[i].trim(); const match = matches[i].trim();
if (match.startsWith('<img')) { if (match.startsWith('<img')) {
result.push({ html: match }); result.push({ html: match });
}
if (match !== '' && !match.startsWith('<img')) {
result.push({ text: match });
}
} }
return result; if (match !== '' && !match.startsWith('<img')) {
result.push({ text: match });
}
}
return result;
} }
client.on('message', (channel, tags, message, self) => { client.on('message', (channel, tags, message, self) => {
if (self) { if (self) {
return; return;
} }
const emotes = tags.emotes || {}; const emotes = tags.emotes || {};
const emoteValues = Object.entries(emotes); const emoteValues = Object.entries(emotes);
let fileteredMessage = message; let filteredMessage = message;
let emoteMessage = message; let emoteMessage = message;
emoteValues.forEach((entry) => { emoteValues.forEach(entry => {
entry[1].forEach((lol) => { entry[1].forEach(lol => {
const [start, end] = lol.split('-'); const [start, end] = lol.split('-');
let emote = `<img src="https://static-cdn.jtvnw.net/emoticons/v2/${entry[0]}/default/dark/1.0"/>`; const emote = `<img src="https://static-cdn.jtvnw.net/emoticons/v2/${entry[0]}/default/dark/1.0"/>`;
emoteMessage = emoteMessage.replaceAll(message.slice(parseInt(start), parseInt(end) + 1), emote); emoteMessage = emoteMessage.replaceAll(message.slice(parseInt(start), parseInt(end) + 1), emote);
fileteredMessage = fileteredMessage.replaceAll(message.slice(parseInt(start), parseInt(end) + 1), ''); filteredMessage = filteredMessage.replaceAll(message.slice(parseInt(start), parseInt(end) + 1), '');
});
}); });
});
let messageObject = parseString(emoteMessage); const messageObject = parseString(emoteMessage);
getProfileImage(tags['user-id'], tags['display-name'], messageObject, fileteredMessage); getProfileImage(tags['user-id'], tags['display-name'], messageObject, filteredMessage);
}); });
function formatTwitchEmojis(emojis, name) {
emojis.forEach(emoji => {
const emojiToBeAdded = {
name: emoji.name,
shortcodes: [emoji.name],
url: emoji.images.url_1x,
category: name
};
customEmojis.push(emojiToBeAdded);
});
emojiPicker.customEmoji = customEmojis;
}
function getTwitchGLobalEmotes() {
// Get user Logo with access token
options = {
method: 'GET',
url: 'https://api.twitch.tv/helix/chat/emotes/global',
headers: {
'Client-ID': settings.TWITCH.CLIENT_ID,
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(responseLogoUrl => {
formatTwitchEmojis(responseLogoUrl.data.data, 'Twitch Global');
// console.log(responseLogoUrl);
})
.catch(error => {
console.error(error);
});
}
if (settings.TWITCH.OAUTH_TOKEN) {
getTwitchGLobalEmotes();
}
module.exports = { sendMessage, ping, client }; module.exports = { sendMessage, ping, client };

View file

@ -1,3 +1,5 @@
/* global pythonPath, a */
const { app, BrowserWindow, ipcMain } = require('electron'); const { app, BrowserWindow, ipcMain } = require('electron');
const { writeIniFile } = require('write-ini-file'); const { writeIniFile } = require('write-ini-file');
const path = require('path'); const path = require('path');
@ -14,197 +16,199 @@ let settings;
let window; let window;
if (app.isPackaged) { if (app.isPackaged) {
settingsPath = path.join(process.resourcesPath, './settings.ini'); settingsPath = path.join(process.resourcesPath, './settings.ini');
pythonPath = path.join(process.resourcesPath, './backend'); pythonPath = path.join(process.resourcesPath, './backend');
resourcesPath = process.resourcesPath; resourcesPath = process.resourcesPath;
} else { } else {
settingsPath = path.join(resourcesPath, './config/settings.ini'); settingsPath = path.join(resourcesPath, './config/settings.ini');
pythonPath = path.join(resourcesPath, './backend'); pythonPath = path.join(resourcesPath, './backend');
} }
// Handle creating/removing shortcuts on Windows when installing/uninstalling. // Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { if (require('electron-squirrel-startup')) {
app.quit(); app.quit();
} }
async function createWindow() { async function createWindow() {
if (!fs.existsSync(settingsPath)) { if (!fs.existsSync(settingsPath)) {
console.log(resourcesPath); console.log(resourcesPath);
await createIniFile(); await createIniFile();
} else { } else {
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8'));
}
window = new BrowserWindow({
icon: path.join(__dirname, '/images/icon-512.png'),
width: parseInt(settings.GENERAL.WIDTH),
height: parseInt(settings.GENERAL.HEIGHT),
x: parseInt(settings.GENERAL.POSITION_X),
y: parseInt(settings.GENERAL.POSITION_Y),
frame: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
} }
});
window = new BrowserWindow({ window.loadFile(path.join(__dirname, 'index.html'));
icon: path.join(__dirname, '/images/icon-512.png'),
width: parseInt(settings.GENERAL.WIDTH),
height: parseInt(settings.GENERAL.HEIGHT),
x: parseInt(settings.GENERAL.POSITION_X),
y: parseInt(settings.GENERAL.POSITION_Y),
frame: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
},
});
window.loadFile(path.join(__dirname, 'index.html')); if (!app.isPackaged) {
window.webContents.openDevTools();
}
if (!app.isPackaged) { window.on('close', e => {
window.webContents.openDevTools(); settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); // load newest settings in case anything changed after starting the program
} const bounds = window.getBounds();
window.on('close', (e) => { settings.GENERAL.WIDTH = bounds.width;
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); // load newest settings in case anything changed after starting the program settings.GENERAL.HEIGHT = bounds.height;
const bounds = window.getBounds(); settings.GENERAL.POSITION_X = bounds.x;
settings.GENERAL.POSITION_Y = bounds.y;
settings.GENERAL.WIDTH = bounds.width; fs.writeFileSync(settingsPath, ini.stringify(settings));
settings.GENERAL.HEIGHT = bounds.height; });
settings.GENERAL.POSITION_X = bounds.x;
settings.GENERAL.POSITION_Y = bounds.y;
fs.writeFileSync(settingsPath, ini.stringify(settings));
});
} }
app.whenReady().then(() => { app.whenReady().then(() => {
createWindow(); createWindow();
}); });
app.on('window-all-closed', (event) => { app.on('window-all-closed', event => {
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
app.quit(); app.quit();
} }
}); });
app.on('activate', () => { app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) { if (BrowserWindow.getAllWindows().length === 0) {
createWindow(); createWindow();
} }
}); });
app.on('before-quit', () => { app.on('before-quit', () => {
window.webContents.send('quit-event'); window.webContents.send('quit-event');
}); });
ipcMain.on('resize-window', (event, width, height) => { ipcMain.on('resize-window', (event, width, height) => {
const browserWindow = BrowserWindow.fromWebContents(event.sender); const browserWindow = BrowserWindow.fromWebContents(event.sender);
browserWindow.setSize(width, height); browserWindow.setSize(width, height);
}); });
ipcMain.on('minimize-window', (event) => { ipcMain.on('minimize-window', event => {
const browserWindow = BrowserWindow.fromWebContents(event.sender); const browserWindow = BrowserWindow.fromWebContents(event.sender);
browserWindow.minimize(); browserWindow.minimize();
}); });
ipcMain.on('maximize-window', (event) => { ipcMain.on('maximize-window', event => {
const browserWindow = BrowserWindow.fromWebContents(event.sender); const browserWindow = BrowserWindow.fromWebContents(event.sender);
if (!browserWindow.isMaximized()) { if (!browserWindow.isMaximized()) {
browserWindow.maximize(); browserWindow.maximize();
} else { } else {
browserWindow.unmaximize(); browserWindow.unmaximize();
} }
}); });
ipcMain.on('close-window', (event) => { ipcMain.on('close-window', event => {
const browserWindow = BrowserWindow.fromWebContents(event.sender); const browserWindow = BrowserWindow.fromWebContents(event.sender);
kill('loquendoBot_backend'); kill('loquendoBot_backend');
browserWindow.close(); browserWindow.close();
app.quit(); app.quit();
}); });
ipcMain.on('restart', (event) => { ipcMain.on('restart', event => {
app.relaunch(); app.relaunch();
}); });
ipcMain.on('environment', (event) => { ipcMain.on('environment', event => {
event.returnValue = { resourcesPath, pythonPath, settingsPath, settings, isPackaged: app.isPackaged }; event.returnValue = { resourcesPath, pythonPath, settingsPath, settings, isPackaged: app.isPackaged };
}); });
async function createIniFile() { async function createIniFile() {
await writeIniFile(settingsPath, { await writeIniFile(settingsPath, {
GENERAL: { GENERAL: {
VOICE_ENABLED: true, VOICE_ENABLED: true,
NOTIFICATION_ENABLED: true, NOTIFICATION_ENABLED: true,
POSITION_X: 0, POSITION_X: 0,
POSITION_Y: 0, POSITION_Y: 0,
WIDTH: 1024, WIDTH: 1024,
HEIGHT: 768, HEIGHT: 768,
LANGUAGE: 'EN', LANGUAGE: 'EN',
PORT: 9000, PORT: 9000,
VIEWERS_PANEL: false, VIEWERS_PANEL: false,
LOCATION: pythonPath, LOCATION: pythonPath,
}, ZOOMLEVEL: 1
LANGUAGE: { },
USE_DETECTION: false, LANGUAGE: {
}, USE_DETECTION: false
TTS: { },
USE_TTS: true, TTS: {
PRIMARY_VOICE: '', USE_TTS: true,
PRIMARY_TTS_LANGUAGE: 'EN', PRIMARY_VOICE: '',
SECONDARY_VOICE: '', PRIMARY_TTS_LANGUAGE: 'EN',
SECONDARY_TTS_LANGUAGE: 'EN', SECONDARY_VOICE: '',
}, SECONDARY_TTS_LANGUAGE: 'EN'
STT: { },
USE_STT: false, STT: {
MICROPHONE_ID: 'default', USE_STT: false,
SELECTED_MICROPHONE: 'default', MICROPHONE_ID: 'default',
MICROPHONE: 0, SELECTED_MICROPHONE: 'default',
LANGUAGE: 'vosk-model-small-es-0.42', MICROPHONE: 0,
}, LANGUAGE: 'vosk-model-small-es-0.42'
AUDIO: { },
USE_NOTIFICATION_SOUNDS: true, AUDIO: {
NOTIFICATION_AUDIO_DEVICE: 0, USE_NOTIFICATION_SOUNDS: true,
NOTIFICATION_SOUND: 0, SELECTED_NOTIFICATION_AUDIO_DEVICE: 'default',
NOTIFICATION_VOLUME: 50, NOTIFICATION_AUDIO_DEVICE: 0,
SELECTED_TTS_AUDIO_DEVICE: 0, NOTIFICATION_SOUND: 0,
TTS_AUDIO_DEVICE: 'default', NOTIFICATION_VOLUME: 50,
TTS_VOLUME: 50, SELECTED_TTS_AUDIO_DEVICE: 0,
}, TTS_AUDIO_DEVICE: 'default',
THEME: { TTS_VOLUME: 50
USE_CUSTOM_THEME: false, },
MAIN_COLOR_1: '#cdc1c1', THEME: {
MAIN_COLOR_2: '#b12020', USE_CUSTOM_THEME: false,
MAIN_COLOR_3: '#6c4104', MAIN_COLOR_1: '#cdc1c1',
MAIN_COLOR_4: '#532d2d', MAIN_COLOR_2: '#b12020',
TOP_BAR: '#c8ff00', MAIN_COLOR_3: '#6c4104',
MID_SECTION: '#6b8578', MAIN_COLOR_4: '#532d2d',
CHAT_BUBBLE_BG: '#447466', TOP_BAR: '#c8ff00',
CHAT_BUBBLE_HEADER: '#ffffff', MID_SECTION: '#6b8578',
CHAT_BUBBLE_MESSAGE: '#b5b5b5', CHAT_BUBBLE_BG: '#447466',
}, CHAT_BUBBLE_HEADER: '#ffffff',
TWITCH: { CHAT_BUBBLE_MESSAGE: '#b5b5b5'
USE_TWITCH: false, },
CHANNEL_NAME: '', TWITCH: {
USERNAME: '', USE_TWITCH: false,
USER_ID: '', CHANNEL_NAME: '',
USER_LOGO_URL: '', USERNAME: '',
OAUTH_TOKEN: '', USER_ID: '',
CLIENT_ID: '2t206sj7rvtr1rutob3p627d13jch9', USER_LOGO_URL: '',
}, OAUTH_TOKEN: '',
MODULES: { CLIENT_ID: '2t206sj7rvtr1rutob3p627d13jch9'
USE_MODULES: false, },
USE_VTUBER: false, MODULES: {
USE_CHATBUBBLE: false, USE_MODULES: false,
}, USE_VTUBER: false,
AMAZON: { USE_CHATBUBBLE: false
USE_AMAZON: false, },
ACCESS_KEY: '', AMAZON: {
ACCESS_SECRET: '', USE_AMAZON: false,
PRIMARY_VOICE: '', ACCESS_KEY: '',
SECONDARY_VOICE: '', ACCESS_SECRET: '',
CHARACTERS_USED: 0, PRIMARY_VOICE: '',
}, SECONDARY_VOICE: '',
GOOGLE: { CHARACTERS_USED: 0
USE_GOOGLE: false, },
API_KEY: '', GOOGLE: {
PRIMARY_VOICE: '', USE_GOOGLE: false,
SECONDARY_VOICE: '', API_KEY: '',
CHARACTERS_USED: 0, PRIMARY_VOICE: '',
}, SECONDARY_VOICE: '',
}).then(() => { CHARACTERS_USED: 0
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); }
}); }).then(() => {
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8'));
});
} }

View file

@ -1,23 +1,23 @@
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<title>Chat</title> <title>Chat</title>
<script <script
src="https://cdn.socket.io/4.6.0/socket.io.min.js" src="https://cdn.socket.io/4.6.0/socket.io.min.js"
integrity="sha384-c79GN5VsunZvi+Q/WObgk2in0CbZsHnjEqvFxC5DxHn9lTfNce2WW6h2pH6u/kF+" integrity="sha384-c79GN5VsunZvi+Q/WObgk2in0CbZsHnjEqvFxC5DxHn9lTfNce2WW6h2pH6u/kF+"
crossorigin="anonymous" crossorigin="anonymous"
></script> ></script>
<link rel="stylesheet" href="./fonts/FRAMCDN/font.css" /> <link rel="stylesheet" href="./fonts/FRAMCDN/font.css" />
<link href="main.css" rel="stylesheet" /> <link href="main.css" rel="stylesheet" />
</head> </head>
<body> <body>
<!-- #region Main chat box--> <!-- #region Main chat box-->
<div class="OptionPanel show" id="Chat"> <div class="OptionPanel show" id="Chat">
<div id="chatBox" class="message-window"> <div id="chatBox" class="message-window">
<div class="texts"></div> <div class="texts"></div>
</div> </div>
</div> </div>
<script src="main.js"></script> <script src="main.js"></script>
<video id="camera" autoplay></video> <video id="camera" autoplay></video>
</body> </body>
</html> </html>

View file

@ -1,171 +1,171 @@
body { body {
background-color: transparent; background-color: transparent;
font-family: 'FRAMDCN'; font-family: 'FRAMDCN';
} }
:root { :root {
--variable: 2s; --variable: 2s;
--buttonBackground: #bf2c2c; --buttonBackground: #bf2c2c;
} }
.thomas { .thomas {
position: relative; position: relative;
float: center; float: center;
display: inline-block; /* display: inline-block; */
} }
.speechbubble { .speechbubble {
display: block; display: block;
bottom: 0; bottom: 0;
position: absolute; position: absolute;
z-index: -1; z-index: -1;
} }
.fade-outx { .fade-outx {
animation: fade-outx var(--variable) linear; animation: fade-outx var(--variable) linear;
} }
@keyframes fade-outx { @keyframes fade-outx {
from { from {
opacity: 1; opacity: 1;
} }
to { to {
opacity: 0; opacity: 0;
} }
} }
.fade-outxx { .fade-outxx {
animation: fade-outxx var(--variable) linear; animation: fade-outxx var(--variable) linear;
} }
@keyframes fade-outxx { @keyframes fade-outxx {
from { from {
opacity: 1; opacity: 1;
} }
to { to {
opacity: 0; opacity: 0;
} }
} }
.bounce-in { .bounce-in {
animation: bounce-in 1s ease; animation: bounce-in 1s ease;
} }
@keyframes bounce-in { @keyframes bounce-in {
0% { 0% {
opacity: 0; opacity: 0;
transform: scale(0.3); transform: scale(0.3);
} }
50% { 50% {
opacity: 1; opacity: 1;
transform: scale(1.05); transform: scale(1.05);
} }
70% { 70% {
transform: scale(0.9); transform: scale(0.9);
} }
100% { 100% {
transform: scale(1); transform: scale(1);
} }
} }
.bounce-inx { .bounce-inx {
animation: bounce-inx 1s ease; animation: bounce-inx 1s ease;
} }
@keyframes bounce-inx { @keyframes bounce-inx {
0% { 0% {
opacity: 0; opacity: 0;
} }
50% { 50% {
opacity: 1; opacity: 1;
} }
} }
.msg-container { .msg-container {
position: static; position: static;
display: inline-block; display: inline-block;
width: 100%; width: 100%;
padding-top: 10px; padding-top: 10px;
} }
.message-window { .message-window {
height: calc(100% - 50px); height: calc(100% - 50px);
overflow: hidden; overflow: hidden;
overflow-y: hidden; overflow-y: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 80%; width: 80%;
margin: auto; margin: auto;
background: transparent; background: transparent;
} }
.message-window::before { .message-window::before {
content: ''; content: '';
flex: 1 0 0px; flex: 1 0 0px;
} }
.OptionPanel { .OptionPanel {
flex: 3; flex: 3;
display: none; display: none;
position: absolute; position: absolute;
top: 10px; top: 10px;
left: 0; left: 0;
width: 100%; width: 100%;
height: calc(100% - 25px); height: calc(100% - 25px);
background: transparent; background: transparent;
} }
.OptionPanel.show { .OptionPanel.show {
display: block; display: block;
} }
.message { .message {
text-align: left; text-align: left;
max-width: 100%; max-width: 100%;
height: auto; height: auto;
min-width: 125px; min-width: 125px;
hyphens: auto; hyphens: auto;
bottom: 0; bottom: 0;
right: 0; right: 0;
float: right; float: right;
overflow-wrap: break-word; overflow-wrap: break-word;
} }
.message { .message {
position: relative; position: relative;
border: 2px solid #ff80e1; border: 2px solid #ff80e1;
box-shadow: 0 2px 10px rgba(255, 128, 225, 0.5); box-shadow: 0 2px 10px rgba(255, 128, 225, 0.5);
background: linear-gradient(45deg, rgb(15, 12, 41, 0.7), rgb(48, 43, 99, 0.7)); background: linear-gradient(45deg, rgb(15, 12, 41, 0.7), rgb(48, 43, 99, 0.7));
/* background: linear-gradient(45deg, rgba(72, 0, 154, 0.7), rgba(138, 43, 226, 0.7)); */ /* background: linear-gradient(45deg, rgba(72, 0, 154, 0.7), rgba(138, 43, 226, 0.7)); */
color: white; color: white;
padding: 15px; padding: 15px;
border-radius: 20px; border-radius: 20px;
} }
/*
.message::after { .message::after {
} } */
.arrow { .arrow {
content: ''; content: '';
border: 2px solid #ff80e1; border: 2px solid #ff80e1;
position: absolute; position: absolute;
left: 50%; left: 50%;
top: 100%; top: 100%;
transform: translateX(-50%) rotate(180deg); transform: translateX(-50%) rotate(180deg);
border-width: 10px; border-width: 10px;
border-style: solid; border-style: solid;
border-color: transparent transparent rgb(255, 128, 225, 0.7) transparent; border-color: transparent transparent rgb(255, 128, 225, 0.7) transparent;
color: #ff80e1; color: #ff80e1;
} }
.sender { .sender {
color: #ff80e1; color: #ff80e1;
font-size: 14pt; font-size: 14pt;
} }

View file

@ -1,3 +1,5 @@
/* global io */
// Connect to the Socket.IO server // Connect to the Socket.IO server
const socket = io(); const socket = io();
@ -5,18 +7,18 @@ const socket = io();
socket.emit('message', 'Hello, Server!'); socket.emit('message', 'Hello, Server!');
function getPostTime() { function getPostTime() {
const d = new Date(); const d = new Date();
document.body.querySelectorAll('.container').innerHTML = d.getHours(); document.body.querySelectorAll('.container').innerHTML = d.getHours();
const hours = d.getHours(); const hours = d.getHours();
const minutes = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); const minutes = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
const time = `${hours}:${minutes}`; const time = `${hours}:${minutes}`;
return time; return time;
} }
function showChatMessage(article) { function showChatMessage(article) {
const main = document.querySelector('#chatBox'); const main = document.querySelector('#chatBox');
main.appendChild(article); main.appendChild(article);
main.scrollTop = main.scrollHeight; main.scrollTop = main.scrollHeight;
} }
let textStreamContainer; let textStreamContainer;
@ -28,96 +30,96 @@ let x;
let currentIndex = 0; let currentIndex = 0;
let messageStream = ''; let messageStream = '';
let tempMessageObject = ''; const tempMessageObject = '';
let fullMessageLength = 0; const fullMessageLength = 0;
function getFullMessageLength(text) { function getFullMessageLength(text) {
let fullMessageLength = 0; let fullMessageLength = 0;
text.forEach((element) => { text.forEach(element => {
if (element.text) { if (element.text) {
fullMessageLength += element.text.length; fullMessageLength += element.text.length;
} }
element.html; // element.html;
fullMessageLength += 1; fullMessageLength += 1;
}); });
return fullMessageLength; return fullMessageLength;
} }
function streamText() { function streamText() {
// if (currentIndex < fullMessageLength) { // if (currentIndex < fullMessageLength) {
// textStreamContainer.innerHTML += messageStream.filtered.charAt(currentIndex); // textStreamContainer.innerHTML += messageStream.filtered.charAt(currentIndex);
// currentIndex++; // currentIndex++;
// setTimeout(streamText, 50); // setTimeout(streamText, 50);
// } // }
if (currentIndex < messageStream.length) { if (currentIndex < messageStream.length) {
textStreamContainer.innerHTML += messageStream.charAt(currentIndex); textStreamContainer.innerHTML += messageStream.charAt(currentIndex);
currentIndex++; currentIndex++;
setTimeout(streamText, 50); setTimeout(streamText, 50);
} else { } else {
currentIndex = 0; currentIndex = 0;
x.classList.add('fade-outx'); x.classList.add('fade-outx');
} }
} }
function displayTwitchMessage(logoUrl, username, messageObject) { function displayTwitchMessage(logoUrl, username, messageObject) {
if (!messageObject) { if (!messageObject) {
return; return;
}
const root = document.querySelector(':root');
root.style.setProperty('--variable', '5s');
const article = document.createElement('article');
x = article;
article.className = 'msg-container';
const placeMessage = `
<div class="thomas bounce-in">
<div class="message"></div>
<div class="sender"></div>
<div class="speechbubble"></div>
<div class="arrow"></div>
</div>
`.trim();
article.innerHTML = placeMessage;
const msg = article.querySelector('.message');
msg.innerHTML = `<div class="sender">${username}</div>`; // \n${message}`;
msg.style.fontSize = '12pt';
showChatMessage(article);
const elements = document.getElementsByClassName('msg-container');
if (elements.length > 1) {
elements[0].remove();
}
article.addEventListener('animationend', e => {
if (e.animationName === 'fade-outx') {
article.remove();
} }
});
const root = document.querySelector(':root'); if (elements.length > 1) {
root.style.setProperty('--variable', '5s'); elements[0].classList.add('fade-outxx');
elements[0].addEventListener('animationend', e => {
const article = document.createElement('article'); if (e.animationName === 'fade-outxx') {
x = article;
article.className = 'msg-container';
const placeMessage = `
<div class="thomas bounce-in">
<div class="message"></div>
<div class="sender"></div>
<div class="speechbubble"></div>
<div class="arrow"></div>
</div>
`.trim();
article.innerHTML = placeMessage;
const msg = article.querySelector('.message');
msg.innerHTML = `<div class="sender">${username}</div>`; //\n${message}`;
msg.style.fontSize = '12pt';
showChatMessage(article);
const elements = document.getElementsByClassName('msg-container');
if (elements.length > 1) {
elements[0].remove(); elements[0].remove();
} }
article.addEventListener('animationend', (e) => {
if (e.animationName == 'fade-outx') {
article.remove();
}
}); });
}
if (elements.length > 1) { // fullMessageLength = getFullMessageLength(messageObject);
elements[0].classList.add('fade-outxx'); messageStream = messageObject.filtered;
elements[0].addEventListener('animationend', (e) => { textStreamContainer = document.querySelector('.message');
if (e.animationName == 'fade-outxx') { streamText();
elements[0].remove();
}
});
}
// fullMessageLength = getFullMessageLength(messageObject);
messageStream = messageObject.filtered;
textStreamContainer = document.querySelector('.message');
streamText();
} }
// // Receive a message from the server // // Receive a message from the server
socket.on('message', (logoUrl, username, message, messageDuration) => { socket.on('message', (logoUrl, username, message, messageDuration) => {
displayTwitchMessage(logoUrl, username, message); displayTwitchMessage(logoUrl, username, message);
}); });

View file

@ -20,8 +20,8 @@ body {
padding-left: 40dip; padding-left: 40dip;
padding-right: 10dip; padding-right: 10dip;
vertical-align: top; vertical-align: top;
foreground-repeat: no-repeat; /* foreground-repeat: no-repeat;
foreground-position: 16dip 50%; foreground-position: 16dip 50%; */
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 10dip 50%; background-position: 10dip 50%;
background-size: 64dip 64dip; background-size: 64dip 64dip;
@ -37,7 +37,7 @@ body {
.title { .title {
font-weight: bold !important; font-weight: bold !important;
flow: column !important; /* flow: column !important; */
text-align: left !important; text-align: left !important;
margin: auto !important; margin: auto !important;
width: min-content !important; width: min-content !important;
@ -86,12 +86,12 @@ img {
} }
#button-bar { #button-bar {
flow: horizontal; /* flow: horizontal; */
padding: 10dip; padding: 10dip;
border-spacing: 10dip; border-spacing: 10dip;
margin: 0; margin: 0;
flow: horizontal; /* flow: horizontal; */
horizontal-align: right; /* horizontal-align: right; */
} }
label { label {
@ -103,7 +103,7 @@ label {
text-shadow: #fff 0px 1px; text-shadow: #fff 0px 1px;
min-width: 4em; min-width: 4em;
line-height: 2em; line-height: 2em;
vertical-align: middle; /* vertical-align: middle; */
width: min-intrinsic; width: min-intrinsic;
text-align: center; text-align: center;
} }

View file

@ -1,386 +1,380 @@
* { * {
box-sizing: border-box; box-sizing: border-box;
image-rendering: optimize-quality; image-rendering: optimize-quality;
} }
:disabled { :disabled {
display: none; display: none;
} }
html { html {
overflow: hidden; overflow: hidden;
} }
body { body {
margin: 0; margin: 0;
padding: 16dip; padding: 16dip;
position: relative; position: relative;
background-image: url('../png/grid.png'); background-image: url('../png/grid.png');
background-size: 70px; background-size: 70px;
background-repeat: repeat; background-repeat: repeat;
} }
#controls { #controls {
height: 100%; height: 100%;
width: 100%; width: 100%;
/* flow: horizontal; */ /* flow: horizontal; */
overflow: hidden; overflow: hidden;
display: flex; display: flex;
} }
#controls-left { #controls-left {
order: 2px solid cyan; order: 2px solid cyan;
width: 7%; width: 7%;
height: 10%; height: 10%;
/* flow: vertical; */ /* flow: vertical; */
border-spacing: 1%; border-spacing: 1%;
} }
#controls-top { #controls-top {
height: 10%; height: 10%;
width: 100%; width: 100%;
/* flow: horizontal; */ /* flow: horizontal; */
border-spacing: 1%; border-spacing: 1%;
margin-left: 10px; margin-left: 10px;
} }
#meters { #meters {
display: flex; display: flex;
height: 50vh; height: 50vh;
/* flow: horizontal; */ /* flow: horizontal; */
/* border-spacing: *; */ /* border-spacing: *; */
position: relative; position: relative;
} }
#meter-microphone { #meter-microphone {
margin-left: 10%; margin-left: 10%;
margin-right: 10%; margin-right: 10%;
} }
#meter-delay { #meter-delay {
margin-right: 20%; margin-right: 20%;
} }
#meter-microphone, #meter-microphone,
#meter-delay { #meter-delay {
height: 45vh; height: 45vh;
width: 25%; width: 25%;
background-repeat: no-repeat; background-repeat: no-repeat;
} }
input[type='vslider']>button.slider { input[type='vslider'] > button.slider {
background-size: 100% auto; background-size: 100% auto;
border-radius: 0; border-radius: 0;
width: 275%; width: 275%;
height: 5%; height: 5%;
background-position: 0 50%; background-position: 0 50%;
border-width: 0; border-width: 0;
} }
button { button {
height: 50px; height: 50px;
width: 50px; width: 50px;
background-size: cover; background-size: cover;
overflow: hidden; overflow: hidden;
border-style: none; border-style: none;
background-color: transparent; background-color: transparent;
} }
#meter-microphone>button.slider { #meter-microphone > button.slider {
background-image: url('../png/controls/meters/left.png'); background-image: url('../png/controls/meters/left.png');
} }
#meter-delay>button.slider { #meter-delay > button.slider {
background-image: url('../png/controls/meters/right.png'); background-image: url('../png/controls/meters/right.png');
} }
#meter-microphone { #meter-microphone {
color: #2ebe38; color: #2ebe38;
} }
#meter-delay { #meter-delay {
color: #453be2; color: #453be2;
} }
#slider-left { #slider-left {
left: -25%; left: -25%;
} }
#slider-right { #slider-right {
right: -25%; right: -25%;
} }
#buttons-left { #buttons-left {
width: 100%; width: 100%;
height: 100%; height: 100%;
box-shadow: none; box-shadow: none;
} }
#buttons-top { #buttons-top {
height: 50px; height: 50px;
width: 100%; width: 100%;
display: flex; display: flex;
} }
#buttons-left button { #buttons-left button {
width: 50; width: 50;
height: 50px; height: 50px;
display: flex; display: flex;
background-size: cover; background-size: cover;
overflow: hidden; overflow: hidden;
} }
#buttons-top button { #buttons-top button {
background-size: auto 100%; background-size: auto 100%;
background-position: 50% 50%; background-position: 50% 50%;
border-width: 0; border-width: 0;
border-radius: 0; border-radius: 0;
} }
#buttons-left button:active, #buttons-left button:active,
#about:active, #about:active,
#close:active { #close:active {
filter: brightness(-10%); filter: brightness(-10%);
} }
popup[role='tooltip'] { popup[role='tooltip'] {
color: white; color: white;
background: rgba(0, 0, 0, 0.666); background: rgba(0, 0, 0, 0.666);
border-width: 0; border-width: 0;
padding: 0.333em; padding: 0.333em;
font-size: 1.25em; font-size: 1.25em;
font-family: Calibri; font-family: Calibri;
} }
#microphone-device { #microphone-device {
background-image: url('../png/controls/buttons/left/mic.png'); background-image: url('../png/controls/buttons/left/mic.png');
} }
#background-color { #background-color {
background-image: url('../png/controls/buttons/left/bg.png'); background-image: url('../png/controls/buttons/left/bg.png');
} }
#open-file { #open-file {
background-image: url('../png/controls/buttons/left/open.png'); background-image: url('../png/controls/buttons/left/open.png');
} }
#save-file { #save-file {
background-image: url('../png/controls/buttons/left/save.png'); background-image: url('../png/controls/buttons/left/save.png');
} }
/* TOP ROW BUTTONS */ /* TOP ROW BUTTONS */
button.mouth-image.border-default { button.mouth-image.border-default {
background-image: url('../png/controls/buttons/top/avatar-change/border/default.png'); background-image: url('../png/controls/buttons/top/avatar-change/border/default.png');
position: absolute; position: absolute;
width: 50px; width: 50px;
height: 50px; height: 50px;
top: 0; top: 0;
bottom: 0; bottom: 0;
} }
button.mouth-image.border-add { button.mouth-image.border-add {
background-image: url('../png/controls/buttons/top/avatar-change/border/add.png'); background-image: url('../png/controls/buttons/top/avatar-change/border/add.png');
} }
button.mouth-image:active { button.mouth-image:active {
filter: brightness(-10%); filter: brightness(-10%);
} }
button.mouth-image::before { button.mouth-image::before {
position: absolute; position: absolute;
top: 5%; top: 5%;
right: 10%; right: 10%;
width: 50px; width: 50px;
height: 66%; height: 66%;
background-size: 100% 100%; background-size: 100% 100%;
z-index: -1; z-index: -1;
} }
button.mouth-image::after { button.mouth-image::after {
position: absolute; position: absolute;
top: 69%; top: 69%;
left: 37%; left: 37%;
width: 50px; width: 50px;
height: 35%; height: 35%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
background-size: 100% 100%; background-size: 100% 100%;
} }
#closed-mouth-image.border-default::before { #closed-mouth-image.border-default::before {
background-image: url('../png/avatars/crab/closed.png'); background-image: url('../png/avatars/crab/closed.png');
} }
#closed-mouth-image::after { #closed-mouth-image::after {
background-image: url('../png/controls/buttons/top/avatar-change/closed.png'); background-image: url('../png/controls/buttons/top/avatar-change/closed.png');
} }
#open-mouth-image.border-default::before { #open-mouth-image.border-default::before {
background-image: url('../png/avatars/crab/open.png'); background-image: url('../png/avatars/crab/open.png');
} }
#open-mouth-image::after { #open-mouth-image::after {
background-image: url('../png/controls/buttons/top/avatar-change/open.png'); background-image: url('../png/controls/buttons/top/avatar-change/open.png');
} }
#closed-mouth-blinking-image.border-default::before { #closed-mouth-blinking-image.border-default::before {
background-image: url('../png/avatars/crab/closed-blink.png'); background-image: url('../png/avatars/crab/closed-blink.png');
} }
#closed-mouth-blinking-image::after { #closed-mouth-blinking-image::after {
background-image: url('../png/controls/buttons/top/avatar-change/closed-blink.png'); background-image: url('../png/controls/buttons/top/avatar-change/closed-blink.png');
} }
#open-mouth-blinking-image.border-default::before { #open-mouth-blinking-image.border-default::before {
background-image: url('../png/avatars/crab/open-blink.png'); background-image: url('../png/avatars/crab/open-blink.png');
} }
#open-mouth-blinking-image::after { #open-mouth-blinking-image::after {
background-image: url('../png/controls/buttons/top/avatar-change/open-blink.png'); background-image: url('../png/controls/buttons/top/avatar-change/open-blink.png');
} }
button.motion { button.motion {
/* background-image: url('../png/controls/buttons/top/motion/template.png'); */ /* background-image: url('../png/controls/buttons/top/motion/template.png'); */
position: relative; position: relative;
/* var(x): 0dip; /* var(x): 0dip;
var(y): height(33%); */ var(y): height(33%); */
height: 50px; height: 50px;
width: 50px; width: 50px;
} }
.closed-mouth-motion { .closed-mouth-motion {
background-image: url('../png/controls/buttons/top/motion/closed.png'); background-image: url('../png/controls/buttons/top/motion/closed.png');
box-sizing: border-box; box-sizing: border-box;
image-rendering: optimize-quality; image-rendering: optimize-quality;
height: 50px; height: 50px;
width: 50px; width: 50px;
background-color: #9bccd4; background-color: #9bccd4;
} }
.test { .test {
width: 50px; width: 50px;
height: 50px; height: 50px;
background-size: cover; background-size: cover;
overflow: hidden; overflow: hidden;
} }
.avatar-change { .avatar-change {
background-image: url('../png/controls/buttons/top/avatar-change/border/default.png'); background-image: url('../png/controls/buttons/top/avatar-change/border/default.png');
background-size: cover; background-size: cover;
width: 50px; width: 50px;
height: 50px; height: 50px;
position: relative; position: relative;
left: -5px; left: -5px;
} }
.border { .border {
background-image: url('../png/controls/buttons/top/motion/border.png'); background-image: url('../png/controls/buttons/top/motion/border.png');
background-size: cover; background-size: cover;
width: 50px; width: 50px;
height: 50px; height: 50px;
position: relative; position: relative;
top: -50px; top: -50px;
} }
.open-mouth-motion { .open-mouth-motion {
background-image: url('../png/controls/buttons/top/motion/open.png'); background-image: url('../png/controls/buttons/top/motion/open.png');
box-sizing: border-box; box-sizing: border-box;
image-rendering: optimize-quality; image-rendering: optimize-quality;
height: 50px; height: 50px;
width: 50px; width: 50px;
} }
.mouth-transition { .mouth-transition {
background-image: url('../png/controls/buttons/top/avatar-change/border/default.png'); background-image: url('../png/controls/buttons/top/avatar-change/border/default.png');
box-sizing: border-box; box-sizing: border-box;
image-rendering: optimize-quality; image-rendering: optimize-quality;
height: 50px; height: 50px;
width: 50px; width: 50px;
background-position: 50% 50%; background-position: 50% 50%;
background-color: yellow; background-color: yellow;
} }
.mouth-transitionx { .mouth-transitionx {
background-image: url('../png/controls/buttons/top/avatar-change/border/default.png'); background-image: url('../png/controls/buttons/top/avatar-change/border/default.png');
box-sizing: border-box; box-sizing: border-box;
image-rendering: optimize-quality; image-rendering: optimize-quality;
height: 50px; height: 50px;
width: 50px; width: 50px;
background-position: 50% 50%; background-position: 50% 50%;
background-color: red; background-color: red;
} }
#mouth-transition::before { #mouth-transition::before {
background-color: red; background-color: red;
background-image: url('../png/controls/buttons/top/avatar-change/border/default.png'); background-image: url('../png/controls/buttons/top/avatar-change/border/default.png');
} }
button.motion::before { button.motion::before {
position: absolute; position: absolute;
width: 50px; width: 50px;
height: 90%; height: 90%;
background-size: 105% 105%; background-size: 105% 105%;
transform: translate(-11%, -11%); transform: translate(-11%, -11%);
/* background-position: -50% -50%; */ /* background-position: -50% -50%; */
overflow: hidden; overflow: hidden;
z-index: -1; z-index: -1;
/* hit-margin: -999px; */ /* hit-margin: -999px; */
} }
#closed-mouth-motion::before { #closed-mouth-motion::before {
background-color: #2ebe38; background-color: #2ebe38;
} }
#open-mouth-motion::before { #open-mouth-motion::before {
background-image: url('../png/controls/buttons/top/motion/open.png'); background-image: url('../png/controls/buttons/top/motion/open.png');
height: 50px; height: 50px;
width: 50px; width: 50px;
pointer-events: none; pointer-events: none;
background-color: yellow; background-color: yellow;
} }
button.motion::after { button.motion::after {
position: absolute; position: absolute;
width: 80%; width: 80%;
height: 80%; height: 80%;
background-color: red; background-color: red;
overflow: hidden; overflow: hidden;
z-index: -1; z-index: -1;
transform: translate(11%, 11%); transform: translate(11%, 11%);
/* hit-margin: -999px; */ /* hit-margin: -999px; */
} }
#set-hotkey { #set-hotkey {
background-image: url('../png/controls/buttons/top/hotkey/set/default.png'); background-image: url('../png/controls/buttons/top/hotkey/set/default.png');
} }
#hotkey-mode { #hotkey-mode {
background-image: url('../png/controls/buttons/top/hotkey/mode/0.png'); background-image: url('../png/controls/buttons/top/hotkey/mode/0.png');
} }
#delete-state { #delete-state {
background-image: url('../png/controls/buttons/right/delete.png'); background-image: url('../png/controls/buttons/right/delete.png');
} }
#about { #about {
background-image: url('../png/controls/buttons/top/info.png'); background-image: url('../png/controls/buttons/top/info.png');
} }
#close { #close {
background-image: url('../png/controls/buttons/top/close.png'); background-image: url('../png/controls/buttons/top/close.png');
} }
#avatar { #avatar {
position: absolute; position: absolute;
left: 50%; left: 50%;
top: 50%; top: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
width: 40%; width: 40%;
height: width(100%); height: width(100%);
} }
menu.popup {
/* box-shadow: 3px 3px 1px rgba(0, 0, 0, 0.692); */
}

View file

@ -38,4 +38,4 @@
<script src="../js/about.js"></script> <script src="../js/about.js"></script>
</body> </body>
</html> </html>

View file

@ -1,76 +1,76 @@
<!DOCTYPE html> <!doctype html>
<html window-frame="transparent"> <html window-frame="transparent">
<head> <head>
<title>TransTube</title> <title>TransTube</title>
<script <script
src="https://code.jquery.com/jquery-3.7.0.min.js" src="https://code.jquery.com/jquery-3.7.0.min.js"
integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g="
crossorigin="anonymous" crossorigin="anonymous"
></script> ></script>
<link href="./css/main.css" rel="stylesheet" /> <link href="./css/main.css" rel="stylesheet" />
<script src="./js/main.js" type="module"></script> <script src="./js/main.js" type="module"></script>
</head> </head>
<body> <body>
<img id="avatar" src="./png/avatars/crab/closed.png" width="900" height="900" /> <img id="avatar" src="./png/avatars/crab/closed.png" width="900" height="900" />
<div id="controls"> <div id="controls">
<div id="controls-left"> <div id="controls-left">
<div id="meters"> <div id="meters">
<input id="meter-microphone" value="50" min="0" max="100" title="microphone volume sensitivity" /> <input id="meter-microphone" value="50" min="0" max="100" title="microphone volume sensitivity" />
<input id="meter-delay" value="95" min="0" max="100" title="microphone delay sensitivity" /> <input id="meter-delay" value="95" min="0" max="100" title="microphone delay sensitivity" />
</div>
<div id="buttons-left">
<button id="microphone-device" title="microphone device"></button>
<button id="background-color" title="background color"></button>
<button id="open-file" title="open file"></button>
<button id="save-file" title="save file"></button>
</div>
</div>
<div id="controls-top">
<div id="buttons-top">
<div>
<button class="mouth-image.border-default" id="closed-mouth-image" title="closed mouth image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="mouth-image.border-default" id="open-mouth-image" title="open mouth image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="mouth-image.border-default" id="closed-mouth-blinking-image" title="closed mouth blinking image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="mouth-image.border-default" id="open-mouth-blinking-image" title="open mouth blinking image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="motion closed-mouth-motion" id="closed-mouth-motion" title="closed mouth motion" counter="1"></button>
<div class="border"></div>
</div>
<div>
<button class="motion open-mouth-motion" id="open-mouth-motion" title="open mouth motion" counter="4"></button>
<div class="border"></div>
</div>
<div>
<button class="motion mouth-transition" id="mouth-transition" title="mouth transition"></button>
<div class="border"></div>
</div>
<button id="set-hotkey" title="set hotkey"></button>
<button id="hotkey-mode" title="hotkey mode"></button>
<button id="delete-state" title="delete state"></button>
</div>
</div>
</div> </div>
<div id="buttons-left">
<button id="microphone-device" title="microphone device"></button>
<button id="background-color" title="background color"></button>
<button id="open-file" title="open file"></button>
<button id="save-file" title="save file"></button>
</div>
</div>
<div id="controls-top">
<div id="buttons-top">
<div>
<button class="mouth-image.border-default" id="closed-mouth-image" title="closed mouth image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="mouth-image.border-default" id="open-mouth-image" title="open mouth image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="mouth-image.border-default" id="closed-mouth-blinking-image" title="closed mouth blinking image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="mouth-image.border-default" id="open-mouth-blinking-image" title="open mouth blinking image">
<div class="avatar-change"></div>
</button>
</div>
<div>
<button class="motion closed-mouth-motion" id="closed-mouth-motion" title="closed mouth motion" counter="1"></button>
<div class="border"></div>
</div>
<div>
<button class="motion open-mouth-motion" id="open-mouth-motion" title="open mouth motion" counter="4"></button>
<div class="border"></div>
</div>
<div>
<button class="motion mouth-transition" id="mouth-transition" title="mouth transition"></button>
<div class="border"></div>
</div>
<menu class="popup"> <button id="set-hotkey" title="set hotkey"></button>
<li id="change-image">change image</li> <button id="hotkey-mode" title="hotkey mode"></button>
<li id="remove-image">remove image</li> <button id="delete-state" title="delete state"></button>
</menu> </div>
</body> </div>
</div>
<menu class="popup">
<li id="change-image">change image</li>
<li id="remove-image">remove image</li>
</menu>
</body>
</html> </html>

View file

@ -10,311 +10,270 @@ globalThis.MOUTH_IS_OPEN = false;
globalThis.BLINKING = false; globalThis.BLINKING = false;
function avatarBlink() { function avatarBlink() {
const state = globalThis.BLINKING ? './png/avatars/crab/closed-blink.png' : './png/avatars/crab/closed.png'; const state = globalThis.BLINKING ? './png/avatars/crab/closed-blink.png' : './png/avatars/crab/closed.png';
return state; return state;
} }
function avatarTalk() { function avatarTalk() {
let state = globalThis.MOUTH_IS_OPEN ? './png/avatars/crab/open.png' : './png/avatars/crab/closed.png'; let state = globalThis.MOUTH_IS_OPEN ? './png/avatars/crab/open.png' : './png/avatars/crab/closed.png';
if (globalThis.BLINK) { if (globalThis.BLINK) {
state = './png/avatars/crab/open-blink.png'; state = './png/avatars/crab/open-blink.png';
} }
return state; return state;
} }
function adjustWindow() { function adjustWindow() {
// const [width, height] = Window.this.screenBox('frame', 'dimension'); // const [width, height] = Window.this.screenBox('frame', 'dimension');
// const w = width * 0.666; // const w = width * 0.666;
// const h = height * 0.666; // const h = height * 0.666;
// Window.this.move(width / 2 - w / 2, height / 2 - h / 2, w, h, true); // Window.this.move(width / 2 - w / 2, height / 2 - h / 2, w, h, true);
} }
adjustWindow(); adjustWindow();
async function monitorDelay() { async function monitorDelay() {
setInterval(() => { }); setInterval(() => {});
} }
monitorDelay(); monitorDelay();
function animate() { function animate() {
let avatarCurr = $('#avatar').src; let avatarCurr = $('#avatar').src;
const animation = globalThis.MOUTH_IS_OPEN const animation = globalThis.MOUTH_IS_OPEN ? globalThis.CHOSEN_OPEN_MOUTH_ANIMATION : globalThis.CHOSEN_CLOSED_MOUTH_ANIMATION;
? globalThis.CHOSEN_OPEN_MOUTH_ANIMATION
: globalThis.CHOSEN_CLOSED_MOUTH_ANIMATION;
globalThis.ANIMATION = animation; globalThis.ANIMATION = animation;
clearInterval(globalThis.ANIMATION_INTERVAL); clearInterval(globalThis.ANIMATION_INTERVAL);
globalThis.ANIMATION_INTERVAL = setInterval(() => { globalThis.ANIMATION_INTERVAL = setInterval(() => {
// console.log(globalThis.ANIMATION_INTERVAL); // console.log(globalThis.ANIMATION_INTERVAL);
const t = Date.now() / 1000; const t = Date.now() / 1000;
const { x, y } = MOTION[animation](t); const { x, y } = MOTION[animation](t);
const left = -50 - x * 5; const left = -50 - x * 5;
const top = -50 - y * 5; const top = -50 - y * 5;
document.body.querySelector('#avatar').style.transform = `translate(${left}%, ${top}%)`; document.body.querySelector('#avatar').style.transform = `translate(${left}%, ${top}%)`;
avatarCurr = $('#avatar').src; avatarCurr = $('#avatar').src;
if (globalThis.MOUTH_IS_OPEN === false) { if (globalThis.MOUTH_IS_OPEN === false) {
// const avatarNew = avatarCurr.replace('open', 'closed'); // const avatarNew = avatarCurr.replace('open', 'closed');
const avatarNew = avatarTalk(); const avatarNew = avatarTalk();
if (avatarNew !== avatarCurr) { if (avatarNew !== avatarCurr) {
$('#avatar').src = avatarNew; $('#avatar').src = avatarNew;
avatarCurr = avatarNew; avatarCurr = avatarNew;
} }
} else { } else {
// const avatarNew = avatarCurr.replace('closed', 'open'); // const avatarNew = avatarCurr.replace('closed', 'open');
const avatarNew = avatarBlink(); const avatarNew = avatarBlink();
if (avatarNew !== avatarCurr) { if (avatarNew !== avatarCurr) {
$('#avatar').src = avatarNew; $('#avatar').src = avatarNew;
avatarCurr = avatarNew; avatarCurr = avatarNew;
} }
} }
}); });
} }
animate(); animate();
function updateMeter() { function updateMeter() {
setInterval(() => { setInterval(() => {
// let volume = 50//Window.this.xcall('get_volume'); // let volume = 50//Window.this.xcall('get_volume');
const volume = 100; const volume = 100;
document.body.querySelector('#meter-microphone').value = volume; document.body.querySelector('#meter-microphone').value = volume;
const delayVolume = document.body.querySelector('#meter-delay').value; const delayVolume = document.body.querySelector('#meter-delay').value;
const delaySlider = document.body.querySelector('#meter-delay').value; const delaySlider = document.body.querySelector('#meter-delay').value;
const microphoneVolume = document.body.querySelector('#meter-microphone').value; const microphoneVolume = document.body.querySelector('#meter-microphone').value;
const microphoneSlider = document.body.querySelector('#meter-microphone').value; const microphoneSlider = document.body.querySelector('#meter-microphone').value;
if (microphoneVolume > microphoneSlider) { if (microphoneVolume > microphoneSlider) {
document.body.querySelector('#meter-delay').value = 100; document.body.querySelector('#meter-delay').value = 100;
} else { } else {
document.body.querySelector('#meter-delay').value = Math.max(0, delayVolume - 1); document.body.querySelector('#meter-delay').value = Math.max(0, delayVolume - 1);
} }
if (delayVolume > delaySlider) { if (delayVolume > delaySlider) {
if (globalThis.MOUTH_IS_OPEN === false) { if (globalThis.MOUTH_IS_OPEN === false) {
globalThis.MOUTH_IS_OPEN = true; globalThis.MOUTH_IS_OPEN = true;
// console.log('monitor delay => delayVolume > delaySlider'); // console.log('monitor delay => delayVolume > delaySlider');
$('#avatar').src = avatarTalk(); $('#avatar').src = avatarTalk();
animate(); animate();
} }
} else if (globalThis.MOUTH_IS_OPEN === true) { } else if (globalThis.MOUTH_IS_OPEN === true) {
globalThis.MOUTH_IS_OPEN = false; globalThis.MOUTH_IS_OPEN = false;
// console.log('monitor delay => else'); // console.log('monitor delay => else');
$('#avatar').src = avatarTalk(); $('#avatar').src = avatarTalk();
animate(); animate();
} }
}); });
} }
updateMeter(); updateMeter();
function animateButton(button, animation = 'motionless') { function animateButton(button, animation = 'motionless') {
clearInterval(button.BUTTON_INTERVAL); clearInterval(button.BUTTON_INTERVAL);
const animatedButton = document.body.querySelector(button); const animatedButton = document.body.querySelector(button);
animatedButton.BUTTON_INTERVAL = setInterval(() => { animatedButton.BUTTON_INTERVAL = setInterval(() => {
const t = Date.now() / 1000; const t = Date.now() / 1000;
const { x, y } = MOTION[animation](t); const { x, y } = MOTION[animation](t);
const left = 50 + x * 50; const left = 50 + x * 50;
const top = 50 - y * 50; const top = 50 - y * 50;
// animatedButton // animatedButton
// animatedButton.style.x = left; // animatedButton.style.x = left;
// animatedButton.style.y = (top + 500) * -1; // animatedButton.style.y = (top + 500) * -1;
// animatedButton.style.transform = `translate(${left}%, -${top + 500}%)`; // animatedButton.style.transform = `translate(${left}%, -${top + 500}%)`;
}); });
} }
animateButton( animateButton('#closed-mouth-motion', globalThis.CHOSEN_CLOSED_MOUTH_ANIMATION);
'#closed-mouth-motion',
globalThis.CHOSEN_CLOSED_MOUTH_ANIMATION,
);
animateButton('#open-mouth-motion', globalThis.CHOSEN_OPEN_MOUTH_ANIMATION); animateButton('#open-mouth-motion', globalThis.CHOSEN_OPEN_MOUTH_ANIMATION);
function blink() { function blink() {
let avatarCurr = $('#avatar').src; let avatarCurr = $('#avatar').src;
setInterval(() => { setInterval(() => {
avatarCurr = $('#avatar').src; avatarCurr = $('#avatar').src;
const n = Date.now() % 3200; const n = Date.now() % 3200;
if (n > 3000) { if (n > 3000) {
globalThis.BLINKING = true; globalThis.BLINKING = true;
const avatarNew = avatarBlink(); const avatarNew = avatarBlink();
if (avatarCurr !== avatarNew) { if (avatarCurr !== avatarNew) {
document.body.querySelector('#avatar').src = avatarNew; document.body.querySelector('#avatar').src = avatarNew;
avatarCurr = avatarNew; avatarCurr = avatarNew;
} }
} else { } else {
globalThis.BLINKING = false; globalThis.BLINKING = false;
// const avatarNew = avatarCurr.replace('-blink', ''); // const avatarNew = avatarCurr.replace('-blink', '');
const avatarNew = avatarBlink(); const avatarNew = avatarBlink();
if (avatarCurr !== avatarNew) { if (avatarCurr !== avatarNew) {
document.body.querySelector('#avatar').src = avatarNew; document.body.querySelector('#avatar').src = avatarNew;
avatarCurr = avatarNew; avatarCurr = avatarNew;
} }
} }
}); });
} }
blink(); blink();
async function _cycleAnimations() { async function _cycleAnimations() {
const animations = Object.keys(MOTION); const animations = Object.keys(MOTION);
let i = 0; let i = 0;
while (true) { while (true) {
const key = animations[i % animations.length]; const key = animations[i % animations.length];
animate(key); animate(key);
Window.this.caption = key; Window.this.caption = key;
i++; i++;
await new Promise((r) => setTimeout(r, 2000)); await new Promise(resolve => setTimeout(resolve, 2000));
} }
} }
$(document).on( $(document).on('~mousedown', '#closed-mouth-motion, #open-mouth-motion', motionButtonEvent);
'~mousedown',
'#closed-mouth-motion, #open-mouth-motion',
motionButtonEvent,
);
$(document).on( $(document).on('~doubleclick', '#closed-mouth-motion, #open-mouth-motion', motionButtonEvent);
'~doubleclick',
'#closed-mouth-motion, #open-mouth-motion',
motionButtonEvent,
);
function motionButtonEvent(evt) { function motionButtonEvent(evt) {
const { target: button } = evt; const { target: button } = evt;
button.attributes.counter = button.attributes.counter || 0; button.attributes.counter = button.attributes.counter || 0;
if (evt.button === 1) { if (evt.button === 1) {
button.attributes.counter++; button.attributes.counter++;
} else if (evt.button === 2) { } else if (evt.button === 2) {
button.attributes.counter--; button.attributes.counter--;
} }
const color = [ const color = ['white', '#9BCCD4', '#8087D6', '#AB65CF', '#E7FD5B', '#EC9F45', '#E24555'][mod(button.attributes.counter, 7)];
'white', button.style.variable('color', color);
'#9BCCD4',
'#8087D6',
'#AB65CF',
'#E7FD5B',
'#EC9F45',
'#E24555',
][mod(button.attributes.counter, 7)];
button.style.variable('color', color);
const animation = [ const animation = ['motionless', 'vibing', 'shaking', 'shakingMore', 'bouncy', 'excited', 'nervous'][mod(button.attributes.counter, 7)];
'motionless',
'vibing',
'shaking',
'shakingMore',
'bouncy',
'excited',
'nervous',
][mod(button.attributes.counter, 7)];
animateButton(button, animation); animateButton(button, animation);
if (button.id === 'closed-mouth-motion') { if (button.id === 'closed-mouth-motion') {
globalThis.CHOSEN_CLOSED_MOUTH_ANIMATION = animation; globalThis.CHOSEN_CLOSED_MOUTH_ANIMATION = animation;
animate(); animate();
} else if (button.id === 'open-mouth-motion') { } else if (button.id === 'open-mouth-motion') {
globalThis.CHOSEN_OPEN_MOUTH_ANIMATION = animation; globalThis.CHOSEN_OPEN_MOUTH_ANIMATION = animation;
animate(); animate();
} }
} }
function animateMouthButton() { function animateMouthButton() {
setInterval(() => { setInterval(() => {
const n = Date.now() % 1200; const n = Date.now() % 1200;
document.body.querySelector('.mouth-transition').style.backgroundImage = `url('../vtuber/png/controls/buttons/top/motion/${n > 600 ? 'open' : 'closed' document.body.querySelector('.mouth-transition').style.backgroundImage = `url('../vtuber/png/controls/buttons/top/motion/${
}.png')`; n > 600 ? 'open' : 'closed'
}); }.png')`;
});
} }
animateMouthButton(); animateMouthButton();
function mod(n, m) { function mod(n, m) {
return ((n % m) + m) % m; return ((n % m) + m) % m;
} }
globalThis.CURRENT_BUTTON = null; globalThis.CURRENT_BUTTON = null;
$(document).on( $(document).on('click', '.mouth-image.border-default:not(:first-of-type)', (evt, el) => {
'click', globalThis.CURRENT_BUTTON = el;
'.mouth-image.border-default:not(:first-of-type)', el.popup($('menu'));
(evt, el) => { });
globalThis.CURRENT_BUTTON = el;
el.popup($('menu'));
},
);
function loadImage() { function loadImage() {
const filename = Window.this.selectFile({ const filename = Window.this.selectFile({
mode: 'open', mode: 'open',
filter: filter: 'image files (*.bmp,*.dib,*.gif,*.png,*.apng,*.jpg,*.jpeg,*.jiff)|*.bmp;*.dib;*.gif;*.png;*.apng;*.jpg;*.jpeg;*.jiff',
'image files (*.bmp,*.dib,*.gif,*.png,*.apng,*.jpg,*.jpeg,*.jiff)|*.bmp;*.dib;*.gif;*.png;*.apng;*.jpg;*.jpeg;*.jiff', caption: 'select image for closed mouth...'
caption: 'select image for closed mouth...', });
}); return filename;
return filename;
} }
function changeImage(evt, el) { function changeImage(evt, el) {
// setTimeout to avoid context menu popping up // setTimeout to avoid context menu popping up
setTimeout(() => { setTimeout(() => {
if (el.matches('.mouth-image:first-of-type, .mouth-image.border-add')) { if (el.matches('.mouth-image:first-of-type, .mouth-image.border-add')) {
globalThis.CURRENT_BUTTON = el; globalThis.CURRENT_BUTTON = el;
} }
const filename = loadImage(); const filename = loadImage();
if (!filename) return; if (!filename) return;
const which = globalThis.CURRENT_BUTTON.id const which = globalThis.CURRENT_BUTTON.id.match(/closed|open|blink/g).join('-');
.match(/closed|open|blink/g) document.style.variable(which, `url('${filename}')`);
.join('-');
document.style.variable(which, `url('${filename}')`);
globalThis.CURRENT_BUTTON.classList.add('border-default'); globalThis.CURRENT_BUTTON.classList.add('border-default');
globalThis.CURRENT_BUTTON.classList.remove('border-add'); globalThis.CURRENT_BUTTON.classList.remove('border-add');
}); });
} }
$(document).on( $(document).on('click', '.mouth-image:first-of-type, .mouth-image.border-add', changeImage);
'click',
'.mouth-image:first-of-type, .mouth-image.border-add',
changeImage,
);
$(document).on('click', '#change-image', changeImage); $(document).on('click', '#change-image', changeImage);
$(document).on('click', '#remove-image', (evt, el) => { $(document).on('click', '#remove-image', (evt, el) => {
globalThis.CURRENT_BUTTON.classList.remove('border-default'); globalThis.CURRENT_BUTTON.classList.remove('border-default');
globalThis.CURRENT_BUTTON.classList.add('border-add'); globalThis.CURRENT_BUTTON.classList.add('border-add');
const which = globalThis.CURRENT_BUTTON.id const which = globalThis.CURRENT_BUTTON.id.match(/closed|open|blink/g).join('-');
.match(/closed|open|blink/g) document.style.variable(which, null);
.join('-');
document.style.variable(which, null);
}); });
movableView('body'); movableView('body');
// Window.this.on('activate', (evt) => { // Window.this.on('activate', (evt) => {
// if (evt.reason === 0) { // if (evt.reason === 0) {
// document.classList.add('transparent'); // document.classList.add('transparent');
// } else { // } else {
// document.classList.remove('transparent'); // document.classList.remove('transparent');
// } // }
// }); // });
// setInterval(() => (Window.this.isTopmost = true)); // setInterval(() => (Window.this.isTopmost = true));

View file

@ -1,65 +1,65 @@
import { pnoise1 } from './perlin_noise.js'; import { pnoise1 } from './perlin_noise.js';
export default { export default {
motionless, motionless,
vibing, vibing,
shaking, shaking,
shakingMore, shakingMore,
bouncy, bouncy,
excited, excited,
nervous, nervous
}; };
function motionless(t) { function motionless(t) {
return { x: 0, y: 0 }; return { x: 0, y: 0 };
} }
function clamp01(number) { function clamp01(number) {
return Math.max(0, Math.min(number, 1)); return Math.max(0, Math.min(number, 1));
} }
function _shake(t, amount, velocity) { function _shake(t, amount, velocity) {
let num = clamp01(pnoise1(t * velocity, 0)); let num = clamp01(pnoise1(t * velocity, 0));
let num2 = clamp01(pnoise1(t * velocity, 50)); let num2 = clamp01(pnoise1(t * velocity, 50));
num = num * 2 - 1; num = num * 2 - 1;
num2 = num2 * 2 - 1; num2 = num2 * 2 - 1;
return { return {
x: amount * (num * Math.sqrt(1 - (num2 * num2) / 2)), x: amount * (num * Math.sqrt(1 - (num2 * num2) / 2)),
y: amount * (num2 * Math.sqrt(1 - (num * num) / 2)), y: amount * (num2 * Math.sqrt(1 - (num * num) / 2))
}; };
} }
function _jumpy(t, amountX, amountY, velocity) { function _jumpy(t, amountX, amountY, velocity) {
t *= velocity; t *= velocity;
const num = t % 1; const num = t % 1;
const num2 = -8 * num * (num - 1) - 1; const num2 = -8 * num * (num - 1) - 1;
let num3 = t % 2; let num3 = t % 2;
if (num3 > 1) { if (num3 > 1) {
num3 = 2 - num3; num3 = 2 - num3;
} }
return { x: (num3 * 2 - 1) * amountX, y: num2 * amountY }; return { x: (num3 * 2 - 1) * amountX, y: num2 * amountY };
} }
function vibing(t) { function vibing(t) {
return _shake(t, 0.7, 0.5); return _shake(t, 0.7, 0.5);
} }
function shaking(t) { function shaking(t) {
return _shake(t, 0.3, 10); return _shake(t, 0.3, 10);
} }
function shakingMore(t) { function shakingMore(t) {
return _shake(t, 1, 8); return _shake(t, 1, 8);
} }
function bouncy(t) { function bouncy(t) {
return _jumpy(t, 0, 0.5, 1); return _jumpy(t, 0, 0.5, 1);
} }
function excited(t) { function excited(t) {
return _jumpy(t, 0.5, 0.5, 2); return _jumpy(t, 0.5, 0.5, 2);
} }
function nervous(t) { function nervous(t) {
return _jumpy(t, 1, 1, 4); return _jumpy(t, 1, 1, 4);
} }

View file

@ -1,64 +1,65 @@
if (!Number.prototype.limit) { if (!Number.prototype.limit) {
Number.prototype.limit = function (min, max) { // eslint-disable-next-line no-extend-native
if (this < min) return min; Number.prototype.limit = function (min, max) {
if (this > max) return max; if (this < min) return min;
return this; if (this > max) return max;
}; return this;
};
} }
function movableView(s, screenBound = false) { function movableView(s, screenBound = false) {
let xoff; let yoff; let minXY; let maxX; let let xoff;
maxY; let yoff;
let dragging = false; let minXY;
let maxX;
let maxY;
let dragging = false;
function screenBounds() { function screenBounds() {
if (screenBound) { if (screenBound) {
[maxX, maxY] = Window.this.screenBox('workarea', 'dimension'); [maxX, maxY] = Window.this.screenBox('workarea', 'dimension');
const [w, h] = Window.this.box('dimension', 'border'); const [w, h] = Window.this.box('dimension', 'border');
maxX -= w; maxX -= w;
maxY -= h; maxY -= h;
minXY = 0; minXY = 0;
} else { } else {
maxX = Number.MAX_SAFE_INTEGER; maxX = Number.MAX_SAFE_INTEGER;
maxY = Number.MAX_SAFE_INTEGER; maxY = Number.MAX_SAFE_INTEGER;
minXY = Number.MIN_SAFE_INTEGER; minXY = Number.MIN_SAFE_INTEGER;
} }
} }
function onMouseDown(e) { function onMouseDown(e) {
screenBounds(); screenBounds();
e.target.state.capture(true); e.target.state.capture(true);
const [x, y] = Window.this.box('position', 'border', 'screen'); const [x, y] = Window.this.box('position', 'border', 'screen');
xoff = e.screenX - x; xoff = e.screenX - x;
yoff = e.screenY - y; yoff = e.screenY - y;
dragging = true; dragging = true;
} }
function onMouseMove(e) { function onMouseMove(e) {
if (dragging) { if (dragging) {
Window.this.move( Window.this.move((e.screenX - xoff).limit(minXY, maxX), (e.screenY - yoff).limit(minXY, maxY));
(e.screenX - xoff).limit(minXY, maxX), }
(e.screenY - yoff).limit(minXY, maxY), }
);
}
}
function onMouseUp(e) { function onMouseUp(e) {
if (dragging) { if (dragging) {
dragging = false; dragging = false;
e.target.state.capture(false); e.target.state.capture(false);
} }
} }
const elements = document.querySelectorAll(s); const elements = document.querySelectorAll(s);
for (let i = 0; i < elements.length; ++i) { for (let i = 0; i < elements.length; ++i) {
// elements[i].on('mousedown', onMouseDown); // elements[i].on('mousedown', onMouseDown);
// elements[i].on('mousemove', onMouseMove); // elements[i].on('mousemove', onMouseMove);
// elements[i].on('mouseup', onMouseUp); // elements[i].on('mouseup', onMouseUp);
} }
return !!elements.length; return !!elements.length;
} }
// | Module export (uncomment bellow) // | Module export (uncomment bellow)

File diff suppressed because it is too large Load diff