Skip to content

Commit

Permalink
Implements #12 Add support for badges
Browse files Browse the repository at this point in the history
  • Loading branch information
Glodenox committed Jan 3, 2022
1 parent 29a850e commit 6c4d208
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 19 deletions.
9 changes: 6 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<!doctype html>
<!-- The default settings can be found at the end of this file -->
<html>
<head>
<meta charset="utf-8">
Expand Down Expand Up @@ -48,7 +49,6 @@ <h3>Style</h3>
</div>
<div id="settings-custom-style-exchange"><label>Custom style import/export: <input size="36" type="text" id="settings-custom-style-exchange-field"/></label></div>
<div><label><input type="checkbox" id="settings-hide-cursor"/> Hide cursor when it hasn't moved for 4 seconds</label></div>
<div><label><input type="checkbox" id="settings-align-messages"/> Line up messages vertically</label></div>
<div><label>Font size: <input type="number" size="3" max="200" min="4" id="settings-font-size"/> pixels</label></div>
</div>
<div>
Expand All @@ -75,14 +75,16 @@ <h3>Chat Behavior</h3>
</div>
<div>
<h3>Message Handling</h3>
<div><label><input type="checkbox" id="settings-align-messages"/> Line up messages vertically</label></div>
<div><label><input type="checkbox" id="settings-show-badges"/> Show user badges</label></div>
<div><label><input type="checkbox" id="settings-format-urls"/> Turn URLs into clickable links</label></div>
<div>
<label><input type="checkbox" id="settings-shorten-urls"/> Shorten long URLs</label>
<span class="help" title="More information" data-title="To preserve space, try to limit the lengt of a link. Usually done by truncating the path."></span>
<span class="help" title="More information" data-title="To preserve space, try to limit the length of a link. Usually done by truncating the path."></span>
</div>
<div>
<label><input type="checkbox" id="settings-inline-images"/> Show any images linked to by users</label>
<span class="help" title="More information" data-title="Load the images linked to by other users in chat. Links must end with a known image format or must point to Giphy or Imgur."></span>
<span class="help" title="More information" data-title="Load the images linked to by other users in chat. Links must end with a known image extension or must point to Giphy or Imgur."></span>
<div class="subfield hidden"><label>Maximum image size: <input type="number" size="2" max="80" min="5" id="settings-inline-images-height"/>% of available screen height</label></div>
</div>
<div><label><input type="checkbox" id="settings-unfurl-twitter"/> Unfurl Twitter links</label></div>
Expand Down Expand Up @@ -197,6 +199,7 @@ <h3>Hotkeys overview</h3>
'smooth-scroll': true,
'smooth-scroll-duration': 1000, // Time in milliseconds allowed for a message to appear
'combine-messages': false,
'show-badges': false,
'format-urls': true,
'shorten-urls': true,
'inline-images': true,
Expand Down
57 changes: 51 additions & 6 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,35 @@ var HexCompressor = function() {
};
}();

var Badges = function() {
var globalBadges = {};
var channelBadges = {};
var loadBadges = (url, handler, timeout = 2000) => {
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error(`Non-ok answer received from server: ${response.status} ${response.statusText}`);
}
})
.then(badgeSets => handler(badgeSets.badge_sets))
.catch(error => {
console.error(`Failed to retrieve badges at ${url}, attempting again in ${timeout}ms`, error);
setTimeout(() => loadBadges(url, handler, timeout * 2), timeout);
});
};
loadBadges('https://badges.twitch.tv/v1/badges/global/display?language=en', (badgeSet) => globalBadges = badgeSet);
return {
'lookup': (badge, version, channel) => globalBadges[badge]?.versions[version] ?? channelBadges[channel]?.[badge]?.versions[version] ?? null,
'load' : (channel) => {
if (channelBadges[channel] == undefined) {
loadBadges(`https://badges.twitch.tv/v1/badges/channels/${channel}/display?language=en`, (badgeSet) => channelBadges[channel] = badgeSet);
}
}
};
}();

var highlightUsers = Settings.get('highlight-users').toLowerCase().split(',').filter((user) => user != ''),
highlightKeyphrases = Settings.get('highlight-keyphrases').toLowerCase().split(',').filter((phrase) => phrase != '');

Expand Down Expand Up @@ -318,9 +347,6 @@ document.addEventListener('mousemove', () => {
}
});

