Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

Commit 8233238

Browse files
authored
Merge pull request #252 from LarsVomMars/googleapis
nodecg-io-googleapis - closes #226
2 parents 0fd32e7 + b3ce03d commit 8233238

File tree

13 files changed

+114
-270
lines changed

13 files changed

+114
-270
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { NodeCG } from "nodecg-types/types/server";
2+
import { Result, emptySuccess, success, error, ServiceBundle } from "nodecg-io-core";
3+
import { google, GoogleApis } 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";
6+
import * as express from "express";
7+
import opn = require("open");
8+
9+
interface GoogleApisServiceConfig {
10+
clientID: string;
11+
clientSecret: string;
12+
refreshToken?: string;
13+
scopes?: string | string[];
14+
}
15+
16+
export type GoogleApisServiceClient = GoogleApis;
17+
18+
module.exports = (nodecg: NodeCG) => {
19+
new GoogleApisService(nodecg, "googleapis", __dirname, "../googleapis-schema.json").register();
20+
};
21+
22+
class GoogleApisService extends ServiceBundle<GoogleApisServiceConfig, GoogleApisServiceClient> {
23+
async validateConfig(_config: GoogleApisServiceConfig): Promise<Result<void>> {
24+
return emptySuccess();
25+
}
26+
27+
async createClient(config: GoogleApisServiceConfig): Promise<Result<GoogleApisServiceClient>> {
28+
const auth = new google.auth.OAuth2({
29+
clientId: config.clientID,
30+
clientSecret: config.clientSecret,
31+
redirectUri: "http://localhost:9090/nodecg-io-googleapis/oauth2callback",
32+
});
33+
34+
await this.refreshTokens(config, auth);
35+
36+
const client = new GoogleApis({ auth });
37+
return success(client);
38+
}
39+
40+
stopClient(_client: GoogleApisServiceClient): void {
41+
return;
42+
}
43+
44+
private async initialAuth(config: GoogleApisServiceConfig, auth: OAuth2Client): Promise<Credentials> {
45+
const authURL = auth.generateAuthUrl({
46+
access_type: "offline",
47+
prompt: "consent",
48+
scope: config.scopes,
49+
});
50+
51+
return new Promise((resolve, reject) => {
52+
const router = express.Router();
53+
54+
router.get("/nodecg-io-googleapis/oauth2callback", async (req, res) => {
55+
try {
56+
const response = `<html><head><script>window.close();</script></head><body>Google Api connection successful! You may close this window now.</body></html>`;
57+
res.send(response);
58+
59+
const { tokens } = await auth.getToken(req.query.code as string);
60+
resolve(tokens);
61+
} catch (e) {
62+
reject(error(e));
63+
}
64+
});
65+
66+
this.nodecg.mount(router);
67+
opn(authURL, { wait: false }).then((cp) => cp.unref());
68+
});
69+
}
70+
71+
private async refreshTokens(config: GoogleApisServiceConfig, auth: OAuth2Client) {
72+
if (config.refreshToken) {
73+
this.nodecg.log.info("Re-using saved refresh token.");
74+
auth.setCredentials({ refresh_token: config.refreshToken });
75+
} else {
76+
this.nodecg.log.info("No refresh token found. Starting auth flow to get one ...");
77+
auth.setCredentials(await this.initialAuth(config, auth));
78+
if (auth.credentials.refresh_token) {
79+
config.refreshToken = auth.credentials.refresh_token;
80+
}
81+
}
82+
83+
auth.on("tokens", (tokens) => {
84+
if (tokens.refresh_token) config.refreshToken = tokens.refresh_token;
85+
});
86+
}
87+
}

nodecg-io-gsheets/gsheets-schema.json renamed to nodecg-io-googleapis/googleapis-schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
"refreshToken": {
1515
"type": "string",
1616
"description": "Token that allows the client to refresh access tokens. This is set automatically after first login, you don't need to set it."
17+
},
18+
"scopes": {
19+
"type": "array",
20+
"description": "Scope URLs for all used services."
1721
}
1822
},
1923
"required": ["clientID", "clientSecret"]

nodecg-io-youtube/package.json renamed to nodecg-io-googleapis/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
2-
"name": "nodecg-io-youtube",
2+
"name": "nodecg-io-googleapis",
33
"version": "0.2.0",
4-
"description": "Allows to connect and interact to youtube",
4+
"description": "Allows to connect to and interact with many google-apis",
55
"homepage": "https://nodecg.io/RELEASE/samples/youtube",
66
"author": {
7-
"name": "CodeOverflow team",
8-
"url": "http://codeoverflow.org"
7+
"name": "LarsVomMars",
8+
"url": "https://github.com/LarsVomMars"
99
},
1010
"repository": {
1111
"type": "git",
File renamed without changes.

nodecg-io-gsheets/extension/index.ts

Lines changed: 0 additions & 86 deletions
This file was deleted.

nodecg-io-gsheets/package.json

Lines changed: 0 additions & 50 deletions
This file was deleted.

nodecg-io-youtube/extension/index.ts

Lines changed: 0 additions & 91 deletions
This file was deleted.

nodecg-io-youtube/tsconfig.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

nodecg-io-youtube/youtube-schema.json

Lines changed: 0 additions & 20 deletions
This file was deleted.

samples/gsheets/extension/index.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { NodeCG } from "nodecg-types/types/server";
2-
import { GSheetsServiceClient } from "nodecg-io-gsheets";
2+
import { GoogleApisServiceClient } from "nodecg-io-googleapis";
33
import { requireService } from "nodecg-io-core";
44

55
module.exports = function (nodecg: NodeCG) {
66
nodecg.log.info("Sample bundle for Google Sheets started");
77

8-
const gsheets = requireService<GSheetsServiceClient>(nodecg, "gsheets");
8+
const googleApis = requireService<GoogleApisServiceClient>(nodecg, "googleapis");
99

10-
gsheets?.onAvailable(async (client) => {
10+
googleApis?.onAvailable(async (client) => {
11+
const gsheets = client.sheets("v4");
1112
try {
12-
const data = await client.spreadsheets.values.get(
13+
const data = await gsheets.spreadsheets.values.get(
1314
{
1415
spreadsheetId: "<ID>", //Spreadsheet ID, URL is formatted https://docs.google.de/spreadsheets/d/<ID>/edit
1516
range: "<tableSheetName>", //The sheet name, witch will used to get the data.
@@ -24,5 +25,5 @@ module.exports = function (nodecg: NodeCG) {
2425
}
2526
});
2627

27-
gsheets?.onUnavailable(() => nodecg.log.info("GSheets client has been unset."));
28+
googleApis?.onUnavailable(() => nodecg.log.info("GSheets client has been unset."));
2829
};

0 commit comments

Comments
 (0)