-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtwitchLiveChecker.js
421 lines (413 loc) · 13.7 KB
/
twitchLiveChecker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
registerPlugin({
name: 'Twitch Live Checker',
version: '1.2.0',
description: 'Checks twitch status and assigns server group, so that users can see if a client is currently streaming.',
author: 'Jaywalker',
requiredModules: ["http"],
vars: [{
name: 'mode',
title: 'How twitch streamers in your Teamspeak will be identified',
type: 'select',
options: [
'List',
'Description']
}, {
name: 'userChannels',
title: 'Each line represents TS3 Unique Ids and Twitch UserIDs (tsID:twitchID)',
type: 'multiline',
conditions: [{
field: 'mode',
value: 0
}]
}, {
name: 'twitchNameHint',
title: 'The hint in the description that comes before the twitch name (HINTtwitchID)',
type: 'string',
placeholder: 'twitch.tv/',
conditions: [{
field: 'mode',
value: 1
}]
}, {
name: 'interval',
title: 'Interval (in seconds) Best case not under 30 seconds...',
type: 'number',
placeholder: '30'
}, {
name: 'twitchLiveGroup',
title: 'Group-Number of your "Twitch Live Display" Server Group',
type: 'number',
placeholder: '123'
}, {
name: 'infoChannelMode',
title: 'Enable a Channel where its description and name show Live streamers',
type: 'select',
options: [
'Disabled',
'Enabled']
}, {
name: 'twitchInfoChannel',
title: 'Channel-Id where twitch statuses are displayed.',
type: 'channel',
conditions: [{
field: 'infoChannelMode',
value: 1
}]
}, {
name: 'channelCreateMode',
title: 'Create Channels for Streamers (of Server Group)',
type: 'select',
options: [
'Disabled',
'Enabled']
}, {
name: 'streamerChannelGroup',
title: 'Group-Number of your Twitch Live Streamer Group, Leave empty to not filter.',
type: 'number',
placeholder: '123',
conditions: [{
field: 'channelCreateMode',
value: 1
}]
}, {
name: 'streamerChannelParent',
title: 'Under this channel, the Streamer Channels get created',
type: 'channel',
conditions: [{
field: 'channelCreateMode',
value: 1
}]
}, {
name: 'clientIdTwitch',
title: 'Your Twitch Dev-App Client ID ( https://twitchtokengenerator.com/ )',
type: 'string'
}, {
name: 'tokenTwitch',
title: 'Your Twitch Access Token (OAuth)',
type: 'string'
}, {
name: 'outputType',
title: 'Logging Output-Type',
type: 'select',
options: [
'Log Only',
'Channel-Chat'
]
}, {
name: 'outputVerbosity',
title: 'Logging Verbosity',
type: 'select',
options: [
'Errors',
'Debug'
]
}]
}, function (sinusbot, config) {
//for ts-specific stuff
var backend = require('backend');
//for logging stuff
var engine = require('engine');
//for web stuff
var http = require("http");
//var store = require("store");
const TOKEN = config.tokenTwitch;
const APIKEY = config.clientIdTwitch;
var firstRun = true;
var checkStreamerCount = 0;
var checkedStreamerCount = 0;
var onlineStreamer = [];
var onlineStreamerContent = [];
function logToOutput(s, isError) {
//checks the set outputType and either logs to chat or only to the sinus Console
if (isError || config.outputVerbosity == 1) {
if (config.outputType == 1) {
backend.getCurrentChannel().chat(s);
}
engine.log(s);
}
}
//when loading the plugin, we split the user info, each line represents the global TS-ID and the twitch username
if (config.mode == 0) {
try {
var tsTwitch = (config && config.userChannels) ? config.userChannels.split('\n').map(function (e) {
return e.trim().replace(/\r/g, '');
}) : [];
} catch (err) {
logToOutput('Config error (TS-Twitch: ' + err.message, true);
}
}
//function to check if client cl is currently a member of a server group
function isInGroup(cl, groupIndex) {
var groups = cl.getServerGroups();
var found = false;
for (var i = 0; i < groups.length; i++) {
if (groups[i].id() == groupIndex) {
found = true;
break;
}
}
return found;
}
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function getChannelChildren(channel) {
var children = [];
var allC = backend.getChannels();
allC.forEach(c => {
if (c.parent() != null && c.parent().id() == channel.id()) {
children.push(c);
}
});
return children;
}
function checkLiveStatus(cl, twitchName) {
//sending a request to twitch helix api with the corresponding twitch username to check if the channel is online
http.simpleRequest({
method: 'GET',
url: 'https://api.twitch.tv/helix/streams?user_login=' + twitchName,
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Client-ID": APIKEY
},
timeout: 10 * 1000
}, function (error, response) {
if (error) {
logToOutput('Error: ' + error, true);
} else if (response.statusCode != 200) {
logToOutput('HTTP-Error: ' + response.status, true);
} else {
//logToOutput('API-GET success', false);
var res;
try {
res = JSON.parse(response.data.toString());
} catch (err) {
logToOutput('JSONparse-Error: ' + err.message, true);
}
if (res === undefined) {
logToOutput('Invalid JSON.', true);
} else {
//logToOutput('JSON parse success', false);
if (res.data.length == 0) {
//stream is offline
//logToOutput(cl.name() + '\'s Stream is currently offline', false);
if (isInGroup(cl, config.twitchLiveGroup)) {
logToOutput('Live group is being removed...', false);
cl.removeFromServerGroup(config.twitchLiveGroup);
} else {
//logToOutput('Live group was already removed.', false);
}
} else {
//stream is online ... probably
if (res.data[0].type == 'live') {
logToOutput(cl.name() + '\'s Stream is currently live!', false);
//stream is definitely online
if (!isInGroup(cl, config.twitchLiveGroup)) {
logToOutput('Live group is being applied...', false);
cl.addToServerGroup(config.twitchLiveGroup);
} else {
//logToOutput('Live group was already applied.', false);
}
if (!onlineStreamer.includes(twitchName.toLowerCase())) {
var title = res.data[0].title;
var thumbNail = res.data[0].thumbnail_url;
var liveString = "[b][size=14]" + twitchName + "[/size][/b]\r\n" + "[url=https://twitch.tv/" + twitchName + "][img]" + thumbNail + "[/img][/url]\r\n" + title + "\r\n\r\n";
onlineStreamer.push(twitchName.toLowerCase());
onlineStreamerContent.push({ "name": twitchName, "desc": liveString, "tsclient": cl });
}
}
}
}
}
checkedStreamerCount++;
});
}
//this is called every (interval) seconds
setInterval(function () {
//Check if all Streamers that should have been checked have been checked.
if (checkStreamerCount != checkedStreamerCount) {
return;
}
try {
var parentChannel = null;
if (config.channelCreateMode) {
parentChannel = backend.getChannelByID(config.streamerChannelParent);
}
var liveStreamerCount = onlineStreamer.length;
var infoChannelDesc = "[b][size=18][color=#FF0000]L[/color][color=#BF003F]I[/color][color=#7F007F]V[/color][color=#3F00BF]E[/color] Twitch Streamer (" + liveStreamerCount + ")[/size][/b]\r\n\r\n";
var liveChannelsCheck = [];
//Sort the names, so that it updates the Content only when something has changed
onlineStreamerContent.sort(function (a, b) {
if (a.name < b.name) { return -1; }
if (a.name > b.name) { return 1; }
return 0;});
while (onlineStreamerContent.length > 0) {
var twitchContent = onlineStreamerContent.pop();
var twitchName = twitchContent.name;
var liveClient = twitchContent.tsclient;
if (config.infoChannelMode) {
infoChannelDesc += twitchContent.desc.replace("{width}", "160").replace("{height}", "90") + "\r\n\r\n";
}
if (config.channelCreateMode) {
try {
var liveDescChannel = twitchContent.desc.replace("{width}", "320").replace("{height}", "180");
if (parentChannel != null) {
var twitchChannels = backend.getChannelsByName(twitchName);
var twitchChannel = null;
twitchChannels.forEach(chnnl => {
try {
logToOutput('CheckChannel ' + chnnl.name(), false);
if (twitchChannel == null && chnnl.parent().id() == parentChannel.id()) {
twitchChannel = chnnl;
}
} catch (error) {
logToOutput('FindChannelError ' + twitchName + ' : ' + error.message, true);
}
});
var userEligible = true;
if (config.streamerChannelGroup > 0) {
userEligible = isInGroup(liveClient, config.streamerChannelGroup);
}
if (twitchChannel == null) {
if (userEligible) {
var randomPW = makeid(6);
twitchChannel = backend.createChannel({ name: twitchName, parent: parentChannel.id(), description: liveDescChannel, password: randomPW, semiPermanent: true, topic: liveClient.name() });
liveClient.chat("Channel created, password is: " + randomPW);
liveChannelsCheck.push(twitchChannel.id());
}
} else {
if (userEligible) {
if (twitchChannel.description() != liveDescChannel) {
twitchChannel.setDescription(liveDescChannel);
}
liveChannelsCheck.push(twitchChannel.id());
}
}
}
} catch (error) {
logToOutput('ChannelCreateError ' + config.twitchInfoChannel + ' : ' + error.message, true);
}
}
}
if (config.infoChannelMode) {
var infoChannelName = "[cspacer]Keine Streamer Online";
try {
if (firstRun) {
infoChannelName = "[cspacer]--INITIALIZING--";
infoChannelDesc = "[b][size=18][color=#FF0000]L[/color][color=#BF003F]I[/color][color=#7F007F]V[/color][color=#3F00BF]E[/color] Twitch Streamer[/b]\r\n\r\nInitializing...";
} else {
if (liveStreamerCount > 0) {
infoChannelName = "[cspacer]" + liveStreamerCount + " Streamer online [click me]";
}
}
var infoChannel = backend.getChannelByID(config.twitchInfoChannel);
if (infoChannel != null) {
if (infoChannel.description() != infoChannelDesc) {
infoChannel.setName(infoChannelName);
infoChannel.setDescription(infoChannelDesc);
}
}
} catch (error) {
logToOutput('InfoChannelError ' + config.twitchInfoChannel + ' : ' + error.message, true);
}
}
if (config.channelCreateMode) {
if (parentChannel != null) {
var cChannels = getChannelChildren(parentChannel);
cChannels.forEach(cChnnl => {
if (!liveChannelsCheck.includes(cChnnl.id())) {
if (cChnnl.topic().length > 0 && cChnnl.getClientCount() == 0) {
cChnnl.delete();
}
}
});
}
}
} catch (error) {
logToOutput('ChannelStuffError ' + config.twitchInfoChannel + ' : ' + error.message, true);
}
onlineStreamer = [];
checkStreamerCount = 0;
checkedStreamerCount = 0;
if (config.mode == 0) {
logToOutput('Checking Twitch Live Status for ' + tsTwitch.length + ' users', false);
//check for all users that are configurated
for (i = 0; i < tsTwitch.length; i++) {
//usr looks like this: globalTwitchID63274gs82=:myChannelTV
var usr = tsTwitch[i];
//we split with the delimeter
var tmp = usr.split(':');
//check if split worked
if (tmp.length == 2) {
var tsID = tmp[0];
logToOutput('TS-ID: ' + tsID, false);
var twitchID = tmp[1];
logToOutput('Twitch-ID: ' + twitchID, false);
//we search for the client and check if he is online
var client = backend.getClientByUniqueID(tsID);
if (client != undefined && client != null) {
//client is found and is online
logToOutput(client.name() + ' is online in Teamspeak', false);
checkStreamerCount += 1;
//and we check for the client's live status
checkLiveStatus(client, twitchID);
} else {
logToOutput('Client not found', false);
}
}
}
} else {
//check for all online users
var onlineClients = backend.getClients();
logToOutput('Checking Twitch Live Status for ' + onlineClients.length + ' users', false);
var checkStreamers = [];
onlineClients.forEach(function (client) {
//get the description of the client
var desc = client.description();
//now we search and extract the twitch name from the description
var twitchNamePos = desc.search(config.twitchNameHint);
if (twitchNamePos != -1) {
twitchNamePos = twitchNamePos + config.twitchNameHint.length;
var twitchNameAndRest = desc.substr(twitchNamePos);
var twitchNameEnd = twitchNameAndRest.search(' ');
if (twitchNameEnd == -1) {
twitchNameEnd = twitchNameAndRest.search('\n');
}
//MAGIC NUMBEEEERRRRS
if (twitchNameEnd == -1) {
twitchNameEnd = twitchNameAndRest.length;
}
if (twitchNameEnd != -1) {
//Okay we have found the twitch name start and end position and can now extract it from the substring
var twitchName = twitchNameAndRest.substr(0, twitchNameEnd);
logToOutput('Found the twitch Name: ' + twitchName, false);
//and check for the client's live status
checkStreamers.push({ "cl": client, "tn": twitchName });
} else {
logToOutput('Could not find end of twitch Name: ' + twitchNameAndRest, true);
}
} else {
//logToOutput(client.name() + ' has no twitch name in description', false);
if (isInGroup(client, config.twitchLiveGroup)) {
logToOutput('Live group is being removed...', false);
client.removeFromServerGroup(config.twitchLiveGroup);
}
}
});
checkStreamerCount = checkStreamers.length;
for (let i = 0; i < checkStreamerCount; i++) {
const cs = checkStreamers[i];
checkLiveStatus(cs.cl, cs.tn);
}
}
if (firstRun) {
firstRun = false;
}
}, config.interval * 1000);
});