Add files via upload

This commit is contained in:
Rodrigo Emanuel
2025-05-11 02:34:38 -03:00
committed by GitHub
parent 594abf2dc1
commit 9f6fdfc691
22 changed files with 1249 additions and 79 deletions

View File

@@ -32,6 +32,14 @@
<span class="viewers"><i class="fa-solid fa-user"></i> <span>0</span></span> <span class="viewers"><i class="fa-solid fa-user"></i> <span>0</span></span>
<span class="likes"><i class="fa-solid fa-heart"></i> <span>0</span></span> <span class="likes"><i class="fa-solid fa-heart"></i> <span>0</span></span>
</div> </div>
<div class="platform" id="kick">
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<polygon class="st0" points="336 111 336 239 401 239 401 175 465 175 465 111 657 111 657 303 593 303 593 367 529 367 529 432 593 432 593 496 657 496 657 689 465 689 465 624 401 624 401 560 336 560 336 689 143 689 143 111 336 111"/>
</svg>
<span class="viewers"><i class="fa-solid fa-user"></i> <span>0</span></span>
</div>
</div> </div>
@@ -47,7 +55,7 @@
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.5/dist/purify.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.5/dist/purify.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/simple-notify@1.0.4/dist/simple-notify.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/simple-notify@1.0.4/dist/simple-notify.min.js"></script>
<script src="https://unpkg.com/@streamerbot/client/dist/streamerbot-client.js"></script> <script src="https://cdn.jsdelivr.net/npm/@streamerbot/client@1.9.5/dist/streamerbot-client.min.js"></script>
<script src="js/lang/ptbr.js"></script> <script src="js/lang/ptbr.js"></script>
<script src="js/lang/en.js"></script> <script src="js/lang/en.js"></script>
@@ -61,6 +69,7 @@
<script src="js/twitch/module.js"></script> <script src="js/twitch/module.js"></script>
<script src="js/youtube/module.js"></script> <script src="js/youtube/module.js"></script>
<script src="js/tiktok/module.js"></script> <script src="js/tiktok/module.js"></script>
<script src="js/kick/module.js"></script>
<script src="js/streamlabs/module.js"></script> <script src="js/streamlabs/module.js"></script>
<script src="js/streamelements/module.js"></script> <script src="js/streamelements/module.js"></script>

View File

@@ -70,25 +70,31 @@ body {
#chat .message .avatar { #chat .message .avatar {
display: inline-block; display: inline-block;
position: relative;
margin: 2px 0px; margin: 2px 0px;
width: 28px;
height: 28px;
overflow: hidden;
border-radius: 100px;
transform: translateY(11px);
} }
#chat .message .avatar img { #chat .message .avatar img {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
height: 28px; height: 28px;
border-radius: 100px;
} }
#chat .message .platform { #chat .message .platform {
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: #000;
width: 24px; width: 24px;
height: 24px; height: 24px;
font-size: 18px; filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.25));
transform: translateY(2px); transform: translateY(6px);
border-radius: 5px;
text-shadow: 2px 2px 2px rgba(0,0,0,0.25);
} }
#chat .message .badges i { #chat .message .badges i {
@@ -134,15 +140,6 @@ body {
color: #999; color: #999;
} }
#chat .message.twitch .shared span {
display: inline-block;
border-radius: 5px;
padding: 2px 10px 2px 5px;
background: rgba(169,112,255,0.85);
background: linear-gradient(180deg, rgba(169,112,255,0.85) 0%, rgba(95,67,138,0.85) 100%);
color: #fff;
}
#chat .message .shared i { #chat .message .shared i {
margin: 0 3px; margin: 0 3px;
} }
@@ -153,10 +150,10 @@ body {
font-size: 16px; font-size: 16px;
} }
#chat .message.event .platform { #chat .message.event .platform {
background: none;
margin: 2px 7px 0 6px;
transform: translateY(0px); transform: translateY(0px);
margin: 0px 5px 0 0;
} }
#chat .message.event > div { #chat .message.event > div {
@@ -170,7 +167,16 @@ body {
/*#chat .message.twitch .platform { background: #a970ff; }*/
#chat .message.twitch .shared span {
display: inline-block;
border-radius: 5px;
padding: 2px 10px 2px 5px;
background: rgba(169,112,255,0.85);
background: linear-gradient(180deg, rgba(169,112,255,0.85) 0%, rgba(95,67,138,0.85) 100%);
color: #fff;
}
#chat .message.twitch.first-message > div { #chat .message.twitch.first-message > div {
background: rgba(18,18,18,0.5); background: rgba(18,18,18,0.5);
@@ -185,31 +191,11 @@ body {
} }
#chat .message.twitch .platform { color: #a970ff; background: transparent !important; text-shadow: 0px 0px 0px #a970ff;}
#chat .message.twitch .platform::after {
content: '';
background: #FFF;
width: 11px;
height: 10px;
position: absolute;
z-index: -1;
transform: translate(1px,-3px);
}
#chat .message.twitch.event .platform {
color: #FFF;
}
#chat .message.twitch.event .platform::after {
background: transparent;
text-shadow: none;
}
#chat .message.twitch .badges img { margin: 0 2px; } #chat .message.twitch .badges img { margin: 0 2px; }
#chat .message.twitch.event > div { #chat .message.twitch.event > div {
background: rgba(169,112,255,0.85); background: rgba(169,112,255,0.85);
background: linear-gradient(180deg, rgba(169,112,255,0.85) 0%, rgba(95,67,138,0.85) 100%); background: linear-gradient(180deg, rgba(169,112,255,0.85) 0%, rgba(95,67,138,0.85) 100%);
} }
#chat .message.twitch.event .platform { background: transparent; }
#chat .message.twitch.announcement > div { #chat .message.twitch.announcement > div {
padding: 10px 15px 13px 10px; padding: 10px 15px 13px 10px;
@@ -229,6 +215,7 @@ body {
} }
#chat .message.twitch.announcement .platform { #chat .message.twitch.announcement .platform {
transform: translateY(6px);
margin: 0; margin: 0;
} }
@@ -250,6 +237,7 @@ body {
} }
#chat .message.twitch.rewards-redemption .platform { #chat .message.twitch.rewards-redemption .platform {
transform: translateY(6px);
margin: 0; margin: 0;
} }
@@ -259,19 +247,11 @@ body {
/*#chat .message.youtube .platform { background: #ff0000; }*/
#chat .message.youtube .platform { color: #FF0000; background: transparent !important; }
#chat .message.youtube .platform::after { content: ''; background: #FFF; width: 5px; height: 5px; position: absolute; z-index: -1; }
#chat .message.youtube.event .platform { color: #FFF; } #chat .message.youtube.event .platform { color: #FFF; }
#chat .message.youtube.event .platform::after { background: transparent; }
#chat .message.youtube.event > div { #chat .message.youtube.event > div {
background: rgba(255,0,0,0.85); background: rgba(255,0,0,0.85);
background: linear-gradient(180deg, rgba(255,0,0,0.85) 1%, rgba(136,0,0,0.85) 100%); background: linear-gradient(180deg, rgba(255,0,0,0.85) 1%, rgba(136,0,0,0.85) 100%);
} }
#chat .message.youtube.event .platform { background: transparent; }
#chat .message.youtube.owner .user { #chat .message.youtube.owner .user {
@@ -326,37 +306,26 @@ body {
#chat .message.streamlabs .platform { background: #80f5d2; }
#chat .message.streamlabs.event > div { #chat .message.streamlabs.event > div {
background: rgba(128,245,210,0.85); background: rgba(128,245,210,0.85);
background: linear-gradient(180deg, rgba(128,245,210,0.85) 1%, rgba(8,108,78,0.85) 100%); background: linear-gradient(180deg, rgba(128,245,210,0.85) 1%, rgba(8,108,78,0.85) 100%);
} }
#chat .message.streamlabs.event .platform { background: transparent; }
#chat .message.streamelements .platform { background: #2700ff; }
#chat .message.streamelements.event > div { #chat .message.streamelements.event > div {
background: rgba(39,0,255,0.85); background: rgba(39,0,255,0.85);
background: linear-gradient(180deg, rgba(39,0,255,0.85) 1%, rgba(13,0,88,0.85) 100%); background: linear-gradient(180deg, rgba(39,0,255,0.85) 1%, rgba(13,0,88,0.85) 100%);
} }
#chat .message.streamelements.event .platform { background: transparent; }
/*#chat .message.tiktok .platform { background: #000; }*/
#chat .message.tiktok .platform { color: #FFF; background: transparent !important; }
#chat .message.tiktok.event > div { #chat .message.tiktok.event > div {
background: rgba(255,0,80,0.85); background: rgba(255,0,80,0.85);
background: linear-gradient(180deg, rgba(255,0,80,0.85) 1%, rgba(120,0,38,0.85) 100%); background: linear-gradient(180deg, rgba(255,0,80,0.85) 1%, rgba(120,0,38,0.85) 100%);
} }
#chat .message.tiktok.event .platform { background: transparent; }
#chat .message.tiktok.mod .badges i.fa-solid.fa-wrench { #chat .message.tiktok.mod .badges i.fa-solid.fa-wrench {
background: #121212; background: #121212;
@@ -369,6 +338,29 @@ body {
#chat .message.kick .badges svg {
width: 20px;
transform: translateY(4px);
}
#chat .message.kick .badges i.sub {
margin: 0;
color: #48d415;
}
#chat .message.kick.event > div {
background: #48d415;
background: linear-gradient(180deg,rgba(72, 212, 21, 1) 0%, rgba(39, 145, 0, 1) 100%);
}
#chat.horizontal { #chat.horizontal {
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
@@ -393,6 +385,7 @@ body {
font-weight: bold; font-weight: bold;
-webkit-mask-image: linear-gradient(to top, transparent, black 40%); -webkit-mask-image: linear-gradient(to top, transparent, black 40%);
mask-image: linear-gradient(to top, transparent, black 40%); mask-image: linear-gradient(to top, transparent, black 40%);
text-shadow: 2px 2px 2px rgba(0,0,0,0.25);
} }
@@ -428,3 +421,35 @@ body {
#statistics .platform#tiktok { #statistics .platform#tiktok {
background: #ff0050; background: #ff0050;
} }
#statistics .platform#kick {
background: #48d415;
}
#statistics .platform#kick svg {
width: 24px;
fill: #FFF;
filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.25));
}
@media (max-width: 768px) {
#statistics {
justify-content: center;
padding: 20px 10px;
font-size: 12px;
gap: 5px;
text-shadow: 2px 2px 2px rgba(0,0,0,0.5);
}
#statistics .platform {
padding: 5px 10px;
text-align: center;
}
#statistics .platform#kick svg {
width: 18px;
filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.5));
}
}

