mirror of
https://github.com/LuanRT/YouTube.js.git
synced 2026-06-13 17:42:18 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6caa679df6 | ||
|
|
2a87f42b32 | ||
|
|
f7c1e0f249 | ||
|
|
fe4c5433cf | ||
|
|
0e5e0c0fab | ||
|
|
f0fd6146c7 | ||
|
|
43061970c6 | ||
|
|
746023d9bb | ||
|
|
3102479dd9 | ||
|
|
c7a13c948c | ||
|
|
ec875ba321 | ||
|
|
db77bba802 | ||
|
|
5ea0a0ebf8 | ||
|
|
0130229236 | ||
|
|
da517fe6d1 | ||
|
|
95ff1e6c5e | ||
|
|
0f8adfd9b8 | ||
|
|
b514765354 | ||
|
|
3cbcd71a3a | ||
|
|
4c00f15f55 |
66
README.md
66
README.md
@@ -406,7 +406,32 @@ See [`./examples/comments`](https://github.com/LuanRT/YouTube.js/blob/main/examp
|
||||
### getHomeFeed()
|
||||
Retrieves YouTube's home feed.
|
||||
|
||||
**Returns**: `Promise.<FilterableFeed>`
|
||||
**Returns**: `Promise.<HomeFeed>`
|
||||
|
||||
<details>
|
||||
<summary>Methods & Getters</summary>
|
||||
<p>
|
||||
|
||||
- `<home_feed>#videos`
|
||||
- Returns all videos in the home feed.
|
||||
|
||||
- `<home_feed>#posts`
|
||||
- Returns all posts in the home feed.
|
||||
|
||||
- `<home_feed>#shelves`
|
||||
- Returns all shelves in the home feed.
|
||||
|
||||
- `<home_feed>#filters`
|
||||
- Returns available filters.
|
||||
|
||||
- `<home_feed>#applyFilter(name | ChipCloudChip)`
|
||||
- Applies given filter and returns a new HomeFeed instance.
|
||||
|
||||
- `<home_feed>#getContinuation()`
|
||||
- Retrieves feed continuation.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<a name="getlibrary"></a>
|
||||
### getLibrary()
|
||||
@@ -472,11 +497,16 @@ Retrieves contents for a given channel.
|
||||
<p>
|
||||
|
||||
- `<channel>#getVideos()`
|
||||
- `<channel>#getShorts()`
|
||||
- `<channel>#getLiveStreams()`
|
||||
- `<channel>#getPlaylists()`
|
||||
- `<channel>#getHome()`
|
||||
- `<channel>#getCommunity()`
|
||||
- `<channel>#getChannels()`
|
||||
- `<channel>#getAbout()`
|
||||
- `<channel>#getContinuation()`
|
||||
- `<channel>#filters`
|
||||
- `<channel>#page`
|
||||
|
||||
</p>
|
||||
</details>
|
||||
@@ -578,6 +608,7 @@ For example, you may want to call an endpoint directly, that can be achieved wit
|
||||
// ...
|
||||
|
||||
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.
|
||||
@@ -593,10 +624,10 @@ Or maybe there's an interesting `NavigationEndpoint` in a parsed response and we
|
||||
```ts
|
||||
// ...
|
||||
const artist = await yt.music.getArtist('UC52ZqHVQz5OoGhvbWiRal6g');
|
||||
const albums = artist.sections[1].as(MusicCarouselShelf);
|
||||
const albums = artist.sections[1].as(YTNodes.MusicCarouselShelf);
|
||||
|
||||
// Say we have a button and want to “click” it
|
||||
const button = albums.as(MusicCarouselShelf).header?.more_content;
|
||||
const button = albums.as(YTNodes.MusicCarouselShelf).header?.more_content;
|
||||
|
||||
if (button) {
|
||||
// To do that, we can call its navigation endpoint:
|
||||
@@ -609,24 +640,11 @@ if (button) {
|
||||
|
||||
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!
|
||||
|
||||
<details>
|
||||
<summary>Example:</summary>
|
||||
<p>
|
||||
|
||||
Example:
|
||||
```ts
|
||||
// See ./examples/parser
|
||||
|
||||
import { Parser } from 'youtubei.js';
|
||||
|
||||
import SectionList from 'youtubei.js/dist/src/parser/classes/SectionList';
|
||||
import SingleColumnBrowseResults from 'youtubei.js/dist/src/parser/classes/SingleColumnBrowseResults';
|
||||
|
||||
import MusicVisualHeader from 'youtubei.js/dist/src/parser/classes/MusicVisualHeader';
|
||||
import MusicImmersiveHeader from 'youtubei.js/dist/src/parser/classes/MusicImmersiveHeader';
|
||||
import MusicCarouselShelf from 'youtubei.js/dist/src/parser/classes/MusicCarouselShelf';
|
||||
import MusicDescriptionShelf from 'youtubei.js/dist/src/parser/classes/MusicDescriptionShelf';
|
||||
import MusicShelf from 'youtubei.js/dist/src/parser/classes/MusicShelf';
|
||||
|
||||
import { Parser, YTNodes } from 'youtubei.js';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Artist page response from YouTube Music
|
||||
@@ -634,7 +652,7 @@ const data = readFileSync('./artist.json').toString();
|
||||
|
||||
const page = Parser.parseResponse(JSON.parse(data));
|
||||
|
||||
const header = page.header.item().as(MusicImmersiveHeader, MusicVisualHeader);
|
||||
const header = page.header?.item().as(YTNodes.MusicImmersiveHeader, YTNodes.MusicVisualHeader);
|
||||
|
||||
console.info('Header:', header);
|
||||
|
||||
@@ -642,7 +660,8 @@ console.info('Header:', header);
|
||||
// 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(SingleColumnBrowseResults).tabs.get({ selected: false });
|
||||
const tab = page.contents.item().as(YTNodes.SingleColumnBrowseResults).tabs.firstOfType(YTNodes.Tab);
|
||||
|
||||
|
||||
if (!tab)
|
||||
throw new Error('Target tab not found');
|
||||
@@ -650,14 +669,11 @@ if (!tab)
|
||||
if (!tab.content)
|
||||
throw new Error('Target tab appears to be empty');
|
||||
|
||||
const sections = tab.content?.as(SectionList).contents.array().as(MusicCarouselShelf, MusicDescriptionShelf, MusicShelf);
|
||||
const sections = tab.content?.as(YTNodes.SectionList).contents.array().as(YTNodes.MusicCarouselShelf, YTNodes.MusicDescriptionShelf, YTNodes.MusicShelf);
|
||||
|
||||
console.info('Sections:', sections);
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
Detailed documentation can be found [here](https://github.com/LuanRT/YouTube.js/blob/main/src/parser).
|
||||
|
||||
<!-- CONTRIBUTING -->
|
||||
@@ -693,4 +709,4 @@ Distributed under the [MIT](https://choosealicense.com/licenses/mit/) License.
|
||||
|
||||
<p align=" right">
|
||||
(<a href="#top">back to top</a>)
|
||||
</p>
|
||||
</p>
|
||||
|
||||
@@ -6,4 +6,6 @@ export * from './src/utils';
|
||||
export { YTNodes } from './src/parser/map';
|
||||
export { default as Parser } from './src/parser';
|
||||
export { default as Innertube } from './src/Innertube';
|
||||
export { default as Session } from './src/core/Session';
|
||||
export { default as Player } from './src/core/Player';
|
||||
export default Innertube;
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Innertube, UniversalCache } from 'youtubei.js';
|
||||
import { Innertube, UniversalCache, YTNodes } from 'youtubei.js';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache() });
|
||||
|
||||
const channel = await yt.getChannel('UCX6OQ3DkcsbYNE6H8uQQuVA');
|
||||
|
||||
console.info('Viewing channel:', channel.header.author.name);
|
||||
console.info('Family Safe:', channel.metadata.is_family_safe);
|
||||
if (channel.header?.is(YTNodes.C4TabbedHeader)) {
|
||||
console.info('Viewing channel:', channel?.header?.author.name);
|
||||
console.info('Family Safe:', channel.metadata.is_family_safe);
|
||||
}
|
||||
|
||||
const about = await channel.getAbout();
|
||||
|
||||
|
||||
@@ -1,31 +1,25 @@
|
||||
import { Innertube, UniversalCache } from 'youtubei.js';
|
||||
import { Innertube, UniversalCache, YTNodes } from 'youtubei.js';
|
||||
|
||||
import { LiveChatContinuation } from 'youtubei.js/dist/src/parser';
|
||||
|
||||
import LiveChat, { ChatAction, LiveMetadata } from 'youtubei.js/dist/src/parser/youtube/LiveChat';
|
||||
|
||||
import Video from 'youtubei.js/dist/src/parser/classes/Video';
|
||||
import AddChatItemAction from 'youtubei.js/dist/src/parser/classes/livechat/AddChatItemAction';
|
||||
import MarkChatItemAsDeletedAction from 'youtubei.js/dist/src/parser/classes/livechat/MarkChatItemAsDeletedAction';
|
||||
|
||||
import LiveChatTextMessage from 'youtubei.js/dist/src/parser/classes/livechat/items/LiveChatTextMessage';
|
||||
import LiveChatPaidMessage from 'youtubei.js/dist/src/parser/classes/livechat/items/LiveChatPaidMessage';
|
||||
import { ChatAction, LiveMetadata } from 'youtubei.js/dist/src/parser/youtube/LiveChat';
|
||||
|
||||
(async () => {
|
||||
const yt = await Innertube.create({ cache: new UniversalCache() });
|
||||
|
||||
|
||||
const search = await yt.search('Lofi girl live');
|
||||
const info = await yt.getInfo(search.videos[0].as(Video).id);
|
||||
const info = await yt.getInfo(search.videos[0].as(YTNodes.Video).id);
|
||||
|
||||
const livechat = info.getLiveChat();
|
||||
|
||||
const livechat = await info.getLiveChat();
|
||||
|
||||
livechat.on('start', (initial_data: LiveChatContinuation) => {
|
||||
/**
|
||||
* Initial info is what you see when you first open a Live Chat — this is; inital actions (pinned messages, top donations..), account's info and so on.
|
||||
*/
|
||||
|
||||
|
||||
console.info(`Hey ${initial_data.viewer_name || 'N/A'}, welcome to Live Chat!`);
|
||||
});
|
||||
|
||||
|
||||
livechat.on('chat-update', (action: ChatAction) => {
|
||||
/**
|
||||
* An action represents what is being added to
|
||||
@@ -35,28 +29,28 @@ import LiveChatPaidMessage from 'youtubei.js/dist/src/parser/classes/livechat/it
|
||||
* Below are a few examples of how this can be used.
|
||||
*/
|
||||
|
||||
if (action.is(AddChatItemAction)) {
|
||||
const item = action.as(AddChatItemAction).item;
|
||||
|
||||
if (action.is(YTNodes.AddChatItemAction)) {
|
||||
const item = action.as(YTNodes.AddChatItemAction).item;
|
||||
|
||||
if (!item)
|
||||
return console.info('Action did not have an item.', action);
|
||||
|
||||
|
||||
const hours = new Date(item.hasKey('timestamp') ? item.timestamp : Date.now()).toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
|
||||
|
||||
switch (item.type) {
|
||||
case 'LiveChatTextMessage':
|
||||
console.info(
|
||||
`${hours} - ${item.as(LiveChatTextMessage).author?.name.toString()}:\n` +
|
||||
`${item.as(LiveChatTextMessage).message.toString()}\n`
|
||||
`${hours} - ${item.as(YTNodes.LiveChatTextMessage).author?.name.toString()}:\n` +
|
||||
`${item.as(YTNodes.LiveChatTextMessage).message.toString()}\n`
|
||||
);
|
||||
break;
|
||||
case 'LiveChatPaidMessage':
|
||||
console.info(
|
||||
`${hours} - ${item.as(LiveChatPaidMessage).author.name.toString()}:\n` +
|
||||
`${item.as(LiveChatPaidMessage).purchase_amount}\n`
|
||||
`${hours} - ${item.as(YTNodes.LiveChatPaidMessage).author.name.toString()}:\n` +
|
||||
`${item.as(YTNodes.LiveChatPaidMessage).purchase_amount}\n`
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@@ -64,8 +58,8 @@ import LiveChatPaidMessage from 'youtubei.js/dist/src/parser/classes/livechat/it
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (action.is(MarkChatItemAsDeletedAction)) {
|
||||
|
||||
if (action.is(YTNodes.MarkChatItemAsDeletedAction)) {
|
||||
console.warn(`Message ${action.target_item_id} just got deleted and should be replaced with ${action.deleted_state_message.toString()}!`, '\n');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
import { Parser } from 'youtubei.js';
|
||||
|
||||
import SectionList from 'youtubei.js/dist/src/parser/classes/SectionList';
|
||||
import SingleColumnBrowseResults from 'youtubei.js/dist/src/parser/classes/SingleColumnBrowseResults';
|
||||
|
||||
import MusicVisualHeader from 'youtubei.js/dist/src/parser/classes/MusicVisualHeader';
|
||||
import MusicImmersiveHeader from 'youtubei.js/dist/src/parser/classes/MusicImmersiveHeader';
|
||||
import MusicCarouselShelf from 'youtubei.js/dist/src/parser/classes/MusicCarouselShelf';
|
||||
import MusicDescriptionShelf from 'youtubei.js/dist/src/parser/classes/MusicDescriptionShelf';
|
||||
import MusicShelf from 'youtubei.js/dist/src/parser/classes/MusicShelf';
|
||||
|
||||
import { Parser, YTNodes } from 'youtubei.js';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Artist page response from YouTube Music
|
||||
const data = readFileSync('./artist.json').toString();
|
||||
|
||||
const page = Parser.parseResponse(JSON.parse(data));
|
||||
|
||||
const header = page.header.item().as(MusicImmersiveHeader, MusicVisualHeader);
|
||||
const header = page.header?.item().as(YTNodes.MusicImmersiveHeader, YTNodes.MusicVisualHeader);
|
||||
|
||||
console.info('Header:', header);
|
||||
|
||||
@@ -24,14 +13,14 @@ console.info('Header:', header);
|
||||
// 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(SingleColumnBrowseResults).tabs.get({ selected: false });
|
||||
const tab = page.contents.item().as(YTNodes.SingleColumnBrowseResults).tabs.firstOfType(YTNodes.Tab);
|
||||
|
||||
if (!tab)
|
||||
throw new Error('Target tab not found');
|
||||
|
||||
if (!tab.content)
|
||||
throw new Error('Target tab appears to be empty');
|
||||
|
||||
const sections = tab.content?.as(SectionList).contents.array().as(MusicCarouselShelf, MusicDescriptionShelf, MusicShelf);
|
||||
|
||||
const sections = tab.content?.as(YTNodes.SectionList).contents.array().as(YTNodes.MusicCarouselShelf, YTNodes.MusicDescriptionShelf, YTNodes.MusicShelf);
|
||||
|
||||
console.info('Sections:', sections);
|
||||
2
index.ts
2
index.ts
@@ -23,4 +23,6 @@ export * from './src/utils';
|
||||
export { YTNodes } from './src/parser/map';
|
||||
export { default as Parser } from './src/parser';
|
||||
export { default as Innertube } from './src/Innertube';
|
||||
export { default as Session } from './src/core/Session';
|
||||
export { default as Player } from './src/core/Player';
|
||||
export default Innertube;
|
||||
439
package-lock.json
generated
439
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "2.3.3",
|
||||
"version": "2.5.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "youtubei.js",
|
||||
"version": "2.3.3",
|
||||
"version": "2.5.0",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/LuanRT"
|
||||
],
|
||||
@@ -106,9 +106,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.2.tgz",
|
||||
"integrity": "sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==",
|
||||
"version": "7.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz",
|
||||
"integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.20.2",
|
||||
@@ -385,9 +385,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.2.tgz",
|
||||
"integrity": "sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==",
|
||||
"version": "7.20.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz",
|
||||
"integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -1202,15 +1202,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@protobuf-ts/plugin": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.1.tgz",
|
||||
"integrity": "sha512-lacRdXJ9TkTbI28U0KApsnVqnxeq1aZftOdq6LNPQJaIzBrVRxrMkqnnGWGQFYe0Tr93OKeW4A2lLjTkn32CuA==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.2.tgz",
|
||||
"integrity": "sha512-rTPxaeKBfUar8ubKxbVdv4XL6AcGA0OOgHNHFyrfODP7Epy80omwuvgFJex1YpeNFJxm/FZXXj5Z+nHuhYEqJg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@protobuf-ts/plugin-framework": "^2.8.1",
|
||||
"@protobuf-ts/protoc": "^2.8.1",
|
||||
"@protobuf-ts/runtime": "^2.8.1",
|
||||
"@protobuf-ts/runtime-rpc": "^2.8.1",
|
||||
"@protobuf-ts/plugin-framework": "^2.8.2",
|
||||
"@protobuf-ts/protoc": "^2.8.2",
|
||||
"@protobuf-ts/runtime": "^2.8.2",
|
||||
"@protobuf-ts/runtime-rpc": "^2.8.2",
|
||||
"typescript": "^3.9"
|
||||
},
|
||||
"bin": {
|
||||
@@ -1219,12 +1219,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@protobuf-ts/plugin-framework": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.1.tgz",
|
||||
"integrity": "sha512-hfLoYIyxCI6Ro6LY1BltNBDcXWL+36SwnWR/hcF4ttPHLE3rMIpYbz4IwQsfeU2SKbBeGFhZv9rcnDJB22cXog==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.2.tgz",
|
||||
"integrity": "sha512-ivcJdNVB3Iee8044f8erZGBgmB6ZfQbbKyxRgDBXRVKYxsruLr432WcT5upw9autK9OnlSVLaebi8kDneFXd2g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@protobuf-ts/runtime": "^2.8.1",
|
||||
"@protobuf-ts/runtime": "^2.8.2",
|
||||
"typescript": "^3.9"
|
||||
}
|
||||
},
|
||||
@@ -1255,26 +1255,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@protobuf-ts/protoc": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.1.tgz",
|
||||
"integrity": "sha512-6fehuL9bS22zCgPBBlESZjnoA4fxAUkOjMcaFMJSlVpN6CDN2O+c/Mo1pCXaNDO7FAidMPj5yhz48Kws4kOXEA==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.2.tgz",
|
||||
"integrity": "sha512-1e+rOgp22ElyqRWunSc8bhatJcvRe90AGPceVn67IFYzybvfKl17vP1igHddeYkN0dzOucnOrwqn2v1jnDfE2w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"protoc": "protoc.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@protobuf-ts/runtime": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.1.tgz",
|
||||
"integrity": "sha512-D9M5hSumYCovIfNllt7N6ODh4q+LrjiMWtNETvooaf+a2XheZJ7kgjFlsFghti0CFWwtA//of4JXQfw9hU+cCw=="
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.2.tgz",
|
||||
"integrity": "sha512-PVxsH81y9kEbHldxxG/8Y3z2mTXWQytRl8zNS0mTPUjkEC+8GUX6gj6LsA8EFp25fAs9V0ruh+aNWmPccEI9MA=="
|
||||
},
|
||||
"node_modules/@protobuf-ts/runtime-rpc": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.1.tgz",
|
||||
"integrity": "sha512-hc+HJpoAu50by8aBS55UygcrzD8jAvRKWZMCRJ9XY3h9Gl2tciYysfzSH1SWtF6XOT/4b5CKnnmdMR3ad7uU5g==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.2.tgz",
|
||||
"integrity": "sha512-vum/Y7AXdUTWGFu7dke/jCSB9dV3Oo3iVPcce3j7KudpzzWarDkEGvXjKv3Y8zJPj5waToyxwBNSb7eo5Vw5WA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@protobuf-ts/runtime": "^2.8.1"
|
||||
"@protobuf-ts/runtime": "^2.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
@@ -1284,9 +1284,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sinonjs/commons": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.4.tgz",
|
||||
"integrity": "sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==",
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz",
|
||||
"integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"type-detect": "4.0.8"
|
||||
@@ -1302,9 +1302,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.1.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz",
|
||||
"integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==",
|
||||
"version": "7.1.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz",
|
||||
"integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.1.0",
|
||||
@@ -1416,9 +1416,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "17.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
|
||||
"integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
|
||||
"version": "17.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.14.tgz",
|
||||
"integrity": "sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/yargs-parser": "*"
|
||||
@@ -1431,14 +1431,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz",
|
||||
"integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
|
||||
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/type-utils": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/type-utils": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -1464,14 +1464,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz",
|
||||
"integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
|
||||
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1491,13 +1491,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz",
|
||||
"integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
|
||||
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0"
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -1508,13 +1508,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz",
|
||||
"integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz",
|
||||
"integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -1535,9 +1535,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz",
|
||||
"integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
|
||||
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -1548,13 +1548,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz",
|
||||
"integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
|
||||
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -1575,16 +1575,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz",
|
||||
"integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
|
||||
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@@ -1601,12 +1601,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz",
|
||||
"integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
|
||||
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1705,9 +1705,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
@@ -1941,9 +1941,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001430",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz",
|
||||
"integrity": "sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==",
|
||||
"version": "1.0.30001434",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
|
||||
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -1982,10 +1982,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ci-info": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
|
||||
"integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==",
|
||||
"dev": true
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz",
|
||||
"integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cjs-module-lexer": {
|
||||
"version": "1.2.2",
|
||||
@@ -2651,9 +2654,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.26.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
|
||||
"integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==",
|
||||
"version": "8.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
|
||||
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint/eslintrc": "^1.3.3",
|
||||
@@ -3166,9 +3169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "13.17.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
|
||||
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
|
||||
"version": "13.18.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
|
||||
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"type-fest": "^0.20.2"
|
||||
@@ -3827,9 +3830,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jest-pnp-resolver": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
|
||||
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
|
||||
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@@ -4133,10 +4136,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-sdsl": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
|
||||
"integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
|
||||
"dev": true
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
|
||||
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/js-sdsl"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
@@ -4236,9 +4243,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/linkedom": {
|
||||
"version": "0.14.19",
|
||||
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.19.tgz",
|
||||
"integrity": "sha512-sFNkQZlKBWpEaAcbsDIghTLE0hHbyvS6dZuM7IH+KTM09GaQ772PtDZAuFlN0oFgyAjUj8XS9FpoWSLmBjl8MA==",
|
||||
"version": "0.14.21",
|
||||
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.21.tgz",
|
||||
"integrity": "sha512-V+c0AAFMTVJA2iAhrdd+u44lL0TjL6hBenVB061VQ6BHqTAHtXw1v5F1/CHGKtwg0OHm+hrGbepb9ZSFJ7lJkg==",
|
||||
"dependencies": {
|
||||
"css-select": "^5.1.0",
|
||||
"cssom": "^0.5.0",
|
||||
@@ -4992,9 +4999,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/stack-utils": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz",
|
||||
"integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==",
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
|
||||
"integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^2.0.0"
|
||||
@@ -5307,9 +5314,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||
"version": "4.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
||||
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -5566,9 +5573,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.2.tgz",
|
||||
"integrity": "sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==",
|
||||
"version": "7.20.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz",
|
||||
"integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.20.2",
|
||||
@@ -5782,9 +5789,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.2.tgz",
|
||||
"integrity": "sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==",
|
||||
"version": "7.20.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz",
|
||||
"integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/plugin-syntax-async-generators": {
|
||||
@@ -6408,15 +6415,15 @@
|
||||
}
|
||||
},
|
||||
"@protobuf-ts/plugin": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.1.tgz",
|
||||
"integrity": "sha512-lacRdXJ9TkTbI28U0KApsnVqnxeq1aZftOdq6LNPQJaIzBrVRxrMkqnnGWGQFYe0Tr93OKeW4A2lLjTkn32CuA==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.8.2.tgz",
|
||||
"integrity": "sha512-rTPxaeKBfUar8ubKxbVdv4XL6AcGA0OOgHNHFyrfODP7Epy80omwuvgFJex1YpeNFJxm/FZXXj5Z+nHuhYEqJg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@protobuf-ts/plugin-framework": "^2.8.1",
|
||||
"@protobuf-ts/protoc": "^2.8.1",
|
||||
"@protobuf-ts/runtime": "^2.8.1",
|
||||
"@protobuf-ts/runtime-rpc": "^2.8.1",
|
||||
"@protobuf-ts/plugin-framework": "^2.8.2",
|
||||
"@protobuf-ts/protoc": "^2.8.2",
|
||||
"@protobuf-ts/runtime": "^2.8.2",
|
||||
"@protobuf-ts/runtime-rpc": "^2.8.2",
|
||||
"typescript": "^3.9"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -6429,12 +6436,12 @@
|
||||
}
|
||||
},
|
||||
"@protobuf-ts/plugin-framework": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.1.tgz",
|
||||
"integrity": "sha512-hfLoYIyxCI6Ro6LY1BltNBDcXWL+36SwnWR/hcF4ttPHLE3rMIpYbz4IwQsfeU2SKbBeGFhZv9rcnDJB22cXog==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.8.2.tgz",
|
||||
"integrity": "sha512-ivcJdNVB3Iee8044f8erZGBgmB6ZfQbbKyxRgDBXRVKYxsruLr432WcT5upw9autK9OnlSVLaebi8kDneFXd2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@protobuf-ts/runtime": "^2.8.1",
|
||||
"@protobuf-ts/runtime": "^2.8.2",
|
||||
"typescript": "^3.9"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -6447,23 +6454,23 @@
|
||||
}
|
||||
},
|
||||
"@protobuf-ts/protoc": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.1.tgz",
|
||||
"integrity": "sha512-6fehuL9bS22zCgPBBlESZjnoA4fxAUkOjMcaFMJSlVpN6CDN2O+c/Mo1pCXaNDO7FAidMPj5yhz48Kws4kOXEA==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.8.2.tgz",
|
||||
"integrity": "sha512-1e+rOgp22ElyqRWunSc8bhatJcvRe90AGPceVn67IFYzybvfKl17vP1igHddeYkN0dzOucnOrwqn2v1jnDfE2w==",
|
||||
"dev": true
|
||||
},
|
||||
"@protobuf-ts/runtime": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.1.tgz",
|
||||
"integrity": "sha512-D9M5hSumYCovIfNllt7N6ODh4q+LrjiMWtNETvooaf+a2XheZJ7kgjFlsFghti0CFWwtA//of4JXQfw9hU+cCw=="
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.8.2.tgz",
|
||||
"integrity": "sha512-PVxsH81y9kEbHldxxG/8Y3z2mTXWQytRl8zNS0mTPUjkEC+8GUX6gj6LsA8EFp25fAs9V0ruh+aNWmPccEI9MA=="
|
||||
},
|
||||
"@protobuf-ts/runtime-rpc": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.1.tgz",
|
||||
"integrity": "sha512-hc+HJpoAu50by8aBS55UygcrzD8jAvRKWZMCRJ9XY3h9Gl2tciYysfzSH1SWtF6XOT/4b5CKnnmdMR3ad7uU5g==",
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.8.2.tgz",
|
||||
"integrity": "sha512-vum/Y7AXdUTWGFu7dke/jCSB9dV3Oo3iVPcce3j7KudpzzWarDkEGvXjKv3Y8zJPj5waToyxwBNSb7eo5Vw5WA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@protobuf-ts/runtime": "^2.8.1"
|
||||
"@protobuf-ts/runtime": "^2.8.2"
|
||||
}
|
||||
},
|
||||
"@sinclair/typebox": {
|
||||
@@ -6473,9 +6480,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.4.tgz",
|
||||
"integrity": "sha512-RpmQdHVo8hCEHDVpO39zToS9jOhR6nw+/lQAzRNq9ErrGV9IeHM71XCn68svVl/euFeVW6BWX4p35gkhbOcSIQ==",
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz",
|
||||
"integrity": "sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-detect": "4.0.8"
|
||||
@@ -6491,9 +6498,9 @@
|
||||
}
|
||||
},
|
||||
"@types/babel__core": {
|
||||
"version": "7.1.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz",
|
||||
"integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==",
|
||||
"version": "7.1.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz",
|
||||
"integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/parser": "^7.1.0",
|
||||
@@ -6605,9 +6612,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/yargs": {
|
||||
"version": "17.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz",
|
||||
"integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==",
|
||||
"version": "17.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.14.tgz",
|
||||
"integrity": "sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/yargs-parser": "*"
|
||||
@@ -6620,14 +6627,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz",
|
||||
"integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz",
|
||||
"integrity": "sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/type-utils": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/type-utils": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -6637,53 +6644,53 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz",
|
||||
"integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.44.0.tgz",
|
||||
"integrity": "sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz",
|
||||
"integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
|
||||
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0"
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz",
|
||||
"integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz",
|
||||
"integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/utils": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"@typescript-eslint/utils": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz",
|
||||
"integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
|
||||
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz",
|
||||
"integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
|
||||
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/visitor-keys": "5.42.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/visitor-keys": "5.44.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -6692,28 +6699,28 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz",
|
||||
"integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
|
||||
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.42.0",
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/typescript-estree": "5.42.0",
|
||||
"@typescript-eslint/scope-manager": "5.44.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"@typescript-eslint/typescript-estree": "5.44.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz",
|
||||
"integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==",
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
|
||||
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.42.0",
|
||||
"@typescript-eslint/types": "5.44.0",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
@@ -6774,9 +6781,9 @@
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
@@ -6952,9 +6959,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001430",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz",
|
||||
"integrity": "sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==",
|
||||
"version": "1.0.30001434",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz",
|
||||
"integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
@@ -6974,9 +6981,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"ci-info": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz",
|
||||
"integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==",
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz",
|
||||
"integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==",
|
||||
"dev": true
|
||||
},
|
||||
"cjs-module-lexer": {
|
||||
@@ -7372,9 +7379,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.26.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
|
||||
"integrity": "sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==",
|
||||
"version": "8.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz",
|
||||
"integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.3.3",
|
||||
@@ -7768,9 +7775,9 @@
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"version": "13.17.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
|
||||
"integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
|
||||
"version": "13.18.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz",
|
||||
"integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-fest": "^0.20.2"
|
||||
@@ -8252,9 +8259,9 @@
|
||||
}
|
||||
},
|
||||
"jest-pnp-resolver": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
|
||||
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
|
||||
"integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
@@ -8499,9 +8506,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"js-sdsl": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
|
||||
"integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
|
||||
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-tokens": {
|
||||
@@ -8578,9 +8585,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"linkedom": {
|
||||
"version": "0.14.19",
|
||||
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.19.tgz",
|
||||
"integrity": "sha512-sFNkQZlKBWpEaAcbsDIghTLE0hHbyvS6dZuM7IH+KTM09GaQ772PtDZAuFlN0oFgyAjUj8XS9FpoWSLmBjl8MA==",
|
||||
"version": "0.14.21",
|
||||
"resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.14.21.tgz",
|
||||
"integrity": "sha512-V+c0AAFMTVJA2iAhrdd+u44lL0TjL6hBenVB061VQ6BHqTAHtXw1v5F1/CHGKtwg0OHm+hrGbepb9ZSFJ7lJkg==",
|
||||
"requires": {
|
||||
"css-select": "^5.1.0",
|
||||
"cssom": "^0.5.0",
|
||||
@@ -9131,9 +9138,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"stack-utils": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz",
|
||||
"integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==",
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
|
||||
"integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"escape-string-regexp": "^2.0.0"
|
||||
@@ -9342,9 +9349,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||
"version": "4.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
||||
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
||||
"dev": true
|
||||
},
|
||||
"uhyphen": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "youtubei.js",
|
||||
"version": "2.3.3",
|
||||
"description": "Full-featured wrapper around YouTube's private API.",
|
||||
"version": "2.5.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",
|
||||
"types": "./dist",
|
||||
@@ -71,6 +71,7 @@
|
||||
"youtube-dl",
|
||||
"youtube-downloader",
|
||||
"youtube-music",
|
||||
"youtube-studio",
|
||||
"innertubeapi",
|
||||
"innertube",
|
||||
"unofficial",
|
||||
|
||||
@@ -24,11 +24,11 @@ import { YTNodeConstructor } from './helpers';
|
||||
|
||||
${import_list.join('\n')}
|
||||
|
||||
const map: Record<string, YTNodeConstructor> = {
|
||||
export const YTNodes = {
|
||||
${json.join(',\n ')}
|
||||
};
|
||||
|
||||
export const YTNodes = map;
|
||||
const map: Record<string, YTNodeConstructor> = YTNodes;
|
||||
|
||||
/**
|
||||
* @param name - Name of the node to be parsed
|
||||
|
||||
@@ -17,10 +17,10 @@ import { ActionsResponse } from './core/Actions';
|
||||
import Feed from './core/Feed';
|
||||
import YTMusic from './core/Music';
|
||||
import Studio from './core/Studio';
|
||||
import HomeFeed from './parser/youtube/HomeFeed';
|
||||
import AccountManager from './core/AccountManager';
|
||||
import PlaylistManager from './core/PlaylistManager';
|
||||
import InteractionManager from './core/InteractionManager';
|
||||
import FilterableFeed from './core/FilterableFeed';
|
||||
import TabbedFeed from './core/TabbedFeed';
|
||||
import Constants from './utils/Constants';
|
||||
import Proto from './proto/index';
|
||||
@@ -69,7 +69,7 @@ class Innertube {
|
||||
async getInfo(video_id: string, client?: InnerTubeClient) {
|
||||
const cpn = generateRandomString(16);
|
||||
|
||||
const initial_info = await this.actions.getVideoInfo(video_id, cpn, client);
|
||||
const initial_info = this.actions.getVideoInfo(video_id, cpn, client);
|
||||
const continuation = this.actions.execute('/next', { videoId: video_id });
|
||||
|
||||
const response = await Promise.all([ initial_info, continuation ]);
|
||||
@@ -155,7 +155,7 @@ class Innertube {
|
||||
*/
|
||||
async getHomeFeed() {
|
||||
const response = await this.actions.execute('/browse', { browseId: 'FEwhat_to_watch' });
|
||||
return new FilterableFeed(this.actions, response.data);
|
||||
return new HomeFeed(this.actions, response.data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,9 +212,10 @@ class Innertube {
|
||||
/**
|
||||
* Retrieves unseen notifications count.
|
||||
*/
|
||||
async getUnseenNotificationsCount() {
|
||||
async getUnseenNotificationsCount(): Promise<number> {
|
||||
const response = await this.actions.execute('/notification/get_unseen_count');
|
||||
return response.data.unseenCount;
|
||||
// TODO: properly parse this
|
||||
return response.data?.unseenCount || response.data?.actions?.[0].updateNotificationsUnseenCountAction?.unseenCount || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ class AccountManager {
|
||||
*/
|
||||
editName: (new_name: string) => {
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
return this.#actions.execute('/channel/edit_name', {
|
||||
givenName: new_name,
|
||||
@@ -34,7 +34,7 @@ class AccountManager {
|
||||
*/
|
||||
editDescription: (new_description: string) => {
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
return this.#actions.execute('/channel/edit_description', {
|
||||
givenDescription: new_description,
|
||||
@@ -53,7 +53,7 @@ class AccountManager {
|
||||
*/
|
||||
async getInfo() {
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const response = await this.#actions.execute('/account/accounts_list', { client: 'ANDROID' });
|
||||
return new AccountInfo(response);
|
||||
|
||||
@@ -49,7 +49,7 @@ class Actions {
|
||||
referer: 'https://www.youtube.com',
|
||||
currentUrl: `/watch?v=${id}`,
|
||||
autonavState: 'STATE_OFF',
|
||||
signatureTimestamp: this.#session.player.sts,
|
||||
signatureTimestamp: this.#session.player?.sts || 0,
|
||||
autoCaptionsDefaultOn: false,
|
||||
html5Preference: 'HTML5_PREF_WANTS',
|
||||
lactMilliseconds: '-1'
|
||||
@@ -122,7 +122,7 @@ class Actions {
|
||||
|
||||
if (Reflect.has(data, 'browseId')) {
|
||||
if (this.#needsLogin(data.browseId) && !this.#session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
}
|
||||
|
||||
if (Reflect.has(data, 'override_endpoint'))
|
||||
@@ -166,7 +166,7 @@ class Actions {
|
||||
|
||||
const response = await this.#session.http.fetch(endpoint, {
|
||||
method: 'POST',
|
||||
body: args?.protobuf ? data : JSON.stringify(data),
|
||||
body: args?.protobuf ? data : JSON.stringify((data || {})),
|
||||
headers: {
|
||||
'Content-Type': args?.protobuf ?
|
||||
'application/x-protobuf' :
|
||||
@@ -188,6 +188,7 @@ class Actions {
|
||||
'FEsubscriptions',
|
||||
'FEmusic_listening_review',
|
||||
'FEmusic_library_landing',
|
||||
'SPaccount_overview',
|
||||
'SPaccount_notifications',
|
||||
'SPaccount_privacy',
|
||||
'SPtime_watched'
|
||||
|
||||
@@ -29,6 +29,7 @@ import AppendContinuationItemsAction from '../parser/classes/actions/AppendConti
|
||||
import ContinuationItem from '../parser/classes/ContinuationItem';
|
||||
|
||||
import Video from '../parser/classes/Video';
|
||||
import ReelItem from '../parser/classes/ReelItem';
|
||||
|
||||
class Feed {
|
||||
#page: ParsedResponse;
|
||||
@@ -63,9 +64,10 @@ class Feed {
|
||||
* Get all videos on a given page via memo
|
||||
*/
|
||||
static getVideosFromMemo(memo: Memo) {
|
||||
return memo.getType<Video | GridVideo | CompactVideo | PlaylistVideo | PlaylistPanelVideo | WatchCardCompactVideo>([
|
||||
return memo.getType<Video | GridVideo | ReelItem | CompactVideo | PlaylistVideo | PlaylistPanelVideo | WatchCardCompactVideo>([
|
||||
Video,
|
||||
GridVideo,
|
||||
ReelItem,
|
||||
CompactVideo,
|
||||
PlaylistVideo,
|
||||
PlaylistPanelVideo,
|
||||
@@ -115,7 +117,7 @@ class Feed {
|
||||
/**
|
||||
* Returns contents from the page.
|
||||
*/
|
||||
get contents() {
|
||||
get page_contents() {
|
||||
const tab_content = this.#memo.getType(Tab)?.[0]?.content;
|
||||
const reload_continuation_items = this.#memo.getType(ReloadContinuationItemsCommand)?.[0];
|
||||
const append_continuation_items = this.#memo.getType(AppendContinuationItemsAction)?.[0];
|
||||
|
||||
@@ -13,7 +13,7 @@ class FilterableFeed extends Feed {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filters for the feed
|
||||
* Returns the filter chips.
|
||||
*/
|
||||
get filter_chips() {
|
||||
if (this.#chips)
|
||||
@@ -30,6 +30,9 @@ class FilterableFeed extends Feed {
|
||||
return this.#chips || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available filters.
|
||||
*/
|
||||
get filters() {
|
||||
return this.filter_chips.map((chip) => chip.text.toString()) || [];
|
||||
}
|
||||
@@ -42,9 +45,7 @@ class FilterableFeed extends Feed {
|
||||
|
||||
if (typeof filter === 'string') {
|
||||
if (!this.filters.includes(filter))
|
||||
throw new InnertubeError('Filter not found', {
|
||||
available_filters: this.filters
|
||||
});
|
||||
throw new InnertubeError('Filter not found', { available_filters: this.filters });
|
||||
target_filter = this.filter_chips.find((chip) => chip.text.toString() === filter);
|
||||
} else if (filter.type === 'ChipCloudChip') {
|
||||
target_filter = filter;
|
||||
@@ -54,6 +55,7 @@ class FilterableFeed extends Feed {
|
||||
|
||||
if (!target_filter)
|
||||
throw new InnertubeError('Filter not found');
|
||||
|
||||
if (target_filter.is_selected)
|
||||
return this;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class InteractionManager {
|
||||
throwIfMissing({ video_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const action = await this.#actions.execute('/like/like', {
|
||||
client: 'ANDROID',
|
||||
@@ -37,7 +37,7 @@ class InteractionManager {
|
||||
throwIfMissing({ video_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const action = await this.#actions.execute('/like/dislike', {
|
||||
client: 'ANDROID',
|
||||
@@ -57,7 +57,7 @@ class InteractionManager {
|
||||
throwIfMissing({ video_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const action = await this.#actions.execute('/like/removelike', {
|
||||
client: 'ANDROID',
|
||||
@@ -77,7 +77,7 @@ class InteractionManager {
|
||||
throwIfMissing({ channel_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const action = await this.#actions.execute('/subscription/subscribe', {
|
||||
client: 'ANDROID',
|
||||
@@ -96,7 +96,7 @@ class InteractionManager {
|
||||
throwIfMissing({ channel_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const action = await this.#actions.execute('/subscription/unsubscribe', {
|
||||
client: 'ANDROID',
|
||||
@@ -116,7 +116,7 @@ class InteractionManager {
|
||||
throwIfMissing({ video_id, text });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const action = await this.#actions.execute('/comment/create_comment', {
|
||||
client: 'ANDROID',
|
||||
@@ -163,7 +163,7 @@ class InteractionManager {
|
||||
throwIfMissing({ channel_id, type });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new Error('You are not signed in');
|
||||
throw new Error('You must be signed in to perform this operation.');
|
||||
|
||||
const pref_types = {
|
||||
PERSONALIZED: 1,
|
||||
|
||||
@@ -61,7 +61,7 @@ class Music {
|
||||
videoId: video_id,
|
||||
playbackContext: {
|
||||
contentPlaybackContext: {
|
||||
signatureTimestamp: this.#session.player.sts
|
||||
signatureTimestamp: this.#session.player?.sts || 0
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -89,7 +89,7 @@ class Music {
|
||||
client: 'YTMUSIC',
|
||||
playbackContext: {
|
||||
contentPlaybackContext: {
|
||||
signatureTimestamp: this.#session.player.sts
|
||||
signatureTimestamp: this.#session.player?.sts || 0
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ class PlaylistManager {
|
||||
throwIfMissing({ title, video_ids });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const response = await this.#actions.execute('/playlist/create', {
|
||||
title,
|
||||
@@ -44,7 +44,7 @@ class PlaylistManager {
|
||||
throwIfMissing({ playlist_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const response = await this.#actions.execute('playlist/delete', { playlistId: playlist_id });
|
||||
|
||||
@@ -65,7 +65,7 @@ class PlaylistManager {
|
||||
throwIfMissing({ playlist_id, video_ids });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const response = await this.#actions.execute('/browse/edit_playlist', {
|
||||
playlistId: playlist_id,
|
||||
@@ -91,7 +91,7 @@ class PlaylistManager {
|
||||
throwIfMissing({ playlist_id, video_ids });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const info = await this.#actions.execute('/browse', {
|
||||
browseId: `VL${playlist_id}`,
|
||||
@@ -150,7 +150,7 @@ class PlaylistManager {
|
||||
throwIfMissing({ playlist_id, moved_video_id, predecessor_video_id });
|
||||
|
||||
if (!this.#actions.session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const info = await this.#actions.execute('/browse', {
|
||||
browseId: `VL${playlist_id}`,
|
||||
|
||||
@@ -20,6 +20,10 @@ export interface Context {
|
||||
hl: string;
|
||||
gl: string;
|
||||
remoteHost: string;
|
||||
screenDensityFloat: number;
|
||||
screenHeightPoints: number;
|
||||
screenPixelDensity: number;
|
||||
screenWidthPoints: number;
|
||||
visitorData: string;
|
||||
userAgent: string;
|
||||
clientName: string;
|
||||
@@ -52,6 +56,7 @@ export interface Context {
|
||||
|
||||
export interface SessionOptions {
|
||||
lang?: string;
|
||||
account_index?: number;
|
||||
device_category?: DeviceCategory;
|
||||
client_type?: ClientType;
|
||||
timezone?: string;
|
||||
@@ -64,6 +69,7 @@ export default class Session extends EventEmitterLike {
|
||||
#api_version;
|
||||
#key;
|
||||
#context;
|
||||
#account_index;
|
||||
#player;
|
||||
|
||||
oauth;
|
||||
@@ -72,9 +78,10 @@ export default class Session extends EventEmitterLike {
|
||||
actions;
|
||||
cache;
|
||||
|
||||
constructor(context: Context, api_key: string, api_version: string, player: Player, cookie?: string, fetch?: FetchFunction, cache?: UniversalCache) {
|
||||
constructor(context: Context, api_key: string, api_version: string, account_index: number, player?: Player, cookie?: string, fetch?: FetchFunction, cache?: UniversalCache) {
|
||||
super();
|
||||
this.#context = context;
|
||||
this.#account_index = account_index;
|
||||
this.#key = api_key;
|
||||
this.#api_version = api_version;
|
||||
this.#player = player;
|
||||
@@ -103,12 +110,20 @@ export default class Session extends EventEmitterLike {
|
||||
}
|
||||
|
||||
static async create(options: SessionOptions = {}) {
|
||||
const { context, api_key, api_version } = await Session.getSessionData(options.lang, options.device_category, options.client_type, options.timezone, options.fetch);
|
||||
return new Session(context, api_key, api_version, await Player.create(options.cache, options.fetch), options.cookie, options.fetch, options.cache);
|
||||
const { context, api_key, api_version, account_index } = await Session.getSessionData(
|
||||
options.lang,
|
||||
options.account_index,
|
||||
options.device_category,
|
||||
options.client_type,
|
||||
options.timezone,
|
||||
options.fetch
|
||||
);
|
||||
return new Session(context, api_key, api_version, account_index, await Player.create(options.cache, options.fetch), options.cookie, options.fetch, options.cache);
|
||||
}
|
||||
|
||||
static async getSessionData(
|
||||
lang = 'en-US',
|
||||
account_index = 0,
|
||||
device_category: DeviceCategory = 'desktop',
|
||||
client_name: ClientType = ClientType.WEB,
|
||||
tz: string = Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
@@ -144,6 +159,10 @@ export default class Session extends EventEmitterLike {
|
||||
hl: device_info[0],
|
||||
gl: device_info[2],
|
||||
remoteHost: device_info[3],
|
||||
screenDensityFloat: 1,
|
||||
screenHeightPoints: 720,
|
||||
screenPixelDensity: 1,
|
||||
screenWidthPoints: 1280,
|
||||
visitorData: device_info[13],
|
||||
userAgent: device_info[14],
|
||||
clientName: client_name,
|
||||
@@ -169,7 +188,7 @@ export default class Session extends EventEmitterLike {
|
||||
}
|
||||
};
|
||||
|
||||
return { context, api_key, api_version };
|
||||
return { context, api_key, api_version, account_index };
|
||||
}
|
||||
|
||||
async signIn(credentials?: Credentials): Promise<void> {
|
||||
@@ -205,7 +224,7 @@ export default class Session extends EventEmitterLike {
|
||||
|
||||
async signOut() {
|
||||
if (!this.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const response = await this.oauth.revokeCredentials();
|
||||
this.logged_in = false;
|
||||
@@ -229,6 +248,10 @@ export default class Session extends EventEmitterLike {
|
||||
return this.#context.client.clientName;
|
||||
}
|
||||
|
||||
get account_index() {
|
||||
return this.#account_index;
|
||||
}
|
||||
|
||||
get context() {
|
||||
return this.#context;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class Studio {
|
||||
*/
|
||||
async setThumbnail(video_id: string, buffer: Uint8Array): Promise<ApiResponse> {
|
||||
if (!this.#session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
if (!video_id || !buffer)
|
||||
throw new MissingParamError('One or more parameters are missing.');
|
||||
@@ -83,7 +83,7 @@ class Studio {
|
||||
*/
|
||||
async updateVideoMetadata(video_id: string, metadata: VideoMetadata) {
|
||||
if (!this.#session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const payload = Proto.encodeVideoMetadataPayload(video_id, metadata);
|
||||
|
||||
@@ -105,7 +105,7 @@ class Studio {
|
||||
*/
|
||||
async upload(file: BodyInit, metadata: UploadedVideoMetadata = {}): Promise<ApiResponse> {
|
||||
if (!this.#session.logged_in)
|
||||
throw new InnertubeError('You are not signed in');
|
||||
throw new InnertubeError('You must be signed in to perform this operation.');
|
||||
|
||||
const initial_data = await this.#getInitialUploadData();
|
||||
const upload_result = await this.#uploadVideo(initial_data.upload_url, file);
|
||||
|
||||
13
src/parser/classes/CarouselHeader.ts
Normal file
13
src/parser/classes/CarouselHeader.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import Parser from '..';
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
export default class CarouselHeader extends YTNode {
|
||||
static type = 'CarouselHeader';
|
||||
|
||||
contents: YTNode[];
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.contents = Parser.parseArray(data.contents);
|
||||
}
|
||||
}
|
||||
23
src/parser/classes/CarouselItem.ts
Normal file
23
src/parser/classes/CarouselItem.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import Parser from '..';
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
|
||||
export default class CarouselItem extends YTNode {
|
||||
static type = 'CarouselItem';
|
||||
|
||||
items: YTNode[];
|
||||
background_color: string;
|
||||
layout_style: string;
|
||||
pagination_thumbnails: Thumbnail[];
|
||||
paginator_alignment: string;
|
||||
|
||||
constructor (data: any) {
|
||||
super();
|
||||
this.items = Parser.parseArray(data.carouselItems);
|
||||
this.background_color = data.backgroundColor;
|
||||
this.layout_style = data.layoutStyle;
|
||||
this.pagination_thumbnails = Thumbnail.fromResponse(data.paginationThumbnails);
|
||||
this.paginator_alignment = data.paginatorAlignment;
|
||||
}
|
||||
}
|
||||
25
src/parser/classes/CompactStation.ts
Normal file
25
src/parser/classes/CompactStation.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
|
||||
export default class CompactStation extends YTNode {
|
||||
static type = 'CompactStation';
|
||||
|
||||
title: Text;
|
||||
description: Text;
|
||||
video_count: Text;
|
||||
endpoint: NavigationEndpoint;
|
||||
thumbnail: Thumbnail[];
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
|
||||
this.title = new Text(data.title);
|
||||
this.description = new Text(data.description);
|
||||
this.video_count = new Text(data.videoCountText);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
|
||||
}
|
||||
}
|
||||
36
src/parser/classes/DefaultPromoPanel.ts
Normal file
36
src/parser/classes/DefaultPromoPanel.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import Parser from '..';
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
|
||||
export default class DefaultPromoPanel extends YTNode {
|
||||
static type = 'DefaultPromoPanel';
|
||||
|
||||
title: Text;
|
||||
description: Text;
|
||||
endpoint: NavigationEndpoint;
|
||||
large_form_factor_background_thumbnail;
|
||||
small_form_factor_background_thumbnail;
|
||||
scrim_color_values: number[];
|
||||
min_panel_display_duration_ms: number;
|
||||
min_video_play_duration_ms: number;
|
||||
scrim_duration: number;
|
||||
metadata_order: string;
|
||||
panel_layout: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.title = new Text(data.title);
|
||||
this.description = new Text(data.description);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.large_form_factor_background_thumbnail = Parser.parseItem(data.largeFormFactorBackgroundThumbnail);
|
||||
this.small_form_factor_background_thumbnail = Parser.parseItem(data.smallFormFactorBackgroundThumbnail);
|
||||
this.scrim_color_values = data.scrimColorValues;
|
||||
this.min_panel_display_duration_ms = data.minPanelDisplayDurationMs;
|
||||
this.min_video_play_duration_ms = data.minVideoPlayDurationMs;
|
||||
this.scrim_duration = data.scrimDuration;
|
||||
this.metadata_order = data.metadataOrder;
|
||||
this.panel_layout = data.panelLayout;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
import Parser from '../index';
|
||||
import { YTNode } from '../helpers';
|
||||
import ChipCloudChip from './ChipCloudChip';
|
||||
|
||||
class FeedFilterChipBar extends YTNode {
|
||||
export default class FeedFilterChipBar extends YTNode {
|
||||
static type = 'FeedFilterChipBar';
|
||||
|
||||
contents;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.contents = Parser.parse(data.contents);
|
||||
this.contents = Parser.parseArray<ChipCloudChip>(data.contents, ChipCloudChip);
|
||||
}
|
||||
}
|
||||
|
||||
export default FeedFilterChipBar;
|
||||
}
|
||||
13
src/parser/classes/GameCard.ts
Normal file
13
src/parser/classes/GameCard.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import Parser from '..';
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
export default class GameCard extends YTNode {
|
||||
static type = 'GameCard';
|
||||
|
||||
game;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.game = Parser.parseItem(data.game);
|
||||
}
|
||||
}
|
||||
24
src/parser/classes/GameDetails.ts
Normal file
24
src/parser/classes/GameDetails.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
|
||||
export default class GameDetails extends YTNode {
|
||||
static type = 'GameDetails';
|
||||
|
||||
title: Text;
|
||||
box_art: Thumbnail[];
|
||||
box_art_overlay_text: Text;
|
||||
endpoint: NavigationEndpoint;
|
||||
is_official_box_art: boolean;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.title = new Text(data.title);
|
||||
this.box_art = Thumbnail.fromResponse(data.boxArt);
|
||||
this.box_art_overlay_text = new Text(data.boxArtOverlayText);
|
||||
this.endpoint = new NavigationEndpoint(data.endpoint);
|
||||
this.is_official_box_art = data.isOfficialBoxArt;
|
||||
}
|
||||
}
|
||||
36
src/parser/classes/InteractiveTabbedHeader.ts
Normal file
36
src/parser/classes/InteractiveTabbedHeader.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import Parser from '..';
|
||||
import { ObservedArray, YTNode } from '../helpers';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import SubscribeButton from './SubscribeButton';
|
||||
import MetadataBadge from './MetadataBadge';
|
||||
import Button from './Button';
|
||||
|
||||
export default class InteractiveTabbedHeader extends YTNode {
|
||||
static type = 'InteractiveTabbedHeader';
|
||||
|
||||
header_type: string;
|
||||
title: Text;
|
||||
description: Text;
|
||||
metadata: Text;
|
||||
badges: MetadataBadge[];
|
||||
box_art: Thumbnail[];
|
||||
banner: Thumbnail[];
|
||||
buttons: ObservedArray<SubscribeButton | Button>;
|
||||
auto_generated: Text;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
|
||||
this.header_type = data.type;
|
||||
this.title = new Text(data.title);
|
||||
this.description = new Text(data.description);
|
||||
this.metadata = new Text(data.metadata);
|
||||
this.badges = Parser.parseArray<MetadataBadge>(data.badges, MetadataBadge);
|
||||
this.box_art = Thumbnail.fromResponse(data.boxArt);
|
||||
this.banner = Thumbnail.fromResponse(data.banner);
|
||||
this.buttons = Parser.parseArray<SubscribeButton | Button>(data.buttons, [ SubscribeButton, Button ]);
|
||||
this.auto_generated = new Text(data.autoGenerated);
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,18 @@ import ItemSectionHeader from './ItemSectionHeader';
|
||||
|
||||
import { YTNode } from '../helpers';
|
||||
import ItemSectionTabbedHeader from './ItemSectionTabbedHeader';
|
||||
import CommentsHeader from './comments/CommentsHeader';
|
||||
|
||||
class ItemSection extends YTNode {
|
||||
static type = 'ItemSection';
|
||||
|
||||
header: ItemSectionHeader | ItemSectionTabbedHeader | null;
|
||||
header: CommentsHeader | ItemSectionHeader | ItemSectionTabbedHeader | null;
|
||||
contents;
|
||||
target_id;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.header = Parser.parseItem<ItemSectionHeader | ItemSectionTabbedHeader>(data.header, [ ItemSectionHeader, ItemSectionTabbedHeader ]);
|
||||
this.header = Parser.parseItem<CommentsHeader | ItemSectionHeader | ItemSectionTabbedHeader>(data.header);
|
||||
this.contents = Parser.parse(data.contents, true);
|
||||
|
||||
if (data.targetId || data.sectionIdentifier) {
|
||||
|
||||
@@ -76,6 +76,8 @@ class NavigationEndpoint extends YTNode {
|
||||
return '/browse';
|
||||
case 'watchEndpoint':
|
||||
return '/player';
|
||||
case 'searchEndpoint':
|
||||
return '/search';
|
||||
case 'watchPlaylistEndpoint':
|
||||
return '/next';
|
||||
case 'liveChatItemContextMenuEndpoint':
|
||||
|
||||
13
src/parser/classes/PlaylistCustomThumbnail.ts
Normal file
13
src/parser/classes/PlaylistCustomThumbnail.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { YTNode } from '../helpers';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
|
||||
export default class PlaylistCustomThumbnail extends YTNode {
|
||||
static type = 'PlaylistCustomThumbnail';
|
||||
|
||||
thumbnail: Thumbnail[];
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.thumbnail = Thumbnail.fromResponse(data.thumbnail);
|
||||
}
|
||||
}
|
||||
26
src/parser/classes/RecognitionShelf.ts
Normal file
26
src/parser/classes/RecognitionShelf.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import Parser from '..';
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
import Button from './Button';
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
|
||||
export default class RecognitionShelf extends YTNode {
|
||||
static type = 'RecognitionShelf';
|
||||
|
||||
title: Text;
|
||||
subtitle: Text;
|
||||
avatars: Thumbnail[];
|
||||
button: Button | null;
|
||||
surface: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
|
||||
this.title = new Text(data.title);
|
||||
this.subtitle = new Text(data.subtitle);
|
||||
this.avatars = data.avatars.map((avatar: any) => new Thumbnail(avatar));
|
||||
this.button = Parser.parseItem<Button>(data.button, Button);
|
||||
this.surface = data.surface;
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ class RichGrid extends YTNode {
|
||||
super();
|
||||
// XXX: we don't parse the masthead since it is usually an advertisement
|
||||
// XXX: reflowOptions aren't parsed, I think its only used internally for layout
|
||||
this.header = Parser.parse(data.header);
|
||||
this.contents = Parser.parse(data.contents);
|
||||
this.header = Parser.parseItem(data.header);
|
||||
this.contents = Parser.parseArray(data.contents);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ class RichItem extends YTNode {
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
// TODO: check this
|
||||
this.content = Parser.parse(data.content);
|
||||
this.content = Parser.parseItem(data.content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@ class RichListHeader extends YTNode {
|
||||
static type = 'RichListHeader';
|
||||
|
||||
title: Text;
|
||||
subtitle: Text;
|
||||
title_style: string | undefined;
|
||||
icon_type: string;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.title = new Text(data.title);
|
||||
this.icon_type = data.icon.iconType;
|
||||
this.subtitle = new Text(data.subtitle);
|
||||
this.title_style = data?.titleStyle?.style;
|
||||
this.icon_type = data?.icon?.iconType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import { YTNode } from '../helpers';
|
||||
class RichSection extends YTNode {
|
||||
static type = 'RichSection';
|
||||
|
||||
contents;
|
||||
content;
|
||||
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.contents = Parser.parse(data.content);
|
||||
this.content = Parser.parseItem(data.content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class RichShelf extends YTNode {
|
||||
constructor(data: any) {
|
||||
super();
|
||||
this.title = new Text(data.title);
|
||||
this.contents = Parser.parse(data.contents);
|
||||
this.contents = Parser.parseArray(data.contents);
|
||||
this.endpoint = data.endpoint ? new NavigationEndpoint(data.endpoint) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ class SectionList extends YTNode {
|
||||
this.target_id = data.targetId;
|
||||
}
|
||||
|
||||
// TODO: this should be Parser#parseArray
|
||||
this.contents = Parser.parse(data.contents);
|
||||
|
||||
if (data.continuations) {
|
||||
|
||||
15
src/parser/classes/ThumbnailLandscapePortrait.ts
Normal file
15
src/parser/classes/ThumbnailLandscapePortrait.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { YTNode } from '../helpers';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
|
||||
export default class ThumbnailLandscapePortrait extends YTNode {
|
||||
static type = 'ThumbnailLandscapePortrait';
|
||||
|
||||
landscape: Thumbnail[];
|
||||
portrait: Thumbnail[];
|
||||
|
||||
constructor (data: any) {
|
||||
super();
|
||||
this.landscape = Thumbnail.fromResponse(data.landscape);
|
||||
this.portrait = Thumbnail.fromResponse(data.portrait);
|
||||
}
|
||||
}
|
||||
27
src/parser/classes/TopicChannelDetails.ts
Normal file
27
src/parser/classes/TopicChannelDetails.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import Parser from '..';
|
||||
import { YTNode } from '../helpers';
|
||||
|
||||
import Text from './misc/Text';
|
||||
import Thumbnail from './misc/Thumbnail';
|
||||
import NavigationEndpoint from './NavigationEndpoint';
|
||||
import SubscribeButton from './SubscribeButton';
|
||||
|
||||
export default class TopicChannelDetails extends YTNode {
|
||||
static type = 'TopicChannelDetails';
|
||||
|
||||
title: Text;
|
||||
avatar: Thumbnail[];
|
||||
subtitle: Text;
|
||||
subscribe_button: SubscribeButton | null;
|
||||
endpoint: NavigationEndpoint;
|
||||
|
||||
constructor (data: any) {
|
||||
super();
|
||||
|
||||
this.title = new Text(data.title);
|
||||
this.avatar = Thumbnail.fromResponse(data.thumbnail);
|
||||
this.subtitle = new Text(data.title);
|
||||
this.subscribe_button = Parser.parseItem<SubscribeButton>(data.subscribeButton, SubscribeButton);
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
}
|
||||
}
|
||||
9
src/parser/classes/VideoCard.ts
Normal file
9
src/parser/classes/VideoCard.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import Video from './Video';
|
||||
|
||||
export default class VideoCard extends Video {
|
||||
static type = 'VideoCard';
|
||||
|
||||
constructor(data: any) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ class WatchCardHeroVideo extends YTNode {
|
||||
this.endpoint = new NavigationEndpoint(data.navigationEndpoint);
|
||||
this.call_to_action_button = Parser.parse(data.callToActionButton);
|
||||
this.hero_image = Parser.parse(data.heroImage);
|
||||
this.label = data.accessibility.accessibilityData.label;
|
||||
this.label = data.lengthText.accessibility.accessibilityData.label;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Player from '../../../core/Player';
|
||||
import { InnertubeError } from '../../../utils/Utils';
|
||||
|
||||
class Format {
|
||||
itag: string;
|
||||
@@ -73,7 +74,8 @@ class Format {
|
||||
* Decipher the streaming url of the format.
|
||||
* @returns Deciphered URL.
|
||||
*/
|
||||
decipher(player: Player): string {
|
||||
decipher(player: Player | undefined): string {
|
||||
if (!player) throw new InnertubeError('Cannot decipher format, this session appears to have no valid player.');
|
||||
return player.decipher(this.url, this.signature_cipher, this.cipher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ class NavigatableText extends Text {
|
||||
super(node);
|
||||
// TODO: is this needed? Text now supports this itself
|
||||
this.endpoint =
|
||||
node.runs?.[0]?.navigationEndpoint ?
|
||||
new NavigationEndpoint(node.runs[0].navigationEndpoint) :
|
||||
node.navigationEndpoint ?
|
||||
new NavigationEndpoint(node.navigationEndpoint) :
|
||||
node.titleNavigationEndpoint ?
|
||||
new NavigationEndpoint(node.titleNavigationEndpoint) : null;
|
||||
node?.runs?.[0]?.navigationEndpoint ?
|
||||
new NavigationEndpoint(node?.runs[0].navigationEndpoint) :
|
||||
node?.navigationEndpoint ?
|
||||
new NavigationEndpoint(node?.navigationEndpoint) :
|
||||
node?.titleNavigationEndpoint ?
|
||||
new NavigationEndpoint(node?.titleNavigationEndpoint) : null;
|
||||
}
|
||||
|
||||
toJSON(): NavigatableText {
|
||||
|
||||
@@ -357,9 +357,13 @@ export default class Parser {
|
||||
}
|
||||
|
||||
static parseItem<T extends YTNode = YTNode>(data: any, validTypes?: YTNodeConstructor<T> | YTNodeConstructor<T>[]) {
|
||||
if (!data) return null;
|
||||
if (!data ) return null;
|
||||
|
||||
const keys = Object.keys(data);
|
||||
|
||||
if (!keys.length)
|
||||
return null;
|
||||
|
||||
const classname = this.sanitizeClassName(keys[0]);
|
||||
|
||||
if (!this.shouldIgnore(classname)) {
|
||||
@@ -493,6 +497,7 @@ export default class Parser {
|
||||
}
|
||||
|
||||
static ignore_list = new Set<string>([
|
||||
'AdSlot',
|
||||
'DisplayAd',
|
||||
'SearchPyv',
|
||||
'MealbarPromo',
|
||||
|
||||
@@ -28,6 +28,8 @@ import { default as C4TabbedHeader } from './classes/C4TabbedHeader';
|
||||
import { default as CallToActionButton } from './classes/CallToActionButton';
|
||||
import { default as Card } from './classes/Card';
|
||||
import { default as CardCollection } from './classes/CardCollection';
|
||||
import { default as CarouselHeader } from './classes/CarouselHeader';
|
||||
import { default as CarouselItem } from './classes/CarouselItem';
|
||||
import { default as Channel } from './classes/Channel';
|
||||
import { default as ChannelAboutFullMetadata } from './classes/ChannelAboutFullMetadata';
|
||||
import { default as ChannelFeaturedContent } from './classes/ChannelFeaturedContent';
|
||||
@@ -54,11 +56,13 @@ import { default as CommentThread } from './classes/comments/CommentThread';
|
||||
import { default as CompactLink } from './classes/CompactLink';
|
||||
import { default as CompactMix } from './classes/CompactMix';
|
||||
import { default as CompactPlaylist } from './classes/CompactPlaylist';
|
||||
import { default as CompactStation } from './classes/CompactStation';
|
||||
import { default as CompactVideo } from './classes/CompactVideo';
|
||||
import { default as ConfirmDialog } from './classes/ConfirmDialog';
|
||||
import { default as ContinuationItem } from './classes/ContinuationItem';
|
||||
import { default as CopyLink } from './classes/CopyLink';
|
||||
import { default as CreatePlaylistDialog } from './classes/CreatePlaylistDialog';
|
||||
import { default as DefaultPromoPanel } from './classes/DefaultPromoPanel';
|
||||
import { default as DidYouMean } from './classes/DidYouMean';
|
||||
import { default as DownloadButton } from './classes/DownloadButton';
|
||||
import { default as Dropdown } from './classes/Dropdown';
|
||||
@@ -73,6 +77,8 @@ import { default as ExpandableTab } from './classes/ExpandableTab';
|
||||
import { default as ExpandedShelfContents } from './classes/ExpandedShelfContents';
|
||||
import { default as FeedFilterChipBar } from './classes/FeedFilterChipBar';
|
||||
import { default as FeedTabbedHeader } from './classes/FeedTabbedHeader';
|
||||
import { default as GameCard } from './classes/GameCard';
|
||||
import { default as GameDetails } from './classes/GameDetails';
|
||||
import { default as Grid } from './classes/Grid';
|
||||
import { default as GridChannel } from './classes/GridChannel';
|
||||
import { default as GridHeader } from './classes/GridHeader';
|
||||
@@ -83,6 +89,7 @@ import { default as HistorySuggestion } from './classes/HistorySuggestion';
|
||||
import { default as HorizontalCardList } from './classes/HorizontalCardList';
|
||||
import { default as HorizontalList } from './classes/HorizontalList';
|
||||
import { default as IconLink } from './classes/IconLink';
|
||||
import { default as InteractiveTabbedHeader } from './classes/InteractiveTabbedHeader';
|
||||
import { default as ItemSection } from './classes/ItemSection';
|
||||
import { default as ItemSectionHeader } from './classes/ItemSectionHeader';
|
||||
import { default as ItemSectionTab } from './classes/ItemSectionTab';
|
||||
@@ -189,6 +196,7 @@ import { default as PlayerOverlay } from './classes/PlayerOverlay';
|
||||
import { default as PlayerOverlayAutoplay } from './classes/PlayerOverlayAutoplay';
|
||||
import { default as PlayerStoryboardSpec } from './classes/PlayerStoryboardSpec';
|
||||
import { default as Playlist } from './classes/Playlist';
|
||||
import { default as PlaylistCustomThumbnail } from './classes/PlaylistCustomThumbnail';
|
||||
import { default as PlaylistHeader } from './classes/PlaylistHeader';
|
||||
import { default as PlaylistInfoCardContent } from './classes/PlaylistInfoCardContent';
|
||||
import { default as PlaylistMetadata } from './classes/PlaylistMetadata';
|
||||
@@ -207,6 +215,7 @@ import { default as ProfileColumn } from './classes/ProfileColumn';
|
||||
import { default as ProfileColumnStats } from './classes/ProfileColumnStats';
|
||||
import { default as ProfileColumnStatsEntry } from './classes/ProfileColumnStatsEntry';
|
||||
import { default as ProfileColumnUserInfo } from './classes/ProfileColumnUserInfo';
|
||||
import { default as RecognitionShelf } from './classes/RecognitionShelf';
|
||||
import { default as ReelItem } from './classes/ReelItem';
|
||||
import { default as ReelShelf } from './classes/ReelShelf';
|
||||
import { default as RelatedChipCloud } from './classes/RelatedChipCloud';
|
||||
@@ -245,6 +254,7 @@ import { default as Tab } from './classes/Tab';
|
||||
import { default as Tabbed } from './classes/Tabbed';
|
||||
import { default as TabbedSearchResults } from './classes/TabbedSearchResults';
|
||||
import { default as TextHeader } from './classes/TextHeader';
|
||||
import { default as ThumbnailLandscapePortrait } from './classes/ThumbnailLandscapePortrait';
|
||||
import { default as ThumbnailOverlayBottomPanel } from './classes/ThumbnailOverlayBottomPanel';
|
||||
import { default as ThumbnailOverlayEndorsement } from './classes/ThumbnailOverlayEndorsement';
|
||||
import { default as ThumbnailOverlayHoverText } from './classes/ThumbnailOverlayHoverText';
|
||||
@@ -261,6 +271,7 @@ import { default as TitleAndButtonListHeader } from './classes/TitleAndButtonLis
|
||||
import { default as ToggleButton } from './classes/ToggleButton';
|
||||
import { default as ToggleMenuServiceItem } from './classes/ToggleMenuServiceItem';
|
||||
import { default as Tooltip } from './classes/Tooltip';
|
||||
import { default as TopicChannelDetails } from './classes/TopicChannelDetails';
|
||||
import { default as TwoColumnBrowseResults } from './classes/TwoColumnBrowseResults';
|
||||
import { default as TwoColumnSearchResults } from './classes/TwoColumnSearchResults';
|
||||
import { default as TwoColumnWatchNextResults } from './classes/TwoColumnWatchNextResults';
|
||||
@@ -268,6 +279,7 @@ import { default as UniversalWatchCard } from './classes/UniversalWatchCard';
|
||||
import { default as VerticalList } from './classes/VerticalList';
|
||||
import { default as VerticalWatchCardList } from './classes/VerticalWatchCardList';
|
||||
import { default as Video } from './classes/Video';
|
||||
import { default as VideoCard } from './classes/VideoCard';
|
||||
import { default as VideoInfoCardContent } from './classes/VideoInfoCardContent';
|
||||
import { default as VideoOwner } from './classes/VideoOwner';
|
||||
import { default as VideoPrimaryInfo } from './classes/VideoPrimaryInfo';
|
||||
@@ -279,7 +291,7 @@ import { default as WatchCardSectionSequence } from './classes/WatchCardSectionS
|
||||
import { default as WatchNextEndScreen } from './classes/WatchNextEndScreen';
|
||||
import { default as WatchNextTabbedResults } from './classes/WatchNextTabbedResults';
|
||||
|
||||
const map: Record<string, YTNodeConstructor> = {
|
||||
export const YTNodes = {
|
||||
AccountChannel,
|
||||
AccountItemSection,
|
||||
AccountItemSectionHeader,
|
||||
@@ -306,6 +318,8 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
CallToActionButton,
|
||||
Card,
|
||||
CardCollection,
|
||||
CarouselHeader,
|
||||
CarouselItem,
|
||||
Channel,
|
||||
ChannelAboutFullMetadata,
|
||||
ChannelFeaturedContent,
|
||||
@@ -332,11 +346,13 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
CompactLink,
|
||||
CompactMix,
|
||||
CompactPlaylist,
|
||||
CompactStation,
|
||||
CompactVideo,
|
||||
ConfirmDialog,
|
||||
ContinuationItem,
|
||||
CopyLink,
|
||||
CreatePlaylistDialog,
|
||||
DefaultPromoPanel,
|
||||
DidYouMean,
|
||||
DownloadButton,
|
||||
Dropdown,
|
||||
@@ -351,6 +367,8 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
ExpandedShelfContents,
|
||||
FeedFilterChipBar,
|
||||
FeedTabbedHeader,
|
||||
GameCard,
|
||||
GameDetails,
|
||||
Grid,
|
||||
GridChannel,
|
||||
GridHeader,
|
||||
@@ -361,6 +379,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
HorizontalCardList,
|
||||
HorizontalList,
|
||||
IconLink,
|
||||
InteractiveTabbedHeader,
|
||||
ItemSection,
|
||||
ItemSectionHeader,
|
||||
ItemSectionTab,
|
||||
@@ -467,6 +486,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
PlayerOverlayAutoplay,
|
||||
PlayerStoryboardSpec,
|
||||
Playlist,
|
||||
PlaylistCustomThumbnail,
|
||||
PlaylistHeader,
|
||||
PlaylistInfoCardContent,
|
||||
PlaylistMetadata,
|
||||
@@ -485,6 +505,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
ProfileColumnStats,
|
||||
ProfileColumnStatsEntry,
|
||||
ProfileColumnUserInfo,
|
||||
RecognitionShelf,
|
||||
ReelItem,
|
||||
ReelShelf,
|
||||
RelatedChipCloud,
|
||||
@@ -523,6 +544,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
Tabbed,
|
||||
TabbedSearchResults,
|
||||
TextHeader,
|
||||
ThumbnailLandscapePortrait,
|
||||
ThumbnailOverlayBottomPanel,
|
||||
ThumbnailOverlayEndorsement,
|
||||
ThumbnailOverlayHoverText,
|
||||
@@ -539,6 +561,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
ToggleButton,
|
||||
ToggleMenuServiceItem,
|
||||
Tooltip,
|
||||
TopicChannelDetails,
|
||||
TwoColumnBrowseResults,
|
||||
TwoColumnSearchResults,
|
||||
TwoColumnWatchNextResults,
|
||||
@@ -546,6 +569,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
VerticalList,
|
||||
VerticalWatchCardList,
|
||||
Video,
|
||||
VideoCard,
|
||||
VideoInfoCardContent,
|
||||
VideoOwner,
|
||||
VideoPrimaryInfo,
|
||||
@@ -558,7 +582,7 @@ const map: Record<string, YTNodeConstructor> = {
|
||||
WatchNextTabbedResults
|
||||
};
|
||||
|
||||
export const YTNodes = map;
|
||||
const map: Record<string, YTNodeConstructor> = YTNodes;
|
||||
|
||||
/**
|
||||
* @param name - Name of the node to be parsed
|
||||
|
||||
@@ -1,46 +1,96 @@
|
||||
import Actions from '../../core/Actions';
|
||||
import TabbedFeed from '../../core/TabbedFeed';
|
||||
import C4TabbedHeader from '../classes/C4TabbedHeader';
|
||||
import CarouselHeader from '../classes/CarouselHeader';
|
||||
import InteractiveTabbedHeader from '../classes/InteractiveTabbedHeader';
|
||||
import ChannelAboutFullMetadata from '../classes/ChannelAboutFullMetadata';
|
||||
import ChannelMetadata from '../classes/ChannelMetadata';
|
||||
import MicroformatData from '../classes/MicroformatData';
|
||||
import SubscribeButton from '../classes/SubscribeButton';
|
||||
import Tab from '../classes/Tab';
|
||||
|
||||
class Channel extends TabbedFeed {
|
||||
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';
|
||||
|
||||
export default class Channel extends TabbedFeed {
|
||||
header;
|
||||
metadata;
|
||||
sponsor_button;
|
||||
subscribe_button;
|
||||
current_tab;
|
||||
|
||||
constructor(actions: Actions, data: any, already_parsed = false) {
|
||||
super(actions, data, already_parsed);
|
||||
|
||||
this.header = this.page.header?.item().as(C4TabbedHeader);
|
||||
const metadata = this.page.metadata.item().as(ChannelMetadata);
|
||||
this.header = this.page.header?.item()?.as(C4TabbedHeader, CarouselHeader, InteractiveTabbedHeader);
|
||||
|
||||
const metadata = this.page.metadata?.item().as(ChannelMetadata);
|
||||
const microformat = this.page.microformat?.as(MicroformatData);
|
||||
|
||||
if (!metadata && !this.page.contents)
|
||||
throw new InnertubeError('Invalid channel', this);
|
||||
|
||||
this.metadata = { ...metadata, ...(microformat || {}) };
|
||||
this.sponsor_button = this.header?.sponsor_button;
|
||||
this.subscribe_button = this.header?.subscribe_button;
|
||||
|
||||
this.subscribe_button = this.page.header_memo.getType(SubscribeButton)?.[0];
|
||||
|
||||
const tab = this.page.contents.item().key('tabs').parsed().array().filterType(Tab).get({ selected: true });
|
||||
|
||||
this.current_tab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies given filter to the list.
|
||||
* @param filter - The filter to apply
|
||||
*/
|
||||
async applyFilter(filter: string | ChipCloudChip) {
|
||||
let target_filter: ChipCloudChip | undefined;
|
||||
|
||||
const filter_chipbar = this.memo.getType(FeedFilterChipBar)?.[0];
|
||||
|
||||
if (typeof filter === 'string') {
|
||||
target_filter = filter_chipbar?.contents.get({ text: filter });
|
||||
if (!target_filter)
|
||||
throw new InnertubeError(`Filter ${filter} not found`, { available_filters: this.filters });
|
||||
} else if (filter instanceof ChipCloudChip) {
|
||||
target_filter = filter;
|
||||
}
|
||||
|
||||
if (!target_filter)
|
||||
throw new InnertubeError('Invalid filter', filter);
|
||||
|
||||
const page = await target_filter.endpoint?.call(this.actions, { parse: true });
|
||||
return new FilteredChannelList(this.actions, page, true);
|
||||
}
|
||||
|
||||
get filters(): string[] {
|
||||
return this.memo.getType(FeedFilterChipBar)?.[0]?.contents.filterType(ChipCloudChip).map((chip) => chip.text) || [];
|
||||
}
|
||||
|
||||
async getHome() {
|
||||
const tab = await this.getTab('Home');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getVideos() {
|
||||
const tab = await this.getTab('Videos');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getPlaylists() {
|
||||
const tab = await this.getTab('Playlists');
|
||||
async getShorts() {
|
||||
const tab = await this.getTab('Shorts');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getHome() {
|
||||
const tab = await this.getTab('Home');
|
||||
async getLiveStreams() {
|
||||
const tab = await this.getTab('Live');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
async getPlaylists() {
|
||||
const tab = await this.getTab('Playlists');
|
||||
return new Channel(this.actions, tab.page, true);
|
||||
}
|
||||
|
||||
@@ -62,6 +112,74 @@ class Channel extends TabbedFeed {
|
||||
const tab = await this.getTab('About');
|
||||
return tab.memo.getType(ChannelAboutFullMetadata)?.[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrives list continuation.
|
||||
*/
|
||||
async getContinuation() {
|
||||
const page = await super.getContinuationData();
|
||||
return new ChannelListContinuation(this.actions, page, true);
|
||||
}
|
||||
}
|
||||
|
||||
export default Channel;
|
||||
export class ChannelListContinuation extends Feed {
|
||||
contents;
|
||||
|
||||
constructor(actions: Actions, data: any, already_parsed = false) {
|
||||
super(actions, data, already_parsed);
|
||||
this.contents =
|
||||
this.page.on_response_received_actions?.[0] ||
|
||||
this.page.on_response_received_endpoints?.[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves list continuation.
|
||||
*/
|
||||
async getContinuation() {
|
||||
const page = await super.getContinuationData();
|
||||
return new ChannelListContinuation(this.actions, page, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class FilteredChannelList extends FilterableFeed {
|
||||
applied_filter: ChipCloudChip | undefined;
|
||||
contents;
|
||||
|
||||
constructor(actions: Actions, data: any, already_parsed = false) {
|
||||
super(actions, data, already_parsed);
|
||||
|
||||
this.applied_filter = this.memo.getType(ChipCloudChip).get({ is_selected: true });
|
||||
|
||||
// Removes the filter chipbar from the actions list
|
||||
if (
|
||||
this.page.on_response_received_actions &&
|
||||
this.page.on_response_received_actions.length > 1
|
||||
) {
|
||||
this.page.on_response_received_actions.shift();
|
||||
}
|
||||
|
||||
this.contents = this.page.on_response_received_actions?.[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies given filter to the list.
|
||||
* @param filter - The filter to apply
|
||||
*/
|
||||
async applyFilter(filter: string | ChipCloudChip) {
|
||||
const feed = await super.getFilteredFeed(filter);
|
||||
return new FilteredChannelList(this.actions, feed.page, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves list continuation.
|
||||
*/
|
||||
async getContinuation() {
|
||||
const page = await super.getContinuationData();
|
||||
|
||||
// Keep the filters
|
||||
page?.on_response_received_actions_memo.set('FeedFilterChipBar', this.memo.getType(FeedFilterChipBar));
|
||||
page?.on_response_received_actions_memo.set('ChipCloudChip', this.memo.getType(ChipCloudChip));
|
||||
|
||||
return new FilteredChannelList(this.actions, page, true);
|
||||
}
|
||||
}
|
||||
42
src/parser/youtube/HomeFeed.ts
Normal file
42
src/parser/youtube/HomeFeed.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import Actions from '../../core/Actions';
|
||||
import FilterableFeed from '../../core/FilterableFeed';
|
||||
import ChipCloudChip from '../classes/ChipCloudChip';
|
||||
import FeedTabbedHeader from '../classes/FeedTabbedHeader';
|
||||
import RichGrid from '../classes/RichGrid';
|
||||
|
||||
import { ReloadContinuationItemsCommand, AppendContinuationItemsAction } from '..';
|
||||
|
||||
export default class HomeFeed extends FilterableFeed {
|
||||
contents: RichGrid | AppendContinuationItemsAction | ReloadContinuationItemsCommand;
|
||||
header: FeedTabbedHeader;
|
||||
|
||||
constructor(actions: Actions, data: any, already_parsed = false) {
|
||||
super(actions, data, already_parsed);
|
||||
this.header = this.memo.getType<FeedTabbedHeader>(FeedTabbedHeader)?.[0];
|
||||
this.contents =
|
||||
this.memo.getType<RichGrid>(RichGrid)?.[0] ||
|
||||
this.page.on_response_received_actions?.[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies given filter to the feed.
|
||||
* @param filter - Filter to apply.
|
||||
*/
|
||||
async applyFilter(filter: string | ChipCloudChip): Promise<HomeFeed> {
|
||||
const feed = await super.getFilteredFeed(filter);
|
||||
return new HomeFeed(this.actions, feed.page, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves next batch of contents.
|
||||
*/
|
||||
async getContinuation(): Promise<HomeFeed> {
|
||||
const feed = await super.getContinuation();
|
||||
|
||||
// Keep the page header
|
||||
feed.page.header = this.page.header;
|
||||
feed.page.header_memo.set(this.header.type, [ this.header ]);
|
||||
|
||||
return new HomeFeed(this.actions, feed.page, true);
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,10 @@ import { InnertubeError } from '../../utils/Utils';
|
||||
import Feed from '../../core/Feed';
|
||||
import History from './History';
|
||||
import Playlist from './Playlist';
|
||||
|
||||
import Tab from '../classes/Tab';
|
||||
import Menu from '../classes/menus/Menu';
|
||||
import Shelf from '../classes/Shelf';
|
||||
import Button from '../classes/Button';
|
||||
import SectionList from '../classes/SectionList';
|
||||
import ItemSection from '../classes/ItemSection';
|
||||
import TwoColumnBrowseResults from '../classes/TwoColumnBrowseResults';
|
||||
|
||||
import ProfileColumn from '../classes/ProfileColumn';
|
||||
import ProfileColumnStats from '../classes/ProfileColumnStats';
|
||||
import ProfileColumnUserInfo from '../classes/ProfileColumnUserInfo';
|
||||
|
||||
@@ -29,30 +23,17 @@ class Library {
|
||||
this.#actions = actions;
|
||||
this.#page = Parser.parseResponse(response);
|
||||
|
||||
const two_col = this.#page.contents.item().as(TwoColumnBrowseResults);
|
||||
|
||||
if (!two_col)
|
||||
throw new InnertubeError('Response did not have a TwoColumnBrowseResults.');
|
||||
|
||||
const tab = two_col.tabs.array().as(Tab).get({ selected: true });
|
||||
|
||||
if (!tab)
|
||||
throw new InnertubeError('Could not find target tab.');
|
||||
|
||||
const stats = two_col.secondary_contents.item().as(ProfileColumn).items.array().get({ type: 'ProfileColumnStats' })?.as(ProfileColumnStats) || null;
|
||||
const user_info = two_col.secondary_contents.item().as(ProfileColumn).items.array().get({ type: 'ProfileColumnUserInfo' })?.as(ProfileColumnUserInfo) || null;
|
||||
const stats = this.#page.contents_memo.getType(ProfileColumnStats)?.[0];
|
||||
const user_info = this.#page.contents_memo.getType(ProfileColumnUserInfo)?.[0];
|
||||
|
||||
this.profile = { stats, user_info };
|
||||
|
||||
if (!tab.content)
|
||||
throw new InnertubeError('Target tab did not have any content.');
|
||||
|
||||
const shelves = tab.content.as(SectionList).contents.array().as(ItemSection).map((is: ItemSection) => is.contents?.firstOfType(Shelf));
|
||||
const shelves = this.#page.contents_memo.getType(Shelf);
|
||||
|
||||
this.sections = shelves.map((shelf: any) => ({
|
||||
type: shelf.icon_type,
|
||||
title: shelf.title,
|
||||
contents: shelf.content?.item().items.array() || [],
|
||||
contents: shelf.content?.item().items || [],
|
||||
getAll: () => this.#getAll(shelf)
|
||||
}));
|
||||
}
|
||||
@@ -61,7 +42,7 @@ class Library {
|
||||
if (!shelf.menu?.item().as(Menu).hasKey('top_level_buttons'))
|
||||
throw new InnertubeError(`The ${shelf.title.text} shelf doesn't have more items`);
|
||||
|
||||
const button = await shelf.menu.item().as(Menu).top_level_buttons.get({ text: 'See all' });
|
||||
const button = shelf.menu.item().as(Menu).top_level_buttons.get({ text: 'See all' });
|
||||
|
||||
if (!button)
|
||||
throw new InnertubeError('Did not find target button.');
|
||||
|
||||
@@ -40,8 +40,8 @@ class Search extends Feed {
|
||||
|
||||
this.watch_card = {
|
||||
header: universal_watch_card?.header.item() || null,
|
||||
call_to_action: universal_watch_card?.call_to_action.item().as(WatchCardHeroVideo) || null,
|
||||
sections: universal_watch_card?.sections.array().filterType(WatchCardSectionSequence) || []
|
||||
call_to_action: universal_watch_card?.call_to_action?.item()?.as(WatchCardHeroVideo) || null,
|
||||
sections: universal_watch_card?.sections?.array()?.filterType(WatchCardSectionSequence) || []
|
||||
};
|
||||
|
||||
this.refinement_cards = {
|
||||
|
||||
@@ -92,7 +92,7 @@ class VideoInfo {
|
||||
* @param data - API response.
|
||||
* @param cpn - Client Playback Nonce
|
||||
*/
|
||||
constructor(data: [ApiResponse, ApiResponse?], actions: Actions, player: Player, cpn: string) {
|
||||
constructor(data: [ApiResponse, ApiResponse?], actions: Actions, player?: Player, cpn?: string) {
|
||||
this.#actions = actions;
|
||||
this.#player = player;
|
||||
this.#cpn = cpn;
|
||||
@@ -492,7 +492,7 @@ class VideoInfo {
|
||||
throw new InnertubeError('Index and init ranges not available', { format });
|
||||
|
||||
const url = new URL(format.decipher(this.#player));
|
||||
url.searchParams.set('cpn', this.#cpn);
|
||||
url.searchParams.set('cpn', this.#cpn || '');
|
||||
|
||||
set.appendChild(this.#el(document, 'Representation', {
|
||||
id: format.itag,
|
||||
@@ -522,7 +522,7 @@ class VideoInfo {
|
||||
throw new InnertubeError('Index and init ranges not available', { format });
|
||||
|
||||
const url = new URL(format.decipher(this.#player));
|
||||
url.searchParams.set('cpn', this.#cpn);
|
||||
url.searchParams.set('cpn', this.#cpn || '');
|
||||
|
||||
set.appendChild(this.#el(document, 'Representation', {
|
||||
id: format.itag,
|
||||
|
||||
@@ -458,36 +458,6 @@ export interface CreateCommentParams_Params {
|
||||
*/
|
||||
index: number;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message youtube.CreateCommentReplyParams
|
||||
*/
|
||||
export interface CreateCommentReplyParams {
|
||||
/**
|
||||
* @generated from protobuf field: string video_id = 2;
|
||||
*/
|
||||
videoId: string;
|
||||
/**
|
||||
* @generated from protobuf field: string comment_id = 4;
|
||||
*/
|
||||
commentId: string;
|
||||
/**
|
||||
* @generated from protobuf field: youtube.CreateCommentReplyParams.UnknownParams params = 5;
|
||||
*/
|
||||
params?: CreateCommentReplyParams_UnknownParams;
|
||||
/**
|
||||
* @generated from protobuf field: optional int32 unk_num = 10;
|
||||
*/
|
||||
unkNum?: number;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message youtube.CreateCommentReplyParams.UnknownParams
|
||||
*/
|
||||
export interface CreateCommentReplyParams_UnknownParams {
|
||||
/**
|
||||
* @generated from protobuf field: int32 unk_num = 1;
|
||||
*/
|
||||
unkNum: number;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message youtube.PeformCommentActionParams
|
||||
*/
|
||||
@@ -2402,121 +2372,6 @@ class CreateCommentParams_Params$Type extends MessageType<CreateCommentParams_Pa
|
||||
*/
|
||||
export const CreateCommentParams_Params = new CreateCommentParams_Params$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class CreateCommentReplyParams$Type extends MessageType<CreateCommentReplyParams> {
|
||||
constructor() {
|
||||
super("youtube.CreateCommentReplyParams", [
|
||||
{ no: 2, name: "video_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 4, name: "comment_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 5, name: "params", kind: "message", T: () => CreateCommentReplyParams_UnknownParams },
|
||||
{ no: 10, name: "unk_num", kind: "scalar", opt: true, T: 5 /*ScalarType.INT32*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<CreateCommentReplyParams>): CreateCommentReplyParams {
|
||||
const message = { videoId: "", commentId: "" };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<CreateCommentReplyParams>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CreateCommentReplyParams): CreateCommentReplyParams {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string video_id */ 2:
|
||||
message.videoId = reader.string();
|
||||
break;
|
||||
case /* string comment_id */ 4:
|
||||
message.commentId = reader.string();
|
||||
break;
|
||||
case /* youtube.CreateCommentReplyParams.UnknownParams params */ 5:
|
||||
message.params = CreateCommentReplyParams_UnknownParams.internalBinaryRead(reader, reader.uint32(), options, message.params);
|
||||
break;
|
||||
case /* optional int32 unk_num */ 10:
|
||||
message.unkNum = reader.int32();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: CreateCommentReplyParams, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string video_id = 2; */
|
||||
if (message.videoId !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.videoId);
|
||||
/* string comment_id = 4; */
|
||||
if (message.commentId !== "")
|
||||
writer.tag(4, WireType.LengthDelimited).string(message.commentId);
|
||||
/* youtube.CreateCommentReplyParams.UnknownParams params = 5; */
|
||||
if (message.params)
|
||||
CreateCommentReplyParams_UnknownParams.internalBinaryWrite(message.params, writer.tag(5, WireType.LengthDelimited).fork(), options).join();
|
||||
/* optional int32 unk_num = 10; */
|
||||
if (message.unkNum !== undefined)
|
||||
writer.tag(10, WireType.Varint).int32(message.unkNum);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message youtube.CreateCommentReplyParams
|
||||
*/
|
||||
export const CreateCommentReplyParams = new CreateCommentReplyParams$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class CreateCommentReplyParams_UnknownParams$Type extends MessageType<CreateCommentReplyParams_UnknownParams> {
|
||||
constructor() {
|
||||
super("youtube.CreateCommentReplyParams.UnknownParams", [
|
||||
{ no: 1, name: "unk_num", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<CreateCommentReplyParams_UnknownParams>): CreateCommentReplyParams_UnknownParams {
|
||||
const message = { unkNum: 0 };
|
||||
globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this });
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<CreateCommentReplyParams_UnknownParams>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CreateCommentReplyParams_UnknownParams): CreateCommentReplyParams_UnknownParams {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* int32 unk_num */ 1:
|
||||
message.unkNum = reader.int32();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: CreateCommentReplyParams_UnknownParams, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* int32 unk_num = 1; */
|
||||
if (message.unkNum !== 0)
|
||||
writer.tag(1, WireType.Varint).int32(message.unkNum);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message youtube.CreateCommentReplyParams.UnknownParams
|
||||
*/
|
||||
export const CreateCommentReplyParams_UnknownParams = new CreateCommentReplyParams_UnknownParams$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class PeformCommentActionParams$Type extends MessageType<PeformCommentActionParams> {
|
||||
constructor() {
|
||||
super("youtube.PeformCommentActionParams", [
|
||||
|
||||
@@ -103,9 +103,12 @@ export default class HTTPClient {
|
||||
|
||||
if (this.#cookie) {
|
||||
const papisid = getStringBetweenStrings(this.#cookie, 'PAPISID=', ';');
|
||||
|
||||
if (papisid) {
|
||||
request_headers.set('authorization', await generateSidAuth(papisid));
|
||||
request_headers.set('x-goog-authuser', this.#session.account_index.toString());
|
||||
}
|
||||
|
||||
request_headers.set('cookie', this.#cookie);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,16 @@ export const VIDEOS = [
|
||||
{
|
||||
ID: 'WSeNSzJ2-Jw',
|
||||
QUERY: 'Scary Monsters and Nice Sprites Official Audio'
|
||||
},
|
||||
{
|
||||
ID: 'I1qsF0WQy8c',
|
||||
QUERY: 'mkbhd',
|
||||
}
|
||||
];
|
||||
|
||||
export const CHANNELS = [
|
||||
{
|
||||
ID: 'UC_x5XG1OV2P6uZZ5FSM9Ttw',
|
||||
NAME: 'Linus Tech Tips'
|
||||
}
|
||||
];
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs';
|
||||
import Innertube from '..';
|
||||
import { VIDEOS } from './constants';
|
||||
import { CHANNELS, VIDEOS } from './constants';
|
||||
import { streamToIterable } from '../src/utils/Utils';
|
||||
|
||||
describe('YouTube.js Tests', () => {
|
||||
@@ -38,6 +38,14 @@ describe('YouTube.js Tests', () => {
|
||||
expect(search.channels).toBeDefined();
|
||||
expect(search.has_continuation).toBe(true);
|
||||
});
|
||||
|
||||
it('should search with WatchCardHeroVideo parse', async () => {
|
||||
search = await yt.search(VIDEOS[2].QUERY);
|
||||
expect(search.results.length).toBeGreaterThanOrEqual(5);
|
||||
expect(search.playlists).toBeDefined();
|
||||
expect(search.channels).toBeDefined();
|
||||
expect(search.has_continuation).toBe(true);
|
||||
});
|
||||
|
||||
it('should retrieve search continuation', async () => {
|
||||
const next = await search.getContinuation();
|
||||
@@ -82,8 +90,22 @@ describe('YouTube.js Tests', () => {
|
||||
expect(playlist.items.length).toBeLessThanOrEqual(100);
|
||||
});
|
||||
|
||||
it('should retrieve channel', async () => {
|
||||
const channel = await yt.getChannel(CHANNELS[0].ID);
|
||||
expect(channel.videos.length).toBeGreaterThan(0);
|
||||
expect(channel.shelves.length).toBeGreaterThan(0);
|
||||
|
||||
const videos_tab = await channel.getVideos();
|
||||
expect(videos_tab.videos.length).toBeGreaterThan(0);
|
||||
|
||||
const filtered_list = await videos_tab.applyFilter('Popular');
|
||||
expect(filtered_list.videos.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should retrieve home feed', async () => {
|
||||
const homefeed = await yt.getHomeFeed();
|
||||
expect(homefeed.header).toBeDefined();
|
||||
expect(homefeed.contents).toBeDefined();
|
||||
expect(homefeed.videos.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user