youtubei 0.0.1-rc.3 → 0.0.1-rc.32

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.
Files changed (62) hide show
  1. package/README.md +6 -5
  2. package/dist/classes/Base.d.ts +10 -0
  3. package/dist/classes/{client/types.js → Base.js} +3 -0
  4. package/dist/classes/BaseVideo.d.ts +59 -0
  5. package/dist/classes/BaseVideo.js +121 -0
  6. package/dist/classes/Channel.d.ts +27 -31
  7. package/dist/classes/Channel.js +59 -135
  8. package/dist/classes/ChannelCompact.d.ts +74 -23
  9. package/dist/classes/ChannelCompact.js +114 -103
  10. package/dist/classes/Chat.d.ts +29 -0
  11. package/dist/classes/Chat.js +31 -0
  12. package/dist/classes/Client.d.ts +49 -0
  13. package/dist/classes/Client.js +97 -0
  14. package/dist/classes/Comment.d.ts +50 -0
  15. package/dist/classes/Comment.js +84 -0
  16. package/dist/classes/LiveVideo.d.ts +47 -0
  17. package/dist/classes/LiveVideo.js +94 -0
  18. package/dist/classes/MixPlaylist.d.ts +32 -0
  19. package/dist/classes/MixPlaylist.js +44 -0
  20. package/dist/classes/Playlist.d.ts +35 -18
  21. package/dist/classes/Playlist.js +80 -116
  22. package/dist/classes/PlaylistCompact.d.ts +27 -15
  23. package/dist/classes/PlaylistCompact.js +42 -46
  24. package/dist/classes/Reply.d.ts +38 -0
  25. package/dist/classes/Reply.js +35 -0
  26. package/dist/classes/SearchResult.d.ts +52 -8
  27. package/dist/classes/SearchResult.js +101 -122
  28. package/dist/classes/Thumbnails.d.ts +42 -0
  29. package/dist/classes/Thumbnails.js +66 -0
  30. package/dist/classes/Video.d.ts +44 -37
  31. package/dist/classes/Video.js +74 -83
  32. package/dist/classes/VideoCompact.d.ts +38 -19
  33. package/dist/classes/VideoCompact.js +53 -53
  34. package/dist/classes/index.d.ts +10 -2
  35. package/dist/classes/index.js +20 -4
  36. package/dist/common/HTTP.d.ts +26 -0
  37. package/dist/common/HTTP.js +85 -0
  38. package/dist/common/decorators.js +6 -26
  39. package/dist/common/helper.d.ts +4 -0
  40. package/dist/common/helper.js +37 -18
  41. package/dist/common/index.d.ts +2 -1
  42. package/dist/common/index.js +5 -3
  43. package/dist/common/mixins.d.ts +2 -0
  44. package/dist/common/mixins.js +12 -0
  45. package/dist/common/types.d.ts +0 -5
  46. package/dist/constants.d.ts +5 -2
  47. package/dist/constants.js +6 -3
  48. package/package.json +23 -20
  49. package/.prettierrc +0 -8
  50. package/.vscode/settings.json +0 -4
  51. package/CHANGELOG.md +0 -6
  52. package/debug.log +0 -47
  53. package/dist/classes/BaseCompact.d.ts +0 -10
  54. package/dist/classes/BaseCompact.js +0 -27
  55. package/dist/classes/client/Client.d.ts +0 -23
  56. package/dist/classes/client/Client.js +0 -128
  57. package/dist/classes/client/index.d.ts +0 -2
  58. package/dist/classes/client/index.js +0 -19
  59. package/dist/classes/client/types.d.ts +0 -12
  60. package/dist/common/axios.d.ts +0 -4
  61. package/dist/common/axios.js +0 -44
  62. package/jest.config.js +0 -5