View File

@@ -93,6 +93,12 @@ a { color: #ffcc00; }
margin-right: 5px; margin-right: 5px;
} }
.tab-content h2 svg {
width: 26px;
vertical-align: bottom;
fill: #FFF;
}
.tab-content .setting { .tab-content .setting {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -278,6 +284,10 @@ a { color: #ffcc00; }
background-color: #ff0050; background-color: #ff0050;
} }
.tab-content#kick .setting input[type=checkbox]:checked + .slider {
background-color: #48d415;
}
.tab-content#extras .setting input[type=checkbox]:checked + .slider { .tab-content#extras .setting input[type=checkbox]:checked + .slider {
background-color: #00dd63; background-color: #00dd63;
} }
@@ -304,7 +314,7 @@ footer {
padding: 20px; padding: 20px;
background: rgba(18,18,18,0.5); background: rgba(18,18,18,0.5);
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
margin-top: 20px; margin-top: 80px;
font-size: 14px; font-size: 14px;
} }
@@ -315,6 +325,58 @@ footer a {
color: #ffcc00; color: #ffcc00;
} }
footer a svg {
width: 24px;
vertical-align: bottom;
fill: #ffcc00;
}
footer .nav-bar {
display: inline-flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 12px;
width: 100%;
}
footer .nav-bar a {
display: inline-block;
border-radius: 100px;
padding: 10px 15px;
margin: 0;
font-size: 16px;
text-decoration: none;
color: #FFF;
transition: all ease-in-out 300ms;
}
footer .nav-bar a:hover {
color: #ffcc00;
background: rgba(0,0,0,0.40);
}
footer .nav-bar a svg {
width: 20px;
fill: #FFF;
transition: all ease-in-out 300ms;
}
footer .nav-bar a:hover svg {
fill: #ffcc00;
}
footer .nav-bar a.active {
color: #ffcc00;
background: rgba(0,0,0,0.20);
}
footer .nav-bar a.active svg {
fill: #ffcc00;
}
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
#chat-divided { #chat-divided {

