youtubei 1.7.0 → 1.8.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.
Files changed (42) hide show
  1. package/dist/cjs/music/MusicClient/MusicClient.js +13 -18
  2. package/dist/cjs/music/MusicSearchResult/MusicSearchResult.js +6 -4
  3. package/dist/cjs/music/MusicSearchResult/MusicSearchResultParser.js +205 -14
  4. package/dist/cjs/music/MusicSearchResult/index.js +0 -1
  5. package/dist/cjs/youtube/BaseChannel/BaseChannel.js +2 -0
  6. package/dist/cjs/youtube/BaseChannel/BaseChannelParser.js +3 -2
  7. package/dist/cjs/youtube/BaseChannel/ChannelPlaylists.js +12 -2
  8. package/dist/cjs/youtube/BaseChannel/ChannelPosts.js +59 -0
  9. package/dist/cjs/youtube/BaseVideo/BaseVideoParser.js +1 -1
  10. package/dist/cjs/youtube/Channel/ChannelParser.js +10 -6
  11. package/dist/cjs/youtube/PlaylistCompact/PlaylistCompactParser.js +3 -3
  12. package/dist/cjs/youtube/Post/Post.js +23 -0
  13. package/dist/cjs/youtube/Post/PostParser.js +23 -0
  14. package/dist/cjs/youtube/Post/index.js +14 -0
  15. package/dist/esm/music/MusicClient/MusicClient.js +16 -20
  16. package/dist/esm/music/MusicSearchResult/MusicSearchResult.js +5 -4
  17. package/dist/esm/music/MusicSearchResult/MusicSearchResultParser.js +221 -14
  18. package/dist/esm/music/MusicSearchResult/index.js +0 -1
  19. package/dist/esm/youtube/BaseChannel/BaseChannel.js +2 -0
  20. package/dist/esm/youtube/BaseChannel/BaseChannelParser.js +3 -2
  21. package/dist/esm/youtube/BaseChannel/ChannelPlaylists.js +11 -3
  22. package/dist/esm/youtube/BaseChannel/ChannelPosts.js +111 -0
  23. package/dist/esm/youtube/BaseVideo/BaseVideoParser.js +1 -1
  24. package/dist/esm/youtube/Channel/ChannelParser.js +12 -8
  25. package/dist/esm/youtube/PlaylistCompact/PlaylistCompactParser.js +3 -3
  26. package/dist/esm/youtube/Post/Post.js +36 -0
  27. package/dist/esm/youtube/Post/PostParser.js +23 -0
  28. package/dist/esm/youtube/Post/index.js +2 -0
  29. package/dist/typings/music/MusicClient/MusicClient.d.ts +3 -7
  30. package/dist/typings/music/MusicSearchResult/MusicSearchResult.d.ts +7 -4
  31. package/dist/typings/music/MusicSearchResult/MusicSearchResultParser.d.ts +15 -3
  32. package/dist/typings/music/MusicSearchResult/index.d.ts +0 -1
  33. package/dist/typings/youtube/BaseChannel/BaseChannel.d.ts +4 -1
  34. package/dist/typings/youtube/BaseChannel/BaseChannelParser.d.ts +1 -0
  35. package/dist/typings/youtube/BaseChannel/ChannelPosts.d.ts +30 -0
  36. package/dist/typings/youtube/Post/Post.d.ts +32 -0
  37. package/dist/typings/youtube/Post/PostParser.d.ts +5 -0
  38. package/dist/typings/youtube/Post/index.d.ts +2 -0
  39. package/package.json +1 -1
  40. package/dist/cjs/music/MusicSearchResult/MusicAllSearchResultParser.js +0 -218
  41. package/dist/esm/music/MusicSearchResult/MusicAllSearchResultParser.js +0 -234
  42. package/dist/typings/music/MusicSearchResult/MusicAllSearchResultParser.d.ts +0 -19
@@ -20,19 +20,18 @@ class MusicClient {
20
20
  const fullOptions = Object.assign(Object.assign({ initialCookie: "", oauth: { enabled: false }, fetchOptions: {} }, options), { youtubeClientOptions: Object.assign({ hl: "en", gl: "US" }, options.youtubeClientOptions), apiKey: options.apiKey || constants_1.INNERTUBE_API_KEY, baseUrl: options.baseUrl || constants_1.BASE_URL, clientName: options.clientName || constants_1.INNERTUBE_CLIENT_NAME, clientVersion: options.clientVersion || constants_1.INNERTUBE_CLIENT_VERSION });
21
21
  this.http = new common_1.HTTP(fullOptions);
22
22
  }
23
+ /**
24
+ * Searches for video, song, album, playlist, or artist
25
+ *
26
+ * @param query The search query
27
+ * @param type Search type
28
+ *
29
+ */
23
30
  search(query, type) {
24
31
  return __awaiter(this, void 0, void 0, function* () {
25
- if (!type) {
26
- const response = yield this.http.post(`${constants_1.I_END_POINT}/search`, {
27
- data: { query },
28
- });
29
- return MusicSearchResult_1.MusicAllSearchResultParser.parseSearchResult(response.data, this);
30
- }
31
- else {
32
- const result = new MusicSearchResult_1.MusicSearchResult({ client: this });
33
- yield result.search(query, type);
34
- return result;
35
- }
32
+ const result = new MusicSearchResult_1.MusicSearchResult({ client: this });
33
+ yield result.search(query, type);
34
+ return result;
36
35
  });
37
36
  }
