youtubei 0.0.1-rc.3 → 0.0.1-rc.30

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
package/README.md CHANGED
@@ -2,11 +2,16 @@
2
2
 
3
3
  `Youtubei` is made to replace my other library [scrape-yt](https://github.com/SuspiciousLookingOwl/scrape-yt/). Instead of scrapping data from Youtube page, `youtubei` fetches data by sending a request directly to `https://www.youtube.com/youtubei/v1`, which should be faster and provide more reliable result.
4
4
 
5
+ <b>Requires Node >= 12</b>
6
+
7
+ #### [Documentation](https://youtubei.netlify.app/docs)
8
+
5
9
  ## Installation
6
10
  ```
7
11
  npm i youtubei
8
12
  ```
9
13
 
14
+
10
15
  ## Example
11
16
  ```js
12
17
  const { Client } = require("youtubei");
@@ -41,8 +46,4 @@ const run = async () => {
41
46
  };
42
47
 
43
48
  run();
44
- ```
45
-
46
- ## Documentation
47
-
48
- Coming soon.
49
+ ```
@@ -0,0 +1,10 @@
1
+ import { Client } from ".";
2
+ /** @hidden */
3
+ export interface BaseAttributes {
4
+ id: string;
5
+ client: Client;
6
+ }
7
+ export default class Base implements BaseAttributes {
8
+ id: string;
9
+ client: Client;
10
+ }
@@ -1,2 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Base {
4
+ }
5
+ exports.default = Base;
@@ -0,0 +1,59 @@
1
+ import { PlaylistCompact, VideoCompact, ChannelCompact, Base, BaseAttributes, Thumbnails } from ".";
2
+ import { YoutubeRawData } from "../common";
3
+ /** @hidden */
4
+ export interface BaseVideoAttributes extends BaseAttributes {
5
+ title: string;
6
+ thumbnails: Thumbnails;
7
+ description: string;
8
+ channel: ChannelCompact;
9
+ uploadDate: string;
10
+ viewCount: number | null;
11
+ likeCount: number | null;
12
+ isLiveContent: boolean;
13
+ tags: string[];
14
+ upNext: VideoCompact | PlaylistCompact | null;
15
+ related: (VideoCompact | PlaylistCompact)[];
16
+ relatedContinuation?: string;
17
+ }
18
+ /** Represents a Video */
19
+ export default class BaseVideo extends Base implements BaseVideoAttributes {
20
+ /** The title of this video */
21
+ title: string;
22
+ /** Thumbnails of the video with different sizes */
23
+ thumbnails: Thumbnails;
24
+ /** The description of this video */
25
+ description: string;
26
+ /** The channel that uploaded this video */
27
+ channel: ChannelCompact;
28
+ /** The date this video is uploaded at */
29
+ uploadDate: string;
30
+ /** How many view does this video have, null if the view count is hidden */
31
+ viewCount: number | null;
32
+ /** How many like does this video have, null if the like count hidden */
33
+ likeCount: number | null;
34
+ /** Whether this video is a live content or not */
35
+ isLiveContent: boolean;
36
+ /** The tags of this video */
37
+ tags: string[];
38
+ /** Next video / playlist recommended by Youtube */
39
+ upNext: VideoCompact | PlaylistCompact | null;
40
+ /** Videos / playlists related to this video */
41
+ related: (VideoCompact | PlaylistCompact)[];
42
+ /** Current continuation token to load next related content */
43
+ relatedContinuation?: string;
44
+ /** @hidden */
45
+ constructor(video?: Partial<BaseVideoAttributes>);
46
+ /**
47
+ * Load this instance with raw data from Youtube
48
+ *
49
+ * @hidden
50
+ */
51
+ load(data: YoutubeRawData): BaseVideo;
52
+ /** Load next related videos / playlists */
53
+ nextRelated(count?: number): Promise<(VideoCompact | PlaylistCompact)[]>;
54
+ /** @hidden */
55
+ static parseRawData(data: YoutubeRawData): YoutubeRawData;
56
+ private static parseRelated;
57
+ private static parseCompactRenderer;
58
+ private static parseButtonRenderer;
59
+ }
@@ -0,0 +1,121 @@
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
+ const _1 = require(".");
13
+ const common_1 = require("../common");
14
+ const constants_1 = require("../constants");
15
+ /** Represents a Video */
16
+ class BaseVideo extends _1.Base {
17
+ /** @hidden */
18
+ constructor(video = {}) {
19
+ super();
20
+ /** Videos / playlists related to this video */
21
+ this.related = [];
22
+ Object.assign(this, video);
23
+ }
24
+ /**
25
+ * Load this instance with raw data from Youtube
26
+ *
27
+ * @hidden
28
+ */
29
+ load(data) {
30
+ var _a, _b, _c, _d;
31
+ const videoInfo = BaseVideo.parseRawData(data);
32
+ // Basic information
33
+ this.id = videoInfo.videoDetails.videoId;
34
+ this.title = videoInfo.videoDetails.title;
35
+ this.uploadDate = videoInfo.dateText.simpleText;
36
+ this.viewCount = +videoInfo.videoDetails.viewCount || null;
37
+ this.isLiveContent = videoInfo.videoDetails.isLiveContent;
38
+ this.thumbnails = new _1.Thumbnails().load(videoInfo.videoDetails.thumbnail.thumbnails);
39
+ // Channel
40
+ const { title, thumbnail, subscriberCountText } = videoInfo.owner.videoOwnerRenderer;
41
+ this.channel = new _1.ChannelCompact({
42
+ client: this.client,
43
+ id: title.runs[0].navigationEndpoint.browseEndpoint.browseId,
44
+ name: title.runs[0].text,
45
+ subscriberCount: subscriberCountText === null || subscriberCountText === void 0 ? void 0 : subscriberCountText.simpleText,
46
+ thumbnails: new _1.Thumbnails().load(thumbnail.thumbnails),
47
+ });
48
+ // Like Count and Dislike Count
49
+ const topLevelButtons = videoInfo.videoActions.menuRenderer.topLevelButtons;
50
+ this.likeCount = common_1.stripToInt(BaseVideo.parseButtonRenderer(topLevelButtons[0]));
51
+ // Tags and description
52
+ this.tags =
53
+ ((_b = (_a = videoInfo.superTitleLink) === null || _a === void 0 ? void 0 : _a.runs) === null || _b === void 0 ? void 0 : _b.map((r) => r.text.trim()).filter((t) => t)) || [];
54
+ this.description =
55
+ ((_c = videoInfo.description) === null || _c === void 0 ? void 0 : _c.runs.map((d) => d.text).join("")) || "";
56
+ // Up Next and related videos
57
+ this.related = [];
58
+ const secondaryContents = data[3].response.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults
59
+ .results;
60
+ if (secondaryContents) {
61
+ const upNext = ((_d = secondaryContents.find((s) => "compactAutoplayRenderer" in s)) === null || _d === void 0 ? void 0 : _d.compactAutoplayRenderer.contents[0]) || null;
62
+ this.upNext = upNext ? BaseVideo.parseCompactRenderer(upNext, this.client) : upNext;
63
+ this.related.push(...BaseVideo.parseRelated(secondaryContents, this.client));
64
+ // Related continuation
65
+ this.relatedContinuation = common_1.getContinuationFromItems(secondaryContents);
66
+ }
67
+ else {
68
+ this.upNext = null;
69
+ this.related = [];
70
+ }
71
+ return this;
72
+ }
73
+ /** Load next related videos / playlists */
74
+ nextRelated(count = 1) {
75
+ return __awaiter(this, void 0, void 0, function* () {
76
+ const newRelated = [];
77
+ for (let i = 0; i < count || count == 0; i++) {
78
+ if (this.relatedContinuation === undefined)
79
+ break;
80
+ const response = yield this.client.http.post(`${constants_1.I_END_POINT}/next`, {
81
+ data: { continuation: this.relatedContinuation },
82
+ });
83
+ const secondaryContents = response.data.onResponseReceivedEndpoints[0].appendContinuationItemsAction
84
+ .continuationItems;
85
+ newRelated.push(...BaseVideo.parseRelated(secondaryContents, this.client));
86
+ this.relatedContinuation = common_1.getContinuationFromItems(secondaryContents);
87
+ }
88
+ this.related.push(...newRelated);
89
+ return newRelated;
90
+ });
91
+ }
92
+ /** @hidden */
93
+ static parseRawData(data) {
94
+ const contents = data[3].response.contents.twoColumnWatchNextResults.results.results.contents;
95
+ const primaryInfo = contents.find((c) => "videoPrimaryInfoRenderer" in c)
96
+ .videoPrimaryInfoRenderer;
97
+ const secondaryInfo = contents.find((c) => "videoSecondaryInfoRenderer" in c).videoSecondaryInfoRenderer;
98
+ const videoDetails = data[2].playerResponse.videoDetails;
99
+ return Object.assign(Object.assign(Object.assign({}, secondaryInfo), primaryInfo), { videoDetails });
100
+ }
101
+ static parseRelated(secondaryContents, client) {
102
+ return secondaryContents
103
+ .map((c) => BaseVideo.parseCompactRenderer(c, client))
104
+ .filter((c) => c !== undefined);
105
+ }
106
+ static parseCompactRenderer(data, client) {
107
+ if ("compactVideoRenderer" in data) {
108
+ return new _1.VideoCompact({ client }).load(data.compactVideoRenderer);
109
+ }
110
+ else if ("compactRadioRenderer" in data) {
111
+ return new _1.PlaylistCompact({ client }).load(data.compactRadioRenderer);
112
+ }
113
+ }
114
+ static parseButtonRenderer(data) {
115
+ var _a;
116
+ const buttonRenderer = data.toggleButtonRenderer || data.buttonRenderer;
117
+ const accessibilityData = (((_a = buttonRenderer.defaultText) === null || _a === void 0 ? void 0 : _a.accessibility) || buttonRenderer.accessibilityData).accessibilityData;
118
+ return accessibilityData.label;
119
+ }
120
+ }
121
+ exports.default = BaseVideo;
@@ -1,37 +1,33 @@
1
- import { Thumbnail, YoutubeRawData } from "../common";
2
- import { BaseCompact, PlaylistCompact, VideoCompact } from ".";
3
- interface ChannelProperties {
4
- id: string;
5
- name: string;
6
- url: string;
7
- thumbnails: Thumbnail[];
8
- videoCount?: number;
1
+ import { YoutubeRawData } from "../common";
2
+ import ChannelCompact, { ChannelCompactAttributes } from "./ChannelCompact";
3
+ import PlaylistCompact from "./PlaylistCompact";
4
+ import Thumbnails from "./Thumbnails";
5
+ import VideoCompact from "./VideoCompact";
6
+ interface Shelf {
7
+ title: string;
8
+ subtitle?: string;
9
+ items: ChannelCompact[] | VideoCompact[] | PlaylistCompact[];
9
10
  }
10
- /**
11
- * Represent a Youtube Channel
12
- */
13
- export default class Channel extends BaseCompact implements ChannelProperties {
14
- name: string;
15
- url: string;
16
- videoCount?: number;
17
- constructor(channel?: Partial<ChannelProperties>);
18
- /**
19
- * Get videos from current Channel
20
- *
21
- * TODO: Add continuation support
22
- */
23
- getVideos(): Promise<VideoCompact[]>;
24
- /**
25
- * Get playlists from current channel
26
- *
27
- * TODO: Add continuation support
28
- */
29
- getPlaylists(): Promise<PlaylistCompact[]>;
11
+ /** @hidden */
12
+ interface ChannelAttributes extends ChannelCompactAttributes {
13
+ banner: Thumbnails;
14
+ tvBanner: Thumbnails;
15
+ mobileBanner: Thumbnails;
16
+ shelves: Shelf[];
17
+ }
18
+ /** Represents a Youtube Channel */
19
+ export default class Channel extends ChannelCompact implements ChannelAttributes {
20
+ banner: Thumbnails;
21
+ mobileBanner: Thumbnails;
22
+ tvBanner: Thumbnails;
23
+ shelves: Shelf[];
24
+ /** @hidden */
25
+ constructor(channel?: Partial<ChannelAttributes>);
30
26
  /**
31
- * Load instance attributes from youtube raw data
27
+ * Load this instance with raw data from Youtube
32
28
  *
33
- * @param youtubeRawData raw object from youtubei
29
+ * @hidden
34
30
  */
35
- load(youtubeRawData: YoutubeRawData): Channel;
31
+ load(data: YoutubeRawData): Channel;
36
32
  }
37
33
  export {};
@@ -1,145 +1,69 @@
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
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
17
- return new (P || (P = Promise))(function (resolve, reject) {
18
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
19
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
20
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
21
- step((generator = generator.apply(thisArg, _arguments || [])).next());
22
- });
23
- };
24
- var __generator = (this && this.__generator) || function (thisArg, body) {
25
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
26
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
27
- function verb(n) { return function (v) { return step([n, v]); }; }
28
- function step(op) {
29
- if (f) throw new TypeError("Generator is already executing.");
30
- while (_) try {
31
- 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;
32
- if (y = 0, t) op = [op[0] & 2, t.value];
33
- switch (op[0]) {
34
- case 0: case 1: t = op; break;
35
- case 4: _.label++; return { value: op[1], done: false };
36
- case 5: _.label++; y = op[1]; op = [0]; continue;
37
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
38
- default:
39
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
40
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
41
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
42
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
43
- if (t[2]) _.ops.pop();
44
- _.trys.pop(); continue;
45
- }
46
- op = body.call(thisArg, _);
47
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
48
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
49
- }
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
50
4
  };
51
5
  Object.defineProperty(exports, "__esModule", { value: true });
52
- var common_1 = require("../common");
53
- var _1 = require(".");
54
- var constants_1 = require("../constants");
55
- /**
56
- * Represent a Youtube Channel
57
- */
58
- var Channel = /** @class */ (function (_super) {
59
- __extends(Channel, _super);
60
- function Channel(channel) {
61
- if (channel === void 0) { channel = {}; }
62
- var _this = _super.call(this) || this;
63
- Object.assign(_this, channel);
64
- return _this;
6
+ const ChannelCompact_1 = __importDefault(require("./ChannelCompact"));
7
+ const PlaylistCompact_1 = __importDefault(require("./PlaylistCompact"));
8
+ const Thumbnails_1 = __importDefault(require("./Thumbnails"));
9
+ const VideoCompact_1 = __importDefault(require("./VideoCompact"));
10
+ /** Represents a Youtube Channel */
11
+ class Channel extends ChannelCompact_1.default {
12
+ /** @hidden */
13
+ constructor(channel = {}) {
14
+ super();
15
+ this.shelves = [];
16
+ this.videos = [];
17
+ this.playlists = [];
18
+ Object.assign(this, channel);
65
19
  }
66
20
  /**
67
- * Get videos from current Channel
68
- *
69
- * TODO: Add continuation support
70
- */
71
- Channel.prototype.getVideos = function () {
72
- return __awaiter(this, void 0, void 0, function () {
73
- var response;
74
- return __generator(this, function (_a) {
75
- switch (_a.label) {
76
- case 0: return [4 /*yield*/, common_1.axios.post(constants_1.I_END_POINT + "/browse", {
77
- browseId: this.id,
78
- params: "EgZ2aWRlb3M%3D",
79
- })];
80
- case 1:
81
- response = _a.sent();
82
- return [2 /*return*/, response.data.contents.twoColumnBrowseResultsRenderer.tabs[1].tabRenderer.content.sectionListRenderer.contents[0].itemSectionRenderer.contents[0].gridRenderer.items
83
- .filter(function (i) { return i.gridVideoRenderer; })
84
- .map(function (i) { return new _1.VideoCompact().load(i.gridVideoRenderer); })];
85
- }
86
- });
87
- });
88
- };
89
- /**
90
- * Get playlists from current channel
21
+ * Load this instance with raw data from Youtube
91
22
  *
92
- * TODO: Add continuation support
23
+ * @hidden
93
24
  */
94
- Channel.prototype.getPlaylists = function () {
95
- return __awaiter(this, void 0, void 0, function () {
96
- var response, section, gridPlaylistRenderer;
97
- return __generator(this, function (_a) {
98
- switch (_a.label) {
99
- case 0: return [4 /*yield*/, common_1.axios.post(constants_1.I_END_POINT + "/browse", {
100
- browseId: this.id,
101
- params: "EglwbGF5bGlzdHM%3D",
102
- })];
103
- case 1:
104
- response = _a.sent();
105
- section = response.data.contents.twoColumnBrowseResultsRenderer.tabs[2].tabRenderer.content
106
- .sectionListRenderer;
107
- // Has category
108
- if ("shelfRenderer" in section.contents[0].itemSectionRenderer.contents[0]) {
109
- gridPlaylistRenderer = section.contents
110
- .map(function (c) {
111
- return c.itemSectionRenderer.contents[0].shelfRenderer.content
112
- .horizontalListRenderer.items;
113
- })
114
- .flat();
115
- }
116
- else {
117
- gridPlaylistRenderer =
118
- section.contents[0].itemSectionRenderer.contents[0].gridRenderer.items;
119
- }
120
- return [2 /*return*/, gridPlaylistRenderer.map(function (i) {
121
- return new _1.PlaylistCompact().load(i.gridPlaylistRenderer);
122
- })];
123
- }
124
- });
125
- });
126
- };
127
- /**
128
- * Load instance attributes from youtube raw data
129
- *
130
- * @param youtubeRawData raw object from youtubei
131
- */
132
- Channel.prototype.load = function (youtubeRawData) {
133
- var _a;
134
- var channelId = youtubeRawData.channelId, title = youtubeRawData.title, thumbnail = youtubeRawData.thumbnail, videoCountText = youtubeRawData.videoCountText, navigationEndpoint = youtubeRawData.navigationEndpoint;
135
- var _b = navigationEndpoint.browseEndpoint, browseId = _b.browseId, canonicalBaseUrl = _b.canonicalBaseUrl;
25
+ load(data) {
26
+ const { channelId, title, avatar, subscriberCountText, } = data.header.c4TabbedHeaderRenderer;
136
27
  this.id = channelId;
137
- this.name = title.simpleText;
138
- this.thumbnails = thumbnail.thumbnails;
139
- this.url = "https://www.youtube.com" + (canonicalBaseUrl || "/channel/" + browseId);
140
- this.videoCount = (_a = +(videoCountText === null || videoCountText === void 0 ? void 0 : videoCountText.runs[0].text.replace(/[^0-9]/g, ""))) !== null && _a !== void 0 ? _a : 0;
28
+ this.name = title;
29
+ this.thumbnails = new Thumbnails_1.default().load(avatar.thumbnails);
30
+ this.videoCount = 0; // data not available
31
+ this.subscriberCount = subscriberCountText.simpleText;
32
+ this.videos = [];
33
+ this.playlists = [];
34
+ const { tvBanner, mobileBanner, banner } = data.header.c4TabbedHeaderRenderer;
35
+ this.banner = new Thumbnails_1.default().load(banner.thumbnails);
36
+ this.tvBanner = new Thumbnails_1.default().load(tvBanner.thumbnails);
37
+ this.mobileBanner = new Thumbnails_1.default().load(mobileBanner.thumbnails);
38
+ // shelves
39
+ const rawShelves = data.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content
40
+ .sectionListRenderer.contents;
41
+ for (const rawShelf of rawShelves) {
42
+ const shelfRenderer = rawShelf.itemSectionRenderer.contents[0].shelfRenderer;
43
+ if (!shelfRenderer)
44
+ continue;
45
+ const { title, content, subtitle } = shelfRenderer;
46
+ if (!content.horizontalListRenderer)
47
+ continue;
48
+ const items = content.horizontalListRenderer.items
49
+ .map((i) => {
50
+ if (i.gridVideoRenderer)
51
+ return new VideoCompact_1.default({ client: this.client }).load(i.gridVideoRenderer);
52
+ if (i.gridPlaylistRenderer)
53
+ return new PlaylistCompact_1.default({ client: this.client }).load(i.gridPlaylistRenderer);
54
+ if (i.gridChannelRenderer)
55
+ return new ChannelCompact_1.default({ client: this.client }).load(i.gridChannelRenderer);
56
+ return undefined;
57
+ })
58
+ .filter((i) => i !== undefined);
59
+ const shelf = {
60
+ title: title.runs[0].text,
61
+ subtitle: subtitle === null || subtitle === void 0 ? void 0 : subtitle.simpleText,
62
+ items,
63
+ };
64
+ this.shelves.push(shelf);
65
+ }
141
66
  return this;
142
- };
143
- return Channel;
144
- }(_1.BaseCompact));
67
+ }
68
+ }
145
69
  exports.default = Channel;
@@ -1,39 +1,90 @@
1
1
  import { YoutubeRawData } from "../common";
2
- import { PlaylistCompact, VideoCompact } from ".";
3
- interface ChannelCompactProperties {
4
- id: string;
2
+ import { Base, PlaylistCompact, Thumbnails, VideoCompact, BaseAttributes } from ".";
3
+ /** @hidden */
4
+ export interface ChannelCompactAttributes extends BaseAttributes {
5
5
  name: string;
6
- url: string;
7
- thumbnail?: string;
6
+ thumbnails?: Thumbnails;
8
7
  videoCount?: number;
8
+ subscriberCount?: string;
9
+ videoContinuation?: string | null;
10
+ playlistContinuation?: string | null;
9
11
  }
10
- /**
11
- * Represent a Youtube Channel
12
- */
13
- export default class ChannelCompact implements ChannelCompactProperties {
14
- id: string;
12
+ /** Represents a Youtube Channel */
13
+ export default class ChannelCompact extends Base implements ChannelCompactAttributes {
14
+ /** The channel's name */
15
15
  name: string;
16
- url: string;
17
- thumbnail?: string;
16
+ /** Thumbnails of the Channel with different sizes */
17
+ thumbnails?: Thumbnails;
18
+ /** How many video does this channel have */
18
19
  videoCount?: number;
19
- constructor(channel?: Partial<ChannelCompactProperties>);
20
20
  /**
21
- * Get videos from current Channel
21
+ * How many subscriber does this channel have,
22
22
  *
23
- * TODO: Add continuation support
23
+ * This is not the exact amount, but a literal string like `"1.95M subscribers"`
24
24
  */
25
- getVideos(): Promise<VideoCompact[]>;
25
+ subscriberCount?: string;
26
+ /** Loaded videos on the channel, fetched from `channel.nextVideos()` */
27
+ videos: VideoCompact[];
28
+ /** Loaded playlists on the channel, fetched from `channel.nextPlaylists()` */
29
+ playlists: PlaylistCompact[];
30
+ /** Current continuation token to load next videos */
31
+ videoContinuation?: string | null;
32
+ /** Current continuation token to load next playlists */
33
+ playlistContinuation?: string | null;
34
+ /** @hidden */
35
+ constructor(channel?: Partial<ChannelCompactAttributes>);
36
+ /** The URL of the channel page */
37
+ get url(): string;
26
38
  /**
27
- * Get playlists from current channel
39
+ * Load this instance with raw data from Youtube
28
40
  *
29
- * TODO: Add continuation support
41
+ * @hidden
30
42
  */
31
- getPlaylists(): Promise<PlaylistCompact[]>;
43
+ load(data: YoutubeRawData): ChannelCompact;
32
44
  /**
33
- * Load instance attributes from youtube raw data
45
+ * Load next 30 videos made by the channel, and push the loaded videos to {@link Channel.videos}
34
46
  *
35
- * @param youtubeRawData raw object from youtubei
47
+ * @example
48
+ * ```js
49
+ * const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
50
+ * await channel.nextVideos();
51
+ * console.log(channel.videos) // first 30 videos
52
+ *
53
+ * let newVideos = await channel.nextVideos();
54
+ * console.log(newVideos) // 30 loaded videos
55
+ * console.log(channel.videos) // first 60 videos
56
+ *
57
+ * await channel.nextVideos(0); // load the rest of the videos in the channel
58
+ * ```
59
+ *
60
+ * @param count How many time to load the next videos, pass `0` to load all
61
+ *
62
+ * @return New loaded videos
63
+ */
64
+ nextVideos(count?: number): Promise<VideoCompact[]>;
65
+ /**
66
+ * Load next 30 playlists made by the channel, and push the loaded playlists to {@link Channel.playlists}
67
+ *
68
+ * @example
69
+ * ```js
70
+ * const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
71
+ * await channel.nextPlaylists();
72
+ * console.log(channel.playlists) // first 30 playlists
73
+ *
74
+ * let newPlaylists = await channel.nextPlaylists();
75
+ * console.log(newPlaylists) // 30 loaded playlists
76
+ * console.log(channel.playlists) // first 60 playlists
77
+ *
78
+ * await channel.nextPlaylists(0); // load the rest of the playlists in the channel
79
+ * ```
80
+ *
81
+ * @param count How many time to load the next playlists, pass `0` to load all
82
+ *
83
+ * @return New loaded playlists
36
84
  */
37
- load(youtubeRawData: YoutubeRawData): ChannelCompact;
85
+ nextPlaylists(count?: number): Promise<PlaylistCompact[]>;
86
+ /** Get tab data from youtube */
87
+ private getTabData;
88
+ /** Parse tab data from request, tab name is ignored if it's a continuation data */
89
+ private static parseTabData;
38
90
  }
39
- export {};