youtubei 0.0.1-rc.26 → 0.0.1-rc.29
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/classes/BaseVideo.d.ts +0 -3
- package/dist/classes/BaseVideo.js +2 -2
- package/dist/classes/Channel.js +2 -0
- package/dist/classes/Client.d.ts +3 -3
- package/dist/classes/LiveVideo.js +4 -2
- package/dist/classes/SearchResult.js +1 -3
- package/dist/common/HTTP.js +1 -1
- package/package.json +1 -1
- package/dist/classes/CompactChannel.d.ts +0 -89
- package/dist/classes/CompactChannel.js +0 -142
|
@@ -9,7 +9,6 @@ export interface BaseVideoAttributes extends BaseAttributes {
|
|
|
9
9
|
uploadDate: string;
|
|
10
10
|
viewCount: number | null;
|
|
11
11
|
likeCount: number | null;
|
|
12
|
-
dislikeCount: number | null;
|
|
13
12
|
isLiveContent: boolean;
|
|
14
13
|
tags: string[];
|
|
15
14
|
upNext: VideoCompact | PlaylistCompact | null;
|
|
@@ -32,8 +31,6 @@ export default class BaseVideo extends Base implements BaseVideoAttributes {
|
|
|
32
31
|
viewCount: number | null;
|
|
33
32
|
/** How many like does this video have, null if the like count hidden */
|
|
34
33
|
likeCount: number | null;
|
|
35
|
-
/** How many dislike does this video have, null if the dislike count is hidden */
|
|
36
|
-
dislikeCount: number | null;
|
|
37
34
|
/** Whether this video is a live content or not */
|
|
38
35
|
isLiveContent: boolean;
|
|
39
36
|
/** The tags of this video */
|
|
@@ -37,17 +37,17 @@ class BaseVideo extends _1.Base {
|
|
|
37
37
|
this.isLiveContent = videoInfo.videoDetails.isLiveContent;
|
|
38
38
|
this.thumbnails = new _1.Thumbnails().load(videoInfo.videoDetails.thumbnail.thumbnails);
|
|
39
39
|
// Channel
|
|
40
|
-
const { title, thumbnail } = videoInfo.owner.videoOwnerRenderer;
|
|
40
|
+
const { title, thumbnail, subscriberCountText } = videoInfo.owner.videoOwnerRenderer;
|
|
41
41
|
this.channel = new _1.ChannelCompact({
|
|
42
42
|
client: this.client,
|
|
43
43
|
id: title.runs[0].navigationEndpoint.browseEndpoint.browseId,
|
|
44
44
|
name: title.runs[0].text,
|
|
45
|
+
subscriberCount: subscriberCountText === null || subscriberCountText === void 0 ? void 0 : subscriberCountText.simpleText,
|
|
45
46
|
thumbnails: new _1.Thumbnails().load(thumbnail.thumbnails),
|
|
46
47
|
});
|
|
47
48
|
// Like Count and Dislike Count
|
|
48
49
|
const topLevelButtons = videoInfo.videoActions.menuRenderer.topLevelButtons;
|
|
49
50
|
this.likeCount = common_1.stripToInt(BaseVideo.parseButtonRenderer(topLevelButtons[0]));
|
|
50
|
-
this.dislikeCount = common_1.stripToInt(BaseVideo.parseButtonRenderer(topLevelButtons[1]));
|
|
51
51
|
// Tags and description
|
|
52
52
|
this.tags =
|
|
53
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)) || [];
|
package/dist/classes/Channel.js
CHANGED
|
@@ -43,6 +43,8 @@ class Channel extends ChannelCompact_1.default {
|
|
|
43
43
|
if (!shelfRenderer)
|
|
44
44
|
continue;
|
|
45
45
|
const { title, content, subtitle } = shelfRenderer;
|
|
46
|
+
if (!content.horizontalListRenderer)
|
|
47
|
+
continue;
|
|
46
48
|
const items = content.horizontalListRenderer.items
|
|
47
49
|
.map((i) => {
|
|
48
50
|
if (i.gridVideoRenderer)
|
package/dist/classes/Client.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ export declare namespace Client {
|
|
|
7
7
|
type SearchType = "video" | "channel" | "playlist" | "all";
|
|
8
8
|
type SearchOptions = {
|
|
9
9
|
/** Search type, can be `"video"`, `"channel"`, `"playlist"`, or `"all"` */
|
|
10
|
-
type
|
|
10
|
+
type?: SearchType;
|
|
11
11
|
/** Raw search params to be passed on the request, ignores `type` value if this is provided */
|
|
12
|
-
params
|
|
12
|
+
params?: string;
|
|
13
13
|
};
|
|
14
14
|
type ClientOptions = {
|
|
15
15
|
cookie: string;
|
|
@@ -33,7 +33,7 @@ export default class Client {
|
|
|
33
33
|
* @param searchOptions Search options
|
|
34
34
|
*
|
|
35
35
|
*/
|
|
36
|
-
search<T extends Client.SearchOptions>(query: string, searchOptions?:
|
|
36
|
+
search<T extends Client.SearchOptions>(query: string, searchOptions?: T): Promise<SearchResult<T["type"]>>;
|
|
37
37
|
/**
|
|
38
38
|
* Search for videos / playlists / channels and returns the first result
|
|
39
39
|
*
|
|
@@ -30,14 +30,14 @@ class LiveVideo extends _1.BaseVideo {
|
|
|
30
30
|
* @hidden
|
|
31
31
|
*/
|
|
32
32
|
load(data) {
|
|
33
|
+
var _a;
|
|
33
34
|
super.load(data);
|
|
34
35
|
const videoInfo = _1.BaseVideo.parseRawData(data);
|
|
35
36
|
this.watchingCount = +videoInfo.viewCount.videoViewCountRenderer.viewCount.runs
|
|
36
37
|
.map((r) => r.text)
|
|
37
38
|
.join(" ")
|
|
38
39
|
.replace(/[^0-9]/g, "");
|
|
39
|
-
this.chatContinuation =
|
|
40
|
-
data[3].response.contents.twoColumnWatchNextResults.conversationBar.liveChatRenderer.continuations[0].reloadContinuationData.continuation;
|
|
40
|
+
this.chatContinuation = (_a = data[3].response.contents.twoColumnWatchNextResults.conversationBar.liveChatRenderer) === null || _a === void 0 ? void 0 : _a.continuations[0].reloadContinuationData.continuation;
|
|
41
41
|
return this;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
@@ -65,6 +65,8 @@ class LiveVideo extends _1.BaseVideo {
|
|
|
65
65
|
const response = yield this.client.http.post(constants_1.LIVE_CHAT_END_POINT, {
|
|
66
66
|
data: { continuation: this.chatContinuation },
|
|
67
67
|
});
|
|
68
|
+
if (!response.continuationContents)
|
|
69
|
+
return;
|
|
68
70
|
this.parseChat(response.data);
|
|
69
71
|
const timedContinuation = response.data.continuationContents.liveChatContinuation.continuations[0]
|
|
70
72
|
.timedContinuationData;
|
|
@@ -68,9 +68,7 @@ let SearchResult = SearchResult_1 = class SearchResult extends Array {
|
|
|
68
68
|
const response = yield this.client.http.post(`${constants_1.I_END_POINT}/search`, {
|
|
69
69
|
data: {
|
|
70
70
|
query,
|
|
71
|
-
params:
|
|
72
|
-
? SearchResult_1.getSearchTypeParam(options.type)
|
|
73
|
-
: options.params,
|
|
71
|
+
params: options.params || SearchResult_1.getSearchTypeParam(options.type || "all"),
|
|
74
72
|
},
|
|
75
73
|
});
|
|
76
74
|
this.estimatedResults = +response.data.estimatedResults;
|
package/dist/common/HTTP.js
CHANGED
|
@@ -46,7 +46,7 @@ class HTTP {
|
|
|
46
46
|
*/
|
|
47
47
|
request(partialOptions) {
|
|
48
48
|
return new Promise((resolve, reject) => {
|
|
49
|
-
const options = Object.assign(Object.assign(Object.assign({ hostname: constants_1.BASE_URL, port: 443 }, partialOptions), this._defaultRequestOptions), { path: `${partialOptions.path}?${querystring_1.default.stringify(partialOptions.params)}`, headers: Object.assign({ "x-youtube-client-version": constants_1.INNERTUBE_CLIENT_VERSION, "x-youtube-client-name": "1", "content-type": "application/json", "accept-encoding": "gzip" }, partialOptions.headers) });
|
|
49
|
+
const options = Object.assign(Object.assign(Object.assign({ hostname: constants_1.BASE_URL, port: 443 }, partialOptions), this._defaultRequestOptions), { path: `${partialOptions.path}?${querystring_1.default.stringify(partialOptions.params)}`, headers: Object.assign({ "x-youtube-client-version": constants_1.INNERTUBE_CLIENT_VERSION, "x-youtube-client-name": "1", "content-type": "application/json", "accept-encoding": "gzip", cookie: this._cookie }, partialOptions.headers) });
|
|
50
50
|
let body = options.data || "";
|
|
51
51
|
if (options.data)
|
|
52
52
|
body = JSON.stringify(body);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "youtubei",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.29",
|
|
4
4
|
"description": "Simple package to get information from youtube such as videos, playlists, channels, video information & comments, related videos, up next video, and more!",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { YoutubeRawData } from "../common";
|
|
2
|
-
import { Base, PlaylistCompact, Thumbnails, VideoCompact, BaseAttributes } from ".";
|
|
3
|
-
/** @hidden */
|
|
4
|
-
interface CompactChannelAttributes extends BaseAttributes {
|
|
5
|
-
name: string;
|
|
6
|
-
thumbnails?: Thumbnails;
|
|
7
|
-
videoCount?: number;
|
|
8
|
-
subscriberCount?: string;
|
|
9
|
-
}
|
|
10
|
-
/** Represents a Youtube Channel */
|
|
11
|
-
export default class CompactChannel extends Base implements CompactChannelAttributes {
|
|
12
|
-
/** The channel's name */
|
|
13
|
-
name: string;
|
|
14
|
-
/** Thumbnails of the Channel with different sizes */
|
|
15
|
-
thumbnails?: Thumbnails;
|
|
16
|
-
/** How many video does this channel have */
|
|
17
|
-
videoCount?: number;
|
|
18
|
-
/**
|
|
19
|
-
* How many subscriber does this channel have,
|
|
20
|
-
*
|
|
21
|
-
* This is not the exact amount, but a literal string like `"1.95M subscribers"`
|
|
22
|
-
*/
|
|
23
|
-
subscriberCount?: string;
|
|
24
|
-
/** Loaded videos on the channel, fetched from `channel.nextVideos()` */
|
|
25
|
-
videos: VideoCompact[];
|
|
26
|
-
/** Loaded playlists on the channel, fetched from `channel.nextPlaylists()` */
|
|
27
|
-
playlists: PlaylistCompact[];
|
|
28
|
-
private _videoContinuation?;
|
|
29
|
-
private _playlistContinuation?;
|
|
30
|
-
/** @hidden */
|
|
31
|
-
constructor(channel?: Partial<CompactChannelAttributes>);
|
|
32
|
-
/** The URL of the channel page */
|
|
33
|
-
get url(): string;
|
|
34
|
-
/**
|
|
35
|
-
* Load this instance with raw data from Youtube
|
|
36
|
-
*
|
|
37
|
-
* @hidden
|
|
38
|
-
*/
|
|
39
|
-
load(data: YoutubeRawData): CompactChannel;
|
|
40
|
-
/**
|
|
41
|
-
* Load next 30 videos made by the channel, and push the loaded videos to {@link Channel.videos}
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* ```js
|
|
45
|
-
* const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
|
|
46
|
-
* await channel.nextVideos();
|
|
47
|
-
* console.log(channel.videos) // first 30 videos
|
|
48
|
-
*
|
|
49
|
-
* let newVideos = await channel.nextVideos();
|
|
50
|
-
* console.log(newVideos) // 30 loaded videos
|
|
51
|
-
* console.log(channel.videos) // first 60 videos
|
|
52
|
-
*
|
|
53
|
-
* await channel.nextVideos(0); // load the rest of the videos in the channel
|
|
54
|
-
* ```
|
|
55
|
-
*
|
|
56
|
-
* @param count How many time to load the next videos, pass `0` to load all
|
|
57
|
-
*
|
|
58
|
-
* @return New loaded videos
|
|
59
|
-
*/
|
|
60
|
-
nextVideos(count?: number): Promise<VideoCompact[]>;
|
|
61
|
-
/**
|
|
62
|
-
* Load next 30 playlists made by the channel, and push the loaded playlists to {@link Channel.playlists}
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```js
|
|
66
|
-
* const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
|
|
67
|
-
* await channel.nextPlaylists();
|
|
68
|
-
* console.log(channel.playlists) // first 30 playlists
|
|
69
|
-
*
|
|
70
|
-
* let newPlaylists = await channel.nextPlaylists();
|
|
71
|
-
* console.log(newPlaylists) // 30 loaded playlists
|
|
72
|
-
* console.log(channel.playlists) // first 60 playlists
|
|
73
|
-
*
|
|
74
|
-
* await channel.nextPlaylists(0); // load the rest of the playlists in the channel
|
|
75
|
-
* ```
|
|
76
|
-
*
|
|
77
|
-
* @param count How many time to load the next playlists, pass `0` to load all
|
|
78
|
-
*
|
|
79
|
-
* @return New loaded playlists
|
|
80
|
-
*/
|
|
81
|
-
nextPlaylists(count?: number): Promise<PlaylistCompact[]>;
|
|
82
|
-
/** Get tab data from youtube */
|
|
83
|
-
private getTabData;
|
|
84
|
-
/** Parse tab data from request, tab name is ignored if it's a continuation data */
|
|
85
|
-
private static parseTabData;
|
|
86
|
-
/** Get continuation token from items (if exists) */
|
|
87
|
-
private static getContinuationFromItems;
|
|
88
|
-
}
|
|
89
|
-
export {};
|
|
@@ -1,142 +0,0 @@
|
|
|
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 common_1 = require("../common");
|
|
13
|
-
const _1 = require(".");
|
|
14
|
-
const constants_1 = require("../constants");
|
|
15
|
-
/** Represents a Youtube Channel */
|
|
16
|
-
class CompactChannel extends _1.Base {
|
|
17
|
-
/** @hidden */
|
|
18
|
-
constructor(channel = {}) {
|
|
19
|
-
super();
|
|
20
|
-
this._videoContinuation = null;
|
|
21
|
-
this._playlistContinuation = null;
|
|
22
|
-
Object.assign(this, channel);
|
|
23
|
-
this.videos = [];
|
|
24
|
-
this.playlists = [];
|
|
25
|
-
}
|
|
26
|
-
/** The URL of the channel page */
|
|
27
|
-
get url() {
|
|
28
|
-
return `https://www.youtube.com/channel/${this.id}`;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Load this instance with raw data from Youtube
|
|
32
|
-
*
|
|
33
|
-
* @hidden
|
|
34
|
-
*/
|
|
35
|
-
load(data) {
|
|
36
|
-
const { channelId, title, thumbnail, videoCountText, subscriberCountText } = data;
|
|
37
|
-
this.id = channelId;
|
|
38
|
-
this.name = title.simpleText;
|
|
39
|
-
this.thumbnails = new _1.Thumbnails().load(thumbnail.thumbnails);
|
|
40
|
-
this.videoCount = common_1.stripToInt(videoCountText === null || videoCountText === void 0 ? void 0 : videoCountText.runs[0].text) || 0;
|
|
41
|
-
this.subscriberCount = subscriberCountText === null || subscriberCountText === void 0 ? void 0 : subscriberCountText.simpleText;
|
|
42
|
-
this.videos = [];
|
|
43
|
-
this.playlists = [];
|
|
44
|
-
return this;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Load next 30 videos made by the channel, and push the loaded videos to {@link Channel.videos}
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```js
|
|
51
|
-
* const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
|
|
52
|
-
* await channel.nextVideos();
|
|
53
|
-
* console.log(channel.videos) // first 30 videos
|
|
54
|
-
*
|
|
55
|
-
* let newVideos = await channel.nextVideos();
|
|
56
|
-
* console.log(newVideos) // 30 loaded videos
|
|
57
|
-
* console.log(channel.videos) // first 60 videos
|
|
58
|
-
*
|
|
59
|
-
* await channel.nextVideos(0); // load the rest of the videos in the channel
|
|
60
|
-
* ```
|
|
61
|
-
*
|
|
62
|
-
* @param count How many time to load the next videos, pass `0` to load all
|
|
63
|
-
*
|
|
64
|
-
* @return New loaded videos
|
|
65
|
-
*/
|
|
66
|
-
nextVideos(count = 1) {
|
|
67
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
-
const newVideos = [];
|
|
69
|
-
for (let i = 0; i < count || count == 0; i++) {
|
|
70
|
-
if (this._videoContinuation === undefined)
|
|
71
|
-
break;
|
|
72
|
-
const items = yield this.getTabData("videos");
|
|
73
|
-
this._videoContinuation = CompactChannel.getContinuationFromItems(items);
|
|
74
|
-
newVideos.push(...items
|
|
75
|
-
.filter((i) => i.gridVideoRenderer)
|
|
76
|
-
.map((i) => new _1.VideoCompact({ client: this.client }).load(i.gridVideoRenderer)));
|
|
77
|
-
}
|
|
78
|
-
this.videos.push(...newVideos);
|
|
79
|
-
return newVideos;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Load next 30 playlists made by the channel, and push the loaded playlists to {@link Channel.playlists}
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```js
|
|
87
|
-
* const channel = await youtube.findOne(CHANNEL_NAME, {type: "channel"});
|
|
88
|
-
* await channel.nextPlaylists();
|
|
89
|
-
* console.log(channel.playlists) // first 30 playlists
|
|
90
|
-
*
|
|
91
|
-
* let newPlaylists = await channel.nextPlaylists();
|
|
92
|
-
* console.log(newPlaylists) // 30 loaded playlists
|
|
93
|
-
* console.log(channel.playlists) // first 60 playlists
|
|
94
|
-
*
|
|
95
|
-
* await channel.nextPlaylists(0); // load the rest of the playlists in the channel
|
|
96
|
-
* ```
|
|
97
|
-
*
|
|
98
|
-
* @param count How many time to load the next playlists, pass `0` to load all
|
|
99
|
-
*
|
|
100
|
-
* @return New loaded playlists
|
|
101
|
-
*/
|
|
102
|
-
nextPlaylists(count = 1) {
|
|
103
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
const newPlaylists = [];
|
|
105
|
-
for (let i = 0; i < count || count == 0; i++) {
|
|
106
|
-
if (this._playlistContinuation === undefined)
|
|
107
|
-
break;
|
|
108
|
-
const items = yield this.getTabData("playlists");
|
|
109
|
-
this._playlistContinuation = CompactChannel.getContinuationFromItems(items);
|
|
110
|
-
newPlaylists.push(...items
|
|
111
|
-
.filter((i) => i.gridPlaylistRenderer)
|
|
112
|
-
.map((i) => new _1.PlaylistCompact({ client: this.client }).load(i.gridPlaylistRenderer)));
|
|
113
|
-
}
|
|
114
|
-
this.playlists.push(...newPlaylists);
|
|
115
|
-
return newPlaylists;
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
/** Get tab data from youtube */
|
|
119
|
-
getTabData(name) {
|
|
120
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
121
|
-
const params = name === "videos" ? "EgZ2aWRlb3M%3D" : "EglwbGF5bGlzdHMgAQ%3D%3D";
|
|
122
|
-
const continuation = name === "videos" ? this._videoContinuation : this._playlistContinuation;
|
|
123
|
-
const response = yield this.client.http.post(`${constants_1.I_END_POINT}/browse`, {
|
|
124
|
-
data: { browseId: this.id, params, continuation },
|
|
125
|
-
});
|
|
126
|
-
return CompactChannel.parseTabData(name, response.data);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
/** Parse tab data from request, tab name is ignored if it's a continuation data */
|
|
130
|
-
static parseTabData(name, data) {
|
|
131
|
-
var _a;
|
|
132
|
-
const index = name === "videos" ? 1 : 2;
|
|
133
|
-
return (((_a = data.contents) === null || _a === void 0 ? void 0 : _a.twoColumnBrowseResultsRenderer.tabs[index].tabRenderer.content.sectionListRenderer.contents[0].itemSectionRenderer.contents[0].gridRenderer.items) ||
|
|
134
|
-
data.onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems);
|
|
135
|
-
}
|
|
136
|
-
/** Get continuation token from items (if exists) */
|
|
137
|
-
static getContinuationFromItems(items) {
|
|
138
|
-
var _a;
|
|
139
|
-
return (_a = items[items.length - 1].continuationItemRenderer) === null || _a === void 0 ? void 0 : _a.continuationEndpoint.continuationCommand.token;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
exports.default = CompactChannel;
|