Lots of changes

This commit is contained in:
Khyretos 2024-10-13 22:21:59 +02:00
parent bc7beab074
commit da985d3e42
313 changed files with 45761 additions and 491 deletions

1
.gitignore vendored
View file

@ -110,3 +110,4 @@ src/config/twitch-emotes.json
dist/* dist/*
src/config/betterttv-emotes.json src/config/betterttv-emotes.json
test.py test.py
src/config/settings.json

View file

@ -34,17 +34,22 @@ from vosk import Model, KaldiRecognizer, SetLogLevel
SetLogLevel(-1) SetLogLevel(-1)
settings = configparser.ConfigParser() settings = None;
app = Flask(__name__) app = Flask(__name__)
if len(sys.argv) > 1: if len(sys.argv) > 1:
settingsPath = os.path.normpath(sys.argv[1]) settingsPath = os.path.normpath(sys.argv[1])
environment = sys.argv[2] environment = sys.argv[2]
q = queue.Queue() q = queue.Queue()
# gobal functions # gobal functions
def loadSettings():
with open(settingsPath, 'r') as file:
global settings
settings = json.load(file)
# classes # classes
class LanguageDetection: class LanguageDetection:
@ -135,8 +140,8 @@ class STT:
def stop_recognition(self): def stop_recognition(self):
self.is_running = False self.is_running = False
settings.read(settingsPath) loadSettings()
if settings["STT"]["USE_STT"] and bool(settings["STT"]["LANGUAGE"]): if settings["STT"]["USE_STT"] and settings["STT"]["LANGUAGE"] != '':
speech_recognition_service = STT() speech_recognition_service = STT()
@ -179,7 +184,7 @@ class TTS:
return [voice.name for voice in voices] return [voice.name for voice in voices]
settings.read(settingsPath) loadSettings()
if settings["TTS"]["USE_TTS"]: if settings["TTS"]["USE_TTS"]:
text_to_speech_service = TTS() text_to_speech_service = TTS()
@ -231,17 +236,17 @@ def get_language():
@app.route("/translate", methods=["POST"]) @app.route("/translate", methods=["POST"])
def get_translation(): def get_translation():
loadSettings()
request_data = request.json
message = request_data.get("message", "")
detectedLanguage = request_data.get("language", "")
try: try:
settings.read(settingsPath) # try:
request_data = request.json
message = request_data.get("message", "")
detectedLanguage = request_data.get("language", "")
try:
translated = MyMemoryTranslator( translated = MyMemoryTranslator(
source=detectedLanguage, target=settings["LANGUAGE"]["TRANSLATE_TO"] source=detectedLanguage, target=settings["LANGUAGE"]["TRANSLATE_TO"]
).translate(message) ).translate(message)
except Exception as e: # except Exception as e:
return jsonify({"error": str(e), "code":429 }), 429 # return jsonify({"error": str(e), "code":429 }), 429
except Exception as e: except Exception as e:
return jsonify({"error": str(e), "code":500 }), 500 return jsonify({"error": str(e), "code":500 }), 500
return jsonify({"translation": translated}), 200 return jsonify({"translation": translated}), 200
@ -276,7 +281,7 @@ def get_voices():
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) > 1: if len(sys.argv) > 1:
settings.read(settingsPath) loadSettings()
port = int(settings["GENERAL"]["PORT"]) port = int(settings["GENERAL"]["PORT"])
else: else:
environment = "dev" environment = "dev"

View file

@ -40,13 +40,16 @@
}, },
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@mediapipe/tasks-vision": "^0.10.12",
"axios": "^1.4.0", "axios": "^1.4.0",
"dlivetv-api": "^1.0.10",
"emoji-picker-element": "^1.21.0", "emoji-picker-element": "^1.21.0",
"express": "^4.18.2", "express": "^4.18.2",
"flag-icons": "^7.1.0", "flag-icons": "^7.1.0",
"ini": "^2.0.0", "ini": "^2.0.0",
"kill-process-by-name": "^1.0.5", "kill-process-by-name": "^1.0.5",
"node-google-tts-api": "^1.1.1", "node-google-tts-api": "^1.1.1",
"p5": "^1.9.2",
"querystring": "^0.2.1", "querystring": "^0.2.1",
"socket.io": "^4.7.1", "socket.io": "^4.7.1",
"socket.io-client": "^4.7.1", "socket.io-client": "^4.7.1",
@ -54,7 +57,8 @@
"tmi.js": "^1.8.5", "tmi.js": "^1.8.5",
"url": "^0.11.1", "url": "^0.11.1",
"winston": "^3.10.0", "winston": "^3.10.0",
"write-ini-file": "^4.0.1" "write-ini-file": "^4.0.1",
"youtube-chat": "^2.2.0"
}, },
"devDependencies": { "devDependencies": {
"@electron-forge/cli": "^6.2.1", "@electron-forge/cli": "^6.2.1",

View file

@ -297,12 +297,12 @@ h1 {
align-self: start; align-self: start;
} }
.post-time.sender { .post-time.sender {
padding: 5px 5px 0px 15px; padding: 5px 5px 5px 15px;
margin: 0px 0px 0px 50px; margin: 0px 0px 0px 50px;
} }
.post-time.user { .post-time.user {
padding: 5px 15px 0px 5px; padding: 5px 15px 5px 5px;
margin: 0px 50px 0px 0px; margin: 0px 50px 0px 0px;
} }
@ -573,3 +573,8 @@ h1 {
right: 18px; right: 18px;
top: -65px; top: -65px;
} }
.emote {
width: 28px;
height: 28px;
}

View file

@ -260,3 +260,15 @@ body {
unicode-range: U+1F1E6-1F1FF; unicode-range: U+1F1E6-1F1FF;
src: url(https://raw.githack.com/googlefonts/noto-emoji/main/fonts/NotoColorEmoji.ttf); src: url(https://raw.githack.com/googlefonts/noto-emoji/main/fonts/NotoColorEmoji.ttf);
} }
#drop-zone {
width: 300px;
height: 200px;
border: 2px dashed #ccc;
text-align: center;
padding: 20px;
margin: 20px auto;
}
#dropped-file {
font-weight: bold;
}

View file

@ -267,7 +267,37 @@ pop-content div {
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
} }
.network-select {
position: relative;
cursor: pointer;
}
.send-to-channel {
display: none;
position: absolute;
background-color: var(--main-color3);
top: calc(-50% - 3px);
border: 1px solid #444;
z-index: 1;
width: 107px;
}
send-to-channel div {
color: white;
text-decoration: none;
display: block;
}
send-to-channel div:hover {
backdrop-filter: invert(50%);
}
.network-select:hover .send-to-channel {
display: block;
backdrop-filter: invert(50%);
grid-template-columns: repeat(3, 1fr);
}
.language-select { .language-select {
padding: 5px;
position: relative; position: relative;
} }

View file

@ -0,0 +1,88 @@
.token-autocomplete-container {
display: inline-flex;
flex-wrap: wrap;
width: 300px;
}
.token-autocomplete-container,
.token-autocomplete-container * {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
}
.token-autocomplete-container .token-autocomplete-input {
color: var(--main-color2);
font-size: 16px;
line-height: 32px;
margin: 4px 2px;
padding: 0px 8px;
height: 40px;
width: 300px;
background-color: var(--main-color3);
border-radius: 20px;
}
.token-autocomplete-container .token-autocomplete-input:empty::before {
content: attr(data-placeholder);
color: gray;
}
.token-autocomplete-container .token-autocomplete-token {
font-size: 16px;
line-height: 32px;
background-color: var(--main-color3);
margin: 4px 2px;
border-radius: 32px;
padding: 0px 8px;
pointer-events: none;
}
.token-autocomplete-container .token-autocomplete-token:hover {
background-color: #ef9a9a;
}
.token-autocomplete-container .token-autocomplete-token .token-autocomplete-token-delete {
cursor: pointer;
font-size: 24px;
line-height: 16px;
margin-left: 4px;
pointer-events: auto;
border-radius: 50%;
height: 24px;
width: 24px;
display: inline-block;
text-align: center;
}
.token-autocomplete-container .token-autocomplete-token .token-autocomplete-token-delete:hover {
background-color: #e55858;
}
.token-autocomplete-container .token-autocomplete-suggestions {
display: none;
width: 100%;
list-style-type: none;
padding: 0px;
margin: 0px;
}
.token-autocomplete-container .token-autocomplete-suggestions li {
width: 100%;
padding: 8px;
cursor: pointer;
}
.token-autocomplete-container .token-autocomplete-suggestions li.token-autocomplete-suggestion-active {
color: #747474;
background-color: #fdfdfd;
}
.token-autocomplete-container .token-autocomplete-suggestions li.token-autocomplete-suggestion-highlighted {
background-color: #95caec;
}
.token-autocomplete-container .token-autocomplete-suggestions li .token-autocomplete-suggestion-description {
display: block;
font-size: 0.7em;
color: #808080;
}

BIN
src/images/dlive-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
src/images/dlive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

BIN
src/images/trovo-icon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
src/images/trovo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
src/images/youtube-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
src/images/youtube.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

View file

@ -17,6 +17,8 @@
<link rel="stylesheet" href="./css/tts-menu.css" /> <link rel="stylesheet" href="./css/tts-menu.css" />
<link rel="stylesheet" href="./css/volume-slider.css" /> <link rel="stylesheet" href="./css/volume-slider.css" />
<link rel="stylesheet" href="./css/sliders.css" /> <link rel="stylesheet" href="./css/sliders.css" />
<link rel="stylesheet" href="./css/token-autocomplete.css" />
<link <link
rel="stylesheet" rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
@ -76,15 +78,21 @@
<li class="item" tip="Chat Creator" id="btnChatCreator"> <li class="item" tip="Chat Creator" id="btnChatCreator">
<i class="fa-solid fa-spray-can"></i> <i class="fa-solid fa-spray-can"></i>
</li> </li>
<li class="item" tip="BrowserSource ChatBubble" id="btnBrowsersourceChat"> <li class="item" tip="BrowserSource ChatBubble" id="btnBrowsersourceChatBubble">
<i class="fa fa-history menu-icon"></i> <i class="fa fa-history menu-icon"></i>
</li> </li>
<li class="item" tip="BrowserSource Vtuber" id="btnBrowsersourceVtuber"> <li class="item" tip="BrowserSource Vtuber" id="btnBrowsersourceVtuber">
<i class="fa fa-user menu-icon"></i> <i class="fa-solid fa-address-card menu-icon"></i>
</li>
<li class="item" tip="BrowserSource PNGTuber" id="btnBrowsersourcePNGTuber">
<i class="fa-solid fa-image-portrait menu-icon"></i>
</li> </li>
<li class="item" tip="Logs" id="btnLogs"> <li class="item" tip="Logs" id="btnLogs">
<i class="fa fa-clipboard menu-icon"></i> <i class="fa fa-clipboard menu-icon"></i>
</li> </li>
<li class="item" tip="FaceMask" id="btnFaceMask">
<i class="fa-solid fa-masks-theater"></i>
</li>
<li class="item active-mic" tip="Info" id="btnConfiguration"> <li class="item active-mic" tip="Info" id="btnConfiguration">
<i class="fa-solid fa-microphone-lines"></i> <i class="fa-solid fa-microphone-lines"></i>
</li> </li>
@ -116,14 +124,42 @@
</div> </div>
<!--#endregion --> <!--#endregion -->
<!-- #region Commands Screen--> <!-- #region Chat-->
<div class="OptionPanel" id="BrowsersourceChat"></div> <div class="OptionPanel" id="BrowsersourceChatWindow"></div>
<!--#endregion --> <!--#endregion -->
<!-- #region Commands Screen--> <!-- #region ChatBubble-->
<div class="OptionPanel" id="BrowsersourceChatBubble"></div>
<!--#endregion -->
<!-- #region Vtuber-->
<div class="OptionPanel" id="BrowsersourceVtuber"></div> <div class="OptionPanel" id="BrowsersourceVtuber"></div>
<!--#endregion --> <!--#endregion -->
<!-- #region Vtuber-->
<div class="OptionPanel" id="BrowsersourcePNGTuber"></div>
<!--#endregion -->
<!-- #region FaceMask-->
<div class="OptionPanel" id="FaceMask">
<!-- <div class="select">
<label for="audioSource">Audio source: </label
><select id="audioSource"></select>
</div>
<div class="select">
<label for="videoSource">Video source: </label
><select id="videoSource"></select>
</div> -->
<!-- <video id="video" autoplay></video> -->
<div id="drop-zone">
<p>Drag a file here</p>
<p id="dropped-file"></p>
</div>
</div>
<!--#endregion -->
<!-- #region Configuration Screen--> <!-- #region Configuration Screen-->
<div class="OptionPanel" id="Configuration"> <div class="OptionPanel" id="Configuration">
<div id="tstx"> <div id="tstx">
@ -361,7 +397,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 class="fa-solid fa-key fa-2x SmallButton option-icon-container" id="Info_USERNAME" tip="Get OAuth Token"></i> <i class="fa-solid fa-key fa-2x SmallButton option-icon-container" id="Info_TWITCH_USERNAME" tip="Get OAuth Token"></i>
</div> </div>
<div class="AdvancedMenuRow inputTwitch"> <div class="AdvancedMenuRow inputTwitch">
<div class="AdvancedMenuLabel">Channel Name</div> <div class="AdvancedMenuLabel">Channel Name</div>
@ -381,6 +417,15 @@
tip="Test Twitch credentials" tip="Test Twitch credentials"
></i> ></i>
</div> </div>
<div class="AdvancedMenuRow inputTwitch">
<div class="AdvancedMenuLabel">BetterTTV Channels</div>
<div id="sample"></div>
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_BETTERTTV_CHANNELS"
tip="Insert the channel names of the betterTTV emotes you want"
></i>
</div>
<div class="AdvancedMenuRow inputTwitch"> <div class="AdvancedMenuRow inputTwitch">
<div class="AdvancedMenuLabel">Get BetterTTV emotes</div> <div class="AdvancedMenuLabel">Get BetterTTV emotes</div>
<button type="text" class="AdvancedMenuButton" id="GetBetterTtvEmotes"> <button type="text" class="AdvancedMenuButton" id="GetBetterTtvEmotes">
@ -394,6 +439,147 @@
</div> </div>
</fieldset> </fieldset>
<fieldset id="YoutubeMenu" class="AdvancedMenu">
<legend class="legendStyle" tip="Enable/Disable Youtube">
<img class="AdvancedMenuIcon" src="./images/youtube.png" alt=" " />
<input type="checkbox" id="USE_YOUTUBE" class="checkbox" />
<label for="USE_YOUTUBE" class="toggle-small"></label>
<div class="AdvancedMenuLabel3">Enable Youtube</div>
</legend>
<!-- <div class="AdvancedMenuRow inputYoutube">
<div class="AdvancedMenuLabel">API Key</div>
<input
type="password"
type2="text"
class="fname inputYoutube"
id="YOUTUBE_OAUTH_TOKEN"
placeholder="click the key icon to get the OAuth token"
/>
<button class="password-toggle-btn password-toggle-btn2">
<span class="password-toggle-icon"><i class="fa-regular fa-eye-slash"></i></span>
</button>
<i class="fa-solid fa-key fa-2x SmallButton option-icon-container" id="Info_YOUTUBE_USERNAME" tip="Get OAuth Token"></i>
</div> -->
<div class="AdvancedMenuRow inputYoutube">
<div class="AdvancedMenuLabel">Channel Handle</div>
<input type="text" class="fname inputYoutube" id="YOUTUBE_CHANNEL_HANDLE" />
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_YOUTUBE_CHANNEL_HANDLE"
tip="The channel you want to connect to"
></i>
</div>
<div class="AdvancedMenuRow inputYoutube">
<div class="AdvancedMenuLabel">Channel ID</div>
<input type="text" class="fname inputYoutube" id="YOUTUBE_CHANNEL_ID" />
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_YOUTUBE_CHANNEL_ID"
tip="The channel you want to connect to"
></i>
</div>
<div class="AdvancedMenuRow inputYoutube">
<div class="AdvancedMenuLabel">Live ID</div>
<input type="text" class="fname inputYoutube" id="YOUTUBE_LIVE_ID" />
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_YOUTUBE_LIVE_ID"
tip="The channel you want to connect to"
></i>
</div>
<div class="AdvancedMenuRow inputYoutube">
<div class="AdvancedMenuLabel">Test credentials</div>
<button type="text" class="AdvancedMenuButton" id="TestYoutubeCredentials">Test</button>
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_YOUTUBE_TEST_CREDENTIALS"
tip="Test Youtube credentials"
></i>
</div>
</fieldset>
<fieldset id="TrovoMenu" class="AdvancedMenu">
<legend class="legendStyle" tip="Enable/Disable Trovo">
<img class="AdvancedMenuIcon" src="./images/trovo.png" alt=" " />
<input type="checkbox" id="USE_TROVO" class="checkbox" />
<label for="USE_TROVO" class="toggle-small"></label>
<div class="AdvancedMenuLabel3">Enable Trovo</div>
</legend>
<div class="AdvancedMenuRow inputTrovo">
<div class="AdvancedMenuLabel">Oauth Token</div>
<input
type="password"
type2="text"
class="fname inputTrovo"
id="TROVO_OAUTH_TOKEN"
placeholder="click the key icon to get the OAuth token"
/>
<button class="password-toggle-btn password-toggle-btn2">
<span class="password-toggle-icon"><i class="fa-regular fa-eye-slash"></i></span>
</button>
<i class="fa-solid fa-key fa-2x SmallButton option-icon-container" id="Info_TROVO_USERNAME" tip="Get OAuth Token"></i>
</div>
<div class="AdvancedMenuRow inputTrovo">
<div class="AdvancedMenuLabel">Channel Name</div>
<input type="text" class="fname inputTrovo" id="TROVO_CHANNEL_NAME" />
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_TROVO_CHANNEL_NAME"
tip="The channel you want to connect to"
></i>
</div>
<div class="AdvancedMenuRow inputTrovo">
<div class="AdvancedMenuLabel">Test credentials</div>
<button type="text" class="AdvancedMenuButton" id="TestTrovoCredentials">Test</button>
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_TROVO_TEST_CREDENTIALS"
tip="Test Trovo credentials"
></i>
</div>
</fieldset>
<fieldset id="DLiveMenu" class="AdvancedMenu">
<legend class="legendStyle" tip="Enable/Disable DLive">
<img class="AdvancedMenuIcon" src="./images/dlive.png" alt=" " />
<input type="checkbox" id="USE_DLIVE" class="checkbox" />
<label for="USE_DLIVE" class="toggle-small"></label>
<div class="AdvancedMenuLabel3">Enable DLive</div>
</legend>
<div class="AdvancedMenuRow inputDLive">
<div class="AdvancedMenuLabel">API Key</div>
<input
type="password"
type2="text"
class="fname inputDLive"
id="DLIVE_OAUTH_TOKEN"
placeholder="click the key icon to get the OAuth token"
/>
<button class="password-toggle-btn password-toggle-btn2">
<span class="password-toggle-icon"><i class="fa-regular fa-eye-slash"></i></span>
</button>
<i class="fa-solid fa-key fa-2x SmallButton option-icon-container" id="Info_DLIVE_USERNAME" tip="Get OAuth Token"></i>
</div>
<div class="AdvancedMenuRow inputDLive">
<div class="AdvancedMenuLabel">Channel Name</div>
<input type="text" class="fname inputDLive" id="DLIVE_CHANNEL_NAME" />
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_DLIVE_CHANNEL_NAME"
tip="The channel you want to connect to"
></i>
</div>
<div class="AdvancedMenuRow inputDLive">
<div class="AdvancedMenuLabel">Test credentials</div>
<button type="text" class="AdvancedMenuButton" id="TestDLiveCredentials">Test</button>
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_DLIVE_TEST_CREDENTIALS"
tip="Test DLive credentials"
></i>
</div>
</fieldset>
<fieldset id="AdvancedMenuServer" class="AdvancedMenu"> <fieldset id="AdvancedMenuServer" class="AdvancedMenu">
<legend class="legendStyle" tip="Enable/Disable Server"> <legend class="legendStyle" tip="Enable/Disable Server">
<img class="AdvancedMenuIcon" src="./images/server.png" alt /> <img class="AdvancedMenuIcon" src="./images/server.png" alt />
@ -401,8 +587,8 @@
<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" style="height: 0; visibility: hidden"> <div class="AdvancedMenuRow inputServer">
<div class="AdvancedMenuLabel">Use PNGtuber</div> <div class="AdvancedMenuLabel">PNGtuber</div>
<input type="checkbox" id="USE_PNGTUBER" class="checkbox" /> <input type="checkbox" id="USE_PNGTUBER" class="checkbox" />
<label for="USE_PNGTUBER" class="toggle-small"></label> <label for="USE_PNGTUBER" class="toggle-small"></label>
<input type="url" type2="text" class="fname inputServer" id="PNGTUBER_URL" /> <input type="url" type2="text" class="fname inputServer" id="PNGTUBER_URL" />
@ -413,7 +599,7 @@
></i> ></i>
</div> </div>
<div class="AdvancedMenuRow inputServer"> <div class="AdvancedMenuRow inputServer">
<div class="AdvancedMenuLabel">Use Vtuber</div> <div class="AdvancedMenuLabel">Vtuber</div>
<input type="checkbox" id="USE_VTUBER" class="checkbox" /> <input type="checkbox" id="USE_VTUBER" class="checkbox" />
<label for="USE_VTUBER" class="toggle-small"></label> <label for="USE_VTUBER" class="toggle-small"></label>
<input type="url" type2="text" class="fname inputServer" id="VTUBER_URL" /> <input type="url" type2="text" class="fname inputServer" id="VTUBER_URL" />
@ -424,17 +610,35 @@
></i> ></i>
</div> </div>
<div class="AdvancedMenuRow inputServer"> <div class="AdvancedMenuRow inputServer">
<div class="AdvancedMenuLabel">Use ChatBubble</div> <div class="AdvancedMenuLabel">external Chat window</div>
<input type="checkbox" id="USE_CHATWINDOW" class="checkbox" />
<label for="USE_CHATWINDOW" class="toggle-small"></label>
<input type="url" type2="text" class="fname inputServer" id="CHATWINDOW_URL" />
<i
class="fa fa-question-circle fa-2x SmallButton option-icon-container"
id="Info_CHATWINDOW"
tip="You can use it as a browsersource on http://localhost:PORT/chat"
></i>
</div>
<div class="AdvancedMenuRow inputServer">
<div class="AdvancedMenuLabel">ChatBubble</div>
<input type="checkbox" id="USE_CHATBUBBLE" class="checkbox" /> <input type="checkbox" id="USE_CHATBUBBLE" class="checkbox" />
<label for="USE_CHATBUBBLE" class="toggle-small"></label> <label for="USE_CHATBUBBLE" class="toggle-small"></label>
<input type="url" type2="text" class="fname inputServer" id="CHATBUBBLE_URL" /> <input type="url" type2="text" class="fname inputServer" id="CHATBUBBLE_URL" />
<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_CHATBUBBLE" id="Info_CHATBUBBLE"
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/chatbubble"
></i> ></i>
</div> </div>
<div class="AdvancedMenuRow inputServer" style="height: 0; visibility: hidden"> <div class="AdvancedMenuRow inputServer">
<div class="AdvancedMenuLabel">FaceMask</div>
<input type="checkbox" id="USE_FACEMASK" class="checkbox" />
<label for="USE_FACEMASK" class="toggle-small"></label>
<input type="url" type2="text" class="fname inputServer" id="FACEMASK_URL" />
<i class="fa fa-question-circle fa-2x SmallButton option-icon-container" id="Info_FACEMASK" tip="WIP"></i>
</div>
<!-- <div class="AdvancedMenuRow inputServer" style="height: 0; visibility: hidden">
<div class="AdvancedMenuLabel">Use Finger</div> <div class="AdvancedMenuLabel">Use Finger</div>
<input type="checkbox" id="USE_CHATBUBBLE" class="checkbox" /> <input type="checkbox" id="USE_CHATBUBBLE" class="checkbox" />
<label for="USE_CHATBUBBLE" class="toggle-small"></label> <label for="USE_CHATBUBBLE" class="toggle-small"></label>
@ -444,7 +648,7 @@
id="Info_CHATBUBBLE" id="Info_CHATBUBBLE"
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> -->
</fieldset> </fieldset>
<fieldset id="AdvancedMenuAmazon" class="AdvancedMenu" style="height: 0; visibility: hidden"> <fieldset id="AdvancedMenuAmazon" class="AdvancedMenu" style="height: 0; visibility: hidden">
@ -622,6 +826,12 @@
<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" />
<!-- Send button--> <!-- Send button-->
<div class="network-select">
<button class="SmallButton">
<i class="fa-brands fa-stack-exchange fa-2x" aria-hidden="true"></i>
</button>
<div class="send-to-channel" id="SEND_TO_CHANNELS"></div>
</div>
<button class="SmallButton" id="SendButton"> <button class="SmallButton" id="SendButton">
<i class="fa fa-play-circle fa-2x" aria-hidden="true"></i> <i class="fa fa-play-circle fa-2x" aria-hidden="true"></i>
</button> </button>

View file

@ -1,10 +1,10 @@
/* global settings,twitch, fs, settingsPath, ini, shell, options, axios */ /* global settings,twitch,trovo, 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', 'user:read:follows', 'user:read:subscriptions']; const scopes = ['chat:edit', 'chat:read', 'user:read:follows', 'user:read:subscriptions', 'channel:read:redemptions'];
const express = require('express'); const express = require('express');
const tempAuthServer = express(); const tempAuthServer = express();
@ -13,55 +13,53 @@ const twitchAuthentication = () =>
const { parse: parseQueryString } = require('querystring'); const { parse: parseQueryString } = require('querystring');
tempAuthServer.use(function (req, res, next) { tempAuthServer.use(function (req, res, next) {
console.log('1');
if (req.url !== '/auth') { if (req.url !== '/auth') {
console.log(req.url);
const token = parseQueryString(req.query.auth); const token = parseQueryString(req.query.auth);
console.log(req);
console.log(token);
settings.TWITCH.OAUTH_TOKEN = token['#access_token']; settings.TWITCH.OAUTH_TOKEN = token['#access_token'];
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
resolve(token['#access_token']); resolve(token['#access_token']);
stopServer(); stopServer();
} else {
res.send(htmlString);
} }
next();
}); });
const htmlString = ` const htmlString = `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Authentication</title> <title>Authentication</title>
</head> </head>
<body> <body>
<h1>Authentication successful! You can close this window now.</h1> <h1>Authentication successful! You can close this window now.</h1>
<form name="auth" "action="auth" method="get" > <form name="auth" "action="auth" method="get" >
<input type="text" id="auth" name="auth"/> <input type="text" id="auth" name="auth"/>
</form> </form>
</body> </body>
</html> <script>
<script>
function onSubmitComplete() { function onSubmitComplete() {
close(); close();
} }
document.querySelector("#auth").style.display="none"; document.querySelector("#auth").style.display="none";
document.querySelector("#auth").value = document.location.hash; document.querySelector("#auth").value = document.location.hash;
document.auth.submit(); document.auth.submit();
setTimeout(onSubmitComplete, 500); setTimeout(onSubmitComplete, 500);
</script> </script>
</html>
`; `;
tempAuthServer.get('/auth', (req, res) => { console.log('-1');
res.send(htmlString);
});
tempAuthServer.post('/auth', (req, res) => {
res.render('authentication', { name: req.body.name });
});
const server = http.createServer(tempAuthServer); const server = http.createServer(tempAuthServer);
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);
}); });
@ -73,9 +71,60 @@ const twitchAuthentication = () =>
function getTwitchOauthToken() { function getTwitchOauthToken() {
return twitchAuthentication().then(res => { return twitchAuthentication().then(res => {
twitch.getTwitchUserId(); twitch.getTwitchUserId();
// twitch.getTwitchChannelId();
return res; return res;
}); });
} }
module.exports = { getTwitchOauthToken }; const trovoAuthentication = () =>
new Promise(resolve => {
const http = require('http');
const redirectUri = 'http://localhost:1989/auth';
const scopes = ['user_details_self', 'chat_send_self', 'send_to_my_channel', 'manage_messages'];
const express = require('express');
const tempAuthServer = express();
const port = 1989;
tempAuthServer.use(function (req, res) {
res.send(htmlString);
const token = req.query.access_token;
settings.TROVO.OAUTH_TOKEN = token;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
resolve(token);
stopServer();
});
const htmlString = `
<!DOCTYPE html>
<html>
<head>
<title>Authentication</title>
</head>
<body>
<h1>Authentication successful! You can close this window now.</h1>
</body>
</html>
`;
const server = http.createServer(tempAuthServer);
server.listen(port, () => {
const authURL = `https://open.trovo.live/page/login.html?client_id=${
settings.TROVO.CLIENT_ID
}&response_type=token&scope=${scopes.join('+')}&redirect_uri=${encodeURIComponent(redirectUri)}`;
const lol = shell.openExternal(authURL);
});
function stopServer() {
server.close(() => {});
}
});
function getTrovoOAuthToken() {
return trovoAuthentication().then(res => {
trovo.getTrovoUserId();
return res;
});
}
module.exports = { getTwitchOauthToken, getTrovoOAuthToken };

View file

@ -75,12 +75,12 @@ function setTranslatedUserMessage(message) {
function setTranslatedMessage(message) { function setTranslatedMessage(message) {
// this determines if it is a message that is send by a user // this determines if it is a message that is send by a user
const languageBox = document.getElementById(message.messageId).getElementsByClassName('language-icon flag-icon')[0]; const languageBox = document.getElementById(message.messageId).getElementsByClassName('language-icon flag-icon')[0];
if (!languageBox) { // if (false) {
twitch.sendMessage( // twitch.sendMessage(
`[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${message.username}: ${message.translation}` // `[${message.language.detectedLanguage.name} ${message.language.detectedLanguage.ISO639} > ${message.language.selectedLanguage.name} ${message.language.selectedLanguage.ISO639}] @${settings.TWITCH.USERNAME}: ${message.translation}`
); // );
return setTranslatedUserMessage(message); // return setTranslatedUserMessage(message);
} // }
if (message.language.selectedLanguage.ISO639 !== message.language.detectedLanguage.ISO639) { if (message.language.selectedLanguage.ISO639 !== message.language.detectedLanguage.ISO639) {
const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0]; const messageBox = document.getElementById(message.messageId).getElementsByClassName('msg-box')[0];
@ -106,9 +106,14 @@ function setTranslatedMessage(message) {
translationMessage.className = 'translation-message'; translationMessage.className = 'translation-message';
translationMessage.innerText = message.translation; translationMessage.innerText = message.translation;
messageBox.appendChild(translationMessage); messageBox.appendChild(translationMessage);
showChatMessage(); // showChatMessage();
const messages = document.body.querySelectorAll('.msg-container');
const lastMessage = messages[messages.length - 1];
lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' });
} }
console.log(message);
if (settings.LANGUAGE.OUTPUT_TO_TTS) { if (settings.LANGUAGE.OUTPUT_TO_TTS) {
sound.playVoice({ sound.playVoice({
originalMessage: message.originalMessage, originalMessage: message.originalMessage,
@ -123,6 +128,9 @@ function setTranslatedMessage(message) {
} }
async function getTranslatedMessage(message) { async function getTranslatedMessage(message) {
// TODO: translate primary language to
console.log(message);
console.log(message.isPrimaryLanguage ? message.language.selectedLanguage.IETF : message.language.detectedLanguage.IETF);
const requestOptions = { const requestOptions = {
method: 'POST', // HTTP method method: 'POST', // HTTP method
headers: { headers: {
@ -130,7 +138,7 @@ async function getTranslatedMessage(message) {
}, },
body: JSON.stringify({ body: JSON.stringify({
message: message.message, message: message.message,
language: message.language.detectedLanguage.IETF language: message.isPrimaryLanguage ? message.language.selectedLanguage.IETF : message.language.detectedLanguage.IETF
}) // Convert the data to JSON and include it in the request body }) // Convert the data to JSON and include it in the request body
}; };
@ -226,11 +234,15 @@ async function filterLanguage(message) {
} }
const language = selectedPrimaryLanguageIndex < selectedSecondaryLanguageIndex ? selectedPrimaryLanguage : detectedLanguage; const language = selectedPrimaryLanguageIndex < selectedSecondaryLanguageIndex ? selectedPrimaryLanguage : detectedLanguage;
if (settings.LANGUAGE.TRANSLATE_TO !== 'none' && selectedPrimaryLanguage.ISO639 !== detectedLanguage.ISO639) {
if (settings.LANGUAGE.TRANSLATE_TO !== 'none' && selectedPrimaryLanguage.ISO639 !== language.ISO639) {
// console.log('1');
console.log('hola');
getTranslatedMessage({ getTranslatedMessage({
message: message.message, message: message.message,
messageId: message.messageId, messageId: message.messageId,
remainingDetectedLanguages, remainingDetectedLanguages,
isPrimaryLanguage: false,
language: { language: {
selectedLanguage: selectedPrimaryLanguage, selectedLanguage: selectedPrimaryLanguage,
detectedLanguage: detectedLanguage detectedLanguage: detectedLanguage
@ -240,6 +252,8 @@ async function filterLanguage(message) {
logoUrl: message.logoUrl logoUrl: message.logoUrl
}); });
} else { } else {
console.log('adios');
// console.log('2');
setTranslatedMessage({ setTranslatedMessage({
originalMessage: message.message, originalMessage: message.message,
translation: message.message, translation: message.message,
@ -252,6 +266,19 @@ async function filterLanguage(message) {
username: message.username, username: message.username,
logoUrl: message.logoUrl logoUrl: message.logoUrl
}); });
// getTranslatedMessage({
// message: message.message,
// messageId: message.messageId,
// remainingDetectedLanguages: [],
// isPrimaryLanguage: true,
// language: {
// selectedLanguage: selectedSecondaryLanguage,
// detectedLanguage: selectedPrimaryLanguage
// },
// username: message.username,
// formattedMessage: message.formattedMessage,
// logoUrl: message.logoUrl
// });
} }
return language; return language;

View file

@ -70,7 +70,7 @@ const replaceChatMessageWithCustomEmojis = message =>
if (word !== '') { if (word !== '') {
await emojiPicker.database.getEmojiByUnicodeOrName(word).then(data => { await emojiPicker.database.getEmojiByUnicodeOrName(word).then(data => {
if (data && data.name === word) { if (data && data.name === word) {
const url = `<img src="${data.url}">`; const url = `<img class="emote" src="${data.url}" >`;
message = message.replace(word, url); message = message.replace(word, url);
} }
}); });
@ -144,8 +144,10 @@ const displayPanel = (panelSelectorClass, panelSelectorID, btnSelectorID) => {
displayPanel('.OptionPanel', '#Configuration', '#btnConfiguration'); displayPanel('.OptionPanel', '#Configuration', '#btnConfiguration');
displayPanel('.OptionPanel', '#Logs', '#btnLogs'); displayPanel('.OptionPanel', '#Logs', '#btnLogs');
displayPanel('.OptionPanel', '#BrowsersourceChat', '#btnBrowsersourceChat'); displayPanel('.OptionPanel', '#BrowsersourceChatBubble', '#btnBrowsersourceChatBubble');
displayPanel('.OptionPanel', '#BrowsersourceVtuber', '#btnBrowsersourceVtuber'); displayPanel('.OptionPanel', '#BrowsersourceVtuber', '#btnBrowsersourceVtuber');
displayPanel('.OptionPanel', '#BrowsersourcePNGTuber', '#btnBrowsersourcePNGTuber');
displayPanel('.OptionPanel', '#FaceMask', '#btnFaceMask');
displayPanel('.OptionPanel', '#Chat', '#btnChat'); displayPanel('.OptionPanel', '#Chat', '#btnChat');
displayPanel('.OptionPanel', '#ThemeCreator', '#btnThemeCreator'); displayPanel('.OptionPanel', '#ThemeCreator', '#btnThemeCreator');
displayPanel('.OptionPanel', '#ChatCreator', '#btnChatCreator'); displayPanel('.OptionPanel', '#ChatCreator', '#btnChatCreator');
@ -175,8 +177,10 @@ const displayPanelX = (panelSelectorClass, panelSelectorID, btnSelectorID) => {
}; };
displayPanelX('.item', '#btnChat', '#btnChat'); displayPanelX('.item', '#btnChat', '#btnChat');
displayPanelX('.item', '#btnBrowsersourceChat', '#btnBrowsersourceChat'); displayPanelX('.item', '#btnBrowsersourceChatBubble', '#btnBrowsersourceChatBubble');
displayPanelX('.item', '#btnBrowsersourceVtuber', '#btnBrowsersourceVtuber'); displayPanelX('.item', '#btnBrowsersourceVtuber', '#btnBrowsersourceVtuber');
displayPanelX('.item', '#btnBrowsersourcePNGTuber', '#btnBrowsersourcePNGTuber');
displayPanelX('.item', '#btnFaceMask', '#btnFaceMask');
displayPanelX('.item', '#btnLogs', '#btnLogs'); displayPanelX('.item', '#btnLogs', '#btnLogs');
displayPanelX('.item', '#btnConfiguration', '#btnConfiguration'); displayPanelX('.item', '#btnConfiguration', '#btnConfiguration');
displayPanelX('.item', '#btnThemeCreator', '#btnThemeCreator'); displayPanelX('.item', '#btnThemeCreator', '#btnThemeCreator');

102
src/js/dlive.js Normal file
View file

@ -0,0 +1,102 @@
/* global settings, bot,settingsPath, fs, ini, messageId, showChatMessage, messageTemplates, chat, addSingleTooltip,getPostTime */
const Dlive = require('dlivetv-api');
const bot = new Dlive(settings.DLIVE.API_KEY);
function setTrovoSendButton() {
const languageSelectContent = document.querySelector('.send-to-channel');
const option = document.createElement('div');
option.classList = 'language-select';
const checkbox = document.createElement('input');
checkbox.classList = 'checkbox';
checkbox.type = 'checkbox';
checkbox.id = 'SEND_CHAT_DLIVE';
option.appendChild(checkbox);
const label = document.createElement('label');
label.classList = 'toggle-small';
option.setAttribute('for', 'SEND_CHAT_DLIVE');
checkbox.checked = settings.TROVO.SEND_CHAT;
option.appendChild(label);
const network = document.createElement('img');
network.src = './images/dlive.png';
network.classList = 'emote';
option.appendChild(network);
option.addEventListener('click', () => {
checkbox.checked = !checkbox.checked;
settings.TROVO.SEND_CHAT = checkbox.checked;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
});
languageSelectContent.appendChild(option);
}
setTrovoSendButton();
bot.on('ChatText', message => {
// console.log(`[${msg.sender.displayname}]: ${msg.content}`);
displayDLiveMessage(message);
});
// bot.sendMessage('test').then(console.log).catch(console.log);
bot.on('ChatGift', msg => {
console.log(`${msg.sender.displayname} donated ${msg.amount} ${msg.gift}'s`);
});
bot.on('ChatHost', msg => {
console.log(`${msg.sender.displayname} coming in with that ${msg.viewer} viewer host!`);
});
bot.on('ChatFollow', msg => {
console.log(`New follower! ${msg.sender.displayname} has joined the party!`);
});
async function displayDLiveMessage(message) {
messageId++;
const article = document.createElement('article');
article.className = 'msg-container sender';
article.setAttribute('id', messageId);
article.innerHTML = messageTemplates.dliveTemplate;
const userImg = article.querySelector('.user-img');
if (userImg) {
userImg.src = message.sender.avatar;
userImg.setAttribute('tip', '');
}
addSingleTooltip(userImg);
const usernameHtml = article.querySelector('.username');
if (usernameHtml) {
usernameHtml.innerText = message.sender.displayname;
}
const postTime = article.querySelector('.post-time');
if (postTime) {
postTime.innerText = getPostTime();
}
article.appendChild(postTime);
const formattedMessage = article.querySelector('.msg-box');
if (formattedMessage) {
formattedMessage.innerHTML = message.content;
// message.message.forEach(entry => {
// if (entry.text) {
// formattedMessage.innerHTML += entry.text;
// } else {
// formattedMessage.innerHTML += `<img src="${entry.url}"/>`;
// }
// });
}
await chat.replaceChatMessageWithCustomEmojis(formattedMessage.innerHTML).then(data => {
formattedMessage.innerHTML = data;
showChatMessage(article);
});
}

