youtubei 0.0.1-rc.3 → 0.0.1-rc.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/classes/Base.d.ts +10 -0
- package/dist/classes/{client/types.js → Base.js} +3 -0
- package/dist/classes/BaseVideo.d.ts +59 -0
- package/dist/classes/BaseVideo.js +121 -0
- package/dist/classes/Channel.d.ts +27 -31
- package/dist/classes/Channel.js +59 -135
- package/dist/classes/ChannelCompact.d.ts +74 -23
- package/dist/classes/ChannelCompact.js +114 -103
- package/dist/classes/Chat.d.ts +29 -0
- package/dist/classes/Chat.js +31 -0
- package/dist/classes/Client.d.ts +49 -0
- package/dist/classes/Client.js +97 -0
- package/dist/classes/Comment.d.ts +50 -0
- package/dist/classes/Comment.js +84 -0
- package/dist/classes/LiveVideo.d.ts +47 -0
- package/dist/classes/LiveVideo.js +94 -0
- package/dist/classes/MixPlaylist.d.ts +32 -0
- package/dist/classes/MixPlaylist.js +44 -0
- package/dist/classes/Playlist.d.ts +35 -18
- package/dist/classes/Playlist.js +80 -116
- package/dist/classes/PlaylistCompact.d.ts +27 -15
- package/dist/classes/PlaylistCompact.js +42 -46
- package/dist/classes/Reply.d.ts +38 -0
- package/dist/classes/Reply.js +35 -0
- package/dist/classes/SearchResult.d.ts +52 -8
- package/dist/classes/SearchResult.js +101 -122
- package/dist/classes/Thumbnails.d.ts +42 -0
- package/dist/classes/Thumbnails.js +66 -0
- package/dist/classes/Video.d.ts +44 -37
- package/dist/classes/Video.js +74 -83
- package/dist/classes/VideoCompact.d.ts +38 -19
- package/dist/classes/VideoCompact.js +53 -53
- package/dist/classes/index.d.ts +10 -2
- package/dist/classes/index.js +20 -4
- package/dist/common/HTTP.d.ts +26 -0
- package/dist/common/HTTP.js +85 -0
- package/dist/common/decorators.js +6 -26
- package/dist/common/helper.d.ts +4 -0
- package/dist/common/helper.js +37 -18
- package/dist/common/index.d.ts +2 -1
- package/dist/common/index.js +5 -3
- package/dist/common/mixins.d.ts +2 -0
- package/dist/common/mixins.js +12 -0
- package/dist/common/types.d.ts +0 -5
- package/dist/constants.d.ts +5 -2
- package/dist/constants.js +6 -3
- package/package.json +23 -20
- package/.prettierrc +0 -8
- package/.vscode/settings.json +0 -4
- package/CHANGELOG.md +0 -6
- package/debug.log +0 -47
- package/dist/classes/BaseCompact.d.ts +0 -10
- package/dist/classes/BaseCompact.js +0 -27
- package/dist/classes/client/Client.d.ts +0 -23
- package/dist/classes/client/Client.js +0 -128
- package/dist/classes/client/index.d.ts +0 -2
- package/dist/classes/client/index.js +0 -19
- package/dist/classes/client/types.d.ts +0 -12
- package/dist/common/axios.d.ts +0 -4
- package/dist/common/axios.js +0 -44
- package/jest.config.js +0 -5
|
@@ -0,0 +1,94 @@
|
|
|
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 events_1 = require("events");
|
|
13
|
+
const common_1 = require("../common");
|
|
14
|
+
const _1 = require(".");
|
|
15
|
+
const constants_1 = require("../constants");
|
|
16
|
+
/** Represents a video that's currently live, usually returned from `client.getVideo()` */
|
|
17
|
+
class LiveVideo extends _1.BaseVideo {
|
|
18
|
+
/** @hidden */
|
|
19
|
+
constructor(video = {}) {
|
|
20
|
+
super();
|
|
21
|
+
this._delay = 0;
|
|
22
|
+
this._timeoutMs = 0;
|
|
23
|
+
this._isChatPlaying = false;
|
|
24
|
+
this._chatQueue = [];
|
|
25
|
+
Object.assign(this, video);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Load this instance with raw data from Youtube
|
|
29
|
+
*
|
|
30
|
+
* @hidden
|
|
31
|
+
*/
|
|
32
|
+
load(data) {
|
|
33
|
+
var _a;
|
|
34
|
+
super.load(data);
|
|
35
|
+
const videoInfo = _1.BaseVideo.parseRawData(data);
|
|
36
|
+
this.watchingCount = +videoInfo.viewCount.videoViewCountRenderer.viewCount.runs
|
|
37
|
+
.map((r) => r.text)
|
|
38
|
+
.join(" ")
|
|
39
|
+
.replace(/[^0-9]/g, "");
|
|
40
|
+
this.chatContinuation = (_a = data[3].response.contents.twoColumnWatchNextResults.conversationBar.liveChatRenderer) === null || _a === void 0 ? void 0 : _a.continuations[0].reloadContinuationData.continuation;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Start polling for get live chat request
|
|
45
|
+
*
|
|
46
|
+
* @param delay chat delay in millisecond
|
|
47
|
+
*/
|
|
48
|
+
playChat(delay = 0) {
|
|
49
|
+
if (this._isChatPlaying)
|
|
50
|
+
return;
|
|
51
|
+
this._delay = delay;
|
|
52
|
+
this._isChatPlaying = true;
|
|
53
|
+
this.pollChatContinuation();
|
|
54
|
+
}
|
|
55
|
+
/** Stop request polling for live chat */
|
|
56
|
+
stopChat() {
|
|
57
|
+
if (!this._chatRequestPoolingTimeout)
|
|
58
|
+
return;
|
|
59
|
+
this._isChatPlaying = false;
|
|
60
|
+
clearTimeout(this._chatRequestPoolingTimeout);
|
|
61
|
+
}
|
|
62
|
+
/** Start request polling */
|
|
63
|
+
pollChatContinuation() {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
const response = yield this.client.http.post(constants_1.LIVE_CHAT_END_POINT, {
|
|
66
|
+
data: { continuation: this.chatContinuation },
|
|
67
|
+
});
|
|
68
|
+
if (!response.data.continuationContents)
|
|
69
|
+
return;
|
|
70
|
+
this.parseChat(response.data);
|
|
71
|
+
const continuation = response.data.continuationContents.liveChatContinuation.continuations[0];
|
|
72
|
+
const continuationData = continuation.timedContinuationData || continuation.invalidationContinuationData;
|
|
73
|
+
this._timeoutMs = continuationData.timeoutMs;
|
|
74
|
+
this.chatContinuation = continuationData.continuation;
|
|
75
|
+
this._chatRequestPoolingTimeout = setTimeout(() => this.pollChatContinuation(), this._timeoutMs);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** Parse chat data from Youtube and add to chatQueue */
|
|
79
|
+
parseChat(data) {
|
|
80
|
+
var _a;
|
|
81
|
+
const chats = ((_a = data.continuationContents.liveChatContinuation.actions) === null || _a === void 0 ? void 0 : _a.flatMap((a) => { var _a; return ((_a = a.addChatItemAction) === null || _a === void 0 ? void 0 : _a.item.liveChatTextMessageRenderer) || []; })) || [];
|
|
82
|
+
for (const rawChatData of chats) {
|
|
83
|
+
const chat = new _1.Chat({ client: this.client }).load(rawChatData);
|
|
84
|
+
if (this._chatQueue.find((c) => c.id === chat.id))
|
|
85
|
+
continue;
|
|
86
|
+
this._chatQueue.push(chat);
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
this.emit("chat", chat);
|
|
89
|
+
}, chat.timestamp / 1000 - (new Date().getTime() - this._delay));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
common_1.applyMixins(LiveVideo, [events_1.EventEmitter]);
|
|
94
|
+
exports.default = LiveVideo;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Base, BaseAttributes, VideoCompact } from ".";
|
|
2
|
+
import { YoutubeRawData } from "../common";
|
|
3
|
+
/** @hidden */
|
|
4
|
+
interface PlaylistAttributes extends BaseAttributes {
|
|
5
|
+
title: string;
|
|
6
|
+
videoCount: number;
|
|
7
|
+
videos: VideoCompact[];
|
|
8
|
+
}
|
|
9
|
+
/** Represents a MixPlaylist, usually returned from `client.getPlaylist()` */
|
|
10
|
+
export default class MixPlaylist extends Base implements PlaylistAttributes {
|
|
11
|
+
/** The title of this playlist */
|
|
12
|
+
title: string;
|
|
13
|
+
/** How many videos in this playlist */
|
|
14
|
+
videoCount: number;
|
|
15
|
+
/** How many viewers does this playlist have */
|
|
16
|
+
videos: VideoCompact[];
|
|
17
|
+
/** @hidden */
|
|
18
|
+
constructor(playlist?: Partial<MixPlaylist>);
|
|
19
|
+
/**
|
|
20
|
+
* Load this instance with raw data from Youtube
|
|
21
|
+
*
|
|
22
|
+
* @hidden
|
|
23
|
+
*/
|
|
24
|
+
load(data: YoutubeRawData): MixPlaylist;
|
|
25
|
+
/**
|
|
26
|
+
* Get compact videos
|
|
27
|
+
*
|
|
28
|
+
* @param MixplaylistContents raw object from youtubei
|
|
29
|
+
*/
|
|
30
|
+
private static parseVideos;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _1 = require(".");
|
|
4
|
+
/** Represents a MixPlaylist, usually returned from `client.getPlaylist()` */
|
|
5
|
+
class MixPlaylist extends _1.Base {
|
|
6
|
+
/** @hidden */
|
|
7
|
+
constructor(playlist = {}) {
|
|
8
|
+
super();
|
|
9
|
+
/** How many viewers does this playlist have */
|
|
10
|
+
this.videos = [];
|
|
11
|
+
Object.assign(this, playlist);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Load this instance with raw data from Youtube
|
|
15
|
+
*
|
|
16
|
+
* @hidden
|
|
17
|
+
*/
|
|
18
|
+
load(data) {
|
|
19
|
+
const twoColumnWatchNextResults = data.contents.twoColumnWatchNextResults;
|
|
20
|
+
const playlist = twoColumnWatchNextResults.playlist.playlist;
|
|
21
|
+
this.title = playlist.titleText.simpleText;
|
|
22
|
+
this.id = playlist.playlistId;
|
|
23
|
+
this.videoCount = playlist.contents.length;
|
|
24
|
+
this.videos = MixPlaylist.parseVideos(playlist.contents, this);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get compact videos
|
|
29
|
+
*
|
|
30
|
+
* @param MixplaylistContents raw object from youtubei
|
|
31
|
+
*/
|
|
32
|
+
static parseVideos(MixplaylistContents, playlist) {
|
|
33
|
+
const videosRenderer = MixplaylistContents.map((c) => c.playlistPanelVideoRenderer);
|
|
34
|
+
const videos = [];
|
|
35
|
+
for (const videoRenderer of videosRenderer) {
|
|
36
|
+
if (!videoRenderer)
|
|
37
|
+
continue;
|
|
38
|
+
const video = new _1.VideoCompact({ client: playlist.client }).load(videoRenderer);
|
|
39
|
+
videos.push(video);
|
|
40
|
+
}
|
|
41
|
+
return videos;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.default = MixPlaylist;
|
|
@@ -1,36 +1,53 @@
|
|
|
1
|
+
import { BaseAttributes, VideoCompact, ChannelCompact, Base } from ".";
|
|
1
2
|
import { YoutubeRawData } from "../common";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
interface PlaylistAttributes {
|
|
5
|
-
id: string;
|
|
3
|
+
/** @hidden */
|
|
4
|
+
interface PlaylistAttributes extends BaseAttributes {
|
|
6
5
|
title: string;
|
|
7
6
|
videoCount: number;
|
|
8
7
|
viewCount: number;
|
|
9
8
|
lastUpdatedAt: string;
|
|
10
|
-
channel?:
|
|
9
|
+
channel?: ChannelCompact;
|
|
11
10
|
videos: VideoCompact[];
|
|
11
|
+
continuation?: string;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
*/
|
|
16
|
-
export default class Playlist implements PlaylistAttributes {
|
|
17
|
-
id: string;
|
|
13
|
+
/** Represents a Playlist, usually returned from `client.getPlaylist()` */
|
|
14
|
+
export default class Playlist extends Base implements PlaylistAttributes {
|
|
15
|
+
/** The title of this playlist */
|
|
18
16
|
title: string;
|
|
17
|
+
/** How many videos in this playlist */
|
|
19
18
|
videoCount: number;
|
|
19
|
+
/** How many viewers does this playlist have */
|
|
20
20
|
viewCount: number;
|
|
21
|
+
/** Last time this playlist is updated */
|
|
21
22
|
lastUpdatedAt: string;
|
|
22
|
-
channel
|
|
23
|
+
/** The channel that made this playlist */
|
|
24
|
+
channel?: ChannelCompact;
|
|
25
|
+
/** Videos in the playlist */
|
|
23
26
|
videos: VideoCompact[];
|
|
24
|
-
|
|
27
|
+
/** Current continuation token to load next videos */
|
|
28
|
+
continuation: string | undefined;
|
|
29
|
+
/** @hidden */
|
|
25
30
|
constructor(playlist?: Partial<Playlist>);
|
|
26
31
|
/**
|
|
27
|
-
* Load instance
|
|
32
|
+
* Load this instance with raw data from Youtube
|
|
28
33
|
*
|
|
29
|
-
* @
|
|
34
|
+
* @hidden
|
|
30
35
|
*/
|
|
31
|
-
load(
|
|
36
|
+
load(data: YoutubeRawData): Playlist;
|
|
32
37
|
/**
|
|
33
|
-
* Load next videos of the playlist
|
|
38
|
+
* Load next 100 videos of the playlist, and push the loaded videos to {@link Playlist.videos}
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```js
|
|
42
|
+
* const playlist = await youtube.getPlaylist(PLAYLIST_ID);
|
|
43
|
+
* console.log(playlist.videos) // first 100 videos
|
|
44
|
+
*
|
|
45
|
+
* let newVideos = await playlist.next();
|
|
46
|
+
* console.log(newVideos) // 100 loaded videos
|
|
47
|
+
* console.log(playlist.videos) // first 200 videos
|
|
48
|
+
*
|
|
49
|
+
* await playlist.next(0); // load the rest of the videos in the playlist
|
|
50
|
+
* ```
|
|
34
51
|
*
|
|
35
52
|
* @param count How many times to load the next videos. Set 0 to load all videos (might take a while on a large playlist!)
|
|
36
53
|
*/
|
|
@@ -40,7 +57,7 @@ export default class Playlist implements PlaylistAttributes {
|
|
|
40
57
|
*
|
|
41
58
|
* @param playlistContents raw object from youtubei
|
|
42
59
|
*/
|
|
43
|
-
private
|
|
44
|
-
private
|
|
60
|
+
private static parseVideos;
|
|
61
|
+
private static parseSideBarInfo;
|
|
45
62
|
}
|
|
46
63
|
export {};
|
package/dist/classes/Playlist.js
CHANGED
|
@@ -8,160 +8,124 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (_) try {
|
|
18
|
-
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;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
-
};
|
|
41
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
12
|
+
const _1 = require(".");
|
|
13
|
+
const common_1 = require("../common");
|
|
14
|
+
const constants_1 = require("../constants");
|
|
15
|
+
/** Represents a Playlist, usually returned from `client.getPlaylist()` */
|
|
16
|
+
class Playlist extends _1.Base {
|
|
17
|
+
/** @hidden */
|
|
18
|
+
constructor(playlist = {}) {
|
|
19
|
+
super();
|
|
20
|
+
/** Videos in the playlist */
|
|
21
|
+
this.videos = [];
|
|
52
22
|
Object.assign(this, playlist);
|
|
53
23
|
}
|
|
54
24
|
/**
|
|
55
|
-
* Load instance
|
|
25
|
+
* Load this instance with raw data from Youtube
|
|
56
26
|
*
|
|
57
|
-
* @
|
|
27
|
+
* @hidden
|
|
58
28
|
*/
|
|
59
|
-
|
|
60
|
-
var _a, _b;
|
|
61
|
-
|
|
62
|
-
|
|
29
|
+
load(data) {
|
|
30
|
+
var _a, _b, _c;
|
|
31
|
+
const sidebarRenderer = data.sidebar.playlistSidebarRenderer.items;
|
|
32
|
+
const primaryRenderer = sidebarRenderer[0].playlistSidebarPrimaryInfoRenderer;
|
|
33
|
+
const metadata = data.metadata.playlistMetadataRenderer;
|
|
63
34
|
// Basic information
|
|
64
|
-
this.id =
|
|
65
|
-
|
|
66
|
-
|
|
35
|
+
this.id = (_a = Object.values(metadata)
|
|
36
|
+
.find((v) => v.includes("playlist?list="))) === null || _a === void 0 ? void 0 : _a.split("=")[1];
|
|
37
|
+
this.title = metadata.title;
|
|
38
|
+
const { stats } = primaryRenderer;
|
|
67
39
|
if (primaryRenderer.stats.length === 3) {
|
|
68
|
-
this.videoCount =
|
|
69
|
-
this.viewCount =
|
|
70
|
-
this.lastUpdatedAt =
|
|
40
|
+
this.videoCount = Playlist.parseSideBarInfo(stats[0], true);
|
|
41
|
+
this.viewCount = Playlist.parseSideBarInfo(stats[1], true);
|
|
42
|
+
this.lastUpdatedAt = Playlist.parseSideBarInfo(stats[2], false);
|
|
71
43
|
}
|
|
72
44
|
else if (stats.length === 2) {
|
|
73
|
-
this.videoCount =
|
|
74
|
-
this.lastUpdatedAt =
|
|
45
|
+
this.videoCount = Playlist.parseSideBarInfo(stats[0], true);
|
|
46
|
+
this.lastUpdatedAt = Playlist.parseSideBarInfo(stats[1], false);
|
|
75
47
|
}
|
|
76
|
-
|
|
77
|
-
var playlistContents = youtubeRawData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content
|
|
48
|
+
const playlistContents = ((_b = data.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content
|
|
78
49
|
.sectionListRenderer.contents[0].itemSectionRenderer.contents[0]
|
|
79
|
-
.playlistVideoListRenderer.contents;
|
|
80
|
-
var videos = this.getVideos(playlistContents);
|
|
50
|
+
.playlistVideoListRenderer) === null || _b === void 0 ? void 0 : _b.contents) || [];
|
|
81
51
|
// Video Continuation Token
|
|
82
|
-
this.
|
|
83
|
-
this.videos = videos;
|
|
52
|
+
this.continuation = common_1.getContinuationFromItems(playlistContents);
|
|
84
53
|
// Channel
|
|
85
|
-
|
|
54
|
+
const videoOwner = (_c = sidebarRenderer[1]) === null || _c === void 0 ? void 0 : _c.playlistSidebarSecondaryInfoRenderer.videoOwner;
|
|
86
55
|
if (videoOwner) {
|
|
87
|
-
|
|
88
|
-
this.channel = new
|
|
56
|
+
const { title, thumbnail } = videoOwner.videoOwnerRenderer;
|
|
57
|
+
this.channel = new _1.ChannelCompact({
|
|
89
58
|
id: title.runs[0].navigationEndpoint.browseEndpoint.browseId,
|
|
90
59
|
name: title.runs[0].text,
|
|
91
|
-
thumbnails: thumbnail.thumbnails,
|
|
92
|
-
|
|
93
|
-
title.runs[0].navigationEndpoint.commandMetadata.webCommandMetadata.url,
|
|
60
|
+
thumbnails: new _1.Thumbnails().load(thumbnail.thumbnails),
|
|
61
|
+
client: this.client,
|
|
94
62
|
});
|
|
95
63
|
}
|
|
64
|
+
// Videos
|
|
65
|
+
this.videos = Playlist.parseVideos(playlistContents, this);
|
|
96
66
|
return this;
|
|
97
|
-
}
|
|
67
|
+
}
|
|
98
68
|
/**
|
|
99
|
-
* Load next videos of the playlist
|
|
69
|
+
* Load next 100 videos of the playlist, and push the loaded videos to {@link Playlist.videos}
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```js
|
|
73
|
+
* const playlist = await youtube.getPlaylist(PLAYLIST_ID);
|
|
74
|
+
* console.log(playlist.videos) // first 100 videos
|
|
75
|
+
*
|
|
76
|
+
* let newVideos = await playlist.next();
|
|
77
|
+
* console.log(newVideos) // 100 loaded videos
|
|
78
|
+
* console.log(playlist.videos) // first 200 videos
|
|
79
|
+
*
|
|
80
|
+
* await playlist.next(0); // load the rest of the videos in the playlist
|
|
81
|
+
* ```
|
|
100
82
|
*
|
|
101
83
|
* @param count How many times to load the next videos. Set 0 to load all videos (might take a while on a large playlist!)
|
|
102
84
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
continuation: this.latestContinuationToken,
|
|
121
|
-
})];
|
|
122
|
-
case 2:
|
|
123
|
-
response = _c.sent();
|
|
124
|
-
playlistContents = response.data.onResponseReceivedActions[0].appendContinuationItemsAction
|
|
125
|
-
.continuationItems;
|
|
126
|
-
newVideos.push.apply(newVideos, this.getVideos(playlistContents));
|
|
127
|
-
this.latestContinuationToken = (_a = playlistContents[100]) === null || _a === void 0 ? void 0 : _a.continuationItemRenderer.continuationEndpoint.continuationCommand.token;
|
|
128
|
-
_c.label = 3;
|
|
129
|
-
case 3:
|
|
130
|
-
i++;
|
|
131
|
-
return [3 /*break*/, 1];
|
|
132
|
-
case 4:
|
|
133
|
-
(_b = this.videos).push.apply(_b, newVideos);
|
|
134
|
-
return [2 /*return*/, newVideos];
|
|
135
|
-
}
|
|
136
|
-
});
|
|
85
|
+
next(count = 1) {
|
|
86
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
const newVideos = [];
|
|
88
|
+
for (let i = 0; i < count || count == 0; i++) {
|
|
89
|
+
if (!this.continuation)
|
|
90
|
+
break;
|
|
91
|
+
const response = yield this.client.http.post(`${constants_1.I_END_POINT}/browse`, {
|
|
92
|
+
data: { continuation: this.continuation },
|
|
93
|
+
});
|
|
94
|
+
const playlistContents = response.data.onResponseReceivedActions[0].appendContinuationItemsAction
|
|
95
|
+
.continuationItems;
|
|
96
|
+
const videos = common_1.mapFilter(playlistContents, "playlistVideoRenderer");
|
|
97
|
+
newVideos.push(...videos.map((video) => new _1.VideoCompact({ client: this.client }).load(video)));
|
|
98
|
+
this.continuation = common_1.getContinuationFromItems(playlistContents);
|
|
99
|
+
}
|
|
100
|
+
this.videos.push(...newVideos);
|
|
101
|
+
return newVideos;
|
|
137
102
|
});
|
|
138
|
-
}
|
|
103
|
+
}
|
|
139
104
|
/**
|
|
140
105
|
* Get compact videos
|
|
141
106
|
*
|
|
142
107
|
* @param playlistContents raw object from youtubei
|
|
143
108
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
for (
|
|
148
|
-
var videoRenderer = videosRenderer_1[_i];
|
|
109
|
+
static parseVideos(playlistContents, playlist) {
|
|
110
|
+
const videosRenderer = playlistContents.map((c) => c.playlistVideoRenderer);
|
|
111
|
+
const videos = [];
|
|
112
|
+
for (const videoRenderer of videosRenderer) {
|
|
149
113
|
if (!videoRenderer)
|
|
150
114
|
continue;
|
|
151
|
-
|
|
115
|
+
const video = new _1.VideoCompact({ client: playlist.client }).load(videoRenderer);
|
|
116
|
+
videos.push(video);
|
|
152
117
|
}
|
|
153
118
|
return videos;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
119
|
+
}
|
|
120
|
+
static parseSideBarInfo(stats, parseInt) {
|
|
121
|
+
let data;
|
|
157
122
|
if ("runs" in stats)
|
|
158
|
-
data = stats.runs.map(
|
|
123
|
+
data = stats.runs.map((r) => r.text).join("");
|
|
159
124
|
else
|
|
160
125
|
data = stats.simpleText.replace(/[^0-9]/g, "");
|
|
161
126
|
if (parseInt)
|
|
162
127
|
data = +data.replace(/[^0-9]/g, "");
|
|
163
128
|
return data;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
}());
|
|
129
|
+
}
|
|
130
|
+
}
|
|
167
131
|
exports.default = Playlist;
|
|
@@ -1,26 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
interface PlaylistCompactAttributes {
|
|
5
|
-
id: string;
|
|
1
|
+
import { Thumbnails, BaseAttributes, Base, Playlist, ChannelCompact } from ".";
|
|
2
|
+
import { YoutubeRawData } from "../common";
|
|
3
|
+
/** @hidden */
|
|
4
|
+
interface PlaylistCompactAttributes extends BaseAttributes {
|
|
6
5
|
title: string;
|
|
7
|
-
thumbnails:
|
|
8
|
-
channel?:
|
|
6
|
+
thumbnails: Thumbnails;
|
|
7
|
+
channel?: ChannelCompact;
|
|
9
8
|
videoCount: number;
|
|
10
9
|
}
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
*/
|
|
14
|
-
export default class PlaylistCompact extends BaseCompact implements PlaylistCompactAttributes {
|
|
10
|
+
/** Represents a Compact Playlist (e.g. from search result, upNext / related of a video) */
|
|
11
|
+
export default class PlaylistCompact extends Base implements PlaylistCompactAttributes {
|
|
12
|
+
/** The playlist's title */
|
|
15
13
|
title: string;
|
|
16
|
-
|
|
14
|
+
/** Thumbnails of the playlist with different sizes */
|
|
15
|
+
thumbnails: Thumbnails;
|
|
16
|
+
/** The channel that made this playlist */
|
|
17
|
+
channel?: ChannelCompact;
|
|
18
|
+
/** How many videos in this playlist */
|
|
17
19
|
videoCount: number;
|
|
20
|
+
/** @hidden */
|
|
18
21
|
constructor(playlist?: Partial<PlaylistCompactAttributes>);
|
|
19
22
|
/**
|
|
20
|
-
* Load instance
|
|
23
|
+
* Load this instance with raw data from Youtube
|
|
21
24
|
*
|
|
22
|
-
* @
|
|
25
|
+
* @hidden
|
|
23
26
|
*/
|
|
24
|
-
load(
|
|
27
|
+
load(data: YoutubeRawData): PlaylistCompact;
|
|
28
|
+
/**
|
|
29
|
+
* Get {@link Playlist} object based on current playlist id
|
|
30
|
+
*
|
|
31
|
+
* Equivalent to
|
|
32
|
+
* ```js
|
|
33
|
+
* client.getPlaylist(playlistCompact.id);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
getPlaylist(): Promise<Playlist | undefined>;
|
|
25
37
|
}
|
|
26
38
|
export {};
|
|
@@ -1,63 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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 __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
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
|
+
});
|
|
17
10
|
};
|
|
18
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (playlist === void 0) { playlist = {}; }
|
|
28
|
-
var _this = _super.call(this) || this;
|
|
29
|
-
Object.assign(_this, playlist);
|
|
30
|
-
return _this;
|
|
12
|
+
const _1 = require(".");
|
|
13
|
+
const common_1 = require("../common");
|
|
14
|
+
/** Represents a Compact Playlist (e.g. from search result, upNext / related of a video) */
|
|
15
|
+
class PlaylistCompact extends _1.Base {
|
|
16
|
+
/** @hidden */
|
|
17
|
+
constructor(playlist = {}) {
|
|
18
|
+
super();
|
|
19
|
+
Object.assign(this, playlist);
|
|
31
20
|
}
|
|
32
21
|
/**
|
|
33
|
-
* Load instance
|
|
22
|
+
* Load this instance with raw data from Youtube
|
|
34
23
|
*
|
|
35
|
-
* @
|
|
24
|
+
* @hidden
|
|
36
25
|
*/
|
|
37
|
-
|
|
26
|
+
load(data) {
|
|
38
27
|
var _a;
|
|
39
|
-
|
|
28
|
+
const { playlistId, title, thumbnail, shortBylineText, videoCount, videoCountShortText, } = data;
|
|
40
29
|
this.id = playlistId;
|
|
41
30
|
this.title = title.simpleText || title.runs[0].text;
|
|
42
|
-
this.videoCount =
|
|
43
|
-
+((_a = (videoCount !== null && videoCount !== void 0 ? videoCount : videoCountShortText.simpleText)) === null || _a === void 0 ? void 0 : _a.replace(/[^0-9]/g, "")) || 0;
|
|
31
|
+
this.videoCount = common_1.stripToInt(videoCount || videoCountShortText.simpleText) || 0;
|
|
44
32
|
// Thumbnail
|
|
45
|
-
|
|
46
|
-
if (!thumbnails)
|
|
47
|
-
thumbnails = thumbnail.thumbnails;
|
|
48
|
-
else
|
|
49
|
-
thumbnails = thumbnails[0].thumbnails;
|
|
50
|
-
this.thumbnails = thumbnails;
|
|
33
|
+
this.thumbnails = new _1.Thumbnails().load(((_a = data.thumbnails) === null || _a === void 0 ? void 0 : _a[0].thumbnails) || thumbnail.thumbnails);
|
|
51
34
|
// Channel
|
|
52
35
|
if (shortBylineText && shortBylineText.simpleText !== "YouTube") {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
const shortByLine = shortBylineText.runs[0];
|
|
37
|
+
this.channel = new _1.ChannelCompact({
|
|
38
|
+
id: shortByLine.navigationEndpoint.browseEndpoint.browseId,
|
|
39
|
+
name: shortByLine.text,
|
|
40
|
+
client: this.client,
|
|
57
41
|
});
|
|
58
42
|
}
|
|
59
43
|
return this;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get {@link Playlist} object based on current playlist id
|
|
47
|
+
*
|
|
48
|
+
* Equivalent to
|
|
49
|
+
* ```js
|
|
50
|
+
* client.getPlaylist(playlistCompact.id);
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
getPlaylist() {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
return (yield this.client.getPlaylist(this.id));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
63
59
|
exports.default = PlaylistCompact;
|