38
37
  /**
@@ -42,13 +41,9 @@ class MusicClient {
42
41
  */
43
42
  searchAll(query) {
44
43
  return __awaiter(this, void 0, void 0, function* () {
45
- const response = yield this.http.post(`${constants_1.I_END_POINT}/search`, {
46
- data: { query },
47
- });
48
- return {
49
- top: MusicSearchResult_1.MusicAllSearchResultParser.parseTopResult(response.data, this),
50
- shelves: MusicSearchResult_1.MusicAllSearchResultParser.parseSearchResult(response.data, this),
51
- };
44
+ const result = new MusicSearchResult_1.MusicSearchResult({ client: this });
45
+ yield result.search(query);
46
+ return result;
52
47
  });
53
48
  }
54
49
  /**
@@ -60,14 +60,16 @@ class MusicSearchResult extends MusicContinuable_1.MusicContinuable {
60
60
  return __awaiter(this, void 0, void 0, function* () {
61
61
  this.items = [];
62
62
  this.type = type;
63
- const bufferParams = proto_1.MusicSearchProto.encode(proto_1.optionsToProto(type)).finish();
63
+ let bufferParams;
64
+ if (type)
65
+ bufferParams = proto_1.MusicSearchProto.encode(proto_1.optionsToProto(type)).finish();
64
66
  const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
65
67
  data: {
66
68
  query,
67
- params: Buffer.from(bufferParams).toString("base64"),
69
+ params: bufferParams ? Buffer.from(bufferParams).toString("base64") : undefined,
68
70
  },
69
71
  });
70
- const { data, continuation } = MusicSearchResultParser_1.MusicSearchResultParser.parseInitialSearchResult(response.data, type, this.client);
72
+ const { data, continuation } = MusicSearchResultParser_1.MusicSearchResultParser.parseInitialSearchResult(response.data, this.client);
71
73
  this.items.push(...data);
72
74
  this.continuation = continuation;
73
75
  return this;
@@ -84,7 +86,7 @@ class MusicSearchResult extends MusicContinuable_1.MusicContinuable {
84
86
  const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
85
87
  data: { continuation: this.continuation },
86
88
  });
87
- const { data, continuation } = MusicSearchResultParser_1.MusicSearchResultParser.parseContinuationSearchResult(response.data, this.type, this.client);
89
+ const { data, continuation } = MusicSearchResultParser_1.MusicSearchResultParser.parseContinuationSearchResult(response.data, this.client);
88
90
  return {
89
91
  items: data,
90
92
  continuation,
@@ -1,42 +1,233 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MusicSearchResultParser = void 0;
4
- const MusicAllSearchResultParser_1 = require("./MusicAllSearchResultParser");
4
+ const common_1 = require("../../common");
5
+ const MusicAlbumCompact_1 = require("../MusicAlbumCompact");
6
+ const MusicArtistCompact_1 = require("../MusicArtistCompact");
7
+ const MusicBaseArtist_1 = require("../MusicBaseArtist");
8
+ const MusicBaseChannel_1 = require("../MusicBaseChannel");
9
+ const MusicPlaylistCompact_1 = require("../MusicPlaylistCompact");
10
+ const MusicSongCompact_1 = require("../MusicSongCompact");
11
+ const MusicVideoCompact_1 = require("../MusicVideoCompact");
5
12
  class MusicSearchResultParser {
6
- static parseInitialSearchResult(data, type, client) {
13
+ static parseInitialSearchResult(data, client) {
7
14
  var _a, _b;
8
- const contentSection = data.contents.tabbedSearchResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents.find((c) => "musicShelfRenderer" in c);
9
- if (!contentSection) {
15
+ const sectionContents = data.contents.tabbedSearchResultsRenderer.tabs[0].tabRenderer.content
16
+ .sectionListRenderer.contents;
17
+ const topContent = sectionContents.find((c) => "musicCardShelfRenderer" in c);
18
+ const resultContents = sectionContents.find((c) => "musicShelfRenderer" in c);
19
+ const topResult = this.parseTopResult(topContent, client);
20
+ if (!resultContents) {
10
21
  // no results
11
22
  return {
12
- data: [],
23
+ data: topResult ? [topResult] : [],
13
24
  continuation: undefined,
14
25
  };
15
26
  }
16
- const { contents, continuations } = contentSection.musicShelfRenderer;
27
+ const { contents, continuations } = resultContents.musicShelfRenderer;
28
+ const result = MusicSearchResultParser.parseSearchResult(contents, client);
29
+ if (topResult)
30
+ result.unshift(topResult);
17
31
  return {
18
- data: MusicSearchResultParser.parseSearchResult(contents, type, client),
32
+ data: result,
19
33
  continuation: (_b = (_a = continuations === null || continuations === void 0 ? void 0 : continuations[0]) === null || _a === void 0 ? void 0 : _a.nextContinuationData) === null || _b === void 0 ? void 0 : _b.continuation,
20
34
  };
21
35
  }
22
- static parseContinuationSearchResult(data, type, client) {
36
+ static parseContinuationSearchResult(data, client) {
23
37
  const shelf = data.continuationContents.musicShelfContinuation;
24
38
  return {
25
- data: MusicSearchResultParser.parseSearchResult(shelf.contents, type, client),
39
+ data: MusicSearchResultParser.parseSearchResult(shelf.contents, client),
26
40
  continuation: shelf.continuations[0].nextContinuationData.continuation,
27
41
  };
28
42
  }
29
- static parseSearchResult(shelfContents, type, client) {
30
- const rawContents = shelfContents
31
- .filter((c) => "musicResponsiveListItemRenderer" in c)
32
- .map((c) => c.musicResponsiveListItemRenderer);
43
+ static parseTopResult(data, client) {
44
+ const top = data === null || data === void 0 ? void 0 : data.musicCardShelfRenderer;
45
+ if (!top)
46
+ return;
47
+ const { browseEndpoint, watchEndpoint } = top.title.runs[0].navigationEndpoint;
48
+ const id = (watchEndpoint === null || watchEndpoint === void 0 ? void 0 : watchEndpoint.videoId) || (browseEndpoint === null || browseEndpoint === void 0 ? void 0 : browseEndpoint.browseId);
49
+ const type = (watchEndpoint === null || watchEndpoint === void 0 ? void 0 : watchEndpoint.watchEndpointMusicSupportedConfigs.watchEndpointMusicConfig.musicVideoType) || (browseEndpoint === null || browseEndpoint === void 0 ? void 0 : browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType);
50
+ const title = top.title.runs[0].text;
51
+ const thumbnail = top.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails;
52
+ let topResult;
53
+ if (type === "MUSIC_VIDEO_TYPE_ATV") {
54
+ topResult = new MusicSongCompact_1.MusicSongCompact({
55
+ client,
56
+ id,
57
+ title,
58
+ duration: common_1.getDuration(top.subtitle.runs.at(-1).text),
59
+ artists: this.parseArtists(top.subtitle.runs, client),
60
+ album: this.parseAlbum(top.subtitle.runs, client),
61
+ thumbnails: new common_1.Thumbnails().load(thumbnail),
62
+ });
63
+ }
64
+ else if (type === "MUSIC_VIDEO_TYPE_UGC" || type === "MUSIC_VIDEO_TYPE_OMV") {
65
+ topResult = new MusicVideoCompact_1.MusicVideoCompact({
66
+ client,
67
+ id,
68
+ title,
69
+ duration: common_1.getDuration(top.subtitle.runs.at(-1).text),
70
+ artists: this.parseArtists(top.subtitle.runs, client),
71
+ thumbnails: new common_1.Thumbnails().load(thumbnail),
72
+ });
73
+ }
74
+ else if (type === "MUSIC_PAGE_TYPE_ALBUM") {
75
+ topResult = new MusicAlbumCompact_1.MusicAlbumCompact({
76
+ client,
77
+ id,
78
+ title,
79
+ artists: this.parseArtists(top.subtitle.runs, client),
80
+ thumbnails: new common_1.Thumbnails().load(thumbnail),
81
+ });
82
+ }
83
+ else if (type === "MUSIC_PAGE_TYPE_ARTIST") {
84
+ topResult = new MusicArtistCompact_1.MusicArtistCompact({
85
+ client,
86
+ id,
87
+ name: title,
88
+ thumbnails: new common_1.Thumbnails().load(thumbnail),
89
+ });
90
+ }
91
+ else if (type === "MUSIC_PAGE_TYPE_PLAYLIST") {
92
+ topResult = new MusicPlaylistCompact_1.MusicPlaylistCompact({
93
+ client,
94
+ id,
95
+ title,
96
+ channel: this.parseChannel(top.subtitle.runs, client),
97
+ thumbnails: new common_1.Thumbnails().load(thumbnail),
98
+ });
99
+ }
100
+ return topResult;
101
+ }
102
+ static parseSearchResult(shelfContents, client) {
103
+ const rawContents = shelfContents.filter((c) => "musicResponsiveListItemRenderer" in c);
33
104
  const contents = [];
34
105
  for (const c of rawContents) {
35
- const parsed = MusicAllSearchResultParser_1.MusicAllSearchResultParser.parseVideoItem(c, type === "video" ? "MUSIC_VIDEO_TYPE_UGC" : "MUSIC_VIDEO_TYPE_ATV", client);
106
+ const parsed = this.parseSearchItem(c, client);
36
107
  if (parsed)
37
108
  contents.push(parsed);
38
109
  }
39
110
  return contents;
40
111
  }
112
+ static parseSearchItem(content, client) {
113
+ var _a;
114
+ const item = content.musicResponsiveListItemRenderer;
115
+ const playEndpoint = (_a = item.overlay) === null || _a === void 0 ? void 0 : _a.musicItemThumbnailOverlayRenderer.content.musicPlayButtonRenderer.playNavigationEndpoint;
116
+ if (playEndpoint === null || playEndpoint === void 0 ? void 0 : playEndpoint.watchEndpoint) {
117
+ const pageType = playEndpoint.watchEndpoint.watchEndpointMusicSupportedConfigs
118
+ .watchEndpointMusicConfig.musicVideoType;
119
+ return this.parseVideoItem(item, pageType, client);
120
+ }
121
+ else if (playEndpoint === null || playEndpoint === void 0 ? void 0 : playEndpoint.watchPlaylistEndpoint.params) {
122
+ return this.parsePlaylistItem(item, client);
123
+ }
124
+ else if (playEndpoint === null || playEndpoint === void 0 ? void 0 : playEndpoint.watchPlaylistEndpoint) {
125
+ // TODO add podcast support, id starts with PL
126
+ if (playEndpoint.watchPlaylistEndpoint.playlistId.startsWith("OL")) {
127
+ return this.parseAlbumItem(item, client);
128
+ }
129
+ }
130
+ else {
131
+ return this.parseArtistItem(item, client);
132
+ }
133
+ }
134
+ static parseVideoItem(item, pageType, client) {
135
+ // TODO support other types
136
+ if (!["MUSIC_VIDEO_TYPE_ATV", "MUSIC_VIDEO_TYPE_UGC", "MUSIC_VIDEO_TYPE_OMV"].includes(pageType)) {
137
+ return;
138
+ }
139
+ const [topColumn, bottomColumn] = item.flexColumns.map((c) => c.musicResponsiveListItemFlexColumnRenderer.text.runs);
140
+ const id = topColumn[0].navigationEndpoint.watchEndpoint.videoId;
141
+ const title = topColumn[0].text;
142
+ const duration = common_1.getDuration(bottomColumn.at(-1).text) || undefined;
143
+ const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
144
+ const artists = this.parseArtists(bottomColumn, client);
145
+ if (pageType === "MUSIC_VIDEO_TYPE_ATV") {
146
+ return new MusicSongCompact_1.MusicSongCompact({
147
+ client,
148
+ id,
149
+ album: this.parseAlbum(bottomColumn, client),
150
+ title,
151
+ artists,
152
+ thumbnails,
153
+ duration,
154
+ });
155
+ }
156
+ else if (pageType === "MUSIC_VIDEO_TYPE_UGC" || pageType === "MUSIC_VIDEO_TYPE_OMV") {
157
+ return new MusicVideoCompact_1.MusicVideoCompact({ client, id, title, artists, thumbnails, duration });
158
+ }
159
+ }
160
+ static parsePlaylistItem(item, client) {
161
+ const [topColumn, bottomColumn] = item.flexColumns.map((c) => c.musicResponsiveListItemFlexColumnRenderer.text.runs);
162
+ const id = item.overlay.musicItemThumbnailOverlayRenderer.content.musicPlayButtonRenderer
163
+ .playNavigationEndpoint.watchPlaylistEndpoint.playlistId;
164
+ const title = topColumn[0].text;
165
+ const songCount = common_1.stripToInt(bottomColumn.at(-1).text) || undefined;
166
+ const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
167
+ const channel = this.parseChannel(bottomColumn, client);
168
+ return new MusicPlaylistCompact_1.MusicPlaylistCompact({ client, id, title, thumbnails, songCount, channel });
169
+ }
170
+ static parseAlbumItem(item, client) {
171
+ const [topColumn, bottomColumn] = item.flexColumns.map((c) => c.musicResponsiveListItemFlexColumnRenderer.text.runs);
172
+ const id = item.overlay.musicItemThumbnailOverlayRenderer.content.musicPlayButtonRenderer
173
+ .playNavigationEndpoint.watchPlaylistEndpoint.playlistId;
174
+ const title = topColumn[0].text;
175
+ const year = common_1.stripToInt(bottomColumn.at(-1).text) || undefined;
176
+ const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
177
+ const artists = this.parseArtists(bottomColumn, client);
178
+ return new MusicAlbumCompact_1.MusicAlbumCompact({ client, id, title, thumbnails, artists, year });
179
+ }
180
+ static parseArtistItem(item, client) {
181
+ const [topColumn] = item.flexColumns.map((c) => c.musicResponsiveListItemFlexColumnRenderer.text.runs);
182
+ const id = item.navigationEndpoint.browseEndpoint.browseId;
183
+ const name = topColumn[0].text;
184
+ const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
185
+ return new MusicArtistCompact_1.MusicArtistCompact({ client, id, name, thumbnails });
186
+ }
187
+ static parseAlbum(items, client) {
188
+ var _a;
189
+ const albumRaw = items.find((r) => {
190
+ var _a;
191
+ const pageType = (_a = r.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType;
192
+ return pageType === "MUSIC_PAGE_TYPE_ALBUM";
193
+ });
194
+ if (!albumRaw)
195
+ return;
196
+ const album = new MusicAlbumCompact_1.MusicAlbumCompact({
197
+ client,
198
+ title: albumRaw.text,
199
+ id: (_a = albumRaw.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseId,
200
+ });
201
+ return album;
202
+ }
203
+ static parseArtists(items, client) {
204
+ return this.parseArtistsOrChannel(items).map((r) => {
205
+ var _a;
206
+ return new MusicBaseArtist_1.MusicBaseArtist({
207
+ client,
208
+ name: r.text,
209
+ id: (_a = r.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseId,
210
+ });
211
+ });
212
+ }
213
+ static parseChannel(items, client) {
214
+ var _a;
215
+ const [channelRaw] = this.parseArtistsOrChannel(items);
216
+ if (!channelRaw)
217
+ return;
218
+ const channel = new MusicBaseChannel_1.MusicBaseChannel({
219
+ client,
220
+ name: channelRaw.text,
221
+ id: (_a = channelRaw.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseId,
222
+ });
223
+ return channel;
224
+ }
225
+ static parseArtistsOrChannel(items) {
226
+ return items.filter((i) => {
227
+ var _a;
228
+ const pageType = (_a = i.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType;
229
+ return (pageType === "MUSIC_PAGE_TYPE_ARTIST" || pageType == "MUSIC_PAGE_TYPE_USER_CHANNEL");
230
+ });
231
+ }
41
232
  }
42
233
  exports.MusicSearchResultParser = MusicSearchResultParser;
@@ -10,6 +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("./MusicAllSearchResultParser"), exports);
14
13
  __exportStar(require("./MusicSearchResult"), exports);
15
14
  __exportStar(require("./MusicSearchResultParser"), exports);
@@ -5,6 +5,7 @@ const Base_1 = require("../Base");
5
5
  const BaseChannelParser_1 = require("./BaseChannelParser");
6
6
  const ChannelLive_1 = require("./ChannelLive");
7
7
  const ChannelPlaylists_1 = require("./ChannelPlaylists");
8
+ const ChannelPosts_1 = require("./ChannelPosts");
8
9
  const ChannelShorts_1 = require("./ChannelShorts");
9
10
  const ChannelVideos_1 = require("./ChannelVideos");
10
11
  /** Represents a Youtube Channel */