@@ -0,0 +1,38 @@
1
+ import { Base, ChannelCompact, Video, BaseAttributes, Comment } from ".";
2
+ import { YoutubeRawData } from "../common";
3
+ /** @hidden */
4
+ interface ReplyAttributes extends BaseAttributes {
5
+ comment: Comment;
6
+ video: Video;
7
+ author: ChannelCompact;
8
+ content: string;
9
+ publishDate: string;
10
+ likeCount: number;
11
+ isAuthorChannelOwner: boolean;
12
+ }
13
+ /** Represents a Reply */
14
+ export default class Reply extends Base implements ReplyAttributes {
15
+ /** The comment this reply belongs to */
16
+ comment: Comment;
17
+ /** The video this reply belongs to */
18
+ video: Video;
19
+ /** The comment's author */
20
+ author: ChannelCompact;
21
+ /** The content of this comment */
22
+ content: string;
23
+ /** The publish date of the comment */
24
+ publishDate: string;
25
+ /** How many likes does this comment have */
26
+ likeCount: number;
27
+ /** Whether the comment is posted by the video uploader / owner */
28
+ isAuthorChannelOwner: boolean;
29
+ /** @hidden */
30
+ constructor(reply?: Partial<ReplyAttributes>);
31
+ /**
32
+ * Load this instance with raw data from Youtube
33
+ *
34
+ * @hidden
35
+ */
36
+ load(data: YoutubeRawData): Reply;
37
+ }
38
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const _1 = require(".");
4
+ /** Represents a Reply */
5
+ class Reply extends _1.Base {
6
+ /** @hidden */
7
+ constructor(reply = {}) {
8
+ super();
9
+ Object.assign(this, reply);
10
+ }
11
+ /**
12
+ * Load this instance with raw data from Youtube
13
+ *
14
+ * @hidden
15
+ */
16
+ load(data) {
17
+ const { authorText, authorThumbnail, authorEndpoint, contentText, publishedTimeText, commentId, likeCount, authorIsChannelOwner, } = data;
18
+ // Basic information
19
+ this.id = commentId;
20
+ this.content = contentText.runs.map((r) => r.text).join("");
21
+ this.publishDate = publishedTimeText.runs.shift().text;
22
+ this.likeCount = likeCount;
23
+ this.isAuthorChannelOwner = authorIsChannelOwner;
24
+ // Author
25
+ const { browseId } = authorEndpoint.browseEndpoint;
26
+ this.author = new _1.ChannelCompact({
27
+ id: browseId,
28
+ name: authorText.simpleText,
29
+ thumbnails: new _1.Thumbnails().load(authorThumbnail.thumbnails),
30
+ client: this.client,
31
+ });
32
+ return this;
33
+ }
34
+ }
35
+ exports.default = Reply;
@@ -1,28 +1,72 @@
1
- import { SearchResultType, SearchOptions } from "./client";
1
+ import { ChannelCompact, PlaylistCompact, VideoCompact, ClientTypes, Client } from ".";
2
+ export declare type SearchResultType<T> = T extends "video" | VideoCompact ? VideoCompact : T extends "channel" | ChannelCompact ? ChannelCompact : T extends "playlist" | PlaylistCompact ? PlaylistCompact : VideoCompact | ChannelCompact | PlaylistCompact;
3
+ /**
4
+ * Represents search result, usually returned from `client.search();`.
5
+ *
6
+ * {@link SearchResult} is a subclass of [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
7
+ * with {@link SearchResult.next} method to navigate through pagination
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const searchResult = await youtube.search("Keyword");
12
+ *
13
+ * console.log(searchResult); // search result from first page
14
+ *
15
+ * let nextSearchResult = await searchResult.next();
16
+ * console.log(nextSearchResult); // search result from second page
17
+ *
18
+ * nextSearchResult = await searchResult.next();
19
+ * console.log(nextSearchResult); // search result from third page
20
+ *
21
+ * console.log(searchResult); // search result from first, second, and third page.
22
+ * ```
23
+ *
24
+ * @noInheritDoc
25
+ */
2
26
  export default class SearchResult<T> extends Array<SearchResultType<T>> {
3
- private latestContinuationToken;
27
+ /** The estimated search result count */
28
+ estimatedResults: number;
29
+ continuation?: string;
30
+ private client;
31
+ /** @hidden */
4
32
  constructor();
33
+ /**
34
+ * Load this instance
35
+ *
36
+ * @hidden
37
+ */
38
+ load(client: Client): SearchResult<T>;
5
39
  /**
6
40
  * Initialize data from search
7
41
  *
8
42
  * @param query Search query
9
43
  * @param options Search Options
44
+ * @hidden
10
45
  */
11
- init(query: string, options: SearchOptions): Promise<SearchResult<T>>;
46
+ init(query: string, options: ClientTypes.SearchOptions): Promise<SearchResult<T>>;
12
47
  /**
13
- * Load next search data
48
+ * Load next search data. Youtube returns inconsistent amount of search result, it usually varies from 18 to 20
49
+ *
50
+ * @example
51
+ * ```js
52
+ * const videos = await youtube.search("keyword", { type: "video" });
53
+ * console.log(videos) // first 18-20 videos from the search result
54
+ *
55
+ * let newVideos = await videos.next();
56
+ * console.log(newVideos) // 18-20 loaded videos
57
+ * console.log(videos) // 36-40 first videos from the search result
58
+ * ```
14
59
  *
15
60
  * @param count How many times to load the next data
16
61
  */
17
62
  next(count?: number): Promise<Array<SearchResultType<T>>>;
18
- /**
19
- * Load videos data from youtube
20
- */
21
- private loadVideos;
63
+ /** Load videos data from youtube */
64
+ private loadSearchResult;
22
65
  /**
23
66
  * Get type query value
24
67
  *
25
68
  * @param type Search type
69
+ * @hidden
26
70
  */
27
71
  static getSearchTypeParam(type: "video" | "playlist" | "channel" | "all"): string;
28
72
  }