View file

@ -1,6 +1,30 @@
const twitchTemplate = ` const twitchTemplate = `
<img class="user-img" src="" /> <img class="user-img" src="" />
<img class="status-circle sender" src="./images/twitch-icon.png" tip="twitch" /> <img class="status-circle sender" src="./images/twitch-icon.png" tip="Twitch" />
<span class="post-time sender"></span>
<span class="username sender"></span>
<div class="msg-box sender"></div>
`.trim();
const trovoTemplate = `
<img class="user-img" src="" />
<img class="status-circle sender" src="./images/trovo-icon.jpg" tip="Trovo" />
<span class="post-time sender"></span>
<span class="username sender"></span>
<div class="msg-box sender"></div>
`.trim();
const youtubeTemplate = `
<img class="user-img" src="" />
<img class="status-circle sender" src="./images/youtube-icon.png" tip="Youtube" />
<span class="post-time sender"></span>
<span class="username sender"></span>
<div class="msg-box sender"></div>
`.trim();
const dliveTemplate = `
<img class="user-img" src="" />
<img class="status-circle sender" src="./images/dlive-icon.png" tip="DLive" />
<span class="post-time sender"></span> <span class="post-time sender"></span>
<span class="username sender"></span> <span class="username sender"></span>
<div class="msg-box sender"></div> <div class="msg-box sender"></div>
@ -24,4 +48,4 @@ const messageTemplate = `
</article> </article>
`.trim(); `.trim();
module.exports = { twitchTemplate, userTemplate, messageTemplate }; module.exports = { twitchTemplate, dliveTemplate, youtubeTemplate, userTemplate, messageTemplate, trovoTemplate };

View file

@ -1,10 +1,10 @@
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
const fs = require('fs'); const fs = require('fs');
const ini = require('ini'); const path = require('path');
const path = require('path'); // get directory path
const axios = require('axios'); const axios = require('axios');
const Sockette = require('sockette');
const { webFrame, ipcRenderer, shell } = require('electron'); // necessary electron libraries to send data to the app const { webFrame, ipcRenderer, shell } = require('electron');
const io = require('socket.io-client'); const io = require('socket.io-client');
const GoogleTTS = require('node-google-tts-api'); const GoogleTTS = require('node-google-tts-api');
@ -23,12 +23,8 @@ const settings = main.settings;
const googleVoices = fs.readFileSync(path.join(__dirname, './config/googleVoices.txt')).toString().split('\r\n'); const googleVoices = fs.readFileSync(path.join(__dirname, './config/googleVoices.txt')).toString().split('\r\n');
// TODO: remove amazon voices txt and use api instead (sakura project has it) // TODO: remove amazon voices txt and use api instead (sakura project has it)
const amazonVoices = fs.readFileSync(path.join(__dirname, './config/amazonVoices.txt')).toString().split('\r\n'); const amazonVoices = fs.readFileSync(path.join(__dirname, './config/amazonVoices.txt')).toString().split('\r\n');
const twitchEmoteListSavePath = const customEmotesListSavePath =
main.isPackaged === true ? path.join(resourcesPath, './twitch-emotes.json') : path.join(resourcesPath, './config/twitch-emotes.json'); main.isPackaged === true ? path.join(resourcesPath, './custom-emotes.json') : path.join(resourcesPath, './config/custom-emotes.json');
const betterTtvEmoteListSavePath =
main.isPackaged === true
? path.join(resourcesPath, './betterttv-emotes.json')
: path.join(resourcesPath, './config/betterttv-emotes.json');
// html elements // html elements
const root = document.documentElement; const root = document.documentElement;
@ -51,6 +47,17 @@ const languageObject = require(path.join(__dirname, './js/languages'));
const logger = require(path.join(__dirname, './js/logger')); const logger = require(path.join(__dirname, './js/logger'));
const sound = require(path.join(__dirname, './js/sound')); const sound = require(path.join(__dirname, './js/sound'));
const config = require(path.join(__dirname, './js/settings')); const config = require(path.join(__dirname, './js/settings'));
const { TokenAutocomplete } = require(path.join(__dirname, './js/token-autocomplete'));
const betterTTVAutocomplete = new TokenAutocomplete({
name: 'sample',
selector: '#sample',
noMatchesText: 'No matching results...',
initialTokens: [...settings.TWITCH.BETTERTTV_CHANNELS]
});
const test = settings.TWITCH.BETTERTTV_CHANNELS;
console.log(test);
const mediaDevices = require(path.join(__dirname, './js/mediaDevices')); const mediaDevices = require(path.join(__dirname, './js/mediaDevices'));
@ -67,6 +74,16 @@ const socket = io(`http://localhost:${settings.GENERAL.PORT}`); // Connect to yo
let twitch = null; let twitch = null;
twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './js/twitch')) : ''; twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './js/twitch')) : '';
let dlive = null;
dlive = settings.DLIVE.USE_DLIVE ? require(path.join(__dirname, './js/dlive')) : '';
let youtube = null;
youtube = settings.YOUTUBE.USE_YOUTUBE ? require(path.join(__dirname, './js/youtube')) : '';
let trovo = null;
trovo = settings.TROVO.USE_TROVO ? require(path.join(__dirname, './js/trovo')) : '';
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')) : '';
@ -79,6 +96,7 @@ let customEmojis = [];
customEmojis = []; customEmojis = [];
let messageId = 0; let messageId = 0;
messageId = 0; messageId = 0;
let customEmojiList = [];
// initialize values // initialize values
config.getGeneralSettings(); config.getGeneralSettings();
@ -191,7 +209,7 @@ function setLanguagesinSelectx(languageSelector, language) {
settings.LANGUAGE.SEND_TRANSLATION_OUT = language.IETF; settings.LANGUAGE.SEND_TRANSLATION_OUT = language.IETF;
} }
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
setSelectedLanguageinSelect(languageSelect, language); setSelectedLanguageinSelect(languageSelect, language);
}); });
@ -327,14 +345,27 @@ Array.from(document.body.querySelectorAll('[tip]')).forEach(el => {
}); });
function showChatMessage(article) { function showChatMessage(article) {
let body = null;
if (article !== undefined) { if (article !== undefined) {
document.querySelector('#chatBox').appendChild(article); body = document.getElementById('chatBox');
body.appendChild(article);
} }
const messages = document.body.querySelectorAll('.msg-container'); const messages = document.body.querySelectorAll('.msg-container');
const lastMessage = messages[messages.length - 1]; const lastMessage = messages[messages.length - 1];
lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' }); lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' });
// const messageId = article.id;
// languageElement.setAttribute('id', article.id);
// console.log(article);
const username = article.querySelector('.username').innerHTML;
const image = article.querySelector('.user-img').src;
const statusCircle = article.querySelector('.status-circle').src;
const message = article.querySelector('.msg-box').innerHTML;
const postTime = article.querySelector('.post-time').innerHTML;
socket.emit('chat-out', { messageId, username, image, statusCircle, message, postTime });
} }
function getPostTime() { function getPostTime() {
@ -370,6 +401,7 @@ function hideText(button, field) {
} }
hideText('.password-toggle-btn1', '#TWITCH_OAUTH_TOKEN'); hideText('.password-toggle-btn1', '#TWITCH_OAUTH_TOKEN');
hideText('.password-toggle-btn2', '#TROVO_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');
@ -386,28 +418,10 @@ function setZoomLevel(currentZoom, zoomIn) {
webFrame.setZoomFactor(parseFloat(newZoom)); webFrame.setZoomFactor(parseFloat(newZoom));
settings.GENERAL.ZOOMLEVEL = newZoom; settings.GENERAL.ZOOMLEVEL = newZoom;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
document.body.querySelector('#ZOOMLEVEL').value = (settings.GENERAL.ZOOMLEVEL * 100).toFixed(0); document.body.querySelector('#ZOOMLEVEL').value = (settings.GENERAL.ZOOMLEVEL * 100).toFixed(0);
} }
// TODO: refactor
let twitchEmotes = null;
if (fs.existsSync(twitchEmoteListSavePath)) {
const xxx = fs.readFileSync(twitchEmoteListSavePath);
twitchEmotes = JSON.parse(xxx);
emojiPicker.customEmoji = [...twitchEmotes];
}
let betterTtvEmotes = null;
if (fs.existsSync(betterTtvEmoteListSavePath)) {
const xxx = fs.readFileSync(betterTtvEmoteListSavePath);
betterTtvEmotes = JSON.parse(xxx);
emojiPicker.customEmoji = [...betterTtvEmotes];
}
if (twitchEmotes && betterTtvEmotes) {
emojiPicker.customEmoji = [...twitchEmotes, ...betterTtvEmotes];
}
function getLanguageProperties(languageToDetect) { function getLanguageProperties(languageToDetect) {
try { try {
const filteredLanguage = Object.keys(languageObject.languages).reduce(function (accumulator, currentValue) { const filteredLanguage = Object.keys(languageObject.languages).reduce(function (accumulator, currentValue) {
@ -434,3 +448,132 @@ function getLanguageProperties(languageToDetect) {
return 'error'; return 'error';
} }
} }
let customEmotes = null;
if (fs.existsSync(customEmotesListSavePath)) {
const file = fs.readFileSync(customEmotesListSavePath);
customEmotes = JSON.parse(file);
customEmojiList = [...customEmojiList, ...customEmotes];
}
emojiPicker.customEmoji = customEmojiList;
function saveCustomEmotesToFile(emotes) {
const data = JSON.stringify(emotes);
customEmojiList = [...customEmojiList, data];
const savePath =
main.isPackaged === true ? path.join(resourcesPath, './custom-emotes.json') : path.join(resourcesPath, './config/custom-emotes.json');
fs.writeFile(savePath, data, error => {
if (error) {
console.error(error);
throw error;
}
});
}
function countWords(str) {
return str.trim().split(/\s+/).length;
}
// function saveSettingsToFile(settings) {
// const data = JSON.stringify(settings);
// const savePath =
// main.isPackaged === true ? path.join(resourcesPath, './settings.json') : path.join(resourcesPath, './config/settings.json');
// fs.writeFile(savePath, data, error => {
// if (error) {
// console.error(error);
// throw error;
// }
// });
// }
/*
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// var videoElement = document.querySelector('video');
// var audioSelect = document.querySelector('select#audioSource');
// var videoSelect = document.querySelector('select#videoSource');
// audioSelect.onchange = getStream;
// videoSelect.onchange = getStream;
// getStream().then(getDevices).then(gotDevices);
// function getDevices() {
// // AFAICT in Safari this only gets default devices until gUM is called :/
// return navigator.mediaDevices.enumerateDevices();
// }
// function gotDevices(deviceInfos) {
// window.deviceInfos = deviceInfos; // make available to console
// console.log('Available input and output devices:', deviceInfos);
// for (const deviceInfo of deviceInfos) {
// const option = document.createElement('option');
// option.value = deviceInfo.deviceId;
// if (deviceInfo.kind === 'audioinput') {
// option.text = deviceInfo.label || `Microphone ${audioSelect.length + 1}`;
// audioSelect.appendChild(option);
// } else if (deviceInfo.kind === 'videoinput') {
// option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`;
// videoSelect.appendChild(option);
// }
// }
// }
// function getStream() {
// if (window.stream) {
// window.stream.getTracks().forEach(track => {
// track.stop();
// });
// }
// const audioSource = audioSelect.value;
// const videoSource = videoSelect.value;
// const constraints = {
// audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
// video: { deviceId: videoSource ? { exact: videoSource } : undefined }
// };
// return navigator.mediaDevices.getUserMedia(constraints).then(gotStream).catch(handleError);
// }
// function gotStream(stream) {
// window.stream = stream; // make stream available to console
// audioSelect.selectedIndex = [...audioSelect.options].findIndex(option => option.text === stream.getAudioTracks()[0].label);
// videoSelect.selectedIndex = [...videoSelect.options].findIndex(option => option.text === stream.getVideoTracks()[0].label);
// videoElement.srcObject = stream;
// }
// function handleError(error) {
// console.error('Error: ', error);
// }
// const settingxs = {
// video: true
// };
// navigator.mediaDevices
// .getUserMedia(settingxs)
// .then(stream => {
// const video = document.getElementById('video');
// video.srcObject = stream;
// video.play();
// })
// .catch(err => {
// console.log(err);
// alert('Não há permissões para acessar a webcam.');
// });

View file

@ -28,14 +28,33 @@ function startVtuberModule() {
startVtuberModule(); startVtuberModule();
function startChatBubbleModule() { function startPNGtuberModule() {
if (!settings.MODULES.USE_PNGTUBER) {
return;
}
app.use('/pngtuber', express.static(path.join(__dirname, '../modules/pngtuber/')));
const pngtuber = document.body.querySelector('#BrowsersourcePNGTuber');
const pngtuberframe = document.createElement('iframe');
pngtuberframe.class = 'frame';
pngtuberframe.src = `http://localhost:${settings.GENERAL.PORT}/pngtuber`;
pngtuberframe.style.width = '100%';
pngtuberframe.style.height = '100%';
pngtuberframe.frameBorder = 0;
pngtuber.appendChild(pngtuberframe);
}
startPNGtuberModule();
function startChatWindowModule() {
if (!settings.MODULES.USE_CHATBUBBLE) { if (!settings.MODULES.USE_CHATBUBBLE) {
return; return;
} }
app.use('/chat', express.static(path.join(__dirname, '../modules/chat'))); app.use('/chat', express.static(path.join(__dirname, '../modules/chat')));
const chat = document.body.querySelector('#BrowsersourceChat'); const chat = document.body.querySelector('#BrowsersourceChatWindow');
const 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`;
@ -45,9 +64,26 @@ function startChatBubbleModule() {
chat.appendChild(chatframe); chat.appendChild(chatframe);
} }
startChatBubbleModule(); startChatWindowModule();
function startSTT() {} function startChatBubbleModule() {
if (!settings.MODULES.USE_CHATBUBBLE) {
return;
}
app.use('/chatbubble', express.static(path.join(__dirname, '../modules/chatbubble')));
const chatBubble = document.body.querySelector('#BrowsersourceChatBubble');
const chatBubbleFrame = document.createElement('iframe');
chatBubbleFrame.class = 'frame';
chatBubbleFrame.src = `http://localhost:${settings.GENERAL.PORT}/chatbubble`;
chatBubbleFrame.style.width = '100%';
chatBubbleFrame.style.height = '100%';
chatBubbleFrame.frameBorder = 0;
chatBubble.appendChild(chatBubbleFrame);
}
startChatBubbleModule();
// Middleware to conditionally serve routes // Middleware to conditionally serve routes
app.use((req, res, next) => { app.use((req, res, next) => {
@ -62,6 +98,7 @@ app.use((req, res, next) => {
localServer.listen(settings.GENERAL.PORT, () => { localServer.listen(settings.GENERAL.PORT, () => {
startVtuberModule(); startVtuberModule();
startChatWindowModule();
startChatBubbleModule(); startChatBubbleModule();
}); });
@ -69,6 +106,9 @@ localServer.listen(settings.GENERAL.PORT, () => {
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 => {});
socket.on('chat-out', message => {
socket.broadcast.emit('chat-in', message);
});
// Receive data from the client // Receive data from the client
socket.on('xxx', (logoUrl, username, message) => { socket.on('xxx', (logoUrl, username, message) => {
@ -78,4 +118,4 @@ io.on('connection', socket => {
socket.on('disconnect', () => {}); socket.on('disconnect', () => {});
}); });
module.exports = { startVtuberModule, startChatBubbleModule }; module.exports = { startVtuberModule, startChatBubbleModule, startChatWindowModule };

View file

@ -1,4 +1,4 @@
/* global settings,main sttModels, setZoomLevel, webFrame, theme, fs, settingsPath, ini, startVoiceRecognition,notificationSoundAudioDevices, ttsAudioDevices, notificationSound, path, resourcesPath, ipcRenderer, auth, shell, sound, twitch, server, backend */ /* global settings,main, betterTTVAutocomplete sttModels, trovo, 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
@ -30,14 +30,26 @@ function getGeneralSettings() {
document.body.querySelector('#TWITCH_CHANNEL_NAME').value = settings.TWITCH.CHANNEL_NAME; document.body.querySelector('#TWITCH_CHANNEL_NAME').value = settings.TWITCH.CHANNEL_NAME;
document.body.querySelector('#TWITCH_OAUTH_TOKEN').value = settings.TWITCH.OAUTH_TOKEN; document.body.querySelector('#TWITCH_OAUTH_TOKEN').value = settings.TWITCH.OAUTH_TOKEN;
// Trovo
document.body.querySelector('#USE_TROVO').checked = settings.TROVO.USE_TWITCH;
document.body.querySelector('#TROVO_CHANNEL_NAME').value = settings.TROVO.CHANNEL_NAME;
document.body.querySelector('#TROVO_OAUTH_TOKEN').value = settings.TROVO.OAUTH_TOKEN;
// Modules // Modules
document.body.querySelector('#USE_MODULES').checked = settings.MODULES.USE_MODULES; document.body.querySelector('#USE_MODULES').checked = settings.MODULES.USE_MODULES;
document.body.querySelector('#USE_VTUBER').checked = settings.MODULES.USE_VTUBER; document.body.querySelector('#USE_VTUBER').checked = settings.MODULES.USE_VTUBER;
document.body.querySelector('#VTUBER_URL').value = `http://localhost:${settings.GENERAL.PORT}/vtuber/`; document.body.querySelector('#VTUBER_URL').value = `http://localhost:${settings.GENERAL.PORT}/vtuber`;
showMenuButton('#btnBrowsersourceVtuber', settings.MODULES.USE_VTUBER); showMenuButton('#btnBrowsersourceVtuber', settings.MODULES.USE_VTUBER);
document.body.querySelector('#USE_PNGTUBER').checked = settings.MODULES.USE_PNGTUBER;
document.body.querySelector('#PNGTUBER_URL').value = `http://localhost:${settings.GENERAL.PORT}/pngtuber`;
showMenuButton('#btnBrowsersourcePNGTuber', settings.MODULES.USE_PNGTUBER);
document.body.querySelector('#USE_CHATBUBBLE').checked = settings.MODULES.USE_CHATBUBBLE; document.body.querySelector('#USE_CHATBUBBLE').checked = settings.MODULES.USE_CHATBUBBLE;
document.body.querySelector('#CHATBUBBLE_URL').value = `http://localhost:${settings.GENERAL.PORT}/chat/`; document.body.querySelector('#CHATBUBBLE_URL').value = `http://localhost:${settings.GENERAL.PORT}/chatbubble`;
showMenuButton('#btnBrowsersourceChat', settings.GENERAL.USE_CHATBUBBLE); document.body.querySelector('#USE_CHATWINDOW').checked = settings.MODULES.USE_CHATWINDOW;
document.body.querySelector('#CHATWINDOW_URL').value = `http://localhost:${settings.GENERAL.PORT}/chat`;
document.body.querySelector('#USE_FACEMASK').checked = settings.MODULES.USE_FACEMASK;
showMenuButton('#btnBrowsersourceChatBubble', settings.GENERAL.USE_CHATWINDOW);
showMenuButton('#btnFaceMask', settings.MODULES.USE_FACEMASK);
// Amazon // Amazon
document.body.querySelector('#USE_AMAZON').checked = settings.AMAZON.USE_AMAZON; document.body.querySelector('#USE_AMAZON').checked = settings.AMAZON.USE_AMAZON;
@ -52,35 +64,35 @@ function getGeneralSettings() {
document.body.querySelector('#primaryAmazonVoice').addEventListener('change', () => { document.body.querySelector('#primaryAmazonVoice').addEventListener('change', () => {
const 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, JSON.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', () => {
const 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, JSON.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', () => {
const 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, JSON.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', () => {
const 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, JSON.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', () => {
const 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, JSON.stringify(settings));
createNotification('Saved primary voice!', 'success'); createNotification('Saved primary voice!', 'success');
}); });
@ -88,7 +100,7 @@ document.body.querySelector('#microphone').addEventListener('change', () => {
const 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, JSON.stringify(settings));
createNotification('Saved microphone!', 'success'); createNotification('Saved microphone!', 'success');
startVoiceRecognition(); startVoiceRecognition();
}); });
@ -96,7 +108,7 @@ document.body.querySelector('#microphone').addEventListener('change', () => {
document.body.querySelector('#sttModel').addEventListener('change', () => { document.body.querySelector('#sttModel').addEventListener('change', () => {
const 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, JSON.stringify(settings));
createNotification('Saved voice detection language!', 'success'); createNotification('Saved voice detection language!', 'success');
}); });
@ -104,14 +116,14 @@ document.body.querySelector('#defaultLanguage').addEventListener('change', () =>
const 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].value; settings.TTS.PRIMARY_TTS_LANGUAGE = select.options[select.selectedIndex].value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved default language!', 'success'); createNotification('Saved default language!', 'success');
}); });
document.body.querySelector('#secondaryVoice').addEventListener('change', () => { document.body.querySelector('#secondaryVoice').addEventListener('change', () => {
const 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, JSON.stringify(settings));
createNotification('Saved secondary voice!', 'success'); createNotification('Saved secondary voice!', 'success');
}); });
@ -119,7 +131,7 @@ document.body.querySelector('#secondaryLanguage').addEventListener('change', ()
const 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].value; settings.TTS.SECONDARY_TTS_LANGUAGE = select.options[select.selectedIndex].value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved secondary language!', 'success'); createNotification('Saved secondary language!', 'success');
}); });
@ -127,7 +139,7 @@ document.body.querySelector('#language').addEventListener('change', () => {
const select = document.querySelector('#language'); const select = document.querySelector('#language');
settings.GENERAL.LANGUAGE_INDEX = select.selectedIndex; settings.GENERAL.LANGUAGE_INDEX = select.selectedIndex;
settings.GENERAL.LANGUAGE = select.options[select.selectedIndex].value; settings.GENERAL.LANGUAGE = select.options[select.selectedIndex].value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved language!', 'success'); createNotification('Saved language!', 'success');
}); });
@ -159,34 +171,56 @@ document.body.querySelector('#TRANSLATE_TO').addEventListener('change', () => {
settings.LANGUAGE.TRANSLATE_TO = select.options[select.selectedIndex].value; settings.LANGUAGE.TRANSLATE_TO = select.options[select.selectedIndex].value;
setTranslateToOptions(); setTranslateToOptions();
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved primary voice!', 'success'); createNotification('Saved primary voice!', 'success');
}); });
document.body.querySelector('#ttsAudioDevice').addEventListener('change', () => { document.body.querySelector('#ttsAudioDevice').addEventListener('change', () => {
settings.AUDIO.TTS_AUDIO_DEVICE = ttsAudioDevices.value; settings.AUDIO.TTS_AUDIO_DEVICE = ttsAudioDevices.value;
settings.AUDIO.SELECTED_TTS_AUDIO_DEVICE = ttsAudioDevices.selectedIndex; settings.AUDIO.SELECTED_TTS_AUDIO_DEVICE = ttsAudioDevices.selectedIndex;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved audio device!', 'success'); createNotification('Saved audio device!', 'success');
}); });
document.body.querySelector('#notificationSoundAudioDevice').addEventListener('change', () => { document.body.querySelector('#notificationSoundAudioDevice').addEventListener('change', () => {
settings.AUDIO.SELECTED_NOTIFICATION_AUDIO_DEVICE = notificationSoundAudioDevices.value; settings.AUDIO.SELECTED_NOTIFICATION_AUDIO_DEVICE = notificationSoundAudioDevices.value;
settings.AUDIO.NOTIFICATION_AUDIO_DEVICE = notificationSoundAudioDevices.selectedIndex; settings.AUDIO.NOTIFICATION_AUDIO_DEVICE = notificationSoundAudioDevices.selectedIndex;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved audio device!', 'success'); 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, JSON.stringify(settings));
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');
twitch.getTwitchChannelId(); if (settings.TWITCH.CHANNEL_NAME !== '') {
twitch.getTwitchChannelId(settings.TWITCH.CHANNEL_NAME).then(data => {
settings.TWITCH.CHANNEL_USER_ID = data;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Obtained channel info succesfully', 'success');
twitch.getUserAvailableTwitchEmotes();
});
}
});
document.body.querySelector('#TROVO_CHANNEL_NAME').addEventListener('change', () => {
settings.TROVO.CHANNEL_NAME = document.body.querySelector('#TROVO_CHANNEL_NAME').value;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved Channel name, please restart the application to reset twitch service', 'warning');
if (settings.TROVO.CHANNEL_NAME !== '') {
trovo.getTrovoChannelId();
}
}); });
document.body.querySelector('#TWITCH_OAUTH_TOKEN').addEventListener('change', () => { document.body.querySelector('#TWITCH_OAUTH_TOKEN').addEventListener('change', () => {
settings.TWITCH.OAUTH_TOKEN = document.body.querySelector('#TWITCH_OAUTH_TOKEN').value; settings.TWITCH.OAUTH_TOKEN = document.body.querySelector('#TWITCH_OAUTH_TOKEN').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved OAuth token, please restart the application to reset twitch service', 'warning');
});
document.body.querySelector('#TROVO_OAUTH_TOKEN').addEventListener('change', () => {
settings.TROVO.OAUTH_TOKEN = document.body.querySelector('#TROVO_OAUTH_TOKEN').value;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
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');
}); });
@ -200,31 +234,31 @@ setInputFilter(
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, JSON.stringify(settings));
createNotification('Saved port, please restart the application to reset the port', 'warning'); createNotification('Saved port, please restart the application to reset the port', 'warning');
}); });
document.body.querySelector('#AMAZON_ACCESS_KEY').addEventListener('change', () => { document.body.querySelector('#AMAZON_ACCESS_KEY').addEventListener('change', () => {
settings.AMAZON.ACCESS_KEY = document.body.querySelector('#AMAZON_ACCESS_KEY').value; settings.AMAZON.ACCESS_KEY = document.body.querySelector('#AMAZON_ACCESS_KEY').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved Amazon access key!', 'success'); createNotification('Saved Amazon access key!', 'success');
}); });
document.body.querySelector('#AMAZON_ACCESS_SECRET').addEventListener('change', () => { document.body.querySelector('#AMAZON_ACCESS_SECRET').addEventListener('change', () => {
settings.AMAZON.ACCESS_SECRET = document.body.querySelector('#AMAZON_ACCESS_SECRET').value; settings.AMAZON.ACCESS_SECRET = document.body.querySelector('#AMAZON_ACCESS_SECRET').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved Amazon access secret!', 'success'); createNotification('Saved Amazon access secret!', 'success');
}); });
document.body.querySelector('#GOOGLE_API_KEY').addEventListener('change', () => { document.body.querySelector('#GOOGLE_API_KEY').addEventListener('change', () => {
settings.GOOGLE.API_KEY = document.body.querySelector('#GOOGLE_API_KEY').value; settings.GOOGLE.API_KEY = document.body.querySelector('#GOOGLE_API_KEY').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved Google api key!', 'success'); createNotification('Saved Google api key!', 'success');
}); });
document.body.querySelector('#notification').addEventListener('change', () => { document.body.querySelector('#notification').addEventListener('change', () => {
settings.AUDIO.NOTIFICATION_SOUND = notificationSound.selectedIndex; settings.AUDIO.NOTIFICATION_SOUND = notificationSound.selectedIndex;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification('Saved notification sound!', 'success'); createNotification('Saved notification sound!', 'success');
}); });
@ -306,7 +340,7 @@ document.body.querySelector('#USE_CUSTOM_THEME').addEventListener('click', () =>
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
settings.THEME.USE_CUSTOM_THEME = toggle; settings.THEME.USE_CUSTOM_THEME = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
theme.setTheme(); theme.setTheme();
createNotification(`${toggle ? 'Enabled' : 'Disabled'} custom theme!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} custom theme!`, 'success');
}); });
@ -317,15 +351,27 @@ 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_TWITCH_USERNAME').addEventListener('click', async () => {
const 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();
twitch.checkIfTokenIsValid(); twitch.checkIfTokenIsValid();
createNotification('Saved OAuth token!', 'success'); createNotification('Saved OAuth token!', 'success');
}); });
document.body.querySelector('#Info_TROVO_USERNAME').addEventListener('click', async () => {
const element = document.body.querySelector('#TROVO_OAUTH_TOKEN');
element.value = await auth.getTrovoOAuthToken();
console.log(element.value);
// trovo.checkIfTokenIsValid();
createNotification('Saved OAuth token!', 'success');
});
document.body.querySelector('#GetBetterTtvEmotes').addEventListener('click', async () => { document.body.querySelector('#GetBetterTtvEmotes').addEventListener('click', async () => {
twitch.getBetterTtvGLobalEmotes(); twitch.getBetterTtvGLobalEmotes();
if (betterTTVAutocomplete.tokens.length !== 0) {
twitch.getBetterTtvChannelsEmotes();
}
createNotification('Saved BetterTTV emotes!', 'success'); createNotification('Saved BetterTTV emotes!', 'success');
}); });
@ -353,7 +399,7 @@ function hideOrShowViewerPanel() {
menu.classList.remove('collapse-menu-right'); menu.classList.remove('collapse-menu-right');
leftCircle.classList.remove('collapse-circle-right'); leftCircle.classList.remove('collapse-circle-right');
} }
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
} }
hideOrShowViewerPanel(); hideOrShowViewerPanel();
@ -368,11 +414,19 @@ document.body.querySelector('#VIEWERS_PANEL').addEventListener('click', () => {
}); });
document.body.querySelector('#Info_VTUBER').addEventListener('click', () => { document.body.querySelector('#Info_VTUBER').addEventListener('click', () => {
shell.openExternal(`http://localhost:${settings.GENERAL.PORT}/vtuber/`); shell.openExternal(`http://localhost:${settings.GENERAL.PORT}/vtuber`);
});
document.body.querySelector('#Info_PNGTUBER').addEventListener('click', () => {
shell.openExternal(`http://localhost:${settings.GENERAL.PORT}/pngtuber`);
}); });
document.body.querySelector('#Info_CHATBUBBLE').addEventListener('click', () => { document.body.querySelector('#Info_CHATBUBBLE').addEventListener('click', () => {
shell.openExternal(`http://localhost:${settings.GENERAL.PORT}/chat/`); shell.openExternal(`http://localhost:${settings.GENERAL.PORT}/chatbubble`);
});
document.body.querySelector('#Info_CHATWINDOW').addEventListener('click', () => {
shell.openExternal(`http://localhost:${settings.GENERAL.PORT}/chat`);
}); });
document.body.querySelector('#max-button').addEventListener('click', () => { document.body.querySelector('#max-button').addEventListener('click', () => {
@ -406,7 +460,7 @@ toggleTwitch();
document.body.querySelector('#USE_TWITCH').addEventListener('click', () => { document.body.querySelector('#USE_TWITCH').addEventListener('click', () => {
const toggle = document.getElementById('USE_TWITCH').checked; const toggle = document.getElementById('USE_TWITCH').checked;
settings.TWITCH.USE_TWITCH = toggle; settings.TWITCH.USE_TWITCH = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputTwitch'); const inputs = document.getElementsByClassName('inputTwitch');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './twitch')) : null; twitch = settings.TWITCH.USE_TWITCH ? require(path.join(__dirname, './twitch')) : null;
@ -424,7 +478,7 @@ toggleGoogle();
document.body.querySelector('#USE_GOOGLE').addEventListener('click', () => { document.body.querySelector('#USE_GOOGLE').addEventListener('click', () => {
const toggle = document.getElementById('USE_GOOGLE').checked; const toggle = document.getElementById('USE_GOOGLE').checked;
settings.GOOGLE.USE_GOOGLE = toggle; settings.GOOGLE.USE_GOOGLE = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputGoogle'); const inputs = document.getElementsByClassName('inputGoogle');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Google settings!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} Google settings!`, 'success');
@ -441,7 +495,7 @@ toggleAmazon();
document.body.querySelector('#USE_AMAZON').addEventListener('click', () => { document.body.querySelector('#USE_AMAZON').addEventListener('click', () => {
const toggle = document.getElementById('USE_AMAZON').checked; const toggle = document.getElementById('USE_AMAZON').checked;
settings.AMAZON.USE_AMAZON = toggle; settings.AMAZON.USE_AMAZON = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputAmazon'); const inputs = document.getElementsByClassName('inputAmazon');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Amazon settings!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} Amazon settings!`, 'success');
@ -458,7 +512,7 @@ toggleServer();
document.body.querySelector('#USE_MODULES').addEventListener('click', () => { document.body.querySelector('#USE_MODULES').addEventListener('click', () => {
const toggle = document.getElementById('USE_MODULES').checked; const toggle = document.getElementById('USE_MODULES').checked;
settings.MODULES.USE_MODULES = toggle; settings.MODULES.USE_MODULES = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputServer'); const inputs = document.getElementsByClassName('inputServer');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification( createNotification(
@ -471,7 +525,7 @@ document.body.querySelector('#USE_MODULES').addEventListener('click', () => {
document.body.querySelector('#USE_VTUBER').addEventListener('change', () => { document.body.querySelector('#USE_VTUBER').addEventListener('change', () => {
const toggle = document.getElementById('USE_VTUBER').checked; const toggle = document.getElementById('USE_VTUBER').checked;
settings.MODULES.USE_VTUBER = toggle; settings.MODULES.USE_VTUBER = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
showMenuButton('#btnBrowsersourceVtuber', toggle); showMenuButton('#btnBrowsersourceVtuber', toggle);
createNotification( createNotification(
`${toggle ? 'Enabled' : 'Disabled'} Vtuber setting! `${toggle ? 'Enabled' : 'Disabled'} Vtuber setting!
@ -481,11 +535,45 @@ document.body.querySelector('#USE_VTUBER').addEventListener('change', () => {
server.startVtuberModule(); server.startVtuberModule();
}); });
document.body.querySelector('#USE_PNGTUBER').addEventListener('change', () => {
const toggle = document.getElementById('USE_PNGTUBER').checked;
settings.MODULES.USE_PNGTUBER = toggle;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
showMenuButton('#btnBrowsersourcePNGTuber', toggle);
createNotification(
`${toggle ? 'Enabled' : 'Disabled'} PNGtuber setting!
${toggle ? '' : ', the service will stop working after restarting the application'}`,
'success'
);
server.startVtuberModule();
});
document.body.querySelector('#USE_FACEMASK').addEventListener('change', () => {
const toggle = document.getElementById('USE_FACEMASK').checked;
settings.MODULES.USE_FACEMASK = toggle;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
showMenuButton('#btnFaceMask', toggle);
createNotification(
`${toggle ? 'Enabled' : 'Disabled'} FaceMask setting!
${toggle ? '' : ', the service will stop working after restarting the application'}`,
'success'
);
// server.startVtuberModule();
});
document.body.querySelector('#USE_CHATWINDOW').addEventListener('change', () => {
const toggle = document.getElementById('USE_CHATWINDOW').checked;
settings.MODULES.USE_CHATWINDOW = toggle;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification(`${toggle ? 'Enabled' : 'Disabled'} chat window setting!`, 'success');
server.startChatWindowModule();
});
document.body.querySelector('#USE_CHATBUBBLE').addEventListener('change', () => { document.body.querySelector('#USE_CHATBUBBLE').addEventListener('change', () => {
const toggle = document.getElementById('USE_CHATBUBBLE').checked; const toggle = document.getElementById('USE_CHATBUBBLE').checked;
settings.MODULES.USE_CHATBUBBLE = toggle; settings.MODULES.USE_CHATBUBBLE = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
showMenuButton('#btnBrowsersourceChat', toggle); showMenuButton('#btnBrowsersourceChatBubble', toggle);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} chatbubble setting!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} chatbubble setting!`, 'success');
server.startChatBubbleModule(); server.startChatBubbleModule();
}); });
@ -501,7 +589,7 @@ toggleTTS();
document.body.querySelector('#USE_TTS').addEventListener('change', () => { document.body.querySelector('#USE_TTS').addEventListener('change', () => {
const toggle = document.getElementById('USE_TTS').checked; const toggle = document.getElementById('USE_TTS').checked;
settings.TTS.USE_TTS = toggle; settings.TTS.USE_TTS = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputTTS'); const inputs = document.getElementsByClassName('inputTTS');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} text to speech!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} text to speech!`, 'success');
@ -518,7 +606,7 @@ toggleSTT();
document.body.querySelector('#USE_STT').addEventListener('change', () => { document.body.querySelector('#USE_STT').addEventListener('change', () => {
const toggle = document.getElementById('USE_STT').checked; const toggle = document.getElementById('USE_STT').checked;
settings.STT.USE_STT = toggle; settings.STT.USE_STT = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputSTT'); const inputs = document.getElementsByClassName('inputSTT');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} speech to text!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} speech to text!`, 'success');
@ -535,7 +623,7 @@ toggleSendTranslation();
document.body.querySelector('#SEND_TRANSLATION').addEventListener('change', () => { document.body.querySelector('#SEND_TRANSLATION').addEventListener('change', () => {
const toggle = document.getElementById('SEND_TRANSLATION').checked; const toggle = document.getElementById('SEND_TRANSLATION').checked;
settings.LANGUAGE.SEND_TRANSLATION = toggle; settings.LANGUAGE.SEND_TRANSLATION = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('send-translation'); const inputs = document.getElementsByClassName('send-translation');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Sending translations!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} Sending translations!`, 'success');
@ -550,14 +638,14 @@ document.body.querySelector('#OUTPUT_TO_TTS').addEventListener('change', () => {
} }
settings.LANGUAGE.OUTPUT_TO_TTS = toggle; settings.LANGUAGE.OUTPUT_TO_TTS = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Outputting translations to TTS!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} Outputting translations to TTS!`, 'success');
}); });
document.body.querySelector('#BROADCAST_TRANSLATION').addEventListener('change', () => { document.body.querySelector('#BROADCAST_TRANSLATION').addEventListener('change', () => {
const toggle = document.getElementById('BROADCAST_TRANSLATION').checked; const toggle = document.getElementById('BROADCAST_TRANSLATION').checked;
settings.LANGUAGE.BROADCAST_TRANSLATION = toggle; settings.LANGUAGE.BROADCAST_TRANSLATION = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Language detection!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} Language detection!`, 'success');
}); });
@ -580,7 +668,7 @@ document.body.querySelector('#USE_DETECTION').addEventListener('change', () => {
document.body.querySelector('#OUTPUT_TO_TTS').checked = false; document.body.querySelector('#OUTPUT_TO_TTS').checked = false;
} }
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('languageDetectionInput'); const inputs = document.getElementsByClassName('languageDetectionInput');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} Language detection!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} Language detection!`, 'success');
@ -597,7 +685,7 @@ toggleNotificationSounds();
document.body.querySelector('#USE_NOTIFICATION_SOUNDS').addEventListener('change', () => { document.body.querySelector('#USE_NOTIFICATION_SOUNDS').addEventListener('change', () => {
const toggle = document.getElementById('USE_NOTIFICATION_SOUNDS').checked; const toggle = document.getElementById('USE_NOTIFICATION_SOUNDS').checked;
settings.AUDIO.USE_NOTIFICATION_SOUNDS = toggle; settings.AUDIO.USE_NOTIFICATION_SOUNDS = toggle;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
const inputs = document.getElementsByClassName('inputNotificationSound'); const inputs = document.getElementsByClassName('inputNotificationSound');
toggleRadio(toggle, inputs); toggleRadio(toggle, inputs);
createNotification(`${toggle ? 'Enabled' : 'Disabled'} notification sounds!`, 'success'); createNotification(`${toggle ? 'Enabled' : 'Disabled'} notification sounds!`, 'success');
@ -606,7 +694,7 @@ document.body.querySelector('#USE_NOTIFICATION_SOUNDS').addEventListener('change
document.body.querySelector('#notificationVolume').addEventListener('change', () => { document.body.querySelector('#notificationVolume').addEventListener('change', () => {
const 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, JSON.stringify(settings));
const slider = document.querySelector('#notificationVolumeSlider'); const slider = document.querySelector('#notificationVolumeSlider');
slider.value = settings.AUDIO.NOTIFICATION_VOLUME; slider.value = settings.AUDIO.NOTIFICATION_VOLUME;
@ -626,7 +714,7 @@ document.body.querySelector('#notificationVolumeSlider').addEventListener('chang
e.style.setProperty('--tiempotemporal', e.value); e.style.setProperty('--tiempotemporal', e.value);
document.querySelector('#notificationVolume').value = e.value; document.querySelector('#notificationVolume').value = e.value;
settings.AUDIO.NOTIFICATION_VOLUME = e.value; settings.AUDIO.NOTIFICATION_VOLUME = e.value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
}); });
}); });
@ -644,7 +732,7 @@ if (settings.AUDIO.NOTIFICATION_VOLUME) {
document.body.querySelector('#ttsVolume').addEventListener('change', () => { document.body.querySelector('#ttsVolume').addEventListener('change', () => {
const 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, JSON.stringify(settings));
const slider = document.querySelector('#ttsVolumeSlider'); const slider = document.querySelector('#ttsVolumeSlider');
slider.value = settings.AUDIO.TTS_VOLUME; slider.value = settings.AUDIO.TTS_VOLUME;
@ -664,7 +752,7 @@ document.body.querySelector('#ttsVolumeSlider').addEventListener('change', () =>
e.style.setProperty('--tiempotemporal', e.value); e.style.setProperty('--tiempotemporal', e.value);
document.querySelector('#ttsVolume').value = e.value; document.querySelector('#ttsVolume').value = e.value;
settings.AUDIO.TTS_VOLUME = e.value; settings.AUDIO.TTS_VOLUME = e.value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
}); });
}); });
@ -682,7 +770,7 @@ if (settings.AUDIO.TTS_VOLUME) {
document.body.querySelector('#ttsVolume').addEventListener('change', () => { document.body.querySelector('#ttsVolume').addEventListener('change', () => {
const 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, JSON.stringify(settings));
const slider = document.querySelector('#ttsVolumeSlider'); const slider = document.querySelector('#ttsVolumeSlider');
slider.value = settings.AUDIO.TTS_VOLUME; slider.value = settings.AUDIO.TTS_VOLUME;
@ -769,7 +857,7 @@ setInputFilter(
document.body.querySelector('#ZOOMLEVEL').addEventListener('change', () => { document.body.querySelector('#ZOOMLEVEL').addEventListener('change', () => {
const newZoom = parseInt(document.body.querySelector('#ZOOMLEVEL').value) / 100; const newZoom = parseInt(document.body.querySelector('#ZOOMLEVEL').value) / 100;
settings.GENERAL.ZOOMLEVEL = newZoom; settings.GENERAL.ZOOMLEVEL = newZoom;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
setZoomLevel(newZoom, null); setZoomLevel(newZoom, null);
createNotification('Saved zoom new level', 'warning'); createNotification('Saved zoom new level', 'warning');
}); });
@ -785,7 +873,6 @@ document.body.querySelector('emoji-picker').addEventListener('emoji-click', e =>
div.focus(); div.focus();
}); });
module.exports = { module.exports = {
getGeneralSettings, getGeneralSettings,
createNotification createNotification

View file

@ -101,7 +101,12 @@ async function playVoice(message) {
let voice = settings.TTS.PRIMARY_VOICE; let voice = settings.TTS.PRIMARY_VOICE;
textObject.filtered = `${message.username}: ${message.filteredMessage}`; textObject.filtered = `${message.username}: ${message.filteredMessage}`;
if (settings.LANGUAGE.USE_DETECTION && settings.TTS.SECONDARY_VOICE) { if (
settings.LANGUAGE.USE_DETECTION &&
settings.TTS.SECONDARY_VOICE &&
message.filteredMessage.length > 20 &&
countWords(message.filteredMessage) > 4
) {
const secondaryTTSLanguage = getLanguageProperties(settings.TTS.SECONDARY_TTS_LANGUAGE); const secondaryTTSLanguage = getLanguageProperties(settings.TTS.SECONDARY_TTS_LANGUAGE);
if (message.language.detectedLanguage === null || message.language.detectedLanguage.ISO639 === secondaryTTSLanguage.ISO639) { if (message.language.detectedLanguage === null || message.language.detectedLanguage.ISO639 === secondaryTTSLanguage.ISO639) {
voice = settings.TTS.SECONDARY_VOICE; voice = settings.TTS.SECONDARY_VOICE;

View file

@ -48,7 +48,7 @@ document.body.querySelector('#MAIN_COLOR_1').addEventListener('input', () => {
document.body.querySelector('#MAIN_COLOR_1').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_1').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_1 = document.getElementById('MAIN_COLOR_1').value; settings.THEME.MAIN_COLOR_1 = document.getElementById('MAIN_COLOR_1').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#MAIN_COLOR_1', settings.THEME.MAIN_COLOR_1, '--main-color1'); changeColor('#MAIN_COLOR_1', settings.THEME.MAIN_COLOR_1, '--main-color1');
}); });
@ -59,7 +59,7 @@ document.body.querySelector('#MAIN_COLOR_2').addEventListener('input', () => {
document.body.querySelector('#MAIN_COLOR_2').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_2').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_2 = document.getElementById('MAIN_COLOR_2').value; settings.THEME.MAIN_COLOR_2 = document.getElementById('MAIN_COLOR_2').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#MAIN_COLOR_2', settings.THEME.MAIN_COLOR_2, '--main-color2'); changeColor('#MAIN_COLOR_2', settings.THEME.MAIN_COLOR_2, '--main-color2');
}); });
@ -70,7 +70,7 @@ document.body.querySelector('#MAIN_COLOR_3').addEventListener('input', () => {
document.body.querySelector('#MAIN_COLOR_3').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_3').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_3 = document.getElementById('MAIN_COLOR_3').value; settings.THEME.MAIN_COLOR_3 = document.getElementById('MAIN_COLOR_3').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#MAIN_COLOR_3', settings.THEME.MAIN_COLOR_3, '--main-color3'); changeColor('#MAIN_COLOR_3', settings.THEME.MAIN_COLOR_3, '--main-color3');
}); });
@ -81,7 +81,7 @@ document.body.querySelector('#MAIN_COLOR_4').addEventListener('input', () => {
document.body.querySelector('#MAIN_COLOR_4').addEventListener('change', () => { document.body.querySelector('#MAIN_COLOR_4').addEventListener('change', () => {
settings.THEME.MAIN_COLOR_4 = document.getElementById('MAIN_COLOR_4').value; settings.THEME.MAIN_COLOR_4 = document.getElementById('MAIN_COLOR_4').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#MAIN_COLOR_4', settings.THEME.MAIN_COLOR_4, '--main-color4'); changeColor('#MAIN_COLOR_4', settings.THEME.MAIN_COLOR_4, '--main-color4');
}); });
@ -92,7 +92,7 @@ document.body.querySelector('#TOP_BAR').addEventListener('input', () => {
document.body.querySelector('#TOP_BAR').addEventListener('change', () => { document.body.querySelector('#TOP_BAR').addEventListener('change', () => {
settings.THEME.TOP_BAR = document.getElementById('TOP_BAR').value; settings.THEME.TOP_BAR = document.getElementById('TOP_BAR').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#TOP_BAR', settings.THEME.TOP_BAR, '--top-bar'); changeColor('#TOP_BAR', settings.THEME.TOP_BAR, '--top-bar');
}); });
@ -103,7 +103,7 @@ document.body.querySelector('#MID_SECTION').addEventListener('input', () => {
document.body.querySelector('#MID_SECTION').addEventListener('change', () => { document.body.querySelector('#MID_SECTION').addEventListener('change', () => {
settings.THEME.MID_SECTION = document.getElementById('MID_SECTION').value; settings.THEME.MID_SECTION = document.getElementById('MID_SECTION').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#MID_SECTION', settings.THEME.MID_SECTION, '--mid-section'); changeColor('#MID_SECTION', settings.THEME.MID_SECTION, '--mid-section');
}); });
@ -114,7 +114,7 @@ document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('input', () => {
document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('change', () => { document.body.querySelector('#CHAT_BUBBLE_BG').addEventListener('change', () => {
settings.THEME.CHAT_BUBBLE_BG = document.getElementById('CHAT_BUBBLE_BG').value; settings.THEME.CHAT_BUBBLE_BG = document.getElementById('CHAT_BUBBLE_BG').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#CHAT_BUBBLE_BG', settings.THEME.CHAT_BUBBLE_BG, '--chat-bubble'); changeColor('#CHAT_BUBBLE_BG', settings.THEME.CHAT_BUBBLE_BG, '--chat-bubble');
}); });
@ -125,7 +125,7 @@ document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('input', ()
document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('change', () => { document.body.querySelector('#CHAT_BUBBLE_HEADER').addEventListener('change', () => {
settings.THEME.CHAT_BUBBLE_HEADER = document.getElementById('CHAT_BUBBLE_HEADER').value; settings.THEME.CHAT_BUBBLE_HEADER = document.getElementById('CHAT_BUBBLE_HEADER').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#CHAT_BUBBLE_HEADER', settings.THEME.CHAT_BUBBLE_HEADER, '--chat-bubble-header'); changeColor('#CHAT_BUBBLE_HEADER', settings.THEME.CHAT_BUBBLE_HEADER, '--chat-bubble-header');
}); });
@ -136,7 +136,7 @@ document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('input', ()
document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('change', () => { document.body.querySelector('#CHAT_BUBBLE_MESSAGE').addEventListener('change', () => {
settings.THEME.CHAT_BUBBLE_MESSAGE = document.getElementById('CHAT_BUBBLE_MESSAGE').value; settings.THEME.CHAT_BUBBLE_MESSAGE = document.getElementById('CHAT_BUBBLE_MESSAGE').value;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
changeColor('#CHAT_BUBBLE_MESSAGE', settings.THEME.CHAT_BUBBLE_MESSAGE, '--chat-bubble-message'); changeColor('#CHAT_BUBBLE_MESSAGE', settings.THEME.CHAT_BUBBLE_MESSAGE, '--chat-bubble-message');
}); });

View file

@ -0,0 +1,392 @@
let __assign =
(this && this.__assign) ||
function () {
__assign =
Object.assign ||
function (t) {
for (let s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (const p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
let tokens = [];
const TokenAutocomplete = /** @class */ (function () {
function TokenAutocomplete(options) {
this.KEY_BACKSPACE = 8;
this.KEY_ENTER = 13;
this.KEY_UP = 38;
this.KEY_DOWN = 40;
this.tokens = tokens;
this.defaults = {
name: '',
selector: '',
noMatchesText: null,
initialTokens: null,
initialSuggestions: null,
suggestionsUri: '',
suggestionRenderer: TokenAutocomplete.Autocomplete.defaultRenderer,
minCharactersForSuggestion: 1
};
this.options = __assign(__assign({}, this.defaults), options);
const passedContainer = document.querySelector(this.options.selector);
if (!passedContainer) {
throw new Error('passed selector does not point to a DOM element.');
}
this.container = passedContainer;
this.container.classList.add('token-autocomplete-container');
if (!Array.isArray(this.options.initialTokens) && !Array.isArray(this.options.initialSuggestions)) {
this.parseTokensAndSuggestions();
}
this.hiddenSelect = document.createElement('select');
this.hiddenSelect.id = this.container.id + '-select';
this.hiddenSelect.name = this.options.name;
this.hiddenSelect.setAttribute('multiple', 'true');
this.hiddenSelect.style.display = 'none';
this.textInput = document.createElement('span');
this.textInput.id = this.container.id + '-input';
this.textInput.classList.add('token-autocomplete-input');
this.textInput.setAttribute('data-placeholder', 'Enter BetterTTV channel');
this.textInput.contentEditable = 'true';
this.container.appendChild(this.textInput);
this.container.appendChild(this.hiddenSelect);
this.select = new TokenAutocomplete.MultiSelect(this);
this.autocomplete = new TokenAutocomplete.Autocomplete(this);
this.debug(false);
const me = this;
if (Array.isArray(this.options.initialTokens)) {
this.options.initialTokens.forEach(function (token) {
if (typeof token === 'object') {
me.select.addToken(token.value, token.text);
}
});
}
this.textInput.addEventListener('keydown', function (event) {
if (event.which === me.KEY_ENTER || event.key === me.KEY_ENTER) {
event.preventDefault();
const highlightedSuggestion = me.autocomplete.suggestions.querySelector('.token-autocomplete-suggestion-highlighted');
if (highlightedSuggestion !== null) {
if (highlightedSuggestion.classList.contains('token-autocomplete-suggestion-active')) {
me.select.removeTokenWithText(highlightedSuggestion.textContent);
} else {
me.select.addToken(highlightedSuggestion.getAttribute('data-value'), highlightedSuggestion.textContent);
}
} else {
me.select.addToken(me.textInput.textContent, me.textInput.textContent);
}
me.clearCurrentInput();
} else if (me.textInput.textContent === '' && (event.which === me.KEY_BACKSPACE || event.key === me.KEY_BACKSPACE)) {
event.preventDefault();
// me.select.removeLastToken();
}
});
this.textInput.addEventListener('keyup', function (event) {
let _a, _b;
if ((event.which === me.KEY_UP || event.key === me.KEY_UP) && me.autocomplete.suggestions.childNodes.length > 0) {
const highlightedSuggestion = me.autocomplete.suggestions.querySelector('.token-autocomplete-suggestion-highlighted');
const aboveSuggestion = (_a = highlightedSuggestion) === null || _a === void 0 ? void 0 : _a.previousSibling;
if (aboveSuggestion != null) {
me.autocomplete.highlightSuggestion(aboveSuggestion);
}
return;
}
if ((event.which === me.KEY_DOWN || event.key === me.KEY_DOWN) && me.autocomplete.suggestions.childNodes.length > 0) {
const highlightedSuggestion = me.autocomplete.suggestions.querySelector('.token-autocomplete-suggestion-highlighted');
const belowSuggestion = (_b = highlightedSuggestion) === null || _b === void 0 ? void 0 : _b.nextSibling;
if (belowSuggestion != null) {
me.autocomplete.highlightSuggestion(belowSuggestion);
}
return;
}
me.autocomplete.hideSuggestions();
me.autocomplete.clearSuggestions();
const value = me.textInput.textContent || '';
if (value.length >= me.options.minCharactersForSuggestion) {
if (Array.isArray(me.options.initialSuggestions)) {
me.options.initialSuggestions.forEach(function (suggestion) {
if (typeof suggestion !== 'object') {
// the suggestion is of wrong type and therefore ignored
return;
}
if (value.localeCompare(suggestion.text.slice(0, value.length), undefined, { sensitivity: 'base' }) === 0) {
// The suggestion starts with the query text the user entered and will be displayed
me.autocomplete.addSuggestion(suggestion);
}
});
if (me.autocomplete.suggestions.childNodes.length > 0) {
me.autocomplete.highlightSuggestionAtPosition(0);
} else if (me.options.noMatchesText) {
me.autocomplete.addSuggestion({ value: '_no_match_', text: me.options.noMatchesText, description: null });
}
} else if (me.options.suggestionsUri.length > 0) {
me.autocomplete.requestSuggestions(value);
}
}
});
this.container.tokenAutocomplete = this;
}
/**
* Searches the element given as a container for option elements and creates active tokens (when the option is marked selected)
* and suggestions (all options found) from these. During this all found options are removed from the DOM.
*/
TokenAutocomplete.prototype.parseTokensAndSuggestions = function () {
const initialTokens = [];
const initialSuggestions = [];
const options = this.container.querySelectorAll('option');
const me = this;
options.forEach(function (option) {
if (option.text != null) {
if (option.hasAttribute('selected')) {
initialTokens.push({ value: option.value, text: option.text });
}
initialSuggestions.push({ value: option.value, text: option.text, description: null });
}
me.container.removeChild(option);
});
if (initialTokens.length > 0) {
this.options.initialTokens = initialTokens;
}
if (initialSuggestions.length > 0) {
this.options.initialSuggestions = initialSuggestions;
}
};
/**
* Clears the currently present tokens and creates new ones from the given input value.
*
* @param {(Array\|string)} value - either the name of a single token or a list of tokens to create
*/
TokenAutocomplete.prototype.val = function (value) {
this.select.clear();
if (Array.isArray(value)) {
const me1 = this;
value.forEach(function (token) {
if (typeof token === 'object') {
me1.select.addToken(token.value, token.text);
}
});
} else {
this.select.addToken(value.value, value.text);
}
};
TokenAutocomplete.prototype.clearCurrentInput = function () {
this.textInput.textContent = '';
};
TokenAutocomplete.prototype.debug = function (state) {
if (state) {
this.log = console.log.bind(window.console);
} else {
this.log = function () {};
}
};
let _a;
TokenAutocomplete.MultiSelect = /** @class */ (function () {
function saveTokens() {
settings.TWITCH.BETTERTTV_CHANNELS = tokens;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
}
function class1(parent) {
this.parent = parent;
this.container = parent.container;
this.options = parent.options;
}
/**
* Adds a token with the specified name to the list of currently prensent tokens displayed to the user and the hidden select.
*
* @param {string} tokenText - the name of the token to create
*/
class1.prototype.addToken = function (tokenValue, tokenText) {
if (tokenValue === null || tokenText === null) {
return;
}
tokens.push({ value: tokenValue, text: tokenText });
saveTokens();
const option = document.createElement('option');
option.text = tokenText;
option.value = tokenValue;
option.setAttribute('selected', 'true');
option.setAttribute('data-text', tokenText);
option.setAttribute('data-value', tokenValue);
this.parent.hiddenSelect.add(option);
const token = document.createElement('span');
token.classList.add('token-autocomplete-token');
token.setAttribute('data-text', tokenText);
option.setAttribute('data-value', tokenValue);
token.textContent = tokenText;
const deleteToken = document.createElement('span');
deleteToken.classList.add('token-autocomplete-token-delete');
deleteToken.textContent = '\u00D7';
token.appendChild(deleteToken);
const me = this;
deleteToken.addEventListener('click', function (event) {
me.removeToken(token);
});
this.container.insertBefore(token, this.parent.textInput);
this.parent.log('added token', token);
};
/**
* Completely clears the currently present tokens from the field.
*/
class1.prototype.clear = function () {
const tokens = this.container.querySelectorAll('.token-autocomplete-token');
const me = this;
tokens.forEach(function (token) {
me.removeToken(token);
});
};
/**
* Removes the last token in the list of currently present token. This is the last added token next to the input field.
*/
class1.prototype.removeLastToken = function () {
const tokens = this.container.querySelectorAll('.token-autocomplete-token');
const token = tokens[tokens.length - 1];
if (tokens.length !== 0) {
this.removeToken(token);
}
};
/**
* Removes the specified token from the list of currently present tokens.
*
* @param {Element} token - the token to remove
*/
class1.prototype.removeToken = function (token) {
let _a, _b;
this.container.removeChild(token);
const tokenText = token.getAttribute('data-text');
const hiddenOption = this.parent.hiddenSelect.querySelector('option[data-text="' + tokenText + '"]');
(_b = (_a = hiddenOption) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0
? void 0
: _b.removeChild(hiddenOption);
this.parent.log('removed token', token.textContent);
tokens.splice(
tokens.findIndex(t => t.value === token.value),
1
);
saveTokens();
};
class1.prototype.removeTokenWithText = function (tokenText) {
if (tokenText === null) {
return;
}
const token = this.container.querySelector('.token-autocomplete-token[data-text="' + tokenText + '"]');
if (token !== null) {
this.removeToken(token);
}
};
return class1;
})();
TokenAutocomplete.Autocomplete =
((_a = /** @class */ (function () {
function class2(parent) {
this.parent = parent;
this.container = parent.container;
this.options = parent.options;
this.renderer = parent.options.suggestionRenderer;
this.suggestions = document.createElement('ul');
this.suggestions.id = this.container.id + '-suggestions';
this.suggestions.classList.add('token-autocomplete-suggestions');
this.container.appendChild(this.suggestions);
}
/**
* Hides the suggestions dropdown from the user.
*/
class2.prototype.hideSuggestions = function () {
this.suggestions.style.display = '';
};
/**
* Shows the suggestions dropdown to the user.
*/
class2.prototype.showSuggestions = function () {
this.suggestions.style.display = 'block';
};
class2.prototype.highlightSuggestionAtPosition = function (index) {
const suggestions = this.suggestions.querySelectorAll('li');
suggestions.forEach(function (suggestion) {
suggestion.classList.remove('token-autocomplete-suggestion-highlighted');
});
suggestions[index].classList.add('token-autocomplete-suggestion-highlighted');
};
class2.prototype.highlightSuggestion = function (suggestion) {
this.suggestions.querySelectorAll('li').forEach(function (suggestion) {
suggestion.classList.remove('token-autocomplete-suggestion-highlighted');
});
suggestion.classList.add('token-autocomplete-suggestion-highlighted');
};
/**
* Removes all previous suggestions from the dropdown.
*/
class2.prototype.clearSuggestions = function () {
this.suggestions.innerHTML = '';
};
/**
* Loads suggestions matching the given query from the rest service behind the URI given as an option while initializing the field.
*
* @param query the query to search suggestions for
*/
class2.prototype.requestSuggestions = function (query) {
const me = this;
const request = new XMLHttpRequest();
request.onload = function () {
if (Array.isArray(request.response)) {
request.response.forEach(function (suggestion) {
me.addSuggestion(suggestion);
});
}
};
request.open('GET', me.options.suggestionsUri + '?query=' + query, true);
request.responseType = 'json';
request.setRequestHeader('Content-type', 'application/json');
request.send();
};
/**
* Adds a suggestion with the given text matching the users input to the dropdown.
*
* @param {string} suggestionText - the text that should be displayed for the added suggestion
*/
class2.prototype.addSuggestion = function (suggestion) {
const element = this.renderer(suggestion);
element.setAttribute('data-value', suggestion.value);
const me = this;
element.addEventListener('click', function (_event) {
if (suggestion.text === me.options.noMatchesText) {
return true;
}
if (element.classList.contains('token-autocomplete-suggestion-active')) {
me.parent.select.removeTokenWithText(suggestion.text);
} else {
me.parent.select.addToken(suggestion.value, suggestion.text);
}
me.clearSuggestions();
me.hideSuggestions();
me.parent.clearCurrentInput();
});
if (this.container.querySelector('.token-autocomplete-token[data-text="' + suggestion.text + '"]') !== null) {
element.classList.add('token-autocomplete-suggestion-active');
}
this.suggestions.appendChild(element);
this.showSuggestions();
me.parent.log('added suggestion', suggestion);
};
return class2;
})()),
(_a.defaultRenderer = function (suggestion) {
const option = document.createElement('li');
option.textContent = suggestion.text;
if (suggestion.description) {
const description = document.createElement('small');
description.textContent = suggestion.description;
description.classList.add('token-autocomplete-suggestion-description');
option.appendChild(description);
}
return option;
}),
_a);
return TokenAutocomplete;
})();
module.exports = { TokenAutocomplete };

344
src/js/trovo.js Normal file
View file

@ -0,0 +1,344 @@
/* global client,axios,customEmojiList, saveCustomEmotesToFile,startTime,Sockette, playNotificationSound, chat, replaceChatMessageWithCustomEmojis, messageId, addSingleTooltip, settingsPath, fs, ini, backend, main, path, resourcesPath, customEmojis, emojiPicker,config, settings, options, sound, showChatMessage, messageTemplates, getPostTime */
function setTrovoSendButton() {
const languageSelectContent = document.querySelector('.send-to-channel');
const option = document.createElement('div');
option.classList = 'language-select';
const checkbox = document.createElement('input');
checkbox.classList = 'checkbox';
checkbox.type = 'checkbox';
checkbox.id = 'SEND_CHAT_TROVO';
option.appendChild(checkbox);
const label = document.createElement('label');
label.classList = 'toggle-small';
option.setAttribute('for', 'SEND_CHAT_TROVO');
checkbox.checked = settings.TROVO.SEND_CHAT;
option.appendChild(label);
const network = document.createElement('img');
network.src = './images/trovo.png';
network.classList = 'emote';
option.appendChild(network);
option.addEventListener('click', () => {
checkbox.checked = !checkbox.checked;
settings.TROVO.SEND_CHAT = checkbox.checked;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
});
languageSelectContent.appendChild(option);
}
setTrovoSendButton();
function getTrovoUserId() {
// Get user Logo with access token
options = {
method: 'GET',
url: 'https://open-api.trovo.live/openplatform/validate',
headers: {
Accept: 'application/json',
'Client-ID': settings.TROVO.CLIENT_ID,
Authorization: `OAuth ${settings.TROVO.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(response => {
settings.TROVO.USERNAME = response.data.nick_name;
settings.TROVO.USER_ID = response.data.uid;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
getTrovoUserInfo();
config.createNotification('Obtained user info succesfully', 'success');
})
.catch(error => {
console.error(error);
config.createNotification('could not obtain user info, please try again', 'error');
});
}
function getTrovoUserInfo() {
// Get user Logo with access token
options = {
method: 'GET',
url: 'https://open-api.trovo.live/openplatform/getuserinfo',
headers: {
Accept: 'application/json',
'Client-ID': settings.TROVO.CLIENT_ID,
Authorization: `OAuth ${settings.TROVO.OAUTH_TOKEN}`
}
};
axios
.request(options)
.then(response => {
settings.TROVO.USER_LOGO_URL = response.data.profilePic;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
config.createNotification('Obtained user info succesfully', 'success');
})
.catch(error => {
console.error(error);
config.createNotification('could not obtain user info, please try again', 'error');
});
}
function saveTrovoEmotesToFile(TrovoEmotes) {
const data = JSON.stringify(TrovoEmotes);
const savePath =
main.isPackaged === true ? path.join(resourcesPath, './custom-emotes.json') : path.join(resourcesPath, './config/custom-emotes.json');
fs.writeFile(savePath, data, error => {
if (error) {
console.error(error);
throw error;
}
});
}
function formatTrovoEmotes(data) {
if (data.channels.customizedEmotes.channel) {
data.channels.customizedEmotes.channel.forEach(channel => {
channel.emotes.forEach(emote => {
const emojiToBeAdded = {
name: ':' + emote.name,
shortcodes: [':' + emote.name],
url: emote.url,
category: 'Trovo ' + settings.TROVO.CHANNEL_NAME
};
customEmojis.push(emojiToBeAdded);
});
});
}
// data.channels.eventEmotes.forEach(emote => {
// const emojiToBeAdded = {
// name: emote.name,
// shortcodes: [emote.name],
// url: emote.url,
// category: 'Trovo event emotes'
// };
// customEmojis.push(emojiToBeAdded);
// });
if (data.channels.globalEmotes) {
data.channels.globalEmotes.forEach(emote => {
const emojiToBeAdded = {
name: ':' + emote.name,
shortcodes: [':' + emote.name],
url: emote.url,
category: 'Trovo Global'
};
customEmojis.push(emojiToBeAdded);
});
}
customEmojiList = [...customEmojis];
emojiPicker.customEmoji = customEmojiList;
saveCustomEmotesToFile(customEmojis);
}
function getTrovoEmotes() {
// Get user Logo with access token
options = {
method: 'POST',
url: 'https://open-api.trovo.live/openplatform/getemotes',
headers: {
Accept: 'application/json',
'Client-ID': settings.TROVO.CLIENT_ID,
Authorization: `OAuth ${settings.TROVO.OAUTH_TOKEN}`
},
data: {
emote_type: 0,
channel_id: [settings.TROVO.CHANNEL_ID]
}
};
axios
.request(options)
.then(response => {
formatTrovoEmotes(response.data);
config.createNotification('Obtained user info succesfully', 'success');
})
.catch(error => {
console.error(error);
config.createNotification('could not obtain user info, please try again', 'error');
});
}
function getTrovoChannelId() {
options = {
method: 'POST',
url: 'https://open-api.trovo.live/openplatform/getusers',
headers: {
Accept: 'application/json',
'Client-ID': settings.TROVO.CLIENT_ID
},
data: { user: [settings.TROVO.CHANNEL_NAME.toLowerCase()] }
};
axios
.request(options)
.then(response => {
settings.TROVO.CHANNEL_ID = response.data.users[0].channel_id;
fs.writeFileSync(settingsPath, JSON.stringify(settings));
getTrovoEmotes();
config.createNotification('Obtained user info succesfully', 'success');
})
.catch(error => {
console.error(error);
config.createNotification('could not obtain user info, please try again', 'error');
});
}
function sendTrovoMessage(message) {
options = {
method: 'POST',
url: 'https://open-api.trovo.live/openplatform/chat/send',
headers: {
Accept: 'application/json',
'Client-ID': settings.TROVO.CLIENT_ID,
Authorization: `OAuth ${settings.TROVO.OAUTH_TOKEN}`
},
data: { content: message, channel_id: settings.TROVO.CHANNEL_ID }
};
axios
.request(options)
.then(response => {
console.log(response);
config.createNotification('Obtained user info succesfully', 'success');
})
.catch(error => {
console.error(error);
config.createNotification('could not obtain user info, please try again', 'error');
});
}
const getTrovoChatToken = () =>
new Promise(resolve => {
options = {
method: 'GET',
url: `https://open-api.trovo.live/openplatform/chat/channel-token/${settings.TROVO.CHANNEL_ID}`,
headers: {
Accept: 'application/json',
'Client-ID': settings.TROVO.CLIENT_ID
}
};
axios
.request(options)
.then(response => {
resolve(response.data.token);
})
.catch(error => {
console.error(error);
config.createNotification('could not obtain user info, please try again', 'error');
});
});
async function displayTrovoMessage(message) {
messageId++;
const article = document.createElement('article');
article.className = 'msg-container sender';
article.setAttribute('id', messageId);
article.innerHTML = messageTemplates.trovoTemplate;
const userImg = article.querySelector('.user-img');
if (userImg) {
userImg.src = message.avatar;
userImg.setAttribute('tip', '');
}
addSingleTooltip(userImg);
const usernameHtml = article.querySelector('.username');
if (usernameHtml) {
usernameHtml.innerText = message.nick_name;
}
const postTime = article.querySelector('.post-time');
if (postTime) {
postTime.innerText = getPostTime();
}
article.appendChild(postTime);
const formattedMessage = article.querySelector('.msg-box');
if (formattedMessage) {
formattedMessage.innerHTML = message.content;
}
await chat.replaceChatMessageWithCustomEmojis(formattedMessage.innerHTML).then(data => {
formattedMessage.innerHTML = data;
showChatMessage(article);
});
}
async function connectToTrovoChat(token) {
let startTime = new Date();
let heartbeat = null;
const wsTrovo = new Sockette('wss://open-chat.trovo.live/chat', {
onopen: e => {
// console.log('Connected!', e);
wsTrovo.json({ type: 'AUTH', nonce: 'loquendoBot', data: { token } });
},
onmessage: e => {
// console.log('Received:', e);
const data = JSON.parse(e.data);
// console.log(data);
if (data.type === 'RESPONSE' && !data.error) {
wsTrovo.json({ type: 'PING', nonce: 'loquendoBot' });
heartbeat = setInterval(() => {
wsTrovo.json({ type: 'PING', nonce: 'loquendoBot' });
}, 30e3);
}
if (data.type === 'CHAT' && data.data.chats) {
data.data.chats.forEach(message => {
// console.log(message);
if (message.type === 5007) {
return;
}
if (Math.round(startTime.getTime() / 1000) < message.send_time) {
displayTrovoMessage({
nick_name: message.nick_name,
avatar: message.avatar,
content: message.content
});
}
});
}
if (data.type === 'PONG') {
clearInterval(heartbeat);
heartbeat = setInterval(() => {
wsTrovo.json({ type: 'PING', nonce: 'loquendoBot' });
}, data.data.gap * 1000);
}
},
onreconnect: e => {
console.log('Reconnecting...', e);
startTime = new Date();
clearInterval(heartbeat);
getTrovoChatToken().then(data => {
token = data;
});
},
onmaximum: e => console.log('Stop Attempting!', e),
onclose: e => console.log('Closed!', e),
onerror: e => console.log('Error:', e)
});
// ws.close(); // graceful shutdown
}
if (settings.TROVO.CHANNEL_ID) {
getTrovoChatToken().then(data => {
connectToTrovoChat(data);
});
}
module.exports = { getTrovoUserId, getTrovoChannelId, sendTrovoMessage };

View file

@ -1,7 +1,6 @@
/* global client, playNotificationSound, chat, replaceChatMessageWithCustomEmojis, messageId, addSingleTooltip, settingsPath, fs, ini, backend, main, path, resourcesPath, customEmojis, emojiPicker,config, settings, options, sound, showChatMessage, messageTemplates, getPostTime */ /* global client, axios, playNotificationSound, betterTTVAutocomplete, saveCustomEmotesToFile, customEmojiList, chat, replaceChatMessageWithCustomEmojis, messageId, addSingleTooltip, settingsPath, fs, ini, backend, main, path, resourcesPath, customEmojis, emojiPicker,config, settings, options, sound, showChatMessage, messageTemplates, getPostTime */
const tmi = require('tmi.js'); const tmi = require('tmi.js');
const axios = require('axios');
let client = null; let client = null;
let logoUrl = null; let logoUrl = null;
@ -29,7 +28,7 @@ if (settings.TWITCH.USERNAME && settings.TWITCH.OAUTH_TOKEN) {
.catch(console.error); .catch(console.error);
client.on('message', (channel, tags, message, self) => { client.on('message', (channel, tags, message, self) => {
if (self) { if (self || tags['display-name'] === settings.TWITCH.USERNAME) {
return; return;
} }
const emotes = tags.emotes || {}; const emotes = tags.emotes || {};
@ -139,7 +138,7 @@ async function displayTwitchMessage(logoUrl, username, messageObject, filteredMe
showChatMessage(article); showChatMessage(article);
}); });
if (settings.LANGUAGE.USE_DETECTION) { if (settings.LANGUAGE.USE_DETECTION && filteredMessage.length > 20 && countWords(filteredMessage) > 4) {
await backend.getDetectedLanguage({ message: filteredMessage, messageId, username, logoUrl, formattedMessage }).then(language => { await backend.getDetectedLanguage({ message: filteredMessage, messageId, username, logoUrl, formattedMessage }).then(language => {
const languageElement = document.createElement('span'); const languageElement = document.createElement('span');
languageElement.classList = `fi fi-${language.ISO3166} fis language-icon flag-icon`; languageElement.classList = `fi fi-${language.ISO3166} fis language-icon flag-icon`;
@ -206,25 +205,6 @@ function parseString(inputString) {
return result; return result;
} }
function saveTwitchEmotesToFile(TwitchEmotes) {
const data = JSON.stringify(TwitchEmotes);
const savePath =
main.isPackaged === true ? path.join(resourcesPath, './twitch-emotes.json') : path.join(resourcesPath, './config/twitch-emotes.json');
// console.log(savePath);
fs.writeFile(savePath, data, error => {
// throwing the error
// in case of a writing problem
if (error) {
// logging the error
console.error(error);
throw error;
}
// console.log('twitch-emotes.json written correctly');
});
}
function formatTwitchEmotes(channel) { function formatTwitchEmotes(channel) {
if (channel.emotes.length === 0) { if (channel.emotes.length === 0) {
return; return;
@ -244,27 +224,13 @@ function formatTwitchEmotes(channel) {
name: emote.name, name: emote.name,
shortcodes: [emote.name], shortcodes: [emote.name],
url: emote.images.url_1x, url: emote.images.url_1x,
category: channel.broadcaster_name category: 'Twitch ' + channel.broadcaster_name
}; };
customEmojis.push(emojiToBeAdded); customEmojis.push(emojiToBeAdded);
}); });
emojiPicker.customEmoji = customEmojis; customEmojiList = [...customEmojis];
saveTwitchEmotesToFile(customEmojis); emojiPicker.customEmoji = customEmojiList;
} saveCustomEmotesToFile(customEmojis);
function saveBetterTtvEmotesToFile(BetterTtvEmotes) {
const data = JSON.stringify(BetterTtvEmotes);
const savePath =
main.isPackaged === true
? path.join(resourcesPath, './betterttv-emotes.json')
: path.join(resourcesPath, './config/betterttv-emotes.json');
fs.writeFile(savePath, data, error => {
if (error) {
console.error(error);
throw error;
}
});
} }
function formatBetterTtvEmotes(data) { function formatBetterTtvEmotes(data) {
@ -281,8 +247,9 @@ function formatBetterTtvEmotes(data) {
}; };
customEmojis.push(emojiToBeAdded); customEmojis.push(emojiToBeAdded);
}); });
emojiPicker.customEmoji = customEmojis; customEmojiList = [...customEmojis];
saveBetterTtvEmotesToFile(customEmojis); emojiPicker.customEmoji = customEmojiList;
saveCustomEmotesToFile(customEmojis);
} }
function getBetterTtvGLobalEmotes() { function getBetterTtvGLobalEmotes() {
@ -303,6 +270,32 @@ function getBetterTtvGLobalEmotes() {
}); });
} }
function getBetterTtvChannelsEmotes() {
betterTTVAutocomplete.tokens.forEach(channel => {
getTwitchChannelId(channel.value).then(channelId => {
getBetterTtvChannelEmotes(channelId);
});
});
}
function getBetterTtvChannelEmotes(channel) {
// Get user Logo with access token
options = {
method: 'GET',
url: `https://api.betterttv.net/3/cached/users/twitch/${channel}`,
headers: {}
};
axios
.request(options)
.then(response => {
formatBetterTtvEmotes({ name: 'BetterTTV Channels', emotes: [...response.data.channelEmotes, ...response.data.sharedEmotes] });
})
.catch(error => {
console.error(error);
});
}
function getTwitchUserFollows(paginationToken) { function getTwitchUserFollows(paginationToken) {
let url = ''; let url = '';
if (!paginationToken) { if (!paginationToken) {
@ -407,7 +400,7 @@ function getTwitchGlobalEmotes() {
axios axios
.request(options) .request(options)
.then(responseLogoUrl => { .then(responseLogoUrl => {
formatTwitchEmotes({ broadcaster_name: 'Twitch Global', emotes: responseLogoUrl.data.data }); formatTwitchEmotes({ broadcaster_name: 'Global', emotes: responseLogoUrl.data.data });
}) })
.catch(error => { .catch(error => {
console.error(error); console.error(error);
@ -431,29 +424,27 @@ async function getUserAvailableTwitchEmotes() {
} }
} }
function getTwitchChannelId() { const getTwitchChannelId = channelName =>
options = { new Promise(resolve => {
method: 'GET', options = {
url: `https://api.twitch.tv/helix/users?login=${settings.TWITCH.CHANNEL_NAME}`, method: 'GET',
headers: { url: `https://api.twitch.tv/helix/users?login=${channelName}`,
'Client-ID': settings.TWITCH.CLIENT_ID, headers: {
Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}` 'Client-ID': settings.TWITCH.CLIENT_ID,
} Authorization: `Bearer ${settings.TWITCH.OAUTH_TOKEN}`
}; }
};
axios axios
.request(options) .request(options)
.then(responseLogoUrl => { .then(response => {
settings.TWITCH.CHANNEL_USER_ID = responseLogoUrl.data.data[0].id; resolve(response.data.data[0].id);
fs.writeFileSync(settingsPath, ini.stringify(settings)); })
config.createNotification('Obtained channel info succesfully', 'success'); .catch(error => {
getUserAvailableTwitchEmotes(); console.error(error);
}) config.createNotification('could not obtain channel info, please try again', 'error');
.catch(error => { });
console.error(error); });
config.createNotification('could not obtain channel info, please try again', 'error');
});
}
function getTwitchUserId() { function getTwitchUserId() {
// Get user Logo with access token // Get user Logo with access token
@ -473,7 +464,7 @@ function getTwitchUserId() {
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, JSON.stringify(settings));
config.createNotification('Obtained user info succesfully', 'success'); config.createNotification('Obtained user info succesfully', 'success');
}) })
.catch(error => { .catch(error => {
@ -507,6 +498,8 @@ module.exports = {
ping, ping,
client, client,
getBetterTtvGLobalEmotes, getBetterTtvGLobalEmotes,
getBetterTtvChannelEmotes,
getBetterTtvChannelsEmotes,
getUserAvailableTwitchEmotes, getUserAvailableTwitchEmotes,
getTwitchChannelId, getTwitchChannelId,
getTwitchUserId, getTwitchUserId,

96
src/js/youtube.js Normal file
View file

@ -0,0 +1,96 @@
/* global settings, bot, messageId, showChatMessage, messageTemplates, chat, addSingleTooltip,getPostTime */
const { LiveChat } = require('youtube-chat');
const startTime = new Date();
// If channelId is specified, liveId in the current stream is automatically acquired.
// Recommended
// const liveChat = new LiveChat({ handle: settings.YOUTUBE.CHANNEL_HANDLE });
const liveChat = new LiveChat({ liveId: settings.YOUTUBE.LIVE_ID });
// Or specify LiveID in Stream manually.
// const liveChat = new LiveChat({ liveId: '4xDzrJKXOOY' });
// Emit at start of observation chat.
// liveId: string
liveChat.on('start', liveId => {
/* Your code here! */
console.log(liveId);
});
// Emit at end of observation chat.
// reason: string?
liveChat.on('end', reason => {
/* Your code here! */
console.log(reason);
});
// Emit at receive chat.
// chat: ChatItem
liveChat.on('chat', message => {
/* Your code here! */
if (message.timestamp > startTime) {
displayYoutubeMessage(message);
}
});
// Emit when an error occurs
// err: Error or any
liveChat.on('error', err => {
/* Your code here! */
console.log(err);
});
async function startYoutube() {
// Start fetch loop
const ok = await liveChat.start();
if (!ok) {
console.log('Failed to start, check emitted error');
}
}
startYoutube();
async function displayYoutubeMessage(message) {
messageId++;
const article = document.createElement('article');
article.className = 'msg-container sender';
article.setAttribute('id', messageId);
article.innerHTML = messageTemplates.youtubeTemplate;
const userImg = article.querySelector('.user-img');
if (userImg) {
userImg.src = message.author.thumbnail.url;
userImg.setAttribute('tip', '');
}
addSingleTooltip(userImg);
const usernameHtml = article.querySelector('.username');
if (usernameHtml) {
usernameHtml.innerText = message.author.name;
}
const postTime = article.querySelector('.post-time');
if (postTime) {
postTime.innerText = getPostTime();
}
article.appendChild(postTime);
const formattedMessage = article.querySelector('.msg-box');
if (formattedMessage) {
message.message.forEach(entry => {
if (entry.text) {
formattedMessage.innerHTML += entry.text;
} else {
formattedMessage.innerHTML += `<img src="${entry.url}"/>`;
}
});
}
await chat.replaceChatMessageWithCustomEmojis(formattedMessage.innerHTML).then(data => {
formattedMessage.innerHTML = data;
showChatMessage(article);
});
}

View file

@ -1,35 +1,33 @@
/* global pythonPath, a */ /* global pythonPath, a */
const { app, BrowserWindow, ipcMain } = require('electron'); const { app, BrowserWindow, ipcMain } = require('electron');
const { writeIniFile } = require('write-ini-file');
const path = require('path'); const path = require('path');
const http = require('http'); const http = require('http');
const kill = require('kill-process-by-name'); const kill = require('kill-process-by-name');
const ini = require('ini');
const fs = require('fs'); const fs = require('fs');
let resourcesPath = __dirname; let resourcesPath = __dirname;
let settingsPath; let settingsPath = null;
let settings; let settings;
let window; let window;
if (app.isPackaged) { if (app.isPackaged) {
settingsPath = path.join(process.resourcesPath, './settings.ini'); settingsPath = path.join(process.resourcesPath, './settings.json');
pythonPath = path.join(process.resourcesPath, './backend'); pythonPath = path.join(process.resourcesPath, './backend');
resourcesPath = process.resourcesPath; resourcesPath = process.resourcesPath;
} else { } else {
settingsPath = path.join(resourcesPath, './config/settings.ini'); settingsPath = path.join(resourcesPath, './config/settings.json');
pythonPath = path.join(resourcesPath, './backend'); pythonPath = path.join(resourcesPath, './backend');
} }
async function createWindow() { async function createWindow() {
if (!fs.existsSync(settingsPath)) { if (!fs.existsSync(settingsPath)) {
console.log(resourcesPath); settings = await createSettingsFile();
await createIniFile();
} else { } else {
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8')); const file = fs.readFileSync(settingsPath);
settings = JSON.parse(file);
} }
window = new BrowserWindow({ window = new BrowserWindow({
@ -45,15 +43,35 @@ async function createWindow() {
enableRemoteModule: true enableRemoteModule: true
} }
}); });
window.loadFile(path.join(__dirname, 'index.html')); window.loadFile(path.join(__dirname, 'index.html'));
// Create the second window
const secondWindow = new BrowserWindow({
width: 1920,
height: 1080,
// parent: window, // Set the parent window
// modal: true,
frame: false,
show: true, // Hide the second window initially if needed
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true,
backgroundThrottling: false
}
});
// Load second.html into the second window
secondWindow.loadFile(path.join(__dirname, './modules/facemask/index.html'));
// secondWindow.webContents.setFrameRate(60);
if (!app.isPackaged) { if (!app.isPackaged) {
window.webContents.openDevTools(); window.webContents.openDevTools();
secondWindow.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 = JSON.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();
settings.GENERAL.WIDTH = bounds.width; settings.GENERAL.WIDTH = bounds.width;
@ -61,17 +79,20 @@ async function createWindow() {
settings.GENERAL.POSITION_X = bounds.x; settings.GENERAL.POSITION_X = bounds.x;
settings.GENERAL.POSITION_Y = bounds.y; settings.GENERAL.POSITION_Y = bounds.y;
fs.writeFileSync(settingsPath, ini.stringify(settings)); fs.writeFileSync(settingsPath, JSON.stringify(settings));
}); });
} }
// app.disableHardwareAcceleration();
// app.disableDomainBlockingFor3DAPIs();
app.whenReady().then(() => { app.whenReady().then(() => {
createWindow(); createWindow();
}); });
app.on('window-all-closed', event => { app.on('window-all-closed', event => {
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
kill('loquendoBot_backend'); // kill('loquendoBot_backend');
app.quit(); app.quit();
} }
}); });
@ -84,7 +105,7 @@ app.on('activate', () => {
app.on('before-quit', () => { app.on('before-quit', () => {
window.webContents.send('quit-event'); window.webContents.send('quit-event');
kill('loquendoBot_backend'); // kill('loquendoBot_backend');
}); });
ipcMain.on('resize-window', (event, width, height) => { ipcMain.on('resize-window', (event, width, height) => {
@ -122,8 +143,8 @@ ipcMain.on('environment', event => {
event.returnValue = { resourcesPath, pythonPath, settingsPath, settings, isPackaged: app.isPackaged }; event.returnValue = { resourcesPath, pythonPath, settingsPath, settings, isPackaged: app.isPackaged };
}); });
async function createIniFile() { async function createSettingsFile() {
await writeIniFile(settingsPath, { const settingsx = {
GENERAL: { GENERAL: {
VOICE_ENABLED: true, VOICE_ENABLED: true,
NOTIFICATION_ENABLED: true, NOTIFICATION_ENABLED: true,
@ -189,17 +210,47 @@ async function createIniFile() {
}, },
TWITCH: { TWITCH: {
USE_TWITCH: false, USE_TWITCH: false,
SEND_CHAT: false,
CHANNEL_NAME: '', CHANNEL_NAME: '',
CHANNEL_USER_ID: '', CHANNEL_USER_ID: '',
USERNAME: '', USERNAME: '',
USER_ID: '', USER_ID: '',
USER_LOGO_URL: '', USER_LOGO_URL: '',
OAUTH_TOKEN: '', OAUTH_TOKEN: '',
BETTERTTV_CHANNELS: [
{ value: 'turtlemaw', text: 'turtlemaw' },
{ value: 'tO_Ot', text: 'tO_Ot' },
{ value: 'adew', text: 'adew' }
],
CLIENT_ID: '2t206sj7rvtr1rutob3p627d13jch9' CLIENT_ID: '2t206sj7rvtr1rutob3p627d13jch9'
}, },
TROVO: {
USE_TROVO: false,
SEND_CHAT: false,
CHANNEL_NAME: '',
CHANNEL_ID: '',
USERNAME: '',
USER_LOGO_URL: '',
USER_ID: '',
CLIENT_ID: '8d32385a4be4a29e345aedaf23ca772f',
OAUTH_TOKEN: ''
},
YOUTUBE: {
USE_YOUTUBE: false,
SEND_CHAT: false,
CHANNEL_ID: '',
CHANNEL_HANDLE: '',
LIVE_ID: ''
},
DLIVE: {
USE_DLIVE: false,
SEND_CHAT: false,
API_KEY: ''
},
MODULES: { MODULES: {
USE_MODULES: false, USE_MODULES: false,
USE_VTUBER: false, USE_VTUBER: false,
USE_PNGTUBER: false,
USE_CHATBUBBLE: false USE_CHATBUBBLE: false
}, },
AMAZON: { AMAZON: {
@ -217,7 +268,12 @@ async function createIniFile() {
SECONDARY_VOICE: '', SECONDARY_VOICE: '',
CHARACTERS_USED: 0 CHARACTERS_USED: 0
} }
}).then(() => { };
settings = ini.parse(fs.readFileSync(settingsPath, 'utf-8'));
fs.writeFile(settingsPath, JSON.stringify(settingsx), error => {
if (error) {
console.error(error);
}
}); });
return settingsx;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html> <html lang="en">
<head> <head>
<title>Chat</title> <title>Chat</title>
<script <script
@ -10,14 +10,11 @@
<link rel="stylesheet" href="./fonts/FRAMCDN/font.css" /> <link rel="stylesheet" href="./fonts/FRAMCDN/font.css" />
<link href="main.css" rel="stylesheet" /> <link href="main.css" rel="stylesheet" />
</head> </head>
<body> <body>
<!-- #region Main chat box--> <div id="chatBox" class="message-window"></div>
<div class="OptionPanel show" id="Chat"> <emoji-picker class="dark"></emoji-picker>
<div id="chatBox" class="message-window">
<div class="texts"></div>
</div>
</div>
<script src="main.js"></script>
<video id="camera" autoplay></video>
</body> </body>
<script src="main.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"></script>
</html> </html>

View file

@ -1,90 +1,204 @@
body { @font-face {
background-color: transparent;
font-family: 'FRAMDCN'; font-family: 'FRAMDCN';
src: url(../fonts/FRAMCDN/FRAMDCN.woff);
} }
:root { :root {
--variable: 2s; overflow: hidden;
--buttonBackground: #bf2c2c; --main-color1: #6e2c8c;
--main-color1-temp: #6e2c8c;
/*Left bar and top right bar*/
--main-color2: white;
--main-color2-temp: white;
/*Icons and text*/
--main-color3: #211e1e;
--main-color3-temp: #211e1e;
/*Buttons and input*/
--main-color4: #2f2c34;
--main-color4-temp: #2f2c34;
--top-bar: #100b12;
--top-bar-temp: #100b12;
--mid-section: #352d3d;
--mid-section-temp: #352d3d;
--chat-bubble: #7a6d7f;
--chat-bubble-header: #141414;
--chat-bubble-username: white;
--chat-bubble-message: white;
--chat-bubble-temp: #7a6d7f;
--chat-bubble-header-temp: #141414;
--chat-bubble-message-temp: white;
} }
.thomas { h1 {
font-family: 'FRAMDCN';
}
.message-window {
height: calc(100% - 60px);
overflow: hidden;
overflow-y: auto;
display: flex;
align-items: center;
flex-direction: column-reverse;
font-family: 'FRAMDCN';
position: relative; position: relative;
float: center; z-index: 1;
/* display: inline-block; */
} }
.speechbubble { .input-box {
display: block; display: flex;
bottom: 0; border: none;
position: absolute; width: 100%;
z-index: -1; height: 30px;
font-size: 16px;
} }
.fade-outx { .userText {
animation: fade-outx var(--variable) linear; color: var(--chat-bubble-message);
font-family: Helvetica;
font-size: 16px;
text-align: right;
clear: both;
} }
@keyframes fade-outx { .userText span {
line-height: 1.5em;
display: inline-block;
background: #5ca6fa;
padding: 10px;
border-radius: 8px;
border-bottom-right-radius: 2px;
max-width: 80%;
margin-right: 10px;
animation: floatup 0.5s forwards;
}
.botText {
color: #000;
font-family: Helvetica;
font-weight: normal;
font-size: 16px;
text-align: left;
}
.botText span {
line-height: 1.5em;
display: inline-block;
background: #e0e0e0;
padding: 10px;
border-radius: 8px;
border-bottom-left-radius: 2px;
max-width: 80%;
margin-left: 10px;
animation: floatup 0.5s forwards;
}
@keyframes floatup {
from { from {
opacity: 1; transform: translateY(14px);
opacity: 0;
} }
to { to {
opacity: 0; transform: translateY(0px);
}
}
.fade-outxx {
animation: fade-outxx var(--variable) linear;
}
@keyframes fade-outxx {
from {
opacity: 1; opacity: 1;
} }
}
to { @media screen and (max-width: 600px) {
opacity: 0; .full-chat-block {
width: 100%;
border-radius: 0px;
}
.chat-bar-collapsible {
position: fixed;
bottom: 0;
right: 0;
width: 100%;
}
.collapsible {
width: 100%;
border: 0px;
border-radius: 0px;
} }
} }
.bounce-in { ::-webkit-scrollbar {
animation: bounce-in 1s ease; width: 4px;
} }
@keyframes bounce-in { ::-webkit-scrollbar-thumb {
0% { background-color: #4c4c6a;
opacity: 0; border-radius: 2px;
transform: scale(0.3);
}
50% {
opacity: 1;
transform: scale(1.05);
}
70% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
} }
.bounce-inx { .chatBox {
animation: bounce-inx 1s ease; width: 300px;
height: 400px;
max-height: 400px;
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: 0 0 4px var(--main-color4);
} }
@keyframes bounce-inx { .chat-window {
0% { flex: auto;
opacity: 0; max-height: calc(100% - 60px);
} background: #2f323b;
overflow: auto;
}
50% { .chat-input {
opacity: 1; height: 30px;
} display: flex;
flex: 0 0 auto;
height: 60px;
background: var(--main-color3);
}
.chat-input input {
height: 59px;
line-height: 60px;
outline: 0 none;
border: none;
width: calc(100% - 60px);
color: var(--chat-bubble-message);
text-indent: 10px;
font-size: 12pt;
padding: 0;
background: var(--main-color3);
}
.chat-input button {
float: right;
outline: 0 none;
border: none;
background: var(--main-color3);
height: 40px;
width: 40px;
border-radius: 50%;
padding: 2px 0 0 0;
margin: 10px;
}
.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);
}
.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);
/* filter: brightness(150%); */
}
.chat-input input[good] + button path {
fill: var(--chat-bubble-message);
} }
.msg-container { .msg-container {
@ -94,8 +208,7 @@ body {
padding: 10px 0px 0px 0px; padding: 10px 0px 0px 0px;
display: grid; display: grid;
grid-template: 1fr / 1fr; grid-template: 1fr / 1fr;
align-self: center; align-self: start;
width: fit-content;
} }
.msg-container > * { .msg-container > * {
@ -103,72 +216,383 @@ body {
grid-row: 1 / 1; grid-row: 1 / 1;
} }
.message-window { .msg-container.sender {
height: calc(100% - 50px); place-items: self-start;
overflow: hidden;
overflow-y: hidden;
display: flex;
flex-direction: column;
width: 80%;
margin: auto;
background: transparent;
} }
.message-window::before { .msg-container.user {
content: ''; place-items: self-end;
flex: 1 0 0px;
} }
.OptionPanel { .msg-box {
flex: 3; background: var(--chat-bubble);
display: none;
position: absolute;
top: 10px;
left: 0;
width: 100%;
height: calc(100% - 25px);
background: transparent;
}
.OptionPanel.show {
display: block;
}
.message {
text-align: left;
max-width: 100%;
height: auto;
min-width: fit-content;
hyphens: auto;
/* bottom: 0; */
/* right: 0; */
/* float: right; */
overflow-wrap: break-word;
position: relative;
border: 2px solid #ff80e1;
/* box-shadow: 0 2px 10px rgba(255, 128, 225, 0.5); */
background: linear-gradient(45deg, rgb(15, 12, 41, 0.7), rgb(48, 43, 99, 0.7));
/* background: linear-gradient(45deg, rgba(72, 0, 154, 0.7), rgba(138, 43, 226, 0.7)); */
color: white; color: white;
padding: 15px; min-width: 100px;
border-radius: 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);
width: fit-content;
position: relative;
align-self: start;
}
.msg-box.sender {
margin: 25px 25px 0px 35px;
}
.msg-box.user {
text-align: left;
margin: 25px 35px 0px 0px;
}
.msg-box-user-temp {
background: var(--chat-bubble-temp);
}
.user-img {
display: inline-block;
position: relative;
border-radius: 50%;
height: 50px;
width: 50px;
z-index: 5;
align-self: start;
}
.messages.user {
margin-right: 20px;
}
.msg {
font-size: 12pt;
color: var(--chat-bubble-message);
margin: 0 0 0 0;
}
.msg-temp {
color: var(--chat-bubble-message-temp);
}
.timestamp {
color: var(--chat-bubble-header);
font-size: 10pt;
align-items: center;
font-family: 'xxii_avenmedium';
}
.timestamp-temp {
color: var(--chat-bubble-header-temp);
}
.username {
background-color: var(--main-color4);
color: white;
position: relative;
border-radius: 5px;
z-index: 3;
align-self: start;
}
.username.sender {
padding: 0px 5px 5px 30px;
margin: 20px 5px 5px 25px;
}
.username.user {
padding: 0px 30px 5px 5px;
margin: 20px 30px 5px 5px;
}
.username-temp {
color: var(--chat-bubble-header-temp);
}
.post-time {
font-size: 8pt;
color: white;
display: inline-block;
background-color: var(--main-color4);
position: relative;
z-index: 2;
border-radius: 5px;
align-self: start;
}
.post-time.sender {
padding: 5px 5px 5px 15px;
margin: 0px 0px 0px 50px;
}
.post-time.user {
padding: 5px 15px 5px 5px;
margin: 0px 50px 0px 0px;
}
.mmg {
display: flex;
}
.img {
height: 100%;
width: 100%;
border-radius: 50%;
}
.status-circle {
width: 20px;
border-radius: 50%;
z-index: 6;
position: relative;
align-self: start;
}
.status-circle.sender {
margin-left: 40px;
}
.status-circle.user {
margin-right: 40px;
}
.menu-select {
font-size: 0.9rem;
height: 40px;
border-radius: 20px; border-radius: 20px;
background-color: var(--main-color3);
color: var(--main-color2);
align-items: center;
border: 0px;
padding-left: 10px;
width: 300px;
font-size: 100%;
padding: 10px;
padding-right: 25px;
outline: none;
-webkit-appearance: none;
-moz-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg fill='white' height='34' viewBox='0 0 24 24' width='32' xmlns='http://www.w3.org/2000/svg'><path d='M7 10l5 5 5-5z'/><path d='M0 0h24v24H0z' fill='none'/></svg>");
background-repeat: no-repeat;
background-position-x: 100%;
background-position-y: 5px;
}
.top-select {
width: auto;
height: 24px;
padding: 0px;
margin: 0px;
background-color: transparent;
color: white;
-webkit-appearance: none;
-moz-appearance: none;
border: none;
}
.info-image {
width: 50px;
height: 50px;
}
.top-select option {
margin: 40px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
background-color: var(--top-bar);
}
.AdvancedMenu {
border: 1px var(--main-color2) solid;
margin-top: 10px;
min-width: 555px;
border-radius: 5px;
border-radius: 5px;
}
.legendStyle {
margin-left: 1em;
padding: 0.2em 0.8em;
display: flex;
align-items: center;
}
.AdvancedMenuRow {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
justify-content: left;
margin-bottom: 10px; margin-bottom: 10px;
} }
.arrow { .AdvancedMenuLabel {
content: ''; font-size: 10pt;
border: 2px solid #ff80e1; padding-right: 5px;
position: absolute; margin-left: 10px;
left: 50%; width: 125px;
transform: translateX(-50%) rotate(180deg);
border-width: 10px;
border-style: solid;
border-color: transparent transparent rgb(255, 128, 225, 0.7) transparent;
color: #ff80e1;
bottom: -10px;
} }
.sender { .AdvancedMenuLabel2 {
color: #ff80e1; font-size: 10pt;
font-size: 14pt; padding-right: 5px;
margin-left: 10px;
}
.AdvancedMenuLabel3 {
font-size: 12pt;
padding-right: 5px;
margin-left: 10px;
}
#SaveAdvancedSettingsButton {
margin-left: 10px;
}
.toggle {
position: relative;
display: inline-block;
width: 60px;
height: 40px;
background-color: var(--main-color3);
border-radius: 20px;
}
/* After slide changes */
.toggle:after {
content: '';
position: absolute;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: var(--main-color2);
left: 5px;
top: 5px;
}
/* Checkbox checked effect */
.checkbox:checked + .toggle::after {
left: 25px;
}
/* Checkbox checked toggle label bg color */
.checkbox:checked + .toggle {
background-color: var(--main-color1);
}
/* Checkbox vanished */
.checkbox {
display: none;
}
/* Small toggle */
/* toggle in label designing */
.toggle-small {
position: relative;
display: inline-block;
width: 30px;
height: 20px;
background-color: var(--main-color3);
border-radius: 10px;
margin-left: 10px;
}
/* After slide changes */
.toggle-small:after {
content: '';
position: absolute;
width: 15px;
height: 15px;
border-radius: 50%;
background-color: white;
left: 2px;
top: 2px;
}
/* Checkbox checked effect */
.checkbox:checked + .toggle-small::after {
left: 13px;
}
/* Checkbox checked toggle label bg color */
.checkbox:checked + .toggle-small {
background-color: var(--main-color1);
}
.emotes {
position: relative;
cursor: pointer;
}
.dark {
display: none;
position: absolute;
z-index: 1;
top: -400px;
}
.emotes:hover .dark {
display: block;
}
.fi {
position: relative;
z-index: 5;
border-radius: 50%;
}
.translation-header {
background-color: var(--main-color4);
border-radius: 5px;
width: fit-content;
padding: 5px;
margin: 10px 0px 5px -5px;
position: relative;
}
.translation-message {
position: relative;
margin: 20px 0px 0px 0px;
}
.translation-message.user {
margin: -20px 0px 0px 0px;
}
.translation-icon {
position: relative;
padding: 0px 0px 0px 0px;
margin: -45px 0px 0px -40px;
top: 30px;
}
.language-icon {
position: relative;
top: 45px;
}
.flag-icon {
width: 20px !important;
height: 20px !important;
left: 18px;
}
.flag-icon.user {
left: -18px;
top: -15px;
}
.user-flag {
left: unset;
right: 18px;
top: -65px;
} }

View file

@ -3,123 +3,87 @@
// Connect to the Socket.IO server // Connect to the Socket.IO server
const socket = io(); const socket = io();
const twitchTemplate = `
<img class="user-img" src="" />
<img class="status-circle sender" src="./images/twitch-icon.png" tip="twitch" />
<span class="post-time sender"></span>
<span class="username sender"></span>
<div class="msg-box sender"></div>
`.trim();
const emojiPicker = document.body.querySelector('emoji-picker');
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);
}
});
});
// Emit a message to the server // Emit a message to the server
socket.emit('message', 'Hello, Server!'); socket.emit('message', 'Hello, Server!');
function getPostTime() { async function displayChatMessage(message) {
const d = new Date(); const article = document.createElement('article');
document.body.querySelectorAll('.container').innerHTML = d.getHours(); article.className = 'msg-container sender';
const hours = d.getHours(); article.setAttribute('id', message.messageId);
const minutes = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
const time = `${hours}:${minutes}`; article.innerHTML = twitchTemplate;
return time; const userImg = article.querySelector('.user-img');
if (userImg) {
userImg.src = message.image;
}
const usernameHtml = article.querySelector('.username');
if (usernameHtml) {
usernameHtml.innerText = message.username;
}
const postTime = article.querySelector('.post-time');
if (postTime) {
postTime.innerText = message.postTime;
}
article.appendChild(postTime);
const formattedMessage = article.querySelector('.msg-box');
formattedMessage.innerHTML = message.message;
// if (formattedMessage) {
// messageObject.forEach(entry => {
// if (entry.text) {
// formattedMessage.innerHTML += entry.text;
// } else {
// formattedMessage.innerHTML += entry.html;
// }
// });
// }
await replaceChatMessageWithCustomEmojis(formattedMessage.innerHTML).then(data => {
formattedMessage.innerHTML = data;
showChatMessage(article);
});
} }
function showChatMessage(article) { function showChatMessage(article) {
const main = document.querySelector('#chatBox'); document.getElementById('chatBox').appendChild(article);
main.appendChild(article);
main.scrollTop = main.scrollHeight;
}
let textStreamContainer; const messages = document.body.querySelectorAll('.msg-container');
let x;
// const totalDuration = 5000; // Total duration in milliseconds
// const charactersPerSecond = 20; // Adjust the number of characters to display per second
// const streamingSpeed = totalDuration / (textToStream.length / charactersPerSecond); const lastMessage = messages[messages.length - 1];
lastMessage.scrollIntoView({ block: 'end', behavior: 'smooth' });
let currentIndex = 0;
let messageStream = '';
const tempMessageObject = '';
const fullMessageLength = 0;
function getFullMessageLength(text) {
let fullMessageLength = 0;
text.forEach(element => {
if (element.text) {
fullMessageLength += element.text.length;
}
// element.html;
fullMessageLength += 1;
});
return fullMessageLength;
}
function streamText() {
// if (currentIndex < fullMessageLength) {
// textStreamContainer.innerHTML += messageStream.filtered.charAt(currentIndex);
// currentIndex++;
// setTimeout(streamText, 50);
// }
if (currentIndex < messageStream.length) {
textStreamContainer.innerHTML += messageStream.charAt(currentIndex);
currentIndex++;
setTimeout(streamText, 50);
} else {
currentIndex = 0;
x.classList.add('fade-outx');
}
}
function displayTwitchMessage(message) {
if (!message.filteredMessage) {
return;
}
const root = document.querySelector(':root');
root.style.setProperty('--variable', '5s');
const article = document.createElement('article');
x = article;
article.className = 'msg-container';
const placeMessage = `
<div class="thomas bounce-in">
<div class="message"></div>
<div class="sender"></div>
<div class="speechbubble"></div>
<div class="arrow"></div>
</div>
`.trim();
article.innerHTML = placeMessage;
const msg = article.querySelector('.message');
msg.innerHTML = `<div class="sender">${message.username}</div>`; // \n${message}`;
msg.style.fontSize = '12pt';
showChatMessage(article);
const elements = document.getElementsByClassName('msg-container');
if (elements.length > 1) {
elements[0].remove();
}
article.addEventListener('animationend', e => {
if (e.animationName === 'fade-outx') {
article.remove();
}
});
if (elements.length > 1) {
elements[0].classList.add('fade-outxx');
elements[0].addEventListener('animationend', e => {
if (e.animationName === 'fade-outxx') {
elements[0].remove();
}
});
}
// fullMessageLength = getFullMessageLength(messageObject);
messageStream = message.filteredMessage;
textStreamContainer = document.querySelector('.message');
streamText();
} }
// // Receive a message from the server // // Receive a message from the server
socket.on('message', message => { socket.on('chat-in', message => {
displayTwitchMessage(message); displayChatMessage(message);
}); });

View file

@ -0,0 +1,14 @@
{
"name": "chat",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

View file

@ -0,0 +1,10 @@
@font-face {
font-family: 'FRAMDCN';
src: local('FRAMDCN'), url('./FRAMDCN.woff') format('woff');
}
/* use this class to attach this font to any element i.e. <p class="fontsforweb_fontid_1381">Text with this font applied</p> */
.fontsforweb_fontid_1381 {
font-family: 'FRAMDCN' !important;
}
/* Font downloaded from FontsForWeb.com */

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title> web font from FontsForWeb.com</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="font.css">
<style type="text/css">
/* when @font-face is defined(it is in font.css) you can add the font to any rule by using font-family */
h1 {
font-family: 'FRAMDCN';
}
</style>
</head>
<body>
<h1>Thank you for using FontsForWeb.com</h1>
<p class="fontsforweb_fontid_1381">Look in the source of this file to see how to embed this font on your website</p>
</body>
</html>

View file

@ -0,0 +1,2 @@
Original download page
http://ttfonts.net/font/606_FranklinGothicMediumCond.htm

View file

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

View file

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

View file

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,478 @@
const { FaceLandmarker, HandLandmarker, PoseLandmarker, FilesetResolver, DrawingUtils } = require('@mediapipe/tasks-vision');
const videoBlendShapes = document.getElementById('video-blend-shapes');
const videoSelect = document.querySelector('select#videoSource');
const videoElement = document.getElementById('video');
const canvasElement = document.getElementsByClassName('output_canvas')[0];
const canvasCtx = canvasElement.getContext('2d');
let cameraRunning = false;
let cameraVisible = true;
let cameraFPS = 30;
let cameraWidth = 640;
let cameraHeight = 480;
let lastVideoTime = -1;
const drawingUtils = new DrawingUtils(canvasCtx);
getDevices().then(gotDevices);
let detections = [];
document.body.querySelector('#cameraVisible').addEventListener('click', async () => {
cameraVisible = !cameraVisible;
if (cameraVisible) {
document.body.querySelector('#cameraVisible').innerHTML = 'Hide Camera';
document.body.querySelector('#video').style.display = '';
} else {
document.body.querySelector('#cameraVisible').innerHTML = 'Show Camera';
document.body.querySelector('#video').style.display = 'none';
}
});
document.body.querySelector('#cameraRunning').addEventListener('click', async () => {
cameraRunning = !cameraRunning;
if (cameraRunning) {
getStream();
document.body.querySelector('#cameraRunning').innerHTML = 'Stop Camera';
} else {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
document.body.querySelector('#cameraRunning').innerHTML = 'Start Camera';
}
});
document.body.querySelector('#cameraResolution').addEventListener('change', async e => {
cameraWidth = e.target.options[e.target.selectedIndex].getAttribute('width');
cameraHeight = e.target.options[e.target.selectedIndex].getAttribute('height');
});
document.body.querySelector('#cameraFPS').addEventListener('change', async () => {
cameraFPS = document.body.querySelector('#cameraFPS').value;
});
// -------------- Face Detection --------------
let faceDetectionDelegate = 'GPU';
let minFaceDetectionConfidence = 0.5;
document.getElementById('minFaceDetectionConfidenceValue').innerHTML = minFaceDetectionConfidence;
let minFacePresenceConfidence = 0.5;
document.getElementById('minFacePresenceConfidenceValue').innerHTML = minFacePresenceConfidence;
let minFaceTrackingConfidence = 0.5;
document.getElementById('minFaceTrackingConfidenceValue').innerHTML = minFaceTrackingConfidence;
let faceTrackingEnabled = false;
let hideFace = false;
let faceLandmarker;
let resultsFace;
document.body.querySelector('#face').addEventListener('click', async () => {
faceTrackingEnabled = !faceTrackingEnabled;
if (faceTrackingEnabled) {
createFaceLandmarker();
document.body.querySelector('#face').innerHTML = 'Disable face detection';
} else {
faceLandmarker = null;
document.body.querySelector('#face').innerHTML = 'Enable face detection';
}
});
document.body.querySelector('#hideFace').addEventListener('click', async () => {
hideFace = !hideFace;
if (hideFace) {
document.body.querySelector('#hideFace').innerHTML = 'Show face detection';
} else {
document.body.querySelector('#hideFace').innerHTML = 'Hide face detection';
}
});
document.body.querySelector('#faceDetectionDelegate').addEventListener('change', async () => {
faceDetectionDelegate = document.getElementById('faceDetectionDelegate').value;
if (faceTrackingEnabled) {
createFaceLandmarker();
}
});
document.body.querySelector('#minFaceDetectionConfidence').addEventListener('change', async () => {
minFaceDetectionConfidence = parseInt(document.getElementById('minFaceDetectionConfidence').value);
document.getElementById('minFaceDetectionConfidenceValue').innerHTML = minFaceDetectionConfidence;
if (faceTrackingEnabled) {
createFaceLandmarker();
}
});
document.body.querySelector('#minFacePresenceConfidence').addEventListener('change', async () => {
minFacePresenceConfidence = parseInt(document.getElementById('minFacePresenceConfidence').value);
document.getElementById('minFacePresenceConfidenceValue').innerHTML = minFacePresenceConfidence;
if (faceTrackingEnabled) {
createFaceLandmarker();
}
});
document.body.querySelector('#minFaceTrackingConfidence').addEventListener('change', async () => {
minFaceTrackingConfidence = parseInt(document.getElementById('minFaceTrackingConfidence').value);
document.getElementById('minFaceTrackingConfidenceValue').innerHTML = minFaceTrackingConfidence;
if (faceTrackingEnabled) {
createFaceLandmarker();
}
});
// -------------- Hand Detection --------------
let handDetectionDelegate = 'GPU';
let minHandDetectionConfidence = 0.5;
document.getElementById('minHandDetectionConfidenceValue').innerHTML = minHandDetectionConfidence;
let minHandPresenceConfidence = 0.5;
document.getElementById('minHandPresenceConfidenceValue').innerHTML = minHandPresenceConfidence;
let minHandTrackingConfidence = 0.5;
document.getElementById('minHandTrackingConfidenceValue').innerHTML = minHandTrackingConfidence;
let handTrackingEnabled = false;
let hideHand = false;
let handLandmarker;
let resultsHands;
document.body.querySelector('#hand').addEventListener('click', async () => {
handTrackingEnabled = !handTrackingEnabled;
if (handTrackingEnabled) {
createHandLandmarker();
document.body.querySelector('#hand').innerHTML = 'Disable hand detection';
} else {
handLandmarker = null;
document.body.querySelector('#hand').innerHTML = 'Enable hand detection';
}
});
document.body.querySelector('#hideHand').addEventListener('click', async () => {
hideHand = !hideHand;
if (hideFace) {
document.body.querySelector('#hideHand').innerHTML = 'Show hand detection';
} else {
document.body.querySelector('#hideHand').innerHTML = 'Hide hand detection';
}
});
document.body.querySelector('#handDetectionDelegate').addEventListener('change', async () => {
handDetectionDelegate = document.getElementById('handDetectionDelegate').value;
if (handTrackingEnabled) {
createHandLandmarker();
}
});
document.body.querySelector('#minHandDetectionConfidence').addEventListener('change', async () => {
minHandDetectionConfidence = parseInt(document.getElementById('minHandDetectionConfidence').value);
document.getElementById('minHandDetectionConfidenceValue').innerHTML = minHandDetectionConfidence;
if (handTrackingEnabled) {
createHandLandmarker();
}
});
document.body.querySelector('#minHandPresenceConfidence').addEventListener('change', async () => {
minHandPresenceConfidence = parseInt(document.getElementById('minHandPresenceConfidence').value);
document.getElementById('minHandPresenceConfidenceValue').innerHTML = minHandPresenceConfidence;
if (handTrackingEnabled) {
createHandLandmarker();
}
});
document.body.querySelector('#minHandTrackingConfidence').addEventListener('change', async () => {
minHandTrackingConfidence = parseInt(document.getElementById('minHandTrackingConfidence').value);
document.getElementById('minHandTrackingConfidenceValue').innerHTML = minHandTrackingConfidence;
if (handTrackingEnabled) {
createHandLandmarker();
}
});
// -------------- Pose Detection --------------
let poseDetectionDelegate = 'GPU';
let minPoseDetectionConfidence = 0.5;
document.getElementById('minPoseDetectionConfidenceValue').innerHTML = minPoseDetectionConfidence;
let minPosePresenceConfidence = 0.5;
document.getElementById('minPosePresenceConfidenceValue').innerHTML = minPosePresenceConfidence;
let minPoseTrackingConfidence = 0.5;
document.getElementById('minPoseTrackingConfidenceValue').innerHTML = minPoseTrackingConfidence;
let poseTrackingEnabled = false;
let hidepose = false;
let poseLandmarker;
let resultsPose;
document.body.querySelector('#pose').addEventListener('click', async () => {
poseTrackingEnabled = !poseTrackingEnabled;
if (poseTrackingEnabled) {
createPoseLandmarker();
document.body.querySelector('#pose').innerHTML = 'Disable pose detection';
} else {
poseLandmarker = null;
document.body.querySelector('#pose').innerHTML = 'Enable pose detection';
}
});
document.body.querySelector('#hidePose').addEventListener('click', async () => {
hidepose = !hidepose;
if (hideFace) {
document.body.querySelector('#hidePose').innerHTML = 'Show pose detection';
} else {
document.body.querySelector('#hidePose').innerHTML = 'Hide pose detection';
}
});
document.body.querySelector('#poseDetectionDelegate').addEventListener('change', async () => {
poseDetectionDelegate = document.getElementById('faceDetectionDelegate').value;
if (poseTrackingEnabled) {
createPoseLandmarker();
}
});
document.body.querySelector('#minPoseDetectionConfidence').addEventListener('change', async () => {
minPoseDetectionConfidence = parseInt(document.getElementById('minPoseDetectionConfidence').value);
document.getElementById('minPoseDetectionConfidenceValue').innerHTML = minPoseDetectionConfidence;
if (poseTrackingEnabled) {
createPoseLandmarker();
}
});
document.body.querySelector('#minPosePresenceConfidence').addEventListener('change', async () => {
minPosePresenceConfidence = parseInt(document.getElementById('minPosePresenceConfidence').value);
document.getElementById('minPosePresenceConfidenceValue').innerHTML = minPosePresenceConfidence;
if (poseTrackingEnabled) {
createPoseLandmarker();
}
});
document.body.querySelector('#minPoseTrackingConfidence').addEventListener('change', async () => {
minPoseTrackingConfidence = parseInt(document.getElementById('minPoseTrackingConfidence').value);
document.getElementById('minPoseTrackingConfidenceValue').innerHTML = minPoseTrackingConfidence;
if (poseTrackingEnabled) {
createPoseLandmarker();
}
});
// -------------- Camera --------------
function getDevices() {
// AFAICT in Safari this only gets default devices until gUM is called :/
return navigator.mediaDevices.enumerateDevices();
}
function gotDevices(deviceInfos) {
window.deviceInfos = deviceInfos; // make available to console
for (const deviceInfo of deviceInfos) {
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
}
}
}
function getStream() {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
const videoSource = videoSelect.value;
const constraints = {
video: {
deviceId: videoSource ? { exact: videoSource } : undefined,
frameRate: { min: 30, ideal: cameraFPS, max: 60 },
width: cameraWidth,
height: cameraHeight
}
};
return navigator.mediaDevices.getUserMedia(constraints).then(gotStream).catch(handleError);
}
function gotStream(stream) {
window.stream = stream; // make stream available to console
videoSelect.selectedIndex = [...videoSelect.options].findIndex(option => option.text === stream.getVideoTracks()[0].label);
videoElement.srcObject = stream;
videoElement.addEventListener('loadeddata', predictWebcam);
}
function handleError(error) {
console.error('Error: ', error);
}
// -------------- Tracking --------------
async function createFaceLandmarker() {
const filesetResolver = await FilesetResolver.forVisionTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm');
faceLandmarker = await FaceLandmarker.createFromOptions(filesetResolver, {
baseOptions: {
modelAssetPath: 'face_landmarker_model/face_landmarker.task',
delegate: faceDetectionDelegate
},
minFaceDetectionConfidence: minFaceDetectionConfidence,
minFacePresenceConfidence: minFacePresenceConfidence,
minTrackingConfidence: minFaceTrackingConfidence,
outputFaceBlendshapes: true,
runningMode: 'VIDEO',
numFaces: 1
});
window.requestAnimationFrame(predictWebcam);
}
const createHandLandmarker = async () => {
const vision = await FilesetResolver.forVisionTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm');
handLandmarker = await HandLandmarker.createFromOptions(vision, {
baseOptions: {
modelAssetPath: 'hand_landmarker_model/hand_landmarker.task',
delegate: handDetectionDelegate
},
minHandDetectionConfidence: minHandDetectionConfidence,
minHandPresenceConfidence: minHandPresenceConfidence,
minTrackingConfidence: minHandTrackingConfidence,
runningMode: 'VIDEO',
numHands: 2
});
window.requestAnimationFrame(predictWebcam);
};
const createPoseLandmarker = async () => {
const vision = await FilesetResolver.forVisionTasks('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm');
poseLandmarker = await PoseLandmarker.createFromOptions(vision, {
baseOptions: {
modelAssetPath: 'pose_landmarker_model/pose_landmarker_heavy.task',
delegate: poseDetectionDelegate
},
minPoseDetectionConfidence: minPoseDetectionConfidence,
minPosePresenceConfidence: minPosePresenceConfidence,
minTrackingConfidence: minPoseTrackingConfidence,
runningMode: 'VIDEO',
numPoses: 1
});
window.requestAnimationFrame(predictWebcam);
};
// -------------- Detection --------------
function mediapipeRunning() {
if (faceLandmarker || handLandmarker || poseLandmarker) {
return true;
}
return false;
}
function predictWebcam() {
if (!mediapipeRunning()) {
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
return;
}
if (!hideFace || !hidepose || !hideHand) {
canvasElement.width = videoElement.videoWidth;
canvasElement.height = videoElement.videoHeight;
} else {
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
}
// Now let's start detecting the stream.
const startTimeMs = performance.now();
if (lastVideoTime !== videoElement.currentTime) {
lastVideoTime = videoElement.currentTime;
resultsFace = faceLandmarker ? faceLandmarker.detectForVideo(videoElement, startTimeMs) : null;
// resultsHands = handLandmarker ? handLandmarker.detectForVideo(videoElement, startTimeMs) : null;
// resultsPose = poseLandmarker ? poseLandmarker.detectForVideo(videoElement, startTimeMs) : null;
}
if (faceTrackingEnabled && resultsFace && resultsFace.faceLandmarks) {
// console.log(resultsFace);
drawDebugFace(resultsFace);
}
if (handTrackingEnabled && resultsHands && resultsHands.landmarks) {
// drawDebugHands(resultsHands);
}
if (poseTrackingEnabled && resultsPose && resultsPose.landmarks) {
// drawDebugPose(resultsPose);
}
// drawBlendShapes(videoBlendShapes, resultsFace.faceBlendshapes);
// canvasCtx.restore();
// Call this function again to keep predicting when the browser is ready.
if (cameraRunning === true) {
window.requestAnimationFrame(predictWebcam);
}
}
function drawDebugFace(results) {
if (results) {
detections = results;
}
if (hideFace) {
return;
}
for (const landmarks of results.faceLandmarks) {
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION, { color: '#C0C0C070', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_RIGHT_EYE, { color: '#FF3030', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_RIGHT_EYEBROW, { color: '#FF3030', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LEFT_EYE, { color: '#30FF30', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LEFT_EYEBROW, { color: '#30FF30', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_FACE_OVAL, { color: '#E0E0E0', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LIPS, { color: '#E0E0E0', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_RIGHT_IRIS, { color: '#FF3030', lineWidth: 1 });
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LEFT_IRIS, { color: '#30FF30', lineWidth: 1 });
}
}
function drawDebugHands(results) {
if (hideHand) {
return;
}
for (const landmarks of results.landmarks) {
drawingUtils.drawConnectors(landmarks, HandLandmarker.HAND_CONNECTIONS, {
color: '#E0E0E0',
lineWidth: 1
});
drawingUtils.drawLandmarks(landmarks, { color: '#E0E0E0', lineWidth: 1 });
}
}
function drawDebugPose(results) {
if (hidePose) {
return;
}
for (const landmark of results.landmarks) {
drawingUtils.drawLandmarks(landmark, {
radius: data => DrawingUtils.lerp(data.from.z, -0.15, 0.1, 5, 1)
});
drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS, { color: '#E0E0E0', lineWidth: 1 });
}
}
function drawBlendShapes(el, blendShapes) {
if (!blendShapes.length) {
return;
}
// console.log(blendShapes[0]);
let htmlMaker = '';
blendShapes[0].categories.map(shape => {
htmlMaker += `
<li class="blend-shapes-item">
<span class="blend-shapes-label">${shape.displayName || shape.categoryName}</span>
<span class="blend-shapes-value" style="width: calc(${+shape.score * 100}% - 120px)">${(+shape.score).toFixed(4)}</span>
</li>
`;
});
el.innerHTML = htmlMaker;
}

View file

@ -0,0 +1,75 @@
{
"shapes": [
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 15,
"fill_O": 100,
"stroke_H": 263.0718090188531,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152
]
},
{
"fill_H": 116.38012093685805,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 234.7247860532549,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
151,
50,
280,
151,
9,
330,
101,
9,
151,
361
]
}
]
}

View file

@ -0,0 +1,448 @@
{
"shapes": [
{
"fill_H": 230,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 25,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
14,
87,
178,
88,
95,
78,
191,
80,
81,
82,
13,
12,
11,
0,
164,
2,
94,
19,
1,
4,
5,
195,
197,
6,
122,
245,
244,
243,
112,
26,
22,
23,
24,
110,
226,
247,
30,
29,
27,
28,
56,
190,
243,
244,
245,
122,
6,
168,
8,
9,
151,
10,
109,
67,
103,
54,
21,
162,
127,
234,
93,
132,
58,
172,
136,
150,
149,
176,
148,
152,
175,
199,
200,
18,
17,
16,
15,
14
]
},
{
"fill_H": 75,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
152,
175,
199,
200,
18,
17,
16,
15,
14,
317,
402,
318,
324,
308,
415,
310,
311,
312,
13,
12,
11,
0,
164,
2,
94,
19,
1,
4,
5,
195,
197,
6,
351,
465,
464,
463,
341,
256,
252,
253,
254,
339,
446,
467,
260,
259,
257,
258,
286,
414,
463,
464,
465,
351,
6,
168,
8,
9,
151,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
356
]
},
{
"fill_H": 115,
"fill_S": 50,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
27,
28,
56,
190,
243,
112,
26,
22,
23,
24,
110,
226,
247,
30,
29,
27,
323
]
},
{
"fill_H": 115,
"fill_S": 50,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
257,
259,
260,
467,
446,
339,
254,
253,
252,
256,
341,
463,
414,
286,
258,
257
]
},
{
"fill_H": 355,
"fill_S": 70,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
1,
44,
220,
134,
51,
5,
281,
363,
440,
274,
1
]
},
{
"fill_H": 355,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
27,
52,
29,
27
]
},
{
"fill_H": 355,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
23,
101,
24,
23
]
},
{
"fill_H": 320,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 235,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
257,
282,
259,
257
]
},
{
"fill_H": 320,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 235,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
253,
330,
254,
253
]
},
{
"fill_H": 210,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 170,
"stroke_S": 0,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
61,
76,
62,
78,
95,
88,
178,
87,
14,
317,
402,
318,
324,
308,
292,
306,
291,
306,
292,
308,
319,
404,
315,
16,
85,
180,
89,
78,
62,
76,
61
]
},
{
"fill_H": 5,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 50,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
78,
191,
80,
81,
82,
13,
312,
311,
310,
415,
308,
303,
302,
12,
72,
73,
183,
78,
264
]
},
{
"fill_H": 135,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 40,
"stroke_S": 0,
"stroke_B": 70,
"stroke_O": 100,
"indices": [
107,
66,
105,
63,
70
]
},
{
"fill_H": 135,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 40,
"stroke_S": 0,
"stroke_B": 70,
"stroke_O": 100,
"indices": [
336,
296,
334,
293,
300
]
},
{
"fill_H": 135,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 40,
"stroke_S": 0,
"stroke_B": 70,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,325 @@
{
"shapes": [
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
2,
167,
92,
216,
207,
187,
147,
137,
234,
127,
162,
21,
54,
103,
67,
109,
10,
151,
9,
8,
168,
6,
197,
195,
5,
3,
196,
188,
233,
243,
190,
56,
28,
27,
225,
130,
25,
110,
24,
23,
22,
233,
188,
196,
3,
5,
4,
1,
19,
94,
2
]
},
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
2,
393,
322,
436,
427,
411,
376,
366,
454,
356,
389,
251,
284,
332,
297,
338,
10,
151,
9,
8,
168,
6,
197,
195,
5,
248,
419,
412,
453,
463,
414,
286,
258,
257,
445,
359,
255,
339,
254,
253,
252,
453,
412,
419,
248,
5,
4,
1,
19,
94,
2
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 130,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
188,
245,
189,
221,
222,
223,
46,
226,
31,
228,
229,
230,
231,
128,
233,
22,
23,
24,
110,
25,
130,
225,
27,
28,
56,
190,
243,
233,
128,
188
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
412,
465,
413,
441,
442,
276,
446,
261,
448,
449,
450,
451,
357,
453,
252,
253,
254,
339,
255,
359,
445,
257,
258,
286,
414,
463,
453,
357,
412
]
},
{
"fill_H": 70,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 30,
"stroke_O": 100,
"indices": [
19,
1,
45,
1,
275
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
355,
371,
280,
352
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
277,
329,
347,
346,
340
]
},
{
"fill_H": 225,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
47,
100,
118,
117,
111
]
},
{
"fill_H": 225,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
126,
142,
50,
123
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
168,
107,
151,
336,
168,
447
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": []
}
]
}

