Compare commits

...

13 Commits

Author SHA1 Message Date
github-actions[bot]
312c636ec4 chore(main): release 7.0.0 (#528)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-10-28 15:21:53 -03:00
Azarattum
4c0de199e8 fix(build): Inline package.json import to avoid runtime erros (#509)
* chore(main): Inline package.json import

* chore: add `--legacy-peer-deps` flag to ci

* chore: update lock file

---------

Co-authored-by: LuanRT <luan.lrt4@gmail.com>
2023-10-28 15:19:37 -03:00
Ryan Sandbach
9ab528ec82 feat(Kids): Add blockChannel command to easily block channels (#503)
* Add blockChannel command to support easily blocking content for supervised accounts.

* Moved blockChannel functionality to the Kids client and updated API docs.

* Fix whitepsace issues.

* Resolve remaining linting errors.

* Avoid changing interaction manager. Remove comment for ToggleButton change.

* chore: clean up

---------

Co-authored-by: LuanRT <luan.lrt4@gmail.com>
2023-10-28 14:28:17 -03:00
LuanRT
24ffb01aef Merge branch 'main' of https://github.com/LuanRT/YouTube.js 2023-10-28 13:31:10 -03:00
LuanRT
eaac38c919 chore: lint 2023-10-28 13:30:58 -03:00
absidue
e627887fe0 chore(MediaInfo): Throw helpful errors when calling toDash or download for live and Post-Live DVR videos (#526)
* Address pull request feedback

---------

Co-authored-by: LuanRT <luan.lrt4@gmail.com>
2023-10-28 13:29:37 -03:00
LuanRT
beaa28f4c6 feat(music#getSearchSuggestions)!: Return array of SearchSuggestionsSection instead of a single node 2023-10-28 13:27:58 -03:00
LuanRT
a45273fec4 feat(parser): Add PlayerOverflow and PlayerControlsOverlay 2023-10-28 13:17:26 -03:00
absidue
bc97e07ac6 feat(UpdateViewerShipAction): Add original_view_count and unlabeled_view_count_value (#527) 2023-10-21 12:39:03 -03:00
LuanRT
f35b4c2c8c Merge branch 'main' of https://github.com/LuanRT/YouTube.js 2023-10-18 23:32:01 -03:00
LuanRT
c934325648 chore: update readme [skip ci] 2023-10-18 23:31:03 -03:00
dependabot[bot]
cd27acd25b chore(deps-dev): bump @babel/traverse from 7.22.10 to 7.23.2 (#524)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.10 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-16 22:55:44 -03:00
dependabot[bot]
83b42d2585 chore(deps): bump undici from 5.23.0 to 5.26.2 (#523)
Bumps [undici](https://github.com/nodejs/undici) from 5.23.0 to 5.26.2.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v5.23.0...v5.26.2)

---
updated-dependencies:
- dependency-name: undici
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-16 17:36:00 -03:00
27 changed files with 4524 additions and 1470 deletions

View File

@@ -14,5 +14,5 @@ jobs:
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm ci
- run: npm ci --legacy-peer-deps
- run: npm run lint

View File

@@ -24,7 +24,7 @@ jobs:
node-version: "16.x"
- name: Build for Deno
run: |
npm ci
npm ci --legacy-peer-deps
npm run build:deno
if: ${{ steps.release.outputs.release_created }}
- name: Move Deno files
@@ -55,7 +55,7 @@ jobs:
if: ${{ steps.release.outputs.release_created }}
- name: Publish package to npmjs
run: |
npm ci
npm ci --legacy-peer-deps
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -14,5 +14,5 @@ jobs:
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm ci
- run: npm ci --legacy-peer-deps
- run: npm run test

View File

@@ -1,5 +1,24 @@
# Changelog
## [7.0.0](https://github.com/LuanRT/YouTube.js/compare/v6.4.1...v7.0.0) (2023-10-28)
### ⚠ BREAKING CHANGES
* **music#getSearchSuggestions:** Return array of `SearchSuggestionsSection` instead of a single node
### Features
* **Kids:** Add `blockChannel` command to easily block channels ([#503](https://github.com/LuanRT/YouTube.js/issues/503)) ([9ab528e](https://github.com/LuanRT/YouTube.js/commit/9ab528ec823dcd527a97150009eed632c6d3eb6a))
* **music#getSearchSuggestions:** Return array of `SearchSuggestionsSection` instead of a single node ([beaa28f](https://github.com/LuanRT/YouTube.js/commit/beaa28f4c68de8366caa84ce5a026bf9e12e1b9d))
* **parser:** Add `PlayerOverflow` and `PlayerControlsOverlay` ([a45273f](https://github.com/LuanRT/YouTube.js/commit/a45273fec498df87eecd364ffb708c9f787793d5))
* **UpdateViewerShipAction:** Add `original_view_count` and `unlabeled_view_count_value` ([#527](https://github.com/LuanRT/YouTube.js/issues/527)) ([bc97e07](https://github.com/LuanRT/YouTube.js/commit/bc97e07ac6d1cdc45194e214c6001cf92190e1d5))
### Bug Fixes
* **build:** Inline package.json import to avoid runtime erros ([#509](https://github.com/LuanRT/YouTube.js/issues/509)) ([4c0de19](https://github.com/LuanRT/YouTube.js/commit/4c0de199e85dd5cc8b3719920b24dec9613acaab))
## [6.4.1](https://github.com/LuanRT/YouTube.js/compare/v6.4.0...v6.4.1) (2023-10-02)

View File

@@ -171,7 +171,7 @@ import dashjs from 'dashjs';
const youtube = await Innertube.create({ /* setup - see above */ });
// get the video info
// Get the video info
const videoInfo = await youtube.getInfo('videoId');
// now convert to a dash manifest
@@ -191,7 +191,7 @@ const player = dashjs.MediaPlayer().create();
player.initialize(videoElement, uri, true);
```
A fully working example can be found in [`examples/browser/web`](https://github.com/LuanRT/YouTube.js/blob/main/examples/browser/web). Alternatively, you can view it live at [ytjsexample.pages.dev](https://ytjsexample.pages.dev/).
A fully working example can be found in [`examples/browser/web`](https://github.com/LuanRT/YouTube.js/blob/main/examples/browser/web).
<a name="custom-fetch"></a>

View File

@@ -12,7 +12,7 @@ Handles direct interactions.
* [.unsubscribe(video_id)](#unsubscribe)
* [.comment(video_id, text)](#comment)
* [.translate(text, target_language, args?)](#translate)
* [.setNotificationPreferences(channel_id, type)](#setnotificationpreferences)
* [.setNotificationPreferences(channel_id, type)](#setnotificationpreferences)
<a name="like"></a>
### like(video_id)

View File

@@ -9,6 +9,7 @@ YouTube Kids is a modified version of the YouTube app, with a simplified interfa
* [.getInfo(video_id)](#getinfo)
* [.getChannel(channel_id)](#getchannel)
* [.getHomeFeed()](#gethomefeed)
* [.blockChannel(channel_id)](#blockchannel)
<a name="search"></a>
### search(query)
@@ -110,4 +111,17 @@ Retrieves the home feed.
- Returns available categories.
- `<feed>#page`
- Returns the original InnerTube response(s), parsed and sanitized.
- Returns the original InnerTube response(s), parsed and sanitized.
</details>
<a name="blockChannel"></a>
### blockChannel(channel_id)
Retrieves the list of supervised accounts that the signed-in user has access to and blocks the given channel for each of them.
**Returns:** `Promise.<ApiResponse[]>`
| Param | Type | Description |
| --- | --- | --- |
| channel_id | `string` | Channel id |

View File

@@ -0,0 +1,23 @@
import { Innertube, UniversalCache } from 'youtubei.js';
(async () => {
const yt = await Innertube.create({ cache: new UniversalCache(true, './credcache') });
yt.session.on('auth-pending', (data) => {
console.log(`Go to ${data.verification_url} in your browser and enter code ${data.user_code} to authenticate.`);
});
yt.session.on('auth', async () => {
console.log('Sign in successful');
await yt.session.oauth.cacheCredentials();
});
yt.session.on('update-credentials', async () => {
await yt.session.oauth.cacheCredentials();
});
// Attempt to sign in
await yt.session.signIn();
// Block Channel for all kids / profiles on the signed-in account.
const resp = await yt.kids.blockChannel('UCpbpfcZfo-hoDAx2m1blFhg');
console.info('Blocked channel for ', resp.length, ' profiles.');
})();

View File

@@ -58,6 +58,4 @@ After that, you can use the library as normal.
## Example
We've got a full example in `examples/browser/web` using vite.
If you don't want to run the example yourself, you can see it in action here: [ytjsexample.pages.dev](https://ytjsexample.pages.dev/).
We've got a full example in `examples/browser/web` using vite.

5692
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "youtubei.js",
"version": "6.4.1",
"version": "7.0.0",
"description": "A wrapper around YouTube's private API. Supports YouTube, YouTube Music, YouTube Kids and YouTube Studio (WIP).",
"type": "module",
"types": "./dist/src/platform/lib.d.ts",
@@ -71,7 +71,7 @@
"build": "npm run build:parser-map && npm run build:proto && npm run build:esm && npm run bundle:node && npm run bundle:browser && npm run bundle:browser:prod",
"build:parser-map": "node ./scripts/gen-parser-map.mjs",
"build:proto": "npx pb-gen-ts --entry-path=\"src/proto\" --out-dir=\"src/proto/generated\" --ext-in-import=\".js\"",
"build:esm": "npx tsc",
"build:esm": "npx tspc",
"build:deno": "npx cpy ./src ./deno && npx esbuild ./src/utils/DashManifest.tsx --keep-names --format=esm --platform=neutral --target=es2020 --outfile=./deno/src/utils/DashManifest.js && npx cpy ./package.json ./deno && npx replace \".js';\" \".ts';\" ./deno -r && npx replace '.js\";' '.ts\";' ./deno -r && npx replace \"'./DashManifest.ts';\" \"'./DashManifest.js';\" ./deno -r && npx replace \"'jintr';\" \"'https://esm.sh/jintr';\" ./deno -r",
"bundle:node": "npx esbuild ./dist/src/platform/node.js --bundle --target=node10 --keep-names --format=cjs --platform=node --outfile=./bundle/node.cjs --external:jintr --external:undici --external:linkedom --external:tslib --sourcemap --banner:js=\"/* eslint-disable */\"",
"bundle:browser": "npx esbuild ./dist/src/platform/web.js --banner:js=\"/* eslint-disable */\" --bundle --target=chrome58 --keep-names --format=esm --sourcemap --define:global=globalThis --conditions=module --outfile=./bundle/browser.js --platform=browser",
@@ -104,6 +104,8 @@
"pbkit": "^0.0.59",
"replace": "^1.2.2",
"ts-jest": "^28.0.8",
"ts-patch": "^3.0.2",
"ts-transformer-inline-file": "^0.2.0",
"typescript": "^5.0.0"
},
"bugs": {

View File

@@ -1,16 +1,22 @@
import Parser from '../../parser/index.js';
import Channel from '../../parser/ytkids/Channel.js';
import HomeFeed from '../../parser/ytkids/HomeFeed.js';
import Search from '../../parser/ytkids/Search.js';
import VideoInfo from '../../parser/ytkids/VideoInfo.js';
import type Session from '../Session.js';
import { type ApiResponse } from '../Actions.js';
import { generateRandomString } from '../../utils/Utils.js';
import { InnertubeError, generateRandomString } from '../../utils/Utils.js';
import {
BrowseEndpoint, NextEndpoint,
PlayerEndpoint, SearchEndpoint
} from '../endpoints/index.js';
import { BlocklistPickerEndpoint } from '../endpoints/kids/index.js';
import KidsBlocklistPickerItem from '../../parser/classes/ytkids/KidsBlocklistPickerItem.js';
export default class Kids {
#session: Session;
@@ -80,4 +86,38 @@ export default class Kids {
);
return new HomeFeed(this.#session.actions, response);
}
/**
* Retrieves the list of supervised accounts that the signed-in user has
* access to, and blocks the given channel for each of them.
* @param channel_id - The channel id to block.
* @returns A list of API responses.
*/
async blockChannel(channel_id: string): Promise<ApiResponse[]> {
if (!this.#session.logged_in)
throw new InnertubeError('You must be signed in to perform this operation.');
const blocklist_payload = BlocklistPickerEndpoint.build({ channel_id: channel_id });
const response = await this.#session.actions.execute(BlocklistPickerEndpoint.PATH, blocklist_payload );
const popup = response.data.command.confirmDialogEndpoint;
const popup_fragment = { contents: popup.content, engagementPanels: [] };
const kid_picker = Parser.parseResponse(popup_fragment);
const kids = kid_picker.contents_memo?.getType(KidsBlocklistPickerItem);
if (!kids)
throw new InnertubeError('Could not find any kids profiles or supervised accounts.');
// Iterate through the kids and block the channel if not already blocked.
const responses: ApiResponse[] = [];
for (const kid of kids) {
if (!kid.block_button?.is_toggled) {
kid.setActions(this.#session.actions);
// Block channel and add to the response list.
responses.push(await kid.blockChannel());
}
}
return responses;
}
}

View File

@@ -20,7 +20,7 @@ import SectionList from '../../parser/classes/SectionList.js';
import Tab from '../../parser/classes/Tab.js';
import * as Proto from '../../proto/index.js';
import type { ObservedArray, YTNode } from '../../parser/helpers.js';
import type { ObservedArray } from '../../parser/helpers.js';
import type { MusicSearchFilters } from '../../types/index.js';
import { InnertubeError, generateRandomString, throwIfMissing } from '../../utils/Utils.js';
import type Actions from '../Actions.js';
@@ -355,17 +355,17 @@ export default class Music {
* Retrieves search suggestions for the given query.
* @param query - The query.
*/
async getSearchSuggestions(query: string): Promise<ObservedArray<YTNode>> {
async getSearchSuggestions(query: string): Promise<ObservedArray<SearchSuggestionsSection>> {
const response = await this.#actions.execute(
GetSearchSuggestionsEndpoint.PATH,
{ ...GetSearchSuggestionsEndpoint.build({ input: query }), parse: true }
);
if (!response.contents_memo)
throw new InnertubeError('Unexpected response', response);
return [] as unknown as ObservedArray<SearchSuggestionsSection>;
const search_suggestions_section = response.contents_memo.getType(SearchSuggestionsSection).first();
const search_suggestions_sections = response.contents_memo.getType(SearchSuggestionsSection);
return search_suggestions_section.contents;
return search_suggestions_sections;
}
}

View File

@@ -15,4 +15,5 @@ export * as Music from './music/index.js';
export * as Notification from './notification/index.js';
export * as Playlist from './playlist/index.js';
export * as Subscription from './subscription/index.js';
export * as Upload from './upload/index.js';
export * as Upload from './upload/index.js';
export * as Kids from './kids/index.js';

View File

@@ -0,0 +1,12 @@
import type { IBlocklistPickerRequest, BlocklistPickerRequestEndpointOptions } from '../../../types/index.js';
export const PATH = '/kids/get_kids_blocklist_picker';
/**
* Builds a `/kids/get_kids_blocklist_picker` request payload.
* @param options - The options to use.
* @returns The payload.
*/
export function build(options: BlocklistPickerRequestEndpointOptions): IBlocklistPickerRequest {
return { blockedForKidsContent: { external_channel_id: options.channel_id } };
}

View File

@@ -0,0 +1 @@
export * as BlocklistPickerEndpoint from './BlocklistPickerEndpoint.js';

View File

@@ -46,10 +46,16 @@ export default class MediaInfo {
* @returns DASH manifest
*/
async toDash(url_transformer?: URLTransformer, format_filter?: FormatFilter, options: DashOptions = { include_thumbnails: false }): Promise<string> {
const player_response = this.#page[0];
if (player_response.video_details && (player_response.video_details.is_live || player_response.video_details.is_post_live_dvr)) {
throw new InnertubeError('Generating DASH manifests for live and Post-Live-DVR videos is not supported. Please use the DASH and HLS manifests provided by YouTube in `streaming_data.dash_manifest_url` and `streaming_data.hls_manifest_url` instead.');
}
let storyboards;
if (options.include_thumbnails && this.#page[0].storyboards?.is(PlayerStoryboardSpec)) {
storyboards = this.#page[0].storyboards;
if (options.include_thumbnails && player_response.storyboards?.is(PlayerStoryboardSpec)) {
storyboards = player_response.storyboards;
}
return FormatUtils.toDash(this.streaming_data, url_transformer, format_filter, this.#cpn, this.#actions.session.player, this.#actions, storyboards);
@@ -83,6 +89,12 @@ export default class MediaInfo {
* @param options - Download options.
*/
async download(options: DownloadOptions = {}): Promise<ReadableStream<Uint8Array>> {
const player_response = this.#page[0];
if (player_response.video_details && (player_response.video_details.is_live || player_response.video_details.is_post_live_dvr)) {
throw new InnertubeError('Downloading is not supported for live and Post-Live-DVR videos, as they are split up into 5 second segments that are individual files, which require using a tool such as ffmpeg to stitch them together, so they cannot be returned in a single stream.');
}
return FormatUtils.download(options, this.#actions, this.playability_status, this.streaming_data, this.#actions.session.player, this.cpn);
}

View File

@@ -0,0 +1,14 @@
import { YTNode } from '../helpers.js';
import { Parser, type RawNode } from '../index.js';
import PlayerOverflow from './PlayerOverflow.js';
export default class PlayerControlsOverlay extends YTNode {
static type = 'PlayerControlsOverlay';
overflow: PlayerOverflow | null;
constructor(data: RawNode) {
super();
this.overflow = Parser.parseItem(data.overflow, PlayerOverflow);
}
}

View File

@@ -0,0 +1,16 @@
import { YTNode } from '../helpers.js';
import type { RawNode } from '../index.js';
import NavigationEndpoint from './NavigationEndpoint.js';
export default class PlayerOverflow extends YTNode {
static type = 'PlayerOverflow';
endpoint: NavigationEndpoint;
enable_listen_first: boolean;
constructor(data: RawNode) {
super();
this.endpoint = new NavigationEndpoint(data.endpoint);
this.enable_listen_first = data.enableListenFirst;
}
}

View File

@@ -28,7 +28,7 @@ export default class ToggleButton extends YTNode {
this.toggled_tooltip = data.toggledTooltip;
this.is_toggled = data.isToggled;
this.is_disabled = data.isDisabled;
this.icon_type = data.defaultIcon.iconType;
this.icon_type = data.defaultIcon?.iconType;
const acc_label =
data?.defaultText?.accessibility?.accessibilityData?.label ||

View File

@@ -7,6 +7,8 @@ export default class UpdateViewershipAction extends YTNode {
view_count: Text;
extra_short_view_count: Text;
original_view_count: Number;
unlabeled_view_count_value: Text;
is_live: boolean;
constructor(data: RawNode) {
@@ -14,6 +16,8 @@ export default class UpdateViewershipAction extends YTNode {
const view_count_renderer = data.viewCount.videoViewCountRenderer;
this.view_count = new Text(view_count_renderer.viewCount);
this.extra_short_view_count = new Text(view_count_renderer.extraShortViewCount);
this.original_view_count = parseInt(view_count_renderer.originalViewCount);
this.unlabeled_view_count_value = new Text(view_count_renderer.unlabeledViewCountValue);
this.is_live = view_count_renderer.isLive;
}
}

View File

@@ -0,0 +1,22 @@
import Text from '../misc/Text.js';
import { YTNode } from '../../helpers.js';
import Button from '../Button.js';
import Parser, { type RawNode } from '../../index.js';
import KidsBlocklistPickerItem from './KidsBlocklistPickerItem.js';
export default class KidsBlocklistPicker extends YTNode {
static type = 'KidsBlocklistPicker';
title: Text;
child_rows: KidsBlocklistPickerItem[] | null;
done_button: Button | null;
successful_toast_action_message: Text;
constructor(data: RawNode) {
super();
this.title = new Text(data.title);
this.child_rows = Parser.parse(data.childRows, true, [ KidsBlocklistPickerItem ]);
this.done_button = Parser.parseItem(data.doneButton, [ Button ]);
this.successful_toast_action_message = new Text(data.successfulToastActionMessage);
}
}

View File

@@ -0,0 +1,49 @@
import Text from '../misc/Text.js';
import { YTNode } from '../../helpers.js';
import Parser, { type RawNode } from '../../index.js';
import ToggleButton from '../ToggleButton.js';
import Thumbnail from '../misc/Thumbnail.js';
import type Actions from '../../../core/Actions.js';
import { InnertubeError } from '../../../utils/Utils.js';
import { type ApiResponse } from '../../../core/Actions.js';
export default class KidsBlocklistPickerItem extends YTNode {
static type = 'KidsBlocklistPickerItem';
#actions?: Actions;
child_display_name: Text;
child_account_description: Text;
avatar: Thumbnail[];
block_button: ToggleButton | null;
blocked_entity_key: string;
constructor(data: RawNode) {
super();
this.child_display_name = new Text(data.childDisplayName);
this.child_account_description = new Text(data.childAccountDescription);
this.avatar = Thumbnail.fromResponse(data.avatar);
this.block_button = Parser.parseItem(data.blockButton, [ ToggleButton ]);
this.blocked_entity_key = data.blockedEntityKey;
}
async blockChannel(): Promise<ApiResponse> {
if (!this.#actions)
throw new InnertubeError('An active caller must be provide to perform this operation.');
const button = this.block_button;
if (!button)
throw new InnertubeError('Block button was not found.', { child_display_name: this.child_display_name });
if (button.is_toggled)
throw new InnertubeError('This channel is already blocked.', { child_display_name: this.child_display_name });
const response = await button.endpoint.call(this.#actions, { parse: false });
return response;
}
setActions(actions: Actions | undefined) {
this.#actions = actions;
}
}

View File

@@ -252,11 +252,13 @@ export { default as PageHeaderView } from './classes/PageHeaderView.js';
export { default as PageIntroduction } from './classes/PageIntroduction.js';
export { default as PlayerAnnotationsExpanded } from './classes/PlayerAnnotationsExpanded.js';
export { default as PlayerCaptionsTracklist } from './classes/PlayerCaptionsTracklist.js';
export { default as PlayerControlsOverlay } from './classes/PlayerControlsOverlay.js';
export { default as PlayerErrorMessage } from './classes/PlayerErrorMessage.js';
export { default as PlayerLegacyDesktopYpcOffer } from './classes/PlayerLegacyDesktopYpcOffer.js';
export { default as PlayerLegacyDesktopYpcTrailer } from './classes/PlayerLegacyDesktopYpcTrailer.js';
export { default as PlayerLiveStoryboardSpec } from './classes/PlayerLiveStoryboardSpec.js';
export { default as PlayerMicroformat } from './classes/PlayerMicroformat.js';
export { default as PlayerOverflow } from './classes/PlayerOverflow.js';
export { default as PlayerOverlay } from './classes/PlayerOverlay.js';
export { default as PlayerOverlayAutoplay } from './classes/PlayerOverlayAutoplay.js';
export { default as PlayerStoryboardSpec } from './classes/PlayerStoryboardSpec.js';
@@ -391,6 +393,8 @@ export { default as WatchNextEndScreen } from './classes/WatchNextEndScreen.js';
export { default as WatchNextTabbedResults } from './classes/WatchNextTabbedResults.js';
export { default as YpcTrailer } from './classes/YpcTrailer.js';
export { default as AnchoredSection } from './classes/ytkids/AnchoredSection.js';
export { default as KidsBlocklistPicker } from './classes/ytkids/KidsBlocklistPicker.js';
export { default as KidsBlocklistPickerItem } from './classes/ytkids/KidsBlocklistPickerItem.js';
export { default as KidsCategoriesHeader } from './classes/ytkids/KidsCategoriesHeader.js';
export { default as KidsCategoryTab } from './classes/ytkids/KidsCategoryTab.js';
export { default as KidsHomeScreen } from './classes/ytkids/KidsHomeScreen.js';

View File

@@ -15,17 +15,17 @@ import type { FetchFunction } from '../types/PlatformShim.js';
import path from 'path';
import os from 'os';
import fs from 'fs/promises';
import { readFileSync } from 'fs';
import CustomEvent from './polyfills/node-custom-event.js';
import { fileURLToPath } from 'url';
import evaluate from './jsruntime/jinter.js';
import { $INLINE_JSON } from 'ts-transformer-inline-file';
const meta_url = import.meta.url;
const is_cjs = !meta_url;
const __dirname__ = is_cjs ? __dirname : path.dirname(fileURLToPath(meta_url));
const package_json = JSON.parse(readFileSync(path.resolve(__dirname__, is_cjs ? '../package.json' : '../../package.json'), 'utf-8'));
const repo_url = package_json.homepage?.split('#')[0];
const { homepage, version, bugs } = $INLINE_JSON('../../package.json');
const repo_url = homepage?.split('#')[0];
class Cache implements ICache {
#persistent_directory: string;
@@ -101,8 +101,8 @@ class Cache implements ICache {
Platform.load({
runtime: 'node',
info: {
version: package_json.version,
bugs_url: package_json.bugs?.url || `${repo_url}/issues`,
version: version,
bugs_url: bugs?.url || `${repo_url}/issues`,
repo_url
},
server: true,

View File

@@ -352,4 +352,14 @@ export interface IEditPlaylistRequest extends ObjectSnakeToCamel<EditPlaylistEnd
playlistDescription?: string;
playlistName?: string;
}[];
}
export type BlocklistPickerRequestEndpointOptions = {
channel_id: string;
}
export type IBlocklistPickerRequest = {
blockedForKidsContent: {
external_channel_id: string;
}
}

View File

@@ -98,7 +98,10 @@
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"plugins": [
{ "transform": "ts-transformer-inline-file/transformer" }
]
},
"include": [
"src/**/*.ts",