· 6 years ago · Jan 27, 2020, 12:18 AM
1
2/*Description
3This app will create clips of Twitch Channels for the events of Bits being cheered,
4Subs, and Hosts/Raids happening in the stream.
5
6In the future, will be able to create clips based on events happening through Stream Elements API,
7Warp World API, and Steam labs API. Those will come soon.
8
9Will make clips of all significant events. Users will be able to configure their event list to,
10change parameters on clips being maade. All clips will be stored and sorted into a DB.
11
12selecting + oauth
13SELECT * FROM `settings` JOIN users on users.name = settings.channel WHERE 1
14
15
16*/
17const auth_uri_server = "https://id.twitch.tv/oauth2/token?client_id=grant_type=client_credentials&scope=clips:edit"
18//libraries
19const fs = require('fs');
20const config = require('./config');
21const dbConfig = require('./dbconfig')
22const twitchJS = require('tmi.js');
23const mysql = require('mysql');
24const request = require('request');
25const client_id= ''
26const squel = require("squel");
27const express = require('express');
28const channelList = ['warpmemories'];
29var sql;
30//api
31var app = express();
32
33app.listen(3002, "0.0.0.0");
34
35//handles post request at localhost:3002/channel
36//requires
37
38
39
40app.post("/api/channel", (req,res,next) => {
41 logError("aip/channel","test","entered api/channel function","butts");
42 if(req.headers.channel){
43 if(connectChannel(req.headers.channel)){
44 res.json({"channel":req.headers.channel,
45 "response":"Connection was succesful"})
46 }
47 }
48 else{
49 res.json({"response":"Channel header not included"})
50 }
51});
52
53//handles post request at localhost:3002/channel
54//requires channel, viewer, type, extra details(data json obj)
55app.post("/api/create_clip", (req,res,next) => {
56 if(req.headers.channel){
57 if(!channels[req.headers.channel]){
58 if(connectChannel(req.headers.channel)){
59 }
60 }
61 }
62 else{
63 res.json({"response":"Channel header not included"})
64 }
65});
66
67//channels
68var access_token;
69var channels = [];
70var enable_log = false;
71let twitch = new twitchJS.client(config)
72let twitchmemories = new twitchJS.client(config)
73twitch.connect()
74twitchmemories.connect()
75twitchmemories.join('WarpMemories');
76//twitchmemories is for only connecting to the memories twitch channel
77
78//Database connection
79
80
81//initiate logging
82//create a new file for this instance of the app running
83var log;
84var logFileName = "./logs/" + Date.now() + ".txt";
85console.log( "ACTION: OPENING FILE TO WRITE" + logFileName);
86beginLogging();
87function beginLogging(){
88 if (enable_log){
89 fs.writeFile(logFileName, "Beginning Logging", (err) => {
90 if(err){
91 console.log(err);
92 }
93 })
94 }
95}
96/*origin - Where is the error
97 error - Error message
98 message - Notes from Developer
99 vardump = Variables related to error
100 */
101
102
103
104function logError(origin, error, message="", vardump=""){
105 var log = `-------
106 Origin: ${origin}
107 Error: ${error}
108 Message: ${message}
109 Vardump: ${vardump}`;
110 fs.appendFile(logFileName, '\r\n' + log, (err) => {
111 if (err){
112 console.log(err);
113 }
114 })
115}
116
117
118
119
120connectSQL();
121
122function connectSQL(){
123 try{
124 sql = mysql.createConnection(dbConfig);
125 sql.connect(function(err){
126 if (err){
127 console.log("Error while connecting to DB ", err);
128 //attempt reconnect
129 setTimeout(connectSQL,2000);
130 }
131 console.log("SQL connected");
132 });
133 }
134 catch(e){
135 console.log(e);
136 logError('connectSQL',e);
137 }
138
139}
140
141sql.on('error',function(err){
142 console.log("DB Error: ", err)
143 if(err.code == 'PROTOCOL_CONNECTION_LOST')
144 {
145 connectSQL();
146 }
147 else{
148 throw err;
149 }
150});
151
152//can be used to add new channel, or update existing channel
153function connectChannel(channelName){
154 try{
155 if(!channels[channelName]){
156 //join chat for the selected channel
157 twitch.join(channelName).catch(err => err.log);
158 //create channel object for selected channel
159 channels[channelName] = new Channel(channelName);
160 }
161 }
162 catch(e){
163 console.log("Could not completed connection to ",channelName);
164 logError('connectChannel',e,`Could not connect to user ${channelName} with twitch-js`);
165 return false;
166 }
167 return true;
168}
169
170function connectChat(){
171 //reads all users from settings DB, connects to their chats
172 var selectQuery = squel.select()
173 .from("settings")
174 sql.query(selectQuery.toString(), function(error,results, fields){
175 //for(var i = 0; i<results.length ; i++){
176
177 for(var i = 0; i<results.length ; i++){
178 const channelName = results[i].channel.toLowerCase().replace(/\s/g, '');
179 channelList.push(channelName);
180 }
181 const intervalID = setInterval(function(){
182 const channelName = channelList.shift();
183 if(channelName){
184 //console.log("connecting to - ",channelName);
185 connectChannel(channelName);
186 }
187 if(channelList.length==0){
188 console.log('clearing interval');
189 clearInterval(intervalID);
190 }
191 },50)
192
193 });
194}
195
196class Channel {
197 constructor(channelName){
198 //check for entry in DB, if exists get settings, else create default entry for user
199 //NOTE: channel name in DB does NOT keep # in front
200 try{
201 //get user from DB
202 this.queuedData = [];
203 this.queue = "";
204 getSettings(channelName,(results) => {
205 this.subTier = results.sub_tier;
206 this.twitchID = results.twitch_id;
207 this.subMonth = results.sub_month;
208 this.bits = results.bits;
209 this.autohost = results.autohost;
210 this.hostAmount = results.host_amount;
211 this.accessToken = results.access_token;
212 this.refreshToken = results.refresh_token;
213 this.ownClip = results.own_clip;
214 });
215
216 }
217 catch(e){
218 console.log(e)
219 logError('Channel constructor',e);
220 }
221 }
222
223 isQueue(){
224 if (this.queue == ""){
225 return false
226 }
227 return true
228 }
229
230 activateQueue(){
231 this.queue = "generating";
232 }
233
234 resetQueue(){
235 this.queue = "";
236 this.queuedData = [];
237 }
238
239 addClipToQueue(metadata){
240 this.queuedData.push(metadata);
241 }
242
243 getClips(){
244 return this.queuedData;
245 }
246
247 getSubMonth(){
248 return this.subMonth;
249 }
250 getSubTier(){
251 return this.subTier;
252 }
253 getBits(){
254 return this.bits;
255 }
256 getAutohost(){
257 return this.autohost;
258 }
259 getAccessToken(){
260 return this.accessToken;
261 }
262 getRefreshToken(){
263 return this.refreshToken;
264 }
265 getTwitchID(){
266 return this.twitchID;
267 }
268 setRefreshToken(refresh_token, access_token){
269 this.accessToken = access_token;
270 this.refreshToken = refresh_token;
271 return;
272 }
273
274 gethostAmount(){
275 return this.hostAmount;
276 }
277}
278
279function getSettings(channelName, callback){
280 var selectResults;
281 var selectQuery = squel.select()
282 .from("settings")
283 .left_join("users",null,"users.name = settings.channel")
284 .where("channel = '"+ channelName+"'" );
285 var test;
286 sql.query(selectQuery.toString(), function(error, results, fields){
287 try{
288 if (error){
289 throw error
290 }
291 if (!results[0]){
292 console.log('creating new user in settings table');
293 //enter user with default settings
294 getTwitchUserID(channelName,(twitchID)=>{
295 var newUserQuery = squel.insert()
296 .into("settings")
297 .set("channel",channelName)
298 .set("twitch_id",twitchID);
299
300 sql.query(newUserQuery.toString(), function(error, results, fields){
301 //console.log(results)
302 });
303 return callback({"sub_tier":1,
304 "twitch_id":twitchID,
305 "sub_month":1,
306 "bits":500,
307 "autohost":0,
308 "host_amount":10,
309 "own_clip":0,
310 "accessToken":"",
311 "refreshToken":""});
312 //set default settings
313 });
314
315 }
316 else{
317 if(results[0].twitch_id==0){
318 console.log('attempting to update userIDs for streamers');
319
320 getTwitchUserID(channelName,(twitchID)=>{
321 if (twitchID){
322 var updateString = squel.update()
323 .table("settings")
324 .set("twitch_id",twitchID)
325 .where("channel = '" + channelName + "'").toString();
326
327 console.log("Update string" , updateString);
328
329 sql.query(updateString, function(error,results, fields){
330 //console.log(results);
331 //console.log(error);
332
333 //return callback(results[0].twitch_id=twitchID);
334 if(error){
335 console.log("something went wrong with the query? " + error);
336 }
337 });
338 }
339 });
340 }
341 return callback(results[0]);
342 }
343 }
344 catch(e){
345 console.log(e)
346 logError('getSettings',e);
347 if (e.code == "ER_EMPTY_QUERY"){
348 }
349 }
350
351 });
352
353 //console.log("test" + test);
354 //console.log("select results: "+selectResults);
355};
356
357
358setTimeout(function(){
359 //this connects to all the channels
360 connectChat();
361},1000)
362
363/*
364FILTERS
365SUB
366 Months subbed (default = 1)
367 Tier of sub (default = 1)
368Bits
369 Amount Cheered (Default = 500 and up)
370Host/Raid
371 Amount of raiders (Default 10 and up)
372 Autohost (default no)
373GiftSub
374 Tier
375 eventually add gift bombs
376*/
377
378//gift subs
379twitch.on("subgift", function(channel,username,recipient,method,userstate){
380 try{
381 var subPlan = method["plan"],
382 subMonth = userstate["msg-param-cumulative-months"];
383 if (Number.isInteger(subPlan)){//sets subplan to 1,2 or 3
384 subPlan = parseInt(subPlan)
385 subPlan = subPlan/1000;
386 }
387 else{
388 subPlan = 1;
389 }
390 if(!Number.isInteger(subMonth)){
391 subMonth=1;
392 }
393 //console.log("logs for subgift for "+ channel.substr(1));
394 console.log("User Settings plan- "+ channels[channel.substr(1).toLowerCase()].getSubTier() + " settings months =" + channels[channel.substr(1)].getSubMonth());
395 console.log("Current sub plan =" +subPlan + " current sub months "+ subMonth);
396 if(channels[channel.substr(1)].getSubTier() <= subPlan && channels[channel.substr(1)].getSubMonth() <= subMonth){
397 createClip(userstate['room-id'],20,{"type":"sub","userstate":userstate,"channel":channel,"user":recipient,"user-id":userstate["user-id"]});
398 }
399 console.log("Method ="+ JSON.stringify(method) );
400 console.log("Userstate ="+JSON.stringify(userstate));
401 }
402 catch(e){
403 console.log("subgift didnt work dummy lul");
404 logError('subgift listener',e,`subgift was for channel ${channel}`,'',`Userstate Object ${userstate}`);
405 }
406});
407
408//resubs
409twitch.on("resub", function (channel, username, months, message, userstate, methods) {
410 try{
411 var subPlan = methods["plan"],
412 subMonth = userstate["msg-param-cumulative-months"];
413 if (Number.isInteger(subPlan)){//sets subplan to 1,2 or 3
414 subPlan = parseInt(subPlan)
415 subPlan = subPlan/1000;
416 }
417 else{
418 subPlan = 1;
419 }
420 if(!Number.isInteger(subMonth)){
421 subMonth=1;
422 }
423 console.log("logs for resub for "+ channel.substr(1));
424 console.log("User Settings plan- "+ channels[channel.substr(1)].getSubTier() + " settings months =" + channels[channel.substr(1)].getSubMonth());
425 console.log("Current sub plan =" +subPlan + " current sub months "+ subMonth);
426 if(channels[channel.substr(1)].getSubTier() <= subPlan && channels[channel.substr(1)].getSubMonth() <= subMonth){
427 createClip(userstate['room-id'],20,{"type":"sub","userstate":userstate,"channel":channel,"user":username,"user-id":userstate["user-id"]});
428 }
429 //console.log("Method ="+ JSON.stringify(methods) );
430 //console.log("Message ="+message);
431 //console.log("Userstate ="+JSON.stringify(userstate));
432 }
433 catch(e){
434 console.log("resub didnt work dummy lul");
435 logError("resub error " + e,`resub was for channel ${channel}`,'',`Userstate Object ${userstate}`);
436 }
437});
438
439
440// tier 1 = 1000
441// tier 2 = 2000
442// tier 3 = 3000
443twitch.on("subscription", function (channel, username, method, message, userstate) {
444 try{
445 var subPlan = method["plan"],
446 subMonth = userstate["msg-param-cumulative-months"];
447 if (Number.isInteger(subPlan)){//sets subplan to 1,2 or 3
448 subPlan = parseInt(subPlan)
449 subPlan = subPlan/1000;
450 }
451 else{
452 subPlan = 1;
453 }
454 if(!Number.isInteger(subMonth)){
455 subMonth=1;
456 }
457
458 if (enable_log){
459 console.log("logs for sub for "+ channel.substr(1));
460 console.log("User Settings plan- "+ channels[channel.substr(1)].getSubTier() + " settings months =" + channels[channel.substr(1)].getSubMonth());
461 console.log("Current sub plan =" +subPlan + " current sub months "+ subMonth);
462 }
463
464 if(channels[channel.substr(1)].getSubTier() <= subPlan && channels[channel.substr(1)].getSubMonth() <= subMonth){
465 createClip(userstate['room-id'],20,{"type":"sub","userstate":userstate,"channel":channel,"user":username,"user-id":userstate["user-id"]});
466 }
467
468 if (enable_log){
469 console.log("Method ="+ JSON.stringify(method) );
470 console.log("Message ="+message);
471 console.log("Userstate ="+JSON.stringify(userstate));
472 }
473 }
474 catch(e){
475 console.log("Subscription Failed");
476 logError("sub error " + e,`sub was for channel ${channel}`,'',`Userstate Object ${userstate}`);
477 }
478
479});
480
481//parameters
482//amount of bits
483twitch.on("cheer", function (channel, userstate, message) {
484 try{
485 //temporary
486 //logError("Cheer listener","here for userstate dump","","Userstate -"+JSON.stringify(userstate))
487 //end temporary
488 console.log("Bits Event @ "+ channel + " for " + userstate["bits"] + " bits")
489 if (subPlan = parseInt(userstate["bits"]) >= channels[channel.substr(1)].bits){
490 createClip(userstate['room-id'],20,{"type":"bits","userstate":userstate,"channel":channel,"user":userstate["display-name"],"user-id":userstate["user-id"]});
491 }
492 }
493 catch(e){
494 console.log("bits didnt work dummy lul");
495 logError("cheer error " + e,`cheer was for channel ${channel}`,'',`Userstate Object ${userstate}`);
496 }
497});
498//hosting only works if we're listening with the account that owns the channel - aka no hope for hosts.
499twitch.on("hosted", function ({channel, username, viewers, autohost}) {
500 try{
501 console.log("HOST EVENT", channel, username, viewers, autohost);
502 logError("host listener","here for userstate dump","","Userstate -"+JSON.stringify(userstate))
503 if (!autohost){
504 if (viewers >= channels[channel.substr(1)].hostAmount ){
505 createClip(userstate['room-id'],20,{"type":"host","userstate":userstate,"channel":channel,"user":username,"view-count":viewers,"user-id":userstate["user-id"]});
506 }
507 }
508 }
509 catch(e){
510 console.log("hosts didnt work dummy lul");
511 logError("host error " + e,`host was for channel ${channel}`,'',`Userstate Object ${userstate}`);
512 }
513
514});
515
516twitch.on("raid", function({channel, raider, viewers, userstate}) {
517 try{//raid channel object different?
518 console.log("RAID EVENT", channel, username, viewers, autohost);
519 logError("raid listener","here for userstate dump","","Userstate -"+JSON.stringify(userstate))
520 if(viewers >= channels[channel.substr(1)].hostAmount)
521 createClip(userstate['room-id'],20,{"type":"raid","userstate":userstate,"channel":channel,"user":raider,"view-count":viewers,"user-id":userstate["user-id"]});
522 }
523 catch(e){
524 console.log("raid didnt work dummy lul");
525 logError("raid error " + e,`raid was for channel ${channel}`,'channel object toString here -'+channel.toString(),`Userstate Object ${JSON.stringify(userstate)}`);
526 }
527
528});
529
530twitch.on("chat", function (channel, userstate, message, self) {
531
532 //if(userstate["username"]=="xwater" || userstate["username"]=='navetz')
533 //{
534 //if(message=="!highlight"){
535 //createClip(userstate['room-id'],20,{"type":"chat","userstate":userstate,"channel":channel,"user":userstate['username'],"user-id":userstate['user-id']});
536 //console.log(userstate);
537 //}
538 //}
539 //if bradcaster uses the command
540
541});
542
543twitchmemories.on("chat", function (channel, userstate, message, self) {
544 if(message.toLowerCase() == "!memoriesoff"){
545 sql.query(squel.delete()
546 .from('settings')
547 .where('channel == '+userstate['username']),function(error, results, field){
548 //callback
549 });
550 twitchmemories.action('warpmemories', "WarpMemories will no longer make clips of you channel "+ userstate['username']);
551 }
552});
553
554
555function createClip(roomID,delay=0,metadata){
556 try{
557 var channelName = metadata['channel'].substr(1);
558
559 if (enable_log){
560 console.log("CLIP-METADATA ",metadata);
561 console.log("channel-METADATA ",channels['channel']);
562 }
563
564 if(channels[channelName].isQueue()){
565 channels[channelName].addClipToQueue(metadata);
566 return;
567 }
568 //use user's access token if they want clips created by them (1) otherwise use WarpMemories (0)
569 //save username of token holder in case of token refresh
570 var accessToken = {};
571 //console.log("POSITION01",channels[channelName].ownClip, !channels[channelName].getAccessToken(),channels[channelName].getAccessToken() );
572 if (channels[channelName].ownClip == 1 && channels[channelName].getAccessToken()) {
573 //console.log("CREATING CLIP WITH STREAMER TOKEN");
574 //console.log(channelName);
575 //console.log(channels[channelName].getAccessToken());
576 accessToken['token'] = channels[channelName].getAccessToken();
577 accessToken['channel'] = channelName.toLowerCase();
578 }
579 else{
580 //console.log("CREATING CLIP WITH WARPMEMORIES TOKEN");
581 accessToken['token'] = channels['warpmemories'].getAccessToken();
582 accessToken['channel'] = 'warpmemories';
583 }
584 //building URL to make clip from
585 var options = {
586 url: "https://api.twitch.tv/helix/clips?broadcaster_id="+roomID+"&has_delay=true&scope=clips:edit",
587 headers:{
588 "Authorization":"Bearer "+accessToken['token'],
589 "Scope":"clips:edit" }}
590
591 delay = delay*1000;
592
593 channels[channelName].addClipToQueue(metadata);
594 channels[channelName].activateQueue();
595 //create clip after delay, make records of all queued clips in DB for user
596 }
597 catch(e){
598 console.log(e);
599 logError('createClip',e,'error before entering the timeout part of the function','Metadata: '+metadata)
600 }
601 setTimeout(function(){
602 request.post(options,(err,httpResponse, body)=> {
603 try{
604 if (err) {
605 return console.error('upload failed:', err);
606 }
607 //console.log('Server responded with:', body);
608 if(!(JSON.parse(body)["status"])){
609 var queuedClips = channels[metadata['channel'].substr(1)].getClips();
610 //for each(var data in queuedClips)
611 for(var i=0, len = queuedClips.length; i<len ; i++)
612 {
613 saveClipDB(generateDBMetadata(metadata['type'],queuedClips[i]),JSON.parse(body)['data'][0]['edit_url'].replace("/edit",""))
614 }
615 }
616 else{
617 //if 401 status, refresh token and save it
618 if(JSON.parse(body)["status"] == "401"){
619 logError('createClip',
620 "401 Error making clip for "+ metadata['channel'].substr(1) + " --- response from twitch --- " + body,"clip for "+metadata['channel'],"Metadata: " + JSON.stringify(metadata));
621 logError('createClip API"=',"full response from server","body: "+ body,"http resposnse: "+httpResponse);
622 refreshUser(accessToken['channel'],(result)=>{
623 console.log(result);
624 //callback for refresh
625 });
626 }
627 else{
628 logError('createClip', "Error making clip for "+ metadata['channel'] + " --- response from twitch --- " + body);
629 }
630 }
631 channels[metadata['channel'].substr(1)].resetQueue();
632 }
633 catch(e){
634 console.log(e);
635 channels[metadata['channel'].substr(1)].resetQueue();
636 logError('createClip','e','related to user ' + metadata['channel'], 'metadata -' + metadata);
637 }
638 })
639 },delay);
640}
641
642function saveClipDB(metadata,clip){
643 /*console.log(
644 metadata['channel'].substr(1)+" --- " +
645 metadata['channelID']+" --- " +
646 metadata['viewer']+" --- " +
647 metadata['viewerID']+" --- " +
648 clip +
649 metadata['type']+" --- " +
650 JSON.stringify(metadata['data'])
651 );
652 */
653 var queryString = squel.insert()
654 .into("clips")
655 .set("streamer_name",metadata['channel'].substr(1))
656 .set("streamer_twitch_id",metadata['channelID'])
657 .set("user_twitch_name",metadata['viewer'])
658 .set("user_twitch_id",metadata['viewerID'])
659 .set("url",clip)
660 .set("type",metadata['type'])
661 .set("thumbnail","")
662 .set("data",JSON.stringify(metadata['data']).replace(/\\/g, "\\\\")
663 .replace(/\$/g, "\\$")
664 .replace(/'/g, "\\'")
665 .replace(/"/g, "\\\""))
666 .toString();
667 //console.log(queryString)
668 sql.query(queryString, function(error, results, fields){
669 try{
670 //15 second wait to update thumbnail to give twitch API time to register clip
671 //console.log(error);
672 //console.log(results);
673 setTimeout(function(){
674 saveClipThumbnail(clip);
675 },15000);
676 }
677 catch(e){
678 logError('savecliptodb',e);
679 console.log(e);
680 }
681 });
682}
683//takes genaric metadata from twitch listeners, returns json object with cleaner metadata
684function generateDBMetadata(type, metadata){
685 try{
686
687 if (enable_log){
688 console.log("---position001---")
689 console.log("Type ---" + type);
690 console.log("Metadata ---" + metadata);
691 }
692
693 var result = {'channel':metadata['channel'],'channelID':metadata['userstate']['room-id'],
694 'viewer':metadata['user'],'viewerID':metadata['user-id'],'type':type,data:{}};
695 if(type=='sub'){
696 //include tier, #of months, attached message
697 var subTier = metadata['userstate']['msg-param-sub-plan'];
698 if(subTier == "Prime"){
699 subTier = 1;
700 }
701 else{
702 subTier = subTier/1000;
703 }
704 result['data'] = {"months":metadata['userstate']['msg-param-cumulative-months'],
705 "tier":subTier}
706 }
707 if(type=='raid'){
708 //include number of raiders
709 //need to see userstate for a raiders message
710
711 }
712 if(type=='host'){
713 //include number of host
714 //need to see userstate for a host message
715
716 }
717 if(type=='bits'){
718 //bit message + message
719 //need to use userstate for a bit message
720
721 }
722 if(type=='crowdcontrol'){
723 //TBA
724 }
725 return result;
726 }
727 catch(e){
728 logError('generateDBMetadata','something broke lul',"error message: "+e,"Result variable: "+result);
729 }
730
731
732}
733
734function saveClipThumbnail(clipURL){
735 var thumbnailURL;
736
737 //console.log(clipURL.substr(24))
738 //build URL to get clip information
739 var options = {
740 url: "https://api.twitch.tv/helix/clips?id="+clipURL.substr(24), //substr(24) is to remove the URL and only keep the clip ID
741 headers:{
742 "Authorization":"Bearer "+channels['warpmemories'].getAccessToken()
743 }}
744
745 //getClips request from twitch
746 request.get(options, function optionalCallback(err,httpResponse, body) {
747 try{
748 if (err) {
749 return console.error('Could not get clip', err);
750 }
751 //console.log('Upload successful! Server responded with:', body);
752 if(!err){
753 //console.log
754 thumbnailURL = JSON.parse(body)['data'][0]['thumbnail_url'];
755 var updateString = squel.update()
756 .table("clips")
757 .set("thumbnail",thumbnailURL)
758 .where("url = '"+clipURL+"'");
759 sql.query(updateString.toString(), function(error,results, fields){
760 if(error){
761 console.log("something went wrong with the query? " + error);
762 }
763 });
764 }
765 }
766 catch(e){
767 console.log("Error: ",e);
768 logError('saveClipThumbnail',e);
769 }
770 })
771}
772
773function refreshUser(channelName, callback){
774 var refreshURL = {
775 url: "https://id.twitch.tv/oauth2/token?grant_type=refresh_token&refresh_token="+channels[channelName].getRefreshToken()+"&client_id=sh9x6mp3n1p3auqvxpjrrjdbogk9l1&client_secret=flqp4jt2ybvywsahkeiww3jjsjuiw9"
776 }
777 console.log(refreshURL);
778 console.log(channels[channelName].getRefreshToken());
779 request.post(refreshURL, (err,httpResponse, body)=>{
780 //results
781 var results = JSON.parse(body);
782 console.log("REFRESH TOKEN RESULTS" , results);
783 if(results['access_token']){
784
785 channels[channelName].setRefreshToken(results['refresh_token'], results['access_token']);
786
787 var updateString = squel.update()
788 .table("users")
789 .set("refresh_token",results['refresh_token'])
790 .set("access_token",results['access_token'])
791 .where("name = '"+channelName+"'");
792 sql.query(updateString.toString(), (error,results, fields)=>{
793 if(error){
794 console.log("something went wrong with the query? " + error);
795 }
796 else{
797 return(callback("success"))
798 }
799 });
800 }
801 else{
802 logError('refreshUser','','',"refreshUser response - " + body);
803 return(callback(err));
804 }
805 });
806}
807
808function getTwitchUserID(username,callback){
809 var twitchUserId;
810 var idUrl = {url:"https://api.twitch.tv/helix/users?login="+username,
811 headers:{
812 "Authorization":"Bearer tbfhix87k3k8oae5r3jmlnmvrstx98",
813 "Client-ID":'7jio7lb5zqjvurval0sagt3az9pfdz'
814 }}
815 request.get(idUrl, function optionalCallback(err,httpResponse, body) {
816 console.log('Upload successful! Server responded with:', body);
817 if (JSON.parse(body)['data'][0]['id']){
818 twitchUserId = JSON.parse(body)['data'][0]['id'];
819 console.log("inside the bracket - "+twitchUserId);
820 return(callback(twitchUserId))
821 } else {
822 return false;
823 }
824 });
825 //console.log("Got "+username+"s ID = "+twitchUserId);
826 //return twitchUserId;
827}
828
829
830setTimeout(function(){
831 //console.log(channels);
832 console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(twitch)));
833},5000)
834
835
836
837/*
838sub userstate
839 {"type":"sub","userstate":{"badge-info":"subscriber/13","badges":{"subscriber":"12","bits":"1000"},
840 "color":"#FF0000","display-name":"","emotes":null,"flags":null,"id":"0a-9681ff667071",
841 "login":"wiinch","mod":false,"msg-id":"resub","msg-param-cumulative-months":"13","msg-param-months":false,
842 "msg-param-should-share-streak":true,"msg-param-streak-months":"13",
843 "msg-param-sub-plan-name":"Welcome\\sto\\sthe\\sPool\\sParty.\\s\\sJust\\sdon't\\spoop\\sin\\sit.",
844 "msg-param-sub-plan":"1000","room-id":"22816432","subscriber":true,
845 "system-msg":"Willy1inch\\ssubscribed\\sat\\sTier\\s1.\\sThey've\\ssubscribed\\sfor\\s13\\smonths,\\scurrently\\son\\sa\\s13\\smonth\\sstreak!",
846 "tmi-sent-ts":"1559074761861","user-id":"95193531","user-type":null,"emotes-raw":null,"badges-raw":"subscriber/12,bits/1000",
847 "message-type":"resub"},"channel":"#xwater","user":"Willy1inch","user-id":"95193531"}
848*/