@anmiles/google-api-wrapper 1.0.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +26 -4
- package/dist/index.js.map +1 -1
- package/dist/lib/api/calendar.d.ts +11 -0
- package/dist/lib/api/calendar.js +30 -0
- package/dist/lib/api/calendar.js.map +1 -0
- package/dist/lib/api/shared.d.ts +19 -0
- package/dist/lib/api/shared.js +22 -0
- package/dist/lib/api/shared.js.map +1 -0
- package/dist/lib/api/youtube.d.ts +9 -0
- package/dist/lib/api/youtube.js +25 -0
- package/dist/lib/api/youtube.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/lib/api/__tests__/apiHelpers.ts +18 -0
- package/src/lib/api/__tests__/calendar.test.ts +116 -0
- package/src/lib/api/__tests__/shared.test.ts +73 -0
- package/src/lib/api/__tests__/youtube.test.ts +99 -0
- package/src/lib/api/calendar.ts +26 -0
- package/src/lib/api/shared.ts +44 -0
- package/src/lib/api/youtube.ts +22 -0
- package/dist/lib/data.d.ts +0 -23
- package/dist/lib/data.js +0 -45
- package/dist/lib/data.js.map +0 -1
- package/src/lib/__tests__/data.test.ts +0 -154
- package/src/lib/data.ts +0 -81
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.1](../../tags/v2.0.1) - 2023-03-12
|
|
9
|
+
### Changed
|
|
10
|
+
- Fixed exported types
|
|
11
|
+
|
|
12
|
+
## [2.0.0](../../tags/v2.0.0) - 2023-03-12
|
|
13
|
+
### Changed
|
|
14
|
+
- Split APIs
|
|
15
|
+
|
|
8
16
|
## [1.0.0](../../tags/v1.0.0) - 2023-03-12
|
|
9
17
|
### Changed
|
|
10
18
|
- First release
|
package/README.md
CHANGED
|
@@ -25,10 +25,10 @@ login("username");
|
|
|
25
25
|
``` js
|
|
26
26
|
/* videos.js */
|
|
27
27
|
|
|
28
|
-
import { getProfiles,
|
|
28
|
+
import { getProfiles, youtube } from '@anmiles/google-api-wrapper';
|
|
29
29
|
|
|
30
30
|
getProfiles().map(async (profile) => {
|
|
31
|
-
const videos = await
|
|
31
|
+
const videos = await youtube.getPlaylistItems(profile, { playlistId : 'LL', part : [ 'snippet' ], maxResults : 50 });
|
|
32
32
|
videos.forEach((video) => console.log(`Downloaded: ${video.snippet?.title}`));
|
|
33
33
|
});
|
|
34
34
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.login = exports.getProfiles = exports.createProfile = exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Object.defineProperty(exports, "getVideos", { enumerable: true, get: function () { return data_1.getVideos; } });
|
|
26
|
+
exports.login = exports.getProfiles = exports.createProfile = exports.youtube = exports.calendar = void 0;
|
|
27
|
+
exports.calendar = __importStar(require("./lib/api/calendar"));
|
|
28
|
+
exports.youtube = __importStar(require("./lib/api/youtube"));
|
|
7
29
|
var profiles_1 = require("./lib/profiles");
|
|
8
30
|
Object.defineProperty(exports, "createProfile", { enumerable: true, get: function () { return profiles_1.createProfile; } });
|
|
9
31
|
Object.defineProperty(exports, "getProfiles", { enumerable: true, get: function () { return profiles_1.getProfiles; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+DAA+C;AAC/C,6DAA6C;AAC7C,2CAA4D;AAAnD,yGAAA,aAAa,OAAA;AAAE,uGAAA,WAAW,OAAA;AACnC,mCAAmC;AAA1B,6FAAA,KAAK,OAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type GoogleApis from 'googleapis';
|
|
2
|
+
export { getAPI, getEvents, setEvent };
|
|
3
|
+
declare const _default: {
|
|
4
|
+
getAPI: typeof getAPI;
|
|
5
|
+
getEvents: typeof getEvents;
|
|
6
|
+
setEvent: typeof setEvent;
|
|
7
|
+
};
|
|
8
|
+
export default _default;
|
|
9
|
+
declare function getAPI(profile: string): Promise<GoogleApis.calendar_v3.Calendar>;
|
|
10
|
+
declare function getEvents(profile: string, args: GoogleApis.calendar_v3.Params$Resource$Events$List): Promise<unknown[]>;
|
|
11
|
+
declare function setEvent(profile: string, eventId: string | undefined, args: GoogleApis.calendar_v3.Params$Resource$Events$Update): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.setEvent = exports.getEvents = exports.getAPI = void 0;
|
|
7
|
+
const googleapis_1 = require("googleapis");
|
|
8
|
+
const auth_1 = require("../auth");
|
|
9
|
+
const shared_1 = require("./shared");
|
|
10
|
+
const calendar_1 = __importDefault(require("./calendar"));
|
|
11
|
+
exports.default = { getAPI, getEvents, setEvent };
|
|
12
|
+
async function getAPI(profile) {
|
|
13
|
+
const googleAuth = await (0, auth_1.getAuth)(profile);
|
|
14
|
+
return googleapis_1.google.calendar({
|
|
15
|
+
version: 'v3',
|
|
16
|
+
auth: googleAuth,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
exports.getAPI = getAPI;
|
|
20
|
+
async function getEvents(profile, args) {
|
|
21
|
+
const api = await calendar_1.default.getAPI(profile);
|
|
22
|
+
return (0, shared_1.getItems)(api.events, args);
|
|
23
|
+
}
|
|
24
|
+
exports.getEvents = getEvents;
|
|
25
|
+
async function setEvent(profile, eventId, args) {
|
|
26
|
+
const api = await calendar_1.default.getAPI(profile);
|
|
27
|
+
api.events.update({ eventId, ...args });
|
|
28
|
+
}
|
|
29
|
+
exports.setEvent = setEvent;
|
|
30
|
+
//# sourceMappingURL=calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.js","sourceRoot":"","sources":["../../../src/lib/api/calendar.ts"],"names":[],"mappings":";;;;;;AAAA,2CAAoC;AAEpC,kCAAkC;AAClC,qCAAoC;AACpC,0DAAkC;AAGlC,kBAAe,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AAE/C,KAAK,UAAU,MAAM,CAAC,OAAe;IACpC,MAAM,UAAU,GAAG,MAAM,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IAE1C,OAAO,mBAAM,CAAC,QAAQ,CAAC;QACtB,OAAO,EAAG,IAAI;QACd,IAAI,EAAM,UAAU;KACpB,CAAC,CAAC;AACJ,CAAC;AAVQ,wBAAM;AAWf,KAAK,UAAU,SAAS,CAAC,OAAe,EAAE,IAAwD;IACjG,MAAM,GAAG,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,IAAA,iBAAQ,EAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAdgB,8BAAS;AAgB1B,KAAK,UAAU,QAAQ,CAAC,OAAe,EAAE,OAA2B,EAAE,IAA0D;IAC/H,MAAM,GAAG,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AACzC,CAAC;AAnB2B,4BAAQ"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type GoogleApis from 'googleapis';
|
|
2
|
+
export { getItems };
|
|
3
|
+
declare const _default: {
|
|
4
|
+
getItems: typeof getItems;
|
|
5
|
+
};
|
|
6
|
+
export default _default;
|
|
7
|
+
type CommonApi<TArgs, TResponse> = {
|
|
8
|
+
list: (params: TArgs & {
|
|
9
|
+
pageToken: string | undefined;
|
|
10
|
+
}, options?: GoogleApis.Common.MethodOptions | undefined) => Promise<GoogleApis.Common.GaxiosResponse<TResponse>>;
|
|
11
|
+
};
|
|
12
|
+
type CommonResponse<TItem> = {
|
|
13
|
+
items?: TItem[];
|
|
14
|
+
pageInfo?: {
|
|
15
|
+
totalResults?: number | null | undefined;
|
|
16
|
+
};
|
|
17
|
+
nextPageToken?: string | null | undefined;
|
|
18
|
+
};
|
|
19
|
+
declare function getItems<TApi extends CommonApi<TArgs, TResponse>, TItem, TArgs, TResponse extends CommonResponse<TItem>>(api: TApi, args: TArgs): Promise<TItem[]>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getItems = void 0;
|
|
4
|
+
const logger_1 = require("../logger");
|
|
5
|
+
const sleep_1 = require("../sleep");
|
|
6
|
+
exports.default = { getItems };
|
|
7
|
+
const requestInterval = 300;
|
|
8
|
+
async function getItems(api, args) {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const items = [];
|
|
11
|
+
let pageToken = undefined;
|
|
12
|
+
do {
|
|
13
|
+
const response = await api.list({ ...args, pageToken });
|
|
14
|
+
(_a = response.data.items) === null || _a === void 0 ? void 0 : _a.forEach((item) => items.push(item));
|
|
15
|
+
(0, logger_1.log)(`Getting items (${items.length} of ${((_b = response.data.pageInfo) === null || _b === void 0 ? void 0 : _b.totalResults) || 'many'})...`);
|
|
16
|
+
pageToken = response.data.nextPageToken;
|
|
17
|
+
await (0, sleep_1.sleep)(requestInterval);
|
|
18
|
+
} while (pageToken);
|
|
19
|
+
return items;
|
|
20
|
+
}
|
|
21
|
+
exports.getItems = getItems;
|
|
22
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/lib/api/shared.ts"],"names":[],"mappings":";;;AACA,sCAAgC;AAChC,oCAAiC;AAGjC,kBAAe,EAAE,QAAQ,EAAE,CAAC;AAiB5B,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,KAAK,UAAU,QAAQ,CAKrB,GAAS,EAAE,IAAW;;IACvB,MAAM,KAAK,GAAY,EAAE,CAAC;IAE1B,IAAI,SAAS,GAA8B,SAAS,CAAC;IAErD,GAAG;QACF,MAAM,QAAQ,GAAgD,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACrG,MAAA,QAAQ,CAAC,IAAI,CAAC,KAAK,0CAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,IAAA,YAAG,EAAC,kBAAkB,KAAK,CAAC,MAAM,OAAO,CAAA,MAAA,QAAQ,CAAC,IAAI,CAAC,QAAQ,0CAAE,YAAY,KAAI,MAAM,MAAM,CAAC,CAAC;QAC/F,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC;QACxC,MAAM,IAAA,aAAK,EAAC,eAAe,CAAC,CAAC;KAC7B,QAAQ,SAAS,EAAE;IAEpB,OAAO,KAAK,CAAC;AACd,CAAC;AAvCQ,4BAAQ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type GoogleApis from 'googleapis';
|
|
2
|
+
export { getAPI, getPlaylistItems };
|
|
3
|
+
declare const _default: {
|
|
4
|
+
getAPI: typeof getAPI;
|
|
5
|
+
getPlaylistItems: typeof getPlaylistItems;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
8
|
+
declare function getAPI(profile: string): Promise<GoogleApis.youtube_v3.Youtube>;
|
|
9
|
+
declare function getPlaylistItems(profile: string, args: GoogleApis.youtube_v3.Params$Resource$Playlistitems$List): Promise<unknown[]>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getPlaylistItems = exports.getAPI = void 0;
|
|
7
|
+
const googleapis_1 = require("googleapis");
|
|
8
|
+
const auth_1 = require("../auth");
|
|
9
|
+
const shared_1 = require("./shared");
|
|
10
|
+
const youtube_1 = __importDefault(require("./youtube"));
|
|
11
|
+
exports.default = { getAPI, getPlaylistItems };
|
|
12
|
+
async function getAPI(profile) {
|
|
13
|
+
const googleAuth = await (0, auth_1.getAuth)(profile);
|
|
14
|
+
return googleapis_1.google.youtube({
|
|
15
|
+
version: 'v3',
|
|
16
|
+
auth: googleAuth,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
exports.getAPI = getAPI;
|
|
20
|
+
async function getPlaylistItems(profile, args) {
|
|
21
|
+
const api = await youtube_1.default.getAPI(profile);
|
|
22
|
+
return (0, shared_1.getItems)(api.playlistItems, args);
|
|
23
|
+
}
|
|
24
|
+
exports.getPlaylistItems = getPlaylistItems;
|
|
25
|
+
//# sourceMappingURL=youtube.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"youtube.js","sourceRoot":"","sources":["../../../src/lib/api/youtube.ts"],"names":[],"mappings":";;;;;;AAAA,2CAAoC;AAEpC,kCAAkC;AAClC,qCAAoC;AACpC,wDAAgC;AAGhC,kBAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;AAE5C,KAAK,UAAU,MAAM,CAAC,OAAe;IACpC,MAAM,UAAU,GAAG,MAAM,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IAE1C,OAAO,mBAAM,CAAC,OAAO,CAAC;QACrB,OAAO,EAAG,IAAI;QACd,IAAI,EAAM,UAAU;KACpB,CAAC,CAAC;AACJ,CAAC;AAVQ,wBAAM;AAYf,KAAK,UAAU,gBAAgB,CAAC,OAAe,EAAE,IAA8D;IAC9G,MAAM,GAAG,GAAG,MAAM,iBAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1C,OAAO,IAAA,iBAAQ,EAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AAfgB,4CAAgB"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const getAPI = <T>(items: Array<Array<T> | null>, pageTokens: Array<string | undefined>) => ({
|
|
2
|
+
list : jest.fn().mockImplementation(async ({ pageToken }: {pageToken?: string}) => {
|
|
3
|
+
const index = pageTokens.indexOf(pageToken);
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
data : {
|
|
7
|
+
items : items[index],
|
|
8
|
+
nextPageToken : pageTokens[index + 1],
|
|
9
|
+
pageInfo : !items[index] ? null : {
|
|
10
|
+
totalResults : items.reduce((sum, list) => sum + (list?.length || 0), 0),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}),
|
|
15
|
+
update : jest.fn(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export default { getAPI };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { google } from 'googleapis';
|
|
3
|
+
import auth from '../../auth';
|
|
4
|
+
import calendar from '../calendar';
|
|
5
|
+
import shared from '../shared';
|
|
6
|
+
import apiHelpers from './apiHelpers';
|
|
7
|
+
|
|
8
|
+
const original = jest.requireActual('../calendar').default as typeof calendar;
|
|
9
|
+
jest.mock<Partial<typeof calendar>>('../calendar', () => ({
|
|
10
|
+
getAPI : jest.fn().mockImplementation(async () => ({ events : api })),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock<Partial<typeof shared>>('../shared', () => ({
|
|
14
|
+
getItems : jest.fn().mockImplementation(async () => events),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
jest.mock<Partial<typeof fs>>('fs', () => ({
|
|
18
|
+
writeFileSync : jest.fn(),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
jest.mock('googleapis', () => ({
|
|
22
|
+
google : {
|
|
23
|
+
calendar : jest.fn().mockImplementation(() => ({ events : api })),
|
|
24
|
+
},
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
jest.mock<Partial<typeof auth>>('../../auth', () => ({
|
|
28
|
+
getAuth : jest.fn().mockImplementation(() => googleAuth),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const profile = 'username';
|
|
32
|
+
|
|
33
|
+
const googleAuth = {
|
|
34
|
+
setCredentials : jest.fn(),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const events: Array<{ summary?: string, source?: { url?: string, title?: string} }> = [
|
|
38
|
+
{ summary : 'event 1', source : { title : 'source 1', url : 'https://example.com' } },
|
|
39
|
+
{ summary : 'event 2', source : { title : 'source 2', url : undefined } },
|
|
40
|
+
{ summary : 'event 3', source : { title : undefined, url : undefined } },
|
|
41
|
+
{ summary : 'event 4', source : undefined },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const eventsResponse = [
|
|
45
|
+
[ events[0], events[1] ],
|
|
46
|
+
null,
|
|
47
|
+
[ events[2], events[3] ],
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const pageTokens = [
|
|
51
|
+
undefined,
|
|
52
|
+
'token1',
|
|
53
|
+
'token2',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const api = apiHelpers.getAPI(eventsResponse, pageTokens);
|
|
57
|
+
const args = { timeMin : '2010-01-01T00:00:00', timeMax : '2019-12-31T23:59:59' };
|
|
58
|
+
|
|
59
|
+
describe('src/lib/api/calendar', () => {
|
|
60
|
+
describe('getAPI', () => {
|
|
61
|
+
it('should call getAuth', async () => {
|
|
62
|
+
await original.getAPI(profile);
|
|
63
|
+
|
|
64
|
+
expect(auth.getAuth).toBeCalledWith(profile);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should get calendar api', async () => {
|
|
68
|
+
await original.getAPI(profile);
|
|
69
|
+
|
|
70
|
+
expect(google.calendar).toBeCalledWith({ version : 'v3', auth : googleAuth });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should return calendar api', async () => {
|
|
74
|
+
const result = await original.getAPI(profile);
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual({ events : api });
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('getEvents', () => {
|
|
81
|
+
it('should get api', async () => {
|
|
82
|
+
await original.getEvents(profile, args);
|
|
83
|
+
|
|
84
|
+
expect(calendar.getAPI).toBeCalledWith(profile);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should get items', async () => {
|
|
88
|
+
await original.getEvents(profile, args);
|
|
89
|
+
|
|
90
|
+
expect(shared.getItems).toBeCalledWith(api, args);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return events', async () => {
|
|
94
|
+
const result = await original.getEvents(profile, args);
|
|
95
|
+
|
|
96
|
+
expect(result).toEqual(events);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('setEvent', () => {
|
|
101
|
+
const eventId = 'eventId';
|
|
102
|
+
const updateArgs = { requestBody : { summary : 'summary' } };
|
|
103
|
+
|
|
104
|
+
it('should get api', async () => {
|
|
105
|
+
await original.setEvent(profile, eventId, updateArgs);
|
|
106
|
+
|
|
107
|
+
expect(calendar.getAPI).toBeCalledWith(profile);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should set items', async () => {
|
|
111
|
+
await original.setEvent(profile, eventId, updateArgs);
|
|
112
|
+
|
|
113
|
+
expect(api.update).toBeCalledWith({ eventId, ...updateArgs });
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import logger from '../../logger';
|
|
2
|
+
import sleep from '../../sleep';
|
|
3
|
+
import shared from '../shared';
|
|
4
|
+
import apiHelpers from './apiHelpers';
|
|
5
|
+
|
|
6
|
+
const original = jest.requireActual('../shared').default as typeof shared;
|
|
7
|
+
jest.mock<Partial<typeof shared>>('../shared', () => ({
|
|
8
|
+
getItems : jest.fn().mockImplementation(async () => items),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
jest.mock<Partial<typeof logger>>('../../logger', () => ({
|
|
12
|
+
log : jest.fn(),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
jest.mock<Partial<typeof sleep>>('../../sleep', () => ({
|
|
16
|
+
sleep : jest.fn(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const items: Array<{ data: string}> = [
|
|
20
|
+
{ data : 'first' },
|
|
21
|
+
{ data : 'second' },
|
|
22
|
+
{ data : 'third' },
|
|
23
|
+
{ data : 'forth' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const response = [
|
|
27
|
+
[ items[0], items[1] ],
|
|
28
|
+
null,
|
|
29
|
+
[ items[2], items[3] ],
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const pageTokens = [
|
|
33
|
+
undefined,
|
|
34
|
+
'token1',
|
|
35
|
+
'token2',
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const api = apiHelpers.getAPI(response, pageTokens);
|
|
39
|
+
const args = { key : 'value' };
|
|
40
|
+
|
|
41
|
+
describe('src/lib/api/shared', () => {
|
|
42
|
+
describe('getItems', () => {
|
|
43
|
+
it('should call API list method for each page', async () => {
|
|
44
|
+
await original.getItems(api, args);
|
|
45
|
+
|
|
46
|
+
pageTokens.forEach((pageToken) => {
|
|
47
|
+
expect(api.list).toBeCalledWith({ ...args, pageToken });
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should output progress', async () => {
|
|
52
|
+
await original.getItems(api, args);
|
|
53
|
+
|
|
54
|
+
expect(logger.log).toBeCalledTimes(response.length);
|
|
55
|
+
expect(logger.log).toBeCalledWith('Getting items (2 of 4)...');
|
|
56
|
+
expect(logger.log).toBeCalledWith('Getting items (2 of many)...');
|
|
57
|
+
expect(logger.log).toBeCalledWith('Getting items (4 of 4)...');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should sleep after reach request', async () => {
|
|
61
|
+
await original.getItems(api, args);
|
|
62
|
+
|
|
63
|
+
expect(sleep.sleep).toBeCalledTimes(response.length);
|
|
64
|
+
expect(sleep.sleep).toBeCalledWith(300);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should return items data', async () => {
|
|
68
|
+
const items = await original.getItems(api, args);
|
|
69
|
+
|
|
70
|
+
expect(items).toEqual(items);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { google } from 'googleapis';
|
|
3
|
+
import auth from '../../auth';
|
|
4
|
+
import youtube from '../youtube';
|
|
5
|
+
import shared from '../shared';
|
|
6
|
+
import apiHelpers from './apiHelpers';
|
|
7
|
+
|
|
8
|
+
const original = jest.requireActual('../youtube').default as typeof youtube;
|
|
9
|
+
jest.mock<Partial<typeof youtube>>('../youtube', () => ({
|
|
10
|
+
getAPI : jest.fn().mockImplementation(async () => ({ playlistItems : api })),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock<Partial<typeof shared>>('../shared', () => ({
|
|
14
|
+
getItems : jest.fn().mockImplementation(async () => playlistItems),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
jest.mock<Partial<typeof fs>>('fs', () => ({
|
|
18
|
+
writeFileSync : jest.fn(),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
jest.mock('googleapis', () => ({
|
|
22
|
+
google : {
|
|
23
|
+
youtube : jest.fn().mockImplementation(() => ({ playlistItems : api })),
|
|
24
|
+
},
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
jest.mock<Partial<typeof auth>>('../../auth', () => ({
|
|
28
|
+
getAuth : jest.fn().mockImplementation(() => googleAuth),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const profile = 'username';
|
|
32
|
+
|
|
33
|
+
const googleAuth = {
|
|
34
|
+
setCredentials : jest.fn(),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const playlistItems: Array<{ snippet?: { title?: string, resourceId?: { videoId?: string } } }> = [
|
|
38
|
+
{ snippet : { title : 'video1', resourceId : { videoId : 'video1Id' } } },
|
|
39
|
+
{ snippet : { title : 'video2', resourceId : { videoId : undefined } } },
|
|
40
|
+
{ snippet : { title : undefined, resourceId : undefined } },
|
|
41
|
+
{ snippet : undefined },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const playlistItemsResponse = [
|
|
45
|
+
[ playlistItems[0], playlistItems[1] ],
|
|
46
|
+
null,
|
|
47
|
+
[ playlistItems[2], playlistItems[3] ],
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const pageTokens = [
|
|
51
|
+
undefined,
|
|
52
|
+
'token1',
|
|
53
|
+
'token2',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const api = apiHelpers.getAPI(playlistItemsResponse, pageTokens);
|
|
57
|
+
const args = { playlistId : 'LL', part : [ 'snippet' ], maxResults : 50 };
|
|
58
|
+
|
|
59
|
+
describe('src/lib/api/youtube', () => {
|
|
60
|
+
describe('getAPI', () => {
|
|
61
|
+
it('should call getAuth', async () => {
|
|
62
|
+
await original.getAPI(profile);
|
|
63
|
+
|
|
64
|
+
expect(auth.getAuth).toBeCalledWith(profile);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should get youtube api', async () => {
|
|
68
|
+
await original.getAPI(profile);
|
|
69
|
+
|
|
70
|
+
expect(google.youtube).toBeCalledWith({ version : 'v3', auth : googleAuth });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should return youtube api', async () => {
|
|
74
|
+
const result = await original.getAPI(profile);
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual({ playlistItems : api });
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('getPlaylistItems', () => {
|
|
81
|
+
it('should get api', async () => {
|
|
82
|
+
await original.getPlaylistItems(profile, args);
|
|
83
|
+
|
|
84
|
+
expect(youtube.getAPI).toBeCalledWith(profile);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should call getItems', async () => {
|
|
88
|
+
await original.getPlaylistItems(profile, args);
|
|
89
|
+
|
|
90
|
+
expect(shared.getItems).toBeCalledWith(api, args);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return videos', async () => {
|
|
94
|
+
const result = await original.getPlaylistItems(profile, args);
|
|
95
|
+
|
|
96
|
+
expect(result).toEqual(playlistItems);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { google } from 'googleapis';
|
|
2
|
+
import type GoogleApis from 'googleapis';
|
|
3
|
+
import { getAuth } from '../auth';
|
|
4
|
+
import { getItems } from './shared';
|
|
5
|
+
import calendar from './calendar';
|
|
6
|
+
|
|
7
|
+
export { getAPI, getEvents, setEvent };
|
|
8
|
+
export default { getAPI, getEvents, setEvent };
|
|
9
|
+
|
|
10
|
+
async function getAPI(profile: string): Promise<GoogleApis.calendar_v3.Calendar> {
|
|
11
|
+
const googleAuth = await getAuth(profile);
|
|
12
|
+
|
|
13
|
+
return google.calendar({
|
|
14
|
+
version : 'v3',
|
|
15
|
+
auth : googleAuth,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function getEvents(profile: string, args: GoogleApis.calendar_v3.Params$Resource$Events$List) {
|
|
19
|
+
const api = await calendar.getAPI(profile);
|
|
20
|
+
return getItems(api.events, args);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function setEvent(profile: string, eventId: string | undefined, args: GoogleApis.calendar_v3.Params$Resource$Events$Update) {
|
|
24
|
+
const api = await calendar.getAPI(profile);
|
|
25
|
+
api.events.update({ eventId, ...args });
|
|
26
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type GoogleApis from 'googleapis';
|
|
2
|
+
import { log } from '../logger';
|
|
3
|
+
import { sleep } from '../sleep';
|
|
4
|
+
|
|
5
|
+
export { getItems };
|
|
6
|
+
export default { getItems };
|
|
7
|
+
|
|
8
|
+
type CommonApi<TArgs, TResponse> = {
|
|
9
|
+
list: (
|
|
10
|
+
params: TArgs & {pageToken: string | undefined},
|
|
11
|
+
options?: GoogleApis.Common.MethodOptions | undefined
|
|
12
|
+
) => Promise<GoogleApis.Common.GaxiosResponse<TResponse>>
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type CommonResponse<TItem> = {
|
|
16
|
+
items?: TItem[],
|
|
17
|
+
pageInfo?: {
|
|
18
|
+
totalResults?: number | null | undefined
|
|
19
|
+
},
|
|
20
|
+
nextPageToken?: string | null | undefined
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const requestInterval = 300;
|
|
24
|
+
|
|
25
|
+
async function getItems<
|
|
26
|
+
TApi extends CommonApi<TArgs, TResponse>,
|
|
27
|
+
TItem,
|
|
28
|
+
TArgs,
|
|
29
|
+
TResponse extends CommonResponse<TItem>
|
|
30
|
+
>(api: TApi, args: TArgs): Promise<TItem[]> {
|
|
31
|
+
const items: TItem[] = [];
|
|
32
|
+
|
|
33
|
+
let pageToken: string | null | undefined = undefined;
|
|
34
|
+
|
|
35
|
+
do {
|
|
36
|
+
const response: GoogleApis.Common.GaxiosResponse<TResponse> = await api.list({ ...args, pageToken });
|
|
37
|
+
response.data.items?.forEach((item) => items.push(item));
|
|
38
|
+
log(`Getting items (${items.length} of ${response.data.pageInfo?.totalResults || 'many'})...`);
|
|
39
|
+
pageToken = response.data.nextPageToken;
|
|
40
|
+
await sleep(requestInterval);
|
|
41
|
+
} while (pageToken);
|
|
42
|
+
|
|
43
|
+
return items;
|
|
44
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { google } from 'googleapis';
|
|
2
|
+
import type GoogleApis from 'googleapis';
|
|
3
|
+
import { getAuth } from '../auth';
|
|
4
|
+
import { getItems } from './shared';
|
|
5
|
+
import youtube from './youtube';
|
|
6
|
+
|
|
7
|
+
export { getAPI, getPlaylistItems };
|
|
8
|
+
export default { getAPI, getPlaylistItems };
|
|
9
|
+
|
|
10
|
+
async function getAPI(profile: string): Promise<GoogleApis.youtube_v3.Youtube> {
|
|
11
|
+
const googleAuth = await getAuth(profile);
|
|
12
|
+
|
|
13
|
+
return google.youtube({
|
|
14
|
+
version : 'v3',
|
|
15
|
+
auth : googleAuth,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function getPlaylistItems(profile: string, args: GoogleApis.youtube_v3.Params$Resource$Playlistitems$List) {
|
|
20
|
+
const api = await youtube.getAPI(profile);
|
|
21
|
+
return getItems(api.playlistItems, args);
|
|
22
|
+
}
|
package/dist/lib/data.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type GoogleApis from 'googleapis';
|
|
2
|
-
export { getEvents, getVideos };
|
|
3
|
-
declare const _default: {
|
|
4
|
-
getData: typeof getData;
|
|
5
|
-
getEvents: typeof getEvents;
|
|
6
|
-
getVideos: typeof getVideos;
|
|
7
|
-
};
|
|
8
|
-
export default _default;
|
|
9
|
-
type CommonApi<TArgs, TResponse> = {
|
|
10
|
-
list: (params: TArgs & {
|
|
11
|
-
pageToken: string | undefined;
|
|
12
|
-
}, options?: GoogleApis.Common.MethodOptions | undefined) => Promise<GoogleApis.Common.GaxiosResponse<TResponse>>;
|
|
13
|
-
};
|
|
14
|
-
type CommonResponse<TItem> = {
|
|
15
|
-
items?: TItem[];
|
|
16
|
-
pageInfo?: {
|
|
17
|
-
totalResults?: number | null | undefined;
|
|
18
|
-
};
|
|
19
|
-
nextPageToken?: string | null | undefined;
|
|
20
|
-
};
|
|
21
|
-
declare function getData<TApi extends CommonApi<TArgs, TResponse>, TItem, TArgs, TResponse extends CommonResponse<TItem>>(api: TApi, args: TArgs): Promise<TItem[]>;
|
|
22
|
-
declare function getEvents(profile: string, args: GoogleApis.calendar_v3.Params$Resource$Events$List): Promise<GoogleApis.calendar_v3.Schema$Event[]>;
|
|
23
|
-
declare function getVideos(profile: string, args: GoogleApis.youtube_v3.Params$Resource$Playlistitems$List): Promise<GoogleApis.youtube_v3.Schema$PlaylistItem[]>;
|
package/dist/lib/data.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getVideos = exports.getEvents = void 0;
|
|
7
|
-
const googleapis_1 = require("googleapis");
|
|
8
|
-
const auth_1 = require("./auth");
|
|
9
|
-
const data_1 = __importDefault(require("./data"));
|
|
10
|
-
const logger_1 = require("./logger");
|
|
11
|
-
const sleep_1 = require("./sleep");
|
|
12
|
-
exports.default = { getData, getEvents, getVideos };
|
|
13
|
-
const requestInterval = 300;
|
|
14
|
-
async function getData(api, args) {
|
|
15
|
-
var _a, _b;
|
|
16
|
-
const items = [];
|
|
17
|
-
let pageToken = undefined;
|
|
18
|
-
do {
|
|
19
|
-
const response = await api.list({ ...args, pageToken });
|
|
20
|
-
(_a = response.data.items) === null || _a === void 0 ? void 0 : _a.forEach((item) => items.push(item));
|
|
21
|
-
(0, logger_1.log)(`Getting items (${items.length} of ${((_b = response.data.pageInfo) === null || _b === void 0 ? void 0 : _b.totalResults) || 'many'})...`);
|
|
22
|
-
pageToken = response.data.nextPageToken;
|
|
23
|
-
await (0, sleep_1.sleep)(requestInterval);
|
|
24
|
-
} while (pageToken);
|
|
25
|
-
return items;
|
|
26
|
-
}
|
|
27
|
-
async function getEvents(profile, args) {
|
|
28
|
-
const googleAuth = await (0, auth_1.getAuth)(profile);
|
|
29
|
-
const { events } = googleapis_1.google.calendar({
|
|
30
|
-
version: 'v3',
|
|
31
|
-
auth: googleAuth,
|
|
32
|
-
});
|
|
33
|
-
return data_1.default.getData(events, args);
|
|
34
|
-
}
|
|
35
|
-
exports.getEvents = getEvents;
|
|
36
|
-
async function getVideos(profile, args) {
|
|
37
|
-
const googleAuth = await (0, auth_1.getAuth)(profile);
|
|
38
|
-
const { playlistItems } = googleapis_1.google.youtube({
|
|
39
|
-
version: 'v3',
|
|
40
|
-
auth: googleAuth,
|
|
41
|
-
});
|
|
42
|
-
return data_1.default.getData(playlistItems, args);
|
|
43
|
-
}
|
|
44
|
-
exports.getVideos = getVideos;
|
|
45
|
-
//# sourceMappingURL=data.js.map
|
package/dist/lib/data.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/lib/data.ts"],"names":[],"mappings":";;;;;;AAAA,2CAAoC;AAEpC,iCAAiC;AACjC,kDAA0B;AAC1B,qCAA+B;AAC/B,mCAAgC;AAGhC,kBAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAiBjD,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,KAAK,UAAU,OAAO,CAKpB,GAAS,EAAE,IAAW;;IACvB,MAAM,KAAK,GAAY,EAAE,CAAC;IAE1B,IAAI,SAAS,GAA8B,SAAS,CAAC;IAErD,GAAG;QACF,MAAM,QAAQ,GAAgD,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACrG,MAAA,QAAQ,CAAC,IAAI,CAAC,KAAK,0CAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,IAAA,YAAG,EAAC,kBAAkB,KAAK,CAAC,MAAM,OAAO,CAAA,MAAA,QAAQ,CAAC,IAAI,CAAC,QAAQ,0CAAE,YAAY,KAAI,MAAM,MAAM,CAAC,CAAC;QAC/F,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC;QAExC,MAAM,IAAA,aAAK,EAAC,eAAe,CAAC,CAAC;KAC7B,QAAQ,SAAS,EAAE;IAEpB,OAAO,KAAK,CAAC;AACd,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,OAAe,EAAE,IAAwD;IACjG,MAAM,UAAU,GAAG,MAAM,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IAE1C,MAAM,EAAE,MAAM,EAAE,GAAG,mBAAM,CAAC,QAAQ,CAAC;QAClC,OAAO,EAAG,IAAI;QACd,IAAI,EAAM,UAAU;KACpB,CAAC,CAAC;IAEH,OAAO,cAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACnC,CAAC;AAnDQ,8BAAS;AAqDlB,KAAK,UAAU,SAAS,CAAC,OAAe,EAAE,IAA8D;IACvG,MAAM,UAAU,GAAG,MAAM,IAAA,cAAO,EAAC,OAAO,CAAC,CAAC;IAE1C,MAAM,EAAE,aAAa,EAAE,GAAG,mBAAM,CAAC,OAAO,CAAC;QACxC,OAAO,EAAG,IAAI;QACd,IAAI,EAAM,UAAU;KACpB,CAAC,CAAC;IAEH,OAAO,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AA9DmB,8BAAS"}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import auth from '../auth';
|
|
3
|
-
import data from '../data';
|
|
4
|
-
import logger from '../logger';
|
|
5
|
-
import sleep from '../sleep';
|
|
6
|
-
|
|
7
|
-
const original = jest.requireActual('../data').default as typeof data;
|
|
8
|
-
jest.mock<Partial<typeof data>>('../data', () => ({
|
|
9
|
-
getItems : jest.fn().mockImplementation(async () => videosList),
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
jest.mock<Partial<typeof fs>>('fs', () => ({
|
|
13
|
-
writeFileSync : jest.fn(),
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
jest.mock('googleapis', () => ({
|
|
17
|
-
google : {
|
|
18
|
-
calendar : jest.fn().mockImplementation(() => ({ events : eventsAPI })),
|
|
19
|
-
youtube : jest.fn().mockImplementation(() => ({ playlistItems : videosAPI })),
|
|
20
|
-
},
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
jest.mock<Partial<typeof auth>>('../auth', () => ({
|
|
24
|
-
getAuth : jest.fn().mockImplementation(() => googleAuth),
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
jest.mock<Partial<typeof logger>>('../logger', () => ({
|
|
28
|
-
log : jest.fn(),
|
|
29
|
-
}));
|
|
30
|
-
|
|
31
|
-
jest.mock<Partial<typeof sleep>>('../sleep', () => ({
|
|
32
|
-
sleep : jest.fn(),
|
|
33
|
-
}));
|
|
34
|
-
|
|
35
|
-
const profile = 'username';
|
|
36
|
-
|
|
37
|
-
const googleAuth = {
|
|
38
|
-
setCredentials : jest.fn(),
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const videosList: Array<{ snippet?: { title?: string, resourceId?: { videoId?: string } } }> = [
|
|
42
|
-
{ snippet : { title : 'video1', resourceId : { videoId : 'video1Id' } } },
|
|
43
|
-
{ snippet : { title : 'video2', resourceId : { videoId : undefined } } },
|
|
44
|
-
{ snippet : { title : undefined, resourceId : undefined } },
|
|
45
|
-
{ snippet : undefined },
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
const videos = [
|
|
49
|
-
[ videosList[0], videosList[1] ],
|
|
50
|
-
null,
|
|
51
|
-
[ videosList[2], videosList[3] ],
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
const eventsList: Array<{ snippet?: { title?: string, resourceId?: { videoId?: string } } }> = [
|
|
55
|
-
{ snippet : { title : 'video1', resourceId : { videoId : 'video1Id' } } },
|
|
56
|
-
{ snippet : { title : 'video2', resourceId : { videoId : undefined } } },
|
|
57
|
-
{ snippet : { title : undefined, resourceId : undefined } },
|
|
58
|
-
{ snippet : undefined },
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
const events = [
|
|
62
|
-
[ eventsList[0], eventsList[1] ],
|
|
63
|
-
null,
|
|
64
|
-
[ eventsList[2], eventsList[3] ],
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
const pageTokens = [
|
|
68
|
-
undefined,
|
|
69
|
-
'token1',
|
|
70
|
-
'token2',
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
const getAPI = <T>(items: Array<Array<T> | null>) => ({
|
|
74
|
-
list : jest.fn().mockImplementation(async ({ pageToken }: {pageToken?: string}) => {
|
|
75
|
-
const index = pageTokens.indexOf(pageToken);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
data : {
|
|
79
|
-
items : items[index],
|
|
80
|
-
nextPageToken : pageTokens[index + 1],
|
|
81
|
-
pageInfo : !items[index] ? null : {
|
|
82
|
-
totalResults : items.reduce((sum, list) => sum + (list?.length || 0), 0),
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
}),
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const eventsAPI = getAPI(events);
|
|
90
|
-
const videosAPI = getAPI(videos);
|
|
91
|
-
|
|
92
|
-
const args = { playlistId : 'LL', part : [ 'snippet' ], maxResults : 50 };
|
|
93
|
-
|
|
94
|
-
describe('src/lib/data', () => {
|
|
95
|
-
describe('getItems', () => {
|
|
96
|
-
it('should call API list method for each page', async () => {
|
|
97
|
-
await original.getItems(videosAPI, args);
|
|
98
|
-
|
|
99
|
-
pageTokens.forEach((pageToken) => {
|
|
100
|
-
expect(videosAPI.list).toBeCalledWith({ ...args, pageToken });
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should output progress', async () => {
|
|
105
|
-
await original.getItems(videosAPI, args);
|
|
106
|
-
|
|
107
|
-
expect(logger.log).toBeCalledTimes(videos.length);
|
|
108
|
-
expect(logger.log).toBeCalledWith('Getting items (2 of 4)...');
|
|
109
|
-
expect(logger.log).toBeCalledWith('Getting items (2 of many)...');
|
|
110
|
-
expect(logger.log).toBeCalledWith('Getting items (4 of 4)...');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('should sleep after reach request', async () => {
|
|
114
|
-
await original.getItems(videosAPI, args);
|
|
115
|
-
|
|
116
|
-
expect(sleep.sleep).toBeCalledTimes(videos.length);
|
|
117
|
-
expect(sleep.sleep).toBeCalledWith(300);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('should return items data', async () => {
|
|
121
|
-
const items = await original.getItems(videosAPI, args);
|
|
122
|
-
|
|
123
|
-
expect(items).toEqual(videosList);
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe('getEvents', () => {
|
|
128
|
-
it('should call getItems', async () => {
|
|
129
|
-
await original.getEvents(profile, args);
|
|
130
|
-
|
|
131
|
-
expect(data.getItems).toBeCalledWith(eventsAPI, args);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should return events', async () => {
|
|
135
|
-
const events = await original.getEvents(profile, args);
|
|
136
|
-
|
|
137
|
-
expect(events).toEqual(eventsList);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe('getVideos', () => {
|
|
142
|
-
it('should call getItems', async () => {
|
|
143
|
-
await original.getVideos(profile, args);
|
|
144
|
-
|
|
145
|
-
expect(data.getItems).toBeCalledWith(videosAPI, args);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('should return videos', async () => {
|
|
149
|
-
const videos = await original.getVideos(profile, args);
|
|
150
|
-
|
|
151
|
-
expect(videos).toEqual(videosList);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
});
|
package/src/lib/data.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { google } from 'googleapis';
|
|
2
|
-
import type GoogleApis from 'googleapis';
|
|
3
|
-
import { getAuth } from './auth';
|
|
4
|
-
import data from './data';
|
|
5
|
-
import { log } from './logger';
|
|
6
|
-
import { sleep } from './sleep';
|
|
7
|
-
|
|
8
|
-
export { getItems, getCalendarAPI, getYoutubeAPI, getEvents, getVideos, setEvent };
|
|
9
|
-
export default { getItems, getCalendarAPI, getYoutubeAPI, getEvents, getVideos, setEvent };
|
|
10
|
-
|
|
11
|
-
type CommonApi<TArgs, TResponse> = {
|
|
12
|
-
list: (
|
|
13
|
-
params: TArgs & {pageToken: string | undefined},
|
|
14
|
-
options?: GoogleApis.Common.MethodOptions | undefined
|
|
15
|
-
) => Promise<GoogleApis.Common.GaxiosResponse<TResponse>>
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
type CommonResponse<TItem> = {
|
|
19
|
-
items?: TItem[],
|
|
20
|
-
pageInfo?: {
|
|
21
|
-
totalResults?: number | null | undefined
|
|
22
|
-
},
|
|
23
|
-
nextPageToken?: string | null | undefined
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const requestInterval = 300;
|
|
27
|
-
|
|
28
|
-
async function getItems<
|
|
29
|
-
TApi extends CommonApi<TArgs, TResponse>,
|
|
30
|
-
TItem,
|
|
31
|
-
TArgs,
|
|
32
|
-
TResponse extends CommonResponse<TItem>
|
|
33
|
-
>(api: TApi, args: TArgs): Promise<TItem[]> {
|
|
34
|
-
const items: TItem[] = [];
|
|
35
|
-
|
|
36
|
-
let pageToken: string | null | undefined = undefined;
|
|
37
|
-
|
|
38
|
-
do {
|
|
39
|
-
const response: GoogleApis.Common.GaxiosResponse<TResponse> = await api.list({ ...args, pageToken });
|
|
40
|
-
response.data.items?.forEach((item) => items.push(item));
|
|
41
|
-
log(`Getting items (${items.length} of ${response.data.pageInfo?.totalResults || 'many'})...`);
|
|
42
|
-
pageToken = response.data.nextPageToken;
|
|
43
|
-
|
|
44
|
-
await sleep(requestInterval);
|
|
45
|
-
} while (pageToken);
|
|
46
|
-
|
|
47
|
-
return items;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function getCalendarAPI(profile: string): Promise<GoogleApis.calendar_v3.Calendar> {
|
|
51
|
-
const googleAuth = await getAuth(profile);
|
|
52
|
-
|
|
53
|
-
return google.calendar({
|
|
54
|
-
version : 'v3',
|
|
55
|
-
auth : googleAuth,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function getYoutubeAPI(profile: string): Promise<GoogleApis.youtube_v3.Youtube> {
|
|
60
|
-
const googleAuth = await getAuth(profile);
|
|
61
|
-
|
|
62
|
-
return google.youtube({
|
|
63
|
-
version : 'v3',
|
|
64
|
-
auth : googleAuth,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function getEvents(profile: string, args: GoogleApis.calendar_v3.Params$Resource$Events$List) {
|
|
69
|
-
const api = await data.getCalendarAPI(profile);
|
|
70
|
-
return getItems(api.events, args);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async function getVideos(profile: string, args: GoogleApis.youtube_v3.Params$Resource$Playlistitems$List) {
|
|
74
|
-
const api = await data.getYoutubeAPI(profile);
|
|
75
|
-
return getItems(api.playlistItems, args);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function setEvent(profile: string, eventId: string | undefined, args: GoogleApis.calendar_v3.Params$Resource$Events$Update) {
|
|
79
|
-
const api = await data.getCalendarAPI(profile);
|
|
80
|
-
api.events.update({ eventId, ...args });
|
|
81
|
-
}
|