11import { NodeCG } from "nodecg/types/server" ;
22import { Result , emptySuccess , success , error , ServiceBundle } from "nodecg-io-core" ;
33import { google , youtube_v3 } from "googleapis" ;
4+ import type { Credentials } from "google-auth-library/build/src/auth/credentials" ;
5+ import type { OAuth2Client } from "google-auth-library/build/src/auth/oauth2client" ;
46import * as express from "express" ;
57import opn = require( "open" ) ;
68
79interface YoutubeServiceConfig {
810 clientID : string ;
911 clientSecret : string ;
12+ refreshToken ?: string ;
1013}
1114
1215export type YoutubeServiceClient = youtube_v3 . Youtube ;
@@ -26,6 +29,36 @@ class YoutubeService extends ServiceBundle<YoutubeServiceConfig, YoutubeServiceC
2629 clientSecret : config . clientSecret ,
2730 redirectUri : "http://localhost:9090/nodecg-io-youtube/oauth2callback" ,
2831 } ) ;
32+
33+ if ( config . refreshToken ) {
34+ this . nodecg . log . info ( "Re-using saved refresh token." ) ;
35+ auth . setCredentials ( {
36+ refresh_token : config . refreshToken ,
37+ } ) ;
38+ } else {
39+ this . nodecg . log . info ( "No refresh token found. Starting auth flow to get one..." ) ;
40+ auth . setCredentials ( await this . initialAuth ( auth ) ) ;
41+ if ( auth . credentials . refresh_token ) {
42+ config . refreshToken = auth . credentials . refresh_token ;
43+ }
44+ }
45+
46+ // Save refresh tokens so they can be used next time to get a access token again
47+ auth . on ( "tokens" , ( tokens ) => {
48+ if ( tokens . refresh_token ) {
49+ config . refreshToken = tokens . refresh_token ;
50+ }
51+ } ) ;
52+
53+ const client = new youtube_v3 . Youtube ( { auth } ) ;
54+ return success ( client ) ;
55+ }
56+
57+ stopClient ( _client : YoutubeServiceClient ) : void {
58+ // Cannot stop client
59+ }
60+
61+ private initialAuth ( auth : OAuth2Client ) : Promise < Credentials > {
2962 const authUrl = auth . generateAuthUrl ( {
3063 access_type : "offline" ,
3164 scope : "https://www.googleapis.com/auth/youtube" ,
@@ -38,12 +71,14 @@ class YoutubeService extends ServiceBundle<YoutubeServiceConfig, YoutubeServiceC
3871 router . get ( "/nodecg-io-youtube/oauth2callback" , async ( req , res ) => {
3972 try {
4073 const params = req . query ;
41- res . end ( "<script>window.close()</script>" ) ;
74+
75+ const callbackWebsite =
76+ "<html><head><script>window.close();</script></head><body>YouTube connection successful! You may close this window now.</body></html>" ;
77+ res . send ( callbackWebsite ) ;
78+
4279 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4380 const { tokens } = await auth . getToken ( params . code ! . toString ( ) ) ;
44- auth . credentials = tokens ;
45- const client = new youtube_v3 . Youtube ( { auth } ) ;
46- resolve ( success ( client ) ) ;
81+ resolve ( tokens ) ;
4782 } catch ( e ) {
4883 reject ( error ( e ) ) ;
4984 }
@@ -53,8 +88,4 @@ class YoutubeService extends ServiceBundle<YoutubeServiceConfig, YoutubeServiceC
5388 opn ( authUrl , { wait : false } ) . then ( ( cp ) => cp . unref ( ) ) ;
5489 } ) ;
5590 }
56-
57- stopClient ( _client : YoutubeServiceClient ) : void {
58- // Cannot stop client
59- }
6091}
0 commit comments