@@ -17,6 +18,7 @@ class BaseChannel extends Base_1.Base {
17
18
  this.shorts = new ChannelShorts_1.ChannelShorts({ channel: this, client: this.client });
18
19
  this.live = new ChannelLive_1.ChannelLive({ channel: this, client: this.client });
19
20
  this.playlists = new ChannelPlaylists_1.ChannelPlaylists({ channel: this, client: this.client });
21
+ this.posts = new ChannelPosts_1.ChannelPosts({ channel: this, client: this.client });
20
22
  }
21
23
  /** The URL of the channel page */
22
24
  get url() {
@@ -13,13 +13,13 @@ class BaseChannelParser {
13
13
  }
14
14
  /** Parse tab data from request, tab name is ignored if it's a continuation data */
15
15
  static parseTabData(name, data) {
16
- var _a, _b, _c, _d, _e;
16
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
17
17
  const tab = (_a = data.contents) === null || _a === void 0 ? void 0 : _a.twoColumnBrowseResultsRenderer.tabs.find((t) => {
18
18
  var _a;
19
19
  return (((_a = t.tabRenderer) === null || _a === void 0 ? void 0 : _a.endpoint.browseEndpoint.params) ===
20
20
  BaseChannelParser.TAB_TYPE_PARAMS[name]);
21
21
  });
22
- return (((_d = (_c = (_b = tab === null || tab === void 0 ? void 0 : tab.tabRenderer.content.sectionListRenderer) === null || _b === void 0 ? void 0 : _b.contents) === null || _c === void 0 ? void 0 : _c[0].itemSectionRenderer.contents[0].gridRenderer) === null || _d === void 0 ? void 0 : _d.items) || (tab === null || tab === void 0 ? void 0 : tab.tabRenderer.content.richGridRenderer.contents.map((c) => { var _a; return ((_a = c.richItemRenderer) === null || _a === void 0 ? void 0 : _a.content) || c; })) || ((_e = data.onResponseReceivedActions) === null || _e === void 0 ? void 0 : _e[0].appendContinuationItemsAction.continuationItems.map((c) => { var _a; return ((_a = c.richItemRenderer) === null || _a === void 0 ? void 0 : _a.content) || c; })) ||
22
+ return (((_d = (_c = (_b = tab === null || tab === void 0 ? void 0 : tab.tabRenderer.content.sectionListRenderer) === null || _b === void 0 ? void 0 : _b.contents) === null || _c === void 0 ? void 0 : _c[0].itemSectionRenderer.contents[0].gridRenderer) === null || _d === void 0 ? void 0 : _d.items) || ((_h = (_g = (_f = (_e = tab === null || tab === void 0 ? void 0 : tab.tabRenderer.content) === null || _e === void 0 ? void 0 : _e.sectionListRenderer) === null || _f === void 0 ? void 0 : _f.contents) === null || _g === void 0 ? void 0 : _g[0].itemSectionRenderer) === null || _h === void 0 ? void 0 : _h.contents) || (tab === null || tab === void 0 ? void 0 : tab.tabRenderer.content.richGridRenderer.contents.map((c) => { var _a; return ((_a = c.richItemRenderer) === null || _a === void 0 ? void 0 : _a.content) || c; })) || ((_j = data.onResponseReceivedActions) === null || _j === void 0 ? void 0 : _j[0].appendContinuationItemsAction.continuationItems.map((c) => { var _a; return ((_a = c.richItemRenderer) === null || _a === void 0 ? void 0 : _a.content) || c; })) || ((_k = data.onResponseReceivedEndpoints) === null || _k === void 0 ? void 0 : _k[0].appendContinuationItemsAction.continuationItems) ||
23
23
  []);
24
24
  }
25
25
  }
@@ -29,4 +29,5 @@ BaseChannelParser.TAB_TYPE_PARAMS = {
29
29
  shorts: "EgZzaG9ydHPyBgUKA5oBAA%3D%3D",
30
30
  live: "EgdzdHJlYW1z8gYECgJ6AA%3D%3D",
31
31
  playlists: "EglwbGF5bGlzdHPyBgQKAkIA",
32
+ posts: "EgVwb3N0c_IGBAoCSgA%3D",
32
33
  };
@@ -46,10 +46,20 @@ class ChannelPlaylists extends Continuable_1.Continuable {
46
46
  });
