youtubei 1.3.7 → 1.4.0
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/dist/cjs/common/shared/HTTP/HTTP.js +18 -7
- package/dist/cjs/youtube/BaseVideo/BaseVideoParser.js +7 -2
- package/dist/cjs/youtube/BaseVideo/VideoCaptions.js +81 -0
- package/dist/cjs/youtube/BaseVideo/index.js +1 -0
- package/dist/cjs/youtube/Caption/Caption.js +17 -0
- package/dist/cjs/youtube/Caption/CaptionLanguage.js +17 -0
- package/dist/cjs/youtube/{Transcript/proto → Caption}/index.js +2 -1
- package/dist/cjs/youtube/Client/Client.js +9 -13
- package/dist/cjs/youtube/Comment/CommentParser.js +11 -12
- package/dist/cjs/youtube/LiveVideo/LiveVideo.js +15 -15
- package/dist/cjs/youtube/Video/Video.js +4 -6
- package/dist/cjs/youtube/Video/VideoParser.js +3 -3
- package/dist/cjs/youtube/VideoCompact/VideoCompact.js +2 -2
- package/dist/cjs/youtube/VideoCompact/VideoCompactParser.js +4 -2
- package/dist/cjs/youtube/index.js +0 -1
- package/dist/esm/common/shared/HTTP/HTTP.js +59 -12
- package/dist/esm/youtube/BaseVideo/BaseVideoParser.js +7 -2
- package/dist/esm/youtube/BaseVideo/VideoCaptions.js +133 -0
- package/dist/esm/youtube/BaseVideo/index.js +1 -0
- package/dist/esm/youtube/Caption/Caption.js +19 -0
- package/dist/esm/youtube/Caption/CaptionLanguage.js +15 -0
- package/dist/esm/youtube/Caption/index.js +2 -0
- package/dist/esm/youtube/Client/Client.js +13 -18
- package/dist/esm/youtube/Comment/CommentParser.js +11 -12
- package/dist/esm/youtube/LiveVideo/LiveVideo.js +15 -15
- package/dist/esm/youtube/Video/Video.js +5 -7
- package/dist/esm/youtube/Video/VideoParser.js +4 -4
- package/dist/esm/youtube/VideoCompact/VideoCompact.js +2 -2
- package/dist/esm/youtube/VideoCompact/VideoCompactParser.js +4 -2
- package/dist/esm/youtube/index.js +0 -1
- package/dist/typings/common/shared/HTTP/HTTP.d.ts +2 -2
- package/dist/typings/youtube/BaseVideo/BaseVideo.d.ts +3 -0
- package/dist/typings/youtube/BaseVideo/VideoCaptions.d.ts +40 -0
- package/dist/typings/youtube/BaseVideo/index.d.ts +1 -0
- package/dist/typings/youtube/Caption/Caption.d.ts +22 -0
- package/dist/typings/youtube/Caption/CaptionLanguage.d.ts +30 -0
- package/dist/typings/youtube/Caption/index.d.ts +2 -0
- package/dist/typings/youtube/Client/Client.d.ts +8 -3
- package/dist/typings/youtube/LiveVideo/LiveVideo.d.ts +5 -5
- package/dist/typings/youtube/Video/Video.d.ts +3 -6
- package/dist/typings/youtube/VideoCompact/VideoCompact.d.ts +2 -2
- package/dist/typings/youtube/index.d.ts +0 -1
- package/package.json +1 -1
- package/dist/cjs/youtube/Transcript/Transcript.js +0 -27
- package/dist/cjs/youtube/Transcript/TranscriptParser.js +0 -13
- package/dist/cjs/youtube/Transcript/index.js +0 -15
- package/dist/cjs/youtube/Transcript/proto/TranscriptParamsProto.js +0 -12
- package/dist/esm/youtube/Transcript/Transcript.js +0 -29
- package/dist/esm/youtube/Transcript/TranscriptParser.js +0 -13
- package/dist/esm/youtube/Transcript/index.js +0 -3
- package/dist/esm/youtube/Transcript/proto/TranscriptParamsProto.js +0 -2
- package/dist/esm/youtube/Transcript/proto/index.js +0 -1
- package/dist/typings/youtube/Transcript/Transcript.d.ts +0 -29
- package/dist/typings/youtube/Transcript/TranscriptParser.d.ts +0 -5
- package/dist/typings/youtube/Transcript/index.d.ts +0 -3
- package/dist/typings/youtube/Transcript/proto/TranscriptParamsProto.d.ts +0 -7
- package/dist/typings/youtube/Transcript/proto/index.d.ts +0 -1
|
@@ -34,23 +34,34 @@ class HTTP {
|
|
|
34
34
|
this.defaultFetchOptions = options.fetchOptions || {};
|
|
35
35
|
this.defaultClientOptions = options.youtubeClientOptions || {};
|
|
36
36
|
}
|
|
37
|
-
get(
|
|
37
|
+
get(path, options) {
|
|
38
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
-
return yield this.request(
|
|
39
|
+
return yield this.request(path, Object.assign(Object.assign({}, options), { params: Object.assign({ prettyPrint: "false" }, options === null || options === void 0 ? void 0 : options.params), method: "GET" }));
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
post(
|
|
42
|
+
post(path, options) {
|
|
43
43
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
-
return yield this.request(
|
|
44
|
+
return yield this.request(path, Object.assign(Object.assign({}, options), { method: "POST", params: Object.assign({ key: this.apiKey, prettyPrint: "false" }, options === null || options === void 0 ? void 0 : options.params), data: Object.assign({ context: {
|
|
45
45
|
client: Object.assign({ clientName: this.clientName, clientVersion: this.clientVersion }, this.defaultClientOptions),
|
|
46
46
|
} }, options === null || options === void 0 ? void 0 : options.data) }));
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
request(
|
|
49
|
+
request(path, partialOptions) {
|
|
50
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
51
|
const options = Object.assign(Object.assign(Object.assign({}, partialOptions), this.defaultFetchOptions), { headers: Object.assign(Object.assign(Object.assign(Object.assign({}, this.defaultHeaders), { cookie: this.cookie, referer: `https://${this.baseUrl}/` }), partialOptions.headers), this.defaultFetchOptions.headers), body: partialOptions.data ? JSON.stringify(partialOptions.data) : undefined });
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
// if URL is a full URL, ignore baseUrl
|
|
53
|
+
let urlString;
|
|
54
|
+
if (path.startsWith("http")) {
|
|
55
|
+
const url = new URL(path);
|
|
56
|
+
for (const [key, value] of Object.entries(partialOptions.params || {})) {
|
|
57
|
+
url.searchParams.set(key, value);
|
|
58
|
+
}
|
|
59
|
+
urlString = url.toString();
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
urlString = `https://${this.baseUrl}/${path}?${new url_1.URLSearchParams(partialOptions.params)}`;
|
|
63
|
+
}
|
|
64
|
+
const response = yield node_fetch_1.default(urlString, options);
|
|
54
65
|
const data = yield response.json();
|
|
55
66
|
this.parseCookie(response);
|
|
56
67
|
return { data };
|
|
@@ -5,6 +5,7 @@ const common_1 = require("../../common");
|
|
|
5
5
|
const BaseChannel_1 = require("../BaseChannel");
|
|
6
6
|
const PlaylistCompact_1 = require("../PlaylistCompact");
|
|
7
7
|
const VideoCompact_1 = require("../VideoCompact");
|
|
8
|
+
const VideoCaptions_1 = require("./VideoCaptions");
|
|
8
9
|
class BaseVideoParser {
|
|
9
10
|
static loadBaseVideo(target, data) {
|
|
10
11
|
var _a, _b, _c;
|
|
@@ -38,6 +39,10 @@ class BaseVideoParser {
|
|
|
38
39
|
target.related.items = BaseVideoParser.parseRelatedFromSecondaryContent(secondaryContents, target.client);
|
|
39
40
|
target.related.continuation = common_1.getContinuationFromItems(secondaryContents);
|
|
40
41
|
}
|
|
42
|
+
// captions
|
|
43
|
+
if (videoInfo.captions) {
|
|
44
|
+
target.captions = new VideoCaptions_1.VideoCaptions({ client: target.client, video: target }).load(videoInfo.captions.playerCaptionsTracklistRenderer);
|
|
45
|
+
}
|
|
41
46
|
return target;
|
|
42
47
|
}
|
|
43
48
|
static parseRelated(data, client) {
|
|
@@ -53,8 +58,8 @@ class BaseVideoParser {
|
|
|
53
58
|
const primaryInfo = contents.find((c) => "videoPrimaryInfoRenderer" in c)
|
|
54
59
|
.videoPrimaryInfoRenderer;
|
|
55
60
|
const secondaryInfo = contents.find((c) => "videoSecondaryInfoRenderer" in c).videoSecondaryInfoRenderer;
|
|
56
|
-
const videoDetails = data.playerResponse
|
|
57
|
-
return Object.assign(Object.assign(Object.assign({}, secondaryInfo), primaryInfo), { videoDetails });
|
|
61
|
+
const { videoDetails, captions } = data.playerResponse;
|
|
62
|
+
return Object.assign(Object.assign(Object.assign({}, secondaryInfo), primaryInfo), { videoDetails, captions });
|
|
58
63
|
}
|
|
59
64
|
static parseCompactRenderer(data, client) {
|
|
60
65
|
if ("compactVideoRenderer" in data) {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.VideoCaptions = void 0;
|
|
13
|
+
const Base_1 = require("../Base");
|
|
14
|
+
const Caption_1 = require("../Caption");
|
|
15
|
+
/**
|
|
16
|
+
* Captions of a video
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```js
|
|
20
|
+
*
|
|
21
|
+
* console.log(result.captions.languages.map((l) => `${l.code} - ${l.name}`)); // printing out available languages for captions
|
|
22
|
+
*
|
|
23
|
+
* console.log(await result.captions.get("en")); // printing out captions of a specific language using language code
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
class VideoCaptions extends Base_1.Base {
|
|
27
|
+
/** @hidden */
|
|
28
|
+
constructor({ video, client }) {
|
|
29
|
+
super(client);
|
|
30
|
+
this.video = video;
|
|
31
|
+
this.languages = [];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Load this instance with raw data from Youtube
|
|
35
|
+
*
|
|
36
|
+
* @hidden
|
|
37
|
+
*/
|
|
38
|
+
load(data) {
|
|
39
|
+
const { captionTracks } = data;
|
|
40
|
+
if (captionTracks) {
|
|
41
|
+
this.languages = captionTracks.map((track) => new Caption_1.CaptionLanguage({
|
|
42
|
+
captions: this,
|
|
43
|
+
name: track.name.simpleText,
|
|
44
|
+
code: track.languageCode,
|
|
45
|
+
isTranslatable: !!track.isTranslatable,
|
|
46
|
+
url: track.baseUrl,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get captions of a specific language or a translation of a specific language
|
|
53
|
+
*/
|
|
54
|
+
get(languageCode, translationLanguageCode) {
|
|
55
|
+
var _a, _b;
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
if (!languageCode)
|
|
58
|
+
languageCode = this.client.options.youtubeClientOptions.hl;
|
|
59
|
+
const url = (_a = this.languages.find((l) => l.code.toUpperCase() === (languageCode === null || languageCode === void 0 ? void 0 : languageCode.toUpperCase()))) === null || _a === void 0 ? void 0 : _a.url;
|
|
60
|
+
if (!url)
|
|
61
|
+
return undefined;
|
|
62
|
+
const params = { fmt: "json3" };
|
|
63
|
+
if (translationLanguageCode)
|
|
64
|
+
params["tlang"] = translationLanguageCode;
|
|
65
|
+
const response = yield this.client.http.get(url, { params });
|
|
66
|
+
const captions = (_b = response.data.events) === null || _b === void 0 ? void 0 : _b.reduce((curr, e) => {
|
|
67
|
+
var _a;
|
|
68
|
+
if (e.segs === undefined)
|
|
69
|
+
return curr;
|
|
70
|
+
curr.push(new Caption_1.Caption({
|
|
71
|
+
duration: e.dDurationMs,
|
|
72
|
+
start: e.tStartMs,
|
|
73
|
+
text: (_a = e.segs) === null || _a === void 0 ? void 0 : _a.map((s) => Object.values(s).join("")).join(" "),
|
|
74
|
+
}));
|
|
75
|
+
return curr;
|
|
76
|
+
}, []);
|
|
77
|
+
return captions;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.VideoCaptions = VideoCaptions;
|
|
@@ -12,4 +12,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
__exportStar(require("./BaseVideo"), exports);
|
|
14
14
|
__exportStar(require("./BaseVideoParser"), exports);
|
|
15
|
+
__exportStar(require("./VideoCaptions"), exports);
|
|
15
16
|
__exportStar(require("./VideoRelated"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Caption = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Represent a single video caption entry
|
|
6
|
+
*/
|
|
7
|
+
class Caption {
|
|
8
|
+
/** @hidden */
|
|
9
|
+
constructor(attr) {
|
|
10
|
+
Object.assign(this, attr);
|
|
11
|
+
}
|
|
12
|
+
/** transcript end time in milliseconds */
|
|
13
|
+
get end() {
|
|
14
|
+
return this.start + this.duration;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.Caption = Caption;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CaptionLanguage = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Represents a caption language option
|
|
6
|
+
*/
|
|
7
|
+
class CaptionLanguage {
|
|
8
|
+
/** @hidden */
|
|
9
|
+
constructor(attr) {
|
|
10
|
+
Object.assign(this, attr);
|
|
11
|
+
}
|
|
12
|
+
/** Get the captions of this language using the url */
|
|
13
|
+
get(translationLanguageCode) {
|
|
14
|
+
return this.captions.get(this.code, translationLanguageCode);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.CaptionLanguage = CaptionLanguage;
|
|
@@ -10,4 +10,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
10
10
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./
|
|
13
|
+
__exportStar(require("./Caption"), exports);
|
|
14
|
+
__exportStar(require("./CaptionLanguage"), exports);
|
|
@@ -16,14 +16,13 @@ const LiveVideo_1 = require("../LiveVideo");
|
|
|
16
16
|
const MixPlaylist_1 = require("../MixPlaylist");
|
|
17
17
|
const Playlist_1 = require("../Playlist");
|
|
18
18
|
const SearchResult_1 = require("../SearchResult");
|
|
19
|
-
const Transcript_1 = require("../Transcript");
|
|
20
19
|
const Video_1 = require("../Video");
|
|
21
20
|
const constants_1 = require("../constants");
|
|
22
21
|
/** Youtube Client */
|
|
23
22
|
class Client {
|
|
24
23
|
constructor(options = {}) {
|
|
25
|
-
|
|
26
|
-
this.http = new common_1.HTTP(Object.assign({ apiKey: constants_1.INNERTUBE_API_KEY, baseUrl: constants_1.BASE_URL, clientName: constants_1.INNERTUBE_CLIENT_NAME, clientVersion: constants_1.INNERTUBE_CLIENT_VERSION },
|
|
24
|
+
this.options = Object.assign(Object.assign({ initialCookie: "", fetchOptions: {} }, options), { youtubeClientOptions: Object.assign({ hl: "en", gl: "US" }, options.youtubeClientOptions) });
|
|
25
|
+
this.http = new common_1.HTTP(Object.assign({ apiKey: constants_1.INNERTUBE_API_KEY, baseUrl: constants_1.BASE_URL, clientName: constants_1.INNERTUBE_CLIENT_NAME, clientVersion: constants_1.INNERTUBE_CLIENT_VERSION }, this.options));
|
|
27
26
|
}
|
|
28
27
|
/**
|
|
29
28
|
* Searches for videos / playlists / channels
|
|
@@ -103,17 +102,14 @@ class Client {
|
|
|
103
102
|
return new Channel_1.Channel({ client: this }).load(response.data);
|
|
104
103
|
});
|
|
105
104
|
}
|
|
106
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Get video transcript / caption by video id
|
|
107
|
+
*/
|
|
108
|
+
getVideoTranscript(videoId, languageCode) {
|
|
109
|
+
var _a;
|
|
107
110
|
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
data: { params: Buffer.from(bufferParams).toString("base64") },
|
|
111
|
-
});
|
|
112
|
-
if (!response.data.actions)
|
|
113
|
-
return undefined;
|
|
114
|
-
return response.data.actions[0].updateEngagementPanelAction.content.transcriptRenderer.body.transcriptBodyRenderer.cueGroups
|
|
115
|
-
.map((t) => t.transcriptCueGroupRenderer.cues[0].transcriptCueRenderer)
|
|
116
|
-
.map((t) => new Transcript_1.Transcript().load(t));
|
|
111
|
+
const video = yield this.getVideo(videoId);
|
|
112
|
+
return (_a = video === null || video === void 0 ? void 0 : video.captions) === null || _a === void 0 ? void 0 : _a.get(languageCode);
|
|
117
113
|
});
|
|
118
114
|
}
|
|
119
115
|
}
|
|
@@ -6,25 +6,24 @@ const BaseChannel_1 = require("../BaseChannel");
|
|
|
6
6
|
const Reply_1 = require("../Reply");
|
|
7
7
|
class CommentParser {
|
|
8
8
|
static loadComment(target, data) {
|
|
9
|
-
const {
|
|
9
|
+
const { properties, toolbar, author, avatar } = data;
|
|
10
10
|
// Basic information
|
|
11
|
-
target.id = commentId;
|
|
12
|
-
target.content =
|
|
13
|
-
target.publishDate =
|
|
14
|
-
target.likeCount = +
|
|
15
|
-
target.isAuthorChannelOwner =
|
|
16
|
-
target.isPinned =
|
|
17
|
-
target.replyCount = replyCount;
|
|
11
|
+
target.id = properties.commentId;
|
|
12
|
+
target.content = properties.content.content;
|
|
13
|
+
target.publishDate = properties.publishedTime;
|
|
14
|
+
target.likeCount = +toolbar.likeCountLiked; // probably broken
|
|
15
|
+
target.isAuthorChannelOwner = !!author.isCreator;
|
|
16
|
+
target.isPinned = false; // TODO fix this
|
|
17
|
+
target.replyCount = +toolbar.replyCount;
|
|
18
18
|
// Reply Continuation
|
|
19
19
|
target.replies.continuation = data.replies
|
|
20
20
|
? common_1.getContinuationFromItems(data.replies.commentRepliesRenderer.contents)
|
|
21
21
|
: undefined;
|
|
22
22
|
// Author
|
|
23
|
-
const { browseId } = authorEndpoint.browseEndpoint;
|
|
24
23
|
target.author = new BaseChannel_1.BaseChannel({
|
|
25
|
-
id:
|
|
26
|
-
name:
|
|
27
|
-
thumbnails: new common_1.Thumbnails().load(
|
|
24
|
+
id: author.id,
|
|
25
|
+
name: author.displayName,
|
|
26
|
+
thumbnails: new common_1.Thumbnails().load(avatar.image.sources),
|
|
28
27
|
client: target.client,
|
|
29
28
|
});
|
|
30
29
|
return target;
|
|
@@ -21,10 +21,10 @@ class LiveVideo extends BaseVideo_1.BaseVideo {
|
|
|
21
21
|
/** @hidden */
|
|
22
22
|
constructor(attr) {
|
|
23
23
|
super(attr);
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
24
|
+
this.delay = 0;
|
|
25
|
+
this.timeoutMs = 0;
|
|
26
|
+
this.isChatPlaying = false;
|
|
27
|
+
this.chatQueue = [];
|
|
28
28
|
Object.assign(this, attr);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
@@ -43,18 +43,18 @@ class LiveVideo extends BaseVideo_1.BaseVideo {
|
|
|
43
43
|
* @param delay chat delay in millisecond
|
|
44
44
|
*/
|
|
45
45
|
playChat(delay = 0) {
|
|
46
|
-
if (this.
|
|
46
|
+
if (this.isChatPlaying)
|
|
47
47
|
return;
|
|
48
|
-
this.
|
|
49
|
-
this.
|
|
48
|
+
this.delay = delay;
|
|
49
|
+
this.isChatPlaying = true;
|
|
50
50
|
this.pollChatContinuation();
|
|
51
51
|
}
|
|
52
52
|
/** Stop request polling for live chat */
|
|
53
53
|
stopChat() {
|
|
54
|
-
if (!this.
|
|
54
|
+
if (!this.chatRequestPoolingTimeout)
|
|
55
55
|
return;
|
|
56
|
-
this.
|
|
57
|
-
clearTimeout(this.
|
|
56
|
+
this.isChatPlaying = false;
|
|
57
|
+
clearTimeout(this.chatRequestPoolingTimeout);
|
|
58
58
|
}
|
|
59
59
|
/** Start request polling */
|
|
60
60
|
pollChatContinuation() {
|
|
@@ -67,16 +67,16 @@ class LiveVideo extends BaseVideo_1.BaseVideo {
|
|
|
67
67
|
const chats = LiveVideoParser_1.LiveVideoParser.parseChats(response.data);
|
|
68
68
|
for (const c of chats) {
|
|
69
69
|
const chat = new Chat_1.Chat({ client: this.client }).load(c);
|
|
70
|
-
if (this.
|
|
70
|
+
if (this.chatQueue.find((c) => c.id === chat.id))
|
|
71
71
|
continue;
|
|
72
|
-
this.
|
|
73
|
-
const timeout = chat.timestamp / 1000 - (new Date().getTime() - this.
|
|
72
|
+
this.chatQueue.push(chat);
|
|
73
|
+
const timeout = chat.timestamp / 1000 - (new Date().getTime() - this.delay);
|
|
74
74
|
setTimeout(() => this.emit("chat", chat), timeout);
|
|
75
75
|
}
|
|
76
76
|
const { timeout, continuation } = LiveVideoParser_1.LiveVideoParser.parseContinuation(response.data);
|
|
77
|
-
this.
|
|
77
|
+
this.timeoutMs = timeout;
|
|
78
78
|
this.chatContinuation = continuation;
|
|
79
|
-
this.
|
|
79
|
+
this.chatRequestPoolingTimeout = setTimeout(() => this.pollChatContinuation(), this.timeoutMs);
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -34,14 +34,12 @@ class Video extends BaseVideo_1.BaseVideo {
|
|
|
34
34
|
/**
|
|
35
35
|
* Get Video transcript (if exists)
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
* ```js
|
|
39
|
-
* client.getVideoTranscript(video.id);
|
|
40
|
-
* ```
|
|
37
|
+
* @deprecated use `video.captions.get()` instead
|
|
41
38
|
*/
|
|
42
|
-
getTranscript() {
|
|
39
|
+
getTranscript(languageCode) {
|
|
40
|
+
var _a;
|
|
43
41
|
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
-
return this.
|
|
42
|
+
return (_a = this.captions) === null || _a === void 0 ? void 0 : _a.get(languageCode);
|
|
45
43
|
});
|
|
46
44
|
}
|
|
47
45
|
}
|
|
@@ -23,9 +23,9 @@ class VideoParser {
|
|
|
23
23
|
return target;
|
|
24
24
|
}
|
|
25
25
|
static parseComments(data, video) {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const comments = data.frameworkUpdates.entityBatchUpdate.mutations
|
|
27
|
+
.filter((m) => m.payload.commentEntityPayload)
|
|
28
|
+
.map((m) => m.payload.commentEntityPayload);
|
|
29
29
|
return comments.map((c) => new Comment_1.Comment({ video, client: video.client }).load(c));
|
|
30
30
|
}
|
|
31
31
|
static parseCommentContinuation(data) {
|
|
@@ -53,9 +53,9 @@ class VideoCompact extends Base_1.Base {
|
|
|
53
53
|
* client.getVideoTranscript(video.id);
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
getTranscript() {
|
|
56
|
+
getTranscript(languageCode) {
|
|
57
57
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
return this.client.getVideoTranscript(this.id);
|
|
58
|
+
return this.client.getVideoTranscript(this.id, languageCode);
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -5,7 +5,7 @@ const common_1 = require("../../common");
|
|
|
5
5
|
const BaseChannel_1 = require("../BaseChannel");
|
|
6
6
|
class VideoCompactParser {
|
|
7
7
|
static loadVideoCompact(target, data) {
|
|
8
|
-
var _a, _b, _c, _d;
|
|
8
|
+
var _a, _b, _c, _d, _e;
|
|
9
9
|
const { videoId, title, headline, lengthText, thumbnail, ownerText, shortBylineText, publishedTimeText, viewCountText, badges, thumbnailOverlays, channelThumbnailSupportedRenderers, detailedMetadataSnippets, } = data;
|
|
10
10
|
target.id = videoId;
|
|
11
11
|
target.title = headline
|
|
@@ -18,7 +18,9 @@ class VideoCompactParser {
|
|
|
18
18
|
target.duration =
|
|
19
19
|
common_1.getDuration((lengthText === null || lengthText === void 0 ? void 0 : lengthText.simpleText) || ((_d = thumbnailOverlays === null || thumbnailOverlays === void 0 ? void 0 : thumbnailOverlays[0].thumbnailOverlayTimeStatusRenderer) === null || _d === void 0 ? void 0 : _d.text.simpleText) ||
|
|
20
20
|
"") || null;
|
|
21
|
-
target.isLive =
|
|
21
|
+
target.isLive =
|
|
22
|
+
!!((badges === null || badges === void 0 ? void 0 : badges[0].metadataBadgeRenderer.style) === "BADGE_STYLE_TYPE_LIVE_NOW") ||
|
|
23
|
+
((_e = thumbnailOverlays === null || thumbnailOverlays === void 0 ? void 0 : thumbnailOverlays[0].thumbnailOverlayTimeStatusRenderer) === null || _e === void 0 ? void 0 : _e.style) === "LIVE";
|
|
22
24
|
// Channel
|
|
23
25
|
if (ownerText || shortBylineText) {
|
|
24
26
|
const browseEndpoint = (ownerText || shortBylineText).runs[0].navigationEndpoint
|
|
@@ -24,6 +24,5 @@ __exportStar(require("./Playlist"), exports);
|
|
|
24
24
|
__exportStar(require("./PlaylistCompact"), exports);
|
|
25
25
|
__exportStar(require("./Reply"), exports);
|
|
26
26
|
__exportStar(require("./SearchResult"), exports);
|
|
27
|
-
__exportStar(require("./Transcript"), exports);
|
|
28
27
|
__exportStar(require("./Video"), exports);
|
|
29
28
|
__exportStar(require("./VideoCompact"), exports);
|
|
@@ -45,6 +45,33 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
45
45
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
var __values = (this && this.__values) || function(o) {
|
|
49
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
50
|
+
if (m) return m.call(o);
|
|
51
|
+
if (o && typeof o.length === "number") return {
|
|
52
|
+
next: function () {
|
|
53
|
+
if (o && i >= o.length) o = void 0;
|
|
54
|
+
return { value: o && o[i++], done: !o };
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
58
|
+
};
|
|
59
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
60
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
61
|
+
if (!m) return o;
|
|
62
|
+
var i = m.call(o), r, ar = [], e;
|
|
63
|
+
try {
|
|
64
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
65
|
+
}
|
|
66
|
+
catch (error) { e = { error: error }; }
|
|
67
|
+
finally {
|
|
68
|
+
try {
|
|
69
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
70
|
+
}
|
|
71
|
+
finally { if (e) throw e.error; }
|
|
72
|
+
}
|
|
73
|
+
return ar;
|
|
74
|
+
};
|
|
48
75
|
import fetch from "node-fetch";
|
|
49
76
|
import { URLSearchParams } from "url";
|
|
50
77
|
/**
|
|
@@ -66,21 +93,21 @@ var HTTP = /** @class */ (function () {
|
|
|
66
93
|
this.defaultFetchOptions = options.fetchOptions || {};
|
|
67
94
|
this.defaultClientOptions = options.youtubeClientOptions || {};
|
|
68
95
|
}
|
|
69
|
-
HTTP.prototype.get = function (
|
|
96
|
+
HTTP.prototype.get = function (path, options) {
|
|
70
97
|
return __awaiter(this, void 0, void 0, function () {
|
|
71
98
|
return __generator(this, function (_a) {
|
|
72
99
|
switch (_a.label) {
|
|
73
|
-
case 0: return [4 /*yield*/, this.request(
|
|
100
|
+
case 0: return [4 /*yield*/, this.request(path, __assign(__assign({}, options), { params: __assign({ prettyPrint: "false" }, options === null || options === void 0 ? void 0 : options.params), method: "GET" }))];
|
|
74
101
|
case 1: return [2 /*return*/, _a.sent()];
|
|
75
102
|
}
|
|
76
103
|
});
|
|
77
104
|
});
|
|
78
105
|
};
|
|
79
|
-
HTTP.prototype.post = function (
|
|
106
|
+
HTTP.prototype.post = function (path, options) {
|
|
80
107
|
return __awaiter(this, void 0, void 0, function () {
|
|
81
108
|
return __generator(this, function (_a) {
|
|
82
109
|
switch (_a.label) {
|
|
83
|
-
case 0: return [4 /*yield*/, this.request(
|
|
110
|
+
case 0: return [4 /*yield*/, this.request(path, __assign(__assign({}, options), { method: "POST", params: __assign({ key: this.apiKey, prettyPrint: "false" }, options === null || options === void 0 ? void 0 : options.params), data: __assign({ context: {
|
|
84
111
|
client: __assign({ clientName: this.clientName, clientVersion: this.clientVersion }, this.defaultClientOptions),
|
|
85
112
|
} }, options === null || options === void 0 ? void 0 : options.data) }))];
|
|
86
113
|
case 1: return [2 /*return*/, _a.sent()];
|
|
@@ -88,20 +115,40 @@ var HTTP = /** @class */ (function () {
|
|
|
88
115
|
});
|
|
89
116
|
});
|
|
90
117
|
};
|
|
91
|
-
HTTP.prototype.request = function (
|
|
118
|
+
HTTP.prototype.request = function (path, partialOptions) {
|
|
92
119
|
return __awaiter(this, void 0, void 0, function () {
|
|
93
|
-
var options,
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
var options, urlString, url, _a, _b, _c, key, value, response, data;
|
|
121
|
+
var e_1, _d;
|
|
122
|
+
return __generator(this, function (_e) {
|
|
123
|
+
switch (_e.label) {
|
|
96
124
|
case 0:
|
|
97
125
|
options = __assign(__assign(__assign({}, partialOptions), this.defaultFetchOptions), { headers: __assign(__assign(__assign(__assign({}, this.defaultHeaders), { cookie: this.cookie, referer: "https://" + this.baseUrl + "/" }), partialOptions.headers), this.defaultFetchOptions.headers), body: partialOptions.data ? JSON.stringify(partialOptions.data) : undefined });
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
if (path.startsWith("http")) {
|
|
127
|
+
url = new URL(path);
|
|
128
|
+
try {
|
|
129
|
+
for (_a = __values(Object.entries(partialOptions.params || {})), _b = _a.next(); !_b.done; _b = _a.next()) {
|
|
130
|
+
_c = __read(_b.value, 2), key = _c[0], value = _c[1];
|
|
131
|
+
url.searchParams.set(key, value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
135
|
+
finally {
|
|
136
|
+
try {
|
|
137
|
+
if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
|
|
138
|
+
}
|
|
139
|
+
finally { if (e_1) throw e_1.error; }
|
|
140
|
+
}
|
|
141
|
+
urlString = url.toString();
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
urlString = "https://" + this.baseUrl + "/" + path + "?" + new URLSearchParams(partialOptions.params);
|
|
145
|
+
}
|
|
146
|
+
return [4 /*yield*/, fetch(urlString, options)];
|
|
100
147
|
case 1:
|
|
101
|
-
response =
|
|
148
|
+
response = _e.sent();
|
|
102
149
|
return [4 /*yield*/, response.json()];
|
|
103
150
|
case 2:
|
|
104
|
-
data =
|
|
151
|
+
data = _e.sent();
|
|
105
152
|
this.parseCookie(response);
|
|
106
153
|
return [2 /*return*/, { data: data }];
|
|
107
154
|
}
|
|
@@ -13,6 +13,7 @@ import { getContinuationFromItems, stripToInt, Thumbnails } from "../../common";
|
|
|
13
13
|
import { BaseChannel } from "../BaseChannel";
|
|
14
14
|
import { PlaylistCompact } from "../PlaylistCompact";
|
|
15
15
|
import { VideoCompact } from "../VideoCompact";
|
|
16
|
+
import { VideoCaptions } from "./VideoCaptions";
|
|
16
17
|
var BaseVideoParser = /** @class */ (function () {
|
|
17
18
|
function BaseVideoParser() {
|
|
18
19
|
}
|
|
@@ -48,6 +49,10 @@ var BaseVideoParser = /** @class */ (function () {
|
|
|
48
49
|
target.related.items = BaseVideoParser.parseRelatedFromSecondaryContent(secondaryContents, target.client);
|
|
49
50
|
target.related.continuation = getContinuationFromItems(secondaryContents);
|
|
50
51
|
}
|
|
52
|
+
// captions
|
|
53
|
+
if (videoInfo.captions) {
|
|
54
|
+
target.captions = new VideoCaptions({ client: target.client, video: target }).load(videoInfo.captions.playerCaptionsTracklistRenderer);
|
|
55
|
+
}
|
|
51
56
|
return target;
|
|
52
57
|
};
|
|
53
58
|
BaseVideoParser.parseRelated = function (data, client) {
|
|
@@ -63,8 +68,8 @@ var BaseVideoParser = /** @class */ (function () {
|
|
|
63
68
|
var primaryInfo = contents.find(function (c) { return "videoPrimaryInfoRenderer" in c; })
|
|
64
69
|
.videoPrimaryInfoRenderer;
|
|
65
70
|
var secondaryInfo = contents.find(function (c) { return "videoSecondaryInfoRenderer" in c; }).videoSecondaryInfoRenderer;
|
|
66
|
-
var
|
|
67
|
-
return __assign(__assign(__assign({}, secondaryInfo), primaryInfo), { videoDetails: videoDetails });
|
|
71
|
+
var _a = data.playerResponse, videoDetails = _a.videoDetails, captions = _a.captions;
|
|
72
|
+
return __assign(__assign(__assign({}, secondaryInfo), primaryInfo), { videoDetails: videoDetails, captions: captions });
|
|
68
73
|
};
|
|
69
74
|
BaseVideoParser.parseCompactRenderer = function (data, client) {
|
|
70
75
|
if ("compactVideoRenderer" in data) {
|