View file

@ -0,0 +1,167 @@
{
"shapes": [
{
"fill_H": 225,
"fill_S": 5,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 255,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 255,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
73,
180,
84,
17,
314,
404,
303,
312,
82,
73,
288
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 360,
"stroke_S": 60,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
13,
17
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 265,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
92,
73,
82,
13,
312,
303,
322
]
},
{
"fill_H": 345,
"fill_S": 50,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 130,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
225,
100
]
},
{
"fill_H": 345,
"fill_S": 50,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 130,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
221,
117
]
},
{
"fill_H": 345,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 130,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
453,
452,
451,
450,
449,
448,
261
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 265,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,160 @@
{
"shapes": [
{
"fill_H": 160,
"fill_S": 25,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
152,
170,
138,
177,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
401,
367,
395,
152
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
142,
101,
118,
31,
226,
113,
225,
224,
223,
222,
221,
189,
245,
217,
209,
142
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
429,
437,
465,
413,
441,
442,
443,
444,
445,
342,
446,
261,
347,
330,
371,
429
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
89,
81,
38,
12,
268,
311,
319,
89
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 25,
"stroke_O": 100,
"indices": [
60,
60,
97
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 25,
"stroke_O": 100,
"indices": [
290,
328,
326
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 25,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,115 @@
{
"shapes": [
{
"fill_H": 270,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 285,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
8,
8,
8,
55,
65,
52,
53,
70,
71,
21,
139,
143,
111,
117,
118,
126,
198,
236,
3,
195,
196,
188,
233,
23,
24,
110,
25,
130,
113,
29,
27,
28,
56,
190,
243,
233,
188,
196,
195
]
},
{
"fill_H": 270,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 285,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
8,
285,
295,
282,
283,
300,
301,
251,
368,
372,
340,
346,
347,
355,
420,
456,
248,
195,
419,
412,
453,
253,
254,
339,
255,
359,
342,
259,
257,
258,
286,
414,
463,
453,
412,
419,
195
]
},
{
"fill_H": 270,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 285,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,188 @@
{
"shapes": [
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
150,
150,
212,
216,
206,
98,
97,
2,
462,
250,
459,
440,
363,
456,
399,
412,
465,
413,
441,
442,
443,
444,
445,
342,
265,
372,
264,
389,
251,
284,
332,
297,
338,
10,
109,
67,
103,
54,
21,
162,
127,
34,
143,
35,
226,
113,
225,
224,
223,
222,
221,
189,
244,
233,
232,
231,
230,
229,
228,
31,
226,
35,
143,
34,
127,
234,
93,
132,
58,
172,
136,
150
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
148,
176,
149,
150,
212,
216,
206,
98,
97,
2,
164,
0,
11,
12,
13,
82,
81,
80,
191,
78,
95,
88,
178,
87,
14,
317,
402,
318,
324,
308,
415,
310,
311,
312,
13,
12,
11,
0,
164,
2,
250,
459,
440,
363,
456,
399,
412,
465,
413,
464,
453,
452,
451,
450,
449,
448,
261,
446,
342,
265,
372,
264,
389,
397
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": []
}
]
}

View file

@ -0,0 +1,206 @@
{
"shapes": [
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
4,
45,
218,
235,
203,
205,
123,
227,
162,
21,
54,
104,
69,
108,
151,
9,
8,
168,
6,
122,
245,
244,
243,
190,
56,
28,
27,
225,
130,
25,
110,
24,
23,
22,
26,
112,
243,
244,
245,
122,
6,
197,
195,
5,
4
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
130,
46,
223,
222,
221,
189,
245,
188,
174,
114,
121,
231,
24,
23,
22,
26,
112,
243,
190,
56,
28,
27,
225,
247,
25,
130,
397
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
4,
275,
438,
455,
423,
425,
352,
447,
389,
251,
284,
333,
299,
337,
151,
9,
8,
168,
6,
351,
465,
464,
463,
414,
286,
258,
257,
445,
359,
255,
339,
254,
253,
252,
256,
341,
463,
464,
465,
351,
6,
197,
195,
5,
4
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
399,
412,
465,
413,
441,
442,
443,
276,
342,
255,
467,
445,
257,
258,
286,
414,
463,
341,
256,
252,
253,
254,
451,
350,
343,
399
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": []
}
]
}

View file

@ -0,0 +1,159 @@
{
"shapes": [
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 90,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
6,
6,
294,
64,
6
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
31,
65,
233,
31
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
465,
258,
265,
253,
465
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
0,
312,
302,
311,
303,
310,
270,
409,
291,
375,
320,
324,
404,
402,
315,
14,
85,
178,
180,
88,
91,
95,
146,
61,
185,
40,
42,
39,
81,
37,
82
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
397
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

View file

@ -0,0 +1,123 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="select">
<div>
<h3>Camera</h3>
<label for="videoSource">Camera:</label
><select id="videoSource">
<option value="">None</option>
</select>
</div>
<div>
<label for="fname">W x H</label>
<select id="cameraResolution">
<option value="0" width="640" height="480">640 x 480 (4:3)</option>
<option value="1" width="1920" height="1080">1920 x 1080 (16:9)</option>
<option value="2" width="1280" height="720">1280 x 720 (16:9)</option>
<option value="3" width="320" height="240">320 x 240 (4:3)</option>
</select>
<label for="fname">FPS</label>
<select id="cameraFPS">
<option value="30">30</option>
<option value="60">60</option>
</select>
</div>
<div>
<button id="cameraRunning">Start camera</button>
<button id="cameraVisible">Hide Camera</button>
</div>
<div>
<h3>Face</h3>
<label>Face Inference delegate</label>
<select id="faceDetectionDelegate">
<option value="GPU">GPU</option>
<option value="CPU">CPU</option>
</select>
<div class="slidecontainer">
<label>Minimum face detection confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minFaceDetectionConfidence" />
<span id="minFaceDetectionConfidenceValue"></span>
</div>
<div class="slidecontainer">
<label>Minimum face presence confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minFacePresenceConfidence" />
<span id="minFacePresenceConfidenceValue"></span>
</div>
<div class="slidecontainer">
<label>Minimum face tracking confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minFaceTrackingConfidence" />
<span id="minFaceTrackingConfidenceValue"></span>
</div>
<button id="face">Enable face detection</button>
<button id="hideFace">Hide face detection</button>
</div>
<div>
<h3>Hands</h3>
<label>Hands Inference delegate</label>
<select id="handDetectionDelegate">
<option value="GPU">GPU</option>
<option value="CPU">CPU</option>
</select>
<div class="slidecontainer">
<label>Minimum hand detection confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minHandDetectionConfidence" />
<span id="minHandDetectionConfidenceValue"></span>
</div>
<div class="slidecontainer">
<label>Minimum hand presence confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minHandPresenceConfidence" />
<span id="minHandPresenceConfidenceValue"></span>
</div>
<div class="slidecontainer">
<label>Minimum hand tracking confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minHandTrackingConfidence" />
<span id="minHandTrackingConfidenceValue"></span>
</div>
<button id="hand">Enable hand detection</button>
<button id="hideHand">Hide hand detection</button>
</div>
<div>
<h3>Pose</h3>
<label>Pose Inference delegate</label>
<select id="poseDetectionDelegate">
<option value="GPU">GPU</option>
<option value="CPU">CPU</option>
</select>
<div class="slidecontainer">
<label>Minimum pose detection confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minPoseDetectionConfidence" />
<span id="minPoseDetectionConfidenceValue"></span>
</div>
<div class="slidecontainer">
<label>Minimum pose presence confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minPosePresenceConfidence" />
<span id="minPosePresenceConfidenceValue"></span>
</div>
<div class="slidecontainer">
<label>Minimum pose tracking confidence</label>
<input type="range" min="0" max="1" step="0.1" value="0.5" class="slider" id="minPoseTrackingConfidence" />
<span id="minPoseTrackingConfidenceValue"></span>
</div>
<button id="pose">Enable pose detection</button>
<button id="hidePose">Hide pose detection</button>
</div>
</div>
<div class="canvas-container">
<video class="camera" id="video" autoplay muted playsinline></video>
<canvas class="output_canvas"></canvas>
<main></main>
</div>
<div class="blend-shapes">
<ul class="blend-shapes-list" id="video-blend-shapes"></ul>
</div>
</body>
<!-- <script defer language="javascript" type="text/javascript" src="sketch.js"></script> -->
<script src="detection.js"></script>
</html>

View file

@ -0,0 +1,75 @@
{
"shapes": [
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 15,
"fill_O": 100,
"stroke_H": 263.0718090188531,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152
]
},
{
"fill_H": 116.38012093685805,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 234.7247860532549,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
151,
50,
280,
151,
9,
330,
101,
9,
151,
361
]
}
]
}

View file

@ -0,0 +1,448 @@
{
"shapes": [
{
"fill_H": 230,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 25,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
14,
87,
178,
88,
95,
78,
191,
80,
81,
82,
13,
12,
11,
0,
164,
2,
94,
19,
1,
4,
5,
195,
197,
6,
122,
245,
244,
243,
112,
26,
22,
23,
24,
110,
226,
247,
30,
29,
27,
28,
56,
190,
243,
244,
245,
122,
6,
168,
8,
9,
151,
10,
109,
67,
103,
54,
21,
162,
127,
234,
93,
132,
58,
172,
136,
150,
149,
176,
148,
152,
175,
199,
200,
18,
17,
16,
15,
14
]
},
{
"fill_H": 75,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
152,
175,
199,
200,
18,
17,
16,
15,
14,
317,
402,
318,
324,
308,
415,
310,
311,
312,
13,
12,
11,
0,
164,
2,
94,
19,
1,
4,
5,
195,
197,
6,
351,
465,
464,
463,
341,
256,
252,
253,
254,
339,
446,
467,
260,
259,
257,
258,
286,
414,
463,
464,
465,
351,
6,
168,
8,
9,
151,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
356
]
},
{
"fill_H": 115,
"fill_S": 50,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
27,
28,
56,
190,
243,
112,
26,
22,
23,
24,
110,
226,
247,
30,
29,
27,
323
]
},
{
"fill_H": 115,
"fill_S": 50,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
257,
259,
260,
467,
446,
339,
254,
253,
252,
256,
341,
463,
414,
286,
258,
257
]
},
{
"fill_H": 355,
"fill_S": 70,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
1,
44,
220,
134,
51,
5,
281,
363,
440,
274,
1
]
},
{
"fill_H": 355,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
27,
52,
29,
27
]
},
{
"fill_H": 355,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
23,
101,
24,
23
]
},
{
"fill_H": 320,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 235,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
257,
282,
259,
257
]
},
{
"fill_H": 320,
"fill_S": 0,
"fill_B": 30,
"fill_O": 100,
"stroke_H": 235,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
253,
330,
254,
253
]
},
{
"fill_H": 210,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 170,
"stroke_S": 0,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
61,
76,
62,
78,
95,
88,
178,
87,
14,
317,
402,
318,
324,
308,
292,
306,
291,
306,
292,
308,
319,
404,
315,
16,
85,
180,
89,
78,
62,
76,
61
]
},
{
"fill_H": 5,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 50,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
78,
191,
80,
81,
82,
13,
312,
311,
310,
415,
308,
303,
302,
12,
72,
73,
183,
78,
264
]
},
{
"fill_H": 135,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 40,
"stroke_S": 0,
"stroke_B": 70,
"stroke_O": 100,
"indices": [
107,
66,
105,
63,
70
]
},
{
"fill_H": 135,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 40,
"stroke_S": 0,
"stroke_B": 70,
"stroke_O": 100,
"indices": [
336,
296,
334,
293,
300
]
},
{
"fill_H": 135,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 40,
"stroke_S": 0,
"stroke_B": 70,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,325 @@
{
"shapes": [
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
2,
167,
92,
216,
207,
187,
147,
137,
234,
127,
162,
21,
54,
103,
67,
109,
10,
151,
9,
8,
168,
6,
197,
195,
5,
3,
196,
188,
233,
243,
190,
56,
28,
27,
225,
130,
25,
110,
24,
23,
22,
233,
188,
196,
3,
5,
4,
1,
19,
94,
2
]
},
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
2,
393,
322,
436,
427,
411,
376,
366,
454,
356,
389,
251,
284,
332,
297,
338,
10,
151,
9,
8,
168,
6,
197,
195,
5,
248,
419,
412,
453,
463,
414,
286,
258,
257,
445,
359,
255,
339,
254,
253,
252,
453,
412,
419,
248,
5,
4,
1,
19,
94,
2
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 130,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
188,
245,
189,
221,
222,
223,
46,
226,
31,
228,
229,
230,
231,
128,
233,
22,
23,
24,
110,
25,
130,
225,
27,
28,
56,
190,
243,
233,
128,
188
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
412,
465,
413,
441,
442,
276,
446,
261,
448,
449,
450,
451,
357,
453,
252,
253,
254,
339,
255,
359,
445,
257,
258,
286,
414,
463,
453,
357,
412
]
},
{
"fill_H": 70,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 30,
"stroke_O": 100,
"indices": [
19,
1,
45,
1,
275
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
355,
371,
280,
352
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
277,
329,
347,
346,
340
]
},
{
"fill_H": 225,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
47,
100,
118,
117,
111
]
},
{
"fill_H": 225,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
126,
142,
50,
123
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
168,
107,
151,
336,
168,
447
]
},
{
"fill_H": 0,
"fill_S": 100,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 100,
"stroke_B": 100,
"stroke_O": 0,
"indices": []
}
]
}

