|
| 1 | +//const tmi = require('tmi.js'); |
| 2 | + |
| 3 | +var fadeDelay = false, // Set to false to disable chat fade |
| 4 | + showChannel = true, // Show repespective channels if the channels is longer than 1 |
| 5 | + useColor = true, // Use chatters' colors or to inherit |
| 6 | + showBadges = true, // Show chatters' badges |
| 7 | + showEmotes = true, // Show emotes in the chat |
| 8 | + doTimeouts = false, // Hide the messages of people who are timed-out |
| 9 | + doChatClears = false, // Hide the chat from an entire channel |
| 10 | + showHosting = true, // Show when the channel is hosting or not |
| 11 | + showConnectionNotices = true; // Show messages like "Connected" and "Disconnected" |
| 12 | + channels = []; |
| 13 | + |
| 14 | +var defaultColors = ['rgb(255, 0, 0)','rgb(0, 0, 255)','rgb(0, 128, 0)','rgb(178, 34, 34)','rgb(255, 127, 80)','rgb(154, 205, 50)','rgb(255, 69, 0)','rgb(46, 139, 87)','rgb(218, 165, 32)','rgb(210, 105, 30)','rgb(95, 158, 160)','rgb(30, 144, 255)','rgb(255, 105, 180)','rgb(138, 43, 226)','rgb(0, 255, 127)'], |
| 15 | + randomColorsChosen = {}; |
| 16 | + |
| 17 | +// Define configuration options |
| 18 | +var opts = { |
| 19 | + options: { debug: true }, |
| 20 | + connection: { |
| 21 | + reconnect: true, |
| 22 | + secure: true |
| 23 | + }, |
| 24 | + identity: { |
| 25 | + username: 'hianbot', |
| 26 | + password: 'oauth:82pr79g12rrgykqghj1ca052v3sexx' |
| 27 | + }, |
| 28 | + channels: channels |
| 29 | +}; |
| 30 | + |
| 31 | +// Helper functions |
| 32 | + |
| 33 | +function dehash(channel) { |
| 34 | + return channel.replace(/^#/, ''); |
| 35 | +} |
| 36 | + |
| 37 | +function capitalize(n) { |
| 38 | + return n[0].toUpperCase() + n.substr(1); |
| 39 | +} |
| 40 | + |
| 41 | +function htmlEntities(html) { |
| 42 | + function it() { |
| 43 | + return html.map(function(n, i, arr) { |
| 44 | + if(n.length == 1) { |
| 45 | + return n.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { |
| 46 | + return '&#'+i.charCodeAt(0)+';'; |
| 47 | + }); |
| 48 | + } |
| 49 | + return n; |
| 50 | + }); |
| 51 | + } |
| 52 | + var isArray = Array.isArray(html); |
| 53 | + if(!isArray) { |
| 54 | + html = html.split(''); |
| 55 | + } |
| 56 | + html = it(html); |
| 57 | + if(!isArray) html = html.join(''); |
| 58 | + return html; |
| 59 | +} |
| 60 | + |
| 61 | +function formatEmotes(text, emotes) { |
| 62 | + var splitText = text.split(''); |
| 63 | + for(var i in emotes) { |
| 64 | + var e = emotes[i]; |
| 65 | + for(var j in e) { |
| 66 | + var mote = e[j]; |
| 67 | + if(typeof mote == 'string') { |
| 68 | + mote = mote.split('-'); |
| 69 | + mote = [parseInt(mote[0]), parseInt(mote[1])]; |
| 70 | + var length = mote[1] - mote[0], |
| 71 | + empty = Array.apply(null, new Array(length + 1)).map(function() { return '' }); |
| 72 | + splitText = splitText.slice(0, mote[0]).concat(empty).concat(splitText.slice(mote[1] + 1, splitText.length)); |
| 73 | + // splitText.splice(mote[0], 1, '<img class="emoticon" src="https://cdn.frankerfacez.com/emoticon/' + i + '/3.0">'); |
| 74 | + splitText.splice(mote[0], 1, '<img class="emoticon" src="http://static-cdn.jtvnw.net/emoticons/v1/' + i + '/3.0">'); |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + return htmlEntities(splitText).join('') |
| 79 | +} |
| 80 | + |
| 81 | +function badges(channel, user, isBot) { |
| 82 | + |
| 83 | + function createBadge(name) { |
| 84 | + var badge = document.createElement('div'); |
| 85 | + badge.className = 'chat-badge-' + name; |
| 86 | + return badge; |
| 87 | + } |
| 88 | + |
| 89 | + var chatBadges = document.createElement('span'); |
| 90 | + chatBadges.className = 'chat-badges'; |
| 91 | + |
| 92 | + if(!isBot) { |
| 93 | + if (user.badges) { |
| 94 | + console.log(`Has badges`) |
| 95 | + if (user.badges.admin) { |
| 96 | + chatBadges.appendChild(createBadge('admin')); |
| 97 | + } |
| 98 | + if (user.badges.broadcaster) { |
| 99 | + chatBadges.appendChild(createBadge('broadcaster')); |
| 100 | + } |
| 101 | + if (user.badges.moderator) { |
| 102 | + chatBadges.appendChild(createBadge('moderator')); |
| 103 | + } |
| 104 | + if (user.badges.premium) { |
| 105 | + chatBadges.appendChild(createBadge('premium')); |
| 106 | + } |
| 107 | + } |
| 108 | + else { |
| 109 | + console.log(`No badges`) |
| 110 | + } |
| 111 | + // if(user.username == channel) { |
| 112 | + // chatBadges.appendChild(createBadge('broadcaster')); |
| 113 | + // } |
| 114 | + // if(user['user-type']) { |
| 115 | + // chatBadges.appendChild(createBadge(user['user-type'])); |
| 116 | + // } |
| 117 | + // if(user.turbo) { |
| 118 | + // chatBadges.appendChild(createBadge('turbo')); |
| 119 | + // } |
| 120 | + } |
| 121 | + |
| 122 | + else { |
| 123 | + chatChages.appendChild(createBadge('bot')); |
| 124 | + } |
| 125 | + |
| 126 | + return chatBadges; |
| 127 | +} |
| 128 | + |
| 129 | +function chatNotice(information, noticeFadeDelay, level, additionalClasses) { |
| 130 | + var ele = document.createElement('div'); |
| 131 | + |
| 132 | + ele.className = 'chat-line chat-notice'; |
| 133 | + ele.innerHTML = information; |
| 134 | + |
| 135 | + if(additionalClasses !== undefined) { |
| 136 | + if(Array.isArray(additionalClasses)) { |
| 137 | + additionalClasses = additionalClasses.join(' '); |
| 138 | + } |
| 139 | + ele.className += ' ' + additionalClasses; |
| 140 | + } |
| 141 | + |
| 142 | + if(typeof level == 'number' && level != 0) { |
| 143 | + ele.dataset.level = level; |
| 144 | + } |
| 145 | + |
| 146 | + chat.appendChild(ele); |
| 147 | + |
| 148 | + // if(typeof noticeFadeDelay == 'number') { |
| 149 | + // setTimeout(function() { |
| 150 | + // ele.dataset.faded = ''; |
| 151 | + // }, noticeFadeDelay || 500); |
| 152 | + // } |
| 153 | + |
| 154 | + return ele; |
| 155 | +} |
| 156 | + |
| 157 | +var recentTimeouts = {}; |
| 158 | + |
| 159 | +function timeout(channel, username) { |
| 160 | + if(!doTimeouts) return false; |
| 161 | + if(!recentTimeouts.hasOwnProperty(channel)) { |
| 162 | + recentTimeouts[channel] = {}; |
| 163 | + } |
| 164 | + if(!recentTimeouts[channel].hasOwnProperty(username) || recentTimeouts[channel][username] + 1000*10 < +new Date) { |
| 165 | + recentTimeouts[channel][username] = +new Date; |
| 166 | + chatNotice(capitalize(username) + ' was timed-out in ' + capitalize(dehash(channel)), 1000, 1, 'chat-delete-timeout') |
| 167 | + }; |
| 168 | + var toHide = document.querySelectorAll('.chat-line[data-channel="' + channel + '"][data-username="' + username + '"]:not(.chat-timedout) .chat-message'); |
| 169 | + for(var i in toHide) { |
| 170 | + var h = toHide[i]; |
| 171 | + if(typeof h == 'object') { |
| 172 | + h.innerText = '<Message deleted>'; |
| 173 | + h.parentElement.className += ' chat-timedout'; |
| 174 | + } |
| 175 | + } |
| 176 | +} |
| 177 | + |
| 178 | +function clearChat(channel) { |
| 179 | + if(!doChatClears) return false; |
| 180 | + var toHide = document.querySelectorAll('.chat-line[data-channel="' + channel + '"]'); |
| 181 | + for(var i in toHide) { |
| 182 | + var h = toHide[i]; |
| 183 | + if(typeof h == 'object') { |
| 184 | + h.className += ' chat-cleared'; |
| 185 | + } |
| 186 | + } |
| 187 | + chatNotice('Chat was cleared in ' + capitalize(dehash(channel)), 1000, 1, 'chat-delete-clear') |
| 188 | +} |
| 189 | +function hosting(channel, target, viewers, unhost) { |
| 190 | + if(!showHosting) return false; |
| 191 | + if(viewers == '-') viewers = 0; |
| 192 | + var chan = dehash(channel); |
| 193 | + chan = capitalize(chan); |
| 194 | + if(!unhost) { |
| 195 | + var targ = capitalize(target); |
| 196 | + chatNotice(chan + ' is now hosting ' + targ + ' for ' + viewers + ' viewer' + (viewers !== 1 ? 's' : '') + '.', null, null, 'chat-hosting-yes'); |
| 197 | + } |
| 198 | + else { |
| 199 | + chatNotice(chan + ' is no longer hosting.', null, null, 'chat-hosting-no'); |
| 200 | + } |
| 201 | +} |
| 202 | + |
| 203 | +function updateScroll(){ |
| 204 | + var element = document.getElementById('chat'); |
| 205 | + element.scrollTop = element.scrollHeight; |
| 206 | +} |
| 207 | + |
| 208 | +// Display and parse chat |
| 209 | +function handleChat(channel, user, message, self) { |
| 210 | + // str = JSON.stringify(user, null, 4); |
| 211 | + // console.log(str); |
| 212 | + var chan = dehash(channel), |
| 213 | + name = user.username, |
| 214 | + chatLine = document.createElement('div'), |
| 215 | + chatChannel = document.createElement('span'), |
| 216 | + chatName = document.createElement('span'), |
| 217 | + chatColon = document.createElement('span'), |
| 218 | + chatMessage = document.createElement('span'); |
| 219 | + |
| 220 | + var color = useColor ? user.color : 'inherit'; |
| 221 | + if(color === null) { |
| 222 | + if(!randomColorsChosen.hasOwnProperty(chan)) { |
| 223 | + randomColorsChosen[chan] = {}; |
| 224 | + } |
| 225 | + if(randomColorsChosen[chan].hasOwnProperty(name)) { |
| 226 | + color = randomColorsChosen[chan][name]; |
| 227 | + } |
| 228 | + else { |
| 229 | + color = defaultColors[Math.floor(Math.random()*defaultColors.length)]; |
| 230 | + randomColorsChosen[chan][name] = color; |
| 231 | + } |
| 232 | + } |
| 233 | + |
| 234 | + chatLine.className = 'chat-line'; |
| 235 | + chatLine.dataset.username = name; |
| 236 | + chatLine.dataset.channel = channel; |
| 237 | + |
| 238 | + if(user['message-type'] == 'action') { |
| 239 | + chatLine.className += ' chat-action'; |
| 240 | + } |
| 241 | + |
| 242 | + chatChannel.className = 'chat-channel'; |
| 243 | + chatChannel.innerHTML = chan; |
| 244 | + |
| 245 | + chatName.className = 'chat-name'; |
| 246 | + chatName.style.color = color; |
| 247 | + chatName.innerHTML = user['display-name'] || name; |
| 248 | + |
| 249 | + chatColon.className = 'chat-colon'; |
| 250 | + |
| 251 | + chatMessage.className = 'chat-message'; |
| 252 | + |
| 253 | + chatMessage.style.color = color; |
| 254 | + chatMessage.innerHTML = showEmotes ? formatEmotes(message, user.emotes) : htmlEntities(message); |
| 255 | + |
| 256 | + if(chatClient.client.opts.channels.length > 1) chatLine.appendChild(chatChannel); |
| 257 | + if(showBadges) chatLine.appendChild(badges(chan, user, self)); |
| 258 | + chatLine.appendChild(chatName); |
| 259 | + chatLine.appendChild(chatColon); |
| 260 | + chatLine.appendChild(chatMessage); |
| 261 | + |
| 262 | + chat.appendChild(chatLine); |
| 263 | + |
| 264 | + if(typeof fadeDelay == 'number') { |
| 265 | + setTimeout(function() { |
| 266 | + chatLine.dataset.faded = ''; |
| 267 | + }, fadeDelay); |
| 268 | + } |
| 269 | + |
| 270 | + if(chat.children.length > 50) { |
| 271 | + var oldMessages = [].slice.call(chat.children).slice(0, 10); |
| 272 | + for(var i in oldMessages) oldMessages[i].remove(); |
| 273 | + } |
| 274 | + updateScroll(); |
| 275 | +} |
| 276 | + |
| 277 | +// Register our event handlers (defined below) |
| 278 | +// client.on('message', onMessageHandler); |
| 279 | +// client.on('connected', onConnectedHandler); |
| 280 | + |
| 281 | +var chatClient = function chatClient(options) { |
| 282 | + this.options = options |
| 283 | +} |
| 284 | + |
| 285 | +var previousChannel; |
| 286 | + |
| 287 | +chatClient.prototype.reset = function reset(options){ |
| 288 | + if (previousChannel) { |
| 289 | + chatClient.client.part(previousChannel); |
| 290 | + } |
| 291 | + console.log(`${this.options.channels[0]}`); |
| 292 | + chatClient.client.join(this.options.channels[0]); |
| 293 | + console.log(`${previousChannel}`); |
| 294 | + previousChannel = this.options.channels[0]; |
| 295 | + |
| 296 | +} |
| 297 | + |
| 298 | +chatClient.prototype.open = function open(){ |
| 299 | + |
| 300 | + var chat = document.getElementById('chat'); |
| 301 | + // Create a client with our options |
| 302 | + this.client = new tmi.client(this.options); |
| 303 | + |
| 304 | + // Listeners |
| 305 | + this.client.addListener('message', handleChat); |
| 306 | + this.client.addListener('timeout', timeout); |
| 307 | + this.client.addListener('clearchat', clearChat); |
| 308 | + this.client.addListener('hosting', hosting); |
| 309 | + this.client.addListener('unhost', function(channel, viewers) { hosting(channel, null, viewers, true) }); |
| 310 | + |
| 311 | + this.client.addListener('connecting', function (address, port) { |
| 312 | + if(showConnectionNotices) chatNotice('Connecting', 1000, -4, 'chat-connection-good-connecting'); |
| 313 | + }); |
| 314 | + this.client.addListener('logon', function () { |
| 315 | + if(showConnectionNotices) chatNotice('Authenticating', 1000, -3, 'chat-connection-good-logon'); |
| 316 | + }); |
| 317 | + this.client.addListener('connectfail', function () { |
| 318 | + if(showConnectionNotices) chatNotice('Connection failed', 1000, 3, 'chat-connection-bad-fail'); |
| 319 | + }); |
| 320 | + this.client.addListener('connected', function (address, port) { |
| 321 | + if(showConnectionNotices) chatNotice('Connected', 1000, -2, 'chat-connection-good-connected'); |
| 322 | + joinAccounced = []; |
| 323 | + }); |
| 324 | + this.client.addListener('disconnected', function (reason) { |
| 325 | + if(showConnectionNotices) chatNotice('Disconnected: ' + (reason || ''), 3000, 2, 'chat-connection-bad-disconnected'); |
| 326 | + }); |
| 327 | + this.client.addListener('reconnect', function () { |
| 328 | + if(showConnectionNotices) chatNotice('Reconnected', 1000, 'chat-connection-good-reconnect'); |
| 329 | + }); |
| 330 | + this.client.addListener('join', function (channel, username) { |
| 331 | + if(username == opts.identity.username) { |
| 332 | + if(showConnectionNotices) chatNotice('Joined ' + capitalize(dehash(channel)), 1000, -1, 'chat-room-join'); |
| 333 | + console.log('Joined ' + capitalize(dehash(channel))) |
| 334 | + joinAccounced.push(channel); |
| 335 | + } |
| 336 | + }); |
| 337 | + this.client.addListener('part', function (channel, username) { |
| 338 | + var index = joinAccounced.indexOf(channel); |
| 339 | + if(index > -1) { |
| 340 | + if(showConnectionNotices) chatNotice('Parted ' + capitalize(dehash(channel)), 1000, -1, 'chat-room-part'); |
| 341 | + joinAccounced.splice(joinAccounced.indexOf(channel), 1) |
| 342 | + } |
| 343 | + }); |
| 344 | + |
| 345 | + this.client.addListener('crash', function () { |
| 346 | + chatNotice('Crashed', 10000, 4, 'chat-crash'); |
| 347 | + }); |
| 348 | + |
| 349 | + // Connect to Twitch: |
| 350 | + this.client.connect(); |
| 351 | +} |
0 commit comments