12
images/logo-kick.svg Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<!-- Generator: Adobe Illustrator 29.0.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 186) -->
<defs>
<style>
.st0 {
fill: #53fc18;
}
</style>
</defs>
<polygon class="st0" points="336 111 336 239 401 239 401 175 465 175 465 111 657 111 657 303 593 303 593 367 529 367 529 432 593 432 593 496 657 496 657 689 465 689 465 624 401 624 401 560 336 560 336 689 143 689 143 111 336 111"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800 800">
<!-- Generator: Adobe Illustrator 29.0.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 186) -->
<defs>
<style>
.st0 {
fill: url(#linear-gradient2);
}
.st1 {
fill: #fff;
}
.st2 {
mask: url(#mask);
}
.st3 {
fill: url(#linear-gradient1);
}
.st4 {
fill: url(#linear-gradient4);
}
.st5 {
fill: #ff4800;
}
.st6 {
fill: url(#linear-gradient3);
}
.st7 {
fill: url(#linear-gradient);
}
</style>
<linearGradient id="linear-gradient" x1="399.1" y1="810.1" x2="399.1" y2="-83.5" gradientTransform="translate(0 800) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset=".3" stop-color="#00adff"/>
<stop offset="1" stop-color="#1542ff"/>
</linearGradient>
<mask id="mask" x="152.6" y="181.1" width="493" height="481.8" maskUnits="userSpaceOnUse">
<g id="mask0_131_34">
<path class="st1" d="M399.1,662.5c133,0,240.9-107.8,240.9-240.7s-107.8-240.7-240.9-240.7-240.9,107.8-240.9,240.7,107.8,240.7,240.9,240.7Z"/>
</g>
</mask>
<linearGradient id="linear-gradient1" x1="399" y1="377" x2="399" y2="55.8" gradientTransform="translate(0 800) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fce3ad"/>
<stop offset="0" stop-color="#fce2a4"/>
<stop offset=".2" stop-color="#fce08b"/>
<stop offset=".3" stop-color="#fcdd64"/>
<stop offset=".5" stop-color="#fcda32"/>
<stop offset=".7" stop-color="#f9bc22"/>
<stop offset="1" stop-color="#f57700"/>
</linearGradient>
<linearGradient id="linear-gradient2" x1="399.1" y1="294.8" x2="399.1" y2="112.3" gradientTransform="translate(0 800) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fcd619"/>
<stop offset=".3" stop-color="#f9b811"/>
<stop offset="1" stop-color="#f57700"/>
</linearGradient>
<linearGradient id="linear-gradient3" x1="399.1" y1="203.5" x2="399.1" y2="119.4" gradientTransform="translate(0 800) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#f57700"/>
<stop offset="1" stop-color="#ff4800"/>
</linearGradient>
<linearGradient id="linear-gradient4" x1="399.1" y1="704.2" x2="399.1" y2="279.8" gradientTransform="translate(0 800) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#e4e4e4"/>
<stop offset=".9" stop-color="#b6b8b8"/>
</linearGradient>
</defs>
<path class="st7" d="M470.6,150l15.3,29.8c101.5,36.4,171.2,134.3,171.2,242.7s-115.7,257.8-258,257.8-257.9-115.6-257.9-257.8,69.7-206.3,171.2-242.7l15.3-29.7c-122.9,32.1-210.4,144-210.4,272.4s126.5,281.7,281.8,281.7,281.8-126.4,281.8-281.7-87.5-240.3-210.4-272.4Z"/>
<g class="st2">
<g>
<path class="st3" d="M640.5,416.1c-1.4,18.3-29.7,94.4-64.5,94.4s-17.3-20.7-19.6-36c-6.3,24.5-49.5,77.5-81.5,77.5-58.3,0-71.8-122.8-75.8-139.2-4,16.3-17.5,139.2-75.8,139.2s-75.3-52.9-81.5-77.5c-2.3,15.4-5.4,36-19.6,36-34.8,0-63.1-76.1-64.5-94.4-7.5,11-7.3,55.5,3.7,84,37,95.1,129.5,162.7,237.6,162.7s200.6-67.6,237.6-162.7c11.1-28.5,11.2-73,3.7-84h.1Z"/>
<path class="st0" d="M399.1,552.2c9.6,17.6,30.5,44,66.3,44s63.7-36.9,73-52.5c-3,11-9,34.4,10.5,34.4,44.7,0,77-70.6,77-70.6-35.3,90.8-123.6,155.3-226.8,155.3s-191.5-64.5-226.8-155.3c0,0,32.3,70.6,77,70.6s13.4-23.5,10.5-34.4c9.3,15.6,36.3,52.5,73,52.5s56.7-26.4,66.3-44Z"/>
<path class="st6" d="M455.9,631.5c-22,0-39.1-6.8-56.8-17.8-17.7,11-34.8,17.8-56.8,17.8-33.5,0-43.7-9.9-55.8-18.9.3,11.5,12.1,27.8,24.2,33.7,27,11.9,57.2,16.6,88.4,16.6s61.4-4.8,88.4-16.6c12.1-5.9,23.8-22.1,24.2-33.7-12.1,9-22.3,18.9-55.8,18.9Z"/>
</g>
</g>
<path class="st5" d="M366.6,304.9l-34.6,73.2c-1.4,3-1.9,6.4-1.4,9.7l11,66.2c.3,2.1,3.5,2.1,3.8,0l5.9-36.1c2.4-15,10.4-28.5,22.3-37.9l-7.1-75.2h0Z"/>
<path class="st5" d="M431.7,304.9l34.6,73.2c1.4,3,1.9,6.4,1.4,9.7l-11,66.2c-.3,2.1-3.4,2.1-3.8,0l-5.9-36.1c-2.4-15-10.4-28.5-22.3-37.9l7.1-75.2h0Z"/>
<path class="st4" d="M450.2,190l-47.4-91.9c-1.5-3-5.8-3-7.3,0l-47.4,91.9c-2,3.8-2.7,8.1-2.1,12.3l23.9,167.9-3.6,15.7,12.6,34.6c.3.8,1,1.3,1.8,1.3h36.7c.8,0,1.5-.5,1.8-1.3l12.6-34.6-3.6-15.7,23.9-167.9c.6-4.2-.1-8.5-2.1-12.3h.2Z"/>
<path class="st5" d="M397.5,342.5l-16.8,41.6c-2.6,6.4-3.1,13.6-1.4,20.3l18,71.9c.5,2,3.3,2,3.8,0l18-71.9c1.7-6.7,1.2-13.8-1.4-20.3l-16.8-41.6c-.6-1.5-2.7-1.5-3.3,0h0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<!-- Generator: Adobe Illustrator 29.0.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 186) -->
<defs>
<style>
.st0 {
fill: #fff;
fill-rule: evenodd;
}
</style>
</defs>
<path class="st0" d="M239.1,449.1c0-62.2,0-93.2,12.1-117,10.6-20.9,27.6-37.9,48.5-48.5,23.7-12.1,54.8-12.1,117-12.1h88.8c62.2,0,93.2,0,117,12.1,20.9,10.6,37.9,27.6,48.5,48.5,12.1,23.7,12.1,54.8,12.1,117v25.4c0,62.2,0,93.2-12.1,117-10.6,20.9-27.6,37.9-48.5,48.5-23.7,12.1-54.8,12.1-117,12.1h-164.9c-35.5,0-53.3,0-66.8-6.9-11.9-6.1-21.6-15.8-27.7-27.7-6.9-13.6-6.9-31.3-6.9-66.8v-101.5ZM397.6,461.8c0-17.5,14.2-31.7,31.7-31.7s31.7,14.2,31.7,31.7v63.4c0,17.5-14.2,31.7-31.7,31.7s-31.7-14.2-31.7-31.7v-63.4ZM556.1,430.1c-17.5,0-31.7,14.2-31.7,31.7v63.4c0,17.5,14.2,31.7,31.7,31.7s31.7-14.2,31.7-31.7v-63.4c0-17.5-14.2-31.7-31.7-31.7Z"/>
<path class="st0" d="M349.8,175.7c2.2,17.4-10.2,33.2-27.6,35.4-9.6,1.2-17.3,2.8-24.1,4.9-54.7,17-97.6,59.9-114.6,114.6-2.1,6.8-3.7,14.5-4.9,24.1-2.2,17.4-18,29.7-35.4,27.6-17.4-2.2-29.7-18-27.6-35.4,1.6-12.5,3.8-24,7.3-35.1,23.2-74.6,81.7-133,156.3-156.3,11.1-3.5,22.6-5.8,35.1-7.3,17.4-2.2,33.2,10.2,35.4,27.6Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

12
images/logo-tiktok.svg Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<!-- Generator: Adobe Illustrator 29.0.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 186) -->
<defs>
<style>
.st0 {
fill: #fff;
}
</style>
</defs>
<path class="st0" d="M682.3,351.7c-55.5.1-109.6-17.2-154.7-49.5v225.3c0,85.4-53.1,161.9-133.1,191.8-80,29.9-170.2,7.1-226.3-57.4-56.1-64.4-66.3-156.9-25.7-232.1,40.7-75.1,123.7-117.1,208.3-105.4v113.3c-38.8-12.2-81,1.9-104.7,35-23.7,33.1-23.4,77.6.6,110.4,24.1,32.8,66.5,46.4,105.1,33.7s64.8-48.7,64.8-89.4V87.1h110.9c0,9.4.7,18.7,2.3,27.9,7.8,41.6,32.4,78.2,67.9,101.1,25,16.6,54.4,25.4,84.4,25.4v110.1Z"/>
</svg>

After

Width:  |  Height:  |  Size: 730 B

17
images/logo-twitch.svg Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<!-- Generator: Adobe Illustrator 29.0.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 186) -->
<defs>
<style>
.st0 {
fill: #fff;
}
.st1 {
fill: #a970ff;
}
</style>
</defs>
<polygon class="st0" points="668.5 400 482 602 208 560 224 73 678 91 668.5 400"/>
<path class="st1" d="M723.1,53.8v357l-242.4,229.5h-107.7l-134.6,127.5v-127.5H76.9V181.3L211.5,53.8h511.7ZM669.3,104.8H238.4v382.5h121.2v89.3l94.3-89.3h107.7l107.7-102V104.8ZM440.4,350.5h-53.9v-153.1h53.9v153.1ZM588.5,351.1h-53.9v-153h53.9v153Z"/>
</svg>

After

Width:  |  Height:  |  Size: 698 B

17
images/logo-youtube.svg Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<!-- Generator: Adobe Illustrator 29.0.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 186) -->
<defs>
<style>
.st0 {
fill: #fff;
}
.st1 {
fill: red;
}
</style>
</defs>
<rect class="st0" x="283" y="283" width="284" height="272"/>
<path class="st1" d="M744.2,410.3s0,112.7-14.4,166.8c-7.9,29.8-31.2,52.3-60.9,60.3-53.7,14.5-268.9,14.5-268.9,14.5,0,0-215.3,0-268.9-14.5-29.6-8-52.9-30.5-60.9-60.3-14.4-54-14.4-166.8-14.4-166.8,0,0,0-112.7,14.4-166.8,7.9-29.8,31.2-53.3,60.9-61.3,53.7-14.5,268.9-14.5,268.9-14.5,0,0,215.3,0,268.9,14.5,29.6,8,52.9,31.4,60.9,61.3,14.4,54,14.4,166.8,14.4,166.8ZM509.5,410.3l-179.9-102.4v204.7l179.9-102.3Z"/>
</svg>

After

Width:  |  Height:  |  Size: 833 B

View File

@@ -32,13 +32,18 @@
<div class="setting field"><label>Streamer.bot WebSocket Server</label><input type="text" name="streamerBotServerAddress" value="127.0.0.1"></div> <div class="setting field"><label>Streamer.bot WebSocket Server</label><input type="text" name="streamerBotServerAddress" value="127.0.0.1"></div>
<div class="setting field"><label>Streamer.bot WebSocket Port</label><input type="text" name="streamerBotServerPort" value="8080"></div> <div class="setting field"><label>Streamer.bot WebSocket Port</label><input type="text" name="streamerBotServerPort" value="8080"></div>
<div class="setting"><label>Text-to-Speech Chat<br><small>Enables TTS for Chat.</small></label><label class="switch"><input type="checkbox" name="ttsSpeakerBotChat"><span class="slider"></span></label></div>
<div class="setting"><label>Text-to-Speech Events<br><small>Enables TTS for Events.</small></label><label class="switch"><input type="checkbox" name="ttsSpeakerBotEvents"><span class="slider"></span></label></div> <div class="setting"><label>Run Locally<br><small>In case you want to download ChatRD to run locally or over the network.<br><strong><a target="_blank" href="https://github.com/vortisrd/chatrd#%EF%B8%8F-how-to-use-it-in-a-local-network">Follow the tutorial</a></strong>.</small></label><label class="switch"><input type="checkbox" name="runThisLocally"><span class="slider"></span></label></div>
<div class="setting"></div>
<div class="setting"><small style="display: inline-block; padding: 10px 20px 10px 10px; background-color: #232323; color: #FFF; border-radius: 10px;"><i class="fa-solid fa-volume-high"></i> Speaker.Bot is required for Text-to-Speech! <strong><a target="_blank" href="https://github.com/vortisrd/chatrd#-how-to-set-tts-with-speakerbot">Follow the tutorial</a>.</strong></small></label></div> <div class="setting"><small style="display: inline-block; padding: 10px 20px 10px 10px; background-color: #232323; color: #FFF; border-radius: 10px;"><i class="fa-solid fa-volume-high"></i> Speaker.Bot is required for Text-to-Speech! <strong><a target="_blank" href="https://github.com/vortisrd/chatrd#-how-to-set-tts-with-speakerbot">Follow the tutorial</a>.</strong></small></label></div>
<div class="setting"><label>Run Locally<br><small>In case you want to download ChatRD to run locally or over the network.<br><strong><a target="_blank" href="https://github.com/vortisrd/chatrd#%EF%B8%8F-how-to-use-it-in-a-local-network">Follow the tutorial</a></strong>.</small></label><label class="switch"><input type="checkbox" name="runThisLocally"><span class="slider"></span></label></div> <div class="setting"></div>
<div class="setting"><label>Text-to-Speech Chat<br><small>Enables TTS for Chat.</small></label><label class="switch"><input type="checkbox" name="ttsSpeakerBotChat"><span class="slider"></span></label></div>
<div class="setting"><label>Text-to-Speech Events<br><small>Enables TTS for Events.</small></label><label class="switch"><input type="checkbox" name="ttsSpeakerBotEvents"><span class="slider"></span></label></div>
</div> </div>
<div class="tab-content" id="geral"> <div class="tab-content" id="geral">
@@ -104,13 +109,18 @@
<div class="setting"><label><i class="fa-solid fa-arrow-turn-up"></i> Gifted Membership Train<br><small>Shows all users that were gifted a membership on a massive gifting membership.</small></label><label class="switch"><input type="checkbox" name="showYouTubeMembershipsTrain" checked><span class="slider"></span></label></div> <div class="setting"><label><i class="fa-solid fa-arrow-turn-up"></i> Gifted Membership Train<br><small>Shows all users that were gifted a membership on a massive gifting membership.</small></label><label class="switch"><input type="checkbox" name="showYouTubeMembershipsTrain" checked><span class="slider"></span></label></div>
<div class="setting"><label>Statistics<br><small>Shows viewers and likes.</small></label><label class="switch"><input type="checkbox" name="showYouTubeStatistics" checked><span class="slider"></span></label></div> <div class="setting"><label>Statistics<br><small>Shows viewers and likes.</small></label><label class="switch"><input type="checkbox" name="showYouTubeStatistics" checked><span class="slider"></span></label></div>
<div class="setting"></div>
<div class="setting"><small style="display: inline-block; padding: 10px 20px 10px 10px; background-color: #232323; color: #FFF; border-radius: 10px;"><i class="fa-solid fa-circle-exclamation"></i> YouTube API doesn't expose Member Emotes. <strong><a target="_blank" href="https://github.com/vortisrd/chatrd/tree/main?tab=readme-ov-file#about-youtube-membership-emojis">Read more</a>.</strong></small></label></div>
<div class="setting"></div>
<div class="setting column"> <div class="setting column">
<label> <label>
Members Only Emotes Members Only Emotes
<br> <br>
<small>Because YouTube's API doesn't expose Partner Custom Emotes. <em>Really YouTube!?</em> 🤨 <small>You have to add member emotes manually. <em>Really YouTube!?</em> 🤨
</small> </small>
</label> </label>
<div class="emote-list"> <div class="emote-list">
@@ -129,12 +139,40 @@
<h2><i class="fa-brands fa-tiktok"></i> TikTok</h2> <h2><i class="fa-brands fa-tiktok"></i> TikTok</h2>
<div class="setting"><label>Chat</label><label class="switch"><input type="checkbox" name="showTikTokMessages" checked><span class="slider"></span></label></div> <div class="setting"><label>Chat</label><label class="switch"><input type="checkbox" name="showTikTokMessages" checked><span class="slider"></span></label></div>
<div class="setting"><label>Followers</label><label class="switch"><input type="checkbox" name="showTikTokFollows" checked><span class="slider"></span></label></div> <div class="setting"><label>Followers</label><label class="switch"><input type="checkbox" name="showTikTokFollows" checked><span class="slider"></span></label></div>
<!--<div class="setting"><label>Likes</label><label class="switch"><input type="checkbox" name="showTikTokLikes" checked><span class="slider"></span></label></div>-->
<div class="setting"><label>Gifts</label><label class="switch"><input type="checkbox" name="showTikTokGifts" checked><span class="slider"></span></label></div> <div class="setting"><label>Gifts</label><label class="switch"><input type="checkbox" name="showTikTokGifts" checked><span class="slider"></span></label></div>
<div class="setting"><label>Subscriptions</label><label class="switch"><input type="checkbox" name="showTikTokSubs" checked><span class="slider"></span></label></div> <div class="setting"><label>Subscriptions</label><label class="switch"><input type="checkbox" name="showTikTokSubs" checked><span class="slider"></span></label></div>
<div class="setting"><label>Statistics<br><small>Shows viewers and likes.</small></label><label class="switch"><input type="checkbox" name="showTikTokStatistics" checked><span class="slider"></span></label></div> <div class="setting"><label>Statistics<br><small>Shows viewers and likes.</small></label><label class="switch"><input type="checkbox" name="showTikTokStatistics" checked><span class="slider"></span></label></div>
</div> </div>
<div class="tab-content" id="kick">
<h2>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<polygon class="st0" points="336 111 336 239 401 239 401 175 465 175 465 111 657 111 657 303 593 303 593 367 529 367 529 432 593 432 593 496 657 496 657 689 465 689 465 624 401 624 401 560 336 560 336 689 143 689 143 111 336 111"/>
</svg>
Kick
</h2>
<div class="setting"><small style="display: inline-block; padding: 10px 20px 10px 10px; background-color: #232323; color: #FFF; border-radius: 10px;"><i class="fa-solid fa-triangle-exclamation"></i> This is a <strong>BETA</strong> feature! <a href="https://github.com/vortisrd/chatrd/tree/main#%EF%B8%8F-kick-is-a-beta-feature" target="_blank">Read more</a>.</small></label></div>
<div class="setting"></div>
<div class="setting field"><label>Your Kick Username<br><small>Your user handle. It's on kick.com/<strong><u>username</u></strong></small></label><input type="text" name="kickUserName" value=""></div>
<div class="setting"><label>Viewers<br><small>Self-updates each 15 seconds.</small></label><label class="switch"><input type="checkbox" name="showKickViewers" checked><span class="slider"></span></label></div>
<div class="setting"></div>
<div class="setting"><small style="display: inline-block; padding: 10px 20px 10px 10px; background-color: #232323; color: #FFF; border-radius: 10px;"><i class="fa-solid fa-circle-exclamation"></i> <strong><a href="https://github.com/Sehelitar/Kick.bot/" target="_blank">Kick.Bot</a></strong> is required for events. <strong><a target="_blank" href="https://github.com/vortisrd/chatrd/tree/main#kickbot-installation-on-streamerbot">Follow the tutorial</a>.</strong></small></label></div>
<div class="setting"></div>
<div class="setting"><label>Chat</label><label class="switch"><input type="checkbox" name="showKickMessages" checked><span class="slider"></span></label></div>
<div class="setting"><label>Followers</label><label class="switch"><input type="checkbox" name="showKickFollows" checked><span class="slider"></span></label></div>
<div class="setting"><label>Subscriptions<br><small>Show Subscription events. <u><strong>Disabling this disables all sub events</strong></u>.</small></label><label class="switch"><input type="checkbox" name="showKickSubs" checked><span class="slider"></span></label></div>
<div class="setting"><label><i class="fa-solid fa-arrow-turn-up"></i> Gifted Subs<br><small>When a user gifts another user a sub.</small></label><label class="switch"><input type="checkbox" name="showKickGiftedSubs" checked><span class="slider"></span></label></div>
<div class="setting"><label><i class="fa-solid fa-arrow-turn-up"></i> Gifted Bomb<br><small>When a user gifts subs massively.</small></label><label class="switch"><input type="checkbox" name="showKickMassGiftedSubs" checked><span class="slider"></span></label></div>
<div class="setting"><label>Raids</label><label class="switch"><input type="checkbox" name="showKickRaids" checked><span class="slider"></span></label></div>
</div>
<div class="tab-content" id="extras"> <div class="tab-content" id="extras">
<h2><i class="fa-solid fa-dollar-sign"></i> Donations</h2> <h2><i class="fa-solid fa-dollar-sign"></i> Donations</h2>
<div class="setting"><label>Streamlabs Tips</label><label class="switch"><input type="checkbox" name="showStreamlabsDonations" checked><span class="slider"></span></label></div> <div class="setting"><label>Streamlabs Tips</label><label class="switch"><input type="checkbox" name="showStreamlabsDonations" checked><span class="slider"></span></label></div>
@@ -143,6 +181,21 @@
<footer> <footer>
<div class="nav-bar">
<a href="#config" class="active"><i class="fa-solid fa-screwdriver-wrench"></i></a>
<a href="#geral"><i class="fa-solid fa-gears"></i></a>
<a href="#twitch"><i class="fa-brands fa-twitch"></i></a>
<a href="#youtube"><i class="fa-brands fa-youtube"></i></a>
<a href="#tiktok"><i class="fa-brands fa-tiktok"></i></a>
<a href="#kick">
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<polygon class="st0" points="336 111 336 239 401 239 401 175 465 175 465 111 657 111 657 303 593 303 593 367 529 367 529 432 593 432 593 496 657 496 657 689 465 689 465 624 401 624 401 560 336 560 336 689 143 689 143 111 336 111"/>
</svg>
</a>
<a href="#extras"><i class="fa-solid fa-dollar-sign"></i></a>
</div>
<div class="url-bar"> <div class="url-bar">
<input type="text" id="outputUrl" placeholder="URL Here..." readonly=""> <input type="text" id="outputUrl" placeholder="URL Here..." readonly="">
<button onclick="copyUrl()">Copy URL</button> <button onclick="copyUrl()">Copy URL</button>
@@ -153,6 +206,11 @@
<a target="_blank" href="https://twitch.com/vortisrd"><i class="fa-brands fa-twitch"></i></a> <a target="_blank" href="https://twitch.com/vortisrd"><i class="fa-brands fa-twitch"></i></a>
<a target="_blank" href="https://youtube.com/@vortisrd"><i class="fa-brands fa-youtube"></i></a> <a target="_blank" href="https://youtube.com/@vortisrd"><i class="fa-brands fa-youtube"></i></a>
<a target="_blank" href="https://tiktok.com/@vortisrd"><i class="fa-brands fa-tiktok"></i></a> <a target="_blank" href="https://tiktok.com/@vortisrd"><i class="fa-brands fa-tiktok"></i></a>
<a target="_blank" href="https://kick.com/vortisrd">
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 800 800">
<polygon class="st0" points="336 111 336 239 401 239 401 175 465 175 465 111 657 111 657 303 593 303 593 367 529 367 529 432 593 432 593 496 657 496 657 689 465 689 465 624 401 624 401 560 336 560 336 689 143 689 143 111 336 111"/>
</svg>
</a>
<a target="_blank" href="https://x.com/vortisrd"><i class="fa-brands fa-x-twitter"></i></a> <a target="_blank" href="https://x.com/vortisrd"><i class="fa-brands fa-x-twitter"></i></a>
<a target="_blank" href="https://github.com/vortisrd"><i class="fa-brands fa-github"></i></a> <a target="_blank" href="https://github.com/vortisrd"><i class="fa-brands fa-github"></i></a>
</p> </p>

View File

@@ -162,6 +162,17 @@ const mockData = {
{ "imageUrl": "https://static-cdn.jtvnw.net/badges/v1/4149750c-9582-4515-9e22-da7d5437643b/3" }, { "imageUrl": "https://static-cdn.jtvnw.net/badges/v1/4149750c-9582-4515-9e22-da7d5437643b/3" },
{ "imageUrl": "https://static-cdn.jtvnw.net/badges/v1/5864739a-5e58-4623-9450-a2c0555ef90b/3" } { "imageUrl": "https://static-cdn.jtvnw.net/badges/v1/5864739a-5e58-4623-9450-a2c0555ef90b/3" }
], ],
badgeskick: [
{ "type": "broadcaster" },
{ "type": "sidekick" },
{ "type": "moderator" },
{ "type": "vip" },
{ "type": "sub_gifter" },
{ "type": "og" },
{ "type": "founder" },
{ "type": "verified" },
{ "type": "subscriber" },
],
superstickers: [ superstickers: [
{ "imageUrl": "https://lh3.googleusercontent.com/G2OgWJkuvSullUPp2i09zG_WR0IpQu-6Ti4pFXn_FJ1OkR6zU5GdiP9cBavimQopETyojInsRCe8uefjJBqn=s148-rwa" }, { "imageUrl": "https://lh3.googleusercontent.com/G2OgWJkuvSullUPp2i09zG_WR0IpQu-6Ti4pFXn_FJ1OkR6zU5GdiP9cBavimQopETyojInsRCe8uefjJBqn=s148-rwa" },
{ "imageUrl": "https://lh3.googleusercontent.com/-21C0x6zYcDxpJVYKl8CCKroyjW2Hdvh2FWBipCTFhonaPy2cSJZWTGvmjsoBJu-LedOHQrw1Qu7TYXxIlxv=s148-rwa" }, { "imageUrl": "https://lh3.googleusercontent.com/-21C0x6zYcDxpJVYKl8CCKroyjW2Hdvh2FWBipCTFhonaPy2cSJZWTGvmjsoBJu-LedOHQrw1Qu7TYXxIlxv=s148-rwa" },
@@ -200,6 +211,13 @@ function generateMockEvent() {
'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat', 'tiktok-chat',
'tiktok-follow', 'tiktok-sub', 'tiktok-gift', 'tiktok-follow', 'tiktok-sub', 'tiktok-gift',
'kick-chat', 'kick-chat', 'kick-chat', 'kick-chat', 'kick-chat',
'kick-chat', 'kick-chat', 'kick-chat', 'kick-chat', 'kick-chat',
'kick-follow', 'kick-sub',
'kick-giftsub', 'kick-giftbomb', 'kick-raid',
'streamlabs-tip', 'streamelements-tip', 'streamlabs-tip', 'streamelements-tip',
]; ];
@@ -219,6 +237,10 @@ function generateMockEvent() {
const badgeCount = Math.floor(Math.random() * 3) + 1; // 1 to 3 const badgeCount = Math.floor(Math.random() * 3) + 1; // 1 to 3
const badgeschosen = shuffledBadges.slice(0, badgeCount); const badgeschosen = shuffledBadges.slice(0, badgeCount);
const shuffledBadgesKick = [...mockData.badgeskick].sort(() => Math.random() - 0.5);
const badgeCountKick = Math.floor(Math.random() * 3) + 1; // 1 to 3
const badgesChosenKick = shuffledBadgesKick.slice(0, badgeCountKick);
const randomIndex = Math.floor(Math.random() * mockData.superstickers.length); const randomIndex = Math.floor(Math.random() * mockData.superstickers.length);
const randomStickerUrl = mockData.superstickers[randomIndex].imageUrl; const randomStickerUrl = mockData.superstickers[randomIndex].imageUrl;
@@ -577,6 +599,130 @@ function generateMockEvent() {
break; break;
case 'kick-chat' :
var data = {
id: messageId,
type: "message",
content: messagetext,
sender: {
id: user.name.toLowerCase(),
slug: user.name.toLowerCase(),
username: user.name,
identity: {
color: randomColor(),
badges: badgesChosenKick
}
}
};
const ifHasReplyOnKick = Math.random() < 0.05;
if (ifHasReplyOnKick) {
var replier = mockData.users[Math.floor(Math.random() * mockData.users.length)];
data.metadata = {
original_message: {
content: mockData.messages[Math.floor(Math.random() * mockData.messages.length)]
},
original_sender: {
username: replier.name
},
}
}
kickChatMessage(data);
break;
case 'kick-follow' :
var data = {
userName: user.name.toLowerCase(),
user: user.name,
};
kickFollowMessage(data);
break;
case 'kick-sub' :
var data = {
userName: user.name.toLowerCase(),
user: user.name,
cumulative: Math.floor(Math.random() * 50) + 1,
tier: 1
}
kickSubMessage(data);
break;
case 'kick-giftsub' :
var gifted = mockData.users[Math.floor(Math.random() * mockData.users.length)];
var data = {
user: user.name,
userName: user.name.toLowerCase(),
recipientUser: gifted.name,
tier: 1,
totalSubsGifted: Math.floor(Math.random() * 200) + 1
}
kickGiftMessage(data);
break;
case 'kick-giftbomb' :
var data = {
user: user.name,
userName: user.name.toLowerCase(),
tier: 1,
gifts: Math.floor(Math.random() * 200) + 1
}
kickGiftSubsMessage(data);
break;
case 'kick-raid' :
var data = {
user: user.name,
viewers: Math.floor(Math.random() * 200) + 1
}
kickRaidMessage(data);
break;
case 'streamlabs-tip' : case 'streamlabs-tip' :
var data = { var data = {
@@ -664,6 +810,10 @@ function updateMockStatistics() {
document.querySelector('#statistics #tiktok .viewers span').textContent = formatNumber(Math.floor(Math.random() * 800) + 200); document.querySelector('#statistics #tiktok .viewers span').textContent = formatNumber(Math.floor(Math.random() * 800) + 200);
document.querySelector('#statistics #tiktok .likes span').textContent = formatNumber(Math.floor(Math.random() * 5000) + 500); document.querySelector('#statistics #tiktok .likes span').textContent = formatNumber(Math.floor(Math.random() * 5000) + 500);
} }
if (showKickViewers) {
document.querySelector('#statistics #kick .viewers span').textContent = formatNumber(Math.floor(Math.random() * 800) + 200);
}
} }
} }

View File

@@ -27,7 +27,6 @@ const hideAfter = getURLParam("hideAfter", 0);
const ignoreChatters = getURLParam("ignoreChatters", ""); const ignoreChatters = getURLParam("ignoreChatters", "");
const excludeCommands = getURLParam("excludeCommands", true); const excludeCommands = getURLParam("excludeCommands", true);
const avatars = new Map();
const userColors = new Map(); const userColors = new Map();
const ignoreUserList = ignoreChatters.split(',').map(item => item.trim().toLowerCase()) || []; const ignoreUserList = ignoreChatters.split(',').map(item => item.trim().toLowerCase()) || [];
@@ -92,9 +91,9 @@ async function addMessageToChat(userID, messageID, platform, data) {
${showTimestamps == true ? '<span class="time">'+whatTimeIsIt()+'</span>' : ''} ${showTimestamps == true ? '<span class="time">'+whatTimeIsIt()+'</span>' : ''}
${showPlatform == true ? '<i class="platform fa-brands fa-'+platform+'"></i>' : '' } ${showPlatform == true ? '<span class="platform"><img src="images/logo-'+platform+'.svg" ></span>' : '' }
${showAvatar == true ? '<span class="avatar"><img src="'+data.avatar+'"></span>' : ''} ${showAvatar == true ? (data.avatar ? '<span class="avatar"><img src="'+data.avatar+'"></span>' : '') : ''}
${showBadges == true ? '<span class="badges">'+data.badges+'</span>' : ''} ${showBadges == true ? '<span class="badges">'+data.badges+'</span>' : ''}
@@ -134,7 +133,7 @@ async function addEventToChat(userID, messageID, platform, data) {
<div class="animate__animated ${chatHorizontal == true ? 'animate__fadeInRight' : 'animate__fadeInUp'} animate__faster"> <div class="animate__animated ${chatHorizontal == true ? 'animate__fadeInRight' : 'animate__fadeInUp'} animate__faster">
${!data.reply ? '' : data.reply} ${!data.reply ? '' : data.reply}
${showPlatform == true ? '<i class="platform '+(platform == 'money' ? 'fa-solid' : 'fa-brands')+' fa-'+platform+'"></i>' : '&nbsp;&nbsp;' } ${showPlatform == true ? '<span class="platform"><img src="images/logo-'+platform+'.svg" ></span>' : '' }
<span class="info"> <span class="info">
<!--<span class="avatar"><img src="${data.avatar}"></span>--> <!--<span class="avatar"><img src="${data.avatar}"></span>-->

563
js/kick/module.js Normal file
View File

@@ -0,0 +1,563 @@
const kickUserName = getURLParam("kickUserName", false);
const showKickMessages = getURLParam("showKickMessages", true);
const showKickFollows = getURLParam("showKickFollows", true);
const showKickSubs = getURLParam("showKickSubs", true);
const showKickGiftedSubs = getURLParam("showKickGiftedSubs", true);
const showKickMassGiftedSubs = getURLParam("showKickMassGiftedSubs", true);
const showKickRaids = getURLParam("showKickRaids", true);
const showKickViewers = getURLParam("showKickViewers", true);
const kickAvatars = new Map();
const kick7TVEmojis = new Map();
if (showKickViewers == false) { document.querySelector('#statistics #kick').style.display = 'none'; }
const kickWebSocket = new WebSocket(
`wss://ws-us2.pusher.com/app/32cbd69e4b950bf97679?protocol=7&client=js&version=8.4.0-rc2&flash=false`
);
kickWebSocket.onerror = (error) => {
console.error("Kick WebSocket Error: " + error);
};
kickWebSocket.onopen = () => {
kickGetUserInfo(kickUserName)
.then((userInfo) => {
console.log('Got Kick User Info', userInfo);
(async () => {
const kick7TVEmotes = await get7TVEmotes(userInfo.user_id);
if (kick7TVEmotes != null) {
console.debug("Getting all Kick's 7TV Emojis + Globals", kick7TVEmotes);
kick7TVEmotes.forEach(emote => {
kick7TVEmojis.set(emote.name, emote.url);
});
}
})();
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `chatrooms.${userInfo.chatroom.id}.v2`
},
})
);
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `channel.${userInfo.chatroom.channel_id}`
},
})
);
setInterval(() => {
kickWebSocket.send(
JSON.stringify({
event: "pusher:ping",
data: {},
})
);
}, 60000);
kickUpdateStatistics(userInfo);
setInterval(() => {
kickGetUserInfo(kickUserName)
.then((data) =>{
kickUpdateStatistics(data);
});
}, 15000);
});
};
kickWebSocket.onmessage = async ({ data }) => {
const parsed = JSON.parse(data);
const json = JSON.parse(parsed.data);
if (!parsed.event.includes("pusher")) {
switch (parsed.event) {
case "App\\Events\\ChatMessageEvent":
console.debug('Kick Chat', json);
kickChatMessage(json);
break;
case "App\\Events\\MessageDeletedEvent":
kickChatMessageDeleted(json);
break;
case "App\\Events\\UserBannedEvent":
kickUserBanned(json);
break;
case "App\\Events\\ChatroomClearEvent":
kickChatClearMessages()
break;
default:
console.debug('Kick Event From WebSocket', parsed.event, json);
}
}
};
streamerBotClient.on('General.Custom', (response) => {
if (response.data.platform === 'Kick') {
const data = response.data.data;
switch (data.triggerCustomCodeEventName) {
case "kickFollow" :
console.debug('Kick Follow', data);
kickFollowMessage(data);
break;
case "kickSub" :
console.debug('Kick Sub', data);
kickSubMessage(data);
break;
case "kickGift" :
console.debug('Kick Sub Gift', data);
kickGiftMessage(data);
break;
case "kickGifts" :
console.debug('Kick Mass Sub Gift', data);
kickGiftSubsMessage(data);
break;
case "kickIncomingRaid" :
console.debug('Kick Raid', data);
kickRaidMessage(data);
break;
default:
//console.debug('Kick Event', response.data);
}
}
});
async function kickChatMessage(data) {
if (showKickMessages == false) return;
if (ignoreUserList.includes(data.sender.username.toLowerCase())) return;
if (data.content.startsWith("!") && excludeCommands == true) return;
const {
id: messageId,
type,
content: text,
sender: {
id: userID,
slug: userSlug,
username: userName,
identity: {
color,
badges: badgesToParse
}
}
} = data;
const [avatar, message, badges] = await Promise.all([
getKickAvatar(userSlug),
getKickEmotes(text),
getKickBadges(badgesToParse),
]);
const replyHTML = (type == "reply" ?
`<div class="reply"><i class="fa-solid fa-arrow-turn-up"></i> <strong>${data.metadata.original_sender.username}:</strong> ${await getKickEmotes(data.metadata.original_message.content)}</div>` : '');
const messageData = {
classes: '',
avatar,
badges,
userName,
color,
message,
shared: '',
reply: replyHTML,
};
addMessageToChat(userSlug, messageId, 'kick', messageData);
}
async function kickFollowMessage(data) {
if (showKickFollows == false) return;
const {
userName : userID,
user : userName
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.follow(),
]);
const classes = 'follow';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickSubMessage(data) {
if (showKickSubs == false) return;
const {
userName: userID,
user: userName,
tier,
cumulative
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.sub({
months : cumulative,
tier : tier
})
]);
const classes = 'sub';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickGiftMessage(data) {
if (showKickSubs == false || showKickGiftedSubs == false) return;
const {
user: userName,
userName: userID,
recipientUser: recipientName,
tier,
totalSubsGifted
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.gifted({
gifted : recipientName,
tier : tier,
total : totalSubsGifted
})
]);
const classes = 'sub';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickGiftSubsMessage(data) {
if (showKickSubs == false || showKickMassGiftedSubs == false) return;
const {
user: userName,
userName: userID,
tier,
gifts
} = data;
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.giftedbomb({
count : gifts,
tier : tier
})
]);
const classes = 'sub';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickRaidMessage(data) {
if (showKickRaids == false) return;
const {
user: userName,
viewers
} = data;
const userID = userName.toLowerCase();
const messageID = createRandomString(40);
const [avatar, message] = await Promise.all([
'',
currentLang.kick.raid({ viewers : viewers })
]);
const classes = 'raid';
const messageData = {
classes: classes,
avatar,
badges: '',
userName,
color: '#FFF',
message,
reply: '',
};
addEventToChat(userID, messageID, 'kick', messageData);
}
async function kickChatMessageDeleted(data) {
document.getElementById(data.message.id)?.remove();
}
async function kickUserBanned(data) {
chatContainer.querySelectorAll(`[data-user="${data.user.slug}"]`).forEach(element => {
element.remove();
});
}
async function kickChatClearMessages() {
chatContainer.querySelectorAll(`.kick`).forEach(element => {
element.remove();
});
}
async function kickUpdateStatistics(data) {
if (showPlatformStatistics == false || showKickViewers == false) return;
if (data.livestream == null) { }
else {
const viewers = DOMPurify.sanitize(data.livestream.viewer_count);
document.querySelector('#statistics #kick .viewers span').textContent = formatNumber(viewers);
}
}
async function kickGetUserInfo(user) {
const response = await fetch( `https://kick.com/api/v2/channels/${user}` );
if (response.status === 404) {
console.error("Kick user was not found!");
return 404;
}
else {
const data = await response.json();
return data;
}
}
async function getKickAvatar(user) {
if (showAvatar == true) {
if (kickAvatars.has(user)) {
console.debug(`Kick avatar found for ${user}!`);
return kickAvatars.get(user);
}
else {
console.debug(`Kick avatar not found for ${user}! Trying to get it...`);
const response = await kickGetUserInfo(user);
var newavatar = '';
if (response == 404) {
newavatar = 'https://kick.com/img/default-profile-pictures/default2.jpeg';
}
else {
if (response.user.profile_pic == null) {
newavatar = 'https://kick.com/img/default-profile-pictures/default2.jpeg';
}
else {
newavatar = response.user.profile_pic;
newavatar = newavatar.replace(/fullsize(?=\.webp)/, "medium");
}
kickAvatars.set(user, newavatar);
}
return newavatar;
}
}
}
async function getKickEmotes(text) {
var message = await parseKickEmojis(text);
message = await parseKick7TVEmotes(message);
return message;
}
async function parseKickEmojis(content) {
const message = content;
const messagewithemotes = message.replace(/\[emote:(\d+):([^\]]+)\]/g, (_, id, name) => {
return `<img src="https://files.kick.com/emotes/${id}/fullsize" alt="${name}" class="emote" >`;
});
return messagewithemotes;
}
async function parseKick7TVEmotes(text) {
const words = text.split(/\s+/);
const parsedWords = words.map(word => {
const clean = word.replace(/[^\w]/g, ''); // remove pontuação para comparar
if (kick7TVEmojis.has(clean)) {
const url = kick7TVEmojis.get(clean);
return word.replace(clean, `<img src="${url}" alt="${clean}" class="emote" />`);
}
return word;
});
return parsedWords.join(' ');
}
async function get7TVEmotes(userid) {
const userSet = await fetch(`https://7tv.io/v3/users/kick/${userid}`);
if (userSet.status === 404) {
console.debug("7TV Profile based on this Kick user was not found");
return null;
}
const userEmojis = await userSet.json();
const gettingAllKick7TVEmotes = userEmojis?.emote_set?.emotes?.map(emote => ({
name: emote.name,
id: emote.id,
url: `https://cdn.7tv.app/emote/${emote.id}/1x.webp`
})) || [];
const globalSet = await fetch(`https://7tv.io/v3/emote-sets/global`);
const globalEmojis = await globalSet.json();
const gettingAllGlobal7TVEmotes = globalEmojis?.emotes?.map(emote => ({
name: emote.name,
id: emote.id,
url: `https://cdn.7tv.app/emote/${emote.id}/1x.webp`
})) || [];
const SevenTVEmotesFusion = [...gettingAllKick7TVEmotes, ...gettingAllGlobal7TVEmotes];
return SevenTVEmotesFusion;
}
async function getKickBadges(badges) {
const badgesArray = [];
badges.forEach(badge => {
switch (badge.type) {
case "broadcaster":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32" class="size-[calc(1em*(18/13))]"><defs><linearGradient id="HostBadgeA" x1="16" x2="16" y1="-197.5" y2="118.7" gradientUnits="userSpaceOnUse"><stop stop-color="#FF1CD2"></stop><stop offset="1" stop-color="#B20DFF"></stop></linearGradient><linearGradient id="HostBadgeB" x1="16" x2="16" y1="0" y2="0" gradientUnits="userSpaceOnUse"><stop stop-color="#FF1CD2"></stop><stop offset="1" stop-color="#B20DFF"></stop></linearGradient><linearGradient id="HostBadgeC" x1="16" x2="16" y1="-64" y2="-64" gradientUnits="userSpaceOnUse"><stop stop-color="#FF1CD2"></stop><stop offset="1" stop-color="#B20DFF"></stop></linearGradient><linearGradient id="HostBadgeD" x1="16" x2="16" y1="-197.5" y2="118.7" gradientUnits="userSpaceOnUse"><stop stop-color="#FF1CD2"></stop><stop offset="1" stop-color="#B20DFF"></stop></linearGradient><linearGradient id="HostBadgeE" x1="16" x2="16" y1="-74.7" y2="-74.7" gradientUnits="userSpaceOnUse"><stop stop-color="#FF1CD2"></stop><stop offset="1" stop-color="#B20DFF"></stop></linearGradient><linearGradient id="HostBadgeF" x1="27.2" x2="27.2" y1="-.5" y2="31.1" gradientUnits="userSpaceOnUse"><stop stop-color="#FF1CD2"></stop><stop offset="1" stop-color="#B20DFF"></stop></linearGradient></defs><path fill="url(#HostBadgeA)" d="M9.6 19.2H6.4v3.2h3.2v-3.2Z"></path><path fill="url(#HostBadgeB)" d="M12.8 19.2h6.4V16h3.2V3.2h-3.2V0h-6.4v3.2H9.6V16h3.2v3.2Z"></path><path fill="url(#HostBadgeC)" d="M6.4 12.8H3.2v6.4h3.2v-6.4Z"></path><path fill="url(#HostBadgeD)" d="M25.6 19.2h-3.2v3.2h3.2v-3.2Z"></path><path fill="url(#HostBadgeE)" d="M9.6 22.4v3.2h3.2v3.2H9.6V32h12.8v-3.2h-3.2v-3.2h3.2v-3.2H9.6Z"></path><path fill="url(#HostBadgeF)" d="M25.6 12.8v6.4h3.2v-6.4h-3.2Z"></path></svg>');
break;
case "sidekick":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32" class="size-[calc(1em*(18/13))]"><path fill="url(#SidekickBadgeA)" d="M0 5.5v11.3h2.3V20h2.3v3.2h2.2v3.2h6.9v-3.2h4.6v3.2H25v-3.2h2.3V20h2.3v-3.2H32V5.5h-9.2v3.2h-4.6V12h-4.5V8.7H9V5.5H0Zm13.7 13.7H7V16H4.6V9.6h2.3v3.2h4.5V16h2.3v3.2ZM27.4 16h-2.2v3.2h-6.9V16h2.3v-3.2h4.6V9.6h2.2V16Z"></path><defs><linearGradient id="SidekickBadgeA" x1="18.8" x2="11.7" y1="-2.7" y2="32.7" gradientUnits="userSpaceOnUse"><stop stop-color="#FF6A4A"></stop><stop offset="1" stop-color="#C70C00"></stop></linearGradient></defs></svg>');
break;
case "moderator":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32" class="size-[calc(1em*(18/13))]"><path fill="#00C7FF" d="M23.5 2.5v3h-3v3h-3v3h-3v3h-3v-3h-6v6h3v3h-3v3h-3v6h6v-3h3v-3h3v3h6v-6h-3v-3h3v-3h3v-3h3v-3h3v-6h-6Z"></path></svg>');
break;
case "vip":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32" class="size-[calc(1em*(18/13))]"><path fill="url(#VIPBadgeA)" d="M27.8 4.8V7h-2.5v4.5h-2.1v2.3h-2.3V9.3h-2.4V2.6h-5v6.7H11v4.5H8.8v-2.3H6.7V7H4.2V4.8H0v24.6h32V4.8h-4.2Z"></path><defs><linearGradient id="VIPBadgeA" x1="16" x2="16" y1="-1" y2="35.1" gradientUnits="userSpaceOnUse"><stop stop-color="#FFC900"></stop><stop offset="1" stop-color="#FF9500"></stop></linearGradient></defs></svg>');
break;
case "sub_gifter":
badgesArray.push('<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" class="size-[calc(1em*(18/13))]"><g clip-path="url(#clip0_31_3197)"><path d="M22.34 9.5L26 4H18L16 7L14 4H6L9.66 9.5H4V15.1H28V9.5H22.34Z" fill="#2EFAD1"></path><path d="M26.08 19.1001H5.90002V28.5001H26.08V19.1001Z" fill="#2EFAD1"></path><path d="M26.08 15.1001H5.90002V19.1001H26.08V15.1001Z" fill="#00A18D"></path></g><defs><clipPath id="clip0_31_3197"><rect width="24" height="24.5" fill="white" transform="translate(4 4)"></rect></clipPath></defs></svg>');
break;
case "og":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32" class="size-[calc(1em*(18/13))]"><g clip-path="url(#OGBadgeA)"><path fill="url(#OGBadgeB)" d="M32 32H18.3v-1.6h-1.5v-16h1.5v-1.6H32v6.4h-9v9.6h3v-3.2h-1.6v-3.2H32V32Z"></path><path fill="url(#OGBadgeC)" d="M13.6 17.6v1.6h-12v-1.6H0v-16h1.5V0h12.2v1.6h1.5v16h-1.6Zm-4.5-4.8V3.2H6v9.6h3Z"></path><path fill="#00FFF2" d="M13.6 30.4V32h-12v-1.6H0V17.6h1.5V16h12.2v1.6h1.5v12.8h-1.6Zm-4.5-1.6v-9.6H6v9.6h3ZM32 16H18.3v-1.6h-1.5V1.6h1.5V0H32v3.2h-9v9.6h3V9.6h-1.6V6.4H32V16Z"></path></g><defs><linearGradient id="OGBadgeB" x1="16" x2="16" y1="32" y2="2.5" gradientUnits="userSpaceOnUse"><stop stop-color="#00FFF2"></stop><stop offset="1" stop-color="#006399"></stop></linearGradient><linearGradient id="OGBadgeC" x1="15.5" x2="16.1" y1=".4" y2="31.7" gradientUnits="userSpaceOnUse"><stop stop-color="#00FFF2"></stop><stop offset="1" stop-color="#006399"></stop></linearGradient><clipPath id="OGBadgeA"><path fill="#fff" d="M0 0h32v32H0z"></path></clipPath></defs></svg>');
break;
case "founder":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 32 32" class="size-[calc(1em*(18/13))]"><g clip-path="url(#FounderBadgeA)"><path fill="url(#FounderBadgeB)" fill-rule="evenodd" d="M29.3 8V5.4h-2.7V2.7H24V0H8v2.7H5.4v2.7H2.6V8H0v16h2.6v2.6h2.8v2.7H8V32h16v-2.7h2.6v-2.7h2.7V24H32V8h-2.7Zm-9.5 17.7h-6.5V12.8H9v-2.4h2V8.2h2v-2h7v19.5Z" clip-rule="evenodd"></path></g><defs><linearGradient id="FounderBadgeB" x1="15.7" x2="16.3" y1="-4.5" y2="36.7" gradientUnits="userSpaceOnUse"><stop stop-color="#FFC900"></stop><stop offset="1" stop-color="#FF9500"></stop></linearGradient><clipPath id="FounderBadgeA"><path fill="#fff" d="M0 0h32v32H0z"></path></clipPath></defs></svg>');
break;
case "subscriber":
badgesArray.push('<i class="fa-solid fa-star sub"></i>');
break;
case "verified":
badgesArray.push('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" class="size-[calc(1em*(18/13))]"><path fill="#1EFF00" d="M16 6.83512L13.735 4.93512L13.22 2.02512H10.265L8 0.120117L5.735 2.02012H2.78L2.265 4.93012L0 6.83512L1.48 9.39512L0.965 12.3051L3.745 13.3151L5.225 15.8751L8.005 14.8651L10.785 15.8751L12.265 13.3151L15.045 12.3051L14.53 9.39512L16.01 6.83512H16ZM6.495 12.4051L2.79 8.69512L4.205 7.28012L6.495 9.57512L11.29 4.78012L12.705 6.19512L6.5 12.4001L6.495 12.4051Z"></path></svg>');
break;
}
});
return badgesArray.join(' ');
}

63
js/kick/old.module.js Normal file
View File

@@ -0,0 +1,63 @@
/*
const kickWebSocket = new WebSocket(
`wss://ws-us2.pusher.com/app/32cbd69e4b950bf97679?protocol=7&client=js&version=8.4.0-rc2&flash=false`
);
kickWebSocket.onerror = (error) => {
console.error("Kick WebSocket Error: " + error);
};
kickWebSocket.onopen = () => {
kickGetUserInfo(kickUser)
.then((userInfo) => {
console.log('Got Kick User Info', userInfo);
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `chatrooms.${userInfo.chatroom.id}.v2`
},
})
);
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `channel.${userInfo.chatroom.channel_id}`
},
})
);
kickWebSocket.send(
JSON.stringify({
event: "pusher:subscribe",
data: {
auth: null,
channel: `private-channel_${userInfo.chatroom.channel_id}`
},
})
);
});
};
kickWebSocket.onmessage = async ({ data }) => {
const parsed = JSON.parse(data);
const json = JSON.parse(parsed.data);
console.debug('Kick Event', parsed.event, json);
if (parsed.event === "App\\Events\\ChatMessageEvent") {
console.debug('Kick Chat', json);
kickChatMessage(json);
}
};
*/

View File

@@ -75,5 +75,23 @@ const en = {
sub : ({ months }) => ` subscribed for <i class="fa-solid fa-star"></i> <strong>${months || 1 } ${(months && months > 1) ? 'months' : 'month'}</strong>`, sub : ({ months }) => ` subscribed for <i class="fa-solid fa-star"></i> <strong>${months || 1 } ${(months && months > 1) ? 'months' : 'month'}</strong>`,
gift : ({ gift, count, coins }) => ` gifted <strong>${gift} x${count}</strong> (🪙 <strong>${coins} ${(coins && coins > 1) ? 'coins' : 'coin'})</strong>`, gift : ({ gift, count, coins }) => ` gifted <strong>${gift} x${count}</strong> (🪙 <strong>${coins} ${(coins && coins > 1) ? 'coins' : 'coin'})</strong>`,
} },
kick : {
follow : () => ` followed the channel`,
sub : ({ months, tier }) => ` subscribed for
<strong>${months || 1 } ${months == 1 ? 'month' : 'months'}
(Tier ${tier})</strong>`,
gifted : ({ gifted, tier, total }) => ` gifted
<strong>${total || 1 } ${total == 1 ? 'sub' : 'subs'}
(Tier ${tier})</strong>
to <i class="fa-solid fa-gift"></i> <strong>${gifted}</strong>`,
giftedbomb : ({ count, tier }) => ` gifted <i class="fa-solid fa-gift"></i> <strong>${count} subs (Tier ${tier})</strong> to the Community`,
raid : ({ viewers }) => ` raided the channel with <i class="fa-solid fa-users"></i> <strong>${viewers} viewers</strong>`
},
} }

View File

@@ -68,5 +68,23 @@ const es = {
likes : (likes) => `envió <strong><i class="fa-solid fa-heart"></i> <em class="likecount" style="font-style: normal;">${likes}</em> likes</strong>`, likes : (likes) => `envió <strong><i class="fa-solid fa-heart"></i> <em class="likecount" style="font-style: normal;">${likes}</em> likes</strong>`,
sub : ({ months }) => ` se suscribió por <i class="fa-solid fa-star"></i> <strong>${months || 1 } ${(months && months > 1) ? 'meses' : 'mes'}</strong>`, sub : ({ months }) => ` se suscribió por <i class="fa-solid fa-star"></i> <strong>${months || 1 } ${(months && months > 1) ? 'meses' : 'mes'}</strong>`,
gift : ({ gift, count, coins }) => ` regaló <strong>${gift} x${count}</strong> (🪙 <strong>${coins} ${(coins && coins > 1) ? 'monedas' : 'moneda'})</strong>`, gift : ({ gift, count, coins }) => ` regaló <strong>${gift} x${count}</strong> (🪙 <strong>${coins} ${(coins && coins > 1) ? 'monedas' : 'moneda'})</strong>`,
} },
kick : {
follow : () => ` siguió el canal`,
sub : ({ months, tier }) => ` se suscribió por
<strong>${months || 1 } ${months == 1 ? 'mes' : 'meses'}
(Tier ${tier})</strong>`,
gifted : ({ gifted, tier, total }) => ` regaló
<strong>${total || 1 } ${total == 1 ? 'suscripción' : 'suscripciones'}
(Tier ${tier})</strong>
a <i class="fa-solid fa-gift"></i> <strong>${gifted}</strong>`,
giftedbomb : ({ count, tier }) => ` regaló <i class="fa-solid fa-gift"></i> <strong>${count} suscripciones (Tier ${tier})</strong> a la comunidad`,
raid : ({ viewers }) => ` hizo una raid al canal con <i class="fa-solid fa-users"></i> <strong>${viewers} espectadores</strong>`
},
} }

