· 6 years ago · Mar 20, 2020, 10:54 PM
1const request = require('request')
2const {EventEmitter} = require('events')
3const util = require('util');
4var Bottleneck = require("bottleneck/es5");
5
6var fs = require('fs');
7var readline = require('readline');
8const { google } = require('googleapis');
9var OAuth2 = google.auth.OAuth2;
10
11const youtube = google.youtube('v3');
12
13// If modifying these scopes, delete your previously saved credentials
14// at ~/.credentials/youtube-nodejs-quickstart.json
15var SCOPES = ['https://www.googleapis.com/auth/youtube.readonly'];
16var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
17 process.env.USERPROFILE) + '/.credentials/';
18var TOKEN_PATH = TOKEN_DIR + 'youtube-nodejs-quickstart.json';
19
20function authorize(clientId, clientSecret, callback) {
21 var redirectUrl = 'http://localhost:3000/callback'
22 var oauth2Client = new OAuth2(clientId, clientSecret, redirectUrl);
23
24 // Check if we have previously stored a token.
25 fs.readFile(TOKEN_PATH, function(err, token) {
26 if (err) {
27 getNewToken(oauth2Client, callback);
28 } else {
29 oauth2Client.credentials = JSON.parse(token);
30 return callback(oauth2Client);
31 }
32 });
33}
34
35/**
36 * Get and store new token after prompting for user authorization, and then
37 * execute the given callback with the authorized OAuth2 client.
38 *
39 * @param {google.auth.OAuth2} oauth2Client The OAuth2 client to get token for.
40 * @param {getEventsCallback} callback The callback to call with the authorized
41 * client.
42 */
43function getNewToken(oauth2Client, callback) {
44 var authUrl = oauth2Client.generateAuthUrl({
45 access_type: 'offline',
46 scope: SCOPES
47 });
48 console.log('Authorize this app by visiting this url: ', authUrl);
49 var rl = readline.createInterface({
50 input: process.stdin,
51 output: process.stdout
52 });
53 rl.question('Enter the code from that page here: ', function(code) {
54 rl.close();
55 oauth2Client.getToken(code, function(err, token) {
56 if (err) {
57 console.log('Error while trying to retrieve access token', err);
58 return;
59 }
60 oauth2Client.credentials = token;
61 storeToken(token);
62 callback(oauth2Client);
63 });
64 });
65}
66
67/**
68 * Store token to disk be used in later program executions.
69 *
70 * @param {Object} token The token to store to disk.
71 */
72function storeToken(token) {
73 try {
74 fs.mkdirSync(TOKEN_DIR);
75 } catch (err) {
76 if (err.code != 'EEXIST') {
77 throw err;
78 }
79 }
80 fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
81 if (err) throw err;
82 console.log('Token stored to ' + TOKEN_PATH);
83 });
84}
85
86async function findActiveChat (auth){
87 const response = await youtube.liveBroadcasts.list({
88 auth,
89 part: 'snippet',
90 broadcastStatus: 'active'
91 });
92
93 const latestChat = response.data.items[0];
94 const liveChatId = latestChat.snippet.liveChatId;
95 this.chatId;
96};
97
98
99/**
100 * The main hub for acquire live chat with the YouTube Date API.
101 * @extends {EventEmitter}
102 */
103class MyYouTube extends EventEmitter {
104 /**
105 * @param {string} ChannelID ID of the channel to acquire with
106 * @param {string} APIKey You'r API key
107 */
108 constructor(channelId, apiKey) {
109 super()
110 this.id = channelId
111 this.key = apiKey
112
113 authorize(this.id, this.key, findActiveChat)
114 }
115
116 /**
117 * Gets live chat messages.
118 * See {@link https://developers.google.com/youtube/v3/live/docs/liveChatMessages/list#response|docs}
119 * @return {object}
120 */
121 async getChat(auth) {
122 console.log("Getting youtube messages " + new Date().toUTCString());
123 if (!this.chatId) return this.emit('error', 'Chat id is invalid.')
124
125 const response = await youtube.liveChatMessages.list({
126 auth,
127 part: 'snippet',
128 liveChatId: this.chatId
129 });
130 const { data } = response;
131 this.emit('json', data)
132 }
133
134 /**
135 * Gets live chat messages at regular intervals.
136 * @param {number} delay Interval to get live chat messages
137 * @fires YouTube#message
138 */
139 listen(delay) {
140 let lastRead = 0, time = 0;
141
142 const limiter = new Bottleneck({
143 maxConcurrent: 1,
144 minTime: delay
145 });
146
147 this.interval = setInterval(() => limiter.schedule(() => this.getChat()), delay)
148
149 this.on('json', data => {
150 for (const item of data.items) {
151 time = new Date(item.snippet.publishedAt).getTime()
152 if (lastRead < time) {
153 lastRead = time
154 /**
155 * Emitted whenever a new message is recepted.
156 * See {@link https://developers.google.com/youtube/v3/live/docs/liveChatMessages#resource|docs}
157 * @event YouTube#message
158 * @type {object}
159 */
160 this.emit('message', item)
161 }
162 }
163 })
164 }
165
166 /**
167 * Stops getting live chat messages at regular intervals.
168 */
169 stop() {
170 clearInterval(this.interval)
171 }
172}
173
174module.exports = MyYouTube