youtubei 1.2.0 → 1.3.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/music/MusicClient/MusicClient.js +13 -13
- package/dist/cjs/music/MusicClient/index.js +0 -1
- package/dist/cjs/music/MusicContinuable/MusicContinuable.js +43 -0
- package/dist/cjs/music/MusicContinuable/index.js +13 -0
- package/dist/cjs/music/{MusicClient/MusicSearchResultParser.js → MusicSearchResult/MusicAllSearchResultParser.js} +29 -22
- package/dist/cjs/music/MusicSearchResult/MusicSearchResult.js +92 -0
- package/dist/cjs/music/MusicSearchResult/MusicSearchResultParser.js +34 -0
- package/dist/cjs/music/MusicSearchResult/index.js +15 -0
- package/dist/cjs/music/MusicSearchResult/proto/MusicSearchProto.js +2 -0
- package/dist/cjs/music/MusicSearchResult/proto/index.js +35 -0
- package/dist/cjs/youtube/BaseChannel/ChannelLive.js +3 -3
- package/dist/cjs/youtube/BaseChannel/ChannelShorts.js +7 -7
- package/dist/cjs/youtube/BaseChannel/index.js +2 -0
- package/dist/cjs/youtube/BaseVideo/BaseVideoParser.js +1 -1
- package/dist/cjs/youtube/Client/Client.js +1 -1
- package/dist/cjs/youtube/Playlist/PlaylistParser.js +2 -1
- package/dist/cjs/youtube/SearchResult/SearchResult.js +1 -1
- package/dist/cjs/youtube/SearchResult/proto/index.js +5 -5
- package/dist/cjs/youtube/Transcript/proto/TranscriptParamsProto.js +3 -3
- package/dist/esm/music/MusicClient/MusicClient.js +15 -14
- package/dist/esm/music/MusicClient/index.js +0 -1
- package/dist/esm/music/MusicContinuable/MusicContinuable.js +125 -0
- package/dist/esm/music/MusicContinuable/index.js +1 -0
- package/dist/esm/music/{MusicClient/MusicSearchResultParser.js → MusicSearchResult/MusicAllSearchResultParser.js} +27 -24
- package/dist/esm/music/MusicSearchResult/MusicSearchResult.js +169 -0
- package/dist/esm/music/MusicSearchResult/MusicSearchResultParser.js +56 -0
- package/dist/esm/music/MusicSearchResult/index.js +3 -0
- package/dist/esm/music/MusicSearchResult/proto/MusicSearchProto.js +1 -0
- package/dist/esm/music/MusicSearchResult/proto/index.js +15 -0
- package/dist/esm/youtube/BaseChannel/ChannelLive.js +3 -3
- package/dist/esm/youtube/BaseChannel/ChannelShorts.js +7 -7
- package/dist/esm/youtube/BaseChannel/index.js +2 -0
- package/dist/esm/youtube/BaseVideo/BaseVideoParser.js +1 -1
- package/dist/esm/youtube/Client/Client.js +1 -1
- package/dist/esm/youtube/Playlist/PlaylistParser.js +3 -2
- package/dist/esm/youtube/SearchResult/SearchResult.js +1 -1
- package/dist/esm/youtube/SearchResult/proto/index.js +2 -2
- package/dist/esm/youtube/Transcript/proto/TranscriptParamsProto.js +2 -2
- package/dist/typings/music/MusicBaseArtist/MusicBaseArtist.d.ts +1 -1
- package/dist/typings/music/MusicClient/MusicClient.d.ts +2 -0
- package/dist/typings/music/MusicClient/index.d.ts +0 -1
- package/dist/typings/music/MusicContinuable/MusicContinuable.d.ts +24 -0
- package/dist/typings/music/MusicContinuable/index.d.ts +1 -0
- package/dist/typings/music/{MusicClient/MusicSearchResultParser.d.ts → MusicSearchResult/MusicAllSearchResultParser.d.ts} +4 -3
- package/dist/typings/music/MusicSearchResult/MusicSearchResult.d.ts +46 -0
- package/dist/typings/music/MusicSearchResult/MusicSearchResultParser.d.ts +13 -0
- package/dist/typings/music/MusicSearchResult/index.d.ts +3 -0
- package/dist/typings/music/MusicSearchResult/proto/MusicSearchProto.d.ts +14 -0
- package/dist/typings/music/MusicSearchResult/proto/index.d.ts +5 -0
- package/dist/typings/youtube/BaseChannel/ChannelLive.d.ts +4 -4
- package/dist/typings/youtube/BaseChannel/ChannelShorts.d.ts +8 -8
- package/dist/typings/youtube/BaseChannel/index.d.ts +2 -0
- package/dist/typings/youtube/SearchResult/proto/index.d.ts +2 -41
- package/dist/typings/youtube/Transcript/proto/TranscriptParamsProto.d.ts +2 -11
- package/package.json +2 -2
|
@@ -12,27 +12,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.MusicClient = void 0;
|
|
13
13
|
const common_1 = require("../../common");
|
|
14
14
|
const MusicLyrics_1 = require("../MusicLyrics");
|
|
15
|
+
const MusicSearchResult_1 = require("../MusicSearchResult");
|
|
15
16
|
const constants_1 = require("../constants");
|
|
16
|
-
const MusicSearchResultParser_1 = require("./MusicSearchResultParser");
|
|
17
17
|
/** Youtube Music Client */
|
|
18
18
|
class MusicClient {
|
|
19
19
|
constructor(options = {}) {
|
|
20
20
|
const fullOptions = Object.assign(Object.assign({ initialCookie: "", fetchOptions: {} }, options), { youtubeClientOptions: Object.assign({ hl: "en", gl: "US" }, options.youtubeClientOptions) });
|
|
21
21
|
this.http = new common_1.HTTP(Object.assign({ apiKey: constants_1.INNERTUBE_API_KEY, baseUrl: constants_1.BASE_URL, clientName: "WEB_REMIX", clientVersion: constants_1.INNERTUBE_CLIENT_VERSION }, fullOptions));
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
* Searches for video, song, album, playlist, or artist
|
|
25
|
-
*
|
|
26
|
-
* @param query The search query
|
|
27
|
-
* @param options Search options
|
|
28
|
-
*
|
|
29
|
-
*/
|
|
30
|
-
search(query) {
|
|
23
|
+
search(query, type) {
|
|
31
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
+
}
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
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.MusicContinuable = void 0;
|
|
13
|
+
const MusicBase_1 = require("../MusicBase");
|
|
14
|
+
/** Represents a continuable list of items `T` (like pagination) */
|
|
15
|
+
class MusicContinuable extends MusicBase_1.MusicBase {
|
|
16
|
+
/** @hidden */
|
|
17
|
+
constructor({ client, strictContinuationCheck }) {
|
|
18
|
+
super(client);
|
|
19
|
+
this.items = [];
|
|
20
|
+
this.strictContinuationCheck = !!strictContinuationCheck;
|
|
21
|
+
if (this.strictContinuationCheck)
|
|
22
|
+
this.continuation = null;
|
|
23
|
+
}
|
|
24
|
+
/** Fetch next items using continuation token */
|
|
25
|
+
next(count = 1) {
|
|
26
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
const newItems = [];
|
|
28
|
+
for (let i = 0; i < count || count == 0; i++) {
|
|
29
|
+
if (!this.hasContinuation)
|
|
30
|
+
break;
|
|
31
|
+
const { items, continuation } = yield this.fetch();
|
|
32
|
+
this.continuation = continuation;
|
|
33
|
+
newItems.push(...items);
|
|
34
|
+
}
|
|
35
|
+
this.items.push(...newItems);
|
|
36
|
+
return newItems;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
get hasContinuation() {
|
|
40
|
+
return this.strictContinuationCheck ? this.continuation !== undefined : !!this.continuation;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.MusicContinuable = MusicContinuable;
|
|
@@ -0,0 +1,13 @@
|
|
|
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("./MusicContinuable"), exports);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.MusicAllSearchResultParser = void 0;
|
|
4
4
|
const common_1 = require("../../common");
|
|
5
5
|
const MusicAlbumCompact_1 = require("../MusicAlbumCompact");
|
|
6
6
|
const MusicArtistCompact_1 = require("../MusicArtistCompact");
|
|
@@ -9,7 +9,7 @@ const MusicBaseChannel_1 = require("../MusicBaseChannel");
|
|
|
9
9
|
const MusicPlaylistCompact_1 = require("../MusicPlaylistCompact");
|
|
10
10
|
const MusicSongCompact_1 = require("../MusicSongCompact");
|
|
11
11
|
const MusicVideoCompact_1 = require("../MusicVideoCompact");
|
|
12
|
-
class
|
|
12
|
+
class MusicAllSearchResultParser {
|
|
13
13
|
static parseSearchResult(data, client) {
|
|
14
14
|
const sectionListContents = data.contents.tabbedSearchResultsRenderer.tabs[0].tabRenderer.content
|
|
15
15
|
.sectionListRenderer.contents;
|
|
@@ -18,7 +18,7 @@ class MusicSearchResultParser {
|
|
|
18
18
|
.map((m) => m.musicShelfRenderer);
|
|
19
19
|
return shelves.map((m) => ({
|
|
20
20
|
title: m.title.runs.map((r) => r.text).join(),
|
|
21
|
-
items: m.contents.map((c) =>
|
|
21
|
+
items: m.contents.map((c) => MusicAllSearchResultParser.parseSearchItem(c, client)),
|
|
22
22
|
}));
|
|
23
23
|
}
|
|
24
24
|
static parseSearchItem(content, client) {
|
|
@@ -30,16 +30,16 @@ class MusicSearchResultParser {
|
|
|
30
30
|
.watchEndpointMusicConfig.musicVideoType;
|
|
31
31
|
if (pageType === "MUSIC_VIDEO_TYPE_PODCAST_EPISODE")
|
|
32
32
|
return;
|
|
33
|
-
return
|
|
33
|
+
return MusicAllSearchResultParser.parseVideoItem(item, pageType, client);
|
|
34
34
|
}
|
|
35
35
|
else if (playEndpoint === null || playEndpoint === void 0 ? void 0 : playEndpoint.watchPlaylistEndpoint.params) {
|
|
36
|
-
return
|
|
36
|
+
return MusicAllSearchResultParser.parsePlaylistItem(item, client);
|
|
37
37
|
}
|
|
38
38
|
else if (playEndpoint === null || playEndpoint === void 0 ? void 0 : playEndpoint.watchPlaylistEndpoint) {
|
|
39
|
-
return
|
|
39
|
+
return MusicAllSearchResultParser.parseAlbumItem(item, client);
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
|
-
return
|
|
42
|
+
return MusicAllSearchResultParser.parseArtistItem(item, client);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
static parseVideoItem(item, pageType, client) {
|
|
@@ -48,7 +48,7 @@ class MusicSearchResultParser {
|
|
|
48
48
|
const title = topColumn[0].text;
|
|
49
49
|
const duration = common_1.getDuration(bottomColumn.at(-1).text) || undefined;
|
|
50
50
|
const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
|
|
51
|
-
const artists =
|
|
51
|
+
const artists = MusicAllSearchResultParser.parseArtists(bottomColumn, client);
|
|
52
52
|
if (pageType === "MUSIC_VIDEO_TYPE_ATV") {
|
|
53
53
|
const rawAlbum = bottomColumn.find((r) => {
|
|
54
54
|
var _a;
|
|
@@ -82,7 +82,7 @@ class MusicSearchResultParser {
|
|
|
82
82
|
const title = topColumn[0].text;
|
|
83
83
|
const songCount = common_1.stripToInt(bottomColumn.at(-1).text) || undefined;
|
|
84
84
|
const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
|
|
85
|
-
const channel =
|
|
85
|
+
const channel = MusicAllSearchResultParser.parseChannel(bottomColumn, client);
|
|
86
86
|
return new MusicPlaylistCompact_1.MusicPlaylistCompact({ client, id, title, thumbnails, songCount, channel });
|
|
87
87
|
}
|
|
88
88
|
static parseAlbumItem(item, client) {
|
|
@@ -92,7 +92,7 @@ class MusicSearchResultParser {
|
|
|
92
92
|
const title = topColumn[0].text;
|
|
93
93
|
const year = common_1.stripToInt(bottomColumn.at(-1).text) || undefined;
|
|
94
94
|
const thumbnails = new common_1.Thumbnails().load(item.thumbnail.musicThumbnailRenderer.thumbnail.thumbnails);
|
|
95
|
-
const artists =
|
|
95
|
+
const artists = MusicAllSearchResultParser.parseArtists(bottomColumn, client);
|
|
96
96
|
return new MusicAlbumCompact_1.MusicAlbumCompact({ client, id, title, thumbnails, artists, year });
|
|
97
97
|
}
|
|
98
98
|
static parseArtistItem(item, client) {
|
|
@@ -103,26 +103,33 @@ class MusicSearchResultParser {
|
|
|
103
103
|
return new MusicArtistCompact_1.MusicArtistCompact({ client, id, name, thumbnails });
|
|
104
104
|
}
|
|
105
105
|
static parseArtists(items, client) {
|
|
106
|
-
return this.parseArtistOrChannel(items).map((r) =>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
return this.parseArtistOrChannel(items).map((r) => {
|
|
107
|
+
var _a;
|
|
108
|
+
return new MusicBaseArtist_1.MusicBaseArtist({
|
|
109
|
+
client,
|
|
110
|
+
name: r.text,
|
|
111
|
+
id: (_a = r.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseId,
|
|
112
|
+
});
|
|
113
|
+
});
|
|
111
114
|
}
|
|
112
115
|
static parseChannel(items, client) {
|
|
113
|
-
const [channel] = this.parseArtistOrChannel(items).map((r) =>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
const [channel] = this.parseArtistOrChannel(items).map((r) => {
|
|
117
|
+
var _a;
|
|
118
|
+
return new MusicBaseChannel_1.MusicBaseChannel({
|
|
119
|
+
client,
|
|
120
|
+
name: r.text,
|
|
121
|
+
id: (_a = r.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseId,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
118
124
|
return channel;
|
|
119
125
|
}
|
|
120
126
|
static parseArtistOrChannel(items) {
|
|
121
|
-
|
|
127
|
+
const contents = items.filter((r) => {
|
|
122
128
|
var _a;
|
|
123
129
|
const pageType = (_a = r.navigationEndpoint) === null || _a === void 0 ? void 0 : _a.browseEndpoint.browseEndpointContextSupportedConfigs.browseEndpointContextMusicConfig.pageType;
|
|
124
130
|
return (pageType === "MUSIC_PAGE_TYPE_ARTIST" || pageType === "MUSIC_PAGE_TYPE_USER_CHANNEL");
|
|
125
131
|
});
|
|
132
|
+
return !contents.length && items[0] ? [items[0]] : contents;
|
|
126
133
|
}
|
|
127
134
|
}
|
|
128
|
-
exports.
|
|
135
|
+
exports.MusicAllSearchResultParser = MusicAllSearchResultParser;
|
|
@@ -0,0 +1,92 @@
|
|
|
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.MusicSearchResult = exports.MusicSearchTypeEnum = void 0;
|
|
13
|
+
const MusicContinuable_1 = require("../MusicContinuable");
|
|
14
|
+
const constants_1 = require("../constants");
|
|
15
|
+
const MusicSearchResultParser_1 = require("./MusicSearchResultParser");
|
|
16
|
+
const proto_1 = require("./proto");
|
|
17
|
+
var MusicSearchTypeEnum;
|
|
18
|
+
(function (MusicSearchTypeEnum) {
|
|
19
|
+
MusicSearchTypeEnum["Song"] = "song";
|
|
20
|
+
MusicSearchTypeEnum["Video"] = "video";
|
|
21
|
+
})(MusicSearchTypeEnum = exports.MusicSearchTypeEnum || (exports.MusicSearchTypeEnum = {}));
|
|
22
|
+
/**
|
|
23
|
+
* Represents search result, usually returned from `client.search();`.
|
|
24
|
+
*
|
|
25
|
+
* {@link MusicSearchResult} is a helper class to manage search result
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const result = await music.search("Keyword", "song");
|
|
30
|
+
*
|
|
31
|
+
* console.log(result.items); // search result from first page
|
|
32
|
+
*
|
|
33
|
+
* let nextSearchResult = await result.next();
|
|
34
|
+
* console.log(nextSearchResult); // search result from second page
|
|
35
|
+
*
|
|
36
|
+
* nextSearchResult = await result.next();
|
|
37
|
+
* console.log(nextSearchResult); // search result from third page
|
|
38
|
+
*
|
|
39
|
+
* console.log(result.items); // search result from first, second, and third page.
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @noInheritDoc
|
|
43
|
+
*/
|
|
44
|
+
class MusicSearchResult extends MusicContinuable_1.MusicContinuable {
|
|
45
|
+
/** @hidden */
|
|
46
|
+
constructor({ client }) {
|
|
47
|
+
super({ client });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Initialize data from search
|
|
51
|
+
*
|
|
52
|
+
* @param query Search query
|
|
53
|
+
* @param options Search Options
|
|
54
|
+
*
|
|
55
|
+
* @hidden
|
|
56
|
+
*/
|
|
57
|
+
search(query, type) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
this.items = [];
|
|
60
|
+
const bufferParams = proto_1.MusicSearchProto.encode(proto_1.optionsToProto(type)).finish();
|
|
61
|
+
const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
|
|
62
|
+
data: {
|
|
63
|
+
query,
|
|
64
|
+
params: Buffer.from(bufferParams).toString("base64"),
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
const { data, continuation } = MusicSearchResultParser_1.MusicSearchResultParser.parseInitialSearchResult(response.data, type, this.client);
|
|
68
|
+
this.items.push(...data);
|
|
69
|
+
this.continuation = continuation;
|
|
70
|
+
return this;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
fetch() {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
if (!this.type) {
|
|
76
|
+
return {
|
|
77
|
+
items: [],
|
|
78
|
+
continuation: undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
|
|
82
|
+
data: { continuation: this.continuation },
|
|
83
|
+
});
|
|
84
|
+
const { data, continuation } = MusicSearchResultParser_1.MusicSearchResultParser.parseContinuationSearchResult(response.data, this.type, this.client);
|
|
85
|
+
return {
|
|
86
|
+
items: data,
|
|
87
|
+
continuation,
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.MusicSearchResult = MusicSearchResult;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MusicSearchResultParser = void 0;
|
|
4
|
+
const MusicAllSearchResultParser_1 = require("./MusicAllSearchResultParser");
|
|
5
|
+
class MusicSearchResultParser {
|
|
6
|
+
static parseInitialSearchResult(data, type, client) {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
const { contents, continuations, } = data.contents.tabbedSearchResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents[0].musicShelfRenderer;
|
|
9
|
+
return {
|
|
10
|
+
data: MusicSearchResultParser.parseSearchResult(contents, type, client),
|
|
11
|
+
continuation: (_b = (_a = continuations[0]) === null || _a === void 0 ? void 0 : _a.nextContinuationData) === null || _b === void 0 ? void 0 : _b.continuation,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
static parseContinuationSearchResult(data, type, client) {
|
|
15
|
+
const shelf = data.continuationContents.musicShelfContinuation;
|
|
16
|
+
return {
|
|
17
|
+
data: MusicSearchResultParser.parseSearchResult(shelf.contents, type, client),
|
|
18
|
+
continuation: shelf.continuations[0].nextContinuationData.continuation,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
static parseSearchResult(shelfContents, type, client) {
|
|
22
|
+
const rawContents = shelfContents
|
|
23
|
+
.filter((c) => "musicResponsiveListItemRenderer" in c)
|
|
24
|
+
.map((c) => c.musicResponsiveListItemRenderer);
|
|
25
|
+
const contents = [];
|
|
26
|
+
for (const c of rawContents) {
|
|
27
|
+
const parsed = MusicAllSearchResultParser_1.MusicAllSearchResultParser.parseVideoItem(c, type === "video" ? "MUSIC_VIDEO_TYPE_UGC" : "MUSIC_VIDEO_TYPE_ATV", client);
|
|
28
|
+
if (parsed)
|
|
29
|
+
contents.push(parsed);
|
|
30
|
+
}
|
|
31
|
+
return contents;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.MusicSearchResultParser = MusicSearchResultParser;
|
|
@@ -0,0 +1,15 @@
|
|
|
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("./MusicAllSearchResultParser"), exports);
|
|
14
|
+
__exportStar(require("./MusicSearchResult"), exports);
|
|
15
|
+
__exportStar(require("./MusicSearchResultParser"), exports);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.optionsToProto = exports.MusicSearchProto = void 0;
|
|
7
|
+
const protobufjs_1 = __importDefault(require("protobufjs"));
|
|
8
|
+
// TODO move this to .proto file
|
|
9
|
+
exports.MusicSearchProto = protobufjs_1.default
|
|
10
|
+
.parse(`
|
|
11
|
+
message MusicSearchOptions {
|
|
12
|
+
message Options {
|
|
13
|
+
optional int32 song = 1;
|
|
14
|
+
optional int32 video = 2;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
message Params {
|
|
18
|
+
optional Options options = 17;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
optional Params params = 2;
|
|
22
|
+
}
|
|
23
|
+
`)
|
|
24
|
+
.root.lookupType("MusicSearchOptions");
|
|
25
|
+
const optionsToProto = (type) => {
|
|
26
|
+
return {
|
|
27
|
+
params: {
|
|
28
|
+
options: {
|
|
29
|
+
song: type === "song" ? 1 : undefined,
|
|
30
|
+
video: type === "video" ? 1 : undefined,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
exports.optionsToProto = optionsToProto;
|
|
@@ -24,11 +24,11 @@ const BaseChannelParser_1 = require("./BaseChannelParser");
|
|
|
24
24
|
* await channel.live.next();
|
|
25
25
|
* console.log(channel.live.items) // first 30 live videos
|
|
26
26
|
*
|
|
27
|
-
* let
|
|
28
|
-
* console.log(
|
|
27
|
+
* let newLives = await channel.videos.next();
|
|
28
|
+
* console.log(newLives) // 30 loaded live videos
|
|
29
29
|
* console.log(channel.live.items) // first 60 live videos
|
|
30
30
|
*
|
|
31
|
-
* await channel.live.next(0); // load the rest of the videos in the channel
|
|
31
|
+
* await channel.live.next(0); // load the rest of the live videos in the channel
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
class ChannelLive extends Continuable_1.Continuable {
|
|
@@ -16,19 +16,19 @@ const VideoCompact_1 = require("../VideoCompact");
|
|
|
16
16
|
const constants_1 = require("../constants");
|
|
17
17
|
const BaseChannelParser_1 = require("./BaseChannelParser");
|
|
18
18
|
/**
|
|
19
|
-
* {@link Continuable} of
|
|
19
|
+
* {@link Continuable} of shorts inside a {@link BaseChannel}
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```js
|
|
23
23
|
* const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
|
|
24
|
-
* await channel.
|
|
25
|
-
* console.log(channel.
|
|
24
|
+
* await channel.short.next();
|
|
25
|
+
* console.log(channel.short.items) // first 30 shorts
|
|
26
26
|
*
|
|
27
|
-
* let
|
|
28
|
-
* console.log(
|
|
29
|
-
* console.log(channel.
|
|
27
|
+
* let newShorts = await channel.short.next();
|
|
28
|
+
* console.log(newShorts) // 30 loaded shorts
|
|
29
|
+
* console.log(channel.short.items) // first 60 shorts
|
|
30
30
|
*
|
|
31
|
-
* await channel.
|
|
31
|
+
* await channel.short.next(0); // load the rest of the shorts in the channel
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
class ChannelShorts extends Continuable_1.Continuable {
|
|
@@ -12,5 +12,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
__exportStar(require("./BaseChannel"), exports);
|
|
14
14
|
__exportStar(require("./BaseChannelParser"), exports);
|
|
15
|
+
__exportStar(require("./ChannelLive"), exports);
|
|
15
16
|
__exportStar(require("./ChannelPlaylists"), exports);
|
|
17
|
+
__exportStar(require("./ChannelShorts"), exports);
|
|
16
18
|
__exportStar(require("./ChannelVideos"), exports);
|
|
@@ -31,7 +31,7 @@ class BaseVideoParser {
|
|
|
31
31
|
// Tags and description
|
|
32
32
|
target.tags =
|
|
33
33
|
((_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)) || [];
|
|
34
|
-
target.description = videoInfo.shortDescription || "";
|
|
34
|
+
target.description = videoInfo.videoDetails.shortDescription || "";
|
|
35
35
|
// related videos
|
|
36
36
|
const secondaryContents = data[3].response.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults
|
|
37
37
|
.results;
|
|
@@ -100,7 +100,7 @@ class Client {
|
|
|
100
100
|
}
|
|
101
101
|
getVideoTranscript(videoId) {
|
|
102
102
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
-
const bufferParams = Transcript_1.TranscriptParamsProto.
|
|
103
|
+
const bufferParams = Transcript_1.TranscriptParamsProto.encode({ videoId }).finish();
|
|
104
104
|
const response = yield this.http.post(`${constants_1.I_END_POINT}/get_transcript`, {
|
|
105
105
|
data: { params: Buffer.from(bufferParams).toString("base64") },
|
|
106
106
|
});
|
|
@@ -14,7 +14,8 @@ class PlaylistParser {
|
|
|
14
14
|
target.id = (_a = Object.values(metadata)
|
|
15
15
|
.find((v) => v.includes("playlist?list="))) === null || _a === void 0 ? void 0 : _a.split("=")[1];
|
|
16
16
|
target.title = metadata.title;
|
|
17
|
-
|
|
17
|
+
const { playlistVideoThumbnailRenderer, playlistCustomThumbnailRenderer, } = primaryRenderer.thumbnailRenderer;
|
|
18
|
+
target.thumbnails = new common_1.Thumbnails().load((playlistVideoThumbnailRenderer || playlistCustomThumbnailRenderer).thumbnail.thumbnails);
|
|
18
19
|
const { stats } = primaryRenderer;
|
|
19
20
|
if (primaryRenderer.stats.length === 3) {
|
|
20
21
|
target.videoCount = PlaylistParser.parseSideBarInfo(stats[0], true);
|
|
@@ -101,7 +101,7 @@ class SearchResult extends Continuable_1.Continuable {
|
|
|
101
101
|
return __awaiter(this, void 0, void 0, function* () {
|
|
102
102
|
this.items = [];
|
|
103
103
|
this.estimatedResults = 0;
|
|
104
|
-
const bufferParams = proto_1.SearchProto.
|
|
104
|
+
const bufferParams = proto_1.SearchProto.encode(proto_1.optionsToProto(options)).finish();
|
|
105
105
|
const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
|
|
106
106
|
data: {
|
|
107
107
|
query,
|
|
@@ -4,9 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.optionsToProto = exports.SearchProto = void 0;
|
|
7
|
-
const
|
|
7
|
+
const protobufjs_1 = __importDefault(require("protobufjs"));
|
|
8
8
|
// TODO move this to .proto file
|
|
9
|
-
exports.SearchProto =
|
|
9
|
+
exports.SearchProto = protobufjs_1.default.parse(`
|
|
10
10
|
message SearchOptions {
|
|
11
11
|
message Options {
|
|
12
12
|
optional int32 uploadDate = 1;
|
|
@@ -16,8 +16,8 @@ exports.SearchProto = protocol_buffers_1.default(`
|
|
|
16
16
|
optional int32 subtitles = 5;
|
|
17
17
|
optional int32 creativeCommons = 6;
|
|
18
18
|
optional int32 live = 8;
|
|
19
|
-
optional int32
|
|
20
|
-
optional int32
|
|
19
|
+
optional int32 _4k = 14;
|
|
20
|
+
optional int32 _360 = 15;
|
|
21
21
|
optional int32 location = 23;
|
|
22
22
|
optional int32 hdr = 25;
|
|
23
23
|
optional int32 vr180 = 26;
|
|
@@ -26,7 +26,7 @@ exports.SearchProto = protocol_buffers_1.default(`
|
|
|
26
26
|
optional int32 sortBy = 1;
|
|
27
27
|
optional Options options = 2;
|
|
28
28
|
}
|
|
29
|
-
`);
|
|
29
|
+
`).root.lookupType("SearchOptions");
|
|
30
30
|
const searchUploadDateProto = {
|
|
31
31
|
all: 0,
|
|
32
32
|
hour: 1,
|
|
@@ -4,9 +4,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.TranscriptParamsProto = void 0;
|
|
7
|
-
const
|
|
8
|
-
exports.TranscriptParamsProto =
|
|
7
|
+
const protobufjs_1 = __importDefault(require("protobufjs"));
|
|
8
|
+
exports.TranscriptParamsProto = protobufjs_1.default.parse(`
|
|
9
9
|
message TranscriptParams {
|
|
10
10
|
optional string videoId = 1;
|
|
11
11
|
}
|
|
12
|
-
`);
|
|
12
|
+
`).root.lookupType("TranscriptParams");
|
|
@@ -47,8 +47,8 @@ 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
51
|
import { BASE_URL, INNERTUBE_API_KEY, INNERTUBE_CLIENT_VERSION, I_END_POINT } from "../constants";
|
|
51
|
-
import { MusicSearchResultParser } from "./MusicSearchResultParser";
|
|
52
52
|
/** Youtube Music Client */
|
|
53
53
|
var MusicClient = /** @class */ (function () {
|
|
54
54
|
function MusicClient(options) {
|
|
@@ -56,24 +56,25 @@ var MusicClient = /** @class */ (function () {
|
|
|
56
56
|
var fullOptions = __assign(__assign({ initialCookie: "", fetchOptions: {} }, options), { youtubeClientOptions: __assign({ hl: "en", gl: "US" }, options.youtubeClientOptions) });
|
|
57
57
|
this.http = new HTTP(__assign({ apiKey: INNERTUBE_API_KEY, baseUrl: BASE_URL, clientName: "WEB_REMIX", clientVersion: INNERTUBE_CLIENT_VERSION }, fullOptions));
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
* Searches for video, song, album, playlist, or artist
|
|
61
|
-
*
|
|
62
|
-
* @param query The search query
|
|
63
|
-
* @param options Search options
|
|
64
|
-
*
|
|
65
|
-
*/
|
|
66
|
-
MusicClient.prototype.search = function (query) {
|
|
59
|
+
MusicClient.prototype.search = function (query, type) {
|
|
67
60
|
return __awaiter(this, void 0, void 0, function () {
|
|
68
|
-
var response;
|
|
61
|
+
var response, result;
|
|
69
62
|
return __generator(this, function (_a) {
|
|
70
63
|
switch (_a.label) {
|
|
71
|
-
case 0:
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
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
|
+
})];
|
|
74
69
|
case 1:
|
|
75
70
|
response = _a.sent();
|
|
76
|
-
return [2 /*return*/,
|
|
71
|
+
return [2 /*return*/, MusicAllSearchResultParser.parseSearchResult(response.data, this)];
|
|
72
|
+
case 2:
|
|
73
|
+
result = new MusicSearchResult({ client: this });
|
|
74
|
+
return [4 /*yield*/, result.search(query, type)];
|
|
75
|
+
case 3:
|
|
76
|
+
_a.sent();
|
|
77
|
+
return [2 /*return*/, result];
|
|
77
78
|
}
|
|
78
79
|
});
|
|
79
80
|
});
|