View file

@ -0,0 +1,167 @@
{
"shapes": [
{
"fill_H": 225,
"fill_S": 5,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 255,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 255,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
73,
180,
84,
17,
314,
404,
303,
312,
82,
73,
288
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 360,
"stroke_S": 60,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
13,
17
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 265,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
92,
73,
82,
13,
312,
303,
322
]
},
{
"fill_H": 345,
"fill_S": 50,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 130,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
225,
100
]
},
{
"fill_H": 345,
"fill_S": 50,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 130,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
221,
117
]
},
{
"fill_H": 345,
"fill_S": 50,
"fill_B": 100,
"fill_O": 0,
"stroke_H": 130,
"stroke_S": 50,
"stroke_B": 0,
"stroke_O": 100,
"indices": [
453,
452,
451,
450,
449,
448,
261
]
},
{
"fill_H": 360,
"fill_S": 45,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 265,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,160 @@
{
"shapes": [
{
"fill_H": 160,
"fill_S": 25,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
152,
170,
138,
177,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
401,
367,
395,
152
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
142,
101,
118,
31,
226,
113,
225,
224,
223,
222,
221,
189,
245,
217,
209,
142
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
429,
437,
465,
413,
441,
442,
443,
444,
445,
342,
446,
261,
347,
330,
371,
429
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 80,
"stroke_O": 100,
"indices": [
89,
81,
38,
12,
268,
311,
319,
89
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 25,
"stroke_O": 100,
"indices": [
60,
60,
97
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 25,
"stroke_O": 100,
"indices": [
290,
328,
326
]
},
{
"fill_H": 160,
"fill_S": 95,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 160,
"stroke_S": 50,
"stroke_B": 25,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,115 @@
{
"shapes": [
{
"fill_H": 270,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 285,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
8,
8,
8,
55,
65,
52,
53,
70,
71,
21,
139,
143,
111,
117,
118,
126,
198,
236,
3,
195,
196,
188,
233,
23,
24,
110,
25,
130,
113,
29,
27,
28,
56,
190,
243,
233,
188,
196,
195
]
},
{
"fill_H": 270,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 285,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": [
8,
285,
295,
282,
283,
300,
301,
251,
368,
372,
340,
346,
347,
355,
420,
456,
248,
195,
419,
412,
453,
253,
254,
339,
255,
359,
342,
259,
257,
258,
286,
414,
463,
453,
412,
419,
195
]
},
{
"fill_H": 270,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 285,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,188 @@
{
"shapes": [
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
150,
150,
212,
216,
206,
98,
97,
2,
462,
250,
459,
440,
363,
456,
399,
412,
465,
413,
441,
442,
443,
444,
445,
342,
265,
372,
264,
389,
251,
284,
332,
297,
338,
10,
109,
67,
103,
54,
21,
162,
127,
34,
143,
35,
226,
113,
225,
224,
223,
222,
221,
189,
244,
233,
232,
231,
230,
229,
228,
31,
226,
35,
143,
34,
127,
234,
93,
132,
58,
172,
136,
150
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
148,
176,
149,
150,
212,
216,
206,
98,
97,
2,
164,
0,
11,
12,
13,
82,
81,
80,
191,
78,
95,
88,
178,
87,
14,
317,
402,
318,
324,
308,
415,
310,
311,
312,
13,
12,
11,
0,
164,
2,
250,
459,
440,
363,
456,
399,
412,
465,
413,
464,
453,
452,
451,
450,
449,
448,
261,
446,
342,
265,
372,
264,
389,
397
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": []
}
]
}

View file

@ -0,0 +1,206 @@
{
"shapes": [
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
4,
45,
218,
235,
203,
205,
123,
227,
162,
21,
54,
104,
69,
108,
151,
9,
8,
168,
6,
122,
245,
244,
243,
190,
56,
28,
27,
225,
130,
25,
110,
24,
23,
22,
26,
112,
243,
244,
245,
122,
6,
197,
195,
5,
4
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
130,
46,
223,
222,
221,
189,
245,
188,
174,
114,
121,
231,
24,
23,
22,
26,
112,
243,
190,
56,
28,
27,
225,
247,
25,
130,
397
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
4,
275,
438,
455,
423,
425,
352,
447,
389,
251,
284,
333,
299,
337,
151,
9,
8,
168,
6,
351,
465,
464,
463,
414,
286,
258,
257,
445,
359,
255,
339,
254,
253,
252,
256,
341,
463,
464,
465,
351,
6,
197,
195,
5,
4
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
399,
412,
465,
413,
441,
442,
443,
276,
342,
255,
467,
445,
257,
258,
286,
414,
463,
341,
256,
252,
253,
254,
451,
350,
343,
399
]
},
{
"fill_H": 155,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 330,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": []
}
]
}

View file

@ -0,0 +1,159 @@
{
"shapes": [
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 90,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
10,
338,
297,
332,
284,
251,
389,
356,
454,
323,
361,
288,
397,
365,
379,
378,
400,
377,
152,
148,
176,
149,
150,
136,
172,
58,
132,
93,
234,
127,
162,
21,
54,
103,
67,
109,
10
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
6,
6,
294,
64,
6
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
31,
65,
233,
31
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
465,
258,
265,
253,
465
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
0,
312,
302,
311,
303,
310,
270,
409,
291,
375,
320,
324,
404,
402,
315,
14,
85,
178,
180,
88,
91,
95,
146,
61,
185,
40,
42,
39,
81,
37,
82
]
},
{
"fill_H": 40,
"fill_S": 100,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 30,
"stroke_S": 100,
"stroke_B": 50,
"stroke_O": 100,
"indices": [
397
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

Binary file not shown.

View file

@ -0,0 +1,391 @@
const P = require('p5');
const sketch = function (p) {
let canvas;
const dMouse = [];
let closest = 0;
let isEditMode = true;
let fillHSlider, fillSSlider, fillBSlider, fillOSlider;
let fillHValue, fillSValue, fillBValue, fillOValue;
let strokeHSlider, strokeSSlider, strokeBSlider, strokeOSlider;
let strokeHValue, strokeSValue, strokeBValue, strokeOValue;
let editButton;
let saveDrawingButton;
let indexUoButton;
let indexDownButton;
let completeButton;
let undoButton;
let deleteButton;
let shapes = [
{
fill_H: p.random(360),
fill_S: 50,
fill_B: 100,
fill_O: 100,
stroke_H: p.random(360),
stroke_S: 50,
stroke_B: 100,
stroke_O: 100,
indices: []
}
];
let shapeIndex = 0;
let tParameters;
let isDraggedOver = false;
p.setup = function () {
canvas = p.createCanvas(cameraWidth, cameraHeight);
canvas.id('canvas');
canvas.dragOver(() => {
isDraggedOver = true;
});
canvas.dragLeave(() => {
isDraggedOver = false;
});
canvas.drop(file => {
if (file.subtype === 'json') {
shapes = file.data.shapes;
shapeIndex = shapes.length - 1;
isDraggedOver = false;
} else {
isDraggedOver = false;
}
});
p.colorMode(p.HSB, 360, 100, 100, 100);
editButton = p.createButton('Edit mode off');
editButton.mousePressed(p.toggleEdit);
editButton.class('Buttons');
editButton.id('editButton');
fillHValue = p.createDiv();
fillHValue.class('valueDisplay');
fillHSlider = p.createSlider(0, 360, p.random(360), 5);
fillHSlider.class('Slider');
fillSValue = p.createDiv();
fillSValue.class('valueDisplay');
fillSSlider = p.createSlider(0, 100, 50, 5);
fillSSlider.class('Slider');
fillBValue = p.createDiv();
fillBValue.class('valueDisplay');
fillBSlider = p.createSlider(0, 100, 100, 5);
fillBSlider.class('Slider');
fillOValue = p.createDiv();
fillOValue.class('valueDisplay');
fillOSlider = p.createSlider(0, 100, 100, 5);
fillOSlider.class('Slider');
strokeHValue = p.createDiv();
strokeHValue.class('valueDisplay');
strokeHSlider = p.createSlider(0, 360, p.random(360), 5);
strokeHSlider.class('Slider');
strokeSValue = p.createDiv();
strokeSValue.class('valueDisplay');
strokeSSlider = p.createSlider(0, 100, 50, 5);
strokeSSlider.class('Slider');
strokeBValue = p.createDiv();
strokeBValue.class('valueDisplay');
strokeBSlider = p.createSlider(0, 100, 100, 5);
strokeBSlider.class('Slider');
strokeOValue = p.createDiv();
strokeOValue.class('valueDisplay');
strokeOSlider = p.createSlider(0, 100, 100, 5);
strokeOSlider.class('Slider');
saveDrawingButton = p.createButton('');
saveDrawingButton.mousePressed(p.saveDrawing);
saveDrawingButton.class('imageButtons');
saveDrawingButton.id('saveDrawingButton');
indexUoButton = p.createButton('');
indexUoButton.mousePressed(p.upIndex);
indexUoButton.class('imageButtons');
indexUoButton.id('indexUoButton');
indexDownButton = p.createButton('');
indexDownButton.mousePressed(p.downIndex);
indexDownButton.class('imageButtons');
indexDownButton.id('indexDownButton');
completeButton = p.createButton('complete');
completeButton.mousePressed(p.complete);
completeButton.class('Buttons');
completeButton.id('completeButton');
undoButton = p.createButton('undo');
undoButton.mousePressed(p.undo);
undoButton.class('Buttons');
undoButton.id('undoButton');
deleteButton = p.createButton('delete');
deleteButton.mousePressed(p.deleteDrawing);
deleteButton.class('Buttons');
deleteButton.id('deleteButton');
tParameters = {
fill_H: fillHSlider.value(),
fill_S: fillSSlider.value(),
fill_B: fillBSlider.value(),
fill_O: fillOSlider.value(),
stroke_H: strokeHSlider.value(),
stroke_S: strokeSSlider.value(),
stroke_B: strokeBSlider.value(),
stroke_O: strokeOSlider.value()
};
p.textAlign(p.CENTER, p.CENTER);
p.textSize(24);
};
p.draw = function () {
p.clear();
if (detections !== undefined) {
if (detections.faceLandmarks !== undefined && detections.faceLandmarks.length >= 1) {
p.drawShapes();
if (isEditMode === true) {
p.faceMesh();
p.editShapes();
}
if (isDraggedOver === true) {
p.noStroke();
p.fill(0, 0, 100, 10);
p.rect(0, 0, p.width, p.height);
p.fill(0, 0, 100);
// p.text('Drag your drawing here', p.width / 2, p.height / 2);
}
}
}
fillHValue.html('fill hue: ' + fillHSlider.value());
fillSValue.html('fill saturation: ' + fillSSlider.value());
fillBValue.html('fill brightness: ' + fillBSlider.value());
fillOValue.html('fill opacity: ' + fillOSlider.value());
strokeHValue.html('stroke hue: ' + strokeHSlider.value());
strokeSValue.html('stroke saturation: ' + strokeSSlider.value());
strokeBValue.html('stroke brightness: ' + strokeBSlider.value());
strokeOValue.html('stroke opacity: ' + strokeOSlider.value());
};
p.faceMesh = function () {
p.stroke(0, 0, 100);
p.strokeWeight(3);
p.beginShape(p.POINTS);
for (let i = 0; i < detections.faceLandmarks[0].length; i++) {
const x = detections.faceLandmarks[0][i].x * p.width;
const y = detections.faceLandmarks[0][i].y * p.height;
p.vertex(x, y);
const d = p.dist(x, y, p.mouseX, p.mouseY);
dMouse.push(d);
}
p.endShape();
const minimum = p.min(dMouse);
closest = dMouse.indexOf(minimum);
p.stroke(0, 100, 100);
p.strokeWeight(10);
p.point(detections.faceLandmarks[0][closest].x * p.width, detections.faceLandmarks[0][closest].y * p.height);
dMouse.splice(0, dMouse.length);
};
p.mouseClicked = function () {
if (p.mouseX >= 0 && p.mouseX <= p.width) {
if (p.mouseY >= 0 && p.mouseY <= p.height) {
if (isEditMode === true) {
shapes[shapeIndex].indices.push(closest);
console.log(shapes);
}
}
}
};
p.drawShapes = function () {
for (let s = 0; s < shapes.length; s++) {
p.fill(shapes[s].fill_H, shapes[s].fill_S, shapes[s].fill_B, shapes[s].fill_O);
p.stroke(shapes[s].stroke_H, shapes[s].stroke_S, shapes[s].stroke_B, shapes[s].stroke_O);
p.strokeWeight(3);
if (isEditMode === true) {
if (s === shapeIndex) p.glow('rgba(255, 255, 255, 100)');
else p.glow('rgba(255, 255, 255, 0)');
} else if (isEditMode === false) {
p.glow('rgba(255, 255, 255, 100)');
}
p.beginShape();
for (let i = 0; i < shapes[s].indices.length; i++) {
p.vertex(
detections.faceLandmarks[0][shapes[s].indices[i]].x * p.width,
detections.faceLandmarks[0][shapes[s].indices[i]].y * p.height
);
}
p.endShape();
}
};
p.editShapes = function () {
// --- fill ---
if (tParameters.fill_H !== fillHSlider.value()) {
tParameters.fill_H = fillHSlider.value();
shapes[shapeIndex].fill_H = fillHSlider.value();
}
if (tParameters.fill_S !== fillSSlider.value()) {
tParameters.fill_S = fillSSlider.value();
shapes[shapeIndex].fill_S = fillSSlider.value();
}
if (tParameters.fill_B !== fillBSlider.value()) {
tParameters.fill_B = fillBSlider.value();
shapes[shapeIndex].fill_B = fillBSlider.value();
}
if (tParameters.fill_O !== fillOSlider.value()) {
tParameters.fill_O = fillOSlider.value();
shapes[shapeIndex].fill_O = fillOSlider.value();
}
// --- stroke ---
if (tParameters.stroke_H !== strokeHSlider.value()) {
tParameters.stroke_H = strokeHSlider.value();
shapes[shapeIndex].stroke_H = strokeHSlider.value();
}
if (tParameters.stroke_S !== strokeSSlider.value()) {
tParameters.stroke_S = strokeSSlider.value();
shapes[shapeIndex].stroke_S = strokeSSlider.value();
}
if (tParameters.stroke_B !== strokeBSlider.value()) {
tParameters.stroke_B = strokeBSlider.value();
shapes[shapeIndex].stroke_B = strokeBSlider.value();
}
if (tParameters.stroke_O !== strokeOSlider.value()) {
tParameters.stroke_O = strokeOSlider.value();
shapes[shapeIndex].stroke_O = strokeOSlider.value();
}
};
p.keyTyped = function () {
if (p.key === 'e') p.toggleEdit();
if (p.key === 'c') p.complete();
if (p.key === 'z') p.undo();
if (p.key === 'd') p.deleteDrawing();
if (p.key === 'j') p.saveDrawing();
};
p.toggleEdit = function () {
isEditMode = !isEditMode;
if (isEditMode === true) {
editButton.html('Edit mode on');
} else if (isEditMode === false) {
editButton.html('Edit mode off');
}
};
p.complete = function () {
if (shapes[shapes.length - 1].indices.length > 0) {
if (shapes[shapeIndex].indices.length === 0 && shapes.length > 1) shapes.splice(shapeIndex, 1);
shapes.push({
fill_H: p.random(360),
fill_S: 50,
fill_B: 100,
fill_O: 100,
stroke_H: p.random(360),
stroke_S: 50,
stroke_B: 100,
stroke_O: 100,
indices: []
});
shapeIndex = shapes.length - 1;
}
console.log(shapes);
};
p.undo = function () {
if (shapes[shapeIndex] !== undefined) {
if (shapes[shapeIndex].indices.length > 0) shapes[shapeIndex].indices.pop();
}
console.log(shapes[shapeIndex].indices);
};
p.deleteDrawing = function () {
shapes = [
{
fill_H: p.random(360),
fill_S: 50,
fill_B: 100,
fill_O: 100,
stroke_H: p.random(360),
stroke_S: 50,
stroke_B: 100,
stroke_O: 100,
indices: []
}
];
shapeIndex = 0;
console.log(shapes);
};
p.saveDrawing = function () {
const s = { shapes };
p.saveJSON(s, 'untitled_shapes.json');
};
p.keyPressed = function () {
if (p.keyCode === p.UP_ARROW) p.upIndex();
else if (p.keyCode === p.DOWN_ARROW) p.downIndex();
};
p.upIndex = function () {
if (shapes[shapeIndex] !== undefined) {
if (shapes[shapeIndex].indices.length === 0 && shapes.length > 1) shapes.splice(shapeIndex, 1);
if (shapeIndex < shapes.length - 1) shapeIndex++;
p.resetSliders();
console.log(shapeIndex);
}
};
p.downIndex = function () {
if (shapes[shapeIndex] !== undefined) {
if (shapes[shapeIndex].indices.length === 0 && shapes.length > 1) shapes.splice(shapeIndex, 1);
if (shapeIndex > 0) shapeIndex--;
p.resetSliders();
console.log(shapeIndex);
}
};
p.resetSliders = function () {
fillHSlider.value(shapes[shapeIndex].fill_H);
fillSSlider.value(shapes[shapeIndex].fill_S);
fillBSlider.value(shapes[shapeIndex].fill_B);
fillOSlider.value(shapes[shapeIndex].fill_O);
strokeHSlider.value(shapes[shapeIndex].stroke_H);
strokeSSlider.value(shapes[shapeIndex].stroke_S);
strokeBSlider.value(shapes[shapeIndex].stroke_B);
strokeOSlider.value(shapes[shapeIndex].stroke_O);
};
p.glow = function (glowColor) {
p.drawingContext.shadowOffsetX = 0;
p.drawingContext.shadowOffsetY = 0;
p.drawingContext.shadowBlur = 20;
p.drawingContext.shadowColor = glowColor;
};
};
const myp5 = new P(sketch);

View file

@ -0,0 +1,175 @@
body {
background-color: black;
margin: 0px;
}
.select {
color: white;
display: flex;
flex-direction: column;
width: 500px;
}
.inputResolution {
width: 100px;
}
select {
color: black;
}
button {
position: relative;
z-index: 10;
}
#canvas {
position: absolute;
top: 0;
z-index: 1;
}
.canvas-container {
position: relative;
width: 640px;
height: 480px;
}
.output_canvas {
position: absolute;
object-fit: contain;
width: 100%;
height: 100%;
}
#video {
position: absolute;
width: 100%;
height: 100%;
object-fit: contain;
}
#camera {
opacity: 0.5;
}
.valueDisplay {
position: relative;
margin-left: 665px;
color: #f7bd8f;
font-size: 10pt;
font-family: Helvetica, Arial, sans-serif;
font-weight: 100;
display: none;
}
.Slider {
-webkit-appearance: none;
position: relative;
margin-top: 5px;
margin-left: 665px;
margin-bottom: 10px;
background: none;
height: 12px;
width: 200px;
border-radius: 6px;
border: 1px solid #f7bd8f;
display: none;
}
.Slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 9px;
height: 9px;
border-radius: 5px;
background: #bf794e;
outline: none;
display: none;
}
.imageButtons {
position: relative;
margin-top: 10px;
width: 30px;
height: 30px;
border: none;
cursor: pointer;
display: none;
}
#screenshot_button {
margin-left: 1320px; /*Or 675px*/
/* background: url('/images/screenshot.png'); */
display: none;
}
#save_drawing_button {
margin-left: 20px;
/* background: url('/images/savejson.png'); */
display: none;
}
#index_UP_button {
margin-left: 20px;
/* background: url('/images/shapeindex_up.png'); */
display: none;
}
#index_DOWN_button {
margin-left: 20px;
/* background: url('/images/shapeindex_down.png'); */
display: none;
}
.Buttons {
position: relative;
-webkit-appearance: none;
margin-top: 10px;
height: 36px;
border: 2px solid #fff;
border-radius: 18px;
background: none;
font-size: 10pt;
font-family: Helvetica, Arial, sans-serif;
font-weight: 100;
cursor: pointer;
display: none;
}
#edit_button {
margin-top: 5px;
margin-left: 1310px; /*Or 665px*/
margin-bottom: 15px;
width: 200px;
border-color: #fff;
font-size: 14pt;
color: #fff;
display: none;
}
#complete_button {
margin-left: 1310px; /*Or 665px*/
border-color: #89c3eb;
color: #89c3eb;
width: 80px;
display: none;
}
#undo_button {
margin-left: 5px;
border-color: #fff;
color: #fff;
width: 50px;
display: none;
}
#delete_button {
margin-left: 5px;
border-color: #ee827c;
color: #ee827c;
width: 60px;
display: none;
}

