mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-15 02:22:11 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ad26f28d9 | ||
|
|
4c7b8a3403 | ||
|
|
33a6e740d7 | ||
|
|
0b1840a62c | ||
|
|
f4e0f30e6e | ||
|
|
200632f374 | ||
|
|
f933cb45bc | ||
|
|
a0e6cef00f | ||
|
|
a0bfe16427 | ||
|
|
9d352b58eb |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,5 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
## [3.1.1](https://github.com/LuanRT/YouTube.js/compare/v3.1.0...v3.1.1) (2023-03-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Channel:** getting community continuations ([#329](https://github.com/LuanRT/YouTube.js/issues/329)) ([4c7b8a3](https://github.com/LuanRT/YouTube.js/commit/4c7b8a34030effa26c4ea186d3e9509128aec31c))
|
||||
|
||||
## [3.1.0](https://github.com/LuanRT/YouTube.js/compare/v3.0.0...v3.1.0) (2023-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add upcoming and live info to playlist videos ([#317](https://github.com/LuanRT/YouTube.js/issues/317)) ([a0bfe16](https://github.com/LuanRT/YouTube.js/commit/a0bfe164279ec27b0c49c6b0c32222c1a92df5c3))
|
||||
* **VideoSecondaryInfo:** add support for attributed descriptions ([#325](https://github.com/LuanRT/YouTube.js/issues/325)) ([f933cb4](https://github.com/LuanRT/YouTube.js/commit/f933cb45bcb92c07b3bc063d63869a51cbff4eb0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **parser:** export YTNodes individually so they can be used as types ([200632f](https://github.com/LuanRT/YouTube.js/commit/200632f374d5e0e105b600d579a2665a6fb36e38)), closes [#321](https://github.com/LuanRT/YouTube.js/issues/321)
|
||||
* **PlayerMicroformat:** Make the embed field optional ([#320](https://github.com/LuanRT/YouTube.js/issues/320)) ([a0e6cef](https://github.com/LuanRT/YouTube.js/commit/a0e6cef00fb9e3f52593cec22704f7ddc1f7553e))
|
||||
* send correct UA for Android requests ([f4e0f30](https://github.com/LuanRT/YouTube.js/commit/f4e0f30e6e94b347b28d67d9a86284ea2d23ee15)), closes [#322](https://github.com/LuanRT/YouTube.js/issues/322)
|
||||
|
||||
## [3.0.0](https://github.com/LuanRT/YouTube.js/compare/v2.9.0...v3.0.0) (2023-02-17)
|
||||
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
Thank you for taking the time to contribute!
|
||||
The following is a set of guidelines for contributing to YouTube.js.
|
||||
___
|
||||
* [Issues](#issues)
|
||||
* [Create a new issue](#issue-1)
|
||||
* [Solve an issue](#issue-2)
|
||||
|
||||
* [Make changes](#changes)
|
||||
* [Commit your updates](#changes-1)
|
||||
* [Create a PR](#changes-2)
|
||||
* [Run tests](#test)
|
||||
* [Lint your code](#lint)
|
||||
* [Build](#build)
|
||||
- [Contributing to YouTube.js](#contributing-to-youtubejs)
|
||||
- [Issues](#issues)
|
||||
- [Create a new issue](#create-a-new-issue)
|
||||
- [Solve an issue](#solve-an-issue)
|
||||
- [Make changes](#make-changes)
|
||||
- [Commit your updates](#commit-your-updates)
|
||||
- [Pull Request](#pull-request)
|
||||
- [Test](#test)
|
||||
- [Lint](#lint)
|
||||
- [Build](#build)
|
||||
|
||||
## Issues
|
||||
|
||||
@@ -66,16 +66,26 @@ npm run lint:fix
|
||||
#### Build
|
||||
|
||||
```bash
|
||||
# Node
|
||||
npm run build:node
|
||||
|
||||
# Browser
|
||||
npm run build:browser
|
||||
npm run build:browser:prod
|
||||
# Build all
|
||||
npm run build
|
||||
|
||||
# Protobuf
|
||||
npm run build:proto
|
||||
|
||||
# Parser map
|
||||
npm run build:parser-map
|
||||
|
||||
# Deno
|
||||
npm run build:deno
|
||||
|
||||
# ES Module
|
||||
npm run build:esm
|
||||
|
||||
# Node
|
||||
npm run bundle:node
|
||||
|
||||
# Browser
|
||||
npm run bundle:browser
|
||||
npm run bundle:browser:prod
|
||||
|
||||
```
|
||||
18
README.md
18
README.md
@@ -112,7 +112,10 @@ yarn add youtubei.js@latest
|
||||
npm install github:LuanRT/YouTube.js
|
||||
```
|
||||
|
||||
**TODO:** Deno install instructions (deno.land)
|
||||
When using Deno, you can import YouTube.js directly from deno.land:
|
||||
```ts
|
||||
import { Innertube } from 'https://deno.land/x/youtubei/deno.ts';
|
||||
```
|
||||
|
||||
## Usage
|
||||
Create an InnerTube instance:
|
||||
@@ -128,8 +131,13 @@ To use YouTube.js in the browser you must proxy requests through your own server
|
||||
You may provide your own fetch implementation to be used by YouTube.js. Which we will use here to modify and send the requests through our proxy. See [`examples/browser/web`](https://github.com/LuanRT/YouTube.js/tree/main/examples/browser/web) for a simple example using [Vite](https://vitejs.dev/).
|
||||
|
||||
```ts
|
||||
// Pre-bundled version for the web
|
||||
import { Innertube } from 'youtubei.js/bundle/browser';
|
||||
// We provide multiple exports for the web.
|
||||
// Unbundled ESM version
|
||||
import { Innertube } from 'youtubei.js/web';
|
||||
// Bundled ESM version
|
||||
// import { Innertube } from 'youtubei.js/web.bundle';
|
||||
// Production Bundled ESM version
|
||||
// import { Innertube } from 'youtubei.js/web.bundle.min';
|
||||
await Innertube.create({
|
||||
fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
// Modify the request
|
||||
@@ -147,7 +155,7 @@ YouTube.js supports streaming of videos in the browser by converting YouTube's s
|
||||
The example below uses [`dash.js`](https://github.com/Dash-Industry-Forum/dash.js) to play the video.
|
||||
|
||||
```ts
|
||||
import { Innertube } from 'youtubei.js';
|
||||
import { Innertube } from 'youtubei.js/web';
|
||||
import dashjs from 'dashjs';
|
||||
|
||||
const youtube = await Innertube.create({ /* setup - see above */ });
|
||||
@@ -202,7 +210,7 @@ Our cache uses the `node:fs` module in Node-like environments, `Deno.writeFile`
|
||||
import { Innertube, UniversalCache } from 'youtubei.js';
|
||||
// By default, cache stores files in the OS temp directory (or indexedDB in browsers).
|
||||
const yt = await Innertube.create({
|
||||
cache: new UniversalCache()
|
||||
cache: new UniversalCache(false)
|
||||
});
|
||||
|
||||
// You may wish to make the cache persistent (on Node and Deno)
|
||||
|
||||
@@ -3,7 +3,7 @@ const { Innertube, UniversalCache } = require('youtubei.js');
|
||||
(async () => {
|
||||
const yt = await Innertube.create({
|
||||
// required if you wish to use OAuth#cacheCredentials
|
||||
cache: new UniversalCache()
|
||||
cache: new UniversalCache(false)
|
||||
});
|
||||
|
||||
// 'auth-pending' is fired with the info needed to sign in via OAuth.
|
||||
|
||||
@@ -9,7 +9,7 @@ To use YouTube.js in the browser you must proxy requests through your own server
|
||||
We'll use our own fetch implementation to proxy requests through our server. This is a simple example, but you can use any fetch implementation you want.
|
||||
|
||||
```ts
|
||||
import { Innertube } from "youtubei.js/build/browser";
|
||||
import { Innertube } from "youtubei.js/web.bundle.min";
|
||||
|
||||
const yt = await Innertube.create({
|
||||
fetch: async (input, init) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Innertube, UniversalCache, YTNodes } from 'youtubei.js';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(), generate_session_locally: true });
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(false), generate_session_locally: true });
|
||||
|
||||
const channel = await yt.getChannel('UCX6OQ3DkcsbYNE6H8uQQuVA');
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Innertube, UniversalCache } from 'youtubei.js';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(), generate_session_locally: true });
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(false), generate_session_locally: true });
|
||||
|
||||
const comment_section = await yt.getComments('a-rqu-hjobc');
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Innertube } from '../../bundle/browser.js';
|
||||
import { Innertube } from 'https://deno.land/x/youtubei/deno.ts';
|
||||
|
||||
const yt = await Innertube.create();
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Innertube, UniversalCache } from 'youtubei.js';
|
||||
import { readFileSync, existsSync, mkdirSync, createWriteStream } from 'fs';
|
||||
import { streamToIterable } from 'youtubei.js/dist/src/utils/Utils';
|
||||
import { Innertube, UniversalCache, Utils } from 'youtubei.js';
|
||||
import { existsSync, mkdirSync, createWriteStream } from 'fs';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(), generate_session_locally: true });
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(false), generate_session_locally: true });
|
||||
|
||||
const search = await yt.music.search('No Copyright Background Music', { type: 'album' });
|
||||
|
||||
@@ -34,7 +33,7 @@ import { streamToIterable } from 'youtubei.js/dist/src/utils/Utils';
|
||||
|
||||
const file = createWriteStream(`${dir}/${song.title?.replace(/\//g, '')}.m4a`);
|
||||
|
||||
for await (const chunk of streamToIterable(stream)) {
|
||||
for await (const chunk of Utils.streamToIterable(stream)) {
|
||||
file.write(chunk);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Innertube, UniversalCache, YTNodes } from 'youtubei.js';
|
||||
import { LiveChatContinuation } from 'youtubei.js/dist/src/parser';
|
||||
import { Innertube, UniversalCache, YTNodes, LiveChatContinuation } from 'youtubei.js';
|
||||
import { ChatAction, LiveMetadata } from 'youtubei.js/dist/src/parser/youtube/LiveChat';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(), generate_session_locally: true });
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(false), generate_session_locally: true });
|
||||
|
||||
const search = await yt.search('lofi hip hop radio - beats to relax/study to');
|
||||
const info = await yt.getInfo(search.videos[0].as(YTNodes.Video).id);
|
||||
|
||||
@@ -5,7 +5,7 @@ const creds_path = './my_yt_creds.json';
|
||||
const creds = existsSync(creds_path) ? JSON.parse(readFileSync(creds_path).toString()) : undefined;
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache() });
|
||||
const yt = await Innertube.create({ cache: new UniversalCache(false) });
|
||||
|
||||
yt.session.on('auth-pending', (data: any) => {
|
||||
console.info(`Hello!\nOn your phone or computer, go to ${data.verification_url} and enter the code ${data.user_code}`);
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "youtubei.js",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.1",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/LuanRT"
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "3.0.0",
|
||||
"version": "3.1.1",
|
||||
"description": "A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).",
|
||||
"type": "module",
|
||||
"types": "./dist/src/platform/lib.d.ts",
|
||||
|
||||
@@ -19,7 +19,8 @@ glob.sync('../src/parser/classes/**/*.{js,ts}', { cwd: __dirname })
|
||||
import_list.push(`import { default as ${class_name} } from './classes/${file}.js';`);
|
||||
misc_exports.push(class_name);
|
||||
} else {
|
||||
import_list.push(`import { default as ${import_name} } from './classes/${file}.js';`);
|
||||
import_list.push(`import { default as ${import_name} } from './classes/${file}.js';
|
||||
export { ${import_name} };`);
|
||||
json.push(import_name);
|
||||
}
|
||||
});
|
||||
@@ -32,7 +33,7 @@ import { YTNodeConstructor } from './helpers.js';
|
||||
|
||||
${import_list.join('\n')}
|
||||
|
||||
export const YTNodes = {
|
||||
const map: Record<string, YTNodeConstructor> = {
|
||||
${json.join(',\n ')}
|
||||
};
|
||||
|
||||
@@ -40,8 +41,6 @@ export const Misc = {
|
||||
${misc_exports.join(',\n ')}
|
||||
};
|
||||
|
||||
const map: Record<string, YTNodeConstructor> = YTNodes;
|
||||
|
||||
/**
|
||||
* @param name - Name of the node to be parsed
|
||||
*/
|
||||
|
||||
@@ -21,7 +21,6 @@ class NavigationEndpoint extends YTNode {
|
||||
constructor(data: any) {
|
||||
super();
|
||||
|
||||
// This is only present in Android nav endpoints
|
||||
if (Reflect.has(data || {}, 'innertubeCommand'))
|
||||
data = data.innertubeCommand;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class PlayerMicroformat extends YTNode {
|
||||
// TODO: check these
|
||||
width: any;
|
||||
height: any;
|
||||
};
|
||||
} | null;
|
||||
|
||||
length_seconds: number;
|
||||
|
||||
@@ -42,13 +42,17 @@ class PlayerMicroformat extends YTNode {
|
||||
this.description = new Text(data.description);
|
||||
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);
|
||||
|
||||
this.embed = {
|
||||
iframe_url: data.embed.iframeUrl,
|
||||
flash_url: data.embed.flashUrl,
|
||||
flash_secure_url: data.embed.flashSecureUrl,
|
||||
width: data.embed.width,
|
||||
height: data.embed.height
|
||||
};
|
||||
if (data.embed) {
|
||||
this.embed = {
|
||||
iframe_url: data.embed.iframeUrl,
|
||||
flash_url: data.embed.flashUrl,
|
||||
flash_secure_url: data.embed.flashSecureUrl,
|
||||
width: data.embed.width,
|
||||
height: data.embed.height
|
||||
};
|
||||
} else {
|
||||
this.embed = null;
|
||||
}
|
||||
|
||||
this.length_seconds = parseInt(data.lengthSeconds);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import Parser from '../index.js';
|
||||
import Thumbnail from './misc/Thumbnail.js';
|
||||
import PlaylistAuthor from './misc/PlaylistAuthor.js';
|
||||
import NavigationEndpoint from './NavigationEndpoint.js';
|
||||
import ThumbnailOverlayTimeStatus from './ThumbnailOverlayTimeStatus.js';
|
||||
import type Menu from './menus/Menu.js';
|
||||
|
||||
import { YTNode } from '../helpers.js';
|
||||
@@ -20,6 +21,7 @@ class PlaylistVideo extends YTNode {
|
||||
endpoint: NavigationEndpoint;
|
||||
is_playable: boolean;
|
||||
menu: Menu | null;
|
||||
upcoming;
|
||||
|
||||
duration: {
|
||||
text: string;
|
||||
@@ -33,16 +35,30 @@ class PlaylistVideo extends YTNode {
|
||||
this.title = new Text(data.title);
|
||||
this.author = new PlaylistAuthor(data.shortBylineText);
|
||||
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);
|
||||
this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays);
|
||||
this.thumbnail_overlays = Parser.parseArray(data.thumbnailOverlays);
|
||||
this.set_video_id = data?.setVideoId;
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.is_playable = data.isPlayable;
|
||||
this.menu = Parser.parseItem<Menu>(data.menu);
|
||||
|
||||
const upcoming = data.upcomingEventData && Number(`${data.upcomingEventData.startTime}000`);
|
||||
if (upcoming) {
|
||||
this.upcoming = new Date(upcoming);
|
||||
}
|
||||
|
||||
this.duration = {
|
||||
text: new Text(data.lengthText).text,
|
||||
seconds: parseInt(data.lengthSeconds)
|
||||
};
|
||||
}
|
||||
|
||||
get is_live(): boolean {
|
||||
return this.thumbnail_overlays.firstOfType(ThumbnailOverlayTimeStatus)?.style === 'LIVE';
|
||||
}
|
||||
|
||||
get is_upcoming(): boolean {
|
||||
return this.thumbnail_overlays.firstOfType(ThumbnailOverlayTimeStatus)?.style === 'UPCOMING';
|
||||
}
|
||||
}
|
||||
|
||||
export default PlaylistVideo;
|
||||
@@ -5,10 +5,12 @@ class ThumbnailOverlayTimeStatus extends YTNode {
|
||||
static type = 'ThumbnailOverlayTimeStatus';
|
||||
|
||||
text: string;
|
||||
style: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.text = new Text(data.text).toString();
|
||||
this.style = data.style;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Parser from '../index.js';
|
||||
import Parser, { RawNode } from '../index.js';
|
||||
import Text from './misc/Text.js';
|
||||
import Button from './Button.js';
|
||||
import VideoOwner from './VideoOwner.js';
|
||||
@@ -9,19 +9,24 @@ import { YTNode } from '../helpers.js';
|
||||
class VideoSecondaryInfo extends YTNode {
|
||||
static type = 'VideoSecondaryInfo';
|
||||
|
||||
owner: VideoOwner | null;// TODO: VideoOwner?
|
||||
owner: VideoOwner | null;
|
||||
description: Text;
|
||||
subscribe_button;
|
||||
subscribe_button: SubscribeButton | Button | null;
|
||||
metadata: MetadataRowContainer | null;
|
||||
show_more_text: string;
|
||||
show_less_text: string;
|
||||
default_expanded: string;
|
||||
description_collapsed_lines: string;
|
||||
|
||||
constructor(data: any) {
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
this.owner = Parser.parseItem<VideoOwner>(data.owner);
|
||||
this.description = new Text(data.description);
|
||||
|
||||
if (Reflect.has(data, 'attributedDescription')) {
|
||||
this.description = new Text(this.#convertAttributedDescriptionToRuns(data.attributedDescription));
|
||||
}
|
||||
|
||||
this.subscribe_button = Parser.parseItem<SubscribeButton | Button>(data.subscribeButton, [ SubscribeButton, Button ]);
|
||||
this.metadata = Parser.parseItem<MetadataRowContainer>(data.metadataRowContainer, MetadataRowContainer);
|
||||
this.show_more_text = data.showMoreText;
|
||||
@@ -29,6 +34,74 @@ class VideoSecondaryInfo extends YTNode {
|
||||
this.default_expanded = data.defaultExpanded;
|
||||
this.description_collapsed_lines = data.descriptionCollapsedLines;
|
||||
}
|
||||
|
||||
#convertAttributedDescriptionToRuns(description: RawNode) {
|
||||
const runs: {
|
||||
text: string,
|
||||
navigationEndpoint?: RawNode,
|
||||
attachment?: RawNode
|
||||
}[] = [];
|
||||
|
||||
const content = description.content;
|
||||
const command_runs = description.commandRuns;
|
||||
|
||||
let last_end_index = 0;
|
||||
|
||||
if (command_runs) {
|
||||
for (const item of command_runs) {
|
||||
const length: number = item.length;
|
||||
const start_index: number = item.startIndex;
|
||||
|
||||
if (start_index > last_end_index) {
|
||||
runs.push({
|
||||
text: content.slice(last_end_index, start_index)
|
||||
});
|
||||
}
|
||||
|
||||
if (Reflect.has(item, 'onTap')) {
|
||||
let attachment = null;
|
||||
|
||||
if (Reflect.has(description, 'attachmentRuns')) {
|
||||
const attachment_runs = description.attachmentRuns;
|
||||
|
||||
for (const attatchment_run of attachment_runs) {
|
||||
if ((attatchment_run.startIndex - 2) == start_index) {
|
||||
attachment = attatchment_run;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attachment) {
|
||||
runs.push({
|
||||
text: content.slice(start_index, start_index + length),
|
||||
navigationEndpoint: item.onTap,
|
||||
attachment
|
||||
});
|
||||
} else {
|
||||
runs.push({
|
||||
text: content.slice(start_index, start_index + length),
|
||||
navigationEndpoint: item.onTap
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
last_end_index = start_index + length;
|
||||
}
|
||||
|
||||
if (last_end_index < content.length) {
|
||||
runs.push({
|
||||
text: content.slice(last_end_index)
|
||||
});
|
||||
}
|
||||
} else {
|
||||
runs.push({
|
||||
text: content
|
||||
});
|
||||
}
|
||||
|
||||
return { runs };
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoSecondaryInfo;
|
||||
@@ -1,5 +1,6 @@
|
||||
import NavigationEndpoint from '../NavigationEndpoint.js';
|
||||
import { escape, Run } from './Text.js';
|
||||
import type { RawNode } from '../../index.js';
|
||||
|
||||
class TextRun implements Run {
|
||||
text: string;
|
||||
@@ -7,13 +8,15 @@ class TextRun implements Run {
|
||||
bold: boolean;
|
||||
italics: boolean;
|
||||
strikethrough: boolean;
|
||||
attachment;
|
||||
|
||||
constructor(data: any) {
|
||||
constructor(data: RawNode) {
|
||||
this.text = data.text;
|
||||
this.bold = Boolean(data.bold);
|
||||
this.italics = Boolean(data.italics);
|
||||
this.strikethrough = Boolean(data.strikethrough);
|
||||
this.endpoint = data.navigationEndpoint ? new NavigationEndpoint(data.navigationEndpoint) : undefined;
|
||||
this.attachment = data.attachment;
|
||||
}
|
||||
|
||||
toString() {
|
||||
@@ -22,16 +25,30 @@ class TextRun implements Run {
|
||||
|
||||
toHTML(): string {
|
||||
const tags: string[] = [];
|
||||
|
||||
if (this.bold) tags.push('b');
|
||||
if (this.italics) tags.push('i');
|
||||
if (this.strikethrough) tags.push('s');
|
||||
|
||||
const escaped_text = escape(this.text);
|
||||
const styled_text = tags.map((tag) => `<${tag}>`).join('') + escaped_text + tags.map((tag) => `</${tag}>`).join('');
|
||||
const wrapped_text = `<span style="white-space: pre-wrap;">${styled_text}</span>`;
|
||||
|
||||
if (this.attachment) {
|
||||
if (this.attachment.element.type.imageType.image.sources.length) {
|
||||
const { url } = this.attachment.element.type.imageType.image.sources[0];
|
||||
if (this.endpoint) {
|
||||
const nav_url = this.endpoint.toURL();
|
||||
if (nav_url) return `<a href="${nav_url}" class="yt-ch-link" display: block; width: fit-content; font-size: small;><img src="${url}" style="vertical-align: middle; height: ${this.attachment.element.properties.layoutProperties.height.value}px; width: ${this.attachment.element.properties.layoutProperties.width.value}px;">${wrapped_text}</a>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.endpoint) {
|
||||
const url = this.endpoint.toURL();
|
||||
if (url) return `<a href="${url}">${wrapped_text}</a>`;
|
||||
}
|
||||
|
||||
return wrapped_text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
export { default as Parser } from './parser.js';
|
||||
export * from './parser.js';
|
||||
export * from './types/index.js';
|
||||
export { YTNodes, Misc } from '../parser/map.js';
|
||||
export { Misc } from '../parser/map.js';
|
||||
export * as YTNodes from '../parser/map.js';
|
||||
export * as YT from './youtube/index.js';
|
||||
export * as YTMusic from './ytmusic/index.js';
|
||||
export * as YTKids from './ytkids/index.js';
|
||||
|
||||
export * as Helpers from './helpers.js';
|
||||
import Parser from './parser.js';
|
||||
export default Parser;
|
||||
@@ -3,181 +3,357 @@
|
||||
import { YTNodeConstructor } from './helpers.js';
|
||||
|
||||
import { default as AccountChannel } from './classes/AccountChannel.js';
|
||||
export { AccountChannel };
|
||||
import { default as AccountItemSection } from './classes/AccountItemSection.js';
|
||||
export { AccountItemSection };
|
||||
import { default as AccountItemSectionHeader } from './classes/AccountItemSectionHeader.js';
|
||||
export { AccountItemSectionHeader };
|
||||
import { default as AccountSectionList } from './classes/AccountSectionList.js';
|
||||
export { AccountSectionList };
|
||||
import { default as AppendContinuationItemsAction } from './classes/actions/AppendContinuationItemsAction.js';
|
||||
export { AppendContinuationItemsAction };
|
||||
import { default as OpenPopupAction } from './classes/actions/OpenPopupAction.js';
|
||||
export { OpenPopupAction };
|
||||
import { default as Alert } from './classes/Alert.js';
|
||||
export { Alert };
|
||||
import { default as AnalyticsMainAppKeyMetrics } from './classes/analytics/AnalyticsMainAppKeyMetrics.js';
|
||||
export { AnalyticsMainAppKeyMetrics };
|
||||
import { default as AnalyticsRoot } from './classes/analytics/AnalyticsRoot.js';
|
||||
export { AnalyticsRoot };
|
||||
import { default as AnalyticsShortsCarouselCard } from './classes/analytics/AnalyticsShortsCarouselCard.js';
|
||||
export { AnalyticsShortsCarouselCard };
|
||||
import { default as AnalyticsVideo } from './classes/analytics/AnalyticsVideo.js';
|
||||
export { AnalyticsVideo };
|
||||
import { default as AnalyticsVodCarouselCard } from './classes/analytics/AnalyticsVodCarouselCard.js';
|
||||
export { AnalyticsVodCarouselCard };
|
||||
import { default as CtaGoToCreatorStudio } from './classes/analytics/CtaGoToCreatorStudio.js';
|
||||
export { CtaGoToCreatorStudio };
|
||||
import { default as DataModelSection } from './classes/analytics/DataModelSection.js';
|
||||
export { DataModelSection };
|
||||
import { default as StatRow } from './classes/analytics/StatRow.js';
|
||||
export { StatRow };
|
||||
import { default as AudioOnlyPlayability } from './classes/AudioOnlyPlayability.js';
|
||||
export { AudioOnlyPlayability };
|
||||
import { default as AutomixPreviewVideo } from './classes/AutomixPreviewVideo.js';
|
||||
export { AutomixPreviewVideo };
|
||||
import { default as BackstageImage } from './classes/BackstageImage.js';
|
||||
export { BackstageImage };
|
||||
import { default as BackstagePost } from './classes/BackstagePost.js';
|
||||
export { BackstagePost };
|
||||
import { default as BackstagePostThread } from './classes/BackstagePostThread.js';
|
||||
export { BackstagePostThread };
|
||||
import { default as BrowseFeedActions } from './classes/BrowseFeedActions.js';
|
||||
export { BrowseFeedActions };
|
||||
import { default as BrowserMediaSession } from './classes/BrowserMediaSession.js';
|
||||
export { BrowserMediaSession };
|
||||
import { default as Button } from './classes/Button.js';
|
||||
export { Button };
|
||||
import { default as C4TabbedHeader } from './classes/C4TabbedHeader.js';
|
||||
export { C4TabbedHeader };
|
||||
import { default as CallToActionButton } from './classes/CallToActionButton.js';
|
||||
export { CallToActionButton };
|
||||
import { default as Card } from './classes/Card.js';
|
||||
export { Card };
|
||||
import { default as CardCollection } from './classes/CardCollection.js';
|
||||
export { CardCollection };
|
||||
import { default as CarouselHeader } from './classes/CarouselHeader.js';
|
||||
export { CarouselHeader };
|
||||
import { default as CarouselItem } from './classes/CarouselItem.js';
|
||||
export { CarouselItem };
|
||||
import { default as Channel } from './classes/Channel.js';
|
||||
export { Channel };
|
||||
import { default as ChannelAboutFullMetadata } from './classes/ChannelAboutFullMetadata.js';
|
||||
export { ChannelAboutFullMetadata };
|
||||
import { default as ChannelAgeGate } from './classes/ChannelAgeGate.js';
|
||||
export { ChannelAgeGate };
|
||||
import { default as ChannelFeaturedContent } from './classes/ChannelFeaturedContent.js';
|
||||
export { ChannelFeaturedContent };
|
||||
import { default as ChannelHeaderLinks } from './classes/ChannelHeaderLinks.js';
|
||||
export { ChannelHeaderLinks };
|
||||
import { default as ChannelMetadata } from './classes/ChannelMetadata.js';
|
||||
export { ChannelMetadata };
|
||||
import { default as ChannelMobileHeader } from './classes/ChannelMobileHeader.js';
|
||||
export { ChannelMobileHeader };
|
||||
import { default as ChannelOptions } from './classes/ChannelOptions.js';
|
||||
export { ChannelOptions };
|
||||
import { default as ChannelSubMenu } from './classes/ChannelSubMenu.js';
|
||||
export { ChannelSubMenu };
|
||||
import { default as ChannelThumbnailWithLink } from './classes/ChannelThumbnailWithLink.js';
|
||||
export { ChannelThumbnailWithLink };
|
||||
import { default as ChannelVideoPlayer } from './classes/ChannelVideoPlayer.js';
|
||||
export { ChannelVideoPlayer };
|
||||
import { default as Chapter } from './classes/Chapter.js';
|
||||
export { Chapter };
|
||||
import { default as ChildVideo } from './classes/ChildVideo.js';
|
||||
export { ChildVideo };
|
||||
import { default as ChipCloud } from './classes/ChipCloud.js';
|
||||
export { ChipCloud };
|
||||
import { default as ChipCloudChip } from './classes/ChipCloudChip.js';
|
||||
export { ChipCloudChip };
|
||||
import { default as CollaboratorInfoCardContent } from './classes/CollaboratorInfoCardContent.js';
|
||||
export { CollaboratorInfoCardContent };
|
||||
import { default as CollageHeroImage } from './classes/CollageHeroImage.js';
|
||||
export { CollageHeroImage };
|
||||
import { default as AuthorCommentBadge } from './classes/comments/AuthorCommentBadge.js';
|
||||
export { AuthorCommentBadge };
|
||||
import { default as Comment } from './classes/comments/Comment.js';
|
||||
export { Comment };
|
||||
import { default as CommentActionButtons } from './classes/comments/CommentActionButtons.js';
|
||||
export { CommentActionButtons };
|
||||
import { default as CommentDialog } from './classes/comments/CommentDialog.js';
|
||||
export { CommentDialog };
|
||||
import { default as CommentReplies } from './classes/comments/CommentReplies.js';
|
||||
export { CommentReplies };
|
||||
import { default as CommentReplyDialog } from './classes/comments/CommentReplyDialog.js';
|
||||
export { CommentReplyDialog };
|
||||
import { default as CommentsEntryPointHeader } from './classes/comments/CommentsEntryPointHeader.js';
|
||||
export { CommentsEntryPointHeader };
|
||||
import { default as CommentsHeader } from './classes/comments/CommentsHeader.js';
|
||||
export { CommentsHeader };
|
||||
import { default as CommentSimplebox } from './classes/comments/CommentSimplebox.js';
|
||||
export { CommentSimplebox };
|
||||
import { default as CommentThread } from './classes/comments/CommentThread.js';
|
||||
export { CommentThread };
|
||||
import { default as CreatorHeart } from './classes/comments/CreatorHeart.js';
|
||||
export { CreatorHeart };
|
||||
import { default as EmojiPicker } from './classes/comments/EmojiPicker.js';
|
||||
export { EmojiPicker };
|
||||
import { default as PdgCommentChip } from './classes/comments/PdgCommentChip.js';
|
||||
export { PdgCommentChip };
|
||||
import { default as SponsorCommentBadge } from './classes/comments/SponsorCommentBadge.js';
|
||||
export { SponsorCommentBadge };
|
||||
import { default as CompactChannel } from './classes/CompactChannel.js';
|
||||
export { CompactChannel };
|
||||
import { default as CompactLink } from './classes/CompactLink.js';
|
||||
export { CompactLink };
|
||||
import { default as CompactMix } from './classes/CompactMix.js';
|
||||
export { CompactMix };
|
||||
import { default as CompactPlaylist } from './classes/CompactPlaylist.js';
|
||||
export { CompactPlaylist };
|
||||
import { default as CompactStation } from './classes/CompactStation.js';
|
||||
export { CompactStation };
|
||||
import { default as CompactVideo } from './classes/CompactVideo.js';
|
||||
export { CompactVideo };
|
||||
import { default as ConfirmDialog } from './classes/ConfirmDialog.js';
|
||||
export { ConfirmDialog };
|
||||
import { default as ContinuationItem } from './classes/ContinuationItem.js';
|
||||
export { ContinuationItem };
|
||||
import { default as CopyLink } from './classes/CopyLink.js';
|
||||
export { CopyLink };
|
||||
import { default as CreatePlaylistDialog } from './classes/CreatePlaylistDialog.js';
|
||||
export { CreatePlaylistDialog };
|
||||
import { default as DecoratedPlayerBar } from './classes/DecoratedPlayerBar.js';
|
||||
export { DecoratedPlayerBar };
|
||||
import { default as DefaultPromoPanel } from './classes/DefaultPromoPanel.js';
|
||||
export { DefaultPromoPanel };
|
||||
import { default as DidYouMean } from './classes/DidYouMean.js';
|
||||
export { DidYouMean };
|
||||
import { default as DownloadButton } from './classes/DownloadButton.js';
|
||||
export { DownloadButton };
|
||||
import { default as Dropdown } from './classes/Dropdown.js';
|
||||
export { Dropdown };
|
||||
import { default as DropdownItem } from './classes/DropdownItem.js';
|
||||
export { DropdownItem };
|
||||
import { default as Element } from './classes/Element.js';
|
||||
export { Element };
|
||||
import { default as EmergencyOnebox } from './classes/EmergencyOnebox.js';
|
||||
export { EmergencyOnebox };
|
||||
import { default as EmojiPickerCategory } from './classes/EmojiPickerCategory.js';
|
||||
export { EmojiPickerCategory };
|
||||
import { default as EmojiPickerCategoryButton } from './classes/EmojiPickerCategoryButton.js';
|
||||
export { EmojiPickerCategoryButton };
|
||||
import { default as EmojiPickerUpsellCategory } from './classes/EmojiPickerUpsellCategory.js';
|
||||
export { EmojiPickerUpsellCategory };
|
||||
import { default as Endscreen } from './classes/Endscreen.js';
|
||||
export { Endscreen };
|
||||
import { default as EndscreenElement } from './classes/EndscreenElement.js';
|
||||
export { EndscreenElement };
|
||||
import { default as EndScreenPlaylist } from './classes/EndScreenPlaylist.js';
|
||||
export { EndScreenPlaylist };
|
||||
import { default as EndScreenVideo } from './classes/EndScreenVideo.js';
|
||||
export { EndScreenVideo };
|
||||
import { default as ExpandableMetadata } from './classes/ExpandableMetadata.js';
|
||||
export { ExpandableMetadata };
|
||||
import { default as ExpandableTab } from './classes/ExpandableTab.js';
|
||||
export { ExpandableTab };
|
||||
import { default as ExpandedShelfContents } from './classes/ExpandedShelfContents.js';
|
||||
export { ExpandedShelfContents };
|
||||
import { default as FeedFilterChipBar } from './classes/FeedFilterChipBar.js';
|
||||
export { FeedFilterChipBar };
|
||||
import { default as FeedTabbedHeader } from './classes/FeedTabbedHeader.js';
|
||||
export { FeedTabbedHeader };
|
||||
import { default as GameCard } from './classes/GameCard.js';
|
||||
export { GameCard };
|
||||
import { default as GameDetails } from './classes/GameDetails.js';
|
||||
export { GameDetails };
|
||||
import { default as Grid } from './classes/Grid.js';
|
||||
export { Grid };
|
||||
import { default as GridChannel } from './classes/GridChannel.js';
|
||||
export { GridChannel };
|
||||
import { default as GridHeader } from './classes/GridHeader.js';
|
||||
export { GridHeader };
|
||||
import { default as GridPlaylist } from './classes/GridPlaylist.js';
|
||||
export { GridPlaylist };
|
||||
import { default as GridVideo } from './classes/GridVideo.js';
|
||||
export { GridVideo };
|
||||
import { default as HashtagHeader } from './classes/HashtagHeader.js';
|
||||
export { HashtagHeader };
|
||||
import { default as Heatmap } from './classes/Heatmap.js';
|
||||
export { Heatmap };
|
||||
import { default as HeatMarker } from './classes/HeatMarker.js';
|
||||
export { HeatMarker };
|
||||
import { default as HighlightsCarousel } from './classes/HighlightsCarousel.js';
|
||||
export { HighlightsCarousel };
|
||||
import { default as HistorySuggestion } from './classes/HistorySuggestion.js';
|
||||
export { HistorySuggestion };
|
||||
import { default as HorizontalCardList } from './classes/HorizontalCardList.js';
|
||||
export { HorizontalCardList };
|
||||
import { default as HorizontalList } from './classes/HorizontalList.js';
|
||||
export { HorizontalList };
|
||||
import { default as IconLink } from './classes/IconLink.js';
|
||||
export { IconLink };
|
||||
import { default as InteractiveTabbedHeader } from './classes/InteractiveTabbedHeader.js';
|
||||
export { InteractiveTabbedHeader };
|
||||
import { default as ItemSection } from './classes/ItemSection.js';
|
||||
export { ItemSection };
|
||||
import { default as ItemSectionHeader } from './classes/ItemSectionHeader.js';
|
||||
export { ItemSectionHeader };
|
||||
import { default as ItemSectionTab } from './classes/ItemSectionTab.js';
|
||||
export { ItemSectionTab };
|
||||
import { default as ItemSectionTabbedHeader } from './classes/ItemSectionTabbedHeader.js';
|
||||
export { ItemSectionTabbedHeader };
|
||||
import { default as LikeButton } from './classes/LikeButton.js';
|
||||
export { LikeButton };
|
||||
import { default as LiveChat } from './classes/LiveChat.js';
|
||||
export { LiveChat };
|
||||
import { default as AddBannerToLiveChatCommand } from './classes/livechat/AddBannerToLiveChatCommand.js';
|
||||
export { AddBannerToLiveChatCommand };
|
||||
import { default as AddChatItemAction } from './classes/livechat/AddChatItemAction.js';
|
||||
export { AddChatItemAction };
|
||||
import { default as AddLiveChatTickerItemAction } from './classes/livechat/AddLiveChatTickerItemAction.js';
|
||||
export { AddLiveChatTickerItemAction };
|
||||
import { default as DimChatItemAction } from './classes/livechat/DimChatItemAction.js';
|
||||
export { DimChatItemAction };
|
||||
import { default as LiveChatAutoModMessage } from './classes/livechat/items/LiveChatAutoModMessage.js';
|
||||
export { LiveChatAutoModMessage };
|
||||
import { default as LiveChatBanner } from './classes/livechat/items/LiveChatBanner.js';
|
||||
export { LiveChatBanner };
|
||||
import { default as LiveChatBannerHeader } from './classes/livechat/items/LiveChatBannerHeader.js';
|
||||
export { LiveChatBannerHeader };
|
||||
import { default as LiveChatBannerPoll } from './classes/livechat/items/LiveChatBannerPoll.js';
|
||||
export { LiveChatBannerPoll };
|
||||
import { default as LiveChatMembershipItem } from './classes/livechat/items/LiveChatMembershipItem.js';
|
||||
export { LiveChatMembershipItem };
|
||||
import { default as LiveChatPaidMessage } from './classes/livechat/items/LiveChatPaidMessage.js';
|
||||
export { LiveChatPaidMessage };
|
||||
import { default as LiveChatPaidSticker } from './classes/livechat/items/LiveChatPaidSticker.js';
|
||||
export { LiveChatPaidSticker };
|
||||
import { default as LiveChatPlaceholderItem } from './classes/livechat/items/LiveChatPlaceholderItem.js';
|
||||
export { LiveChatPlaceholderItem };
|
||||
import { default as LiveChatProductItem } from './classes/livechat/items/LiveChatProductItem.js';
|
||||
export { LiveChatProductItem };
|
||||
import { default as LiveChatRestrictedParticipation } from './classes/livechat/items/LiveChatRestrictedParticipation.js';
|
||||
export { LiveChatRestrictedParticipation };
|
||||
import { default as LiveChatTextMessage } from './classes/livechat/items/LiveChatTextMessage.js';
|
||||
export { LiveChatTextMessage };
|
||||
import { default as LiveChatTickerPaidMessageItem } from './classes/livechat/items/LiveChatTickerPaidMessageItem.js';
|
||||
export { LiveChatTickerPaidMessageItem };
|
||||
import { default as LiveChatTickerPaidStickerItem } from './classes/livechat/items/LiveChatTickerPaidStickerItem.js';
|
||||
export { LiveChatTickerPaidStickerItem };
|
||||
import { default as LiveChatTickerSponsorItem } from './classes/livechat/items/LiveChatTickerSponsorItem.js';
|
||||
export { LiveChatTickerSponsorItem };
|
||||
import { default as LiveChatViewerEngagementMessage } from './classes/livechat/items/LiveChatViewerEngagementMessage.js';
|
||||
export { LiveChatViewerEngagementMessage };
|
||||
import { default as PollHeader } from './classes/livechat/items/PollHeader.js';
|
||||
export { PollHeader };
|
||||
import { default as LiveChatActionPanel } from './classes/livechat/LiveChatActionPanel.js';
|
||||
export { LiveChatActionPanel };
|
||||
import { default as MarkChatItemAsDeletedAction } from './classes/livechat/MarkChatItemAsDeletedAction.js';
|
||||
export { MarkChatItemAsDeletedAction };
|
||||
import { default as MarkChatItemsByAuthorAsDeletedAction } from './classes/livechat/MarkChatItemsByAuthorAsDeletedAction.js';
|
||||
export { MarkChatItemsByAuthorAsDeletedAction };
|
||||
import { default as RemoveBannerForLiveChatCommand } from './classes/livechat/RemoveBannerForLiveChatCommand.js';
|
||||
export { RemoveBannerForLiveChatCommand };
|
||||
import { default as RemoveChatItemAction } from './classes/livechat/RemoveChatItemAction.js';
|
||||
export { RemoveChatItemAction };
|
||||
import { default as RemoveChatItemByAuthorAction } from './classes/livechat/RemoveChatItemByAuthorAction.js';
|
||||
export { RemoveChatItemByAuthorAction };
|
||||
import { default as ReplaceChatItemAction } from './classes/livechat/ReplaceChatItemAction.js';
|
||||
export { ReplaceChatItemAction };
|
||||
import { default as ReplayChatItemAction } from './classes/livechat/ReplayChatItemAction.js';
|
||||
export { ReplayChatItemAction };
|
||||
import { default as ShowLiveChatActionPanelAction } from './classes/livechat/ShowLiveChatActionPanelAction.js';
|
||||
export { ShowLiveChatActionPanelAction };
|
||||
import { default as ShowLiveChatDialogAction } from './classes/livechat/ShowLiveChatDialogAction.js';
|
||||
export { ShowLiveChatDialogAction };
|
||||
import { default as ShowLiveChatTooltipCommand } from './classes/livechat/ShowLiveChatTooltipCommand.js';
|
||||
export { ShowLiveChatTooltipCommand };
|
||||
import { default as UpdateDateTextAction } from './classes/livechat/UpdateDateTextAction.js';
|
||||
export { UpdateDateTextAction };
|
||||
import { default as UpdateDescriptionAction } from './classes/livechat/UpdateDescriptionAction.js';
|
||||
export { UpdateDescriptionAction };
|
||||
import { default as UpdateLiveChatPollAction } from './classes/livechat/UpdateLiveChatPollAction.js';
|
||||
export { UpdateLiveChatPollAction };
|
||||
import { default as UpdateTitleAction } from './classes/livechat/UpdateTitleAction.js';
|
||||
export { UpdateTitleAction };
|
||||
import { default as UpdateToggleButtonTextAction } from './classes/livechat/UpdateToggleButtonTextAction.js';
|
||||
export { UpdateToggleButtonTextAction };
|
||||
import { default as UpdateViewershipAction } from './classes/livechat/UpdateViewershipAction.js';
|
||||
export { UpdateViewershipAction };
|
||||
import { default as LiveChatAuthorBadge } from './classes/LiveChatAuthorBadge.js';
|
||||
export { LiveChatAuthorBadge };
|
||||
import { default as LiveChatDialog } from './classes/LiveChatDialog.js';
|
||||
export { LiveChatDialog };
|
||||
import { default as LiveChatHeader } from './classes/LiveChatHeader.js';
|
||||
export { LiveChatHeader };
|
||||
import { default as LiveChatItemList } from './classes/LiveChatItemList.js';
|
||||
export { LiveChatItemList };
|
||||
import { default as LiveChatMessageInput } from './classes/LiveChatMessageInput.js';
|
||||
export { LiveChatMessageInput };
|
||||
import { default as LiveChatParticipant } from './classes/LiveChatParticipant.js';
|
||||
export { LiveChatParticipant };
|
||||
import { default as LiveChatParticipantsList } from './classes/LiveChatParticipantsList.js';
|
||||
export { LiveChatParticipantsList };
|
||||
import { default as MacroMarkersListItem } from './classes/MacroMarkersListItem.js';
|
||||
export { MacroMarkersListItem };
|
||||
import { default as Menu } from './classes/menus/Menu.js';
|
||||
export { Menu };
|
||||
import { default as MenuNavigationItem } from './classes/menus/MenuNavigationItem.js';
|
||||
export { MenuNavigationItem };
|
||||
import { default as MenuServiceItem } from './classes/menus/MenuServiceItem.js';
|
||||
export { MenuServiceItem };
|
||||
import { default as MenuServiceItemDownload } from './classes/menus/MenuServiceItemDownload.js';
|
||||
export { MenuServiceItemDownload };
|
||||
import { default as MultiPageMenu } from './classes/menus/MultiPageMenu.js';
|
||||
export { MultiPageMenu };
|
||||
import { default as MultiPageMenuNotificationSection } from './classes/menus/MultiPageMenuNotificationSection.js';
|
||||
export { MultiPageMenuNotificationSection };
|
||||
import { default as MusicMenuItemDivider } from './classes/menus/MusicMenuItemDivider.js';
|
||||
export { MusicMenuItemDivider };
|
||||
import { default as MusicMultiSelectMenu } from './classes/menus/MusicMultiSelectMenu.js';
|
||||
export { MusicMultiSelectMenu };
|
||||
import { default as MusicMultiSelectMenuItem } from './classes/menus/MusicMultiSelectMenuItem.js';
|
||||
export { MusicMultiSelectMenuItem };
|
||||
import { default as SimpleMenuHeader } from './classes/menus/SimpleMenuHeader.js';
|
||||
export { SimpleMenuHeader };
|
||||
import { default as MerchandiseItem } from './classes/MerchandiseItem.js';
|
||||
export { MerchandiseItem };
|
||||
import { default as MerchandiseShelf } from './classes/MerchandiseShelf.js';
|
||||
export { MerchandiseShelf };
|
||||
import { default as Message } from './classes/Message.js';
|
||||
export { Message };
|
||||
import { default as MetadataBadge } from './classes/MetadataBadge.js';
|
||||
export { MetadataBadge };
|
||||
import { default as MetadataRow } from './classes/MetadataRow.js';
|
||||
export { MetadataRow };
|
||||
import { default as MetadataRowContainer } from './classes/MetadataRowContainer.js';
|
||||
export { MetadataRowContainer };
|
||||
import { default as MetadataRowHeader } from './classes/MetadataRowHeader.js';
|
||||
export { MetadataRowHeader };
|
||||
import { default as MetadataScreen } from './classes/MetadataScreen.js';
|
||||
export { MetadataScreen };
|
||||
import { default as MicroformatData } from './classes/MicroformatData.js';
|
||||
export { MicroformatData };
|
||||
import { default as Author } from './classes/misc/Author.js';
|
||||
import { default as ChildElement } from './classes/misc/ChildElement.js';
|
||||
import { default as EmojiRun } from './classes/misc/EmojiRun.js';
|
||||
@@ -189,151 +365,295 @@ import { default as TextRun } from './classes/misc/TextRun.js';
|
||||
import { default as Thumbnail } from './classes/misc/Thumbnail.js';
|
||||
import { default as VideoDetails } from './classes/misc/VideoDetails.js';
|
||||
import { default as Mix } from './classes/Mix.js';
|
||||
export { Mix };
|
||||
import { default as Movie } from './classes/Movie.js';
|
||||
export { Movie };
|
||||
import { default as MovingThumbnail } from './classes/MovingThumbnail.js';
|
||||
export { MovingThumbnail };
|
||||
import { default as MultiMarkersPlayerBar } from './classes/MultiMarkersPlayerBar.js';
|
||||
export { MultiMarkersPlayerBar };
|
||||
import { default as MusicCarouselShelf } from './classes/MusicCarouselShelf.js';
|
||||
export { MusicCarouselShelf };
|
||||
import { default as MusicCarouselShelfBasicHeader } from './classes/MusicCarouselShelfBasicHeader.js';
|
||||
export { MusicCarouselShelfBasicHeader };
|
||||
import { default as MusicDescriptionShelf } from './classes/MusicDescriptionShelf.js';
|
||||
export { MusicDescriptionShelf };
|
||||
import { default as MusicDetailHeader } from './classes/MusicDetailHeader.js';
|
||||
export { MusicDetailHeader };
|
||||
import { default as MusicDownloadStateBadge } from './classes/MusicDownloadStateBadge.js';
|
||||
export { MusicDownloadStateBadge };
|
||||
import { default as MusicEditablePlaylistDetailHeader } from './classes/MusicEditablePlaylistDetailHeader.js';
|
||||
export { MusicEditablePlaylistDetailHeader };
|
||||
import { default as MusicElementHeader } from './classes/MusicElementHeader.js';
|
||||
export { MusicElementHeader };
|
||||
import { default as MusicHeader } from './classes/MusicHeader.js';
|
||||
export { MusicHeader };
|
||||
import { default as MusicImmersiveHeader } from './classes/MusicImmersiveHeader.js';
|
||||
export { MusicImmersiveHeader };
|
||||
import { default as MusicInlineBadge } from './classes/MusicInlineBadge.js';
|
||||
export { MusicInlineBadge };
|
||||
import { default as MusicItemThumbnailOverlay } from './classes/MusicItemThumbnailOverlay.js';
|
||||
export { MusicItemThumbnailOverlay };
|
||||
import { default as MusicLargeCardItemCarousel } from './classes/MusicLargeCardItemCarousel.js';
|
||||
export { MusicLargeCardItemCarousel };
|
||||
import { default as MusicNavigationButton } from './classes/MusicNavigationButton.js';
|
||||
export { MusicNavigationButton };
|
||||
import { default as MusicPlayButton } from './classes/MusicPlayButton.js';
|
||||
export { MusicPlayButton };
|
||||
import { default as MusicPlaylistShelf } from './classes/MusicPlaylistShelf.js';
|
||||
export { MusicPlaylistShelf };
|
||||
import { default as MusicQueue } from './classes/MusicQueue.js';
|
||||
export { MusicQueue };
|
||||
import { default as MusicResponsiveListItem } from './classes/MusicResponsiveListItem.js';
|
||||
export { MusicResponsiveListItem };
|
||||
import { default as MusicResponsiveListItemFixedColumn } from './classes/MusicResponsiveListItemFixedColumn.js';
|
||||
export { MusicResponsiveListItemFixedColumn };
|
||||
import { default as MusicResponsiveListItemFlexColumn } from './classes/MusicResponsiveListItemFlexColumn.js';
|
||||
export { MusicResponsiveListItemFlexColumn };
|
||||
import { default as MusicShelf } from './classes/MusicShelf.js';
|
||||
export { MusicShelf };
|
||||
import { default as MusicSideAlignedItem } from './classes/MusicSideAlignedItem.js';
|
||||
export { MusicSideAlignedItem };
|
||||
import { default as MusicSortFilterButton } from './classes/MusicSortFilterButton.js';
|
||||
export { MusicSortFilterButton };
|
||||
import { default as MusicThumbnail } from './classes/MusicThumbnail.js';
|
||||
export { MusicThumbnail };
|
||||
import { default as MusicTwoRowItem } from './classes/MusicTwoRowItem.js';
|
||||
export { MusicTwoRowItem };
|
||||
import { default as MusicVisualHeader } from './classes/MusicVisualHeader.js';
|
||||
export { MusicVisualHeader };
|
||||
import { default as NavigationEndpoint } from './classes/NavigationEndpoint.js';
|
||||
export { NavigationEndpoint };
|
||||
import { default as Notification } from './classes/Notification.js';
|
||||
export { Notification };
|
||||
import { default as PageIntroduction } from './classes/PageIntroduction.js';
|
||||
export { PageIntroduction };
|
||||
import { default as PlayerAnnotationsExpanded } from './classes/PlayerAnnotationsExpanded.js';
|
||||
export { PlayerAnnotationsExpanded };
|
||||
import { default as PlayerCaptionsTracklist } from './classes/PlayerCaptionsTracklist.js';
|
||||
export { PlayerCaptionsTracklist };
|
||||
import { default as PlayerErrorMessage } from './classes/PlayerErrorMessage.js';
|
||||
export { PlayerErrorMessage };
|
||||
import { default as PlayerLiveStoryboardSpec } from './classes/PlayerLiveStoryboardSpec.js';
|
||||
export { PlayerLiveStoryboardSpec };
|
||||
import { default as PlayerMicroformat } from './classes/PlayerMicroformat.js';
|
||||
export { PlayerMicroformat };
|
||||
import { default as PlayerOverlay } from './classes/PlayerOverlay.js';
|
||||
export { PlayerOverlay };
|
||||
import { default as PlayerOverlayAutoplay } from './classes/PlayerOverlayAutoplay.js';
|
||||
export { PlayerOverlayAutoplay };
|
||||
import { default as PlayerStoryboardSpec } from './classes/PlayerStoryboardSpec.js';
|
||||
export { PlayerStoryboardSpec };
|
||||
import { default as Playlist } from './classes/Playlist.js';
|
||||
export { Playlist };
|
||||
import { default as PlaylistCustomThumbnail } from './classes/PlaylistCustomThumbnail.js';
|
||||
export { PlaylistCustomThumbnail };
|
||||
import { default as PlaylistHeader } from './classes/PlaylistHeader.js';
|
||||
export { PlaylistHeader };
|
||||
import { default as PlaylistInfoCardContent } from './classes/PlaylistInfoCardContent.js';
|
||||
export { PlaylistInfoCardContent };
|
||||
import { default as PlaylistMetadata } from './classes/PlaylistMetadata.js';
|
||||
export { PlaylistMetadata };
|
||||
import { default as PlaylistPanel } from './classes/PlaylistPanel.js';
|
||||
export { PlaylistPanel };
|
||||
import { default as PlaylistPanelVideo } from './classes/PlaylistPanelVideo.js';
|
||||
export { PlaylistPanelVideo };
|
||||
import { default as PlaylistPanelVideoWrapper } from './classes/PlaylistPanelVideoWrapper.js';
|
||||
export { PlaylistPanelVideoWrapper };
|
||||
import { default as PlaylistSidebar } from './classes/PlaylistSidebar.js';
|
||||
export { PlaylistSidebar };
|
||||
import { default as PlaylistSidebarPrimaryInfo } from './classes/PlaylistSidebarPrimaryInfo.js';
|
||||
export { PlaylistSidebarPrimaryInfo };
|
||||
import { default as PlaylistSidebarSecondaryInfo } from './classes/PlaylistSidebarSecondaryInfo.js';
|
||||
export { PlaylistSidebarSecondaryInfo };
|
||||
import { default as PlaylistVideo } from './classes/PlaylistVideo.js';
|
||||
export { PlaylistVideo };
|
||||
import { default as PlaylistVideoList } from './classes/PlaylistVideoList.js';
|
||||
export { PlaylistVideoList };
|
||||
import { default as PlaylistVideoThumbnail } from './classes/PlaylistVideoThumbnail.js';
|
||||
export { PlaylistVideoThumbnail };
|
||||
import { default as Poll } from './classes/Poll.js';
|
||||
export { Poll };
|
||||
import { default as Post } from './classes/Post.js';
|
||||
export { Post };
|
||||
import { default as PostMultiImage } from './classes/PostMultiImage.js';
|
||||
export { PostMultiImage };
|
||||
import { default as ProfileColumn } from './classes/ProfileColumn.js';
|
||||
export { ProfileColumn };
|
||||
import { default as ProfileColumnStats } from './classes/ProfileColumnStats.js';
|
||||
export { ProfileColumnStats };
|
||||
import { default as ProfileColumnStatsEntry } from './classes/ProfileColumnStatsEntry.js';
|
||||
export { ProfileColumnStatsEntry };
|
||||
import { default as ProfileColumnUserInfo } from './classes/ProfileColumnUserInfo.js';
|
||||
export { ProfileColumnUserInfo };
|
||||
import { default as RecognitionShelf } from './classes/RecognitionShelf.js';
|
||||
export { RecognitionShelf };
|
||||
import { default as ReelItem } from './classes/ReelItem.js';
|
||||
export { ReelItem };
|
||||
import { default as ReelShelf } from './classes/ReelShelf.js';
|
||||
export { ReelShelf };
|
||||
import { default as RelatedChipCloud } from './classes/RelatedChipCloud.js';
|
||||
export { RelatedChipCloud };
|
||||
import { default as RichGrid } from './classes/RichGrid.js';
|
||||
export { RichGrid };
|
||||
import { default as RichItem } from './classes/RichItem.js';
|
||||
export { RichItem };
|
||||
import { default as RichListHeader } from './classes/RichListHeader.js';
|
||||
export { RichListHeader };
|
||||
import { default as RichSection } from './classes/RichSection.js';
|
||||
export { RichSection };
|
||||
import { default as RichShelf } from './classes/RichShelf.js';
|
||||
export { RichShelf };
|
||||
import { default as SearchBox } from './classes/SearchBox.js';
|
||||
export { SearchBox };
|
||||
import { default as SearchRefinementCard } from './classes/SearchRefinementCard.js';
|
||||
export { SearchRefinementCard };
|
||||
import { default as SearchSuggestion } from './classes/SearchSuggestion.js';
|
||||
export { SearchSuggestion };
|
||||
import { default as SearchSuggestionsSection } from './classes/SearchSuggestionsSection.js';
|
||||
export { SearchSuggestionsSection };
|
||||
import { default as SecondarySearchContainer } from './classes/SecondarySearchContainer.js';
|
||||
export { SecondarySearchContainer };
|
||||
import { default as SectionList } from './classes/SectionList.js';
|
||||
export { SectionList };
|
||||
import { default as SegmentedLikeDislikeButton } from './classes/SegmentedLikeDislikeButton.js';
|
||||
export { SegmentedLikeDislikeButton };
|
||||
import { default as SettingBoolean } from './classes/SettingBoolean.js';
|
||||
export { SettingBoolean };
|
||||
import { default as SettingsCheckbox } from './classes/SettingsCheckbox.js';
|
||||
export { SettingsCheckbox };
|
||||
import { default as SettingsOptions } from './classes/SettingsOptions.js';
|
||||
export { SettingsOptions };
|
||||
import { default as SettingsSidebar } from './classes/SettingsSidebar.js';
|
||||
export { SettingsSidebar };
|
||||
import { default as SettingsSwitch } from './classes/SettingsSwitch.js';
|
||||
export { SettingsSwitch };
|
||||
import { default as Shelf } from './classes/Shelf.js';
|
||||
export { Shelf };
|
||||
import { default as ShowingResultsFor } from './classes/ShowingResultsFor.js';
|
||||
export { ShowingResultsFor };
|
||||
import { default as SimpleCardContent } from './classes/SimpleCardContent.js';
|
||||
export { SimpleCardContent };
|
||||
import { default as SimpleCardTeaser } from './classes/SimpleCardTeaser.js';
|
||||
export { SimpleCardTeaser };
|
||||
import { default as SimpleTextSection } from './classes/SimpleTextSection.js';
|
||||
export { SimpleTextSection };
|
||||
import { default as SingleActionEmergencySupport } from './classes/SingleActionEmergencySupport.js';
|
||||
export { SingleActionEmergencySupport };
|
||||
import { default as SingleColumnBrowseResults } from './classes/SingleColumnBrowseResults.js';
|
||||
export { SingleColumnBrowseResults };
|
||||
import { default as SingleColumnMusicWatchNextResults } from './classes/SingleColumnMusicWatchNextResults.js';
|
||||
export { SingleColumnMusicWatchNextResults };
|
||||
import { default as SingleHeroImage } from './classes/SingleHeroImage.js';
|
||||
export { SingleHeroImage };
|
||||
import { default as SlimOwner } from './classes/SlimOwner.js';
|
||||
export { SlimOwner };
|
||||
import { default as SlimVideoMetadata } from './classes/SlimVideoMetadata.js';
|
||||
export { SlimVideoMetadata };
|
||||
import { default as SortFilterSubMenu } from './classes/SortFilterSubMenu.js';
|
||||
export { SortFilterSubMenu };
|
||||
import { default as SubFeedOption } from './classes/SubFeedOption.js';
|
||||
export { SubFeedOption };
|
||||
import { default as SubFeedSelector } from './classes/SubFeedSelector.js';
|
||||
export { SubFeedSelector };
|
||||
import { default as SubscribeButton } from './classes/SubscribeButton.js';
|
||||
export { SubscribeButton };
|
||||
import { default as SubscriptionNotificationToggleButton } from './classes/SubscriptionNotificationToggleButton.js';
|
||||
export { SubscriptionNotificationToggleButton };
|
||||
import { default as Tab } from './classes/Tab.js';
|
||||
export { Tab };
|
||||
import { default as Tabbed } from './classes/Tabbed.js';
|
||||
export { Tabbed };
|
||||
import { default as TabbedSearchResults } from './classes/TabbedSearchResults.js';
|
||||
export { TabbedSearchResults };
|
||||
import { default as TextHeader } from './classes/TextHeader.js';
|
||||
export { TextHeader };
|
||||
import { default as ThumbnailLandscapePortrait } from './classes/ThumbnailLandscapePortrait.js';
|
||||
export { ThumbnailLandscapePortrait };
|
||||
import { default as ThumbnailOverlayBottomPanel } from './classes/ThumbnailOverlayBottomPanel.js';
|
||||
export { ThumbnailOverlayBottomPanel };
|
||||
import { default as ThumbnailOverlayEndorsement } from './classes/ThumbnailOverlayEndorsement.js';
|
||||
export { ThumbnailOverlayEndorsement };
|
||||
import { default as ThumbnailOverlayHoverText } from './classes/ThumbnailOverlayHoverText.js';
|
||||
export { ThumbnailOverlayHoverText };
|
||||
import { default as ThumbnailOverlayInlineUnplayable } from './classes/ThumbnailOverlayInlineUnplayable.js';
|
||||
export { ThumbnailOverlayInlineUnplayable };
|
||||
import { default as ThumbnailOverlayLoadingPreview } from './classes/ThumbnailOverlayLoadingPreview.js';
|
||||
export { ThumbnailOverlayLoadingPreview };
|
||||
import { default as ThumbnailOverlayNowPlaying } from './classes/ThumbnailOverlayNowPlaying.js';
|
||||
export { ThumbnailOverlayNowPlaying };
|
||||
import { default as ThumbnailOverlayPinking } from './classes/ThumbnailOverlayPinking.js';
|
||||
export { ThumbnailOverlayPinking };
|
||||
import { default as ThumbnailOverlayPlaybackStatus } from './classes/ThumbnailOverlayPlaybackStatus.js';
|
||||
export { ThumbnailOverlayPlaybackStatus };
|
||||
import { default as ThumbnailOverlayResumePlayback } from './classes/ThumbnailOverlayResumePlayback.js';
|
||||
export { ThumbnailOverlayResumePlayback };
|
||||
import { default as ThumbnailOverlaySidePanel } from './classes/ThumbnailOverlaySidePanel.js';
|
||||
export { ThumbnailOverlaySidePanel };
|
||||
import { default as ThumbnailOverlayTimeStatus } from './classes/ThumbnailOverlayTimeStatus.js';
|
||||
export { ThumbnailOverlayTimeStatus };
|
||||
import { default as ThumbnailOverlayToggleButton } from './classes/ThumbnailOverlayToggleButton.js';
|
||||
export { ThumbnailOverlayToggleButton };
|
||||
import { default as TimedMarkerDecoration } from './classes/TimedMarkerDecoration.js';
|
||||
export { TimedMarkerDecoration };
|
||||
import { default as TitleAndButtonListHeader } from './classes/TitleAndButtonListHeader.js';
|
||||
export { TitleAndButtonListHeader };
|
||||
import { default as ToggleButton } from './classes/ToggleButton.js';
|
||||
export { ToggleButton };
|
||||
import { default as ToggleMenuServiceItem } from './classes/ToggleMenuServiceItem.js';
|
||||
export { ToggleMenuServiceItem };
|
||||
import { default as Tooltip } from './classes/Tooltip.js';
|
||||
export { Tooltip };
|
||||
import { default as TopicChannelDetails } from './classes/TopicChannelDetails.js';
|
||||
export { TopicChannelDetails };
|
||||
import { default as TwoColumnBrowseResults } from './classes/TwoColumnBrowseResults.js';
|
||||
export { TwoColumnBrowseResults };
|
||||
import { default as TwoColumnSearchResults } from './classes/TwoColumnSearchResults.js';
|
||||
export { TwoColumnSearchResults };
|
||||
import { default as TwoColumnWatchNextResults } from './classes/TwoColumnWatchNextResults.js';
|
||||
export { TwoColumnWatchNextResults };
|
||||
import { default as UniversalWatchCard } from './classes/UniversalWatchCard.js';
|
||||
export { UniversalWatchCard };
|
||||
import { default as UpsellDialog } from './classes/UpsellDialog.js';
|
||||
export { UpsellDialog };
|
||||
import { default as VerticalList } from './classes/VerticalList.js';
|
||||
export { VerticalList };
|
||||
import { default as VerticalWatchCardList } from './classes/VerticalWatchCardList.js';
|
||||
export { VerticalWatchCardList };
|
||||
import { default as Video } from './classes/Video.js';
|
||||
export { Video };
|
||||
import { default as VideoCard } from './classes/VideoCard.js';
|
||||
export { VideoCard };
|
||||
import { default as VideoInfoCardContent } from './classes/VideoInfoCardContent.js';
|
||||
export { VideoInfoCardContent };
|
||||
import { default as VideoOwner } from './classes/VideoOwner.js';
|
||||
export { VideoOwner };
|
||||
import { default as VideoPrimaryInfo } from './classes/VideoPrimaryInfo.js';
|
||||
export { VideoPrimaryInfo };
|
||||
import { default as VideoSecondaryInfo } from './classes/VideoSecondaryInfo.js';
|
||||
export { VideoSecondaryInfo };
|
||||
import { default as WatchCardCompactVideo } from './classes/WatchCardCompactVideo.js';
|
||||
export { WatchCardCompactVideo };
|
||||
import { default as WatchCardHeroVideo } from './classes/WatchCardHeroVideo.js';
|
||||
export { WatchCardHeroVideo };
|
||||
import { default as WatchCardRichHeader } from './classes/WatchCardRichHeader.js';
|
||||
export { WatchCardRichHeader };
|
||||
import { default as WatchCardSectionSequence } from './classes/WatchCardSectionSequence.js';
|
||||
export { WatchCardSectionSequence };
|
||||
import { default as WatchNextEndScreen } from './classes/WatchNextEndScreen.js';
|
||||
export { WatchNextEndScreen };
|
||||
import { default as WatchNextTabbedResults } from './classes/WatchNextTabbedResults.js';
|
||||
export { WatchNextTabbedResults };
|
||||
import { default as AnchoredSection } from './classes/ytkids/AnchoredSection.js';
|
||||
export { AnchoredSection };
|
||||
import { default as KidsCategoriesHeader } from './classes/ytkids/KidsCategoriesHeader.js';
|
||||
export { KidsCategoriesHeader };
|
||||
import { default as KidsCategoryTab } from './classes/ytkids/KidsCategoryTab.js';
|
||||
export { KidsCategoryTab };
|
||||
import { default as KidsHomeScreen } from './classes/ytkids/KidsHomeScreen.js';
|
||||
export { KidsHomeScreen };
|
||||
|
||||
export const YTNodes = {
|
||||
const map: Record<string, YTNodeConstructor> = {
|
||||
AccountChannel,
|
||||
AccountItemSection,
|
||||
AccountItemSectionHeader,
|
||||
@@ -669,8 +989,6 @@ export const Misc = {
|
||||
VideoDetails
|
||||
};
|
||||
|
||||
const map: Record<string, YTNodeConstructor> = YTNodes;
|
||||
|
||||
/**
|
||||
* @param name - Name of the node to be parsed
|
||||
*/
|
||||
|
||||
@@ -254,7 +254,7 @@ export class ChannelListContinuation extends Feed<IBrowseResponse> {
|
||||
constructor(actions: Actions, data: ApiResponse | IBrowseResponse, already_parsed = false) {
|
||||
super(actions, data, already_parsed);
|
||||
this.contents =
|
||||
this.page.on_response_received_actions.first() ||
|
||||
this.page.on_response_received_actions?.first() ||
|
||||
this.page.on_response_received_endpoints?.first();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,9 @@ export const CLIENTS = Object.freeze({
|
||||
},
|
||||
ANDROID: {
|
||||
NAME: 'ANDROID',
|
||||
VERSION: '17.34.35',
|
||||
SDK_VERSION: '29'
|
||||
VERSION: '18.06.35',
|
||||
SDK_VERSION: '29',
|
||||
USER_AGENT: 'com.google.android.youtube/18.06.35 (Linux; U; Android 10; US)'
|
||||
},
|
||||
YTSTUDIO_ANDROID: {
|
||||
NAME: 'ANDROID_CREATOR',
|
||||
|
||||
@@ -91,6 +91,13 @@ export default class HTTPClient {
|
||||
|
||||
delete n_body.client;
|
||||
|
||||
|
||||
if (Platform.shim.server) {
|
||||
if (n_body.context.client.clientName === 'ANDROID' || n_body.context.client.clientName === 'ANDROID_MUSIC') {
|
||||
request_headers.set('User-Agent', Constants.CLIENTS.ANDROID.USER_AGENT);
|
||||
}
|
||||
}
|
||||
|
||||
is_web_kids = n_body.context.client.clientName === 'WEB_KIDS';
|
||||
request_body = JSON.stringify(n_body);
|
||||
}
|
||||
@@ -146,12 +153,14 @@ export default class HTTPClient {
|
||||
ctx.client.clientFormFactor = 'SMALL_FORM_FACTOR';
|
||||
ctx.client.clientName = Constants.CLIENTS.ANDROID.NAME;
|
||||
ctx.client.androidSdkVersion = Constants.CLIENTS.ANDROID.SDK_VERSION;
|
||||
ctx.client.platform = 'MOBILE';
|
||||
break;
|
||||
case 'YTMUSIC_ANDROID':
|
||||
ctx.client.clientVersion = Constants.CLIENTS.YTMUSIC_ANDROID.VERSION;
|
||||
ctx.client.clientFormFactor = 'SMALL_FORM_FACTOR';
|
||||
ctx.client.clientName = Constants.CLIENTS.YTMUSIC_ANDROID.NAME;
|
||||
ctx.client.androidSdkVersion = Constants.CLIENTS.ANDROID.SDK_VERSION;
|
||||
ctx.client.platform = 'MOBILE';
|
||||
break;
|
||||
case 'YTSTUDIO_ANDROID':
|
||||
ctx.client.clientVersion = Constants.CLIENTS.YTSTUDIO_ANDROID.VERSION;
|
||||
|
||||
@@ -4,6 +4,8 @@ export * as Constants from './Constants.js';
|
||||
|
||||
export { default as EventEmitter } from './EventEmitterLike.js';
|
||||
|
||||
export { default as FormatUtils } from './FormatUtils.js';
|
||||
|
||||
export { default as HTTPClient } from './HTTPClient.js';
|
||||
export * from './HTTPClient.js';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user