@@ -1,17 +1,4 @@
1
1
  "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- extendStatics(d, b);
11
- function __() { this.constructor = d; }
12
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
- };
14
- })();
15
2
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
16
3
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
17
4
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -27,145 +14,137 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
27
14
  step((generator = generator.apply(thisArg, _arguments || [])).next());
28
15
  });
29
16
  };
30
- var __generator = (this && this.__generator) || function (thisArg, body) {
31
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
32
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
33
- function verb(n) { return function (v) { return step([n, v]); }; }
34
- function step(op) {
35
- if (f) throw new TypeError("Generator is already executing.");
36
- while (_) try {
37
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
38
- if (y = 0, t) op = [op[0] & 2, t.value];
39
- switch (op[0]) {
40
- case 0: case 1: t = op; break;
41
- case 4: _.label++; return { value: op[1], done: false };
42
- case 5: _.label++; y = op[1]; op = [0]; continue;
43
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
44
- default:
45
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
46
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
47
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
48
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
49
- if (t[2]) _.ops.pop();
50
- _.trys.pop(); continue;
51
- }
52
- op = body.call(thisArg, _);
53
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
54
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
55
- }
56
- };
17
+ var SearchResult_1;
57
18
  Object.defineProperty(exports, "__esModule", { value: true });
58
- var constants_1 = require("../constants");
59
- var common_1 = require("../common");
60
- var __1 = require("..");
61
- var SearchResult = /** @class */ (function (_super) {
62
- __extends(SearchResult, _super);
63
- function SearchResult() {
64
- return _super.call(this) || this;
19
+ const constants_1 = require("../constants");
20
+ const common_1 = require("../common");
21
+ const _1 = require(".");
22
+ /**
23
+ * Represents search result, usually returned from `client.search();`.
24
+ *
25
+ * {@link SearchResult} is a subclass of [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
26
+ * with {@link SearchResult.next} method to navigate through pagination
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const searchResult = await youtube.search("Keyword");
31
+ *
32
+ * console.log(searchResult); // search result from first page
33
+ *
34
+ * let nextSearchResult = await searchResult.next();
35
+ * console.log(nextSearchResult); // search result from second page
36
+ *
37
+ * nextSearchResult = await searchResult.next();
38
+ * console.log(nextSearchResult); // search result from third page
39
+ *
40
+ * console.log(searchResult); // search result from first, second, and third page.
41
+ * ```
42
+ *
43
+ * @noInheritDoc
44
+ */
45
+ let SearchResult = SearchResult_1 = class SearchResult extends Array {
46
+ /** @hidden */
47
+ constructor() {
48
+ super();
49
+ }
50
+ /**
51
+ * Load this instance
52
+ *
53
+ * @hidden
54
+ */
55
+ load(client) {
56
+ this.client = client;
57
+ return this;
65
58
  }
66
- SearchResult_1 = SearchResult;
67
59
  /**
68
60
  * Initialize data from search
69
61
  *
70
62
  * @param query Search query
71
63
  * @param options Search Options
64
+ * @hidden
72
65
  */
73
- SearchResult.prototype.init = function (query, options) {
74
- return __awaiter(this, void 0, void 0, function () {
75
- var response;
76
- return __generator(this, function (_a) {
77
- switch (_a.label) {
78
- case 0: return [4 /*yield*/, common_1.axios.post(constants_1.I_END_POINT + "/search", {
79
- query: query,
80
- params: SearchResult_1.getSearchTypeParam(options.type),
81
- })];
82
- case 1:
83
- response = _a.sent();
84
- this.loadVideos(response.data.contents.twoColumnSearchResultsRenderer.primaryContents
85
- .sectionListRenderer.contents);
86
- return [2 /*return*/, this];
87
- }
66
+ init(query, options) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
69
+ data: {
70
+ query,
71
+ params: options.params || SearchResult_1.getSearchTypeParam(options.type || "all"),
72
+ },
88
73
  });
74
+ this.estimatedResults = +response.data.estimatedResults;
75
+ if (this.estimatedResults > 0) {
76
+ this.loadSearchResult(response.data.contents.twoColumnSearchResultsRenderer.primaryContents
77
+ .sectionListRenderer.contents);
78
+ }
79
+ return this;
89
80
  });
90
- };
81
+ }
91
82
  /**
92
- * Load next search data
83
+ * Load next search data. Youtube returns inconsistent amount of search result, it usually varies from 18 to 20
84
+ *
85
+ * @example
86
+ * ```js
87
+ * const videos = await youtube.search("keyword", { type: "video" });
88
+ * console.log(videos) // first 18-20 videos from the search result
89
+ *
90
+ * let newVideos = await videos.next();
91
+ * console.log(newVideos) // 18-20 loaded videos
92
+ * console.log(videos) // 36-40 first videos from the search result
93
+ * ```
93
94
  *
94
95
  * @param count How many times to load the next data
95
96
  */
96
- SearchResult.prototype.next = function (count) {
97
- if (count === void 0) { count = 1; }
98
- return __awaiter(this, void 0, void 0, function () {
99
- var newVideo, i, response;
100
- return __generator(this, function (_a) {
101
- switch (_a.label) {
102
- case 0:
103
- newVideo = [];
104
- i = 0;
105
- _a.label = 1;
106
- case 1:
107
- if (!(i < count)) return [3 /*break*/, 4];
108
- if (!this.latestContinuationToken)
109
- return [3 /*break*/, 4];
110
- return [4 /*yield*/, common_1.axios.post(constants_1.I_END_POINT + "/search", {
111
- continuation: this.latestContinuationToken,
112
- })];
113
- case 2:
114
- response = _a.sent();
115
- newVideo.push.apply(newVideo, this.loadVideos(response.data.onResponseReceivedCommands[0].appendContinuationItemsAction
116
- .continuationItems));
117
- _a.label = 3;
118
- case 3:
119
- i++;
120
- return [3 /*break*/, 1];
121
- case 4: return [2 /*return*/, newVideo];
122
- }
123
- });
97
+ next(count = 1) {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ const newSearchResults = [];
100
+ for (let i = 0; i < count; i++) {
101
+ if (!this.continuation)
102
+ break;
103
+ const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
104
+ data: { continuation: this.continuation },
105
+ });
106
+ newSearchResults.push(...this.loadSearchResult(response.data.onResponseReceivedCommands[0].appendContinuationItemsAction
107
+ .continuationItems));
108
+ }
109
+ this.push(...newSearchResults);
110
+ return newSearchResults;
124
111
  });
125
- };
126
- /**
127
- * Load videos data from youtube
128
- */
129
- SearchResult.prototype.loadVideos = function (sectionListContents) {
130
- var _a, _b;
131
- var contents = sectionListContents
132
- .filter(function (c) { return "itemSectionRenderer" in c; })
112
+ }
113
+ /** Load videos data from youtube */
114
+ loadSearchResult(sectionListContents) {
115
+ const contents = sectionListContents
116
+ .filter((c) => "itemSectionRenderer" in c)
133
117
  .pop().itemSectionRenderer.contents;
134
- var continuationToken = (_b = (_a = sectionListContents
135
- .filter(function (c) { return "continuationItemRenderer" in c; })
136
- .pop().continuationItemRenderer) === null || _a === void 0 ? void 0 : _a.continuationEndpoint) === null || _b === void 0 ? void 0 : _b.continuationCommand.token;
137
- this.latestContinuationToken = continuationToken;
138
- var newContent = [];
139
- for (var _i = 0, contents_1 = contents; _i < contents_1.length; _i++) {
140
- var content = contents_1[_i];
118
+ this.continuation = common_1.getContinuationFromItems(sectionListContents);
119
+ const newContent = [];
120
+ for (const content of contents) {
141
121
  if ("playlistRenderer" in content)
142
- newContent.push(new __1.PlaylistCompact().load(content.playlistRenderer));
122
+ newContent.push(new _1.PlaylistCompact({ client: this.client }).load(content.playlistRenderer));
143
123
  else if ("videoRenderer" in content)
144
- newContent.push(new __1.VideoCompact().load(content.videoRenderer));
124
+ newContent.push(new _1.VideoCompact({ client: this.client }).load(content.videoRenderer));
145
125
  else if ("channelRenderer" in content)
146
- newContent.push(new __1.Channel().load(content.channelRenderer));
126
+ newContent.push(new _1.ChannelCompact({ client: this.client }).load(content.channelRenderer));
147
127
  }
148
- this.push.apply(this, newContent);
128
+ this.push(...newContent);
149
129
  return newContent;
150
- };
130
+ }
151
131
  /**
152
132
  * Get type query value
153
133
  *
154
134
  * @param type Search type
135
+ * @hidden
155
136
  */
156
- SearchResult.getSearchTypeParam = function (type) {
157
- var searchType = {
137
+ static getSearchTypeParam(type) {
138
+ const searchType = {
158
139
  video: "EgIQAQ%3D%3D",
159
140
  playlist: "EgIQAw%3D%3D",
160
141
  channel: "EgIQAg%3D%3D",
161
142
  all: "",
162
143
  };
163
144
  return type in searchType ? searchType[type] : "";
164
- };
165
- var SearchResult_1;
166
- SearchResult = SearchResult_1 = __decorate([
167
- common_1.extendsBuiltIn()
168
- ], SearchResult);
169
- return SearchResult;
170
- }(Array));
145
+ }
146
+ };
147
+ SearchResult = SearchResult_1 = __decorate([
148
+ common_1.extendsBuiltIn()
149
+ ], SearchResult);
171
150
  exports.default = SearchResult;
@@ -0,0 +1,42 @@
1
+ interface Thumbnail {
2
+ url: string;
3
+ width: number;
4
+ height: number;
5
+ }
6
+ /**
7
+ * Represents Thumbnails, usually found inside Playlist / Channel / Video, etc.
8
+ *
9
+ * {@link Thumbnails} is an array of {@link Thumbnail}
10
+ *
11
+ * @noInheritDoc
12
+ */
13
+ export default class Thumbnails extends Array<Thumbnail> {
14
+ /** @hidden */
15
+ constructor();
16
+ /**
17
+ * Returns thumbnail with the lowest resolution, usually the first element of the Thumbnails array
18
+ *
19
+ * @example
20
+ * ```js
21
+ * const min = video.thumbnails.min;
22
+ * ```
23
+ */
24
+ get min(): string | undefined;
25
+ /**
26
+ * Returns thumbnail with the highest resolution, usually the last element of the Thumbnails array
27
+ *
28
+ * @example
29
+ * ```js
30
+ * const min = video.thumbnails.min;
31
+ * ```
32
+ */
33
+ get best(): string | undefined;
34
+ /**
35
+ * Load this instance with raw data from Youtube
36
+ *
37
+ * @hidden
38
+ */
39
+ load(thumbnails: Thumbnail[]): Thumbnails;
40
+ private static parseThumbnailUrl;
41
+ }
42
+ export {};
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var Thumbnails_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const common_1 = require("../common");
11
+ /**
12
+ * Represents Thumbnails, usually found inside Playlist / Channel / Video, etc.
13
+ *
14
+ * {@link Thumbnails} is an array of {@link Thumbnail}
15
+ *
16
+ * @noInheritDoc
17
+ */
18
+ let Thumbnails = Thumbnails_1 = class Thumbnails extends Array {
19
+ /** @hidden */
20
+ constructor() {
21
+ super();
22
+ }
23
+ /**
24
+ * Returns thumbnail with the lowest resolution, usually the first element of the Thumbnails array
25
+ *
26
+ * @example
27
+ * ```js
28
+ * const min = video.thumbnails.min;
29
+ * ```
30
+ */
31
+ get min() {
32
+ return Thumbnails_1.parseThumbnailUrl(this[0]);
33
+ }
34
+ /**
35
+ * Returns thumbnail with the highest resolution, usually the last element of the Thumbnails array
36
+ *
37
+ * @example
38
+ * ```js
39
+ * const min = video.thumbnails.min;
40
+ * ```
41
+ */
42
+ get best() {
43
+ return Thumbnails_1.parseThumbnailUrl(this[this.length - 1]);
44
+ }
45
+ /**
46
+ * Load this instance with raw data from Youtube
47
+ *
48
+ * @hidden
49
+ */
50
+ load(thumbnails) {
51
+ this.push(...thumbnails);
52
+ return this;
53
+ }
54
+ static parseThumbnailUrl({ url }) {
55
+ if (url.startsWith("//"))
56
+ return `https:${url}`;
57
+ if (!url.startsWith("https://"))
58
+ return `https://${url}`;
59
+ else
60
+ return url;
61
+ }
62
+ };
63
+ Thumbnails = Thumbnails_1 = __decorate([
64
+ common_1.extendsBuiltIn()
65
+ ], Thumbnails);
66
+ exports.default = Thumbnails;
@@ -1,45 +1,52 @@
1
- import { PlaylistCompact, VideoCompact, Channel } from ".";
1
+ import { BaseVideo, BaseVideoAttributes, Comment } from ".";
2
2
  import { YoutubeRawData } from "../common";
3
- interface VideoAttributes {
4
- id: string;
5
- title: string;
6
- duration: number | null;
7
- thumbnail: string;
8
- description: string;
9
- channel: Channel;
10
- uploadDate: string;
11
- viewCount: number | null;
12
- likeCount: number | null;
13
- dislikeCount: number | null;
14
- isLiveContent: boolean;
15
- tags: string[];
16
- upNext: VideoCompact | PlaylistCompact;
17
- related: (VideoCompact | PlaylistCompact)[];
3
+ /** @hidden */
4
+ interface VideoAttributes extends BaseVideoAttributes {
5
+ duration: number;
6
+ comments: Comment[];
7
+ commentContinuation?: string;
18
8
  }
19
- /**
20
- * Represent a Video
21
- */
22
- export default class Video implements VideoAttributes {
23
- id: string;
24
- title: string;
25
- duration: number | null;
26
- thumbnail: string;
27
- description: string;
28
- channel: Channel;
29
- uploadDate: string;
30
- viewCount: number | null;
31
- likeCount: number | null;
32
- dislikeCount: number | null;
33
- isLiveContent: boolean;
34
- tags: string[];
35
- upNext: VideoCompact | PlaylistCompact;
36
- related: (VideoCompact | PlaylistCompact)[];
9
+ /** Represents a Video, usually returned from `client.getVideo()` */
10
+ export default class Video extends BaseVideo implements VideoAttributes {
11
+ /** The duration of this video in second */
12
+ duration: number;
13
+ /**
14
+ * Comments of this video
15
+ *
16
+ * You need to load the comment first by calling `video.nextComments()` as youtube doesn't send any comments data when loading the video (from `client.getVideo()`)
17
+ */
18
+ comments: Comment[];
19
+ /** Current continuation token to load next comments */
20
+ commentContinuation?: string;
21
+ /** @hidden */
37
22
  constructor(video?: Partial<VideoAttributes>);
38
23
  /**
39
- * Load instance attributes from youtube raw data
24
+ * Load this instance with raw data from Youtube
25
+ *
26
+ * @hidden
27
+ */
28
+ load(data: YoutubeRawData): Video;
29
+ /**
30
+ * Load next 20 comments of the video, and push the loaded comments to {@link Video.comments}
31
+ * You can only load up to 2000 comments from a video, this is due to the limitation from Youtube
32
+ *
33
+ * @example
34
+ * ```js
35
+ * const video = await youtube.getVideo(VIDEO_ID);
36
+ * await video.nextComments();
37
+ * console.log(video.comments) // first 20 comments
38
+ *
39
+ * let newComments = await video.nextComments();
40
+ * console.log(newComments) // 20 loaded comments
41
+ * console.log(video.comments) // first 40 comments
42
+ *
43
+ * await video.nextComments(0); // load the rest of the comments in the video
44
+ * ```
45
+ *
46
+ * @param count How many times to load the next comments. Set 0 to load all comments (might take a while on a video with many comments!)
40
47
  *
41
- * @param youtubeRawData raw object from youtubei
48
+ * @returns Loaded comments
42
49
  */
43
- load(youtubeRawData: YoutubeRawData): Video;
50
+ nextComments(count?: number): Promise<Comment[]>;
44
51
  }
45
52
  export {};