View file

@ -0,0 +1,57 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js" crossorigin="anonymous"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="../../css/home.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<!-- <script src="sketch.js"></script> -->
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<!--#region title bar -->
<header id="titlebar">
<div id="drag-region">
<div id="window-controls">
<div class="button" id="min-button" tip="Minimize window">
<i class="fa-solid fa-window-minimize"></i>
</div>
<div class="button" id="max-button" tip="Maximize window">
<i class="fa-solid fa-window-maximize"></i>
</div>
<div class="button" id="close-button" tip="Close application">
<i class="fa-solid fa-xmark"></i>
</div>
</div>
</div>
</header>
<video autoplay playsinline id="video"></video>
<div class="select">
<label for="videoSource">Video source: </label
><select id="videoSource">
<option value="dba62f19023fcf5419be5deb87956950d5553bc211d92e0e82a1f2eb482c8d81">OBS Virtual Camera</option>
</select>
<button id="startCapture">start capture</button>
<button id="startFaceMask">start faceMask</button>
</div>
</body>
<script src="detection.js"></script>
</html>

View file

@ -0,0 +1,163 @@
{
"shapes": [
{
"fill_H": 91.49429372473857,
"fill_S": 50,
"fill_B": 0,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
361,
323,
454,
356,
389,
251,
284,
332,
297,
338,
10,
109,
67,
103,
54,
21,
162,
127,
234,
93,
132,
58,
172,
136,
150,
149,
176,
148,
152,
377,
400,
378,
379,
365,
397,
288,
361,
356,
356,
356,
356,
389
]
},
{
"fill_H": 0,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 289.82746786711664,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
33,
7,
163,
144,
145,
153,
154,
155,
133,
173,
157,
158,
159,
160,
161,
246,
33,
389
]
},
{
"fill_H": 21.511087878199753,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 321.581288983916,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 0,
"indices": [
263,
466,
388,
387,
386,
385,
384,
398,
362,
382,
381,
380,
374,
373,
390,
249,
263,
356
]
},
{
"fill_H": 360,
"fill_S": 0,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 0,
"stroke_S": 0,
"stroke_B": 0,
"stroke_O": 0,
"indices": [
14,
87,
178,
88,
95,
78,
191,
80,
81,
82,
13,
312,
311,
310,
415,
308,
324,
318,
402,
317,
14,
454
]
},
{
"fill_H": 139.54068362704467,
"fill_S": 50,
"fill_B": 100,
"fill_O": 100,
"stroke_H": 164.8282901046115,
"stroke_S": 50,
"stroke_B": 100,
"stroke_O": 100,
"indices": []
}
]
}

