various updates.
This commit is contained in:
parent
914cf831c4
commit
525cb6116e
45 changed files with 5022 additions and 5277 deletions
9
.editorconfig
Normal file
9
.editorconfig
Normal 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
5
.eslintignore
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules
|
||||||
|
docs
|
||||||
|
dist
|
||||||
|
out
|
||||||
|
build
|
||||||
16
.eslintrc.js
Normal file
16
.eslintrc.js
Normal 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
5
.prettierrc.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
singleQuote: true
|
||||||
|
semi: true
|
||||||
|
printWidth: 140
|
||||||
|
trailingComma: none
|
||||||
|
arrowParens: avoid
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
@ -56,9 +65,7 @@ class LanguageDetection:
|
||||||
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()
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'FRAMDCN';
|
font-family: 'FRAMDCN';
|
||||||
|
src: url(../fonts/FRAMCDN/FRAMDCN.woff);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
|
@ -161,11 +162,15 @@ h1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.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:
|
||||||
|
0 8px 17px 0 rgba(0, 0, 0, 0.2),
|
||||||
|
0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
/* filter: brightness(150%); */
|
/* filter: brightness(150%); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,7 +207,9 @@ h1 {
|
||||||
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:
|
||||||
|
0 0 2px rgba(0, 0, 0, 0.12),
|
||||||
|
0 2px 4px rgba(0, 0, 0, 0.24);
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
position: relative;
|
position: relative;
|
||||||
align-self: start;
|
align-self: start;
|
||||||
|
|
@ -497,3 +504,12 @@ h1 {
|
||||||
.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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -12,30 +12,30 @@ 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;
|
||||||
|
|
@ -55,8 +55,8 @@ div[data-toggle="buttons"] label {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -219,8 +219,18 @@ body {
|
||||||
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',
|
||||||
|
-apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
'Segoe UI',
|
||||||
|
Roboto,
|
||||||
|
Helvetica,
|
||||||
|
Arial,
|
||||||
|
sans-serif,
|
||||||
|
'Apple Color Emoji',
|
||||||
|
'Segoe UI Emoji',
|
||||||
|
'Segoe UI Symbol';
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
}
|
}
|
||||||
|
|
@ -232,8 +242,18 @@ body {
|
||||||
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 {
|
||||||
|
|
@ -242,9 +262,9 @@ body {
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,9 @@
|
||||||
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:
|
||||||
|
rgba(0, 0, 0, 0.16) 0px 3px 6px,
|
||||||
|
rgba(0, 0, 0, 0.23) 0px 3px 6px;
|
||||||
transition: 0.3s ease-in-out;
|
transition: 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +98,9 @@
|
||||||
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:
|
||||||
|
rgba(0, 0, 0, 0.16) 0px 3px 6px,
|
||||||
|
rgba(0, 0, 0, 0.23) 0px 3px 6px;
|
||||||
transition: 0.3s ease-in-out;
|
transition: 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,19 +53,27 @@ input[type='range'].styled-slider::-webkit-slider-runnable-track {
|
||||||
}
|
}
|
||||||
|
|
||||||
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*/
|
||||||
|
|
@ -87,19 +95,27 @@ input[type='range'].styled-slider::-moz-range-track {
|
||||||
}
|
}
|
||||||
|
|
||||||
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*/
|
||||||
|
|
|
||||||
|
|
@ -152,8 +152,8 @@ input:checked + label {
|
||||||
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;
|
||||||
|
|
@ -325,7 +325,9 @@ input[type='lol'] {
|
||||||
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 */
|
||||||
|
|
@ -385,7 +387,9 @@ input[type='lol'] {
|
||||||
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:
|
||||||
|
opacity 0.3s,
|
||||||
|
visibility 0s;
|
||||||
color: var(--main-color2);
|
color: var(--main-color2);
|
||||||
font-family: 'xxii_avenmedium';
|
font-family: 'xxii_avenmedium';
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,10 @@ textarea {
|
||||||
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:
|
||||||
|
0 0 5px #070607,
|
||||||
|
0 0 5px #070607,
|
||||||
|
0 0 5px #070607;
|
||||||
/* transition: all 0.15s ease-in-out; */
|
/* transition: all 0.15s ease-in-out; */
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +92,10 @@ textarea {
|
||||||
.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 {
|
||||||
|
|
@ -103,7 +109,9 @@ textarea {
|
||||||
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:
|
||||||
|
box-shadow 0.3s ease,
|
||||||
|
background-color 0.3s ease;
|
||||||
/* Add a smooth transition for box-shadow and background-color */
|
/* Add a smooth transition for box-shadow and background-color */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
186
src/index.html
186
src/index.html
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
referrerpolicy="no-referrer"
|
referrerpolicy="no-referrer"
|
||||||
/>
|
/>
|
||||||
<link rel="stylesheet" href="./css/logger.css" />
|
<link rel="stylesheet" href="./css/logger.css" />
|
||||||
|
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"></script>
|
||||||
<!--#endregion -->
|
<!--#endregion -->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
@ -132,9 +133,9 @@
|
||||||
<img class="AdvancedMenuIcon" src="./images/settings.png" alt=" " />
|
<img class="AdvancedMenuIcon" src="./images/settings.png" alt=" " />
|
||||||
<div class="AdvancedMenuLabel3">General settings</div>
|
<div class="AdvancedMenuLabel3">General settings</div>
|
||||||
</legend>
|
</legend>
|
||||||
<div class="AdvancedMenuRow inputServer">
|
<div class="AdvancedMenuRow">
|
||||||
<div class="AdvancedMenuLabel">Port</div>
|
<div class="AdvancedMenuLabel">Port</div>
|
||||||
<input type="text" class="fname inputServer" id="PORT" />
|
<input type="text" class="fname" id="PORT" />
|
||||||
<i
|
<i
|
||||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||||
id="Info_PORT"
|
id="Info_PORT"
|
||||||
|
|
@ -142,14 +143,40 @@
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow">
|
<div class="AdvancedMenuRow">
|
||||||
|
<div class="AdvancedMenuLabel">Zoom level %</div>
|
||||||
|
<input type="text" class="fname" id="ZOOMLEVEL" />
|
||||||
|
<i
|
||||||
|
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||||
|
id="Info_ZOOMLEVEL"
|
||||||
|
tip="Port to use to host additional services"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="TTSMenu" class="AdvancedMenu">
|
||||||
|
<legend class="legendStyle" tip="Enable/Disable TTS">
|
||||||
|
<img class="AdvancedMenuIcon" src="./images/tts.png" alt=" " />
|
||||||
|
<input type="checkbox" id="USE_TTS" class="checkbox" />
|
||||||
|
<label for="USE_TTS" class="toggle-small"></label>
|
||||||
|
<div class="AdvancedMenuLabel3">Enable TTS</div>
|
||||||
|
</legend>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
<div class="AdvancedMenuLabel">Default TTS Service</div>
|
<div class="AdvancedMenuLabel">Default TTS Service</div>
|
||||||
<select class="menu-select" name="primaryTTSService" id="primaryTTSService"></select>
|
<select class="menu-select" name="primaryTTSService" id="primaryTTSService"></select>
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow">
|
<div class="AdvancedMenuRow languageDetectionInput">
|
||||||
|
<div class="AdvancedMenuLabel">Default TTS language</div>
|
||||||
|
<select class="menu-select" name="defaultLanguage" id="defaultLanguage" tip="Language Service to use"></select>
|
||||||
|
</div>
|
||||||
|
<div class="AdvancedMenuRow languageDetectionInput">
|
||||||
<div class="AdvancedMenuLabel">2<sup>nd</sup> TTS Service</div>
|
<div class="AdvancedMenuLabel">2<sup>nd</sup> TTS Service</div>
|
||||||
<select class="menu-select" name="secondaryTTSService" id="secondaryTTSService"></select>
|
<select class="menu-select" name="secondaryTTSService" id="secondaryTTSService"></select>
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow">
|
<div class="AdvancedMenuRow languageDetectionInput">
|
||||||
|
<div class="AdvancedMenuLabel">2<sup>nd</sup> TTS language</div>
|
||||||
|
<select class="menu-select" name="secondaryLanguage" id="secondaryLanguage" tip="Language Service to use"></select>
|
||||||
|
</div>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
<div class="AdvancedMenuLabel">TTS Output Device</div>
|
<div class="AdvancedMenuLabel">TTS Output Device</div>
|
||||||
<select class="menu-select" name="ttsAudioDevice" id="ttsAudioDevice"></select>
|
<select class="menu-select" name="ttsAudioDevice" id="ttsAudioDevice"></select>
|
||||||
<i
|
<i
|
||||||
|
|
@ -158,7 +185,7 @@
|
||||||
tip="Outputting to specific device will NOT work with voicemeter"
|
tip="Outputting to specific device will NOT work with voicemeter"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow">
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
<div class="AdvancedMenuLabel">TTS Volume</div>
|
<div class="AdvancedMenuLabel">TTS Volume</div>
|
||||||
<div class="slider-container">
|
<div class="slider-container">
|
||||||
<input id="ttsVolumeSlider" class="styled-slider slider-progress1" type="range" />
|
<input id="ttsVolumeSlider" class="styled-slider slider-progress1" type="range" />
|
||||||
|
|
@ -168,6 +195,30 @@
|
||||||
<input type="text" id="ttsVolume" class="inputBox" />
|
<input type="text" id="ttsVolume" class="inputBox" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
|
<div class="AdvancedMenuLabel">Default Internal Voice</div>
|
||||||
|
<select class="menu-select" name="primaryVoice" id="primaryVoice"></select>
|
||||||
|
</div>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
|
<div class="AdvancedMenuLabel">Test default Internal Voice</div>
|
||||||
|
<textarea id="testPrimaryTTS">Hi, This is a test</textarea>
|
||||||
|
<div class="option-icon-container" tip="Test internal TTS">
|
||||||
|
<i class="fa fa-play-circle fa-2x SmallButton option-icon-container" id="TestDefaultTTSButton"></i>
|
||||||
|
<label class="testLabel Basiclabel"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
|
<div class="AdvancedMenuLabel">2<sup>nd</sup> Internal Voice</div>
|
||||||
|
<select class="menu-select" name="secondaryVoice" id="secondaryVoice"></select>
|
||||||
|
</div>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
|
<div class="AdvancedMenuLabel">Test 2<sup>nd</sup> Internal Voice</div>
|
||||||
|
<textarea id="testSecondaryTTS">Hi, This is a test</textarea>
|
||||||
|
<div class="option-icon-container" tip="Test internal TTS">
|
||||||
|
<i class="fa fa-play-circle fa-2x SmallButton option-icon-container" id="TestSecondaryTTSButton"></i>
|
||||||
|
<label class="testLabel Basiclabel"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset id="STTMenu" class="AdvancedMenu">
|
<fieldset id="STTMenu" class="AdvancedMenu">
|
||||||
|
|
@ -195,83 +246,20 @@
|
||||||
<div class="AdvancedMenuLabel3">Enable Language detection</div>
|
<div class="AdvancedMenuLabel3">Enable Language detection</div>
|
||||||
</legend>
|
</legend>
|
||||||
<div class="AdvancedMenuRow languageDetectionInput">
|
<div class="AdvancedMenuRow languageDetectionInput">
|
||||||
<div class="AdvancedMenuLabel">Language detection service</div>
|
<div class="AdvancedMenuLabel">Translate chat messages to</div>
|
||||||
<select
|
<select class="menu-select" name="language" id="translateChatMessageLanguage" tip="Language Service to use"></select>
|
||||||
class="menu-select"
|
|
||||||
name="language"
|
|
||||||
id="languageService"
|
|
||||||
tip="Language Service to use"
|
|
||||||
></select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow languageDetectionInput">
|
<div class="AdvancedMenuRow languageDetectionInput">
|
||||||
<div class="AdvancedMenuLabel">Translate incoming chat messages to</div>
|
<div class="AdvancedMenuLabel">Broadcast translation</div>
|
||||||
<label for="USE_CHAT_LANGUAGE_DETECTION" class="toggle-small"></label>
|
<label for="USE_CHAT_LANGUAGE_DETECTION" class="toggle-small"></label>
|
||||||
<input type="checkbox" id="USE_CHAT_LANGUAGE_DETECTION" class="checkbox" />
|
<input type="checkbox" id="USE_CHAT_LANGUAGE_DETECTION" class="checkbox" />
|
||||||
<select
|
|
||||||
class="menu-select"
|
|
||||||
name="language"
|
|
||||||
id="translateChatMessageLanguage"
|
|
||||||
tip="Language Service to use"
|
|
||||||
></select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow languageDetectionInput">
|
<div class="AdvancedMenuRow languageDetectionInput">
|
||||||
<div class="AdvancedMenuLabel">Default TTS language</div>
|
<div class="AdvancedMenuLabel">Output to TTS service</div>
|
||||||
<select
|
<select class="menu-select" name="language" id="translateChatMessageLanguage" tip="Language Service to use"></select>
|
||||||
class="menu-select"
|
|
||||||
name="defaultLanguage"
|
|
||||||
id="defaultLanguage"
|
|
||||||
tip="Language Service to use"
|
|
||||||
></select>
|
|
||||||
</div>
|
|
||||||
<div class="AdvancedMenuRow languageDetectionInput">
|
|
||||||
<div class="AdvancedMenuLabel">2<sup>nd</sup> TTS language</div>
|
|
||||||
<select
|
|
||||||
class="menu-select"
|
|
||||||
name="secondaryLanguage"
|
|
||||||
id="secondaryLanguage"
|
|
||||||
tip="Language Service to use"
|
|
||||||
></select>
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset id="TTSMenu" class="AdvancedMenu">
|
|
||||||
<legend class="legendStyle" tip="Enable/Disable TTS">
|
|
||||||
<img class="AdvancedMenuIcon" src="./images/tts.png" alt=" " />
|
|
||||||
<input type="checkbox" id="USE_TTS" class="checkbox" />
|
|
||||||
<label for="USE_TTS" class="toggle-small "></label>
|
|
||||||
<div class="AdvancedMenuLabel3">Enable internal TTS</div>
|
|
||||||
</legend>
|
|
||||||
<div class="AdvancedMenuRow inputTTS">
|
|
||||||
<div class="AdvancedMenuLabel">Default Internal Voice</div>
|
|
||||||
<select class="menu-select" name="primaryVoice" id="primaryVoice"></select>
|
|
||||||
</div>
|
|
||||||
<div class="AdvancedMenuRow inputTTS">
|
|
||||||
<div class="AdvancedMenuLabel">Test default Internal Voice</div>
|
|
||||||
<textarea id="testPrimaryTTS">Hi, This is a test</textarea>
|
|
||||||
<div class="option-icon-container" tip="Test internal TTS">
|
|
||||||
<i
|
|
||||||
class="fa fa-play-circle fa-2x SmallButton option-icon-container"
|
|
||||||
id="TestDefaultTTSButton"
|
|
||||||
></i>
|
|
||||||
<label class="testLabel Basiclabel"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="AdvancedMenuRow inputTTS">
|
|
||||||
<div class="AdvancedMenuLabel">2<sup>nd</sup> Internal Voice</div>
|
|
||||||
<select class="menu-select" name="secondaryVoice" id="secondaryVoice"></select>
|
|
||||||
</div>
|
|
||||||
<div class="AdvancedMenuRow inputTTS">
|
|
||||||
<div class="AdvancedMenuLabel">Test 2<sup>nd</sup> Internal Voice</div>
|
|
||||||
<textarea id="testSecondaryTTS">Hi, This is a test</textarea>
|
|
||||||
<div class="option-icon-container" tip="Test internal TTS">
|
|
||||||
<i
|
|
||||||
class="fa fa-play-circle fa-2x SmallButton option-icon-container"
|
|
||||||
id="TestSecondaryTTSButton"
|
|
||||||
></i>
|
|
||||||
<label class="testLabel Basiclabel"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset id="NotificationMenu" class="AdvancedMenu">
|
<fieldset id="NotificationMenu" class="AdvancedMenu">
|
||||||
<legend class="legendStyle" tip="Enable/Disable notification sounds">
|
<legend class="legendStyle" tip="Enable/Disable notification sounds">
|
||||||
<img class="AdvancedMenuIcon" src="./images/sound.png" alt=" " />
|
<img class="AdvancedMenuIcon" src="./images/sound.png" alt=" " />
|
||||||
|
|
@ -279,6 +267,16 @@
|
||||||
<label for="USE_NOTIFICATION_SOUNDS" class="toggle-small"></label>
|
<label for="USE_NOTIFICATION_SOUNDS" class="toggle-small"></label>
|
||||||
<div class="AdvancedMenuLabel3">Enable notification sounds</div>
|
<div class="AdvancedMenuLabel3">Enable notification sounds</div>
|
||||||
</legend>
|
</legend>
|
||||||
|
<div class="AdvancedMenuRow inputTTS">
|
||||||
|
<div class="AdvancedMenuLabel">Notification sounds Output Device</div>
|
||||||
|
<select class="menu-select" name="notificationSoundAudioDevice" id="notificationSoundAudioDevice"></select>
|
||||||
|
<i
|
||||||
|
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||||
|
id="Info_OUTPUT_NOTIFIACTION_SOUNDS"
|
||||||
|
tip="Outputting to specific device will NOT work with voicemeter"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="AdvancedMenuRow inputNotificationSound">
|
<div class="AdvancedMenuRow inputNotificationSound">
|
||||||
<div class="AdvancedMenuLabel">Notification Volume</div>
|
<div class="AdvancedMenuLabel">Notification Volume</div>
|
||||||
<div class="slider-container">
|
<div class="slider-container">
|
||||||
|
|
@ -293,11 +291,7 @@
|
||||||
<div class="AdvancedMenuLabel">Notification Sound</div>
|
<div class="AdvancedMenuLabel">Notification Sound</div>
|
||||||
<select class="menu-select" name="notification" id="notification"></select>
|
<select class="menu-select" name="notification" id="notification"></select>
|
||||||
<div class="option-icon-container">
|
<div class="option-icon-container">
|
||||||
<i
|
<i class="fa fa-play-circle fa-2x SmallButton option-icon-container" id="SoundTestButton" tip="Test Sound"></i>
|
||||||
class="fa fa-play-circle fa-2x SmallButton option-icon-container"
|
|
||||||
id="SoundTestButton"
|
|
||||||
tip="Test Sound"
|
|
||||||
></i>
|
|
||||||
<label class="testLabel Basiclabel"></label>
|
<label class="testLabel Basiclabel"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -331,11 +325,7 @@
|
||||||
<button class="password-toggle-btn password-toggle-btn1">
|
<button class="password-toggle-btn password-toggle-btn1">
|
||||||
<span class="password-toggle-icon"><i class="fa-regular fa-eye-slash"></i></span>
|
<span class="password-toggle-icon"><i class="fa-regular fa-eye-slash"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<i
|
<i class="fa fa-question-circle fa-2x SmallButton option-icon-container" id="Info_USERNAME" tip="Get OAuth Token"></i>
|
||||||
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
|
||||||
id="Info_USERNAME"
|
|
||||||
tip="Get OAuth Token"
|
|
||||||
></i>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="AdvancedMenuRow inputTwitch">
|
<div class="AdvancedMenuRow inputTwitch">
|
||||||
<div class="AdvancedMenuLabel">Test credentials</div>
|
<div class="AdvancedMenuLabel">Test credentials</div>
|
||||||
|
|
@ -355,6 +345,17 @@
|
||||||
<label for="USE_MODULES" class="toggle-small"></label>
|
<label for="USE_MODULES" class="toggle-small"></label>
|
||||||
<div class="AdvancedMenuLabel3">Enable Modules</div>
|
<div class="AdvancedMenuLabel3">Enable Modules</div>
|
||||||
</legend>
|
</legend>
|
||||||
|
<div class="AdvancedMenuRow inputServer">
|
||||||
|
<div class="AdvancedMenuLabel">Use PNGtuber</div>
|
||||||
|
<input type="checkbox" id="USE_PNGTUBER" class="checkbox" />
|
||||||
|
<label for="USE_PNGTUBER" class="toggle-small"></label>
|
||||||
|
<input type="url" type2="text" class="fname inputServer" id="PNGTUBER_URL" />
|
||||||
|
<i
|
||||||
|
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||||
|
id="Info_PNGTUBER"
|
||||||
|
tip="You can use it as a browsersource on http://localhost:PORT/pngtuber"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
<div class="AdvancedMenuRow inputServer">
|
<div class="AdvancedMenuRow inputServer">
|
||||||
<div class="AdvancedMenuLabel">Use Vtuber</div>
|
<div class="AdvancedMenuLabel">Use Vtuber</div>
|
||||||
<input type="checkbox" id="USE_VTUBER" class="checkbox" />
|
<input type="checkbox" id="USE_VTUBER" class="checkbox" />
|
||||||
|
|
@ -377,6 +378,17 @@
|
||||||
tip="You can use it as a browsersource on http://localhost:PORT/chat"
|
tip="You can use it as a browsersource on http://localhost:PORT/chat"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="AdvancedMenuRow inputServer">
|
||||||
|
<div class="AdvancedMenuLabel">Use Finger</div>
|
||||||
|
<input type="checkbox" id="USE_CHATBUBBLE" class="checkbox" />
|
||||||
|
<label for="USE_CHATBUBBLE" class="toggle-small"></label>
|
||||||
|
<input type="url" type2="text" class="fname inputServer" id="CHATBUBBLE_URL" />
|
||||||
|
<i
|
||||||
|
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
|
||||||
|
id="Info_CHATBUBBLE"
|
||||||
|
tip="You can use it as a browsersource on http://localhost:PORT/chat"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<fieldset id="AdvancedMenuAmazon" class="AdvancedMenu">
|
<fieldset id="AdvancedMenuAmazon" class="AdvancedMenu">
|
||||||
|
|
@ -530,6 +542,12 @@
|
||||||
<div id="chatBox" class="message-window"></div>
|
<div id="chatBox" class="message-window"></div>
|
||||||
<!-- User input box-->
|
<!-- User input box-->
|
||||||
<div id="userInput" class="chat-input">
|
<div id="userInput" class="chat-input">
|
||||||
|
<div id="emoji-picker" class="emoji-picker">
|
||||||
|
<emoji-picker class="dark"></emoji-picker>
|
||||||
|
</div>
|
||||||
|
<button class="SmallButton" id="emojis">
|
||||||
|
<i class="fa-regular fa-grin fa-2x" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
<!-- User text input-->
|
<!-- User text input-->
|
||||||
<input id="textInput" class="input-box" type="text" name="msg" placeholder="Tap 'Enter' to send a message" />
|
<input id="textInput" class="input-box" type="text" name="msg" placeholder="Tap 'Enter' to send a message" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* 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');
|
||||||
|
|
@ -10,12 +12,12 @@ function getAmazonVoices() {
|
||||||
|
|
||||||
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');
|
||||||
|
|
||||||
|
|
@ -36,8 +38,6 @@ if (settings.AMAZON.USE_AMAZON) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class PollyTTS {
|
class PollyTTS {
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
textToSpeech(options, callback) {
|
textToSpeech(options, callback) {
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return callback(new Error('Options are missing'));
|
return callback(new Error('Options are missing'));
|
||||||
|
|
@ -49,27 +49,27 @@ class PollyTTS {
|
||||||
VoiceId: options.voiceId || 'Mia',
|
VoiceId: options.voiceId || 'Mia',
|
||||||
SampleRate: options.sampleRate || 22050,
|
SampleRate: options.sampleRate || 22050,
|
||||||
OutputFormat: options.outputFormat || 'mp3',
|
OutputFormat: options.outputFormat || 'mp3',
|
||||||
Engine: options.engine || 'neural',
|
Engine: options.engine || 'neural'
|
||||||
};
|
};
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
service: 'polly',
|
service: 'polly',
|
||||||
region: options.region || 'us-east-1',
|
region: options.region || 'us-east-1',
|
||||||
path: `/v1/speech?${querystring.stringify(qs)}`,
|
path: `/v1/speech?${querystring.stringify(qs)}`,
|
||||||
signQuery: true,
|
signQuery: true
|
||||||
};
|
};
|
||||||
|
|
||||||
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
|
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
|
||||||
aws4.sign(opts, this.credentials);
|
aws4.sign(opts, this.credentials);
|
||||||
https
|
https
|
||||||
.get(opts, (res) => {
|
.get(opts, res => {
|
||||||
if (res.statusCode !== 200) {
|
if (res.statusCode !== 200) {
|
||||||
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
|
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
|
||||||
}
|
}
|
||||||
callback(null, res);
|
callback(null, res);
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.on('error', (e) => {
|
.on('error', e => {
|
||||||
callback(e);
|
callback(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -79,20 +79,20 @@ class PollyTTS {
|
||||||
describeVoices(callback, credentials) {
|
describeVoices(callback, credentials) {
|
||||||
this.credentials = credentials;
|
this.credentials = credentials;
|
||||||
const qs = {
|
const qs = {
|
||||||
Engine: 'neural',
|
Engine: 'neural'
|
||||||
};
|
};
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
service: 'polly',
|
service: 'polly',
|
||||||
region: 'us-east-1',
|
region: 'us-east-1',
|
||||||
path: `/v1/voices?${querystring.stringify(qs)}`,
|
path: `/v1/voices?${querystring.stringify(qs)}`,
|
||||||
signQuery: true,
|
signQuery: true
|
||||||
};
|
};
|
||||||
|
|
||||||
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
|
// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
|
||||||
aws4.sign(opts, this.credentials);
|
aws4.sign(opts, this.credentials);
|
||||||
https
|
https
|
||||||
.get(opts, (res) => {
|
.get(opts, res => {
|
||||||
if (res.statusCode !== 200) {
|
if (res.statusCode !== 200) {
|
||||||
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
|
return callback(new Error(`Request Failed. Status Code: ${res.statusCode}`));
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +107,7 @@ class PollyTTS {
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
})
|
})
|
||||||
.on('error', (e) => {
|
.on('error', e => {
|
||||||
callback(e);
|
callback(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
144
src/js/auth.js
144
src/js/auth.js
|
|
@ -1,18 +1,20 @@
|
||||||
|
/* 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));
|
||||||
|
|
||||||
|
|
@ -22,9 +24,9 @@ const twitchAuthentication = () =>
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
function stopServer() {
|
// function stopServer() {
|
||||||
tempAuthServer.close();
|
// tempAuthServer.close();
|
||||||
}
|
// }
|
||||||
|
|
||||||
const htmlString = `
|
const htmlString = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
@ -62,7 +64,7 @@ const twitchAuthentication = () =>
|
||||||
|
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
const authURL = `https://id.twitch.tv/oauth2/authorize?client_id=${settings.TWITCH.CLIENT_ID}&redirect_uri=${encodeURIComponent(
|
const authURL = `https://id.twitch.tv/oauth2/authorize?client_id=${settings.TWITCH.CLIENT_ID}&redirect_uri=${encodeURIComponent(
|
||||||
redirectUri,
|
redirectUri
|
||||||
)}&response_type=token&scope=${scopes.join(' ')}`;
|
)}&response_type=token&scope=${scopes.join(' ')}`;
|
||||||
shell.openExternal(authURL);
|
shell.openExternal(authURL);
|
||||||
});
|
});
|
||||||
|
|
@ -76,28 +78,140 @@ 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) => {
|
function getTwitchSubscriptions(channelId) {
|
||||||
getTwitchUserId();
|
// Get user Logo with access token
|
||||||
return res;
|
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 };
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
/* 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() {
|
||||||
|
|
@ -21,12 +23,12 @@ async function getInstalledVoices() {
|
||||||
console.error('Error sending termination signal:', error);
|
console.error('Error sending termination signal:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
let primaryVoice = document.querySelector('#primaryVoice');
|
const primaryVoice = document.querySelector('#primaryVoice');
|
||||||
let secondaryVoice = document.querySelector('#secondaryVoice');
|
const secondaryVoice = document.querySelector('#secondaryVoice');
|
||||||
|
|
||||||
function setVoicesinSelect(voiceSelect) {
|
function setVoicesinSelect(voiceSelect) {
|
||||||
const voices = Object.values(internalVoices.voices);
|
const voices = Object.values(internalVoices.voices);
|
||||||
voices.forEach((voice) => {
|
voices.forEach(voice => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
option.classList.add('option');
|
option.classList.add('option');
|
||||||
|
|
||||||
|
|
@ -43,6 +45,7 @@ async function getInstalledVoices() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getBackendServerStatus() {
|
async function getBackendServerStatus() {
|
||||||
|
console.log('getting status');
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/status`, { method: 'GET' });
|
const response = await fetch(`http://127.0.0.1:${settings.GENERAL.PORT}/status`, { method: 'GET' });
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
|
@ -59,12 +62,12 @@ async function getBackendServerStatus() {
|
||||||
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();
|
||||||
|
|
@ -81,9 +84,9 @@ async function getInternalTTSAudio(requestData) {
|
||||||
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 {
|
||||||
|
|
@ -101,32 +104,40 @@ async function getInternalTTSAudio(requestData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
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');
|
||||||
|
// getBackendServerStatus();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Capture the stderr of the Python process
|
// Capture the stderr of the Python process
|
||||||
python.stderr.on('data', (data) => {
|
python.stderr.on('data', data => {
|
||||||
|
// console.error(`${data}`);
|
||||||
|
if (data.toString().startsWith('INFO:waitress:Serving on')) {
|
||||||
|
resolve('finished');
|
||||||
|
} else {
|
||||||
console.error(`${data}`);
|
console.error(`${data}`);
|
||||||
resolve('finished'); // cannot get it to resolve with stdout
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for the Python process to exit
|
// Listen for the Python process to exit
|
||||||
python.on('close', (code) => {
|
python.on('close', code => {
|
||||||
console.log(`Python process exited with code ${code}`);
|
console.log(`Python process exited with code ${code}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof python.pid !== 'number') {
|
if (typeof python.pid !== 'number') {
|
||||||
console.log('failed');
|
console.log('failed');
|
||||||
} else {
|
} else {
|
||||||
console.log(`Spawned subprocess correctly!, PID = ${python.pid}`);
|
// console.log(`Spawned subprocess correctly!, PID = ${python.pid}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
function getResponse() {
|
/* global messageTemplates, emojiPicker, settings, getPostTime, showChatMessage, twitch */
|
||||||
|
|
||||||
|
async function getResponse() {
|
||||||
const userText = document.querySelector('#textInput').value;
|
const userText = document.querySelector('#textInput').value;
|
||||||
|
|
||||||
// If nothing is written don't do anything
|
// If nothing is written don't do anything
|
||||||
|
|
@ -27,20 +29,40 @@ function getResponse() {
|
||||||
|
|
||||||
const msg = article.querySelector('.msg-box');
|
const msg = article.querySelector('.msg-box');
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg.innerText = userText;
|
console.log(0);
|
||||||
}
|
await replaceChatMessageWithCustomEmojis(userText).then(data => {
|
||||||
|
// console.log(data);
|
||||||
|
msg.innerHTML = data;
|
||||||
|
|
||||||
// Appends the message to the main chat box (shows the message)
|
// Appends the message to the main chat box (shows the message)
|
||||||
showChatMessage(article, true);
|
showChatMessage(article);
|
||||||
|
|
||||||
twitch.sendMessage(userText);
|
twitch.sendMessage(userText);
|
||||||
|
|
||||||
// Empty input box after sending message
|
// Empty input box after sending message
|
||||||
document.body.querySelector('#textInput').value = '';
|
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();
|
||||||
}
|
}
|
||||||
|
|
@ -86,20 +108,19 @@ const displayPanel = (panelSelectorClass, panelSelectorID, btnSelectorID) => {
|
||||||
|
|
||||||
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
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -119,20 +140,19 @@ const displayPanelX = (panelSelectorClass, panelSelectorID, btnSelectorID) => {
|
||||||
|
|
||||||
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
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
9
src/js/customEmojis.js
Normal file
9
src/js/customEmojis.js
Normal 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 };
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* global settings, addVoiceService, googleVoices */
|
||||||
|
|
||||||
function getGoogleVoices() {
|
function getGoogleVoices() {
|
||||||
if (!settings.GOOGLE.USE_GOOGLE) {
|
if (!settings.GOOGLE.USE_GOOGLE) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -5,12 +7,12 @@ function getGoogleVoices() {
|
||||||
|
|
||||||
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');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
// *info page with credits, version and more info
|
// *info page with credits, version and more info
|
||||||
|
|
||||||
const languages = {
|
const languages = {
|
||||||
|
none: { IETF: 'none', 'ISO-639': 'none' },
|
||||||
acehnese: { IETF: 'ace-ID', 'ISO-639': 'ace' },
|
acehnese: { IETF: 'ace-ID', 'ISO-639': 'ace' },
|
||||||
afrikaans: { IETF: 'af-ZA', 'ISO-639': 'af' },
|
afrikaans: { IETF: 'af-ZA', 'ISO-639': 'af' },
|
||||||
akan: { IETF: 'ak-GH', 'ISO-639': 'ak' },
|
akan: { IETF: 'ak-GH', 'ISO-639': 'ak' },
|
||||||
|
|
@ -325,7 +326,7 @@ const languages = {
|
||||||
xhosa: { IETF: 'xh-ZA', 'ISO-639': 'xh' },
|
xhosa: { IETF: 'xh-ZA', 'ISO-639': 'xh' },
|
||||||
yiddish: { IETF: 'yi-YD', 'ISO-639': 'yi' },
|
yiddish: { IETF: 'yi-YD', 'ISO-639': 'yi' },
|
||||||
yoruba: { IETF: 'yo-NG', 'ISO-639': 'yo' },
|
yoruba: { IETF: 'yo-NG', 'ISO-639': 'yo' },
|
||||||
zulu: { IETF: 'zu-ZA', 'ISO-639': 'zu' },
|
zulu: { IETF: 'zu-ZA', 'ISO-639': 'zu' }
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = { languages };
|
module.exports = { languages };
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ 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({
|
||||||
|
|
@ -24,32 +24,32 @@ const logger = createLogger({
|
||||||
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');
|
||||||
|
|
||||||
|
|
@ -73,6 +73,8 @@ fetch(path.join(__dirname, '../logs/activity.log'))
|
||||||
tableBody.appendChild(row);
|
tableBody.appendChild(row);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {});
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = logger;
|
module.exports = logger;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -17,10 +19,10 @@ function getAvailableMediaDevices(type) {
|
||||||
|
|
||||||
// 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.
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +46,6 @@ getAvailableMediaDevices('audioinput')
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
console.error('Error retrieving microphones:', error);
|
console.error('Error retrieving microphones:', error);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -78,11 +83,15 @@ 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) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
files.forEach((file, i) => {
|
files.forEach((file, i) => {
|
||||||
// Create a new option element.
|
// Create a new option element.
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
|
|
@ -101,7 +110,11 @@ fs.readdir(notificationSounds, (err, files) => {
|
||||||
|
|
||||||
// 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) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
if (file.includes('.txt')) {
|
if (file.includes('.txt')) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -126,25 +139,27 @@ async function getAudioDevices() {
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -162,7 +177,7 @@ setLanguagesinSelect('#secondaryLanguage', settings.TTS.SECONDARY_TTS_LANGUAGE_I
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
@ -174,7 +189,7 @@ function addVoiceService(name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
@ -185,33 +200,21 @@ Array.from(document.body.querySelectorAll('[tip]')).forEach((el) => {
|
||||||
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);
|
|
||||||
// var style2 = getComputedStyle(usernameHtml);
|
|
||||||
|
|
||||||
const lastMessage = messages[messages.length - 1];
|
const lastMessage = messages[messages.length - 1];
|
||||||
lastMessage.scrollIntoView({ behavior: 'smooth' });
|
lastMessage.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
|
@ -221,7 +224,7 @@ 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}`;
|
||||||
|
|
||||||
|
|
@ -253,3 +256,42 @@ 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'));
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,19 @@ function getBotResponse(input) {
|
||||||
// rock paper scissors
|
// rock paper scissors
|
||||||
if (input === 'rock') {
|
if (input === 'rock') {
|
||||||
return 'paper';
|
return 'paper';
|
||||||
} if (input === 'paper') {
|
}
|
||||||
|
if (input === 'paper') {
|
||||||
return 'scissors';
|
return 'scissors';
|
||||||
} if (input === 'scissors') {
|
}
|
||||||
|
if (input === 'scissors') {
|
||||||
return 'rock';
|
return 'rock';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple responses
|
// Simple responses
|
||||||
if (input === 'hello') {
|
if (input === 'hello') {
|
||||||
return 'Hello there!';
|
return 'Hello there!';
|
||||||
} if (input === 'goodbye') {
|
}
|
||||||
|
if (input === 'goodbye') {
|
||||||
return 'Talk to you later!';
|
return 'Talk to you later!';
|
||||||
}
|
}
|
||||||
return 'Try asking something else!';
|
return 'Try asking something else!';
|
||||||
|
|
|
||||||
|
|
@ -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,7 +7,7 @@ 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) {
|
||||||
|
|
@ -14,8 +16,8 @@ function startVtuberModule() {
|
||||||
|
|
||||||
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%';
|
||||||
|
|
@ -33,8 +35,8 @@ function startChatBubbleModule() {
|
||||||
|
|
||||||
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%';
|
||||||
|
|
@ -61,15 +63,12 @@ app.use((req, res, next) => {
|
||||||
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) => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
/* global settings, setZoomLevel, webFrame, theme, fs, settingsPath, ini, startVoiceRecognition,notificationSoundAudioDevices, ttsAudioDevices, notificationSound, path, resourcesPath, ipcRenderer, auth, shell, sound, twitch, server, backend */
|
||||||
|
|
||||||
function getGeneralSettings() {
|
function getGeneralSettings() {
|
||||||
// General
|
// General
|
||||||
document.body.querySelector('#PORT').value = settings.GENERAL.PORT;
|
document.body.querySelector('#PORT').value = settings.GENERAL.PORT;
|
||||||
|
document.body.querySelector('#ZOOMLEVEL').value = settings.GENERAL.ZOOMLEVEL * 100;
|
||||||
|
webFrame.setZoomFactor(parseFloat(settings.GENERAL.ZOOMLEVEL));
|
||||||
// Theme
|
// Theme
|
||||||
document.querySelector('#USE_CUSTOM_THEME').value = settings.THEME.USE_CUSTOM_THEME;
|
document.querySelector('#USE_CUSTOM_THEME').value = settings.THEME.USE_CUSTOM_THEME;
|
||||||
document.body.querySelector('#USE_CUSTOM_THEME').checked = settings.THEME.USE_CUSTOM_THEME === true ? 1 : 0;
|
document.body.querySelector('#USE_CUSTOM_THEME').checked = settings.THEME.USE_CUSTOM_THEME === true ? 1 : 0;
|
||||||
|
|
@ -44,42 +47,42 @@ function getGeneralSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.querySelector('#primaryAmazonVoice').addEventListener('change', () => {
|
document.body.querySelector('#primaryAmazonVoice').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#primaryAmazonVoice');
|
const select = document.querySelector('#primaryAmazonVoice');
|
||||||
settings.AMAZON.PRIMARY_VOICE = select.value;
|
settings.AMAZON.PRIMARY_VOICE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved Amazon primary voice!', 'success');
|
createNotification('Saved Amazon primary voice!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#secondaryAmazonVoice').addEventListener('change', () => {
|
document.body.querySelector('#secondaryAmazonVoice').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#secondaryAmazonVoice');
|
const select = document.querySelector('#secondaryAmazonVoice');
|
||||||
settings.AMAZON.SECONDARY_VOICE = select.value;
|
settings.AMAZON.SECONDARY_VOICE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved Amazon secondary voice!', 'success');
|
createNotification('Saved Amazon secondary voice!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#primaryGoogleVoice').addEventListener('change', () => {
|
document.body.querySelector('#primaryGoogleVoice').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#primaryGoogleVoice');
|
const select = document.querySelector('#primaryGoogleVoice');
|
||||||
settings.GOOGLE.PRIMARY_VOICE = select.value;
|
settings.GOOGLE.PRIMARY_VOICE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved Google primary voice!', 'success');
|
createNotification('Saved Google primary voice!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#secondaryGoogleVoice').addEventListener('change', () => {
|
document.body.querySelector('#secondaryGoogleVoice').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#secondaryGoogleVoice');
|
const select = document.querySelector('#secondaryGoogleVoice');
|
||||||
settings.GOOGLE.SECONDARY_VOICE = select.value;
|
settings.GOOGLE.SECONDARY_VOICE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved Google secondary voice!', 'success');
|
createNotification('Saved Google secondary voice!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#primaryVoice').addEventListener('change', () => {
|
document.body.querySelector('#primaryVoice').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#primaryVoice');
|
const select = document.querySelector('#primaryVoice');
|
||||||
settings.TTS.PRIMARY_VOICE = select.value;
|
settings.TTS.PRIMARY_VOICE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved primary voice!', 'success');
|
createNotification('Saved primary voice!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#microphone').addEventListener('change', () => {
|
document.body.querySelector('#microphone').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#microphone');
|
const select = document.querySelector('#microphone');
|
||||||
settings.STT.MICROPHONE = select.value;
|
settings.STT.MICROPHONE = select.value;
|
||||||
settings.STT.MICROPHONE_ID = select.options[select.selectedIndex].text;
|
settings.STT.MICROPHONE_ID = select.options[select.selectedIndex].text;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
@ -88,14 +91,14 @@ document.body.querySelector('#microphone').addEventListener('change', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#sttModel').addEventListener('change', () => {
|
document.body.querySelector('#sttModel').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#sttModel');
|
const select = document.querySelector('#sttModel');
|
||||||
settings.STT.LANGUAGE = select.value;
|
settings.STT.LANGUAGE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved voice detection language!', 'success');
|
createNotification('Saved voice detection language!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#defaultLanguage').addEventListener('change', () => {
|
document.body.querySelector('#defaultLanguage').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#defaultLanguage');
|
const select = document.querySelector('#defaultLanguage');
|
||||||
settings.TTS.PRIMARY_TTS_LANGUAGE_INDEX = select.selectedIndex;
|
settings.TTS.PRIMARY_TTS_LANGUAGE_INDEX = select.selectedIndex;
|
||||||
settings.TTS.PRIMARY_TTS_LANGUAGE = select.options[select.selectedIndex].text;
|
settings.TTS.PRIMARY_TTS_LANGUAGE = select.options[select.selectedIndex].text;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
@ -103,14 +106,14 @@ document.body.querySelector('#defaultLanguage').addEventListener('change', () =>
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#secondaryVoice').addEventListener('change', () => {
|
document.body.querySelector('#secondaryVoice').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#secondaryVoice');
|
const select = document.querySelector('#secondaryVoice');
|
||||||
settings.TTS.SECONDARY_VOICE = select.value;
|
settings.TTS.SECONDARY_VOICE = select.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved secondary voice!', 'success');
|
createNotification('Saved secondary voice!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#secondaryLanguage').addEventListener('change', () => {
|
document.body.querySelector('#secondaryLanguage').addEventListener('change', () => {
|
||||||
var select = document.querySelector('#secondaryLanguage');
|
const select = document.querySelector('#secondaryLanguage');
|
||||||
settings.TTS.SECONDARY_TTS_LANGUAGE_INDEX = select.selectedIndex;
|
settings.TTS.SECONDARY_TTS_LANGUAGE_INDEX = select.selectedIndex;
|
||||||
settings.TTS.SECONDARY_TTS_LANGUAGE = select.options[select.selectedIndex].text;
|
settings.TTS.SECONDARY_TTS_LANGUAGE = select.options[select.selectedIndex].text;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
@ -124,11 +127,18 @@ document.body.querySelector('#ttsAudioDevice').addEventListener('change', () =>
|
||||||
createNotification('Saved audio device!', 'success');
|
createNotification('Saved audio device!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.body.querySelector('#notificationSoundAudioDevice').addEventListener('change', () => {
|
||||||
|
settings.AUDIO.SELECTED_NOTIFICATION_AUDIO_DEVICE = notificationSoundAudioDevices.value;
|
||||||
|
settings.AUDIO.NOTIFICATION_AUDIO_DEVICE = notificationSoundAudioDevices.selectedIndex;
|
||||||
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
createNotification('Saved audio device!', 'success');
|
||||||
|
});
|
||||||
|
|
||||||
document.body.querySelector('#TWITCH_CHANNEL_NAME').addEventListener('change', () => {
|
document.body.querySelector('#TWITCH_CHANNEL_NAME').addEventListener('change', () => {
|
||||||
settings.TWITCH.CHANNEL_NAME = document.body.querySelector('#TWITCH_CHANNEL_NAME').value;
|
settings.TWITCH.CHANNEL_NAME = document.body.querySelector('#TWITCH_CHANNEL_NAME').value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
||||||
let button = document.body.querySelector('#TestTwitchCredentials');
|
const button = document.body.querySelector('#TestTwitchCredentials');
|
||||||
button.className = 'AdvancedMenuButton';
|
button.className = 'AdvancedMenuButton';
|
||||||
createNotification('Saved Channel name, please restart the application to reset twitch service', 'warning');
|
createNotification('Saved Channel name, please restart the application to reset twitch service', 'warning');
|
||||||
});
|
});
|
||||||
|
|
@ -138,11 +148,19 @@ document.body.querySelector('#TWITCH_OAUTH_TOKEN').addEventListener('change', ()
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
createNotification('Saved OAuth token!', 'success');
|
createNotification('Saved OAuth token!', 'success');
|
||||||
|
|
||||||
let button = document.body.querySelector('#TestTwitchCredentials');
|
const button = document.body.querySelector('#TestTwitchCredentials');
|
||||||
button.className = 'AdvancedMenuButton';
|
button.className = 'AdvancedMenuButton';
|
||||||
createNotification('Saved OAuth token, please restart the application to reset twitch service', 'warning');
|
createNotification('Saved OAuth token, please restart the application to reset twitch service', 'warning');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setInputFilter(
|
||||||
|
document.body.querySelector('#PORT'),
|
||||||
|
function (value) {
|
||||||
|
return /^\d*\.?\d*$/.test(value); // Allow digits and '.' only, using a RegExp.
|
||||||
|
},
|
||||||
|
"Only digits and '.' are allowed"
|
||||||
|
);
|
||||||
|
|
||||||
document.body.querySelector('#PORT').addEventListener('change', () => {
|
document.body.querySelector('#PORT').addEventListener('change', () => {
|
||||||
settings.GENERAL.PORT = document.body.querySelector('#PORT').value;
|
settings.GENERAL.PORT = document.body.querySelector('#PORT').value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
@ -174,7 +192,7 @@ document.body.querySelector('#notification').addEventListener('change', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function showMenuButton(menuButton, toggle) {
|
function showMenuButton(menuButton, toggle) {
|
||||||
let option = document.body.querySelector(menuButton);
|
const option = document.body.querySelector(menuButton);
|
||||||
if (!toggle) {
|
if (!toggle) {
|
||||||
option.style.display = 'none';
|
option.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -196,7 +214,7 @@ function createNotification(message = null, type = null) {
|
||||||
alertSound = 'error.mp3';
|
alertSound = 'error.mp3';
|
||||||
}
|
}
|
||||||
|
|
||||||
let notfication = new Audio(path.join(resourcesPath, `./sounds/notifications/${alertSound}`));
|
const notfication = new Audio(path.join(resourcesPath, `./sounds/notifications/${alertSound}`));
|
||||||
notfication.volume = settings.AUDIO.NOTIFICATION_VOLUME / 100;
|
notfication.volume = settings.AUDIO.NOTIFICATION_VOLUME / 100;
|
||||||
notfication.play();
|
notfication.play();
|
||||||
setTimeout(() => notification.remove(), 10000);
|
setTimeout(() => notification.remove(), 10000);
|
||||||
|
|
@ -250,14 +268,14 @@ document.body.querySelector('#min-button').addEventListener('click', () => {
|
||||||
|
|
||||||
// #region Top bar buttons
|
// #region Top bar buttons
|
||||||
document.body.querySelector('#Info_USERNAME').addEventListener('click', async () => {
|
document.body.querySelector('#Info_USERNAME').addEventListener('click', async () => {
|
||||||
let element = document.body.querySelector('#TWITCH_OAUTH_TOKEN');
|
const element = document.body.querySelector('#TWITCH_OAUTH_TOKEN');
|
||||||
element.value = await auth.getTwitchOauthToken();
|
element.value = await auth.getTwitchOauthToken();
|
||||||
|
|
||||||
createNotification('Saved OAuth token!', 'success');
|
createNotification('Saved OAuth token!', 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
let hideInputToggleButton = document.body.querySelectorAll('.password-toggle-btn .password-toggle-icon .fa-eye-slash');
|
const hideInputToggleButton = document.body.querySelectorAll('.password-toggle-btn .password-toggle-icon .fa-eye-slash');
|
||||||
hideInputToggleButton.forEach((item) => {
|
hideInputToggleButton.forEach(item => {
|
||||||
item.addEventListener('click', () => {
|
item.addEventListener('click', () => {
|
||||||
if (item.classList.contains('fa-eye')) {
|
if (item.classList.contains('fa-eye')) {
|
||||||
item.classList.remove('fa-eye');
|
item.classList.remove('fa-eye');
|
||||||
|
|
@ -391,7 +409,7 @@ document.body.querySelector('#USE_MODULES').addEventListener('click', () => {
|
||||||
createNotification(
|
createNotification(
|
||||||
`${toggle ? 'Enabled' : 'Disabled'} server settings!, the service will stop working after restarting the application
|
`${toggle ? 'Enabled' : 'Disabled'} server settings!, the service will stop working after restarting the application
|
||||||
${toggle ? '' : ', the service will stop working after restarting the application'}`,
|
${toggle ? '' : ', the service will stop working after restarting the application'}`,
|
||||||
'success',
|
'success'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -403,7 +421,7 @@ document.body.querySelector('#USE_VTUBER').addEventListener('change', () => {
|
||||||
createNotification(
|
createNotification(
|
||||||
`${toggle ? 'Enabled' : 'Disabled'} Vtuber setting!
|
`${toggle ? 'Enabled' : 'Disabled'} Vtuber setting!
|
||||||
${toggle ? '' : ', the service will stop working after restarting the application'}`,
|
${toggle ? '' : ', the service will stop working after restarting the application'}`,
|
||||||
'success',
|
'success'
|
||||||
);
|
);
|
||||||
server.startVtuberModule();
|
server.startVtuberModule();
|
||||||
});
|
});
|
||||||
|
|
@ -486,7 +504,7 @@ document.body.querySelector('#USE_NOTIFICATION_SOUNDS').addEventListener('change
|
||||||
});
|
});
|
||||||
|
|
||||||
document.body.querySelector('#notificationVolume').addEventListener('change', () => {
|
document.body.querySelector('#notificationVolume').addEventListener('change', () => {
|
||||||
let element = document.body.querySelector('#notificationVolume');
|
const element = document.body.querySelector('#notificationVolume');
|
||||||
settings.AUDIO.NOTIFICATION_VOLUME = element.value;
|
settings.AUDIO.NOTIFICATION_VOLUME = element.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
||||||
|
|
@ -524,7 +542,7 @@ if (settings.AUDIO.NOTIFICATION_VOLUME) {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.querySelector('#ttsVolume').addEventListener('change', () => {
|
document.body.querySelector('#ttsVolume').addEventListener('change', () => {
|
||||||
let element = document.body.querySelector('#ttsVolume');
|
const element = document.body.querySelector('#ttsVolume');
|
||||||
settings.AUDIO.TTS_VOLUME = element.value;
|
settings.AUDIO.TTS_VOLUME = element.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
||||||
|
|
@ -562,7 +580,7 @@ if (settings.AUDIO.TTS_VOLUME) {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.body.querySelector('#ttsVolume').addEventListener('change', () => {
|
document.body.querySelector('#ttsVolume').addEventListener('change', () => {
|
||||||
let element = document.body.querySelector('#ttsVolume');
|
const element = document.body.querySelector('#ttsVolume');
|
||||||
settings.AUDIO.TTS_VOLUME = element.value;
|
settings.AUDIO.TTS_VOLUME = element.value;
|
||||||
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
|
||||||
|
|
@ -575,10 +593,10 @@ document.body.querySelector('#TestDefaultTTSButton').addEventListener('click', a
|
||||||
const text = document.getElementById('testPrimaryTTS').value;
|
const text = document.getElementById('testPrimaryTTS').value;
|
||||||
const requestData = {
|
const requestData = {
|
||||||
message: `user: ${text}`,
|
message: `user: ${text}`,
|
||||||
voice: settings.TTS.PRIMARY_VOICE,
|
voice: settings.TTS.PRIMARY_VOICE
|
||||||
};
|
};
|
||||||
let count = await backend.getInternalTTSAudio(requestData);
|
const count = await backend.getInternalTTSAudio(requestData);
|
||||||
let textObject = { filtered: text, formatted: text };
|
const textObject = { filtered: text, formatted: text };
|
||||||
sound.playAudio({ service: 'Internal', message: textObject, count });
|
sound.playAudio({ service: 'Internal', message: textObject, count });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -586,15 +604,89 @@ document.body.querySelector('#TestSecondaryTTSButton').addEventListener('click',
|
||||||
const text = document.getElementById('testSecondaryTTS').value;
|
const text = document.getElementById('testSecondaryTTS').value;
|
||||||
const requestData = {
|
const requestData = {
|
||||||
message: `user: ${text}`,
|
message: `user: ${text}`,
|
||||||
voice: settings.TTS.SECONDARY_VOICE,
|
voice: settings.TTS.SECONDARY_VOICE
|
||||||
};
|
};
|
||||||
|
|
||||||
let count = await backend.getInternalTTSAudio(requestData);
|
const count = await backend.getInternalTTSAudio(requestData);
|
||||||
let textObject = { filtered: text, formatted: text };
|
const textObject = { filtered: text, formatted: text };
|
||||||
|
|
||||||
sound.playAudio({ service: 'Internal', message: textObject, count });
|
sound.playAudio({ service: 'Internal', message: textObject, count });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Restricts input for the given textbox to the given inputFilter function.
|
||||||
|
function setInputFilter(textbox, inputFilter, errMsg) {
|
||||||
|
['input', 'keydown', 'keyup', 'mousedown', 'mouseup', 'select', 'contextmenu', 'drop', 'focusout'].forEach(function (event) {
|
||||||
|
textbox.addEventListener(event, function (e) {
|
||||||
|
if (inputFilter(this.value)) {
|
||||||
|
// Accepted value.
|
||||||
|
if (['keydown', 'mousedown', 'focusout'].indexOf(e.type) >= 0) {
|
||||||
|
this.classList.remove('input-error');
|
||||||
|
this.setCustomValidity('');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oldValue = this.value;
|
||||||
|
this.oldSelectionStart = this.selectionStart;
|
||||||
|
this.oldSelectionEnd = this.selectionEnd;
|
||||||
|
} else if (Object.prototype.hasOwnProperty.call(this, 'oldValue')) {
|
||||||
|
// Rejected value: restore the previous one.
|
||||||
|
this.classList.add('input-error');
|
||||||
|
this.setCustomValidity(errMsg);
|
||||||
|
this.reportValidity();
|
||||||
|
this.value = this.oldValue;
|
||||||
|
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
|
||||||
|
} else {
|
||||||
|
// Rejected value: nothing to restore.
|
||||||
|
this.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
webFrame.setVisualZoomLevelLimits(1, 5);
|
||||||
|
|
||||||
|
document.body.addEventListener('wheel', e => {
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
const currentZoom = webFrame.getZoomFactor();
|
||||||
|
const zoomIn = Boolean(e.deltaY < 0);
|
||||||
|
setZoomLevel(currentZoom, zoomIn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setInputFilter(
|
||||||
|
document.body.querySelector('#ZOOMLEVEL'),
|
||||||
|
function (value) {
|
||||||
|
return /^\d*\.?\d*$/.test(value); // Allow digits and '.' only, using a RegExp.
|
||||||
|
},
|
||||||
|
"Only digits and '.' are allowed"
|
||||||
|
);
|
||||||
|
|
||||||
|
document.body.querySelector('#ZOOMLEVEL').addEventListener('change', () => {
|
||||||
|
const newZoom = parseInt(document.body.querySelector('#ZOOMLEVEL').value) / 100;
|
||||||
|
settings.GENERAL.ZOOMLEVEL = newZoom;
|
||||||
|
fs.writeFileSync(settingsPath, ini.stringify(settings));
|
||||||
|
setZoomLevel(newZoom, null);
|
||||||
|
createNotification('Saved zoom new level', 'warning');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.querySelector('emoji-picker').addEventListener('emoji-click', e => {
|
||||||
|
console.log(e.detail);
|
||||||
|
const div = document.getElementById('textInput');
|
||||||
|
if (e.detail.unicode === undefined) {
|
||||||
|
div.value += e.detail.name + ' ';
|
||||||
|
} else {
|
||||||
|
div.value += e.detail.unicode + ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
div.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// #region Use Custom theme toggle logic
|
||||||
|
document.body.querySelector('#emojis').addEventListener('click', () => {
|
||||||
|
const emojiPicker = document.body.querySelector('#emoji-picker');
|
||||||
|
// console.log(emojiPicker);
|
||||||
|
emojiPicker.style.visibility === 'visible' ? (emojiPicker.style.visibility = 'hidden') : (emojiPicker.style.visibility = 'visible');
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getGeneralSettings,
|
getGeneralSettings
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,24 @@
|
||||||
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|
@ -25,15 +26,19 @@ const playTTS = (data) =>
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tts.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE)
|
tts
|
||||||
|
.setSinkId(settings.AUDIO.TTS_AUDIO_DEVICE)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('playing');
|
// console.log('playing');
|
||||||
tts.volume = settings.AUDIO.TTS_VOLUME / 100;
|
tts.volume = settings.AUDIO.TTS_VOLUME / 100;
|
||||||
tts.play().catch((error) => {
|
tts.play().catch(error => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
resolve('finished');
|
resolve('finished');
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
console.error('Failed to set audio output device:', error);
|
console.error('Failed to set audio output device:', error);
|
||||||
resolve('finished');
|
resolve('finished');
|
||||||
});
|
});
|
||||||
|
|
@ -56,11 +61,24 @@ function add(data) {
|
||||||
|
|
||||||
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,7 +93,7 @@ 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}`;
|
||||||
|
|
||||||
|
|
@ -93,15 +111,16 @@ async function playVoice(filteredMessage, logoUrl, username, message) {
|
||||||
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':
|
case 'Amazon':
|
||||||
// playAudio({ service: 'Amazon', message: textObject, count });
|
// playAudio({ service: 'Amazon', message: textObject, count });
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* 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;
|
||||||
|
|
@ -12,15 +14,11 @@ function setCurrentTheme(adjustTemp = false) {
|
||||||
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',
|
|
||||||
settings.THEME.CHAT_BUBBLE_HEADER,
|
|
||||||
adjustTemp ? '--chat-bubble-header-temp' : '--chat-bubble-header',
|
|
||||||
);
|
|
||||||
changeColor(
|
changeColor(
|
||||||
'#CHAT_BUBBLE_MESSAGE',
|
'#CHAT_BUBBLE_MESSAGE',
|
||||||
settings.THEME.CHAT_BUBBLE_MESSAGE,
|
settings.THEME.CHAT_BUBBLE_MESSAGE,
|
||||||
adjustTemp ? '--chat-bubble-message-temp' : '--chat-bubble-message',
|
adjustTemp ? '--chat-bubble-message-temp' : '--chat-bubble-message'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
/* 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);
|
||||||
|
|
@ -9,30 +12,30 @@ function sendMessage(message) {
|
||||||
|
|
||||||
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!';
|
||||||
});
|
});
|
||||||
|
|
@ -64,7 +67,7 @@ function displayTwitchMessage(logoUrl, username, messageObject, fileteredMessage
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -74,7 +77,7 @@ function displayTwitchMessage(logoUrl, username, messageObject, fileteredMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
@ -88,16 +91,16 @@ function getProfileImage(userid, username, message, fileteredMessage) {
|
||||||
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -125,20 +128,59 @@ client.on('message', (channel, tags, message, self) => {
|
||||||
}
|
}
|
||||||
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 };
|
||||||
|
|
|
||||||
42
src/main.js
42
src/main.js
|
|
@ -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');
|
||||||
|
|
@ -45,8 +47,8 @@ async function createWindow() {
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: false,
|
contextIsolation: false,
|
||||||
enableRemoteModule: true,
|
enableRemoteModule: true
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.loadFile(path.join(__dirname, 'index.html'));
|
window.loadFile(path.join(__dirname, 'index.html'));
|
||||||
|
|
@ -55,7 +57,7 @@ async function createWindow() {
|
||||||
window.webContents.openDevTools();
|
window.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.on('close', (e) => {
|
window.on('close', e => {
|
||||||
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); // load newest settings in case anything changed after starting the program
|
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); // load newest settings in case anything changed after starting the program
|
||||||
const bounds = window.getBounds();
|
const bounds = window.getBounds();
|
||||||
|
|
||||||
|
|
@ -72,7 +74,7 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
@ -93,12 +95,12 @@ ipcMain.on('resize-window', (event, width, height) => {
|
||||||
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()) {
|
||||||
|
|
@ -108,18 +110,18 @@ ipcMain.on('maximize-window', (event) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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 };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -136,32 +138,34 @@ async function createIniFile() {
|
||||||
PORT: 9000,
|
PORT: 9000,
|
||||||
VIEWERS_PANEL: false,
|
VIEWERS_PANEL: false,
|
||||||
LOCATION: pythonPath,
|
LOCATION: pythonPath,
|
||||||
|
ZOOMLEVEL: 1
|
||||||
},
|
},
|
||||||
LANGUAGE: {
|
LANGUAGE: {
|
||||||
USE_DETECTION: false,
|
USE_DETECTION: false
|
||||||
},
|
},
|
||||||
TTS: {
|
TTS: {
|
||||||
USE_TTS: true,
|
USE_TTS: true,
|
||||||
PRIMARY_VOICE: '',
|
PRIMARY_VOICE: '',
|
||||||
PRIMARY_TTS_LANGUAGE: 'EN',
|
PRIMARY_TTS_LANGUAGE: 'EN',
|
||||||
SECONDARY_VOICE: '',
|
SECONDARY_VOICE: '',
|
||||||
SECONDARY_TTS_LANGUAGE: 'EN',
|
SECONDARY_TTS_LANGUAGE: 'EN'
|
||||||
},
|
},
|
||||||
STT: {
|
STT: {
|
||||||
USE_STT: false,
|
USE_STT: false,
|
||||||
MICROPHONE_ID: 'default',
|
MICROPHONE_ID: 'default',
|
||||||
SELECTED_MICROPHONE: 'default',
|
SELECTED_MICROPHONE: 'default',
|
||||||
MICROPHONE: 0,
|
MICROPHONE: 0,
|
||||||
LANGUAGE: 'vosk-model-small-es-0.42',
|
LANGUAGE: 'vosk-model-small-es-0.42'
|
||||||
},
|
},
|
||||||
AUDIO: {
|
AUDIO: {
|
||||||
USE_NOTIFICATION_SOUNDS: true,
|
USE_NOTIFICATION_SOUNDS: true,
|
||||||
|
SELECTED_NOTIFICATION_AUDIO_DEVICE: 'default',
|
||||||
NOTIFICATION_AUDIO_DEVICE: 0,
|
NOTIFICATION_AUDIO_DEVICE: 0,
|
||||||
NOTIFICATION_SOUND: 0,
|
NOTIFICATION_SOUND: 0,
|
||||||
NOTIFICATION_VOLUME: 50,
|
NOTIFICATION_VOLUME: 50,
|
||||||
SELECTED_TTS_AUDIO_DEVICE: 0,
|
SELECTED_TTS_AUDIO_DEVICE: 0,
|
||||||
TTS_AUDIO_DEVICE: 'default',
|
TTS_AUDIO_DEVICE: 'default',
|
||||||
TTS_VOLUME: 50,
|
TTS_VOLUME: 50
|
||||||
},
|
},
|
||||||
THEME: {
|
THEME: {
|
||||||
USE_CUSTOM_THEME: false,
|
USE_CUSTOM_THEME: false,
|
||||||
|
|
@ -173,7 +177,7 @@ async function createIniFile() {
|
||||||
MID_SECTION: '#6b8578',
|
MID_SECTION: '#6b8578',
|
||||||
CHAT_BUBBLE_BG: '#447466',
|
CHAT_BUBBLE_BG: '#447466',
|
||||||
CHAT_BUBBLE_HEADER: '#ffffff',
|
CHAT_BUBBLE_HEADER: '#ffffff',
|
||||||
CHAT_BUBBLE_MESSAGE: '#b5b5b5',
|
CHAT_BUBBLE_MESSAGE: '#b5b5b5'
|
||||||
},
|
},
|
||||||
TWITCH: {
|
TWITCH: {
|
||||||
USE_TWITCH: false,
|
USE_TWITCH: false,
|
||||||
|
|
@ -182,12 +186,12 @@ async function createIniFile() {
|
||||||
USER_ID: '',
|
USER_ID: '',
|
||||||
USER_LOGO_URL: '',
|
USER_LOGO_URL: '',
|
||||||
OAUTH_TOKEN: '',
|
OAUTH_TOKEN: '',
|
||||||
CLIENT_ID: '2t206sj7rvtr1rutob3p627d13jch9',
|
CLIENT_ID: '2t206sj7rvtr1rutob3p627d13jch9'
|
||||||
},
|
},
|
||||||
MODULES: {
|
MODULES: {
|
||||||
USE_MODULES: false,
|
USE_MODULES: false,
|
||||||
USE_VTUBER: false,
|
USE_VTUBER: false,
|
||||||
USE_CHATBUBBLE: false,
|
USE_CHATBUBBLE: false
|
||||||
},
|
},
|
||||||
AMAZON: {
|
AMAZON: {
|
||||||
USE_AMAZON: false,
|
USE_AMAZON: false,
|
||||||
|
|
@ -195,15 +199,15 @@ async function createIniFile() {
|
||||||
ACCESS_SECRET: '',
|
ACCESS_SECRET: '',
|
||||||
PRIMARY_VOICE: '',
|
PRIMARY_VOICE: '',
|
||||||
SECONDARY_VOICE: '',
|
SECONDARY_VOICE: '',
|
||||||
CHARACTERS_USED: 0,
|
CHARACTERS_USED: 0
|
||||||
},
|
},
|
||||||
GOOGLE: {
|
GOOGLE: {
|
||||||
USE_GOOGLE: false,
|
USE_GOOGLE: false,
|
||||||
API_KEY: '',
|
API_KEY: '',
|
||||||
PRIMARY_VOICE: '',
|
PRIMARY_VOICE: '',
|
||||||
SECONDARY_VOICE: '',
|
SECONDARY_VOICE: '',
|
||||||
CHARACTERS_USED: 0,
|
CHARACTERS_USED: 0
|
||||||
},
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Chat</title>
|
<title>Chat</title>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ body {
|
||||||
.thomas {
|
.thomas {
|
||||||
position: relative;
|
position: relative;
|
||||||
float: center;
|
float: center;
|
||||||
display: inline-block;
|
/* display: inline-block; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.speechbubble {
|
.speechbubble {
|
||||||
|
|
@ -148,9 +148,9 @@ body {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
.message::after {
|
.message::after {
|
||||||
}
|
} */
|
||||||
|
|
||||||
.arrow {
|
.arrow {
|
||||||
content: '';
|
content: '';
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* global io */
|
||||||
|
|
||||||
// Connect to the Socket.IO server
|
// Connect to the Socket.IO server
|
||||||
const socket = io();
|
const socket = io();
|
||||||
|
|
||||||
|
|
@ -28,16 +30,16 @@ 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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -97,16 +99,16 @@ function displayTwitchMessage(logoUrl, username, messageObject) {
|
||||||
elements[0].remove();
|
elements[0].remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
article.addEventListener('animationend', (e) => {
|
article.addEventListener('animationend', e => {
|
||||||
if (e.animationName == 'fade-outx') {
|
if (e.animationName === 'fade-outx') {
|
||||||
article.remove();
|
article.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (elements.length > 1) {
|
if (elements.length > 1) {
|
||||||
elements[0].classList.add('fade-outxx');
|
elements[0].classList.add('fade-outxx');
|
||||||
elements[0].addEventListener('animationend', (e) => {
|
elements[0].addEventListener('animationend', e => {
|
||||||
if (e.animationName == 'fade-outxx') {
|
if (e.animationName === 'fade-outxx') {
|
||||||
elements[0].remove();
|
elements[0].remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +248,6 @@ button.motion {
|
||||||
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;
|
||||||
|
|
@ -311,7 +310,6 @@ button.motion {
|
||||||
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');
|
||||||
|
|
@ -380,7 +378,3 @@ button.motion::after {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
height: width(100%);
|
height: width(100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.popup {
|
|
||||||
/* box-shadow: 3px 3px 1px rgba(0, 0, 0, 0.692); */
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html window-frame="transparent">
|
<html window-frame="transparent">
|
||||||
<head>
|
<head>
|
||||||
<title>TransTube</title>
|
<title>TransTube</title>
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,7 @@ 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;
|
||||||
|
|
||||||
|
|
@ -137,10 +135,7 @@ function animateButton(button, animation = 'motionless') {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
||||||
|
|
@ -177,21 +172,13 @@ async function _cycleAnimations() {
|
||||||
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;
|
||||||
|
|
@ -203,26 +190,10 @@ function motionButtonEvent(evt) {
|
||||||
button.attributes.counter--;
|
button.attributes.counter--;
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = [
|
const color = ['white', '#9BCCD4', '#8087D6', '#AB65CF', '#E7FD5B', '#EC9F45', '#E24555'][mod(button.attributes.counter, 7)];
|
||||||
'white',
|
|
||||||
'#9BCCD4',
|
|
||||||
'#8087D6',
|
|
||||||
'#AB65CF',
|
|
||||||
'#E7FD5B',
|
|
||||||
'#EC9F45',
|
|
||||||
'#E24555',
|
|
||||||
][mod(button.attributes.counter, 7)];
|
|
||||||
button.style.variable('color', color);
|
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);
|
||||||
|
|
||||||
|
|
@ -238,7 +209,8 @@ function motionButtonEvent(evt) {
|
||||||
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/${
|
||||||
|
n > 600 ? 'open' : 'closed'
|
||||||
}.png')`;
|
}.png')`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -251,21 +223,16 @@ function mod(n, 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',
|
|
||||||
'.mouth-image.border-default:not(:first-of-type)',
|
|
||||||
(evt, el) => {
|
|
||||||
globalThis.CURRENT_BUTTON = el;
|
globalThis.CURRENT_BUTTON = el;
|
||||||
el.popup($('menu'));
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -279,9 +246,7 @@ function changeImage(evt, 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)
|
|
||||||
.join('-');
|
|
||||||
document.style.variable(which, `url('${filename}')`);
|
document.style.variable(which, `url('${filename}')`);
|
||||||
|
|
||||||
globalThis.CURRENT_BUTTON.classList.add('border-default');
|
globalThis.CURRENT_BUTTON.classList.add('border-default');
|
||||||
|
|
@ -289,11 +254,7 @@ function changeImage(evt, el) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(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);
|
||||||
|
|
||||||
|
|
@ -301,9 +262,7 @@ $(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)
|
|
||||||
.join('-');
|
|
||||||
document.style.variable(which, null);
|
document.style.variable(which, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ export default {
|
||||||
shakingMore,
|
shakingMore,
|
||||||
bouncy,
|
bouncy,
|
||||||
excited,
|
excited,
|
||||||
nervous,
|
nervous
|
||||||
};
|
};
|
||||||
|
|
||||||
function motionless(t) {
|
function motionless(t) {
|
||||||
|
|
@ -25,7 +25,7 @@ function _shake(t, amount, velocity) {
|
||||||
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))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
if (!Number.prototype.limit) {
|
if (!Number.prototype.limit) {
|
||||||
|
// eslint-disable-next-line no-extend-native
|
||||||
Number.prototype.limit = function (min, max) {
|
Number.prototype.limit = function (min, max) {
|
||||||
if (this < min) return min;
|
if (this < min) return min;
|
||||||
if (this > max) return max;
|
if (this > max) return max;
|
||||||
|
|
@ -7,8 +8,11 @@ if (!Number.prototype.limit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 minXY;
|
||||||
|
let maxX;
|
||||||
|
let maxY;
|
||||||
let dragging = false;
|
let dragging = false;
|
||||||
|
|
||||||
function screenBounds() {
|
function screenBounds() {
|
||||||
|
|
@ -38,10 +42,7 @@ function movableView(s, screenBound = false) {
|
||||||
|
|
||||||
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),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue