Add files via upload
- Added the ability to add a scroll bar. - Fixed a bug on rendering emotes on resub messages - Fixed a bug on how likes would not display correctly - Fixed inner margin between messages and events
This commit is contained in:
@@ -45,12 +45,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div id="chat">
|
<div id="chat">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<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>
|
||||||
|
44
css/app.css
44
css/app.css
@@ -20,22 +20,44 @@ html {
|
|||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
position: absolute;
|
#container {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.wrapper {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#chat {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse; /* conteúdo começa no fundo */
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 10px;
|
||||||
|
scrollbar-color: #555 #1e1e1e;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chat {
|
#chat.noscrollbar {
|
||||||
position: absolute;
|
overflow-y: hidden;
|
||||||
width: 100%;
|
|
||||||
bottom: 0px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chat::-webkit-scrollbar { width: 8px; }
|
||||||
|
#chat::-webkit-scrollbar-track { background: #1e1e1e; }
|
||||||
|
#chat::-webkit-scrollbar-thumb { background-color: #555; border-radius: 4px; border: 2px solid #1e1e1e; }
|
||||||
|
#chat::-webkit-scrollbar-thumb:hover { background-color: #777; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#chat .message {
|
#chat .message {
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@@ -134,7 +156,7 @@ body {
|
|||||||
display: block;
|
display: block;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 2px 0 -5px 0;
|
margin: 10px 0 -5px 0;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +185,9 @@ body {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chat .message:not(.event) > div {
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#chat .message.twitch .shared span {
|
#chat .message.twitch .shared span {
|
||||||
|
@@ -63,6 +63,8 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="setting"><label>Scroll Bar<br><small>Adds a scrollbar. Perfect if you using ChatRD as a chat reader instead of an overlay.</small></label></label><label class="switch"><input type="checkbox" name="chatScrollBar"><span class="slider"></span></label></div>
|
||||||
|
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<label>Background Color<br><small>Changes ChatRD's background color</small></label>
|
<label>Background Color<br><small>Changes ChatRD's background color</small></label>
|
||||||
<label>
|
<label>
|
||||||
|
@@ -200,6 +200,7 @@ function generateMockEvent() {
|
|||||||
'twitch-chat', 'twitch-chat', 'twitch-chat', 'twitch-chat', 'twitch-chat',
|
'twitch-chat', 'twitch-chat', 'twitch-chat', 'twitch-chat', 'twitch-chat',
|
||||||
|
|
||||||
'twitch-follow', 'twitch-bits', 'twitch-sub', 'twitch-resub',
|
'twitch-follow', 'twitch-bits', 'twitch-sub', 'twitch-resub',
|
||||||
|
|
||||||
'twitch-giftsub', 'twitch-giftbomb', 'twitch-raid',
|
'twitch-giftsub', 'twitch-giftbomb', 'twitch-raid',
|
||||||
'twitch-announcement', 'twitch-reward', 'twitch-gigantifyemote',
|
'twitch-announcement', 'twitch-reward', 'twitch-gigantifyemote',
|
||||||
|
|
||||||
|
19
js/app.js
19
js/app.js
@@ -15,6 +15,7 @@ const chatContainer = document.querySelector('#chat');
|
|||||||
const chatFontSize = getURLParam("chatFontSize", 1);
|
const chatFontSize = getURLParam("chatFontSize", 1);
|
||||||
const chatBackground = getURLParam("chatBackground", "#121212");
|
const chatBackground = getURLParam("chatBackground", "#121212");
|
||||||
const chatBackgroundOpacity = getURLParam("chatBackgroundOpacity", 1);
|
const chatBackgroundOpacity = getURLParam("chatBackgroundOpacity", 1);
|
||||||
|
const chatScrollBar = getURLParam("chatScrollBar", false);
|
||||||
|
|
||||||
const currentLang = lang[getURLParam("language", 'ptbr')];
|
const currentLang = lang[getURLParam("language", 'ptbr')];
|
||||||
const eventsMockup = getURLParam("eventsMockup", true);
|
const eventsMockup = getURLParam("eventsMockup", true);
|
||||||
@@ -34,6 +35,7 @@ const userColors = new Map();
|
|||||||
const ignoreUserList = ignoreChatters.split(',').map(item => item.trim().toLowerCase()) || [];
|
const ignoreUserList = ignoreChatters.split(',').map(item => item.trim().toLowerCase()) || [];
|
||||||
|
|
||||||
chatContainer.style.zoom = chatFontSize;
|
chatContainer.style.zoom = chatFontSize;
|
||||||
|
if (chatScrollBar == false) { chatContainer.classList.add('noscrollbar'); }
|
||||||
|
|
||||||
/* ----------------------- */
|
/* ----------------------- */
|
||||||
/* START */
|
/* START */
|
||||||
@@ -110,7 +112,7 @@ async function addMessageToChat(userID, messageID, platform, data) {
|
|||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
chatContainer.insertAdjacentHTML('beforeend', html);
|
chatContainer.insertAdjacentHTML('afterbegin', html);
|
||||||
|
|
||||||
const messageElement = document.getElementById(messageID);
|
const messageElement = document.getElementById(messageID);
|
||||||
|
|
||||||
@@ -148,7 +150,7 @@ async function addEventToChat(userID, messageID, platform, data) {
|
|||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
chatContainer.insertAdjacentHTML('beforeend', html);
|
chatContainer.insertAdjacentHTML('afterbegin', html);
|
||||||
|
|
||||||
const messageElement = document.getElementById(messageID);
|
const messageElement = document.getElementById(messageID);
|
||||||
|
|
||||||
@@ -178,15 +180,20 @@ const whatTimeIsIt = () => {
|
|||||||
|
|
||||||
|
|
||||||
function removeExtraChatMessages() {
|
function removeExtraChatMessages() {
|
||||||
const chatMessages = chatContainer.querySelectorAll('div.message').length;
|
const chatMessages = chatContainer.querySelectorAll('div.message');
|
||||||
if (chatMessages >= chatThreshhold) {
|
const total = chatMessages.length;
|
||||||
for (let i = 0; i < Math.floor(chatThreshhold/2); i++) {
|
|
||||||
chatContainer.removeChild(chatContainer.firstElementChild);
|
if (total >= chatThreshhold) {
|
||||||
|
const toRemove = Math.floor(total * 0.25); // 25% do total
|
||||||
|
for (let i = 0; i < toRemove; i++) {
|
||||||
|
const last = chatContainer.lastElementChild;
|
||||||
|
if (last) chatContainer.removeChild(last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function to format large numbers (e.g., 1000 => '1K')
|
// Function to format large numbers (e.g., 1000 => '1K')
|
||||||
function formatNumber(num) {
|
function formatNumber(num) {
|
||||||
if (num >= 1000000) {
|
if (num >= 1000000) {
|
||||||
|
@@ -148,7 +148,6 @@ async function tiktokLikesMessage(data) {
|
|||||||
|
|
||||||
if (showTikTokLikes == false) return;
|
if (showTikTokLikes == false) return;
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
userId: userID,
|
userId: userID,
|
||||||
msgId: messageID,
|
msgId: messageID,
|
||||||
|
@@ -263,7 +263,7 @@ async function twitchAnnouncementMessage(data) {
|
|||||||
|
|
||||||
|
|
||||||
data.message = {
|
data.message = {
|
||||||
message: await getTwitchAnnouncementEmotes(data)
|
message: await getTwitchEmotesOnParts(data)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -366,6 +366,7 @@ async function twitchReSubMessage(data) {
|
|||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
const messageID = createRandomString(40);
|
const messageID = createRandomString(40);
|
||||||
|
const messagetext = await getTwitchEmotesOnParts(data);
|
||||||
|
|
||||||
const [avatar, message] = await Promise.all([
|
const [avatar, message] = await Promise.all([
|
||||||
'',
|
'',
|
||||||
@@ -373,7 +374,7 @@ async function twitchReSubMessage(data) {
|
|||||||
months : data.cumulativeMonths,
|
months : data.cumulativeMonths,
|
||||||
isPrime : data.isPrime,
|
isPrime : data.isPrime,
|
||||||
tier : data.subTier,
|
tier : data.subTier,
|
||||||
message : text
|
message : messagetext
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -452,7 +453,11 @@ async function twitchGiftSubsMessage(data) {
|
|||||||
|
|
||||||
const [avatar, message] = await Promise.all([
|
const [avatar, message] = await Promise.all([
|
||||||
'',
|
'',
|
||||||
currentLang.twitch.giftedbomb({ count : data.total, tier : data.sub_tier, total : data.cumulative_total })
|
currentLang.twitch.giftedbomb({
|
||||||
|
count : data.total,
|
||||||
|
tier : data.sub_tier,
|
||||||
|
total : data.cumulative_total
|
||||||
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const classes = 'sub';
|
const classes = 'sub';
|
||||||
@@ -542,7 +547,7 @@ async function getTwitchEmotes(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function getTwitchAnnouncementEmotes(data) {
|
/*async function getTwitchAnnouncementEmotes(data) {
|
||||||
const message = data.text;
|
const message = data.text;
|
||||||
const emotes = data.parts;
|
const emotes = data.parts;
|
||||||
const words = message.split(" ");
|
const words = message.split(" ");
|
||||||
@@ -555,8 +560,23 @@ async function getTwitchAnnouncementEmotes(data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return words.join(" ");
|
return words.join(" ");
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
async function getTwitchEmotesOnParts(data) {
|
||||||
|
const parts = data?.parts;
|
||||||
|
|
||||||
|
if (!Array.isArray(parts)) {
|
||||||
|
return data.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.map(part => {
|
||||||
|
if (part.type === 'text') {
|
||||||
|
return part.text;
|
||||||
|
} else if (part.type === 'emote') {
|
||||||
|
return `<img src="${part.imageUrl}" alt="${part.text}" class="emote">`;
|
||||||
|
}
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
async function getTwitchBadges(data) {
|
async function getTwitchBadges(data) {
|
||||||
const badges = data.message.badges;
|
const badges = data.message.badges;
|
||||||
|
@@ -140,12 +140,13 @@ async function youTubeSuperChatMessage(data) {
|
|||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
var money = amount;
|
var money = amount;
|
||||||
|
var messagewithemotes = await getYouTubeEmotes(textmessage);
|
||||||
|
|
||||||
const [avatar, message] = await Promise.all([
|
const [avatar, message] = await Promise.all([
|
||||||
``,
|
``,
|
||||||
currentLang.youtube.superchat({
|
currentLang.youtube.superchat({
|
||||||
money : money,
|
money : money,
|
||||||
message : textmessage
|
message : messagewithemotes
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -223,12 +224,14 @@ async function youTubeNewSponsorMessage(data) {
|
|||||||
message: messagetext,
|
message: messagetext,
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
|
var messagewithemotes = await getYouTubeEmotes(messagetext);
|
||||||
|
|
||||||
const [avatar, message] = await Promise.all([
|
const [avatar, message] = await Promise.all([
|
||||||
``,
|
``,
|
||||||
currentLang.youtube.member({
|
currentLang.youtube.member({
|
||||||
months : months,
|
months : months,
|
||||||
tier : levelName,
|
tier : levelName,
|
||||||
message: messagetext
|
message: messagewithemotes
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -357,7 +360,7 @@ async function getYouTubeEmotes(data) {
|
|||||||
emoteMap.set(emote.code, { html: emoteElement, raw: emote.code });
|
emoteMap.set(emote.code, { html: emoteElement, raw: emote.code });
|
||||||
}
|
}
|
||||||
|
|
||||||
// YouTube emotes (ex: :vortisLaugh:)
|
// YouTube emotes (ex: :hand-pink-waving:)
|
||||||
if (data.emotes) {
|
if (data.emotes) {
|
||||||
for (const emote of data.emotes) {
|
for (const emote of data.emotes) {
|
||||||
const emoteElement = `<img src="${emote.imageUrl}" class="emote" alt="${emote.name}">`;
|
const emoteElement = `<img src="${emote.imageUrl}" class="emote" alt="${emote.name}">`;
|
||||||
|
Reference in New Issue
Block a user