View file

@ -0,0 +1,186 @@
CHANNEL POINTS: Pesythos
REDEMPTIONS:
- GACHA TALK - 100
- GACHA RNGSUS- 500
- GACHA SOUNDS- 1K
- GACHA GIFS - 2K
- GACHA ASMR - 5K
- GACHA TROLL - 10K
GENERAL CATEGORIES:
- [GIF], meme
- [SOUND], meme
- [TROLL], viewer,streamer
- [INSULT], viewer,streamer
- [COMPLIMENT], viewer,streamer
ASMR CATEGORIES:
- [SOFT SPOKEN], NORMAL, ECHO
- [SUSURADO] , NORMAL, ECHO
- [PUTO], NORMAL, ECHO
- [PROTA], NORMAL, ECHO
- [TRIGGER], Normal, Echo
RARITY COLORS:
- Grey / Silver / COMÚN / 1 star / 100
- Green / Emerald / NO-COMÚN / 2 stars / 500
- Blue / Diamond / RARO / 3 stars / 1K
- Purple / Sapphire / ÉPICO / 4 stars / 10K
- Yellow / Gold / LEGENDARIO / 5 stars / 100K
TROLL:
invert mouse
flip screen
mirror screen
ASMR_EN:
tighten screws
brain massage
countdown
inaudible
mouth sounds
heavy breathing
beanbag
bubbles
water
sounds
card play
cepillar mic
acariciar mic
hand play
ASMR_ES:
apretar tornillos
masajear cerebro
cuenta regresiva
inaudible
sonidos de boca
respiración profunda
bolsita de frijoles
burbujas
sonidos de agua
juego de barajas, brush mic
caress mic
juego de manos
idea para tarjeta: "seguro dejas loot común cuando te matan"
GIFS_EN:
aaah
aproaching
beetch
damn
dead
deeznutz
drama
helpme
hidaddy
holyshit
howaboutno
illumina
fun
gaaay
gotem
sonofabitch
imout
justdoit
kabuki
lick
menacing
mudamudamuda
nani
nice
nogod
ohno
ohshit
omaewa
omg
omgwow
run
running
oraroraora
pirate
simuation
stopit
surprise
thisisfine
slowclap
wrongnumber
wtf
yareyaredaze
youknowhowmuchisacrificed
youserious
yesyesyes
GIFS_ES:
algonocuadra
aqueroso
baca
balsammg
bienhecho
bonita
callate
carga
comemierda
coñooo
corre
delincuente
diablopapi
droga
eldiablo
elmoreno
gritos
hablabien
hdp
inteligente
mmg
tmm
unmoreno
vegeta
klkconmigo
konodioda
ladrone
loro
lotuyo
mierda
misojos
mmg
mmm
muchachito
nacho
nomeden
nomevanacallar
nonono
nosabencuantohesacrificado
nosedimetu
pajaro
prepotente
preso
respeto
simetria
sobame
tiguere
vaina
yoresuelvo
zawarudo
AUDIO:
airhorn
applause
badumtiss
crickets
eso_pasa
goat_scream
johncena
ooo
Sad_Trombone
Sad_Violin
saludo
scream
tutturuu
whaawhaa
wilhelmscream
wombo_combo
yesyes

