Compare commits

..

13 Commits

Author SHA1 Message Date
LuanRT
c76f5f478d 2.5.1 2022-11-30 19:11:40 -03:00
LuanRT
49d1432b5a chore: fix a few inconsistencies 2022-11-30 19:02:49 -03:00
LuanRT
be157ef016 fix: signature decipher extraction failing (#249) 2022-11-30 18:39:37 -03:00
LuanRT
9f703203b6 chore(docs): update readme 2022-11-29 05:49:15 -03:00
LuanRT
516eeeff45 refactor: improve Search parser (#247)
* refactor: improve Search parser

* chore: lint
2022-11-29 03:50:17 -03:00
LuanRT
6caa679df6 chore(release) v2.5.0 2022-11-25 01:36:50 -03:00
LuanRT
2a87f42b32 fix(Search): check if WatchCardHeroVideo is null before casting
Related #243
2022-11-25 01:25:02 -03:00
LuanRT
f7c1e0f249 fix(Music): search endpoint missing
Related: #242
2022-11-23 20:04:24 -03:00
LuanRT
fe4c5433cf feat: make Player instance optional (#240) 2022-11-16 03:17:59 -03:00
LuanRT
0e5e0c0fab feat(Channel): add support for filters (#237)
* feat: add support for filters

Also add `channel#getShorts()` and `channel#getLiveStreams()`

* docs: update API ref

* chore: add tests
2022-11-14 19:08:16 -03:00
LuanRT
f0fd6146c7 Merge branch 'main' of https://github.com/LuanRT/YouTube.js 2022-11-14 15:32:08 -03:00
LuanRT
43061970c6 fix: export Player & Session classes 2022-11-14 15:30:40 -03:00
LuanRT
746023d9bb chore(docs): fix typo' 2022-11-12 19:36:47 -03:00
41 changed files with 475 additions and 318 deletions

View File

@@ -1,5 +1,3 @@
<!-- Hi there, fellow coder :) -->
<!-- BADGE LINKS -->
[npm]: https://www.npmjs.com/package/youtubei.js
[versions]: https://www.npmjs.com/package/youtubei.js?activeTab=versions
@@ -10,37 +8,23 @@
<!-- OTHER LINKS -->
[project]: https://github.com/LuanRT/YouTube.js
[twitter]: https://twitter.com/lrt_nooneknows
[twitter]: https://twitter.com/thesciencephile
[discord]: https://discord.gg/syDu7Yks54
[nodejs]: https://nodejs.org
<!-- INTRODUCTION -->
<h1 align=center>
YouTube.js
</h1>
<h1 align=center>YouTube.js</h1>
<p align=center>
<i>
A full-featured wrapper around the InnerTube API, which is what YouTube itself uses.
</i>
</p>
<p align="center">
<a href="https://github.com/LuanRT/YouTube.js/issues">
Report Bug
</a>
·
<a href="https://github.com/LuanRT/YouTube.js/issues">
Request Feature
</a>
</p>
<p align=center>A full-featured wrapper around the InnerTube API, which is what YouTube itself uses.</p>
<!-- BADGES -->
<div align="center">
[![Tests](https://github.com/LuanRT/YouTube.js/actions/workflows/node.js.yml/badge.svg)][actions]
[![Latest version](https://img.shields.io/npm/v/youtubei.js?color=%2335C757)][versions]
[![NPM Version](https://img.shields.io/npm/v/youtubei.js?color=%2335C757)][versions]
[![Codefactor](https://www.codefactor.io/repository/github/luanrt/youtube.js/badge)][codefactor]
[![Downloads](https://img.shields.io/npm/dt/youtubei.js)][npm]
[![Discord](https://img.shields.io/badge/discord-online-brightgreen.svg)][discord]
[![Say thanks](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)][say-thanks]
<br>
[![Donate](https://img.shields.io/badge/donate-30363D?style=for-the-badge&logo=GitHub-Sponsors&logoColor=#white)][github-sponsors]
@@ -57,7 +41,7 @@
<body>
<tr>
<td align="center">
<a href="https://serpapi.com/">
<a href="https://serpapi.com/" target="_blank">
<img width="80" alt="SerpApi" src="https://luanrt.is-a.dev/assets/img/serpapi.svg" />
<br>
<b>
@@ -105,7 +89,7 @@ ___
</details>
<!-- ABOUT THE PROJECT -->
## About
## Description
InnerTube is an API used across all YouTube clients, it was created to simplify[^1] the internal structure of the platform in a way that updates, tweaks, and experiments can be easily made. This library handles all the low-level communication with InnerTube, providing a simple, fast, and efficient way to interact with YouTube programmatically.
@@ -245,7 +229,7 @@ const yt = await Innertube.create({
* `Innertube`
<details>
<summary>objects</summary>
<summary>Objects</summary>
<p>
* [.session](https://github.com/LuanRT/YouTube.js/blob/main/docs/API/session.md)
@@ -260,7 +244,7 @@ const yt = await Innertube.create({
<details>
<summary>methods</summary>
<summary>Methods</summary>
<p>
* [.getInfo(video_id, client?)](#getinfo)
@@ -418,8 +402,8 @@ Retrieves YouTube's home feed.
- `<home_feed>#posts`
- Returns all posts in the home feed.
- `<home_feed>#shelfs`
- Returns all shelfs in the home feed.
- `<home_feed>#shelves`
- Returns all shelves in the home feed.
- `<home_feed>#filters`
- Returns available filters.
@@ -497,11 +481,16 @@ Retrieves contents for a given channel.
<p>
- `<channel>#getVideos()`
- `<channel>#getShorts()`
- `<channel>#getLiveStreams()`
- `<channel>#getPlaylists()`
- `<channel>#getHome()`
- `<channel>#getCommunity()`
- `<channel>#getChannels()`
- `<channel>#getAbout()`
- `<channel>#getContinuation()`
- `<channel>#filters`
- `<channel>#page`
</p>
</details>
@@ -685,7 +674,7 @@ Feel free to check the [issues page](https://github.com/LuanRT/YouTube.js/issues
<!-- CONTACT -->
## Contact
LuanRT - [@lrt_nooneknows][twitter] - luan.lrt4@gmail.com
LuanRT - [@thesciencephile][twitter] - luan.lrt4@gmail.com
Project Link: [https://github.com/LuanRT/YouTube.js][project]
@@ -704,4 +693,4 @@ Distributed under the [MIT](https://choosealicense.com/licenses/mit/) License.
<p align=" right">
(<a href="#top">back to top</a>)
</p>
</p>

View File

@@ -6,4 +6,6 @@ export * from './src/utils';
export { YTNodes } from './src/parser/map';
export { default as Parser } from './src/parser';
export { default as Innertube } from './src/Innertube';
export { default as Session } from './src/core/Session';
export { default as Player } from './src/core/Player';
export default Innertube;

View File

@@ -23,4 +23,6 @@ export * from './src/utils';
export { YTNodes } from './src/parser/map';
export { default as Parser } from './src/parser';
export { default as Innertube } from './src/Innertube';
export { default as Session } from './src/core/Session';
export { default as Player } from './src/core/Player';
export default Innertube;

379
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "youtubei.js",
"version": "2.4.1",
"version": "2.5.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "youtubei.js",
"version": "2.4.1",
"version": "2.5.1",
"funding": [
"https://github.com/sponsors/LuanRT"
],
@@ -1202,15 +1202,15 @@
}
},
"node_modules/@protobuf-ts/plugin": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.1.tgz",
"integrity": "sha512-lacRdXJ9TkTbI28U0KApsnVqnxeq1aZftOdq6LNPQJaIzBrVRxrMkqnnGWGQFYe0Tr93OKeW4A2lLjTkn32CuA==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.2.tgz",
"integrity": "sha512-rTPxaeKBfUar8ubKxbVdv4XL6AcGA0OOgHNHFyrfODP7Epy80omwuvgFJex1YpeNFJxm/FZXXj5Z+nHuhYEqJg==",
"dev": true,
"dependencies": {
"@protobuf-ts/plugin-framework": "^2.8.1",
"@protobuf-ts/protoc": "^2.8.1",
"@protobuf-ts/runtime": "^2.8.1",
"@protobuf-ts/runtime-rpc": "^2.8.1",
"@protobuf-ts/plugin-framework": "^2.8.2",
"@protobuf-ts/protoc": "^2.8.2",
"@protobuf-ts/runtime": "^2.8.2",
"@protobuf-ts/runtime-rpc": "^2.8.2",
"typescript": "^3.9"
},
"bin": {
@@ -1219,12 +1219,12 @@
}
},
"node_modules/@protobuf-ts/plugin-framework": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.1.tgz",
"integrity": "sha512-hfLoYIyxCI6Ro6LY1BltNBDcXWL+36SwnWR/hcF4ttPHLE3rMIpYbz4IwQsfeU2SKbBeGFhZv9rcnDJB22cXog==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.2.tgz",
"integrity": "sha512-ivcJdNVB3Iee8044f8erZGBgmB6ZfQbbKyxRgDBXRVKYxsruLr432WcT5upw9autK9OnlSVLaebi8kDneFXd2g==",
"dev": true,
"dependencies": {
"@protobuf-ts/runtime": "^2.8.1",
"@protobuf-ts/runtime": "^2.8.2",
"typescript": "^3.9"
}
},
@@ -1255,26 +1255,26 @@
}
},
"node_modules/@protobuf-ts/protoc": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.1.tgz",
"integrity": "sha512-6fehuL9bS22zCgPBBlESZjnoA4fxAUkOjMcaFMJSlVpN6CDN2O+c/Mo1pCXaNDO7FAidMPj5yhz48Kws4kOXEA==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.2.tgz",
"integrity": "sha512-1e+rOgp22ElyqRWunSc8bhatJcvRe90AGPceVn67IFYzybvfKl17vP1igHddeYkN0dzOucnOrwqn2v1jnDfE2w==",
"dev": true,
"bin": {
"protoc": "protoc.js"
}
},
"node_modules/@protobuf-ts/runtime": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.1.tgz",
"integrity": "sha512-D9M5hSumYCovIfNllt7N6ODh4q+LrjiMWtNETvooaf+a2XheZJ7kgjFlsFghti0CFWwtA//of4JXQfw9hU+cCw=="
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.2.tgz",
"integrity": "sha512-PVxsH81y9kEbHldxxG/8Y3z2mTXWQytRl8zNS0mTPUjkEC+8GUX6gj6LsA8EFp25fAs9V0ruh+aNWmPccEI9MA=="
},
"node_modules/@protobuf-ts/runtime-rpc": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.1.tgz",
"integrity": "sha512-hc+HJpoAu50by8aBS55UygcrzD8jAvRKWZMCRJ9XY3h9Gl2tciYysfzSH1SWtF6XOT/4b5CKnnmdMR3ad7uU5g==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.2.tgz",
"integrity": "sha512-vum/Y7AXdUTWGFu7dke/jCSB9dV3Oo3iVPcce3j7KudpzzWarDkEGvXjKv3Y8zJPj5waToyxwBNSb7eo5Vw5WA==",
"dev": true,
"dependencies": {
"@protobuf-ts/runtime": "^2.8.1"
"@protobuf-ts/runtime": "^2.8.2"
}
},
"node_modules/@sinclair/typebox": {
@@ -1416,9 +1416,9 @@
"dev": true
},
"node_modules/@types/yargs": {
"version": "17.0.13",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
"integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.14.tgz",
"integrity": "sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==",
"dev": true,
"dependencies": {
"@types/yargs-parser": "*"
@@ -1431,14 +1431,14 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.1.tgz",
"integrity": "sha512-LyR6x784JCiJ1j6sH5Y0K6cdExqCCm8DJUTcwG5ThNXJj/G8o5E56u5EdG4SLy+bZAwZBswC+GYn3eGdttBVCg==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.42.1",
"@typescript-eslint/type-utils": "5.42.1",
"@typescript-eslint/utils": "5.42.1",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/type-utils": "5.44.0",
"@typescript-eslint/utils": "5.44.0",
"debug": "^4.3.4",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
@@ -1464,14 +1464,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.1.tgz",
"integrity": "sha512-kAV+NiNBWVQDY9gDJDToTE/NO8BHi4f6b7zTsVAJoTkmB/zlfOpiEVBzHOKtlgTndCKe8vj9F/PuolemZSh50Q==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.42.1",
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/typescript-estree": "5.42.1",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"debug": "^4.3.4"
},
"engines": {
@@ -1491,13 +1491,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.1.tgz",
"integrity": "sha512-QAZY/CBP1Emx4rzxurgqj3rUinfsh/6mvuKbLNMfJMMKYLRBfweus8brgXF8f64ABkIZ3zdj2/rYYtF8eiuksQ==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/visitor-keys": "5.42.1"
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -1508,13 +1508,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.1.tgz",
"integrity": "sha512-WWiMChneex5w4xPIX56SSnQQo0tEOy5ZV2dqmj8Z371LJ0E+aymWD25JQ/l4FOuuX+Q49A7pzh/CGIQflxMVXg==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz",
"integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.42.1",
"@typescript-eslint/utils": "5.42.1",
"@typescript-eslint/typescript-estree": "5.44.0",
"@typescript-eslint/utils": "5.44.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@@ -1535,9 +1535,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.1.tgz",
"integrity": "sha512-Qrco9dsFF5lhalz+lLFtxs3ui1/YfC6NdXu+RAGBa8uSfn01cjO7ssCsjIsUs484vny9Xm699FSKwpkCcqwWwA==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -1548,13 +1548,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.1.tgz",
"integrity": "sha512-qElc0bDOuO0B8wDhhW4mYVgi/LZL+igPwXtV87n69/kYC/7NG3MES0jHxJNCr4EP7kY1XVsRy8C/u3DYeTKQmw==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/visitor-keys": "5.42.1",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -1575,16 +1575,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.1.tgz",
"integrity": "sha512-Gxvf12xSp3iYZd/fLqiQRD4uKZjDNR01bQ+j8zvhPjpsZ4HmvEFL/tC4amGNyxN9Rq+iqvpHLhlqx6KTxz9ZyQ==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.42.1",
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/typescript-estree": "5.42.1",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@@ -1601,12 +1601,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.1.tgz",
"integrity": "sha512-LOQtSF4z+hejmpUvitPlc4hA7ERGoj2BVkesOcG91HCn8edLGUXbTrErmutmPbl8Bo9HjAvOO/zBKQHExXNA2A==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/types": "5.44.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@@ -1705,9 +1705,9 @@
}
},
"node_modules/anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"dependencies": {
"normalize-path": "^3.0.0",
@@ -1941,9 +1941,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001431",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
"integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==",
"version": "1.0.30001434",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
"dev": true,
"funding": [
{
@@ -1982,10 +1982,13 @@
}
},
"node_modules/ci-info": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
"integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==",
"dev": true
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz",
"integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/cjs-module-lexer": {
"version": "1.2.2",
@@ -2651,9 +2654,9 @@
}
},
"node_modules/eslint": {
"version": "8.27.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz",
"integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==",
"version": "8.28.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
"dev": true,
"dependencies": {
"@eslint/eslintrc": "^1.3.3",
@@ -3166,9 +3169,9 @@
}
},
"node_modules/globals": {
"version": "13.17.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
"version": "13.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -3827,9 +3830,9 @@
}
},
"node_modules/jest-pnp-resolver": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
"dev": true,
"engines": {
"node": ">=6"
@@ -4133,10 +4136,14 @@
"dev": true
},
"node_modules/js-sdsl": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
"integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
"dev": true
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/js-sdsl"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
@@ -4236,9 +4243,9 @@
"dev": true
},
"node_modules/linkedom": {
"version": "0.14.19",
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.19.tgz",
"integrity": "sha512-sFNkQZlKBWpEaAcbsDIghTLE0hHbyvS6dZuM7IH+KTM09GaQ772PtDZAuFlN0oFgyAjUj8XS9FpoWSLmBjl8MA==",
"version": "0.14.21",
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.21.tgz",
"integrity": "sha512-V+c0AAFMTVJA2iAhrdd+u44lL0TjL6hBenVB061VQ6BHqTAHtXw1v5F1/CHGKtwg0OHm+hrGbepb9ZSFJ7lJkg==",
"dependencies": {
"css-select": "^5.1.0",
"cssom": "^0.5.0",
@@ -5307,9 +5314,9 @@
}
},
"node_modules/typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -6408,15 +6415,15 @@
}
},
"@protobuf-ts/plugin": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.1.tgz",
"integrity": "sha512-lacRdXJ9TkTbI28U0KApsnVqnxeq1aZftOdq6LNPQJaIzBrVRxrMkqnnGWGQFYe0Tr93OKeW4A2lLjTkn32CuA==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.2.tgz",
"integrity": "sha512-rTPxaeKBfUar8ubKxbVdv4XL6AcGA0OOgHNHFyrfODP7Epy80omwuvgFJex1YpeNFJxm/FZXXj5Z+nHuhYEqJg==",
"dev": true,
"requires": {
"@protobuf-ts/plugin-framework": "^2.8.1",
"@protobuf-ts/protoc": "^2.8.1",
"@protobuf-ts/runtime": "^2.8.1",
"@protobuf-ts/runtime-rpc": "^2.8.1",
"@protobuf-ts/plugin-framework": "^2.8.2",
"@protobuf-ts/protoc": "^2.8.2",
"@protobuf-ts/runtime": "^2.8.2",
"@protobuf-ts/runtime-rpc": "^2.8.2",
"typescript": "^3.9"
},
"dependencies": {
@@ -6429,12 +6436,12 @@
}
},
"@protobuf-ts/plugin-framework": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.1.tgz",
"integrity": "sha512-hfLoYIyxCI6Ro6LY1BltNBDcXWL+36SwnWR/hcF4ttPHLE3rMIpYbz4IwQsfeU2SKbBeGFhZv9rcnDJB22cXog==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.2.tgz",
"integrity": "sha512-ivcJdNVB3Iee8044f8erZGBgmB6ZfQbbKyxRgDBXRVKYxsruLr432WcT5upw9autK9OnlSVLaebi8kDneFXd2g==",
"dev": true,
"requires": {
"@protobuf-ts/runtime": "^2.8.1",
"@protobuf-ts/runtime": "^2.8.2",
"typescript": "^3.9"
},
"dependencies": {
@@ -6447,23 +6454,23 @@
}
},
"@protobuf-ts/protoc": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.1.tgz",
"integrity": "sha512-6fehuL9bS22zCgPBBlESZjnoA4fxAUkOjMcaFMJSlVpN6CDN2O+c/Mo1pCXaNDO7FAidMPj5yhz48Kws4kOXEA==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.2.tgz",
"integrity": "sha512-1e+rOgp22ElyqRWunSc8bhatJcvRe90AGPceVn67IFYzybvfKl17vP1igHddeYkN0dzOucnOrwqn2v1jnDfE2w==",
"dev": true
},
"@protobuf-ts/runtime": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.1.tgz",
"integrity": "sha512-D9M5hSumYCovIfNllt7N6ODh4q+LrjiMWtNETvooaf+a2XheZJ7kgjFlsFghti0CFWwtA//of4JXQfw9hU+cCw=="
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.2.tgz",
"integrity": "sha512-PVxsH81y9kEbHldxxG/8Y3z2mTXWQytRl8zNS0mTPUjkEC+8GUX6gj6LsA8EFp25fAs9V0ruh+aNWmPccEI9MA=="
},
"@protobuf-ts/runtime-rpc": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.1.tgz",
"integrity": "sha512-hc+HJpoAu50by8aBS55UygcrzD8jAvRKWZMCRJ9XY3h9Gl2tciYysfzSH1SWtF6XOT/4b5CKnnmdMR3ad7uU5g==",
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.2.tgz",
"integrity": "sha512-vum/Y7AXdUTWGFu7dke/jCSB9dV3Oo3iVPcce3j7KudpzzWarDkEGvXjKv3Y8zJPj5waToyxwBNSb7eo5Vw5WA==",
"dev": true,
"requires": {
"@protobuf-ts/runtime": "^2.8.1"
"@protobuf-ts/runtime": "^2.8.2"
}
},
"@sinclair/typebox": {
@@ -6605,9 +6612,9 @@
"dev": true
},
"@types/yargs": {
"version": "17.0.13",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
"integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
"version": "17.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.14.tgz",
"integrity": "sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==",
"dev": true,
"requires": {
"@types/yargs-parser": "*"
@@ -6620,14 +6627,14 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.1.tgz",
"integrity": "sha512-LyR6x784JCiJ1j6sH5Y0K6cdExqCCm8DJUTcwG5ThNXJj/G8o5E56u5EdG4SLy+bZAwZBswC+GYn3eGdttBVCg==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.42.1",
"@typescript-eslint/type-utils": "5.42.1",
"@typescript-eslint/utils": "5.42.1",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/type-utils": "5.44.0",
"@typescript-eslint/utils": "5.44.0",
"debug": "^4.3.4",
"ignore": "^5.2.0",
"natural-compare-lite": "^1.4.0",
@@ -6637,53 +6644,53 @@
}
},
"@typescript-eslint/parser": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.1.tgz",
"integrity": "sha512-kAV+NiNBWVQDY9gDJDToTE/NO8BHi4f6b7zTsVAJoTkmB/zlfOpiEVBzHOKtlgTndCKe8vj9F/PuolemZSh50Q==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.42.1",
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/typescript-estree": "5.42.1",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.1.tgz",
"integrity": "sha512-QAZY/CBP1Emx4rzxurgqj3rUinfsh/6mvuKbLNMfJMMKYLRBfweus8brgXF8f64ABkIZ3zdj2/rYYtF8eiuksQ==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/visitor-keys": "5.42.1"
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0"
}
},
"@typescript-eslint/type-utils": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.1.tgz",
"integrity": "sha512-WWiMChneex5w4xPIX56SSnQQo0tEOy5ZV2dqmj8Z371LJ0E+aymWD25JQ/l4FOuuX+Q49A7pzh/CGIQflxMVXg==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz",
"integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==",
"dev": true,
"requires": {
"@typescript-eslint/typescript-estree": "5.42.1",
"@typescript-eslint/utils": "5.42.1",
"@typescript-eslint/typescript-estree": "5.44.0",
"@typescript-eslint/utils": "5.44.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.1.tgz",
"integrity": "sha512-Qrco9dsFF5lhalz+lLFtxs3ui1/YfC6NdXu+RAGBa8uSfn01cjO7ssCsjIsUs484vny9Xm699FSKwpkCcqwWwA==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.1.tgz",
"integrity": "sha512-qElc0bDOuO0B8wDhhW4mYVgi/LZL+igPwXtV87n69/kYC/7NG3MES0jHxJNCr4EP7kY1XVsRy8C/u3DYeTKQmw==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/visitor-keys": "5.42.1",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -6692,28 +6699,28 @@
}
},
"@typescript-eslint/utils": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.1.tgz",
"integrity": "sha512-Gxvf12xSp3iYZd/fLqiQRD4uKZjDNR01bQ+j8zvhPjpsZ4HmvEFL/tC4amGNyxN9Rq+iqvpHLhlqx6KTxz9ZyQ==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.42.1",
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/typescript-estree": "5.42.1",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.42.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.1.tgz",
"integrity": "sha512-LOQtSF4z+hejmpUvitPlc4hA7ERGoj2BVkesOcG91HCn8edLGUXbTrErmutmPbl8Bo9HjAvOO/zBKQHExXNA2A==",
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.42.1",
"@typescript-eslint/types": "5.44.0",
"eslint-visitor-keys": "^3.3.0"
}
},
@@ -6774,9 +6781,9 @@
}
},
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@@ -6952,9 +6959,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001431",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz",
"integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==",
"version": "1.0.30001434",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
"dev": true
},
"chalk": {
@@ -6974,9 +6981,9 @@
"dev": true
},
"ci-info": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
"integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==",
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz",
"integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==",
"dev": true
},
"cjs-module-lexer": {
@@ -7372,9 +7379,9 @@
"dev": true
},
"eslint": {
"version": "8.27.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz",
"integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==",
"version": "8.28.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
"dev": true,
"requires": {
"@eslint/eslintrc": "^1.3.3",
@@ -7768,9 +7775,9 @@
}
},
"globals": {
"version": "13.17.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
"version": "13.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
@@ -8252,9 +8259,9 @@
}
},
"jest-pnp-resolver": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
"dev": true,
"requires": {}
},
@@ -8499,9 +8506,9 @@
"dev": true
},
"js-sdsl": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
"integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
"dev": true
},
"js-tokens": {
@@ -8578,9 +8585,9 @@
"dev": true
},
"linkedom": {
"version": "0.14.19",
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.19.tgz",
"integrity": "sha512-sFNkQZlKBWpEaAcbsDIghTLE0hHbyvS6dZuM7IH+KTM09GaQ772PtDZAuFlN0oFgyAjUj8XS9FpoWSLmBjl8MA==",
"version": "0.14.21",
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.21.tgz",
"integrity": "sha512-V+c0AAFMTVJA2iAhrdd+u44lL0TjL6hBenVB061VQ6BHqTAHtXw1v5F1/CHGKtwg0OHm+hrGbepb9ZSFJ7lJkg==",
"requires": {
"css-select": "^5.1.0",
"cssom": "^0.5.0",
@@ -9342,9 +9349,9 @@
"dev": true
},
"typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
"dev": true
},
"uhyphen": {

View File

@@ -1,6 +1,6 @@
{
"name": "youtubei.js",
"version": "2.4.1",
"version": "2.5.1",
"description": "Full-featured wrapper around YouTube's private API. Supports YouTube, YouTube Music and YouTube Studio (WIP).",
"main": "./dist/index.js",
"browser": "./bundle/browser.js",

View File

@@ -49,7 +49,7 @@ class Actions {
referer: 'https://www.youtube.com',
currentUrl: `/watch?v=${id}`,
autonavState: 'STATE_OFF',
signatureTimestamp: this.#session.player.sts,
signatureTimestamp: this.#session.player?.sts || 0,
autoCaptionsDefaultOn: false,
html5Preference: 'HTML5_PREF_WANTS',
lactMilliseconds: '-1'
@@ -188,6 +188,7 @@ class Actions {
'FEsubscriptions',
'FEmusic_listening_review',
'FEmusic_library_landing',
'SPaccount_overview',
'SPaccount_notifications',
'SPaccount_privacy',
'SPtime_watched'

View File

@@ -29,6 +29,7 @@ import AppendContinuationItemsAction from '../parser/classes/actions/AppendConti
import ContinuationItem from '../parser/classes/ContinuationItem';
import Video from '../parser/classes/Video';
import ReelItem from '../parser/classes/ReelItem';
class Feed {
#page: ParsedResponse;
@@ -63,9 +64,10 @@ class Feed {
* Get all videos on a given page via memo
*/
static getVideosFromMemo(memo: Memo) {
return memo.getType<Video | GridVideo | CompactVideo | PlaylistVideo | PlaylistPanelVideo | WatchCardCompactVideo>([
return memo.getType<Video | GridVideo | ReelItem | CompactVideo | PlaylistVideo | PlaylistPanelVideo | WatchCardCompactVideo>([
Video,
GridVideo,
ReelItem,
CompactVideo,
PlaylistVideo,
PlaylistPanelVideo,

View File

@@ -61,7 +61,7 @@ class Music {
videoId: video_id,
playbackContext: {
contentPlaybackContext: {
signatureTimestamp: this.#session.player.sts
signatureTimestamp: this.#session.player?.sts || 0
}
}
});
@@ -89,7 +89,7 @@ class Music {
client: 'YTMUSIC',
playbackContext: {
contentPlaybackContext: {
signatureTimestamp: this.#session.player.sts
signatureTimestamp: this.#session.player?.sts || 0
}
}
});

View File

@@ -167,13 +167,13 @@ export default class Player {
static extractSigSourceCode(data: string) {
const calls = getStringBetweenStrings(data, 'function(a){a=a.split("")', 'return a.join("")}');
const obj_name = calls?.split('.')?.[0]?.replace(';', '');
const functions = getStringBetweenStrings(data, `var ${obj_name}=`, '};');
const obj_name = calls?.split(/\.|\[/)?.[0]?.replace(';', '')?.trim();
const functions = getStringBetweenStrings(data, `var ${obj_name}={`, '};');
if (!functions || !calls)
console.warn(new PlayerError('Failed to extract signature decipher algorithm'));
return `function descramble_sig(a) { a = a.split(""); let ${obj_name}=${functions}}${calls} return a.join("") } descramble_sig(sig);`;
return `function descramble_sig(a) { a = a.split(""); let ${obj_name}={${functions}}${calls} return a.join("") } descramble_sig(sig);`;
}
static extractNSigSourceCode(data: string) {

View File

@@ -78,7 +78,7 @@ export default class Session extends EventEmitterLike {
actions;
cache;
constructor(context: Context, api_key: string, api_version: string, account_index: number, player: Player, cookie?: string, fetch?: FetchFunction, cache?: UniversalCache) {
constructor(context: Context, api_key: string, api_version: string, account_index: number, player?: Player, cookie?: string, fetch?: FetchFunction, cache?: UniversalCache) {
super();
this.#context = context;
this.#account_index = account_index;

View File

@@ -1,7 +1,7 @@
import Parser from '..';
import { YTNode } from '../helpers';
export default class CarouselHeader extends YTNode {
class CarouselHeader extends YTNode {
static type = 'CarouselHeader';
contents: YTNode[];
@@ -10,4 +10,6 @@ export default class CarouselHeader extends YTNode {
super();
this.contents = Parser.parseArray(data.contents);
}
}
}
export default CarouselHeader;

View File

@@ -3,7 +3,7 @@ import { YTNode } from '../helpers';
import Thumbnail from './misc/Thumbnail';
export default class CarouselItem extends YTNode {
class CarouselItem extends YTNode {
static type = 'CarouselItem';
items: YTNode[];
@@ -20,4 +20,6 @@ export default class CarouselItem extends YTNode {
this.pagination_thumbnails = Thumbnail.fromResponse(data.paginationThumbnails);
this.paginator_alignment = data.paginatorAlignment;
}
}
}
export default CarouselItem;

View File

@@ -4,7 +4,7 @@ import Text from './misc/Text';
import Thumbnail from './misc/Thumbnail';
import NavigationEndpoint from './NavigationEndpoint';
export default class CompactStation extends YTNode {
class CompactStation extends YTNode {
static type = 'CompactStation';
title: Text;
@@ -22,4 +22,6 @@ export default class CompactStation extends YTNode {
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
}
}
}
export default CompactStation;

View File

@@ -4,7 +4,7 @@ import { YTNode } from '../helpers';
import Text from './misc/Text';
import NavigationEndpoint from './NavigationEndpoint';
export default class DefaultPromoPanel extends YTNode {
class DefaultPromoPanel extends YTNode {
static type = 'DefaultPromoPanel';
title: Text;
@@ -33,4 +33,6 @@ export default class DefaultPromoPanel extends YTNode {
this.metadata_order = data.metadataOrder;
this.panel_layout = data.panelLayout;
}
}
}
export default DefaultPromoPanel;

View File

@@ -2,7 +2,7 @@ import Parser from '../index';
import { YTNode } from '../helpers';
import ChipCloudChip from './ChipCloudChip';
export default class FeedFilterChipBar extends YTNode {
class FeedFilterChipBar extends YTNode {
static type = 'FeedFilterChipBar';
contents;
@@ -11,4 +11,6 @@ export default class FeedFilterChipBar extends YTNode {
super();
this.contents = Parser.parseArray<ChipCloudChip>(data.contents, ChipCloudChip);
}
}
}
export default FeedFilterChipBar;

View File

@@ -1,7 +1,7 @@
import Parser from '..';
import { YTNode } from '../helpers';
export default class GameCard extends YTNode {
class GameCard extends YTNode {
static type = 'GameCard';
game;
@@ -10,4 +10,6 @@ export default class GameCard extends YTNode {
super();
this.game = Parser.parseItem(data.game);
}
}
}
export default GameCard;

View File

@@ -4,7 +4,7 @@ import Text from './misc/Text';
import Thumbnail from './misc/Thumbnail';
import NavigationEndpoint from './NavigationEndpoint';
export default class GameDetails extends YTNode {
class GameDetails extends YTNode {
static type = 'GameDetails';
title: Text;
@@ -21,4 +21,6 @@ export default class GameDetails extends YTNode {
this.endpoint = new NavigationEndpoint(data.endpoint);
this.is_official_box_art = data.isOfficialBoxArt;
}
}
}
export default GameDetails;

View File

@@ -4,7 +4,7 @@ import { YTNode } from '../helpers';
class Panel {
static type = 'Panel';
thumbnail: {
thumbnail?: {
image: {
url: string;
width: number;
@@ -43,13 +43,15 @@ class Panel {
};
constructor(data: any) {
this.thumbnail = {
image: data.thumbnail.image.sources,
endpoint: new NavigationEndpoint(data.thumbnail.onTap),
on_long_press_endpoint: new NavigationEndpoint(data.thumbnail.onLongPress),
content_mode: data.thumbnail.contentMode,
crop_options: data.thumbnail.cropOptions
};
if (data.thumbnail) {
this.thumbnail = {
image: data.thumbnail.image.sources,
endpoint: new NavigationEndpoint(data.thumbnail.onTap),
on_long_press_endpoint: new NavigationEndpoint(data.thumbnail.onLongPress),
content_mode: data.thumbnail.contentMode,
crop_options: data.thumbnail.cropOptions
};
}
this.background_image = {
image: data.backgroundImage.image.sources,

View File

@@ -1,5 +1,7 @@
import Parser from '../index';
import { YTNode } from '../helpers';
import SearchRefinementCard from './SearchRefinementCard';
import Button from './Button';
class HorizontalCardList extends YTNode {
static type = 'HorizontalCardList';
@@ -11,10 +13,10 @@ class HorizontalCardList extends YTNode {
constructor(data: any) {
super();
this.cards = Parser.parse(data.cards);
this.header = Parser.parse(data.header);
this.previous_button = Parser.parse(data.previousButton);
this.next_button = Parser.parse(data.nextButton);
this.cards = Parser.parseArray<SearchRefinementCard>(data.cards, SearchRefinementCard);
this.header = Parser.parseItem(data.header);
this.previous_button = Parser.parseItem<Button>(data.previousButton, Button);
this.next_button = Parser.parseItem<Button>(data.nextButton, Button);
}
}

View File

@@ -7,7 +7,7 @@ import SubscribeButton from './SubscribeButton';
import MetadataBadge from './MetadataBadge';
import Button from './Button';
export default class InteractiveTabbedHeader extends YTNode {
class InteractiveTabbedHeader extends YTNode {
static type = 'InteractiveTabbedHeader';
header_type: string;
@@ -33,4 +33,6 @@ export default class InteractiveTabbedHeader extends YTNode {
this.buttons = Parser.parseArray<SubscribeButton | Button>(data.buttons, [ SubscribeButton, Button ]);
this.auto_generated = new Text(data.autoGenerated);
}
}
}
export default InteractiveTabbedHeader;

View File

@@ -76,6 +76,8 @@ class NavigationEndpoint extends YTNode {
return '/browse';
case 'watchEndpoint':
return '/player';
case 'searchEndpoint':
return '/search';
case 'watchPlaylistEndpoint':
return '/next';
case 'liveChatItemContextMenuEndpoint':

View File

@@ -1,7 +1,7 @@
import { YTNode } from '../helpers';
import Thumbnail from './misc/Thumbnail';
export default class PlaylistCustomThumbnail extends YTNode {
class PlaylistCustomThumbnail extends YTNode {
static type = 'PlaylistCustomThumbnail';
thumbnail: Thumbnail[];
@@ -10,4 +10,6 @@ export default class PlaylistCustomThumbnail extends YTNode {
super();
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
}
}
}
export default PlaylistCustomThumbnail;

View File

@@ -5,7 +5,7 @@ import Button from './Button';
import Text from './misc/Text';
import Thumbnail from './misc/Thumbnail';
export default class RecognitionShelf extends YTNode {
class RecognitionShelf extends YTNode {
static type = 'RecognitionShelf';
title: Text;
@@ -23,4 +23,6 @@ export default class RecognitionShelf extends YTNode {
this.button = Parser.parseItem<Button>(data.button, Button);
this.surface = data.surface;
}
}
}
export default RecognitionShelf;

View File

@@ -15,6 +15,7 @@ class SectionList extends YTNode {
this.target_id = data.targetId;
}
// TODO: this should be Parser#parseArray
this.contents = Parser.parse(data.contents);
if (data.continuations) {

View File

@@ -20,14 +20,14 @@ class Shelf extends YTNode {
this.endpoint = new NavigationEndpoint(data.endpoint);
}
this.content = Parser.parse(data.content) || null;
this.content = Parser.parseItem(data.content) || null;
if (data.icon?.iconType) {
this.icon_type = data.icon?.iconType;
}
if (data.menu) {
this.menu = Parser.parse(data.menu);
this.menu = Parser.parseItem(data.menu);
}
}
}

View File

@@ -1,7 +1,7 @@
import { YTNode } from '../helpers';
import Thumbnail from './misc/Thumbnail';
export default class ThumbnailLandscapePortrait extends YTNode {
class ThumbnailLandscapePortrait extends YTNode {
static type = 'ThumbnailLandscapePortrait';
landscape: Thumbnail[];
@@ -12,4 +12,6 @@ export default class ThumbnailLandscapePortrait extends YTNode {
this.landscape = Thumbnail.fromResponse(data.landscape);
this.portrait = Thumbnail.fromResponse(data.portrait);
}
}
}
export default ThumbnailLandscapePortrait;

View File

@@ -6,7 +6,7 @@ import Thumbnail from './misc/Thumbnail';
import NavigationEndpoint from './NavigationEndpoint';
import SubscribeButton from './SubscribeButton';
export default class TopicChannelDetails extends YTNode {
class TopicChannelDetails extends YTNode {
static type = 'TopicChannelDetails';
title: Text;
@@ -24,4 +24,6 @@ export default class TopicChannelDetails extends YTNode {
this.subscribe_button = Parser.parseItem<SubscribeButton>(data.subscribeButton, SubscribeButton);
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
}
}
}
export default TopicChannelDetails;

View File

@@ -1,4 +1,5 @@
import Parser from '../index';
import Text from './misc/Text';
import { YTNode } from '../helpers';
class UniversalWatchCard extends YTNode {
@@ -7,13 +8,17 @@ class UniversalWatchCard extends YTNode {
header;
call_to_action;
sections;
collapsed_label?: Text;
constructor(data: any) {
super();
// TODO: use parseItem / parseArray for these
this.header = Parser.parse(data.header);
this.call_to_action = Parser.parse(data.callToAction);
this.sections = Parser.parse(data.sections);
this.header = Parser.parseItem(data.header);
this.call_to_action = Parser.parseItem(data.callToAction);
this.sections = Parser.parseArray(data.sections);
if (data.collapsedLabel) {
this.collapsed_label = new Text(data.collapsedLabel);
}
}
}

View File

@@ -13,7 +13,7 @@ class VerticalWatchCardList extends YTNode {
constructor(data: any) {
super();
this.items = Parser.parse(data.items);
this.items = Parser.parseArray(data.items);
this.contents = this.items; // XXX: alias for consistency
this.view_all_text = new Text(data.viewAllText);
this.view_all_endpoint = new NavigationEndpoint(data.viewAllEndpoint);

View File

@@ -1,9 +1,10 @@
import Parser from '../index';
import Parser from '..';
import Text from './misc/Text';
import Author from './misc/Author';
import Menu from './menus/Menu';
import Thumbnail from './misc/Thumbnail';
import NavigationEndpoint from './NavigationEndpoint';
import { timeToSeconds } from '../../utils/Utils';
import { YTNode } from '../helpers';
@@ -55,7 +56,7 @@ class Video extends YTNode {
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);
this.thumbnail_overlays = Parser.parseArray(data.thumbnailOverlays);
this.rich_thumbnail = data.richThumbnail ? Parser.parse(data.richThumbnail) : null;
this.rich_thumbnail = data.richThumbnail ? Parser.parseItem(data.richThumbnail) : null;
this.author = new Author(data.ownerText, data.ownerBadges, data.channelThumbnailSupportedRenderers?.channelThumbnailWithLinkRenderer?.thumbnail);
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
this.published = new Text(data.publishedTimeText);

View File

@@ -1,9 +1,11 @@
import Video from './Video';
export default class VideoCard extends Video {
class VideoCard extends Video {
static type = 'VideoCard';
constructor(data: any) {
super(data);
}
}
}
export default VideoCard;

View File

@@ -13,9 +13,9 @@ class WatchCardHeroVideo extends YTNode {
constructor(data: any) {
super();
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
this.call_to_action_button = Parser.parse(data.callToActionButton);
this.hero_image = Parser.parse(data.heroImage);
this.label = data.lengthText.accessibility.accessibilityData.label;
this.call_to_action_button = Parser.parseItem(data.callToActionButton);
this.hero_image = Parser.parseItem(data.heroImage);
this.label = data.lengthText?.accessibility.accessibilityData.label || '';
}
}

View File

@@ -8,7 +8,7 @@ class WatchCardSectionSequence extends YTNode {
constructor(data: any) {
super();
this.lists = Parser.parse(data.lists);
this.lists = Parser.parseArray(data.lists);
}
}

View File

@@ -1,4 +1,5 @@
import Player from '../../../core/Player';
import { InnertubeError } from '../../../utils/Utils';
class Format {
itag: string;
@@ -73,7 +74,8 @@ class Format {
* Decipher the streaming url of the format.
* @returns Deciphered URL.
*/
decipher(player: Player): string {
decipher(player: Player | undefined): string {
if (!player) throw new InnertubeError('Cannot decipher format, this session appears to have no valid player.');
return player.decipher(this.url, this.signature_cipher, this.cipher);
}
}

View File

@@ -10,8 +10,12 @@ import SubscribeButton from '../classes/SubscribeButton';
import Tab from '../classes/Tab';
import { InnertubeError } from '../../utils/Utils';
import FeedFilterChipBar from '../classes/FeedFilterChipBar';
import ChipCloudChip from '../classes/ChipCloudChip';
import FilterableFeed from '../../core/FilterableFeed';
import Feed from '../../core/Feed';
class Channel extends TabbedFeed {
export default class Channel extends TabbedFeed {
header;
metadata;
subscribe_button;
@@ -37,18 +41,56 @@ class Channel extends TabbedFeed {
this.current_tab = tab;
}
/**
* Applies given filter to the list.
* @param filter - The filter to apply
*/
async applyFilter(filter: string | ChipCloudChip) {
let target_filter: ChipCloudChip | undefined;
const filter_chipbar = this.memo.getType(FeedFilterChipBar)?.[0];
if (typeof filter === 'string') {
target_filter = filter_chipbar?.contents.get({ text: filter });
if (!target_filter)
throw new InnertubeError(`Filter ${filter} not found`, { available_filters: this.filters });
} else if (filter instanceof ChipCloudChip) {
target_filter = filter;
}
if (!target_filter)
throw new InnertubeError('Invalid filter', filter);
const page = await target_filter.endpoint?.call(this.actions, { parse: true });
return new FilteredChannelList(this.actions, page, true);
}
get filters(): string[] {
return this.memo.getType(FeedFilterChipBar)?.[0]?.contents.filterType(ChipCloudChip).map((chip) => chip.text) || [];
}
async getHome() {
const tab = await this.getTab('Home');
return new Channel(this.actions, tab.page, true);
}
async getVideos() {
const tab = await this.getTab('Videos');
return new Channel(this.actions, tab.page, true);
}
async getPlaylists() {
const tab = await this.getTab('Playlists');
async getShorts() {
const tab = await this.getTab('Shorts');
return new Channel(this.actions, tab.page, true);
}
async getHome() {
const tab = await this.getTab('Home');
async getLiveStreams() {
const tab = await this.getTab('Live');
return new Channel(this.actions, tab.page, true);
}
async getPlaylists() {
const tab = await this.getTab('Playlists');
return new Channel(this.actions, tab.page, true);
}
@@ -70,6 +112,74 @@ class Channel extends TabbedFeed {
const tab = await this.getTab('About');
return tab.memo.getType(ChannelAboutFullMetadata)?.[0];
}
/**
* Retrives list continuation.
*/
async getContinuation() {
const page = await super.getContinuationData();
return new ChannelListContinuation(this.actions, page, true);
}
}
export default Channel;
export class ChannelListContinuation extends Feed {
contents;
constructor(actions: Actions, data: any, already_parsed = false) {
super(actions, data, already_parsed);
this.contents =
this.page.on_response_received_actions?.[0] ||
this.page.on_response_received_endpoints?.[0];
}
/**
* Retrieves list continuation.
*/
async getContinuation() {
const page = await super.getContinuationData();
return new ChannelListContinuation(this.actions, page, true);
}
}
export class FilteredChannelList extends FilterableFeed {
applied_filter: ChipCloudChip | undefined;
contents;
constructor(actions: Actions, data: any, already_parsed = false) {
super(actions, data, already_parsed);
this.applied_filter = this.memo.getType(ChipCloudChip).get({ is_selected: true });
// Removes the filter chipbar from the actions list
if (
this.page.on_response_received_actions &&
this.page.on_response_received_actions.length > 1
) {
this.page.on_response_received_actions.shift();
}
this.contents = this.page.on_response_received_actions?.[0];
}
/**
* Applies given filter to the list.
* @param filter - The filter to apply
*/
async applyFilter(filter: string | ChipCloudChip) {
const feed = await super.getFilteredFeed(filter);
return new FilteredChannelList(this.actions, feed.page, true);
}
/**
* Retrieves list continuation.
*/
async getContinuation() {
const page = await super.getContinuationData();
// Keep the filters
page?.on_response_received_actions_memo.set('FeedFilterChipBar', this.memo.getType(FeedFilterChipBar));
page?.on_response_received_actions_memo.set('ChipCloudChip', this.memo.getType(ChipCloudChip));
return new FilteredChannelList(this.actions, page, true);
}
}

View File

@@ -39,10 +39,10 @@ class Library {
}
async #getAll(shelf: Shelf): Promise<Playlist | History | Feed> {
if (!shelf.menu?.item().as(Menu).hasKey('top_level_buttons'))
if (!shelf.menu?.as(Menu).hasKey('top_level_buttons'))
throw new InnertubeError(`The ${shelf.title.text} shelf doesn't have more items`);
const button = shelf.menu.item().as(Menu).top_level_buttons.get({ text: 'See all' });
const button = shelf.menu.as(Menu).top_level_buttons.get({ text: 'See all' });
if (!button)
throw new InnertubeError('Did not find target button.');

View File

@@ -1,19 +1,15 @@
import Actions from '../../core/Actions';
import { observe, ObservedArray, YTNode } from '../helpers';
import { ObservedArray, YTNode } from '../helpers';
import { InnertubeError } from '../../utils/Utils';
import Feed from '../../core/Feed';
import SectionList from '../classes/SectionList';
import ItemSection from '../classes/ItemSection';
import HorizontalCardList from '../classes/HorizontalCardList';
import RichListHeader from '../classes/RichListHeader';
import SearchRefinementCard from '../classes/SearchRefinementCard';
import TwoColumnSearchResults from '../classes/TwoColumnSearchResults';
import UniversalWatchCard from '../classes/UniversalWatchCard';
import WatchCardHeroVideo from '../classes/WatchCardHeroVideo';
import WatchCardSectionSequence from '../classes/WatchCardSectionSequence';
class Search extends Feed {
export default class Search extends Feed {
results: ObservedArray<YTNode> | null | undefined;
refinements;
estimated_results;
@@ -24,30 +20,16 @@ class Search extends Feed {
super(actions, data, already_parsed);
const contents =
this.page.contents?.item().as(TwoColumnSearchResults).primary_contents?.item().as(SectionList).contents.array() ||
this.page.contents_memo.getType(SectionList)?.[0]?.contents?.array() ||
this.page.on_response_received_commands?.[0].contents;
const secondary_contents_maybe = this.page.contents?.item().key('secondary_contents');
const secondary_contents = secondary_contents_maybe?.isParsed() ? secondary_contents_maybe.parsed().item().key('contents').parsed().array() : undefined;
this.results = contents.firstOfType(ItemSection)?.contents;
const card_list = this.results?.get({ type: 'HorizontalCardList' }, true)?.as(HorizontalCardList);
const universal_watch_card = secondary_contents?.firstOfType(UniversalWatchCard);
this.refinements = this.page.refinements || [];
this.estimated_results = this.page.estimated_results;
this.watch_card = {
header: universal_watch_card?.header.item() || null,
call_to_action: universal_watch_card?.call_to_action.item().as(WatchCardHeroVideo) || null,
sections: universal_watch_card?.sections.array().filterType(WatchCardSectionSequence) || []
};
this.refinement_cards = {
header: card_list?.header.item().as(RichListHeader) || null,
cards: card_list?.cards.array().filterType(SearchRefinementCard) || observe([] as SearchRefinementCard[])
};
this.watch_card = this.page?.contents_memo.getType(UniversalWatchCard)?.[0];
this.refinement_cards = this.results?.get({ type: 'HorizontalCardList' }, true)?.as(HorizontalCardList);
}
/**
@@ -57,7 +39,8 @@ class Search extends Feed {
let target_card: SearchRefinementCard | undefined;
if (typeof card === 'string') {
target_card = this.refinement_cards.cards.get({ query: card });
if (!this.refinement_cards) throw new InnertubeError('No refinement cards found.');
target_card = this.refinement_cards?.cards.get({ query: card });
if (!target_card)
throw new InnertubeError(`Refinement card "${card}" not found`, { available_cards: this.refinement_card_queries });
} else if (card.type === 'SearchRefinementCard') {
@@ -71,8 +54,11 @@ class Search extends Feed {
return new Search(this.actions, page, true);
}
/**
* Returns a list of refinement card queries.
*/
get refinement_card_queries() {
return this.refinement_cards.cards.map((card) => card.query);
return this.refinement_cards?.cards.map((card) => card.query);
}
/**
@@ -82,6 +68,4 @@ class Search extends Feed {
const continuation = await this.getContinuationData();
return new Search(this.actions, continuation, true);
}
}
export default Search;
}

View File

@@ -92,7 +92,7 @@ class VideoInfo {
* @param data - API response.
* @param cpn - Client Playback Nonce
*/
constructor(data: [ApiResponse, ApiResponse?], actions: Actions, player: Player, cpn: string) {
constructor(data: [ApiResponse, ApiResponse?], actions: Actions, player?: Player, cpn?: string) {
this.#actions = actions;
this.#player = player;
this.#cpn = cpn;
@@ -492,7 +492,7 @@ class VideoInfo {
throw new InnertubeError('Index and init ranges not available', { format });
const url = new URL(format.decipher(this.#player));
url.searchParams.set('cpn', this.#cpn);
url.searchParams.set('cpn', this.#cpn || '');
set.appendChild(this.#el(document, 'Representation', {
id: format.itag,
@@ -522,7 +522,7 @@ class VideoInfo {
throw new InnertubeError('Index and init ranges not available', { format });
const url = new URL(format.decipher(this.#player));
url.searchParams.set('cpn', this.#cpn);
url.searchParams.set('cpn', this.#cpn || '');
set.appendChild(this.#el(document, 'Representation', {
id: format.itag,

View File

@@ -48,7 +48,7 @@ export const CLIENTS = Object.freeze({
},
YTMUSIC_ANDROID: {
NAME: 'ANDROID_MUSIC',
VERSION: '5.17.51'
VERSION: '5.34.51'
},
TV_EMBEDDED: {
NAME: 'TVHTML5_SIMPLY_EMBEDDED_PLAYER',

View File

@@ -11,4 +11,11 @@ export const VIDEOS = [
ID: 'I1qsF0WQy8c',
QUERY: 'mkbhd',
}
];
export const CHANNELS = [
{
ID: 'UC_x5XG1OV2P6uZZ5FSM9Ttw',
NAME: 'Linus Tech Tips'
}
];

View File

@@ -1,6 +1,6 @@
import fs from 'fs';
import Innertube from '..';
import { VIDEOS } from './constants';
import { CHANNELS, VIDEOS } from './constants';
import { streamToIterable } from '../src/utils/Utils';
describe('YouTube.js Tests', () => {
@@ -90,6 +90,18 @@ describe('YouTube.js Tests', () => {
expect(playlist.items.length).toBeLessThanOrEqual(100);
});
it('should retrieve channel', async () => {
const channel = await yt.getChannel(CHANNELS[0].ID);
expect(channel.videos.length).toBeGreaterThan(0);
expect(channel.shelves.length).toBeGreaterThan(0);
const videos_tab = await channel.getVideos();
expect(videos_tab.videos.length).toBeGreaterThan(0);
const filtered_list = await videos_tab.applyFilter('Popular');
expect(filtered_list.videos.length).toBeGreaterThan(0);
});
it('should retrieve home feed', async () => {
const homefeed = await yt.getHomeFeed();
expect(homefeed.header).toBeDefined();