Skip to content

Commit 046f30e

Browse files
committed
twitch chat test
1 parent 23d4981 commit 046f30e

File tree

3 files changed

+631
-0
lines changed

3 files changed

+631
-0
lines changed

bot.js

Lines changed: 351 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,351 @@
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

Comments
 (0)