mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-15 18:42:11 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e24060c31d | ||
|
|
a2c3774e9a | ||
|
|
dee2b07cb0 | ||
|
|
da0551cb4c | ||
|
|
68a6af9b2c | ||
|
|
46c2f6c6c1 | ||
|
|
95976de115 | ||
|
|
8be677adec | ||
|
|
aa7cf561a7 | ||
|
|
bac896501b | ||
|
|
3ea2815aba |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,5 +1,32 @@
|
||||
# Changelog
|
||||
|
||||
## [15.1.1](https://github.com/LuanRT/YouTube.js/compare/v15.1.0...v15.1.1) (2025-09-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Player:** Store the full library version in cache entries ([#1032](https://github.com/LuanRT/YouTube.js/issues/1032)) ([a2c3774](https://github.com/LuanRT/YouTube.js/commit/a2c3774e9a0212d7aab7af2baee1f48ad3319a08))
|
||||
|
||||
## [15.1.0](https://github.com/LuanRT/YouTube.js/compare/v15.0.1...v15.1.0) (2025-09-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **parser:** Add ListView, ListItemView and SubscribeButtonView ([#1025](https://github.com/LuanRT/YouTube.js/issues/1025)) ([68a6af9](https://github.com/LuanRT/YouTube.js/commit/68a6af9b2c2e4e5a31b2d6f5c5add6c238e5113e))
|
||||
* **parser:** Parse badges in ContentMetadataView ([#1017](https://github.com/LuanRT/YouTube.js/issues/1017)) ([aa7cf56](https://github.com/LuanRT/YouTube.js/commit/aa7cf561a7cdec017383b9daa6c9401f08995d4c))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **parser:** LockupMetadataView.image can also be an AvatarStackView ([#1026](https://github.com/LuanRT/YouTube.js/issues/1026)) ([bac8965](https://github.com/LuanRT/YouTube.js/commit/bac896501b9525c28b319301151a0dde93d08ec0))
|
||||
* **Player:** Fix global variable extraction in the deciphering code ([#1029](https://github.com/LuanRT/YouTube.js/issues/1029)) ([3ea2815](https://github.com/LuanRT/YouTube.js/commit/3ea2815abac03ae7371e45ae2f2758caf9db2266))
|
||||
* **types:** Parser.parseArray always returns an ObservedArray ([#1014](https://github.com/LuanRT/YouTube.js/issues/1014)) ([8be677a](https://github.com/LuanRT/YouTube.js/commit/8be677adec6631be557c95adc8f687e5d01b4fdf))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* Replace uses of ObservableArray#get with Array#find ([#1013](https://github.com/LuanRT/YouTube.js/issues/1013)) ([95976de](https://github.com/LuanRT/YouTube.js/commit/95976de115587d8f266bc44355440835f3b2b02f))
|
||||
|
||||
## [15.0.1](https://github.com/LuanRT/YouTube.js/compare/v15.0.0...v15.0.1) (2025-07-22)
|
||||
|
||||
|
||||
|
||||
75
package-lock.json
generated
75
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "15.0.1",
|
||||
"version": "15.1.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "youtubei.js",
|
||||
"version": "15.0.1",
|
||||
"version": "15.1.1",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/LuanRT"
|
||||
],
|
||||
@@ -30,7 +30,6 @@
|
||||
"rimraf": "^6.0.1",
|
||||
"ts-patch": "^3.0.2",
|
||||
"ts-proto": "^2.2.0",
|
||||
"ts-transformer-inline-file": "^0.2.0",
|
||||
"typedoc": "^0.26.7",
|
||||
"typedoc-plugin-markdown": "^4.2.7",
|
||||
"typescript": "^5.0.0",
|
||||
@@ -4731,14 +4730,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
|
||||
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2"
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
@@ -4748,11 +4747,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
|
||||
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
@@ -4919,18 +4921,6 @@
|
||||
"@bufbuild/protobuf": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-transformer-inline-file": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-transformer-inline-file/-/ts-transformer-inline-file-0.2.0.tgz",
|
||||
"integrity": "sha512-16IBBt0d8MxVdEyxDEFx2+EetgELWs/kUu4FEaL4b1dffu5gB/aw+CwVPW3EzsuO67g8OAF34LcDHsyxQp16Aw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -5175,24 +5165,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||
"version": "7.1.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz",
|
||||
"integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3",
|
||||
"postcss": "^8.5.6",
|
||||
"rollup": "^4.43.0",
|
||||
"tinyglobby": "^0.2.15"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
@@ -5201,14 +5191,14 @@
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||
"@types/node": "^20.19.0 || >=22.12.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "*",
|
||||
"less": "^4.0.0",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"sass": "^1.70.0",
|
||||
"sass-embedded": "^1.70.0",
|
||||
"stylus": ">=0.54.8",
|
||||
"sugarss": "^5.0.0",
|
||||
"terser": "^5.16.0",
|
||||
"tsx": "^4.8.1",
|
||||
"yaml": "^2.4.2"
|
||||
@@ -5273,11 +5263,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite/node_modules/fdir": {
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
|
||||
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "15.0.1",
|
||||
"version": "15.1.1",
|
||||
"description": "A JavaScript client for YouTube's private API, known as InnerTube.",
|
||||
"type": "module",
|
||||
"types": "./dist/src/platform/lib.d.ts",
|
||||
@@ -38,6 +38,7 @@
|
||||
"react-native": "./dist/src/platform/react-native.js",
|
||||
"default": "./dist/src/platform/web.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./agnostic": {
|
||||
"types": "./dist/src/platform/lib.d.ts",
|
||||
"default": "./dist/src/platform/lib.js"
|
||||
@@ -122,7 +123,6 @@
|
||||
"rimraf": "^6.0.1",
|
||||
"ts-patch": "^3.0.2",
|
||||
"ts-proto": "^2.2.0",
|
||||
"ts-transformer-inline-file": "^0.2.0",
|
||||
"typedoc": "^0.26.7",
|
||||
"typedoc-plugin-markdown": "^4.2.7",
|
||||
"typescript": "^5.0.0",
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Platform,
|
||||
PlayerError
|
||||
} from '../utils/Utils.js';
|
||||
import packageInfo from '../../package.json' with { type: 'json' };
|
||||
|
||||
const TAG = 'Player';
|
||||
|
||||
@@ -18,7 +19,7 @@ interface SerializablePlayer {
|
||||
sts: number;
|
||||
sig_sc?: string;
|
||||
nsig_sc?: string;
|
||||
library_version: number;
|
||||
library_version: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,10 +200,9 @@ export default class Player {
|
||||
return null;
|
||||
|
||||
try {
|
||||
const current_library_version = parseInt(Platform.shim.info.version.split('.')[0]);
|
||||
const player_data = BinarySerializer.deserialize<SerializablePlayer>(new Uint8Array(buffer));
|
||||
|
||||
if (player_data.library_version !== current_library_version) {
|
||||
if (player_data.library_version !== packageInfo.version) {
|
||||
Log.warn(TAG, `Cached player data is from a different library version (${player_data.library_version}). Ignoring it.`);
|
||||
return null;
|
||||
}
|
||||
@@ -224,14 +224,12 @@ export default class Player {
|
||||
if (!cache || !this.sig_sc || !this.nsig_sc)
|
||||
return;
|
||||
|
||||
const current_library_version = parseInt(Platform.shim.info.version.split('.')[0]);
|
||||
|
||||
const buffer = BinarySerializer.serialize({
|
||||
player_id: this.player_id,
|
||||
sts: this.sts,
|
||||
sig_sc: this.sig_sc,
|
||||
nsig_sc: this.nsig_sc,
|
||||
library_version: current_library_version
|
||||
library_version: packageInfo.version
|
||||
});
|
||||
|
||||
await cache.set(this.player_id, buffer);
|
||||
@@ -286,7 +284,7 @@ export default class Player {
|
||||
if (!functions || !var_name)
|
||||
Log.warn(TAG, 'Failed to extract signature decipher algorithm.');
|
||||
|
||||
return `${global_variable?.result || ''} function descramble_sig(${var_name}) { let ${obj_name}={${functions}}; ${match[2]} } descramble_sig(sig);`;
|
||||
return `${global_variable?.result ? `var ${global_variable.result};` : ''} function descramble_sig(${var_name}) { let ${obj_name}={${functions}}; ${match[2]} } descramble_sig(sig);`;
|
||||
}
|
||||
|
||||
static extractNSigSourceCode(data: string, ast?: ReturnType<typeof Jinter.parseScript>, global_variable?: ASTLookupResult): string | undefined {
|
||||
@@ -303,7 +301,7 @@ export default class Player {
|
||||
nsig_function = findFunction(data, { includes: '.reverse().forEach(function', ast });
|
||||
|
||||
if (nsig_function)
|
||||
return `${global_variable.result} var ${nsig_function.result} ${nsig_function.name}(nsig);`;
|
||||
return `var ${global_variable.result}; var ${nsig_function.result} ${nsig_function.name}(nsig);`;
|
||||
}
|
||||
|
||||
// This is the suffix of the error tag.
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
generateRandomString, getRandomUserAgent,
|
||||
InnertubeError, Platform, SessionError
|
||||
} from '../utils/Utils.js';
|
||||
import packageInfo from '../../package.json' with { type: 'json' };
|
||||
|
||||
import type { DeviceCategory } from '../utils/Utils.js';
|
||||
import type { FetchFunction, ICache } from '../types/index.js';
|
||||
@@ -332,7 +333,7 @@ export default class Session extends EventEmitter {
|
||||
try {
|
||||
const session_data = BinarySerializer.deserialize<SerializableSession>(new Uint8Array(buffer));
|
||||
|
||||
if (session_data.library_version !== parseInt(Platform.shim.info.version.split('.')[0])) {
|
||||
if (session_data.library_version !== parseInt(packageInfo.version.split('.', 1)[0])) {
|
||||
Log.warn(TAG, `Cached session data is from a different library version (${session_data.library_version}). Regenerating session data.`);
|
||||
return null;
|
||||
}
|
||||
@@ -517,7 +518,7 @@ export default class Session extends EventEmitter {
|
||||
|
||||
const buffer = BinarySerializer.serialize({
|
||||
...session_data,
|
||||
library_version: parseInt(Platform.shim.info.version)
|
||||
library_version: parseInt(packageInfo.version)
|
||||
});
|
||||
|
||||
await cache.set('innertube_session_data', buffer);
|
||||
|
||||
@@ -160,7 +160,7 @@ export default class Feed<T extends IParsedResponse = IParsedResponse> {
|
||||
* Finds shelf by title.
|
||||
*/
|
||||
getShelf(title: string) {
|
||||
return this.shelves.get({ title });
|
||||
return this.shelves.find((shelf) => shelf.title.toString() === title);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -188,8 +188,8 @@ export default class MediaInfo {
|
||||
if (!next_response.engagement_panels)
|
||||
throw new InnertubeError('Engagement panels not found. Video likely has no transcript.');
|
||||
|
||||
const transcript_panel = next_response.engagement_panels.get({
|
||||
panel_identifier: 'engagement-panel-searchable-transcript'
|
||||
const transcript_panel = next_response.engagement_panels.find((panel) => {
|
||||
return panel.panel_identifier === 'engagement-panel-searchable-transcript';
|
||||
});
|
||||
|
||||
if (!transcript_panel)
|
||||
|
||||
@@ -5,7 +5,7 @@ import ChipView from './ChipView.js';
|
||||
export default class ChipBarView extends YTNode {
|
||||
static type = 'ChipBarView';
|
||||
|
||||
chips: ObservedArray<ChipView> | null;
|
||||
chips: ObservedArray<ChipView>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class CompactVideo extends YTNode {
|
||||
public short_byline_text?: Text;
|
||||
public long_byline_text?: Text;
|
||||
public published?: Text;
|
||||
public badges: MetadataBadge[];
|
||||
public badges: ObservedArray<MetadataBadge>;
|
||||
public thumbnail_overlays: ObservedArray<YTNode>;
|
||||
public endpoint?: NavigationEndpoint;
|
||||
public menu: Menu | null;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import type { ObservedArray } from '../helpers.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import type { RawNode } from '../index.js';
|
||||
import { Text } from '../misc.js';
|
||||
import { Parser } from '../index.js';
|
||||
import AvatarStackView from './AvatarStackView.js';
|
||||
import BadgeView from './BadgeView.js';
|
||||
|
||||
export type MetadataRow = {
|
||||
metadata_parts?: {
|
||||
@@ -10,6 +12,7 @@ export type MetadataRow = {
|
||||
avatar_stack: AvatarStackView | null;
|
||||
enable_truncation?: boolean;
|
||||
}[];
|
||||
badges: ObservedArray<BadgeView>
|
||||
};
|
||||
|
||||
export default class ContentMetadataView extends YTNode {
|
||||
@@ -25,7 +28,8 @@ export default class ContentMetadataView extends YTNode {
|
||||
text: part.text ? Text.fromAttributed(part.text) : null,
|
||||
avatar_stack: Parser.parseItem(part.avatarStack, AvatarStackView),
|
||||
enable_truncation: data.enableTruncation
|
||||
}))
|
||||
})),
|
||||
badges: Parser.parseArray(row.badges, BadgeView)
|
||||
}));
|
||||
this.delimiter = data.delimiter;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Parser, type RawNode } from '../index.js';
|
||||
import DialogHeaderView from './DialogHeaderView.js';
|
||||
import FormFooterView from './FormFooterView.js';
|
||||
import CreatePlaylistDialogFormView from './CreatePlaylistDialogFormView.js';
|
||||
import ListView from './ListView.js';
|
||||
import PanelFooterView from './PanelFooterView.js';
|
||||
|
||||
export default class DialogView extends YTNode {
|
||||
@@ -10,12 +11,12 @@ export default class DialogView extends YTNode {
|
||||
|
||||
public header: DialogHeaderView | null;
|
||||
public footer: FormFooterView | PanelFooterView | null;
|
||||
public custom_content: CreatePlaylistDialogFormView | null;
|
||||
public custom_content: CreatePlaylistDialogFormView | ListView | null;
|
||||
|
||||
constructor (data: RawNode) {
|
||||
super();
|
||||
this.header = Parser.parseItem(data.header, DialogHeaderView);
|
||||
this.footer = Parser.parseItem(data.footer, [ FormFooterView, PanelFooterView ]);
|
||||
this.custom_content = Parser.parseItem(data.customContent, CreatePlaylistDialogFormView);
|
||||
this.custom_content = Parser.parseItem(data.customContent, [ CreatePlaylistDialogFormView, ListView ]);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ export default class GridShow extends YTNode {
|
||||
thumbnail_renderer: ShowCustomThumbnail | null;
|
||||
endpoint: NavigationEndpoint;
|
||||
long_byline_text: Text;
|
||||
thumbnail_overlays: ObservedArray<ThumbnailOverlayBottomPanel> | null;
|
||||
thumbnail_overlays: ObservedArray<ThumbnailOverlayBottomPanel>;
|
||||
author: Author;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -14,7 +14,7 @@ export default class InteractiveTabbedHeader extends YTNode {
|
||||
title: Text;
|
||||
description: Text;
|
||||
metadata: Text;
|
||||
badges: MetadataBadge[];
|
||||
badges: ObservedArray<MetadataBadge>;
|
||||
box_art: Thumbnail[];
|
||||
banner: Thumbnail[];
|
||||
buttons: ObservedArray<SubscribeButton | Button>;
|
||||
|
||||
32
src/parser/classes/ListItemView.ts
Normal file
32
src/parser/classes/ListItemView.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import type { ObservedArray } from '../helpers.js';
|
||||
import type { RawNode } from '../types/RawResponse.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import { Parser } from '../index.js';
|
||||
|
||||
import AvatarView from './AvatarView.js';
|
||||
import RendererContext from './misc/RendererContext.js';
|
||||
import SubscribeButtonView from './SubscribeButtonView.js';
|
||||
import Text from './misc/Text.js';
|
||||
|
||||
export default class ListItemView extends YTNode {
|
||||
static type = 'ListItemView';
|
||||
|
||||
public title: Text;
|
||||
public subtitle: Text;
|
||||
public leading_accessory: AvatarView | null;
|
||||
public renderer_context: RendererContext;
|
||||
public trailing_buttons?: ObservedArray<SubscribeButtonView>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
this.title = Text.fromAttributed(data.title);
|
||||
this.subtitle = Text.fromAttributed(data.subtitle);
|
||||
this.leading_accessory = Parser.parseItem(data.leadingAccessory, AvatarView);
|
||||
this.renderer_context = new RendererContext(data.rendererContext);
|
||||
|
||||
if ('trailingButtons' in data) {
|
||||
this.trailing_buttons = Parser.parseArray(data.trailingButtons.buttons, SubscribeButtonView);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/parser/classes/ListView.ts
Normal file
18
src/parser/classes/ListView.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { ObservedArray } from '../helpers.js';
|
||||
import type { RawNode } from '../types/RawResponse.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import { Parser } from '../index.js';
|
||||
|
||||
import ListItemView from './ListItemView.js';
|
||||
|
||||
export default class ListView extends YTNode {
|
||||
static type = 'ListView';
|
||||
|
||||
public items: ObservedArray<ListItemView>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
this.items = Parser.parseArray(data.listItems, ListItemView);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { YTNode } from '../helpers.js';
|
||||
import { Parser, type RawNode } from '../index.js';
|
||||
import ContentMetadataView from './ContentMetadataView.js';
|
||||
import AvatarStackView from './AvatarStackView.js';
|
||||
import DecoratedAvatarView from './DecoratedAvatarView.js';
|
||||
import Text from './misc/Text.js';
|
||||
import ButtonView from './ButtonView.js';
|
||||
@@ -10,14 +11,14 @@ export default class LockupMetadataView extends YTNode {
|
||||
|
||||
public title: Text;
|
||||
public metadata: ContentMetadataView | null;
|
||||
public image: DecoratedAvatarView | null;
|
||||
public image: DecoratedAvatarView | AvatarStackView | null;
|
||||
public menu_button: ButtonView | null;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
this.title = Text.fromAttributed(data.title);
|
||||
this.metadata = Parser.parseItem(data.metadata, ContentMetadataView);
|
||||
this.image = Parser.parseItem(data.image, DecoratedAvatarView);
|
||||
this.image = Parser.parseItem(data.image, [ DecoratedAvatarView, AvatarStackView ]);
|
||||
this.menu_button = Parser.parseItem(data.menuButton, ButtonView);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ export class Marker extends YTNode {
|
||||
marker_key: string;
|
||||
value: {
|
||||
heatmap?: Heatmap | null;
|
||||
chapters?: Chapter[];
|
||||
chapters?: ObservedArray<Chapter>;
|
||||
};
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class MusicResponsiveHeader extends YTNode {
|
||||
strapline_text_one: Text;
|
||||
strapline_thumbnail: MusicThumbnail | null;
|
||||
second_subtitle: Text;
|
||||
subtitle_badge?: ObservedArray<MusicInlineBadge> | null;
|
||||
subtitle_badge?: ObservedArray<MusicInlineBadge>;
|
||||
description?: MusicDescriptionShelf | null;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export default class MusicResponsiveListItem extends YTNode {
|
||||
item_type: 'album' | 'playlist' | 'artist' | 'library_artist' | 'non_music_track' | 'video' | 'song' | 'endpoint' | 'unknown' | 'podcast_show' | undefined;
|
||||
index?: Text;
|
||||
thumbnail?: MusicThumbnail | null;
|
||||
badges;
|
||||
badges?: ObservedArray<YTNode>;
|
||||
menu?: Menu | null;
|
||||
overlay?: MusicItemThumbnailOverlay | null;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class Playlist extends YTNode {
|
||||
menu: YTNode;
|
||||
badges: ObservedArray<YTNode>;
|
||||
endpoint: NavigationEndpoint;
|
||||
thumbnail_overlays;
|
||||
thumbnail_overlays: ObservedArray<YTNode>;
|
||||
view_playlist?: Text;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Parser, type RawNode } from '../index.js';
|
||||
import BackstageImage from './BackstageImage.js';
|
||||
import type { ObservedArray } from '../helpers.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
|
||||
export default class PostMultiImage extends YTNode {
|
||||
static type = 'PostMultiImage';
|
||||
|
||||
images : BackstageImage[];
|
||||
images: ObservedArray<BackstageImage>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
70
src/parser/classes/SubscribeButtonView.ts
Normal file
70
src/parser/classes/SubscribeButtonView.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import type { RawNode } from '../types/RawResponse.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import NavigationEndpoint from './NavigationEndpoint.js';
|
||||
|
||||
interface ButtonContent {
|
||||
button_text: string;
|
||||
accessibility_text: string;
|
||||
image_name: string;
|
||||
subscribe_state_subscribed: boolean;
|
||||
endpoint: NavigationEndpoint;
|
||||
}
|
||||
|
||||
export default class SubscribeButtonView extends YTNode {
|
||||
static type = 'SubscribeButtonView';
|
||||
|
||||
public subscribe_button_content: ButtonContent;
|
||||
public unsubscribe_button_content: ButtonContent;
|
||||
public disable_notification_bell: boolean;
|
||||
public button_style: {
|
||||
unsubscribed_state_style: string;
|
||||
subscribed_state_style: string;
|
||||
};
|
||||
public is_signed_out: boolean;
|
||||
public background_style: string;
|
||||
public disable_subscribe_button: boolean;
|
||||
public on_show_subscription_options: NavigationEndpoint;
|
||||
public channel_id: string;
|
||||
public enable_subscribe_button_post_click_animation: boolean;
|
||||
public bell_accessiblity_data: {
|
||||
off_label: string;
|
||||
all_label: string;
|
||||
occasional_label: string;
|
||||
disabled_label: string;
|
||||
};
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
this.subscribe_button_content = this.#parseButtonContent(data.subscribeButtonContent);
|
||||
this.unsubscribe_button_content = this.#parseButtonContent(data.unsubscribeButtonContent);
|
||||
|
||||
this.disable_notification_bell = data.disableNotificationBell;
|
||||
this.button_style = {
|
||||
unsubscribed_state_style: data.buttonStyle.unsubscribedStateStyle,
|
||||
subscribed_state_style: data.buttonStyle.subscribedStateStyle
|
||||
};
|
||||
this.is_signed_out = data.isSignedOut;
|
||||
this.background_style = data.backgroundStyle;
|
||||
this.disable_subscribe_button = data.disableSubscribeButton;
|
||||
this.on_show_subscription_options = new NavigationEndpoint(data.onShowSubscriptionOptions);
|
||||
this.channel_id = data.channelId;
|
||||
this.enable_subscribe_button_post_click_animation = data.enableSubscribeButtonPostClickAnimation;
|
||||
this.bell_accessiblity_data = {
|
||||
off_label: data.bellAccessibilityData.offLabel,
|
||||
all_label: data.bellAccessibilityData.allLabel,
|
||||
occasional_label: data.bellAccessibilityData.occasionalLabel,
|
||||
disabled_label: data.bellAccessibilityData.disabledLabel
|
||||
};
|
||||
}
|
||||
|
||||
#parseButtonContent(data: RawNode): ButtonContent {
|
||||
return {
|
||||
button_text: data.buttonText,
|
||||
accessibility_text: data.accessibilityText,
|
||||
image_name: data.imageName,
|
||||
subscribe_state_subscribed: data.subscribeState.subscribed,
|
||||
endpoint: new NavigationEndpoint(data.onTapCommand)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ObservedArray } from '../helpers.js';
|
||||
import { YTNode } from '../helpers.js';
|
||||
import { Parser, type RawNode } from '../index.js';
|
||||
import ThumbnailBadgeView from './ThumbnailBadgeView.js';
|
||||
@@ -5,7 +6,7 @@ import ThumbnailBadgeView from './ThumbnailBadgeView.js';
|
||||
export default class ThumbnailOverlayBadgeView extends YTNode {
|
||||
static type = 'ThumbnailOverlayBadgeView';
|
||||
|
||||
public badges: ThumbnailBadgeView[];
|
||||
public badges: ObservedArray<ThumbnailBadgeView>;
|
||||
public position: string;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class TwoColumnWatchNextResults extends YTNode {
|
||||
id: string,
|
||||
title: string,
|
||||
author: Text | Author,
|
||||
contents: YTNode[],
|
||||
contents: ObservedArray<YTNode>,
|
||||
current_index: number,
|
||||
is_infinite: boolean,
|
||||
menu: Menu | null
|
||||
|
||||
@@ -24,7 +24,7 @@ export default class Video extends YTNode {
|
||||
public thumbnail_overlays: ObservedArray<YTNode>;
|
||||
public rich_thumbnail?: YTNode;
|
||||
public author: Author;
|
||||
public badges: MetadataBadge[];
|
||||
public badges: ObservedArray<MetadataBadge>;
|
||||
public endpoint?: NavigationEndpoint;
|
||||
public published?: Text;
|
||||
public view_count?: Text;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { YTNode } from '../../helpers.js';
|
||||
export default class AppendContinuationItemsAction extends YTNode {
|
||||
static type = 'AppendContinuationItemsAction';
|
||||
|
||||
contents: ObservedArray<YTNode> | null;
|
||||
contents: ObservedArray<YTNode>;
|
||||
target: string;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -12,7 +12,7 @@ export default class LiveChatSponsorshipsHeader extends YTNode {
|
||||
|
||||
author_name: Text;
|
||||
author_photo: Thumbnail[];
|
||||
author_badges: ObservedArray<LiveChatAuthorBadge> | null;
|
||||
author_badges: ObservedArray<LiveChatAuthorBadge>;
|
||||
primary_text: Text;
|
||||
menu_endpoint: NavigationEndpoint;
|
||||
context_menu_accessibility_label: string;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ObservedArray } from '../../helpers.js';
|
||||
import { YTNode } from '../../helpers.js';
|
||||
import Text from '../misc/Text.js';
|
||||
import { Parser, type RawNode } from '../../index.js';
|
||||
@@ -6,7 +7,7 @@ export default class MobileTopbar extends YTNode {
|
||||
static type = 'MobileTopbar';
|
||||
|
||||
public placeholder_text: Text;
|
||||
public buttons;
|
||||
public buttons: ObservedArray<YTNode>;
|
||||
public logo_type?: string;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { ObservedArray } from '../../helpers.js';
|
||||
import { YTNode } from '../../helpers.js';
|
||||
import { Parser, type RawNode } from '../../index.js';
|
||||
|
||||
export default class PivotBar extends YTNode {
|
||||
static type = 'PivotBar';
|
||||
|
||||
public items;
|
||||
public items: ObservedArray<YTNode>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { ObservedArray } from './helpers.js';
|
||||
export class ItemSectionContinuation extends YTNode {
|
||||
static readonly type = 'itemSectionContinuation';
|
||||
|
||||
contents: ObservedArray<YTNode> | null;
|
||||
contents: ObservedArray<YTNode>;
|
||||
continuation?: string;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
@@ -94,7 +94,7 @@ export class MusicShelfContinuation extends YTNode {
|
||||
static readonly type = 'musicShelfContinuation';
|
||||
|
||||
continuation: string;
|
||||
contents: ObservedArray<YTNode> | null;
|
||||
contents: ObservedArray<YTNode>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
@@ -126,7 +126,7 @@ export class PlaylistPanelContinuation extends YTNode {
|
||||
static readonly type = 'playlistPanelContinuation';
|
||||
|
||||
continuation: string;
|
||||
contents: ObservedArray<YTNode> | null;
|
||||
contents: ObservedArray<YTNode>;
|
||||
|
||||
constructor(data: RawNode) {
|
||||
super();
|
||||
|
||||
@@ -224,6 +224,8 @@ export { default as ItemSectionTab } from './classes/ItemSectionTab.js';
|
||||
export { default as ItemSectionTabbedHeader } from './classes/ItemSectionTabbedHeader.js';
|
||||
export { default as LikeButton } from './classes/LikeButton.js';
|
||||
export { default as LikeButtonView } from './classes/LikeButtonView.js';
|
||||
export { default as ListItemView } from './classes/ListItemView.js';
|
||||
export { default as ListView } from './classes/ListView.js';
|
||||
export { default as LiveChat } from './classes/LiveChat.js';
|
||||
export { default as AddBannerToLiveChatCommand } from './classes/livechat/AddBannerToLiveChatCommand.js';
|
||||
export { default as AddChatItemAction } from './classes/livechat/AddChatItemAction.js';
|
||||
@@ -457,6 +459,7 @@ export { default as StructuredDescriptionPlaylistLockup } from './classes/Struct
|
||||
export { default as SubFeedOption } from './classes/SubFeedOption.js';
|
||||
export { default as SubFeedSelector } from './classes/SubFeedSelector.js';
|
||||
export { default as SubscribeButton } from './classes/SubscribeButton.js';
|
||||
export { default as SubscribeButtonView } from './classes/SubscribeButtonView.js';
|
||||
export { default as SubscriptionNotificationToggleButton } from './classes/SubscriptionNotificationToggleButton.js';
|
||||
export { default as Tab } from './classes/Tab.js';
|
||||
export { default as Tabbed } from './classes/Tabbed.js';
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as YTNodes from './nodes.js';
|
||||
import { InnertubeError, ParsingError, Platform } from '../utils/Utils.js';
|
||||
import { InnertubeError, ParsingError } from '../utils/Utils.js';
|
||||
import type { ObservedArray, YTNode, YTNodeConstructor } from './helpers.js';
|
||||
import { Memo, observe, SuperParsedResult } from './helpers.js';
|
||||
import type { KeyInfo } from './generator.js';
|
||||
import { camelToSnake, generateRuntimeClass, generateTypescriptClass } from './generator.js';
|
||||
import { Log } from '../utils/index.js';
|
||||
import packageInfo from '../../package.json' with { type: 'json' };
|
||||
|
||||
import {
|
||||
Continuation,
|
||||
@@ -102,7 +103,7 @@ let ERROR_HANDLER: ParserErrorHandler = ({ classname, ...context }: ParserError)
|
||||
Log.warn(TAG,
|
||||
new InnertubeError(
|
||||
`Something went wrong at ${classname}!\n` +
|
||||
`This is a bug, please report it at ${Platform.shim.info.bugs_url}`, {
|
||||
`This is a bug, please report it at ${packageInfo.bugs.url}`, {
|
||||
stack: context.error.stack,
|
||||
classdata: JSON.stringify(context.classdata, null, 2)
|
||||
}
|
||||
@@ -122,7 +123,7 @@ let ERROR_HANDLER: ParserErrorHandler = ({ classname, ...context }: ParserError)
|
||||
Log.warn(TAG,
|
||||
new InnertubeError(
|
||||
`Mutation data required for processing ${classname}, but none found.\n` +
|
||||
`This is a bug, please report it at ${Platform.shim.info.bugs_url}`
|
||||
`This is a bug, please report it at ${packageInfo.bugs.url}`
|
||||
)
|
||||
);
|
||||
break;
|
||||
@@ -131,7 +132,7 @@ let ERROR_HANDLER: ParserErrorHandler = ({ classname, ...context }: ParserError)
|
||||
new InnertubeError(
|
||||
`Mutation data missing or invalid for ${context.failed} out of ${context.total} MusicMultiSelectMenuItems. ` +
|
||||
`The titles of the failed items are: ${context.titles.join(', ')}.\n` +
|
||||
`This is a bug, please report it at ${Platform.shim.info.bugs_url}`
|
||||
`This is a bug, please report it at ${packageInfo.bugs.url}`
|
||||
)
|
||||
);
|
||||
break;
|
||||
@@ -139,7 +140,7 @@ let ERROR_HANDLER: ParserErrorHandler = ({ classname, ...context }: ParserError)
|
||||
Log.warn(TAG,
|
||||
new InnertubeError(
|
||||
`${classname} not found!\n` +
|
||||
`This is a bug, want to help us fix it? Follow the instructions at ${Platform.shim.info.repo_url}/blob/main/docs/updating-the-parser.md or report it at ${Platform.shim.info.bugs_url}!\n` +
|
||||
`This is a bug, want to help us fix it? Follow the instructions at ${packageInfo.homepage.split('#', 1)[0]}/blob/main/docs/updating-the-parser.md or report it at ${packageInfo.bugs.url}!\n` +
|
||||
`Introspected and JIT generated this class in the meantime:\n${generateTypescriptClass(classname, context.key_info)}`
|
||||
)
|
||||
);
|
||||
|
||||
@@ -62,7 +62,7 @@ export default class Channel extends TabbedFeed<IBrowseResponse> {
|
||||
this.subscribe_button = this.page.header_memo?.getType(SubscribeButton)[0];
|
||||
|
||||
if (this.page.contents)
|
||||
this.current_tab = this.page.contents.item().as(TwoColumnBrowseResults).tabs.get({ selected: true });
|
||||
this.current_tab = this.page.contents.item().as(TwoColumnBrowseResults).tabs.find((tab) => tab.selected);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ export default class Channel extends TabbedFeed<IBrowseResponse> {
|
||||
const filter_chipbar = this.memo.getType(FeedFilterChipBar)[0];
|
||||
|
||||
if (typeof filter === 'string') {
|
||||
target_filter = filter_chipbar?.contents.get({ text: filter });
|
||||
target_filter = filter_chipbar?.contents.find((chip) => chip.text === filter);
|
||||
if (!target_filter)
|
||||
throw new InnertubeError(`Filter ${filter} not found`, { available_filters: this.filters });
|
||||
} else {
|
||||
@@ -330,7 +330,7 @@ export class FilteredChannelList extends FilterableFeed<IBrowseResponse> {
|
||||
constructor(actions: Actions, data: ApiResponse | IBrowseResponse, already_parsed = false) {
|
||||
super(actions, data, already_parsed);
|
||||
|
||||
this.applied_filter = this.memo.getType(ChipCloudChip).get({ is_selected: true });
|
||||
this.applied_filter = this.memo.getType(ChipCloudChip).find((chip) => chip.is_selected);
|
||||
|
||||
// Removes the filter chipbar from the actions list
|
||||
if (
|
||||
|
||||
@@ -59,7 +59,9 @@ export default class Search extends Feed<ISearchResponse> {
|
||||
|
||||
if (typeof card === 'string') {
|
||||
if (!this.refinement_cards) throw new InnertubeError('No refinement cards found.');
|
||||
target_card = this.refinement_cards?.cards.get({ query: card })?.as(SearchRefinementCard);
|
||||
target_card = this.refinement_cards?.cards.find((refinement_card): refinement_card is SearchRefinementCard => {
|
||||
return refinement_card.is(SearchRefinementCard) && refinement_card.query === card;
|
||||
});
|
||||
if (!target_card)
|
||||
throw new InnertubeError(`Refinement card "${card}" not found`, { available_cards: this.refinement_card_queries });
|
||||
} else if (card.type === 'SearchRefinementCard') {
|
||||
|
||||
@@ -33,7 +33,7 @@ export default class Settings {
|
||||
if (!this.#page.contents)
|
||||
throw new InnertubeError('Page contents not found');
|
||||
|
||||
const tab = this.#page.contents.item().as(TwoColumnBrowseResults).tabs.get({ selected: true });
|
||||
const tab = this.#page.contents.item().as(TwoColumnBrowseResults).tabs.find((tab) => tab.selected);
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Target tab not found');
|
||||
@@ -58,7 +58,7 @@ export default class Settings {
|
||||
let item: CompactLink | undefined;
|
||||
|
||||
if (typeof target_item === 'string') {
|
||||
item = this.sidebar.items.get({ title: target_item });
|
||||
item = this.sidebar.items.find((link) => link.title === target_item);
|
||||
if (!item)
|
||||
throw new InnertubeError(`Item "${target_item}" not found`, { available_items: this.sidebar_items });
|
||||
} else if (target_item?.is(CompactLink)) {
|
||||
|
||||
@@ -131,7 +131,9 @@ export default class VideoInfo extends MediaInfo {
|
||||
}
|
||||
}
|
||||
|
||||
const comments_entry_point = results.get({ target_id: 'comments-entry-point' })?.as(ItemSection);
|
||||
const comments_entry_point = results.find((node): node is ItemSection => {
|
||||
return node.is(ItemSection) && node.target_id === 'comments-entry-point';
|
||||
});
|
||||
|
||||
this.comments_entry_point_header = comments_entry_point?.contents?.firstOfType(CommentsEntryPointHeader);
|
||||
this.livechat = next?.contents_memo?.getType(LiveChat)[0];
|
||||
@@ -163,7 +165,7 @@ export default class VideoInfo extends MediaInfo {
|
||||
let cloud_chip: ChipCloudChip;
|
||||
|
||||
if (typeof target_filter === 'string') {
|
||||
const filter = this.related_chip_cloud?.chips?.get({ text: target_filter });
|
||||
const filter = this.related_chip_cloud?.chips?.find((chip) => chip.text === target_filter);
|
||||
|
||||
if (!filter)
|
||||
throw new InnertubeError('Invalid filter', { available_filters: this.filters });
|
||||
@@ -178,9 +180,11 @@ export default class VideoInfo extends MediaInfo {
|
||||
if (cloud_chip.is_selected) return this;
|
||||
|
||||
const response = await cloud_chip.endpoint?.call(this.actions, { parse: true });
|
||||
const data = response?.on_response_received_endpoints?.get({ target_id: 'watch-next-feed' });
|
||||
const data = response?.on_response_received_endpoints?.find((endpoint): endpoint is ReloadContinuationItemsCommand => {
|
||||
return endpoint.is(ReloadContinuationItemsCommand) && endpoint.target_id === 'watch-next-feed';
|
||||
});
|
||||
|
||||
this.watch_next_feed = data?.as(AppendContinuationItemsAction, ReloadContinuationItemsCommand).contents;
|
||||
this.watch_next_feed = data?.contents;
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -207,12 +211,12 @@ export default class VideoInfo extends MediaInfo {
|
||||
throw new InnertubeError('Watch next feed continuation not found');
|
||||
|
||||
const response = await this.#watch_next_continuation?.endpoint.call(this.actions, { parse: true });
|
||||
const data = response?.on_response_received_endpoints?.get({ type: 'AppendContinuationItemsAction' });
|
||||
const data = response?.on_response_received_endpoints?.firstOfType(AppendContinuationItemsAction);
|
||||
|
||||
if (!data)
|
||||
throw new InnertubeError('AppendContinuationItemsAction not found');
|
||||
|
||||
this.watch_next_feed = data?.as(AppendContinuationItemsAction, ReloadContinuationItemsCommand).contents;
|
||||
this.watch_next_feed = data?.contents;
|
||||
if (this.watch_next_feed?.at(-1)?.is(ContinuationItem)) {
|
||||
this.#watch_next_continuation = this.watch_next_feed.pop()?.as(ContinuationItem);
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class Explore {
|
||||
constructor(response: ApiResponse) {
|
||||
this.#page = Parser.parseResponse<IBrowseResponse>(response.data);
|
||||
|
||||
const tab = this.#page.contents?.item().as(SingleColumnBrowseResults).tabs.get({ selected: true });
|
||||
const tab = this.#page.contents?.item().as(SingleColumnBrowseResults).tabs.find((tab) => tab.selected);
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class HomeFeed {
|
||||
this.#actions = actions;
|
||||
this.#page = Parser.parseResponse<IBrowseResponse>(response.data);
|
||||
|
||||
const tab = this.#page.contents?.item().as(SingleColumnBrowseResults).tabs.get({ selected: true });
|
||||
const tab = this.#page.contents?.item().as(SingleColumnBrowseResults).tabs.find((tab) => tab.selected);
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find Home tab.');
|
||||
@@ -62,7 +62,7 @@ export default class HomeFeed {
|
||||
let cloud_chip: ChipCloudChip | undefined;
|
||||
|
||||
if (typeof target_filter === 'string') {
|
||||
cloud_chip = this.header?.chips?.as(ChipCloudChip).get({ text: target_filter });
|
||||
cloud_chip = this.header?.chips?.as(ChipCloudChip).find((chip) => chip.text === target_filter);
|
||||
if (!cloud_chip)
|
||||
throw new InnertubeError('Could not find filter with given name.', { available_filters: this.filters });
|
||||
} else if (target_filter?.is(ChipCloudChip)) {
|
||||
|
||||
@@ -97,7 +97,7 @@ export default class Library {
|
||||
const chip_cloud = this.#page.contents_memo?.getType(ChipCloud)[0];
|
||||
|
||||
if (typeof filter === 'string') {
|
||||
target_chip = chip_cloud?.chips.get({ text: filter });
|
||||
target_chip = chip_cloud?.chips.find((chip) => chip.text === filter);
|
||||
|
||||
if (!target_chip)
|
||||
throw new InnertubeError(`Filter "${filter}" not found`, { available_filters: this.filters });
|
||||
|
||||
@@ -32,7 +32,7 @@ export default class Search {
|
||||
if (!this.#page.contents || !this.#page.contents_memo)
|
||||
throw new InnertubeError('Response did not contain any contents.');
|
||||
|
||||
const tab = this.#page.contents.item().as(TabbedSearchResults).tabs.get({ selected: true });
|
||||
const tab = this.#page.contents.item().as(TabbedSearchResults).tabs.find((tab) => tab.selected);
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
@@ -87,7 +87,7 @@ export default class Search {
|
||||
let cloud_chip: ChipCloudChip | undefined;
|
||||
|
||||
if (typeof target_filter === 'string') {
|
||||
cloud_chip = this.header?.chips?.as(ChipCloudChip).get({ text: target_filter });
|
||||
cloud_chip = this.header?.chips?.as(ChipCloudChip).find((chip) => chip.text === target_filter);
|
||||
if (!cloud_chip)
|
||||
throw new InnertubeError('Could not find filter with given name.', { available_filters: this.filters });
|
||||
} else if (target_filter?.is(ChipCloudChip)) {
|
||||
|
||||
@@ -48,7 +48,7 @@ class TrackInfo extends MediaInfo {
|
||||
throw new InnertubeError('Could not find any tab');
|
||||
|
||||
const target_tab =
|
||||
this.tabs.get({ title: title_or_page_type }) ||
|
||||
this.tabs.find((tab) => tab.title === title_or_page_type) ||
|
||||
this.tabs.find((tab) => tab.endpoint.payload.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType === title_or_page_type) ||
|
||||
this.tabs?.[0];
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import type { ICache } from '../types/Cache.js';
|
||||
import { Platform } from '../utils/Utils.js';
|
||||
import evaluate from './jsruntime/jinter.js';
|
||||
import { $INLINE_JSON } from 'ts-transformer-inline-file';
|
||||
import sha1Hash from './polyfills/web-crypto.js';
|
||||
|
||||
const { homepage, version, bugs } = $INLINE_JSON('../../package.json');
|
||||
const repo_url = homepage?.split('#')[0];
|
||||
|
||||
class Cache implements ICache {
|
||||
#persistent_directory: string;
|
||||
#persistent: boolean;
|
||||
@@ -44,11 +40,6 @@ class Cache implements ICache {
|
||||
|
||||
Platform.load({
|
||||
runtime: 'cf-worker',
|
||||
info: {
|
||||
version: version,
|
||||
bugs_url: bugs?.url || `${repo_url}/issues`,
|
||||
repo_url
|
||||
},
|
||||
server: true,
|
||||
Cache: Cache,
|
||||
sha1Hash,
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { ICache } from '../types/Cache.js';
|
||||
import { Platform } from '../utils/Utils.js';
|
||||
import evaluate from './jsruntime/jinter.js';
|
||||
import sha1Hash from './polyfills/web-crypto.js';
|
||||
import package_json from '../../package.json' with { type: 'json' };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
@@ -82,11 +81,6 @@ class Cache implements ICache {
|
||||
|
||||
Platform.load({
|
||||
runtime: 'deno',
|
||||
info: {
|
||||
version: package_json.version,
|
||||
bugs_url: package_json.bugs.url,
|
||||
repo_url: package_json.homepage.split('#')[0]
|
||||
},
|
||||
server: true,
|
||||
Cache: Cache,
|
||||
sha1Hash,
|
||||
|
||||
@@ -18,15 +18,11 @@ import fs from 'fs/promises';
|
||||
import CustomEvent from './polyfills/node-custom-event.js';
|
||||
import { fileURLToPath } from 'url';
|
||||
import evaluate from './jsruntime/jinter.js';
|
||||
import { $INLINE_JSON } from 'ts-transformer-inline-file';
|
||||
|
||||
const meta_url = import.meta.url;
|
||||
const is_cjs = !meta_url;
|
||||
const __dirname__ = is_cjs ? __dirname : path.dirname(fileURLToPath(meta_url));
|
||||
|
||||
const { homepage, version, bugs } = $INLINE_JSON('../../package.json');
|
||||
const repo_url = homepage?.split('#')[0];
|
||||
|
||||
class Cache implements ICache {
|
||||
#persistent_directory: string;
|
||||
#persistent: boolean;
|
||||
@@ -100,11 +96,6 @@ class Cache implements ICache {
|
||||
|
||||
Platform.load({
|
||||
runtime: 'node',
|
||||
info: {
|
||||
version: version,
|
||||
bugs_url: bugs?.url || `${repo_url}/issues`,
|
||||
repo_url
|
||||
},
|
||||
server: true,
|
||||
Cache: Cache,
|
||||
sha1Hash: async (data: string) => {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { ICache } from '../types/Cache.js';
|
||||
import { Platform } from '../utils/Utils.js';
|
||||
import sha1Hash from './polyfills/web-crypto.js';
|
||||
import package_json from '../../package.json' with { type: 'json' };
|
||||
import evaluate from './jsruntime/jinter.js';
|
||||
|
||||
class Cache implements ICache {
|
||||
@@ -42,11 +41,6 @@ class Cache implements ICache {
|
||||
Platform.load({
|
||||
runtime: 'react-native',
|
||||
server: false,
|
||||
info: {
|
||||
version: package_json.version,
|
||||
bugs_url: package_json.bugs.url,
|
||||
repo_url: package_json.homepage.split('#')[0]
|
||||
},
|
||||
Cache: Cache,
|
||||
sha1Hash,
|
||||
uuidv4() {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { ICache } from '../types/Cache.js';
|
||||
import { Platform } from '../utils/Utils.js';
|
||||
import sha1Hash from './polyfills/web-crypto.js';
|
||||
import package_json from '../../package.json' assert { type: 'json' };
|
||||
import evaluate from './jsruntime/jinter.js';
|
||||
import * as Log from '../utils/Log.js';
|
||||
|
||||
@@ -95,11 +94,6 @@ class Cache implements ICache {
|
||||
Platform.load({
|
||||
runtime: 'browser',
|
||||
server: false,
|
||||
info: {
|
||||
version: package_json.version,
|
||||
bugs_url: package_json.bugs.url,
|
||||
repo_url: package_json.homepage.split('#')[0]
|
||||
},
|
||||
Cache: Cache,
|
||||
sha1Hash,
|
||||
uuidv4() {
|
||||
|
||||
@@ -8,11 +8,6 @@ export type VMPrimative = string | number | boolean | null | undefined;
|
||||
|
||||
interface PlatformShim {
|
||||
runtime: Runtime;
|
||||
info: {
|
||||
version: string,
|
||||
bugs_url: string,
|
||||
repo_url: string
|
||||
},
|
||||
server: boolean;
|
||||
Cache: ICacheConstructor;
|
||||
sha1Hash(data: string): Promise<string>;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { StoryboardData } from '../parser/classes/PlayerStoryboardSpec.js';
|
||||
import PlayerStoryboardSpec from '../parser/classes/PlayerStoryboardSpec.js';
|
||||
import { getStringBetweenStrings, InnertubeError, Platform } from './Utils.js';
|
||||
import { getStringBetweenStrings, InnertubeError } from './Utils.js';
|
||||
import * as Constants from './Constants.js';
|
||||
import * as Log from './Log.js';
|
||||
import packageInfo from '../../package.json' with { type: 'json' };
|
||||
|
||||
import type Actions from '../core/Actions.js';
|
||||
import type Player from '../core/Player.js';
|
||||
@@ -543,7 +544,7 @@ function getColorInfo(format: Format) {
|
||||
anonymisedFormat.cipher = 'REDACTED';
|
||||
|
||||
Log.warn(TAG_, `Unknown matrix coefficients "${color_info.matrix_coefficients}". The DASH manifest is still usable without this.\n`
|
||||
+ `Please report it at ${Platform.shim.info.bugs_url} so we can add support for it.\n`
|
||||
+ `Please report it at ${packageInfo.bugs.url} so we can add support for it.\n`
|
||||
+ `InnerTube client: ${url.searchParams.get('c')}\nformat:`, anonymisedFormat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Memo } from '../parser/helpers.js';
|
||||
import { Text } from '../parser/misc.js';
|
||||
import * as Log from './Log.js';
|
||||
import userAgents from './user-agents.js';
|
||||
import packageInfo from '../../package.json' with { type: 'json' };
|
||||
|
||||
const TAG_ = 'Utils';
|
||||
|
||||
@@ -40,7 +41,7 @@ export class InnertubeError extends Error {
|
||||
}
|
||||
|
||||
this.date = new Date();
|
||||
this.version = Platform.shim.info.version;
|
||||
this.version = packageInfo.version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +354,7 @@ export function findFunction(source: string, args: ASTLookupArgs): ASTLookupResu
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a variable declaration in the given code based on specified criteria.
|
||||
* Searches for a variable declarator in the given code based on specified criteria.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
@@ -381,23 +382,21 @@ export function findVariable(code: string, options: ASTLookupArgs): ASTLookupRes
|
||||
function walk(node: Node): void {
|
||||
if (found) return;
|
||||
|
||||
if (node.type === 'VariableDeclaration') {
|
||||
if (node.type === 'VariableDeclarator') {
|
||||
const [ start, end ] = node.range!;
|
||||
const node_source = code.slice(start, end);
|
||||
|
||||
for (const declarator of node.declarations) {
|
||||
if (declarator.id.type === 'Identifier') {
|
||||
const var_name = declarator.id.name;
|
||||
if (options.name && var_name === options.name) {
|
||||
found = { start, end, name: var_name, node, result: node_source };
|
||||
return;
|
||||
}
|
||||
if (node.id.type === 'Identifier') {
|
||||
const var_name = node.id.name;
|
||||
if (options.name && var_name === options.name) {
|
||||
found = { start, end, name: var_name, node, result: node_source };
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (
|
||||
(options.includes && node_source.includes(options.includes)) ||
|
||||
(options.regexp && options.regexp.test(node_source))) {
|
||||
found = { start, end, name: (node.declarations?.[0]?.id as any)?.name, node, result: node_source };
|
||||
found = { start, end, name: (node?.id as any)?.name, node, result: node_source };
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
|
||||
"plugins": [
|
||||
{ "transform": "ts-transformer-inline-file/transformer" },
|
||||
{ "transform": "./dev-scripts/enum-optimising-transformer.cjs" }
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user