47
47
  const items = BaseChannelParser_1.BaseChannelParser.parseTabData("playlists", response.data);
48
48
  const continuation = common_1.getContinuationFromItems(items);
49
- const data = common_1.mapFilter(items, "gridPlaylistRenderer");
49
+ const data = items.filter((i) => "gridPlaylistRenderer" in i || "lockupViewModel" in i);
50
50
  return {
51
51
  continuation,
52
- items: data.map((i) => new PlaylistCompact_1.PlaylistCompact({ client: this.client, channel: this.channel }).load(i)),
52
+ items: data.map((i) => {
53
+ const playlist = new PlaylistCompact_1.PlaylistCompact({
54
+ client: this.client,
55
+ channel: this.channel,
56
+ });
57
+ if (i.gridPlaylistRenderer)
58
+ playlist.load(i.gridPlaylistRenderer);
59
+ else if (i.lockupViewModel)
60
+ playlist.loadLockup(i.lockupViewModel);
61
+ return playlist;
62
+ }),
53
63
  };
54
64
  });
55
65
  }
@@ -0,0 +1,59 @@
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.ChannelPosts = void 0;
13
+ const common_1 = require("../../common");
14
+ const Continuable_1 = require("../Continuable");
15
+ const Post_1 = require("../Post");
16
+ const constants_1 = require("../constants");
17
+ const BaseChannelParser_1 = require("./BaseChannelParser");
18
+ /**
19
+ * {@link Continuable} of posts inside a {@link BaseChannel}
20
+ *
21
+ * @example
22
+ * ```js
23
+ * const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
24
+ * await channel.posts.next();
25
+ * console.log(channel.posts.items) // first 30 posts
26
+ *
27
+ * let newPosts = await channel.posts.next();
28
+ * console.log(newPosts) // 30 loaded posts
29
+ * console.log(channel.posts.items) // first 60 posts
30
+ *
31
+ * await channel.posts.next(0); // load the rest of the posts in the channel
32
+ * ```
33
+ */
34
+ class ChannelPosts extends Continuable_1.Continuable {
35
+ /** @hidden */
36
+ constructor({ client, channel }) {
37
+ super({ client, strictContinuationCheck: true });
38
+ this.channel = channel;
39
+ }
40
+ fetch() {
41
+ var _a;
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const params = BaseChannelParser_1.BaseChannelParser.TAB_TYPE_PARAMS.posts;
44
+ const response = yield this.client.http.post(`${constants_1.I_END_POINT}/browse`, {
45
+ data: { browseId: (_a = this.channel) === null || _a === void 0 ? void 0 : _a.id, params, continuation: this.continuation },
46
+ });
47
+ const items = BaseChannelParser_1.BaseChannelParser.parseTabData("posts", response.data);
48
+ const continuation = common_1.getContinuationFromItems(items);
49
+ const data = items
50
+ .map((i) => { var _a, _b; return (_b = (_a = i.backstagePostThreadRenderer) === null || _a === void 0 ? void 0 : _a.post) === null || _b === void 0 ? void 0 : _b.backstagePostRenderer; })
51
+ .filter((i) => i !== undefined);
52
+ return {
53
+ continuation,
54
+ items: data.map((i) => new Post_1.Post({ client: this.client, channel: this.channel }).load(i)),
55
+ };
56
+ });
57
+ }
58
+ }
59
+ exports.ChannelPosts = ChannelPosts;
@@ -37,7 +37,7 @@ class BaseVideoParser {
37
37
  target.description = videoInfo.videoDetails.shortDescription || "";
38
38
  // related videos
39
39
  let secondaryContents = (_c = data.response.contents.twoColumnWatchNextResults.secondaryResults) === null || _c === void 0 ? void 0 : _c.secondaryResults.results;
40
- const itemSectionRenderer = (_d = secondaryContents.find((c) => {
40
+ const itemSectionRenderer = (_d = secondaryContents === null || secondaryContents === void 0 ? void 0 : secondaryContents.find((c) => {
41
41
  return c.itemSectionRenderer;
42
42
  })) === null || _d === void 0 ? void 0 : _d.itemSectionRenderer;
43
43
  if (itemSectionRenderer)
@@ -7,7 +7,7 @@ const PlaylistCompact_1 = require("../PlaylistCompact");
7
7
  const VideoCompact_1 = require("../VideoCompact");
8
8
  class ChannelParser {
9
9
  static loadChannel(target, data) {
10
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
10
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
11
11
  let channelId, title, handle, description, avatar, subscriberCountText, videoCountText, tvBanner, mobileBanner, banner;
12
12
  const { c4TabbedHeaderRenderer, pageHeaderRenderer } = data.header;
13
13
  if (c4TabbedHeaderRenderer) {
@@ -26,11 +26,15 @@ class ChannelParser {
26
26
  .browseEndpoint.browseId;
27
27
  title = pageHeaderRenderer.pageTitle;
28
28
  const { metadata, image: imageModel, banner: bannerModel, description: descriptionModel, } = pageHeaderRenderer.content.pageHeaderViewModel;
29
- const metadataRow = metadata.contentMetadataViewModel.metadataRows.find((m) => m.metadataParts && m.metadataParts.length == 2);
30
- const handleRow = metadata.contentMetadataViewModel.metadataRows.find((m) => m.metadataParts && m.metadataParts.length == 1);
31
- handle = (_j = handleRow === null || handleRow === void 0 ? void 0 : handleRow.metadataParts[0].text) === null || _j === void 0 ? void 0 : _j.content;
32
- videoCountText = (_k = metadataRow.metadataParts.find((m) => m.text.styleRuns)) === null || _k === void 0 ? void 0 : _k.text.content;
33
- subscriberCountText = (_l = metadataRow.metadataParts.find((m) => !m.text.styleRuns)) === null || _l === void 0 ? void 0 : _l.text.content;
29
+ const metadataParts = metadata.contentMetadataViewModel.metadataRows
30
+ .map((m) => m.metadataParts)
31
+ .flat();
32
+ const handlePart = metadataParts.find((m) => { var _a; return (_a = m.text.styleRuns) === null || _a === void 0 ? void 0 : _a.some((s) => "weightLabel" in s); });
33
+ const subscriberCountPart = metadataParts.find((m) => m.accessibilityLabel);
34
+ const videoCountPart = metadataParts.find((m) => { var _a; return (_a = m.text.styleRuns) === null || _a === void 0 ? void 0 : _a.some((s) => "startIndex" in s); });
35
+ handle = (_j = handlePart === null || handlePart === void 0 ? void 0 : handlePart.text) === null || _j === void 0 ? void 0 : _j.content;
36
+ videoCountText = videoCountPart === null || videoCountPart === void 0 ? void 0 : videoCountPart.text.content;
37
+ subscriberCountText = subscriberCountPart === null || subscriberCountPart === void 0 ? void 0 : subscriberCountPart.text.content;
34
38
  avatar = imageModel.decoratedAvatarViewModel.avatar.avatarViewModel.image.sources;
35
39
  banner = bannerModel === null || bannerModel === void 0 ? void 0 : bannerModel.imageBannerViewModel.image.sources;
36
40
  description = descriptionModel === null || descriptionModel === void 0 ? void 0 : descriptionModel.descriptionPreviewViewModel.description.content;
@@ -24,11 +24,11 @@ class PlaylistCompactParser {
24
24
  return target;
25
25
  }
26
26
  static loadLockupPlaylistCompact(target, data) {
27
+ var _a;
27
28
  const lockupMetadataViewModel = data.metadata.lockupMetadataViewModel;
28
- const channelMetadata = lockupMetadataViewModel.metadata.contentMetadataViewModel.metadataRows[0]
29
- .metadataParts[0];
29
+ const channelMetadata = (_a = lockupMetadataViewModel.metadata.contentMetadataViewModel.metadataRows) === null || _a === void 0 ? void 0 : _a[0].metadataParts[0];
30
30
  const thumbnailViewModel = data.contentImage.collectionThumbnailViewModel.primaryThumbnail.thumbnailViewModel;
31
- if (channelMetadata.text.commandRuns) {
31
+ if (channelMetadata === null || channelMetadata === void 0 ? void 0 : channelMetadata.text.commandRuns) {
32
32
  // not a mix
33
33
  const channel = new BaseChannel_1.BaseChannel({
34
34
  client: target.client,
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Post = void 0;
4
+ const Base_1 = require("../Base");
5
+ const PostParser_1 = require("./PostParser");
6
+ /** Represents a chat in a live stream */
7
+ class Post extends Base_1.Base {
8
+ /** @hidden */
9
+ constructor(attr) {
10
+ super(attr.client);
11
+ Object.assign(this, attr);
12
+ }
13
+ /**
14
+ * Load this instance with raw data from Youtube
15
+ *
16
+ * @hidden
17
+ */
18
+ load(data) {
19
+ PostParser_1.PostParser.loadPost(this, data);
20
+ return this;
21
+ }
22
+ }
23
+ exports.Post = Post;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostParser = void 0;
4
+ const BaseChannel_1 = require("../BaseChannel");
5
+ class PostParser {
6
+ static loadPost(target, data) {
7
+ var _a, _b, _c, _d;
8
+ const { postId, authorText, authorThumbnail, authorEndpoint, contentText, publishedTimeText, voteCount, } = data;
9
+ // Basic information
10
+ target.id = postId;
11
+ target.content = (_a = contentText === null || contentText === void 0 ? void 0 : contentText.runs) === null || _a === void 0 ? void 0 : _a.map((r) => r.text).join("");
12
+ target.channel = new BaseChannel_1.BaseChannel({
13
+ id: (_b = authorEndpoint === null || authorEndpoint === void 0 ? void 0 : authorEndpoint.browseEndpoint) === null || _b === void 0 ? void 0 : _b.browseId,
14
+ name: (_c = authorText.runs) === null || _c === void 0 ? void 0 : _c[0].text,
15
+ thumbnails: authorThumbnail.thumbnails,
16
+ client: target.client,
17
+ });
18
+ target.timestamp = (_d = publishedTimeText.runs[0]) === null || _d === void 0 ? void 0 : _d.text;
19
+ target.voteCount = voteCount.simpleText;
20
+ return target;
21
+ }
22
+ }
23
+ exports.PostParser = PostParser;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./Post"), exports);
14
+ __exportStar(require("./PostParser"), exports);
@@ -47,7 +47,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
47
47
  };
48
48
  import { HTTP } from "../../common";
49
49
  import { MusicLyrics } from "../MusicLyrics";
50
- import { MusicAllSearchResultParser, MusicSearchResult, } from "../MusicSearchResult";
50
+ import { MusicSearchResult } from "../MusicSearchResult";
51
51
  import { BASE_URL, INNERTUBE_API_KEY, INNERTUBE_CLIENT_NAME, INNERTUBE_CLIENT_VERSION, I_END_POINT, } from "../constants";
52
52
  /** Youtube Music Client */
53
53
  var MusicClient = /** @class */ (function () {
@@ -56,23 +56,22 @@ var MusicClient = /** @class */ (function () {
56
56
  var fullOptions = __assign(__assign({ initialCookie: "", oauth: { enabled: false }, fetchOptions: {} }, options), { youtubeClientOptions: __assign({ hl: "en", gl: "US" }, options.youtubeClientOptions), apiKey: options.apiKey || INNERTUBE_API_KEY, baseUrl: options.baseUrl || BASE_URL, clientName: options.clientName || INNERTUBE_CLIENT_NAME, clientVersion: options.clientVersion || INNERTUBE_CLIENT_VERSION });
57
57
  this.http = new HTTP(fullOptions);
58
58
  }
59
+ /**
60
+ * Searches for video, song, album, playlist, or artist
61
+ *
62
+ * @param query The search query
63
+ * @param type Search type
64
+ *
65
+ */
59
66
  MusicClient.prototype.search = function (query, type) {
60
67
  return __awaiter(this, void 0, void 0, function () {
61
- var response, result;
68
+ var result;
62
69
  return __generator(this, function (_a) {
63
70
  switch (_a.label) {
64
71
  case 0:
65
- if (!!type) return [3 /*break*/, 2];
66
- return [4 /*yield*/, this.http.post(I_END_POINT + "/search", {
67
- data: { query: query },
68
- })];
69
- case 1:
70
- response = _a.sent();
71
- return [2 /*return*/, MusicAllSearchResultParser.parseSearchResult(response.data, this)];
72
- case 2:
73
72
  result = new MusicSearchResult({ client: this });
74
73
  return [4 /*yield*/, result.search(query, type)];
75
- case 3:
74
+ case 1:
76
75
  _a.sent();
77
76
  return [2 /*return*/, result];
78
77
  }
@@ -86,18 +85,15 @@ var MusicClient = /** @class */ (function () {
86
85
  */
87
86
  MusicClient.prototype.searchAll = function (query) {
88
87
  return __awaiter(this, void 0, void 0, function () {
89
- var response;
88
+ var result;
90
89
  return __generator(this, function (_a) {
91
90
  switch (_a.label) {
92
- case 0: return [4 /*yield*/, this.http.post(I_END_POINT + "/search", {
93
- data: { query: query },
94
- })];
91
+ case 0:
92
+ result = new MusicSearchResult({ client: this });
93
+ return [4 /*yield*/, result.search(query)];
95
94
  case 1:
96
- response = _a.sent();
97
- return [2 /*return*/, {
98
- top: MusicAllSearchResultParser.parseTopResult(response.data, this),
99
- shelves: MusicAllSearchResultParser.parseSearchResult(response.data, this),
100
- }];
95
+ _a.sent();
96
+ return [2 /*return*/, result];
101
97
  }
102
98
  });
103
99
  });