View File

@@ -75,5 +75,23 @@ const ptbr = {
sub : ({ months }) => ` se inscreveu por <i class="fa-solid fa-star"></i> <strong>${months || 1 } ${(months && months > 1) ? 'meses' : 'mês'}</strong>`, sub : ({ months }) => ` se inscreveu por <i class="fa-solid fa-star"></i> <strong>${months || 1 } ${(months && months > 1) ? 'meses' : 'mês'}</strong>`,
gift : ({ gift, count, coins }) => ` doou <strong>${gift} x${count}</strong> (🪙 <strong>${coins} ${(coins && coins > 1) ? 'moedas' : 'moeda'})</strong>`, gift : ({ gift, count, coins }) => ` doou <strong>${gift} x${count}</strong> (🪙 <strong>${coins} ${(coins && coins > 1) ? 'moedas' : 'moeda'})</strong>`,
} },
kick : {
follow : () => ` seguiu o canal`,
sub : ({ months, tier }) => ` se inscreveu por
<strong>${months || 1 } ${months == 1 ? 'mês' : 'meses'}
(Tier ${tier})</strong>`,
gifted : ({ gifted, tier, total }) => ` doou
<strong>${total || 1 } ${total == 1 ? 'inscrição' : 'inscrições'}
(Tier ${tier})</strong>
para <i class="fa-solid fa-gift"></i> <strong>${gifted}</strong>`,
giftedbomb : ({ count, tier }) => ` doou <i class="fa-solid fa-gift"></i> <strong>${count} inscrições (Tier ${tier})</strong> para a Comunidade`,
raid : ({ viewers }) => ` raidou o canal com <i class="fa-solid fa-users"></i> <strong>${viewers} pessoas</strong>`
},
} }

