mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-13 09:32:12 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac9341c769 | ||
|
|
cac762569a | ||
|
|
9978ebf085 | ||
|
|
b036e2fcdc | ||
|
|
e37f42f41b | ||
|
|
883a023624 | ||
|
|
506834b253 | ||
|
|
87e7ef77eb | ||
|
|
27fdd8268a | ||
|
|
d4ea87b8b0 | ||
|
|
ec87eea20d | ||
|
|
e43ad202f4 | ||
|
|
104c36b450 | ||
|
|
f5d61d70f2 |
99
README.md
99
README.md
@@ -12,12 +12,10 @@
|
||||
[discord]: https://discord.gg/syDu7Yks54
|
||||
[nodejs]: https://nodejs.org
|
||||
|
||||
<!-- INTRODUCTION -->
|
||||
<h1 align=center>YouTube.js</h1>
|
||||
|
||||
<p align=center>A full-featured wrapper around the InnerTube API, which is what YouTube itself uses.</p>
|
||||
<p align=center>A full-featured wrapper around the InnerTube API, which is what YouTube itself uses</p>
|
||||
|
||||
<!-- BADGES -->
|
||||
<div align="center">
|
||||
|
||||
[][actions]
|
||||
@@ -31,8 +29,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SPONSORS -->
|
||||
|
||||
<p align="center">
|
||||
<a><sub>Special thanks to:<sub></a>
|
||||
</p>
|
||||
@@ -57,7 +53,6 @@
|
||||
|
||||
___
|
||||
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
<details>
|
||||
<summary>Table of Contents</summary>
|
||||
<ol>
|
||||
@@ -79,23 +74,20 @@ ___
|
||||
<li><a href="#api">API</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#implementing-custom-functionality">Implementing custom functionality </a></li>
|
||||
<li><a href="#extending-the-library">Extending the library</a></li>
|
||||
<li><a href="#contributing">Contributing</a></li>
|
||||
<li><a href="#contributors">Contributors</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
<li><a href="#disclaimer">Disclaimer</a></li>
|
||||
<li><a href="#license">License</a></li>
|
||||
</ol>
|
||||
</details>
|
||||
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
## 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.
|
||||
InnerTube is an API used across all YouTube clients. It was created to simplify the deployment of new features and experiments across the platform[^1]. This library handles all the low-level communication with InnerTube, providing a simple, and efficient way to interact with YouTube programmatically. It is designed to emulate an actual client as closely as possible, including how API responses are parsed.
|
||||
|
||||
If you have any questions or need help, feel free to contact us on our chat server [here](https://discord.gg/syDu7Yks54).
|
||||
If you have any questions or need help, feel free to reach out to us on our [Discord server][discord] or open an issue [here](https://github.com/LuanRT/YouTube.js/issues).
|
||||
|
||||
<!-- GETTING STARTED -->
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
@@ -122,7 +114,6 @@ npm install github:LuanRT/YouTube.js
|
||||
|
||||
**TODO:** Deno install instructions (esm.sh possibly?)
|
||||
|
||||
<!-- USAGE -->
|
||||
## Usage
|
||||
Create an InnerTube instance:
|
||||
```ts
|
||||
@@ -581,48 +572,60 @@ Utility to call navigation endpoints.
|
||||
| --- | --- | --- |
|
||||
| endpoint | `NavigationEndpoint` | The target endpoint |
|
||||
| args? | `object` | Additional payload arguments |
|
||||
|
||||
## Extending the library
|
||||
|
||||
## Implementing custom functionality
|
||||
YouTube.js is completely modular and easy to extend. Almost all methods, classes, and utilities used internally are exposed and can be used to implement your own extensions without having to modify the library's source code.
|
||||
|
||||
Something cool about YouTube.js is that it is completely modular and easy to tinker with. Almost all methods, classes, and utilities used internally are exposed and can be used to implement your own extensions without having to modify the library's source code.
|
||||
|
||||
For example, you may want to call an endpoint directly, that can be achieved with the `Actions` class:
|
||||
For example, let's say we want to implement a method to retrieve video info manually. We can do that by using an instance of the `Actions` class:
|
||||
|
||||
```ts
|
||||
// ...
|
||||
import { Innertube } from 'youtubei.js';
|
||||
|
||||
const payload = {
|
||||
// ...
|
||||
videoId: 'jLTOuvBTLxA',
|
||||
client: 'YTMUSIC', // InnerTube client, can be ANDROID, YTMUSIC, YTMUSIC_ANDROID, WEB or TV_EMBEDDED
|
||||
parse: true // tells YouTube.js to parse the response, this is not sent to InnerTube.
|
||||
};
|
||||
(async () => {
|
||||
const yt = await Innertube.create();
|
||||
|
||||
const response = await yt.actions.execute('/player', payload);
|
||||
async function getVideoInfo(videoId: string) {
|
||||
const videoInfo = await yt.actions.execute('/player', {
|
||||
// anything added here will be merged with the default payload and sent to InnerTube.
|
||||
videoId,
|
||||
client: 'YTMUSIC', // InnerTube client, can be ANDROID, YTMUSIC, YTMUSIC_ANDROID, WEB or TV_EMBEDDED
|
||||
parse: true // tells YouTube.js to parse the response, this is not sent to InnerTube.
|
||||
});
|
||||
|
||||
console.info(response);
|
||||
return videoInfo;
|
||||
}
|
||||
|
||||
const videoInfo = await getVideoInfo('jLTOuvBTLxA');
|
||||
console.info(videoInfo);
|
||||
})();
|
||||
```
|
||||
|
||||
Or maybe there's an interesting `NavigationEndpoint` in a parsed response and we want to call it to see what happens:
|
||||
Or perhaps there's a `NavigationEndpoint` in a parsed response and we want to call it to see what happens:
|
||||
|
||||
```ts
|
||||
// ...
|
||||
const artist = await yt.music.getArtist('UC52ZqHVQz5OoGhvbWiRal6g');
|
||||
const albums = artist.sections[1].as(YTNodes.MusicCarouselShelf);
|
||||
import { Innertube, YTNodes } from 'youtubei.js';
|
||||
|
||||
// Say we have a button and want to “click” it
|
||||
const button = albums.as(YTNodes.MusicCarouselShelf).header?.more_content;
|
||||
|
||||
if (button) {
|
||||
// To do that, we can call its navigation endpoint:
|
||||
const page = await button.endpoint.call(yt.actions, { parse: true, client: 'YTMUSIC' });
|
||||
console.info(page);
|
||||
}
|
||||
(async () => {
|
||||
const yt = await Innertube.create();
|
||||
|
||||
const artist = await yt.music.getArtist('UC52ZqHVQz5OoGhvbWiRal6g');
|
||||
const albums = artist.sections[1].as(YTNodes.MusicCarouselShelf);
|
||||
|
||||
// Say we want to click the “More” button:
|
||||
const button = albums.as(YTNodes.MusicCarouselShelf).header?.more_content;
|
||||
|
||||
if (button) {
|
||||
// After making sure it exists, we can call its navigation endpoint:
|
||||
const page = await button.endpoint.call(yt.actions);
|
||||
console.info(page);
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
### Parser
|
||||
|
||||
If you're working on an extension for the library or just want to have nicely typed and sanitized InnerTube responses for a project then have a look at our powerful parser!
|
||||
YouTube.js' parser allows you to parse InnerTube responses and turn their nodes into strongly typed objects that can be easily manipulated. It also provides a set of utility methods that make working with InnerTube much easier.
|
||||
|
||||
Example:
|
||||
```ts
|
||||
@@ -640,10 +643,12 @@ const header = page.header?.item().as(YTNodes.MusicImmersiveHeader, YTNodes.Musi
|
||||
|
||||
console.info('Header:', header);
|
||||
|
||||
// The parser encapsulates all arrays in a proxy object.
|
||||
// A proxy intercepts access to the actual data, allowing
|
||||
// the parser to add type safety and many utility methods
|
||||
// that make working with InnerTube much easier.
|
||||
/**
|
||||
* The parser encapsulates all arrays in a proxy object.
|
||||
* A proxy intercepts access to the actual data, allowing
|
||||
* the parser to add type safety and many utility methods
|
||||
* that make working with InnerTube much easier.
|
||||
*/
|
||||
const tab = page.contents.item().as(YTNodes.SingleColumnBrowseResults).tabs.firstOfType(YTNodes.Tab);
|
||||
|
||||
|
||||
@@ -658,20 +663,18 @@ const sections = tab.content?.as(YTNodes.SectionList).contents.array().as(YTNode
|
||||
console.info('Sections:', sections);
|
||||
```
|
||||
|
||||
Detailed documentation can be found [here](https://github.com/LuanRT/YouTube.js/blob/main/src/parser).
|
||||
Documentation for the parser can be found [here](https://github.com/LuanRT/YouTube.js/blob/main/src/parser).
|
||||
|
||||
<!-- CONTRIBUTING -->
|
||||
## Contributing
|
||||
Contributions, issues, and feature requests are welcome.
|
||||
Feel free to check the [issues page](https://github.com/LuanRT/YouTube.js/issues) and our [guidelines](https://github.com/LuanRT/YouTube.js/blob/main/CONTRIBUTING.md) if you want to contribute.
|
||||
|
||||
<!-- CONTRIBUTORS -->
|
||||
## Contributors
|
||||
Thank you to all the wonderful people who have contributed to this project:
|
||||
<a href="https://github.com/LuanRT/YouTube.js/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=LuanRT/YouTube.js" />
|
||||
</a>
|
||||
|
||||
<!-- CONTACT -->
|
||||
## Contact
|
||||
|
||||
LuanRT - [@thesciencephile][twitter] - luan.lrt4@gmail.com
|
||||
@@ -684,10 +687,8 @@ All trademarks, logos, and brand names are the property of their respective owne
|
||||
|
||||
Should you have any questions or concerns please contact me directly via email.
|
||||
|
||||
<!-- Footnotes -->
|
||||
[^1]: https://gizmodo.com/how-project-innertube-helped-pull-youtube-out-of-the-gu-1704946491
|
||||
|
||||
<!-- LICENSE -->
|
||||
## License
|
||||
Distributed under the [MIT](https://choosealicense.com/licenses/mit/) License.
|
||||
|
||||
|
||||
@@ -4,42 +4,42 @@ import { streamToIterable } from 'youtubei.js/dist/src/utils/Utils';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache() });
|
||||
|
||||
|
||||
const search = await yt.music.search('No Copyright Background Music', { type: 'album' });
|
||||
|
||||
|
||||
if (!search.results)
|
||||
throw new Error('Filter "type" must be used');
|
||||
|
||||
|
||||
const album = await yt.music.getAlbum(search.results[0].id as string);
|
||||
|
||||
|
||||
if (!album.contents)
|
||||
throw new Error('Album appears to be empty');
|
||||
|
||||
console.info(`Album "${album.header.title.toString()}" by ${album.header.author?.name}`, '\n');
|
||||
|
||||
|
||||
console.info(`Album "${album.header?.title.toString()}" by ${album.header?.author?.name}`, '\n');
|
||||
|
||||
for (const song of album.contents) {
|
||||
const stream = await yt.download(song.id as string, {
|
||||
type: 'audio', // audio, video or audio+video
|
||||
quality: 'best', // best, bestefficiency, 144p, 240p, 480p, 720p and so on.
|
||||
format: 'mp4' // media container format
|
||||
});
|
||||
|
||||
|
||||
console.info(`Downloading ${song.title} (${song.id})`);
|
||||
|
||||
const dir = `./${album.header.title.toString()}`;
|
||||
|
||||
|
||||
const dir = `./${album.header?.title.toString()}`;
|
||||
|
||||
if (!existsSync(dir)) {
|
||||
mkdirSync(dir);
|
||||
}
|
||||
|
||||
|
||||
const file = createWriteStream(`${dir}/${song.title?.replace(/\//g, '')}.m4a`);
|
||||
|
||||
|
||||
for await (const chunk of streamToIterable(stream)) {
|
||||
file.write(chunk);
|
||||
}
|
||||
|
||||
|
||||
console.info(`${song.id} - Done!`, '\n');
|
||||
}
|
||||
|
||||
console.info(`Downloaded ${album.header.song_count}!`);
|
||||
|
||||
console.info(`Downloaded ${album.header?.song_count}!`);
|
||||
})();
|
||||
412
package-lock.json
generated
412
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "2.5.1",
|
||||
"version": "2.6.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "youtubei.js",
|
||||
"version": "2.5.1",
|
||||
"version": "2.6.0",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/LuanRT"
|
||||
],
|
||||
@@ -58,30 +58,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz",
|
||||
"integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
|
||||
"integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz",
|
||||
"integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
|
||||
"integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.1.0",
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/generator": "^7.20.2",
|
||||
"@babel/generator": "^7.20.5",
|
||||
"@babel/helper-compilation-targets": "^7.20.0",
|
||||
"@babel/helper-module-transforms": "^7.20.2",
|
||||
"@babel/helpers": "^7.20.1",
|
||||
"@babel/parser": "^7.20.2",
|
||||
"@babel/helpers": "^7.20.5",
|
||||
"@babel/parser": "^7.20.5",
|
||||
"@babel/template": "^7.18.10",
|
||||
"@babel/traverse": "^7.20.1",
|
||||
"@babel/types": "^7.20.2",
|
||||
"@babel/traverse": "^7.20.5",
|
||||
"@babel/types": "^7.20.5",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
@@ -106,12 +106,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz",
|
||||
"integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz",
|
||||
"integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.20.2",
|
||||
"@babel/types": "^7.20.5",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
@@ -286,14 +286,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz",
|
||||
"integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==",
|
||||
"version": "7.20.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
|
||||
"integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.18.10",
|
||||
"@babel/traverse": "^7.20.1",
|
||||
"@babel/types": "^7.20.0"
|
||||
"@babel/traverse": "^7.20.5",
|
||||
"@babel/types": "^7.20.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -385,9 +385,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.20.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz",
|
||||
"integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
|
||||
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -573,19 +573,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz",
|
||||
"integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz",
|
||||
"integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/generator": "^7.20.1",
|
||||
"@babel/generator": "^7.20.5",
|
||||
"@babel/helper-environment-visitor": "^7.18.9",
|
||||
"@babel/helper-function-name": "^7.19.0",
|
||||
"@babel/helper-hoist-variables": "^7.18.6",
|
||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
||||
"@babel/parser": "^7.20.1",
|
||||
"@babel/types": "^7.20.0",
|
||||
"@babel/parser": "^7.20.5",
|
||||
"@babel/types": "^7.20.5",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -603,9 +603,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz",
|
||||
"integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz",
|
||||
"integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.19.4",
|
||||
@@ -1284,9 +1284,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sinonjs/commons": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz",
|
||||
"integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==",
|
||||
"version": "1.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
|
||||
"integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"type-detect": "4.0.8"
|
||||
@@ -1334,9 +1334,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__traverse": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz",
|
||||
"integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==",
|
||||
"version": "7.18.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz",
|
||||
"integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.3.0"
|
||||
@@ -1416,9 +1416,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.14.tgz",
|
||||
"integrity": "sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==",
|
||||
"version": "17.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz",
|
||||
"integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/yargs-parser": "*"
|
||||
@@ -1431,14 +1431,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
|
||||
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz",
|
||||
"integrity": "sha512-QrZqaIOzJAjv0sfjY4EjbXUi3ZOFpKfzntx22gPGr9pmFcTjcFw/1sS1LJhEubfAGwuLjNrPV0rH+D1/XZFy7Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/type-utils": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"@typescript-eslint/scope-manager": "5.46.0",
|
||||
"@typescript-eslint/type-utils": "5.46.0",
|
||||
"@typescript-eslint/utils": "5.46.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.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
|
||||
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz",
|
||||
"integrity": "sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/scope-manager": "5.46.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/typescript-estree": "5.46.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1491,13 +1491,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
|
||||
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz",
|
||||
"integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0"
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/visitor-keys": "5.46.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -1508,13 +1508,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"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==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.0.tgz",
|
||||
"integrity": "sha512-dwv4nimVIAsVS2dTA0MekkWaRnoYNXY26dKz8AN5W3cBFYwYGFQEqm/cG+TOoooKlncJS4RTbFKgcFY/pOiBCg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.46.0",
|
||||
"@typescript-eslint/utils": "5.46.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -1535,9 +1535,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
|
||||
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz",
|
||||
"integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==",
|
||||
"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.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
|
||||
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz",
|
||||
"integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/visitor-keys": "5.46.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.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
|
||||
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.0.tgz",
|
||||
"integrity": "sha512-4O+Ps1CRDw+D+R40JYh5GlKLQERXRKW5yIQoNDpmXPJ+C7kaPF9R7GWl+PxGgXjB3PQCqsaaZUpZ9dG4U6DO7g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/scope-manager": "5.46.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/typescript-estree": "5.46.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.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
|
||||
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz",
|
||||
"integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1941,9 +1941,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001434",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
|
||||
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
|
||||
"version": "1.0.30001439",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz",
|
||||
"integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2654,9 +2654,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
|
||||
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
|
||||
"version": "8.29.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz",
|
||||
"integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint/eslintrc": "^1.3.3",
|
||||
@@ -2975,9 +2975,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
|
||||
"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz",
|
||||
"integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
@@ -3157,9 +3157,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
|
||||
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz",
|
||||
"integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -3270,9 +3270,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
|
||||
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
@@ -5314,9 +5314,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
||||
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -5332,9 +5332,9 @@
|
||||
"integrity": "sha512-o0QVGuFg24FK765Qdd5kk0zU/U4dEsCtN/GSiwNI9i8xsSVtjIAOdTaVhLwZ1nrbWxFVMxNDDl+9fednsOMsBw=="
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.12.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.12.0.tgz",
|
||||
"integrity": "sha512-zMLamCG62PGjd9HHMpo05bSLvvwWOZgGeiWlN/vlqu3+lRo3elxktVGEyLMX+IO7c2eflLjcW74AlkhEZm15mg==",
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz",
|
||||
"integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==",
|
||||
"dependencies": {
|
||||
"busboy": "^1.6.0"
|
||||
},
|
||||
@@ -5536,27 +5536,27 @@
|
||||
}
|
||||
},
|
||||
"@babel/compat-data": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz",
|
||||
"integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
|
||||
"integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/core": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz",
|
||||
"integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
|
||||
"integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ampproject/remapping": "^2.1.0",
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/generator": "^7.20.2",
|
||||
"@babel/generator": "^7.20.5",
|
||||
"@babel/helper-compilation-targets": "^7.20.0",
|
||||
"@babel/helper-module-transforms": "^7.20.2",
|
||||
"@babel/helpers": "^7.20.1",
|
||||
"@babel/parser": "^7.20.2",
|
||||
"@babel/helpers": "^7.20.5",
|
||||
"@babel/parser": "^7.20.5",
|
||||
"@babel/template": "^7.18.10",
|
||||
"@babel/traverse": "^7.20.1",
|
||||
"@babel/types": "^7.20.2",
|
||||
"@babel/traverse": "^7.20.5",
|
||||
"@babel/types": "^7.20.5",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
@@ -5573,12 +5573,12 @@
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz",
|
||||
"integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz",
|
||||
"integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.20.2",
|
||||
"@babel/types": "^7.20.5",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
@@ -5709,14 +5709,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helpers": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz",
|
||||
"integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==",
|
||||
"version": "7.20.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
|
||||
"integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/template": "^7.18.10",
|
||||
"@babel/traverse": "^7.20.1",
|
||||
"@babel/types": "^7.20.0"
|
||||
"@babel/traverse": "^7.20.5",
|
||||
"@babel/types": "^7.20.5"
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
@@ -5789,9 +5789,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.20.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz",
|
||||
"integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
|
||||
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/plugin-syntax-async-generators": {
|
||||
@@ -5923,19 +5923,19 @@
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.20.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz",
|
||||
"integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz",
|
||||
"integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/generator": "^7.20.1",
|
||||
"@babel/generator": "^7.20.5",
|
||||
"@babel/helper-environment-visitor": "^7.18.9",
|
||||
"@babel/helper-function-name": "^7.19.0",
|
||||
"@babel/helper-hoist-variables": "^7.18.6",
|
||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
||||
"@babel/parser": "^7.20.1",
|
||||
"@babel/types": "^7.20.0",
|
||||
"@babel/parser": "^7.20.5",
|
||||
"@babel/types": "^7.20.5",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -5949,9 +5949,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz",
|
||||
"integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==",
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz",
|
||||
"integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-string-parser": "^7.19.4",
|
||||
@@ -6480,9 +6480,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz",
|
||||
"integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==",
|
||||
"version": "1.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
|
||||
"integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-detect": "4.0.8"
|
||||
@@ -6530,9 +6530,9 @@
|
||||
}
|
||||
},
|
||||
"@types/babel__traverse": {
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz",
|
||||
"integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==",
|
||||
"version": "7.18.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz",
|
||||
"integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.3.0"
|
||||
@@ -6612,9 +6612,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "17.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.14.tgz",
|
||||
"integrity": "sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==",
|
||||
"version": "17.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz",
|
||||
"integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/yargs-parser": "*"
|
||||
@@ -6627,14 +6627,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
|
||||
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.0.tgz",
|
||||
"integrity": "sha512-QrZqaIOzJAjv0sfjY4EjbXUi3ZOFpKfzntx22gPGr9pmFcTjcFw/1sS1LJhEubfAGwuLjNrPV0rH+D1/XZFy7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/type-utils": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"@typescript-eslint/scope-manager": "5.46.0",
|
||||
"@typescript-eslint/type-utils": "5.46.0",
|
||||
"@typescript-eslint/utils": "5.46.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -6644,53 +6644,53 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
|
||||
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz",
|
||||
"integrity": "sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/scope-manager": "5.46.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/typescript-estree": "5.46.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
|
||||
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.0.tgz",
|
||||
"integrity": "sha512-7wWBq9d/GbPiIM6SqPK9tfynNxVbfpihoY5cSFMer19OYUA3l4powA2uv0AV2eAZV6KoAh6lkzxv4PoxOLh1oA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0"
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/visitor-keys": "5.46.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"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==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.0.tgz",
|
||||
"integrity": "sha512-dwv4nimVIAsVS2dTA0MekkWaRnoYNXY26dKz8AN5W3cBFYwYGFQEqm/cG+TOoooKlncJS4RTbFKgcFY/pOiBCg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.46.0",
|
||||
"@typescript-eslint/utils": "5.46.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
|
||||
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.0.tgz",
|
||||
"integrity": "sha512-wHWgQHFB+qh6bu0IAPAJCdeCdI0wwzZnnWThlmHNY01XJ9Z97oKqKOzWYpR2I83QmshhQJl6LDM9TqMiMwJBTw==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"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==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.0.tgz",
|
||||
"integrity": "sha512-kDLNn/tQP+Yp8Ro2dUpyyVV0Ksn2rmpPpB0/3MO874RNmXtypMwSeazjEN/Q6CTp8D7ExXAAekPEcCEB/vtJkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/visitor-keys": "5.46.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -6699,28 +6699,28 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
|
||||
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.0.tgz",
|
||||
"integrity": "sha512-4O+Ps1CRDw+D+R40JYh5GlKLQERXRKW5yIQoNDpmXPJ+C7kaPF9R7GWl+PxGgXjB3PQCqsaaZUpZ9dG4U6DO7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/scope-manager": "5.46.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"@typescript-eslint/typescript-estree": "5.46.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"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==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.0.tgz",
|
||||
"integrity": "sha512-E13gBoIXmaNhwjipuvQg1ByqSAu/GbEpP/qzFihugJ+MomtoJtFAJG/+2DRPByf57B863m0/q7Zt16V9ohhANw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/types": "5.46.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
@@ -6959,9 +6959,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001434",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
|
||||
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
|
||||
"version": "1.0.30001439",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz",
|
||||
"integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
@@ -7379,9 +7379,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
|
||||
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
|
||||
"version": "8.29.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz",
|
||||
"integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.3.3",
|
||||
@@ -7628,9 +7628,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"fastq": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
|
||||
"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz",
|
||||
"integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"reusify": "^1.0.4"
|
||||
@@ -7755,9 +7755,9 @@
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
|
||||
"integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz",
|
||||
"integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -7848,9 +7848,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||
"integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
|
||||
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
|
||||
"dev": true
|
||||
},
|
||||
"import-fresh": {
|
||||
@@ -9349,9 +9349,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
||||
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true
|
||||
},
|
||||
"uhyphen": {
|
||||
@@ -9360,9 +9360,9 @@
|
||||
"integrity": "sha512-o0QVGuFg24FK765Qdd5kk0zU/U4dEsCtN/GSiwNI9i8xsSVtjIAOdTaVhLwZ1nrbWxFVMxNDDl+9fednsOMsBw=="
|
||||
},
|
||||
"undici": {
|
||||
"version": "5.12.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.12.0.tgz",
|
||||
"integrity": "sha512-zMLamCG62PGjd9HHMpo05bSLvvwWOZgGeiWlN/vlqu3+lRo3elxktVGEyLMX+IO7c2eflLjcW74AlkhEZm15mg==",
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz",
|
||||
"integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==",
|
||||
"requires": {
|
||||
"busboy": "^1.6.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "2.5.1",
|
||||
"version": "2.6.0",
|
||||
"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",
|
||||
|
||||
@@ -11,9 +11,6 @@ import Playlist from '../parser/ytmusic/Playlist';
|
||||
import Recap from '../parser/ytmusic/Recap';
|
||||
|
||||
import Tab from '../parser/classes/Tab';
|
||||
import Tabbed from '../parser/classes/Tabbed';
|
||||
import SingleColumnMusicWatchNextResults from '../parser/classes/SingleColumnMusicWatchNextResults';
|
||||
import WatchNextTabbedResults from '../parser/classes/WatchNextTabbedResults';
|
||||
import SectionList from '../parser/classes/SectionList';
|
||||
|
||||
import Message from '../parser/classes/Message';
|
||||
@@ -235,13 +232,9 @@ class Music {
|
||||
parse: true
|
||||
});
|
||||
|
||||
const tabs = data.contents.item()
|
||||
.as(SingleColumnMusicWatchNextResults).contents.item()
|
||||
.as(Tabbed).contents.item()
|
||||
.as(WatchNextTabbedResults)
|
||||
.tabs.array().as(Tab);
|
||||
const tabs = data.contents_memo.getType(Tab);
|
||||
|
||||
const tab = tabs.get({ title: 'Up next' });
|
||||
const tab = tabs?.[0];
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
@@ -287,20 +280,16 @@ class Music {
|
||||
parse: true
|
||||
});
|
||||
|
||||
const tabs = data.contents.item()
|
||||
.as(SingleColumnMusicWatchNextResults).contents.item()
|
||||
.as(Tabbed).contents.item()
|
||||
.as(WatchNextTabbedResults)
|
||||
.tabs.array().as(Tab);
|
||||
const tabs = data.contents_memo.getType(Tab);
|
||||
|
||||
const tab = tabs.get({ title: 'Related' });
|
||||
const tab = tabs?.matchCondition((tab) => tab.endpoint.payload.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType === 'MUSIC_PAGE_TYPE_TRACK_RELATED');
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
|
||||
const page = await tab.endpoint.call(this.#actions, { client: 'YTMUSIC', parse: true });
|
||||
|
||||
const shelves = page.contents.item().as(SectionList).contents.array().as(MusicCarouselShelf, MusicDescriptionShelf);
|
||||
const shelves = page.contents.item().as(SectionList).contents.as(MusicCarouselShelf, MusicDescriptionShelf);
|
||||
|
||||
return shelves;
|
||||
}
|
||||
@@ -318,13 +307,9 @@ class Music {
|
||||
parse: true
|
||||
});
|
||||
|
||||
const tabs = data.contents.item()
|
||||
.as(SingleColumnMusicWatchNextResults).contents.item()
|
||||
.as(Tabbed).contents.item()
|
||||
.as(WatchNextTabbedResults)
|
||||
.tabs.array().as(Tab);
|
||||
const tabs = data.contents_memo.getType(Tab);
|
||||
|
||||
const tab = tabs.get({ title: 'Lyrics' });
|
||||
const tab = tabs?.matchCondition((tab) => tab.endpoint.payload.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType === 'MUSIC_PAGE_TYPE_TRACK_LYRICS');
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
@@ -334,7 +319,7 @@ class Music {
|
||||
if (page.contents.item().key('type').string() === 'Message')
|
||||
throw new InnertubeError(page.contents.item().as(Message).text, video_id);
|
||||
|
||||
const section_list = page.contents.item().as(SectionList).contents.array();
|
||||
const section_list = page.contents.item().as(SectionList).contents;
|
||||
return section_list.firstOfType(MusicDescriptionShelf);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface Context {
|
||||
|
||||
export interface SessionOptions {
|
||||
lang?: string;
|
||||
location?: string;
|
||||
account_index?: number;
|
||||
device_category?: DeviceCategory;
|
||||
client_type?: ClientType;
|
||||
@@ -112,6 +113,7 @@ export default class Session extends EventEmitterLike {
|
||||
static async create(options: SessionOptions = {}) {
|
||||
const { context, api_key, api_version, account_index } = await Session.getSessionData(
|
||||
options.lang,
|
||||
options.location,
|
||||
options.account_index,
|
||||
options.device_category,
|
||||
options.client_type,
|
||||
@@ -123,6 +125,7 @@ export default class Session extends EventEmitterLike {
|
||||
|
||||
static async getSessionData(
|
||||
lang = 'en-US',
|
||||
location = '',
|
||||
account_index = 0,
|
||||
device_category: DeviceCategory = 'desktop',
|
||||
client_name: ClientType = ClientType.WEB,
|
||||
@@ -157,7 +160,7 @@ export default class Session extends EventEmitterLike {
|
||||
const context: Context = {
|
||||
client: {
|
||||
hl: device_info[0],
|
||||
gl: device_info[2],
|
||||
gl: location || device_info[2],
|
||||
remoteHost: device_info[3],
|
||||
screenDensityFloat: 1,
|
||||
screenHeightPoints: 720,
|
||||
|
||||
@@ -17,7 +17,7 @@ class TabbedFeed extends Feed {
|
||||
return this.#tabs.map((tab) => tab.title.toString());
|
||||
}
|
||||
|
||||
async getTab(title: string) {
|
||||
async getTabByName(title: string) {
|
||||
const tab = this.#tabs.find((tab) => tab.title.toLowerCase() === title.toLowerCase());
|
||||
|
||||
if (!tab)
|
||||
@@ -28,8 +28,19 @@ class TabbedFeed extends Feed {
|
||||
|
||||
const response = await tab.endpoint.call(this.#actions);
|
||||
|
||||
if (!response)
|
||||
throw new InnertubeError('Failed to call endpoint');
|
||||
return new TabbedFeed(this.#actions, response.data, false);
|
||||
}
|
||||
|
||||
async getTabByURL(url: string) {
|
||||
const tab = this.#tabs.find((tab) => tab.endpoint.metadata.url?.split('/').pop() === url);
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError(`Tab "${url}" not found`);
|
||||
|
||||
if (tab.selected)
|
||||
return this;
|
||||
|
||||
const response = await tab.endpoint.call(this.#actions);
|
||||
|
||||
return new TabbedFeed(this.#actions, response.data, false);
|
||||
}
|
||||
|
||||
@@ -6,17 +6,21 @@ import { YTNode } from '../helpers';
|
||||
class Button extends YTNode {
|
||||
static type = 'Button';
|
||||
|
||||
text: string;
|
||||
text?: string;
|
||||
|
||||
label;
|
||||
tooltip;
|
||||
icon_type;
|
||||
label?: string;
|
||||
tooltip?: string;
|
||||
icon_type?: string;
|
||||
is_disabled?: boolean;
|
||||
|
||||
endpoint: NavigationEndpoint;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.text = new Text(data.text).toString();
|
||||
|
||||
if (data.text) {
|
||||
this.text = new Text(data.text).toString();
|
||||
}
|
||||
|
||||
if (data.accessibility?.label) {
|
||||
this.label = data.accessibility?.label;
|
||||
@@ -30,6 +34,10 @@ class Button extends YTNode {
|
||||
this.icon_type = data.icon?.iconType;
|
||||
}
|
||||
|
||||
if (Reflect.has(data, 'isDisabled')) {
|
||||
this.is_disabled = data.isDisabled;
|
||||
}
|
||||
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint || data.serviceEndpoint || data.command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import Parser from '../index';
|
||||
import Author from './misc/Author';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
|
||||
import type Button from './Button';
|
||||
import type ChannelHeaderLinks from './ChannelHeaderLinks';
|
||||
import type SubscribeButton from './SubscribeButton';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class C4TabbedHeader extends YTNode {
|
||||
static type = 'C4TabbedHeader';
|
||||
|
||||
author;
|
||||
banner;
|
||||
tv_banner;
|
||||
mobile_banner;
|
||||
subscribers;
|
||||
sponsor_button;
|
||||
subscribe_button;
|
||||
header_links;
|
||||
author: Author;
|
||||
banner: Thumbnail[];
|
||||
tv_banner: Thumbnail[];
|
||||
mobile_banner: Thumbnail[];
|
||||
subscribers: Text;
|
||||
videos_count: Text;
|
||||
sponsor_button: Button | null;
|
||||
subscribe_button: SubscribeButton | null;
|
||||
header_links: ChannelHeaderLinks | null;
|
||||
channel_handle: Text;
|
||||
channel_id: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
@@ -23,13 +31,16 @@ class C4TabbedHeader extends YTNode {
|
||||
navigationEndpoint: data.navigationEndpoint
|
||||
}, data.badges, data.avatar);
|
||||
|
||||
this.banner = data.banner ? Thumbnail.fromResponse(data.banner) : [];
|
||||
this.tv_banner = data.tvBanner ? Thumbnail.fromResponse(data.tvBanner) : [];
|
||||
this.mobile_banner = data.mobileBanner ? Thumbnail.fromResponse(data.mobileBanner) : [];
|
||||
this.banner = Thumbnail.fromResponse(data.banner);
|
||||
this.tv_banner = Thumbnail.fromResponse(data.tvBanner);
|
||||
this.mobile_banner = Thumbnail.fromResponse(data.mobileBanner);
|
||||
this.subscribers = new Text(data.subscriberCountText);
|
||||
this.sponsor_button = data.sponsorButton ? Parser.parseItem(data.sponsorButton) : undefined;
|
||||
this.subscribe_button = data.subscribeButton ? Parser.parseItem(data.subscribeButton) : undefined;
|
||||
this.header_links = data.headerLinks ? Parser.parse(data.headerLinks) : undefined;
|
||||
this.videos_count = new Text(data.videosCountText);
|
||||
this.sponsor_button = Parser.parseItem<Button>(data.sponsorButton);
|
||||
this.subscribe_button = Parser.parseItem<SubscribeButton>(data.subscribeButton);
|
||||
this.header_links = Parser.parseItem<ChannelHeaderLinks>(data.headerLinks);
|
||||
this.channel_handle = new Text(data.channelHandleText);
|
||||
this.channel_id = data.channelId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import Parser from '..';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Author from './misc/Author';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import Text from './misc/Text';
|
||||
|
||||
import type SubscribeButton from './SubscribeButton';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class Channel extends YTNode {
|
||||
@@ -10,7 +15,10 @@ class Channel extends YTNode {
|
||||
author: Author;
|
||||
subscribers: Text;
|
||||
videos: Text;
|
||||
long_byline: Text;
|
||||
short_byline: Text;
|
||||
endpoint: NavigationEndpoint;
|
||||
subscribe_button: SubscribeButton | null;
|
||||
description_snippet: Text;
|
||||
|
||||
constructor(data: any) {
|
||||
@@ -22,9 +30,13 @@ class Channel extends YTNode {
|
||||
navigationEndpoint: data.navigationEndpoint
|
||||
}, data.ownerBadges, data.thumbnail);
|
||||
|
||||
// TODO: subscriberCountText is now the channel's handle and videoCountText is the subscriber count. Why haven't they renamed the properties?
|
||||
this.subscribers = new Text(data.subscriberCountText);
|
||||
this.videos = new Text(data.videoCountText);
|
||||
this.long_byline = new Text(data.longBylineText);
|
||||
this.short_byline = new Text(data.shortBylineText);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.subscribe_button = Parser.parseItem<SubscribeButton>(data.subscribeButton);
|
||||
this.description_snippet = new Text(data.descriptionSnippet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import Parser from '../index';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import Text from './misc/Text';
|
||||
import Parser from '../index';
|
||||
|
||||
import type Button from './Button';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class ChannelAboutFullMetadata extends YTNode {
|
||||
@@ -11,13 +15,20 @@ class ChannelAboutFullMetadata extends YTNode {
|
||||
name: Text;
|
||||
avatar: Thumbnail[];
|
||||
canonical_channel_url: string;
|
||||
|
||||
primary_links: {
|
||||
endpoint: NavigationEndpoint;
|
||||
icon: Thumbnail[];
|
||||
title: Text;
|
||||
}[];
|
||||
|
||||
views: Text;
|
||||
joined: Text;
|
||||
description: Text;
|
||||
email_reveal: NavigationEndpoint;
|
||||
can_reveal_email: boolean;
|
||||
country: Text;
|
||||
buttons;
|
||||
buttons: Button[];
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
@@ -25,13 +36,20 @@ class ChannelAboutFullMetadata extends YTNode {
|
||||
this.name = new Text(data.title);
|
||||
this.avatar = Thumbnail.fromResponse(data.avatar);
|
||||
this.canonical_channel_url = data.canonicalChannelUrl;
|
||||
|
||||
this.primary_links = data.primaryLinks.map((link: any) => ({
|
||||
endpoint: new NavigationEndpoint(link.navigationEndpoint),
|
||||
icon: Thumbnail.fromResponse(link.icon),
|
||||
title: new Text(link.title)
|
||||
}));
|
||||
|
||||
this.views = new Text(data.viewCountText);
|
||||
this.joined = new Text(data.joinedDateText);
|
||||
this.description = new Text(data.description);
|
||||
this.email_reveal = new NavigationEndpoint(data.onBusinessEmailRevealClickCommand);
|
||||
this.can_reveal_email = !data.signInForBusinessEmail;
|
||||
this.country = new Text(data.country);
|
||||
this.buttons = Parser.parse(data.actionButtons);
|
||||
this.buttons = Parser.parseArray<Button>(data.actionButtons);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import Author from './misc/Author';
|
||||
import { timeToSeconds } from '../../utils/Utils';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import type Menu from './menus/Menu';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class CompactVideo extends YTNode {
|
||||
@@ -25,7 +27,7 @@ class CompactVideo extends YTNode {
|
||||
|
||||
thumbnail_overlays;
|
||||
endpoint: NavigationEndpoint;
|
||||
menu;
|
||||
menu: Menu | null;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
@@ -43,9 +45,9 @@ class CompactVideo extends YTNode {
|
||||
seconds: timeToSeconds(new Text(data.lengthText).toString())
|
||||
};
|
||||
|
||||
this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays);
|
||||
this.thumbnail_overlays = Parser.parseArray(data.thumbnailOverlays);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.menu = Parser.parse(data.menu);
|
||||
this.menu = Parser.parseItem<Menu>(data.menu);
|
||||
}
|
||||
|
||||
get best_thumbnail() {
|
||||
|
||||
41
src/parser/classes/ExpandableMetadata.ts
Normal file
41
src/parser/classes/ExpandableMetadata.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import Parser from '..';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
|
||||
import Button from './Button';
|
||||
import HorizontalCardList from './HorizontalCardList';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class ExpandableMetadata extends YTNode {
|
||||
static type = 'ExpandableMetadata';
|
||||
|
||||
header: {
|
||||
collapsed_title: Text;
|
||||
collapsed_thumbnail: Thumbnail[];
|
||||
collapsed_label: Text;
|
||||
expanded_title: Text;
|
||||
};
|
||||
|
||||
expanded_content: HorizontalCardList | null;
|
||||
expand_button: Button | null;
|
||||
collapse_button: Button | null;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
|
||||
this.header = {
|
||||
collapsed_title: new Text(data.header.collapsedTitle),
|
||||
collapsed_thumbnail: Thumbnail.fromResponse(data.header.collapsedThumbnail),
|
||||
collapsed_label: new Text(data.header.collapsedLabel),
|
||||
expanded_title: new Text(data.header.expandedTitle)
|
||||
};
|
||||
|
||||
this.expanded_content = Parser.parseItem<HorizontalCardList>(data.expandedContent);
|
||||
this.expand_button = Parser.parseItem<Button>(data.expandButton);
|
||||
this.collapse_button = Parser.parseItem<Button>(data.collapseButton);
|
||||
}
|
||||
}
|
||||
|
||||
export default ExpandableMetadata;
|
||||
@@ -3,6 +3,9 @@ import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import Author from './misc/Author';
|
||||
|
||||
import type Menu from './menus/Menu';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class GridVideo extends YTNode {
|
||||
@@ -14,12 +17,12 @@ class GridVideo extends YTNode {
|
||||
thumbnail_overlays;
|
||||
rich_thumbnail;
|
||||
published: Text;
|
||||
duration: Text | string;
|
||||
duration: Text | null;
|
||||
author: Author;
|
||||
views: Text;
|
||||
short_view_count: Text;
|
||||
endpoint: NavigationEndpoint;
|
||||
menu;
|
||||
menu: Menu | null;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
@@ -27,15 +30,15 @@ class GridVideo extends YTNode {
|
||||
this.id = data.videoId;
|
||||
this.title = new Text(data.title);
|
||||
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);
|
||||
this.thumbnail_overlays = Parser.parse(data.thumbnailOverlays);
|
||||
this.thumbnail_overlays = Parser.parseArray(data.thumbnailOverlays);
|
||||
this.rich_thumbnail = data.richThumbnail && Parser.parse(data.richThumbnail);
|
||||
this.published = new Text(data.publishedTimeText);
|
||||
this.duration = data.lengthText ? new Text(data.lengthText) : length_alt?.text ? new Text(length_alt.text) : '';
|
||||
this.duration = data.lengthText ? new Text(data.lengthText) : length_alt?.text ? new Text(length_alt.text) : null;
|
||||
this.author = data.shortBylineText && new Author(data.shortBylineText, data.ownerBadges);
|
||||
this.views = new Text(data.viewCountText);
|
||||
this.short_view_count = new Text(data.shortViewCountText);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.menu = Parser.parse(data.menu);
|
||||
this.menu = Parser.parseItem<Menu>(data.menu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import Parser from '../index';
|
||||
import { YTNode } from '../helpers';
|
||||
import SearchRefinementCard from './SearchRefinementCard';
|
||||
import Button from './Button';
|
||||
import MacroMarkersListItem from './MacroMarkersListItem';
|
||||
|
||||
class HorizontalCardList extends YTNode {
|
||||
static type = 'HorizontalCardList';
|
||||
@@ -13,7 +14,7 @@ class HorizontalCardList extends YTNode {
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.cards = Parser.parseArray<SearchRefinementCard>(data.cards, SearchRefinementCard);
|
||||
this.cards = Parser.parseArray<SearchRefinementCard | MacroMarkersListItem>(data.cards);
|
||||
this.header = Parser.parseItem(data.header);
|
||||
this.previous_button = Parser.parseItem<Button>(data.previousButton, Button);
|
||||
this.next_button = Parser.parseItem<Button>(data.nextButton, Button);
|
||||
|
||||
29
src/parser/classes/MacroMarkersListItem.ts
Normal file
29
src/parser/classes/MacroMarkersListItem.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class MacroMarkersListItem extends YTNode {
|
||||
static type = 'MacroMarkersListItem';
|
||||
|
||||
title: Text;
|
||||
time_description: Text;
|
||||
thumbnail: Thumbnail[];
|
||||
on_tap_endpoint: NavigationEndpoint;
|
||||
layout: string;
|
||||
is_highlighted: boolean;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
|
||||
this.title = new Text(data.title);
|
||||
this.time_description = new Text(data.timeDescription);
|
||||
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
|
||||
this.on_tap_endpoint = new NavigationEndpoint(data.onTap);
|
||||
this.layout = data.layout;
|
||||
this.is_highlighted = data.isHighlighted;
|
||||
}
|
||||
}
|
||||
|
||||
export default MacroMarkersListItem;
|
||||
@@ -5,7 +5,8 @@ class MetadataBadge extends YTNode {
|
||||
|
||||
icon_type?: string;
|
||||
style?: string;
|
||||
tooltip: string | null;
|
||||
label?: string;
|
||||
tooltip?: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
@@ -18,7 +19,13 @@ class MetadataBadge extends YTNode {
|
||||
this.style = data.style;
|
||||
}
|
||||
|
||||
this.tooltip = data?.tooltip || data?.iconTooltip || null;
|
||||
if (data?.label) {
|
||||
this.style = data.label;
|
||||
}
|
||||
|
||||
if (data?.tooltip || data?.iconTooltip) {
|
||||
this.tooltip = data.tooltip || data.iconTooltip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,8 @@ class PlaylistPanelVideo extends YTNode {
|
||||
}));
|
||||
}
|
||||
|
||||
this.badges = Parser.parse(data.badges);
|
||||
this.menu = Parser.parse(data.menu);
|
||||
this.badges = Parser.parseArray(data.badges);
|
||||
this.menu = Parser.parseItem(data.menu);
|
||||
this.set_video_id = data.playlistSetVideoId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ import Parser from '../index';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import PlaylistAuthor from './misc/PlaylistAuthor';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import type Menu from './menus/Menu';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
class PlaylistVideo extends YTNode {
|
||||
@@ -17,7 +19,7 @@ class PlaylistVideo extends YTNode {
|
||||
set_video_id: string | undefined;
|
||||
endpoint: NavigationEndpoint;
|
||||
is_playable: boolean;
|
||||
menu;
|
||||
menu: Menu | null;
|
||||
|
||||
duration: {
|
||||
text: string;
|
||||
@@ -35,7 +37,7 @@ class PlaylistVideo extends YTNode {
|
||||
this.set_video_id = data?.setVideoId;
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.is_playable = data.isPlayable;
|
||||
this.menu = Parser.parse(data.menu);
|
||||
this.menu = Parser.parseItem<Menu>(data.menu);
|
||||
this.duration = {
|
||||
text: new Text(data.lengthText).text,
|
||||
seconds: parseInt(data.lengthSeconds)
|
||||
|
||||
@@ -16,7 +16,7 @@ class SectionList extends YTNode {
|
||||
}
|
||||
|
||||
// TODO: this should be Parser#parseArray
|
||||
this.contents = Parser.parse(data.contents);
|
||||
this.contents = Parser.parseArray(data.contents);
|
||||
|
||||
if (data.continuations) {
|
||||
if (data.continuations[0].nextContinuationData) {
|
||||
|
||||
@@ -4,6 +4,8 @@ import Author from './misc/Author';
|
||||
import Menu from './menus/Menu';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import MetadataBadge from './MetadataBadge';
|
||||
import ExpandableMetadata from './ExpandableMetadata';
|
||||
|
||||
import { timeToSeconds } from '../../utils/Utils';
|
||||
import { YTNode } from '../helpers';
|
||||
@@ -18,11 +20,13 @@ class Video extends YTNode {
|
||||
text: Text;
|
||||
hover_text: Text;
|
||||
}[];
|
||||
expandable_metadata: ExpandableMetadata | null;
|
||||
|
||||
thumbnails: Thumbnail[];
|
||||
thumbnail_overlays;
|
||||
rich_thumbnail;
|
||||
author: Author;
|
||||
badges: MetadataBadge[];
|
||||
endpoint: NavigationEndpoint;
|
||||
published: Text;
|
||||
view_count: Text;
|
||||
@@ -36,7 +40,8 @@ class Video extends YTNode {
|
||||
|
||||
show_action_menu: boolean;
|
||||
is_watched: boolean;
|
||||
menu;
|
||||
menu: Menu | null;
|
||||
search_video_result_entity_key: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
@@ -54,10 +59,13 @@ class Video extends YTNode {
|
||||
hover_text: new Text(snippet.snippetHoverText)
|
||||
})) || [];
|
||||
|
||||
this.expandable_metadata = Parser.parseItem<ExpandableMetadata>(data.expandableMetadata);
|
||||
|
||||
this.thumbnails = Thumbnail.fromResponse(data.thumbnail);
|
||||
this.thumbnail_overlays = Parser.parseArray(data.thumbnailOverlays);
|
||||
this.rich_thumbnail = data.richThumbnail ? Parser.parseItem(data.richThumbnail) : null;
|
||||
this.author = new Author(data.ownerText, data.ownerBadges, data.channelThumbnailSupportedRenderers?.channelThumbnailWithLinkRenderer?.thumbnail);
|
||||
this.badges = Parser.parseArray(data.badges, MetadataBadge);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.published = new Text(data.publishedTimeText);
|
||||
this.view_count = new Text(data.viewCountText);
|
||||
@@ -76,6 +84,7 @@ class Video extends YTNode {
|
||||
this.show_action_menu = data.showActionMenu;
|
||||
this.is_watched = data.isWatched || false;
|
||||
this.menu = Parser.parseItem<Menu>(data.menu, Menu);
|
||||
this.search_video_result_entity_key = data.searchVideoResultEntityKey;
|
||||
}
|
||||
|
||||
get description(): string {
|
||||
@@ -85,22 +94,30 @@ class Video extends YTNode {
|
||||
return this.description_snippet?.toString() || '';
|
||||
}
|
||||
|
||||
/*
|
||||
Get is_live() {
|
||||
return this.badges.some((badge) => badge.style === 'BADGE_STYLE_TYPE_LIVE_NOW');
|
||||
get is_live(): boolean {
|
||||
return this.badges.some((badge) => {
|
||||
if (badge.label === 'BADGE_STYLE_TYPE_LIVE_NOW' || badge.style === 'LIVE')
|
||||
return true;
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
get is_upcoming(): boolean | undefined {
|
||||
return this.upcoming && this.upcoming > new Date();
|
||||
}
|
||||
|
||||
/*
|
||||
Get has_captions() {
|
||||
return this.badges.some((badge) => badge.label === 'CC');
|
||||
}*/
|
||||
get is_premiere(): boolean {
|
||||
return this.badges.some((badge) => badge.style === 'PREMIERE');
|
||||
}
|
||||
|
||||
get best_thumbnail(): Thumbnail | undefined{
|
||||
get is_4k(): boolean {
|
||||
return this.badges.some((badge) => badge.style === '4K');
|
||||
}
|
||||
|
||||
get has_captions(): boolean {
|
||||
return this.badges.some((badge) => badge.style === 'CC');
|
||||
}
|
||||
|
||||
get best_thumbnail(): Thumbnail | undefined {
|
||||
return this.thumbnails[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,15 @@ import NavigationEndpoint from '../NavigationEndpoint';
|
||||
class TextRun {
|
||||
text: string;
|
||||
endpoint: NavigationEndpoint | undefined;
|
||||
bold: boolean;
|
||||
italics: boolean;
|
||||
strikethrough: boolean;
|
||||
|
||||
constructor(data: any) {
|
||||
this.text = data.text;
|
||||
this.bold = Boolean(data.bold);
|
||||
this.italics = Boolean(data.italics);
|
||||
this.strikethrough = Boolean(data.strikethrough);
|
||||
this.endpoint = data.navigationEndpoint ? new NavigationEndpoint(data.navigationEndpoint) : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,6 +359,10 @@ export type ObservedArray<T extends YTNode = YTNode> = Array<T> & {
|
||||
* Returns all objects that match the rule.
|
||||
*/
|
||||
getAll: (rule: object, del_items?: boolean) => T[];
|
||||
/**
|
||||
* Returns the first object to match the condition.
|
||||
*/
|
||||
matchCondition: (condition: (node: T) => boolean) => T | undefined;
|
||||
/**
|
||||
* Removes the item at the given index.
|
||||
*/
|
||||
@@ -412,6 +416,14 @@ export function observe<T extends YTNode>(obj: Array<T>) {
|
||||
);
|
||||
}
|
||||
|
||||
if (prop == 'matchCondition') {
|
||||
return (condition: (node: T) => boolean) => (
|
||||
target.find((obj) => {
|
||||
return condition(obj);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (prop == 'filterType') {
|
||||
return (...types: YTNodeConstructor<YTNode>[]) => {
|
||||
return observe(target.filter((node: YTNode) => {
|
||||
|
||||
@@ -73,6 +73,7 @@ import { default as Endscreen } from './classes/Endscreen';
|
||||
import { default as EndscreenElement } from './classes/EndscreenElement';
|
||||
import { default as EndScreenPlaylist } from './classes/EndScreenPlaylist';
|
||||
import { default as EndScreenVideo } from './classes/EndScreenVideo';
|
||||
import { default as ExpandableMetadata } from './classes/ExpandableMetadata';
|
||||
import { default as ExpandableTab } from './classes/ExpandableTab';
|
||||
import { default as ExpandedShelfContents } from './classes/ExpandedShelfContents';
|
||||
import { default as FeedFilterChipBar } from './classes/FeedFilterChipBar';
|
||||
@@ -137,6 +138,7 @@ import { default as LiveChatItemList } from './classes/LiveChatItemList';
|
||||
import { default as LiveChatMessageInput } from './classes/LiveChatMessageInput';
|
||||
import { default as LiveChatParticipant } from './classes/LiveChatParticipant';
|
||||
import { default as LiveChatParticipantsList } from './classes/LiveChatParticipantsList';
|
||||
import { default as MacroMarkersListItem } from './classes/MacroMarkersListItem';
|
||||
import { default as Menu } from './classes/menus/Menu';
|
||||
import { default as MenuNavigationItem } from './classes/menus/MenuNavigationItem';
|
||||
import { default as MenuServiceItem } from './classes/menus/MenuServiceItem';
|
||||
@@ -363,6 +365,7 @@ export const YTNodes = {
|
||||
EndscreenElement,
|
||||
EndScreenPlaylist,
|
||||
EndScreenVideo,
|
||||
ExpandableMetadata,
|
||||
ExpandableTab,
|
||||
ExpandedShelfContents,
|
||||
FeedFilterChipBar,
|
||||
@@ -427,6 +430,7 @@ export const YTNodes = {
|
||||
LiveChatMessageInput,
|
||||
LiveChatParticipant,
|
||||
LiveChatParticipantsList,
|
||||
MacroMarkersListItem,
|
||||
Menu,
|
||||
MenuNavigationItem,
|
||||
MenuServiceItem,
|
||||
|
||||
@@ -9,12 +9,13 @@ import MicroformatData from '../classes/MicroformatData';
|
||||
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';
|
||||
|
||||
import { InnertubeError } from '../../utils/Utils';
|
||||
|
||||
export default class Channel extends TabbedFeed {
|
||||
header;
|
||||
metadata;
|
||||
@@ -70,37 +71,37 @@ export default class Channel extends TabbedFeed {
|
||||
}
|
||||
|
||||
async getHome() {
|
||||
const tab = await this.getTab('Home');
|
||||
const tab = await this.getTabByURL('featured');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getVideos() {
|
||||
const tab = await this.getTab('Videos');
|
||||
const tab = await this.getTabByURL('videos');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getShorts() {
|
||||
const tab = await this.getTab('Shorts');
|
||||
const tab = await this.getTabByURL('shorts');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getLiveStreams() {
|
||||
const tab = await this.getTab('Live');
|
||||
const tab = await this.getTabByURL('streams');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getPlaylists() {
|
||||
const tab = await this.getTab('Playlists');
|
||||
const tab = await this.getTabByURL('playlists');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getCommunity() {
|
||||
const tab = await this.getTab('Community');
|
||||
const tab = await this.getTabByURL('community');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getChannels() {
|
||||
const tab = await this.getTab('Channels');
|
||||
const tab = await this.getTabByURL('channels');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ export default class Channel extends TabbedFeed {
|
||||
* Note that this does not return a new {@link Channel} object.
|
||||
*/
|
||||
async getAbout() {
|
||||
const tab = await this.getTab('About');
|
||||
const tab = await this.getTabByURL('about');
|
||||
return tab.memo.getType(ChannelAboutFullMetadata)?.[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import VideoOwner from '../classes/VideoOwner';
|
||||
import PlaylistMetadata from '../classes/PlaylistMetadata';
|
||||
import PlaylistSidebarPrimaryInfo from '../classes/PlaylistSidebarPrimaryInfo';
|
||||
import PlaylistSidebarSecondaryInfo from '../classes/PlaylistSidebarSecondaryInfo';
|
||||
import PlaylistCustomThumbnail from '../classes/PlaylistCustomThumbnail';
|
||||
import PlaylistVideoThumbnail from '../classes/PlaylistVideoThumbnail';
|
||||
import PlaylistHeader from '../classes/PlaylistHeader';
|
||||
|
||||
@@ -30,8 +31,8 @@ class Playlist extends Feed {
|
||||
this.info = {
|
||||
...this.page.metadata.item().as(PlaylistMetadata),
|
||||
...{
|
||||
author: secondary_info?.owner.item().as(VideoOwner).author,
|
||||
thumbnails: primary_info?.thumbnail_renderer.item().as(PlaylistVideoThumbnail).thumbnail as Thumbnail[],
|
||||
author: secondary_info?.owner.item().as(VideoOwner).author ?? header?.author,
|
||||
thumbnails: primary_info?.thumbnail_renderer.item().as(PlaylistVideoThumbnail, PlaylistCustomThumbnail).thumbnail as Thumbnail[],
|
||||
total_items: this.#getStat(0, primary_info),
|
||||
views: this.#getStat(1, primary_info),
|
||||
last_updated: this.#getStat(2, primary_info),
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class Search extends Feed {
|
||||
super(actions, data, already_parsed);
|
||||
|
||||
const contents =
|
||||
this.page.contents_memo.getType(SectionList)?.[0]?.contents?.array() ||
|
||||
this.page.contents_memo.getType(SectionList)?.[0]?.contents ||
|
||||
this.page.on_response_received_commands?.[0].contents;
|
||||
|
||||
this.results = contents.firstOfType(ItemSection)?.contents;
|
||||
@@ -40,7 +40,7 @@ export default class Search extends Feed {
|
||||
|
||||
if (typeof card === 'string') {
|
||||
if (!this.refinement_cards) throw new InnertubeError('No refinement cards found.');
|
||||
target_card = this.refinement_cards?.cards.get({ query: card });
|
||||
target_card = this.refinement_cards?.cards.get({ query: card })?.as(SearchRefinementCard);
|
||||
if (!target_card)
|
||||
throw new InnertubeError(`Refinement card "${card}" not found`, { available_cards: this.refinement_card_queries });
|
||||
} else if (card.type === 'SearchRefinementCard') {
|
||||
@@ -58,7 +58,7 @@ export default class Search extends Feed {
|
||||
* 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.as(SearchRefinementCard).map((card) => card.query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ class Settings {
|
||||
if (!tab)
|
||||
throw new InnertubeError('Target tab not found');
|
||||
|
||||
const contents = tab.content?.as(SectionList).contents.array().as(ItemSection);
|
||||
const contents = tab.content?.as(SectionList).contents.as(ItemSection);
|
||||
|
||||
this.introduction = contents?.shift()?.contents?.get({ type: 'PageIntroduction' })?.as(PageIntroduction);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class TimeWatched {
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
|
||||
this.contents = tab.content?.as(SectionList).contents.array().as(ItemSection);
|
||||
this.contents = tab.content?.as(SectionList).contents.as(ItemSection);
|
||||
}
|
||||
|
||||
get page(): ParsedResponse {
|
||||
|
||||
@@ -28,8 +28,8 @@ class Explore {
|
||||
if (!section_list)
|
||||
throw new InnertubeError('Target tab did not have any content.');
|
||||
|
||||
this.top_buttons = section_list.contents.array().firstOfType(Grid)?.items.as(MusicNavigationButton) || ([] as MusicNavigationButton[]);
|
||||
this.sections = section_list.contents.array().getAll({ type: 'MusicCarouselShelf' }) as MusicCarouselShelf[];
|
||||
this.top_buttons = section_list.contents.firstOfType(Grid)?.items.as(MusicNavigationButton) || ([] as MusicNavigationButton[]);
|
||||
this.sections = section_list.contents.getAll({ type: 'MusicCarouselShelf' }) as MusicCarouselShelf[];
|
||||
}
|
||||
|
||||
get page(): ParsedResponse {
|
||||
|
||||
@@ -33,7 +33,7 @@ class HomeFeed {
|
||||
}
|
||||
|
||||
this.#continuation = tab.content?.as(SectionList).continuation;
|
||||
this.sections = tab.content?.as(SectionList).contents.array().as(MusicCarouselShelf);
|
||||
this.sections = tab.content?.as(SectionList).contents.as(MusicCarouselShelf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ class Library {
|
||||
const section_list = this.#page.contents_memo.getType(SectionList)?.[0];
|
||||
|
||||
this.header = section_list?.header?.item().as(MusicSideAlignedItem);
|
||||
this.contents = section_list?.contents?.array().as(Grid, MusicShelf);
|
||||
this.contents = section_list?.contents?.as(Grid, MusicShelf);
|
||||
|
||||
this.#continuation = this.contents?.find((list: Grid | MusicShelf) => list.continuation)?.continuation;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class Playlist {
|
||||
/**
|
||||
* Retrieves related playlists
|
||||
*/
|
||||
async getRelated() {
|
||||
async getRelated(): Promise<MusicCarouselShelf> {
|
||||
let section_continuation = this.#page.contents_memo.get('SectionList')?.[0].as(SectionList).continuation;
|
||||
|
||||
while (section_continuation) {
|
||||
@@ -74,19 +74,15 @@ class Playlist {
|
||||
const section_list = data.continuation_contents?.as(SectionListContinuation);
|
||||
const sections = section_list?.contents?.as(MusicCarouselShelf, MusicShelf);
|
||||
|
||||
const related = sections?.filter(
|
||||
(section) =>
|
||||
section.is(MusicCarouselShelf) ? section.header?.title.toString() === 'Related playlists' :
|
||||
section.title.toString() === 'Related playlists'
|
||||
)[0];
|
||||
const related = sections?.matchCondition((section) => section.is(MusicCarouselShelf))?.as(MusicCarouselShelf);
|
||||
|
||||
if (related)
|
||||
return related.contents || [];
|
||||
return related;
|
||||
|
||||
section_continuation = section_list?.continuation;
|
||||
}
|
||||
|
||||
return [];
|
||||
throw new InnertubeError('Target section not found.');
|
||||
}
|
||||
|
||||
async getSuggestions(refresh = true) {
|
||||
@@ -115,9 +111,7 @@ class Playlist {
|
||||
const section_list = page.continuation_contents?.as(SectionListContinuation);
|
||||
const sections = section_list?.contents?.as(MusicCarouselShelf, MusicShelf);
|
||||
|
||||
const suggestions = sections?.filter(
|
||||
(section) => section.is(MusicShelf) && section.title.toString() === 'Suggestions'
|
||||
)[0] as MusicShelf | undefined;
|
||||
const suggestions = sections?.matchCondition((section) => section.is(MusicShelf))?.as(MusicShelf);
|
||||
|
||||
return {
|
||||
items: suggestions?.contents || [],
|
||||
|
||||
@@ -37,7 +37,7 @@ class Recap {
|
||||
if (!tab)
|
||||
throw new InnertubeError('Target tab not found');
|
||||
|
||||
this.sections = tab.content?.as(SectionList).contents.array().as(ItemSection, MusicCarouselShelf, Message);
|
||||
this.sections = tab.content?.as(SectionList).contents.as(ItemSection, MusicCarouselShelf, Message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ class Search {
|
||||
|
||||
this.header = tab_content.hasKey('header') ? tab_content.header?.item().as(ChipCloud) : null;
|
||||
|
||||
const shelves = tab_content.contents.array().as(MusicShelf, ItemSection);
|
||||
const shelves = tab_content.contents.as(MusicShelf, ItemSection);
|
||||
const item_section = shelves.firstOfType(ItemSection);
|
||||
|
||||
this.did_you_mean = item_section?.contents?.firstOfType(DidYouMean) || null;
|
||||
|
||||
@@ -4,9 +4,7 @@ import Constants from '../../utils/Constants';
|
||||
import { InnertubeError } from '../../utils/Utils';
|
||||
|
||||
import Tab from '../classes/Tab';
|
||||
import Tabbed from '../classes/Tabbed';
|
||||
import WatchNextTabbedResults from '../classes/WatchNextTabbedResults';
|
||||
import SingleColumnMusicWatchNextResults from '../classes/SingleColumnMusicWatchNextResults';
|
||||
import MicroformatData from '../classes/MicroformatData';
|
||||
import PlayerOverlay from '../classes/PlayerOverlay';
|
||||
import PlaylistPanel from '../classes/PlaylistPanel';
|
||||
@@ -70,8 +68,7 @@ class TrackInfo {
|
||||
this.#playback_tracking = info.playback_tracking;
|
||||
|
||||
if (next) {
|
||||
const single_col = next.contents.item().as(SingleColumnMusicWatchNextResults);
|
||||
const tabbed_results = single_col.contents.item().as(Tabbed).contents.item().as(WatchNextTabbedResults);
|
||||
const tabbed_results = next.contents_memo.getType(WatchNextTabbedResults)?.[0];
|
||||
|
||||
this.tabs = tabbed_results.tabs.array().as(Tab);
|
||||
this.current_video_endpoint = next.current_video_endpoint;
|
||||
@@ -84,14 +81,17 @@ class TrackInfo {
|
||||
/**
|
||||
* Retrieves contents of the given tab.
|
||||
*/
|
||||
async getTab(title: string) {
|
||||
async getTab(title_or_page_type: string) {
|
||||
if (!this.tabs)
|
||||
throw new InnertubeError('Could not find any tab');
|
||||
|
||||
const target_tab = this.tabs.get({ title });
|
||||
const target_tab =
|
||||
this.tabs.get({ title: title_or_page_type }) ||
|
||||
this.tabs.matchCondition((tab) => tab.endpoint.payload.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType === title_or_page_type) ||
|
||||
this.tabs?.[0];
|
||||
|
||||
if (!target_tab)
|
||||
throw new InnertubeError(`Tab "${title}" not found`, { available_tabs: this.available_tabs });
|
||||
throw new InnertubeError(`Tab "${title_or_page_type}" not found`, { available_tabs: this.available_tabs });
|
||||
|
||||
if (target_tab.content)
|
||||
return target_tab.content;
|
||||
@@ -101,7 +101,7 @@ class TrackInfo {
|
||||
if (page.contents.item().key('type').string() === 'Message')
|
||||
return page.contents.item().as(Message);
|
||||
|
||||
return page.contents.item().as(SectionList).contents.array();
|
||||
return page.contents.item().as(SectionList).contents;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +140,7 @@ class TrackInfo {
|
||||
* Retrieves related content.
|
||||
*/
|
||||
async getRelated(): Promise<ObservedArray<MusicCarouselShelf | MusicDescriptionShelf>> {
|
||||
const tab = await this.getTab('Related') as ObservedArray<MusicDescriptionShelf | MusicDescriptionShelf>;
|
||||
const tab = await this.getTab('MUSIC_PAGE_TYPE_TRACK_RELATED') as ObservedArray<MusicDescriptionShelf | MusicDescriptionShelf>;
|
||||
return tab;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ class TrackInfo {
|
||||
* Retrieves lyrics.
|
||||
*/
|
||||
async getLyrics(): Promise<MusicDescriptionShelf | undefined> {
|
||||
const tab = await this.getTab('Lyrics') as ObservedArray<MusicCarouselShelf | MusicDescriptionShelf>;
|
||||
const tab = await this.getTab('MUSIC_PAGE_TYPE_TRACK_LYRICS') as ObservedArray<MusicCarouselShelf | MusicDescriptionShelf>;
|
||||
return tab.firstOfType(MusicDescriptionShelf);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export default class HTTPClient {
|
||||
const request_headers = new Headers(headers);
|
||||
|
||||
request_headers.set('Accept', '*/*');
|
||||
request_headers.set('Accept-Language', `en-${this.#session.context.client.gl || 'US'}`);
|
||||
request_headers.set('Accept-Language', `${this.#session.context.client.hl}-${this.#session.context.client.gl}`);
|
||||
request_headers.set('x-goog-visitor-id', this.#session.context.client.visitorData || '');
|
||||
request_headers.set('x-origin', request_url.origin);
|
||||
request_headers.set('x-youtube-client-version', this.#session.context.client.clientVersion || '');
|
||||
|
||||
@@ -10,6 +10,10 @@ export const VIDEOS = [
|
||||
{
|
||||
ID: 'I1qsF0WQy8c',
|
||||
QUERY: 'mkbhd',
|
||||
},
|
||||
{
|
||||
ID: 'OqiXFXlYFi8',
|
||||
QUERY: 'formatted comment text'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from 'fs';
|
||||
import Innertube from '..';
|
||||
import { CHANNELS, VIDEOS } from './constants';
|
||||
import { streamToIterable } from '../src/utils/Utils';
|
||||
import TextRun from '../src/parser/classes/misc/TextRun';
|
||||
|
||||
describe('YouTube.js Tests', () => {
|
||||
let yt: Innertube;
|
||||
@@ -68,6 +69,19 @@ describe('YouTube.js Tests', () => {
|
||||
threads = await yt.getComments(VIDEOS[1].ID);
|
||||
expect(threads.contents.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should parse formatted comments', async () => {
|
||||
const threads = await yt.getComments(VIDEOS[3].ID);
|
||||
const authorComment = threads.contents.find(t => t.comment?.author_is_channel_owner)
|
||||
expect(authorComment).not.toBeUndefined();
|
||||
|
||||
expect(authorComment!.comment?.content.runs?.length).toBeGreaterThan(0)
|
||||
const runs = authorComment!.comment!.content.runs! as TextRun[]
|
||||
|
||||
expect(runs[0].bold).toBeTruthy()
|
||||
expect(runs[2].italics).toBeTruthy()
|
||||
expect(runs[4].strikethrough).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should retrieve next batch of comments', async () => {
|
||||
const next = await threads.getContinuation();
|
||||
|
||||
Reference in New Issue
Block a user