View file

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="css/style.css" />
</head>
<body></body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script src="./js/local_creds.js"></script>
<script src="./js/rates.js"></script>
<script src="./js/choices.js"></script>
<script src="./js/script.js"></script>
</html>

View file

@ -0,0 +1,314 @@
@font-face {
font-family: 'genshin';
src: url('../fonts/zh-cn.ttf') format('truetype');
}
html,
body {
margin: 0;
padding: 0;
font-family: 'genshin';
color: #fff;
text-shadow: 0 0 25px rgba(0, 0, 0, 1);
overflow: hidden;
}
h1 {
margin: 0;
padding: 0;
text-align: center;
font-size: 4rem;
position: relative;
}
.container {
width: 100%;
height: 100%;
/* background: rgba(0, 0, 0, 0.7); */
position: absolute;
overflow: hidden;
}
.container img#character {
/* animation: wishAppear 5s steps(100, end) forwards;
transform-origin: center;
display: block;
margin: 0 auto;
height: 100%;
max-width: 100%; */
}
.container h1#name {
animation: nameAppear 0.8s steps(100, end) forwards;
animation-delay: 1s;
animation-timing-function: ease;
position: absolute;
top: calc(50% - 250px);
left: calc(50% - 200px);
opacity: 0;
z-index: 10;
}
.container h2#redeemer {
animation: nameAppear 1.5s steps(100, end) forwards;
animation-delay: 3.5s;
animation-timing-function: ease;
position: absolute;
top: calc(50% - 185px);
left: calc(50% - 200px);
opacity: 0;
z-index: 20;
}
.container h2#redeemer::before {
content: 'redeemed by\A';
white-space: pre;
}
.container h2#redeemer span#actual_name {
font-size: 2.5rem;
}
.container img#element {
animation: nameAppear 0.6s steps(100, end) forwards;
animation-delay: 1.2s;
animation-timing-function: ease;
width: 158px;
height: 158px;
position: absolute;
top: calc(50% - 250px);
left: calc(50% - 350px);
opacity: 0;
filter: drop-shadow(0px 0px 5px rgb(0 0 0 / 0.8));
}
.container div#stars {
z-index: 20;
position: absolute;
top: calc(50% - 190px);
left: calc(50% - 200px);
filter: drop-shadow(0px 0px 5px rgb(0 0 0 / 0.8));
}
.container div#stars img {
animation: starAppear 0.3s steps(100, end) forwards;
animation-delay: 1s;
width: 30px;
height: 30px;
display: inline-block;
opacity: 0;
transform: scale(10);
}
.container.exit {
animation: genshinExit 0.3s steps(100, end) forwards;
}
@keyframes wishAppear {
0% {
filter: brightness(0) blur(20px);
transform: scale(10) translate(0, 0);
}
10% {
filter: brightness(0) blur(0);
transform: scale(1) translate(0, 0);
}
20% {
filter: brightness(0) blur(0);
transform: scale(1) translate(0, 0);
}
28% {
filter: brightness(0) blur(0);
transform: scale(1) translate(50px, 0);
}
30% {
filter: brightness(0) blur(0);
transform: scale(1) translate(50px, 0);
}
40% {
filter: brightness(1) blur(0);
transform: scale(1) translate(50px, 0);
}
100% {
filter: brightness(1) blur(0);
transform: scale(1) translate(50px, 0);
}
}
@keyframes nameAppear {
0% {
opacity: 0;
transform: translate(50px, 0);
}
100% {
opacity: 1;
transform: translate(0, 0);
}
}
@keyframes starAppear {
0% {
opacity: 0;
transform: scale(10);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@keyframes genshinExit {
0% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(10);
opacity: 0;
}
}
#link_to_token {
text-align: center;
display: block;
padding: 1em;
background: #59f;
color: #fff;
text-decoration: none;
width: 50%;
text-shadow: 2px 2px 2px rgb(0 0 0 / 30%);
min-width: 400px;
margin: 2em auto;
border-radius: 15px;
}
.card-stack {
animation: fade-in-up 0.5s ease forwards;
position: absolute;
bottom: -128px;
left: 50%;
width: 256px;
height: 384px;
left: calc(50% - 128px);
}
.single-card {
width: 256px;
height: 384px;
position: absolute;
display: flex;
justify-content: center;
perspective: 900px;
transition: all 0.2s cubic-bezier(0.7, -0.5, 0.3, 1.8);
transform-style: preserve-3d;
}
@keyframes fade-in-up {
0% {
opacity: 0;
transform: translate(0, 256px);
}
100% {
opacity: 1;
}
}
.front,
.back {
position: relative;
width: 256px;
height: 384px;
top: 0;
border-radius: 5px;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
background-size: cover;
background-position: center center;
}
.front {
background-image: url(../img/characters/back.png);
}
.back {
position: absolute;
transform: rotateY(180deg);
/* background-image: url(../img/characters/tmm.png); */
/* img/characters/imout.png */
}
.single-card:nth-child(1) {
animation: card1 0.5s forwards;
}
@keyframes card1 {
100% {
transform: translate(200px, 100px) rotate(26deg);
}
}
.single-card:nth-child(2) {
animation: card2 0.5s forwards;
}
@keyframes card2 {
100% {
transform: translate(100px, 25px) rotate(16deg);
}
}
.single-card:nth-child(3) {
animation: card3 0.5s forwards;
}
@keyframes card3 {
100% {
transform: translate(0px, 0px) rotate(0deg);
}
}
.single-card:nth-child(4) {
animation: card4 0.5s forwards;
}
@keyframes card4 {
100% {
transform: translate(-100px, 25px) rotate(-16deg);
}
}
.single-card:nth-child(5) {
animation: card5 0.5s forwards;
}
@keyframes card5 {
100% {
transform: translate(-200px, 100px) rotate(-26deg);
}
}
@keyframes rotateCard1 {
0% {
transform: translateX(200px);
}
100% {
transform: translate(0px, -250px) rotateY(180deg) scale(1.5);
}
}
@keyframes rotateCard2 {
0% {
transform: translateX(100px);
}
100% {
transform: translate(0px, -250px) rotateY(180deg) scale(1.5);
}
}
@keyframes rotateCard3 {
0% {
transform: translateX(0px);
}
100% {
transform: translate(0px, -250px) rotateY(180deg) scale(1.5);
}
}
@keyframes rotateCard4 {
0% {
transform: translateX(-100px);
}
100% {
transform: translate(0px, -250px) rotateY(180deg) scale(1.5);
}
}
@keyframes rotateCard5 {
0% {
transform: translateX(-200px);
}
100% {
transform: translate(0px, -250px) rotateY(180deg) scale(1.5);
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Some files were not shown because too many files have changed in this diff Show more