document.getElementById('chat').classList.toggle('align-messages', Settings.get('align-messages'));
document.getElementById('settings-align-messages').checked = Settings.get('align-messages');
configureToggler('align-messages', () => document.getElementById('chat').classList.toggle('align-messages', Settings.get('align-messages')));
// Chat Behavior
document.body.classList.toggle('limit-message-rate', !Settings.get('limit-message-rate'));
document.getElementById('settings-limit-message-rate').checked = Settings.get('limit-message-rate');
Expand Down Expand Up @@ -365,6 +391,12 @@ document.getElementById('settings-smooth-scroll-duration').addEventListener('inp
}
});
// Message Handling
document.getElementById('chat').classList.toggle('align-messages', Settings.get('align-messages'));
document.getElementById('settings-align-messages').checked = Settings.get('align-messages');
configureToggler('align-messages', () => document.getElementById('chat').classList.toggle('align-messages', Settings.get('align-messages')));
document.getElementById('chat').classList.toggle('show-badges', Settings.get('show-badges'));
document.getElementById('settings-show-badges').checked = Settings.get('show-badges');
configureToggler('show-badges', () => document.getElementById('chat').classList.toggle('show-badges', Settings.get('show-badges')));
['combine-messages', 'format-urls', 'shorten-urls', 'unfurl-youtube', 'show-subscriptions', 'show-bits', 'show-mod-actions'].forEach(configureToggler);
configureToggler('inline-images', () => document.getElementById('settings-inline-images').parentNode.nextElementSibling.classList.toggle('hidden', !Settings.get('inline-images')));
if (Settings.get('inline-images')) {
Expand Down Expand Up @@ -465,7 +497,6 @@ function scrollUp(now) {
}
window.requestAnimationFrame(scrollUp);


/** Chat event handling **/
function handleChat(channel, userstate, message) {
if (Settings.get('limit-message-rate')) {
Expand Down Expand Up @@ -576,6 +607,7 @@ function processChat(channel, userstate, message) {

function handleRoomstate(channel, state) {
if (roomstate.channel != channel) {
Badges.load(state['room-id']);
flushMessageQueue();
addNotice(`Joined ${channel}.`);
if (state.slow) {
Expand All @@ -596,7 +628,7 @@ function handleSubscription(username, message, userstate) {
return;
}
var chatLine = document.createElement('div');
chatLine.className = 'highlight';
chatLine.className = 'highlight subscription';

var subscriptionNotice = document.createElement('div');
subscriptionNotice.textContent = userstate['system-msg'].replaceAll('\\s', ' ');
Expand Down Expand Up @@ -679,16 +711,29 @@ function configureToggler(key, callback) {
}

function createChatLine(userstate, message) {
// <div><span class="chat-user moderator">$username</span><span id="$msg-id">$message</span></div>
// <div><span class="timestamp">$timestamp</span><span class="chat-user moderator">$username</span><span id="$msg-id">$message</span></div>
var chatLine = document.createElement('div'),
chatTimestamp = document.createElement('span'),
chatName = document.createElement('span'),
chatBadges = document.createElement('span'),
chatMessage = document.createElement('span');

chatTimestamp.className = 'timestamp';
chatTimestamp.dataset.timestamp = userstate['tmi-sent-ts'] || Date.now();
updateTimestamp(chatTimestamp);
chatLine.appendChild(chatTimestamp);
chatBadges.className = 'badges';
Object.entries(userstate.badges ?? {}).forEach(([badge, version]) => {
var badgeData = Badges.lookup(badge, version, userstate['room-id']);
if (badgeData) {
var badge = document.createElement('img');
badge.src = badgeData.image_url_1x;
badge.srcset = `${badgeData.image_url_1x} 1x, ${badgeData.image_url_2x} 2x, ${badgeData.image_url_4x} 4x`;
badge.title = badgeData.title;
chatBadges.appendChild(badge);
}
});
chatLine.appendChild(chatBadges);
chatName.className = 'chat-user';
if (userstate.mod) {
chatName.classList.add('moderator');
Expand Down
39 changes: 29 additions & 10 deletions style.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,17 @@ body.reverse-order #chat {
width: 550px;
}

#chat .chat-user:after {
#chat .chat-user::after {
color: #eee;
color: var(--text-color);
font-weight: 300;
}

#chat .chat-user:not(.action):after {
#chat .chat-user:not(.action)::after {
content: ': ';
}

#chat .chat-user.action:after {
#chat .chat-user.action::after {
content: ' ';
}

Expand All @@ -117,11 +117,14 @@ body.reverse-order #chat {
padding-right: 5px;
}

#chat.align-messages div.notice .chat-user, #chat.align-messages div.highlight .chat-user {
flex-basis: 258px;
}

#chat.align-messages div {
display: flex;
}

#chat.align-messages div span {
#chat.align-messages div.subscription {
display: block;
}

Expand Down Expand Up @@ -176,12 +179,28 @@ body.reverse-order #chat {
color: yellow;
}

#chat .emoticon {
#chat:not(.show-badges) .badges {
display: none;
}

#chat img.emoticon, #chat .badges img {
height: calc(var(--font-size) - 2px);
object-fit: contain;
vertical-align: bottom;
}

#chat.align-messages .badges {
flex-basis: calc(var(--font-size) * 3 + 4px);
flex-shrink: 0;
}

#chat .badges img {
margin-right: 5px;
}
#chat.align-messages .badges img:last-child {
margin-right: 0;
}

#chat .counter {
font-weight: bold;
float: right;
Expand Down Expand Up @@ -498,7 +517,7 @@ body.reverse-order #message-entry {
margin: 0 5px;
}

#message-username:after {
#message-username::after {
content: ': ';
}

Expand All @@ -515,7 +534,7 @@ body.reverse-order #message-entry {
cursor: pointer;
vertical-align: super;
}
.help:after {
.help::after {
content: attr(data-title);
display: none;
border: 1px solid #eee;
Expand All @@ -527,11 +546,11 @@ body.reverse-order #message-entry {
background-color: var(--background-color);
padding: 4px;
}
.help.visible:after {
.help.visible::after {
display: block;
}

.help:hover:after {
.help:hover::after {
opacity: 1;
transition: all 0.1s ease 0.3s;
visibility: visible;
Expand Down

0 comments on commit 6c4d208

Please sign in to comment.