View File

@@ -342,3 +342,32 @@ window.addEventListener('load', () => {
pushChangeEvents(); pushChangeEvents();
populateEmoteList(); populateEmoteList();
}); });
document.querySelectorAll('.nav-bar a').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
// Remove todas as classes dos links dentro da nav-bar
document.querySelectorAll('.nav-bar a').forEach(link => {
link.classList.remove('active');
});
this.classList.add('active');
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
if (targetElement) {
const offset = 20; // ajusta 20px acima
const y = targetElement.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({
top: y,
behavior: 'smooth'
});
}
});
});

View File

@@ -42,5 +42,5 @@ async function streamElementsEventMessage(data) {
message, message,
reply: '', reply: '',
}; };
addEventToChat(userID, messageID, 'dollar-sign', messageData); addEventToChat(userID, messageID, 'streamelements', messageData);
} }

View File

@@ -40,5 +40,5 @@ async function streamLabsEventMessage(data) {
message, message,
reply: '', reply: '',
}; };
addEventToChat(userID, messageID, 'dollar-sign', messageData); addEventToChat(userID, messageID, 'streamlabs', messageData);
} }

View File

@@ -11,6 +11,8 @@ const showTwitchRaids = getURLParam("showTwitchRaids", true);
const showTwitchSharedChat = getURLParam("showTwitchSharedChat", true); const showTwitchSharedChat = getURLParam("showTwitchSharedChat", true);
const showTwitchViewers = getURLParam("showTwitchViewers", true); const showTwitchViewers = getURLParam("showTwitchViewers", true);
const avatars = new Map();
if (showTwitchViewers == false) { document.querySelector('#statistics #twitch').style.display = 'none'; } if (showTwitchViewers == false) { document.querySelector('#statistics #twitch').style.display = 'none'; }
const twitchMessageHandlers = { const twitchMessageHandlers = {
@@ -510,7 +512,9 @@ async function twitchUserBanned(data) {
async function twitchChatClearMessages() { async function twitchChatClearMessages() {
chatContainer.innerHTML = ''; chatContainer.querySelectorAll(`.twitch`).forEach(element => {
element.remove();
});
} }
@@ -567,11 +571,11 @@ async function getTwitchBadges(data) {
async function getTwitchAvatar(user) { async function getTwitchAvatar(user) {
if (showAvatar == true) { if (showAvatar == true) {
if (avatars.has(user)) { if (avatars.has(user)) {
console.debug(`Avatar found for ${user}!`); console.debug(`Twitch avatar found for ${user}!`);
return avatars.get(user); return avatars.get(user);
} }
else { else {
console.debug(`Avatar not found for ${user}! Getting it from DECAPI!`); console.debug(`Twitch avatar not found for ${user}! Getting it from DECAPI!`);
var decapi = await fetch('https://decapi.me/twitch/avatar/' + user); var decapi = await fetch('https://decapi.me/twitch/avatar/' + user);
var newavatar = await decapi.text() var newavatar = await decapi.text()
avatars.set(user, newavatar); avatars.set(user, newavatar);

View File

@@ -1 +1 @@
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