youtube-knowledge-mcp 2.0.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -33
- package/dist/brain-schemas.d.ts +502 -0
- package/dist/brain-schemas.d.ts.map +1 -0
- package/dist/brain-schemas.js +109 -0
- package/dist/brain-schemas.js.map +1 -0
- package/dist/http/app.d.ts +16 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +176 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/auth.d.ts +38 -0
- package/dist/http/auth.d.ts.map +1 -0
- package/dist/http/auth.js +79 -0
- package/dist/http/auth.js.map +1 -0
- package/dist/http/config.d.ts +41 -0
- package/dist/http/config.d.ts.map +1 -0
- package/dist/http/config.js +65 -0
- package/dist/http/config.js.map +1 -0
- package/dist/http/rate-limiter.d.ts +24 -0
- package/dist/http/rate-limiter.d.ts.map +1 -0
- package/dist/http/rate-limiter.js +55 -0
- package/dist/http/rate-limiter.js.map +1 -0
- package/dist/http/sessions.d.ts +34 -0
- package/dist/http/sessions.d.ts.map +1 -0
- package/dist/http/sessions.js +62 -0
- package/dist/http/sessions.js.map +1 -0
- package/dist/http.d.ts +6 -48
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +35 -252
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -431
- package/dist/index.js.map +1 -1
- package/dist/prompts-brain.d.ts +4 -0
- package/dist/prompts-brain.d.ts.map +1 -0
- package/dist/prompts-brain.js +48 -0
- package/dist/prompts-brain.js.map +1 -0
- package/dist/prompts-research.d.ts +4 -0
- package/dist/prompts-research.d.ts.map +1 -0
- package/dist/prompts-research.js +74 -0
- package/dist/prompts-research.js.map +1 -0
- package/dist/prompts-shared.d.ts +13 -0
- package/dist/prompts-shared.d.ts.map +1 -0
- package/dist/prompts-shared.js +7 -0
- package/dist/prompts-shared.js.map +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +5 -58
- package/dist/prompts.js.map +1 -1
- package/dist/registry/brain-tools.d.ts +4 -0
- package/dist/registry/brain-tools.d.ts.map +1 -0
- package/dist/registry/brain-tools.js +104 -0
- package/dist/registry/brain-tools.js.map +1 -0
- package/dist/registry/channel-tools.d.ts +4 -0
- package/dist/registry/channel-tools.d.ts.map +1 -0
- package/dist/registry/channel-tools.js +53 -0
- package/dist/registry/channel-tools.js.map +1 -0
- package/dist/registry/health-tools.d.ts +4 -0
- package/dist/registry/health-tools.d.ts.map +1 -0
- package/dist/registry/health-tools.js +21 -0
- package/dist/registry/health-tools.js.map +1 -0
- package/dist/registry/index.d.ts +8 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +27 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/library-tools.d.ts +4 -0
- package/dist/registry/library-tools.d.ts.map +1 -0
- package/dist/registry/library-tools.js +116 -0
- package/dist/registry/library-tools.js.map +1 -0
- package/dist/registry/media-tools.d.ts +4 -0
- package/dist/registry/media-tools.d.ts.map +1 -0
- package/dist/registry/media-tools.js +100 -0
- package/dist/registry/media-tools.js.map +1 -0
- package/dist/registry/thumbnail-tools.d.ts +7 -0
- package/dist/registry/thumbnail-tools.d.ts.map +1 -0
- package/dist/registry/thumbnail-tools.js +72 -0
- package/dist/registry/thumbnail-tools.js.map +1 -0
- package/dist/registry/transcript-tools.d.ts +4 -0
- package/dist/registry/transcript-tools.d.ts.map +1 -0
- package/dist/registry/transcript-tools.js +68 -0
- package/dist/registry/transcript-tools.js.map +1 -0
- package/dist/registry/types.d.ts +41 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +17 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/registry/video-tools.d.ts +4 -0
- package/dist/registry/video-tools.d.ts.map +1 -0
- package/dist/registry/video-tools.js +101 -0
- package/dist/registry/video-tools.js.map +1 -0
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +75 -6
- package/dist/resources.js.map +1 -1
- package/dist/schemas.d.ts +74 -54
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +30 -4
- package/dist/schemas.js.map +1 -1
- package/dist/thumbnail-resource.d.ts +8 -0
- package/dist/thumbnail-resource.d.ts.map +1 -0
- package/dist/thumbnail-resource.js +38 -0
- package/dist/thumbnail-resource.js.map +1 -0
- package/dist/thumbnail-schemas.d.ts +512 -0
- package/dist/thumbnail-schemas.d.ts.map +1 -0
- package/dist/thumbnail-schemas.js +95 -0
- package/dist/thumbnail-schemas.js.map +1 -0
- package/dist/tools/ask-brain.d.ts +62 -0
- package/dist/tools/ask-brain.d.ts.map +1 -0
- package/dist/tools/ask-brain.js +70 -0
- package/dist/tools/ask-brain.js.map +1 -0
- package/dist/tools/batch.d.ts +10 -10
- package/dist/tools/batch.js +3 -3
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/brain-info.d.ts +180 -0
- package/dist/tools/brain-info.d.ts.map +1 -0
- package/dist/tools/brain-info.js +108 -0
- package/dist/tools/brain-info.js.map +1 -0
- package/dist/tools/build-brain.d.ts +120 -0
- package/dist/tools/build-brain.d.ts.map +1 -0
- package/dist/tools/build-brain.js +123 -0
- package/dist/tools/build-brain.js.map +1 -0
- package/dist/tools/check-health.d.ts +2 -0
- package/dist/tools/check-health.d.ts.map +1 -1
- package/dist/tools/check-health.js +9 -0
- package/dist/tools/check-health.js.map +1 -1
- package/dist/tools/clips.d.ts +13 -45
- package/dist/tools/clips.d.ts.map +1 -1
- package/dist/tools/clips.js +52 -128
- package/dist/tools/clips.js.map +1 -1
- package/dist/tools/fetch-channel-thumbnails.d.ts +179 -0
- package/dist/tools/fetch-channel-thumbnails.d.ts.map +1 -0
- package/dist/tools/fetch-channel-thumbnails.js +123 -0
- package/dist/tools/fetch-channel-thumbnails.js.map +1 -0
- package/dist/tools/fetch-videos.d.ts +11 -8
- package/dist/tools/fetch-videos.d.ts.map +1 -1
- package/dist/tools/fetch-videos.js +3 -0
- package/dist/tools/fetch-videos.js.map +1 -1
- package/dist/tools/frames-subtitles.d.ts +44 -0
- package/dist/tools/frames-subtitles.d.ts.map +1 -0
- package/dist/tools/frames-subtitles.js +104 -0
- package/dist/tools/frames-subtitles.js.map +1 -0
- package/dist/tools/get-channel-info.d.ts +2 -0
- package/dist/tools/get-channel-info.d.ts.map +1 -1
- package/dist/tools/get-channel-info.js +8 -1
- package/dist/tools/get-channel-info.js.map +1 -1
- package/dist/tools/get-chapters.d.ts +2 -2
- package/dist/tools/get-comments.d.ts +2 -2
- package/dist/tools/get-playlist-info.d.ts.map +1 -1
- package/dist/tools/get-playlist-info.js +1 -0
- package/dist/tools/get-playlist-info.js.map +1 -1
- package/dist/tools/get-thumbnail.d.ts +38 -0
- package/dist/tools/get-thumbnail.d.ts.map +1 -0
- package/dist/tools/get-thumbnail.js +152 -0
- package/dist/tools/get-thumbnail.js.map +1 -0
- package/dist/tools/get-transcript.d.ts +2 -2
- package/dist/tools/get-transcript.d.ts.map +1 -1
- package/dist/tools/get-transcript.js +2 -14
- package/dist/tools/get-transcript.js.map +1 -1
- package/dist/tools/library.d.ts +9 -7
- package/dist/tools/library.d.ts.map +1 -1
- package/dist/tools/library.js +23 -7
- package/dist/tools/library.js.map +1 -1
- package/dist/tools/list-channel-thumbnails.d.ts +235 -0
- package/dist/tools/list-channel-thumbnails.d.ts.map +1 -0
- package/dist/tools/list-channel-thumbnails.js +79 -0
- package/dist/tools/list-channel-thumbnails.js.map +1 -0
- package/dist/tools/list-library.d.ts +4 -4
- package/dist/tools/manage-brain.d.ts +39 -0
- package/dist/tools/manage-brain.d.ts.map +1 -0
- package/dist/tools/manage-brain.js +53 -0
- package/dist/tools/manage-brain.js.map +1 -0
- package/dist/tools/save-to-library.d.ts.map +1 -1
- package/dist/tools/save-to-library.js +5 -1
- package/dist/tools/save-to-library.js.map +1 -1
- package/dist/tools/search-channels.d.ts +10 -4
- package/dist/tools/search-channels.d.ts.map +1 -1
- package/dist/tools/search-transcript.d.ts +2 -2
- package/dist/tools/search-transcript.d.ts.map +1 -1
- package/dist/tools/search-transcript.js +6 -13
- package/dist/tools/search-transcript.js.map +1 -1
- package/dist/tools/search-videos.d.ts +11 -8
- package/dist/tools/search-videos.d.ts.map +1 -1
- package/dist/utils/batches.d.ts +15 -0
- package/dist/utils/batches.d.ts.map +1 -0
- package/dist/utils/batches.js +31 -0
- package/dist/utils/batches.js.map +1 -0
- package/dist/utils/brain-build.d.ts +40 -0
- package/dist/utils/brain-build.d.ts.map +1 -0
- package/dist/utils/brain-build.js +200 -0
- package/dist/utils/brain-build.js.map +1 -0
- package/dist/utils/brain-chunks.d.ts +33 -0
- package/dist/utils/brain-chunks.d.ts.map +1 -0
- package/dist/utils/brain-chunks.js +87 -0
- package/dist/utils/brain-chunks.js.map +1 -0
- package/dist/utils/brain-index.d.ts +27 -0
- package/dist/utils/brain-index.d.ts.map +1 -0
- package/dist/utils/brain-index.js +101 -0
- package/dist/utils/brain-index.js.map +1 -0
- package/dist/utils/brain-ingest.d.ts +57 -0
- package/dist/utils/brain-ingest.d.ts.map +1 -0
- package/dist/utils/brain-ingest.js +127 -0
- package/dist/utils/brain-ingest.js.map +1 -0
- package/dist/utils/brain-lock.d.ts +4 -0
- package/dist/utils/brain-lock.d.ts.map +1 -0
- package/dist/utils/brain-lock.js +17 -0
- package/dist/utils/brain-lock.js.map +1 -0
- package/dist/utils/brain-lookup.d.ts +11 -0
- package/dist/utils/brain-lookup.d.ts.map +1 -0
- package/dist/utils/brain-lookup.js +36 -0
- package/dist/utils/brain-lookup.js.map +1 -0
- package/dist/utils/brain-paths.d.ts +19 -0
- package/dist/utils/brain-paths.d.ts.map +1 -0
- package/dist/utils/brain-paths.js +34 -0
- package/dist/utils/brain-paths.js.map +1 -0
- package/dist/utils/brain-phrases.d.ts +31 -0
- package/dist/utils/brain-phrases.d.ts.map +1 -0
- package/dist/utils/brain-phrases.js +116 -0
- package/dist/utils/brain-phrases.js.map +1 -0
- package/dist/utils/brain-stats.d.ts +25 -0
- package/dist/utils/brain-stats.d.ts.map +1 -0
- package/dist/utils/brain-stats.js +64 -0
- package/dist/utils/brain-stats.js.map +1 -0
- package/dist/utils/brain-storage.d.ts +28 -0
- package/dist/utils/brain-storage.d.ts.map +1 -0
- package/dist/utils/brain-storage.js +87 -0
- package/dist/utils/brain-storage.js.map +1 -0
- package/dist/utils/caption-probe.d.ts +7 -0
- package/dist/utils/caption-probe.d.ts.map +1 -0
- package/dist/utils/caption-probe.js +36 -0
- package/dist/utils/caption-probe.js.map +1 -0
- package/dist/utils/channel-images.d.ts +16 -0
- package/dist/utils/channel-images.d.ts.map +1 -0
- package/dist/utils/channel-images.js +35 -0
- package/dist/utils/channel-images.js.map +1 -0
- package/dist/utils/channel-lookup.d.ts +5 -0
- package/dist/utils/channel-lookup.d.ts.map +1 -0
- package/dist/utils/channel-lookup.js +37 -0
- package/dist/utils/channel-lookup.js.map +1 -0
- package/dist/utils/chapters.d.ts +11 -0
- package/dist/utils/chapters.d.ts.map +1 -0
- package/dist/utils/chapters.js +24 -0
- package/dist/utils/chapters.js.map +1 -0
- package/dist/utils/clips.d.ts.map +1 -1
- package/dist/utils/clips.js +22 -30
- package/dist/utils/clips.js.map +1 -1
- package/dist/utils/env.d.ts +26 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +72 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/errors.d.ts +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +20 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/file-lock.d.ts +34 -0
- package/dist/utils/file-lock.d.ts.map +1 -0
- package/dist/utils/file-lock.js +91 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/dist/utils/flat-listing.d.ts +89 -0
- package/dist/utils/flat-listing.d.ts.map +1 -0
- package/dist/utils/flat-listing.js +68 -0
- package/dist/utils/flat-listing.js.map +1 -0
- package/dist/utils/format.d.ts +1 -3
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +1 -5
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/guard.d.ts +21 -0
- package/dist/utils/guard.d.ts.map +1 -0
- package/dist/utils/guard.js +105 -0
- package/dist/utils/guard.js.map +1 -0
- package/dist/utils/image-dimensions.d.ts +19 -0
- package/dist/utils/image-dimensions.d.ts.map +1 -0
- package/dist/utils/image-dimensions.js +93 -0
- package/dist/utils/image-dimensions.js.map +1 -0
- package/dist/utils/image-fetch.d.ts +31 -0
- package/dist/utils/image-fetch.d.ts.map +1 -0
- package/dist/utils/image-fetch.js +141 -0
- package/dist/utils/image-fetch.js.map +1 -0
- package/dist/utils/json-file.d.ts +45 -0
- package/dist/utils/json-file.d.ts.map +1 -0
- package/dist/utils/json-file.js +60 -0
- package/dist/utils/json-file.js.map +1 -0
- package/dist/utils/paths.d.ts +19 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +27 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/pattern.d.ts +30 -0
- package/dist/utils/pattern.d.ts.map +1 -0
- package/dist/utils/pattern.js +130 -0
- package/dist/utils/pattern.js.map +1 -0
- package/dist/utils/search-index.d.ts +22 -7
- package/dist/utils/search-index.d.ts.map +1 -1
- package/dist/utils/search-index.js +26 -8
- package/dist/utils/search-index.js.map +1 -1
- package/dist/utils/storage.d.ts +14 -44
- package/dist/utils/storage.d.ts.map +1 -1
- package/dist/utils/storage.js +47 -84
- package/dist/utils/storage.js.map +1 -1
- package/dist/utils/subtitles.d.ts +7 -0
- package/dist/utils/subtitles.d.ts.map +1 -0
- package/dist/utils/subtitles.js +30 -0
- package/dist/utils/subtitles.js.map +1 -0
- package/dist/utils/thumbnail-entry.d.ts +19 -0
- package/dist/utils/thumbnail-entry.d.ts.map +1 -0
- package/dist/utils/thumbnail-entry.js +119 -0
- package/dist/utils/thumbnail-entry.js.map +1 -0
- package/dist/utils/thumbnail-fetch.d.ts +37 -0
- package/dist/utils/thumbnail-fetch.d.ts.map +1 -0
- package/dist/utils/thumbnail-fetch.js +89 -0
- package/dist/utils/thumbnail-fetch.js.map +1 -0
- package/dist/utils/thumbnail-ladder.d.ts +44 -0
- package/dist/utils/thumbnail-ladder.d.ts.map +1 -0
- package/dist/utils/thumbnail-ladder.js +68 -0
- package/dist/utils/thumbnail-ladder.js.map +1 -0
- package/dist/utils/thumbnail-listing.d.ts +16 -0
- package/dist/utils/thumbnail-listing.d.ts.map +1 -0
- package/dist/utils/thumbnail-listing.js +26 -0
- package/dist/utils/thumbnail-listing.js.map +1 -0
- package/dist/utils/thumbnail-paths.d.ts +20 -0
- package/dist/utils/thumbnail-paths.d.ts.map +1 -0
- package/dist/utils/thumbnail-paths.js +35 -0
- package/dist/utils/thumbnail-paths.js.map +1 -0
- package/dist/utils/thumbnail-store.d.ts +19 -0
- package/dist/utils/thumbnail-store.d.ts.map +1 -0
- package/dist/utils/thumbnail-store.js +125 -0
- package/dist/utils/thumbnail-store.js.map +1 -0
- package/dist/utils/transcript-cache.d.ts +20 -0
- package/dist/utils/transcript-cache.d.ts.map +1 -0
- package/dist/utils/transcript-cache.js +127 -0
- package/dist/utils/transcript-cache.js.map +1 -0
- package/dist/utils/transcript-search.d.ts +20 -0
- package/dist/utils/transcript-search.d.ts.map +1 -0
- package/dist/utils/transcript-search.js +35 -0
- package/dist/utils/transcript-search.js.map +1 -0
- package/dist/utils/transcript.d.ts +14 -34
- package/dist/utils/transcript.d.ts.map +1 -1
- package/dist/utils/transcript.js +5 -64
- package/dist/utils/transcript.js.map +1 -1
- package/dist/utils/validate-youtube.d.ts +35 -0
- package/dist/utils/validate-youtube.d.ts.map +1 -0
- package/dist/utils/validate-youtube.js +87 -0
- package/dist/utils/validate-youtube.js.map +1 -0
- package/dist/utils/validate.d.ts +11 -3
- package/dist/utils/validate.d.ts.map +1 -1
- package/dist/utils/validate.js +43 -18
- package/dist/utils/validate.js.map +1 -1
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +19 -0
- package/dist/utils/version.js.map +1 -0
- package/dist/utils/youtube-channel.d.ts +44 -0
- package/dist/utils/youtube-channel.d.ts.map +1 -0
- package/dist/utils/youtube-channel.js +61 -0
- package/dist/utils/youtube-channel.js.map +1 -0
- package/dist/utils/youtube-download.d.ts +27 -0
- package/dist/utils/youtube-download.d.ts.map +1 -0
- package/dist/utils/youtube-download.js +118 -0
- package/dist/utils/youtube-download.js.map +1 -0
- package/dist/utils/youtube-schemas.d.ts +394 -0
- package/dist/utils/youtube-schemas.d.ts.map +1 -0
- package/dist/utils/youtube-schemas.js +118 -0
- package/dist/utils/youtube-schemas.js.map +1 -0
- package/dist/utils/youtube-search.d.ts +14 -0
- package/dist/utils/youtube-search.d.ts.map +1 -0
- package/dist/utils/youtube-search.js +39 -0
- package/dist/utils/youtube-search.js.map +1 -0
- package/dist/utils/youtube-url.d.ts +25 -0
- package/dist/utils/youtube-url.d.ts.map +1 -0
- package/dist/utils/youtube-url.js +75 -0
- package/dist/utils/youtube-url.js.map +1 -0
- package/dist/utils/youtube-video.d.ts +47 -0
- package/dist/utils/youtube-video.d.ts.map +1 -0
- package/dist/utils/youtube-video.js +98 -0
- package/dist/utils/youtube-video.js.map +1 -0
- package/dist/utils/youtube.d.ts +13 -111
- package/dist/utils/youtube.d.ts.map +1 -1
- package/dist/utils/youtube.js +11 -480
- package/dist/utils/youtube.js.map +1 -1
- package/dist/utils/ytdlp-env.d.ts +33 -0
- package/dist/utils/ytdlp-env.d.ts.map +1 -0
- package/dist/utils/ytdlp-env.js +121 -0
- package/dist/utils/ytdlp-env.js.map +1 -0
- package/dist/utils/ytdlp-limiter.d.ts +24 -0
- package/dist/utils/ytdlp-limiter.d.ts.map +1 -0
- package/dist/utils/ytdlp-limiter.js +69 -0
- package/dist/utils/ytdlp-limiter.js.map +1 -0
- package/dist/utils/ytdlp-parse.d.ts +13 -0
- package/dist/utils/ytdlp-parse.d.ts.map +1 -0
- package/dist/utils/ytdlp-parse.js +48 -0
- package/dist/utils/ytdlp-parse.js.map +1 -0
- package/dist/utils/ytdlp.d.ts +13 -18
- package/dist/utils/ytdlp.d.ts.map +1 -1
- package/dist/utils/ytdlp.js +21 -110
- package/dist/utils/ytdlp.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type BrainManifest } from '../brain-schemas.js';
|
|
2
|
+
/**
|
|
3
|
+
* What a brain records about itself, and who is allowed to be writing it.
|
|
4
|
+
*
|
|
5
|
+
* The manifest is the brain's account of its own construction: which videos it
|
|
6
|
+
* covers, which it could not read, and where a build stopped. Everything that
|
|
7
|
+
* makes a build resumable is here rather than inferred from what happens to be
|
|
8
|
+
* on disk.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BRAIN_MANIFEST_VERSION = 1;
|
|
11
|
+
export declare function ensureBrainDir(channelId: string): Promise<string>;
|
|
12
|
+
export declare function readManifest(channelId: string): Promise<BrainManifest | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* The manifest, or a typed failure naming the tool that would create it.
|
|
15
|
+
*
|
|
16
|
+
* Most callers want this rather than `readManifest`: "there is no brain yet" is
|
|
17
|
+
* the single most likely reason a brain tool cannot do its job, and the model
|
|
18
|
+
* needs to be told what to call, not handed an undefined.
|
|
19
|
+
*/
|
|
20
|
+
export declare function requireManifest(channelId: string): Promise<BrainManifest>;
|
|
21
|
+
export declare function writeManifest(manifest: BrainManifest): Promise<void>;
|
|
22
|
+
/** Every brain on disk, newest first. Unreadable directories are skipped. */
|
|
23
|
+
export declare function listManifests(): Promise<BrainManifest[]>;
|
|
24
|
+
export declare function deleteBrain(channelId: string): Promise<boolean>;
|
|
25
|
+
export declare function readProfile(channelId: string): Promise<string | undefined>;
|
|
26
|
+
export declare function writeProfile(channelId: string, content: string): Promise<string>;
|
|
27
|
+
export declare function hasProfile(channelId: string): boolean;
|
|
28
|
+
//# sourceMappingURL=brain-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-storage.d.ts","sourceRoot":"","sources":["../../src/utils/brain-storage.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAO9E;;;;;;;GAOG;AAEH,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvE;AAID,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAExF;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAW/E;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;AAED,6EAA6E;AAC7E,wBAAsB,aAAa,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAmB9D;AAED,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQrE;AAID,wBAAsB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAIhF;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKtF;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile, readdir, rm } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { brainManifestSchema } from '../brain-schemas.js';
|
|
5
|
+
import { YouTubeError } from './errors.js';
|
|
6
|
+
import { readJsonFile, writeFileAtomic, writeJsonAtomic } from './json-file.js';
|
|
7
|
+
import { ensurePrivateDir } from './paths.js';
|
|
8
|
+
import { brainDir, brainsDir, manifestPath, profilePath } from './brain-paths.js';
|
|
9
|
+
import { forgetBrainCorpus } from './brain-index.js';
|
|
10
|
+
/**
|
|
11
|
+
* What a brain records about itself, and who is allowed to be writing it.
|
|
12
|
+
*
|
|
13
|
+
* The manifest is the brain's account of its own construction: which videos it
|
|
14
|
+
* covers, which it could not read, and where a build stopped. Everything that
|
|
15
|
+
* makes a build resumable is here rather than inferred from what happens to be
|
|
16
|
+
* on disk.
|
|
17
|
+
*/
|
|
18
|
+
export const BRAIN_MANIFEST_VERSION = 1;
|
|
19
|
+
export async function ensureBrainDir(channelId) {
|
|
20
|
+
const directory = brainDir(channelId);
|
|
21
|
+
return ensurePrivateDir(directory);
|
|
22
|
+
}
|
|
23
|
+
// -- Manifest ------------------------------------------------------------
|
|
24
|
+
export async function readManifest(channelId) {
|
|
25
|
+
return readJsonFile(manifestPath(channelId), brainManifestSchema);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The manifest, or a typed failure naming the tool that would create it.
|
|
29
|
+
*
|
|
30
|
+
* Most callers want this rather than `readManifest`: "there is no brain yet" is
|
|
31
|
+
* the single most likely reason a brain tool cannot do its job, and the model
|
|
32
|
+
* needs to be told what to call, not handed an undefined.
|
|
33
|
+
*/
|
|
34
|
+
export async function requireManifest(channelId) {
|
|
35
|
+
const manifest = await readManifest(channelId);
|
|
36
|
+
if (manifest === undefined) {
|
|
37
|
+
throw new YouTubeError('NOT_FOUND', `No brain has been built for channel ${channelId}.`, {
|
|
38
|
+
nextStep: 'Call build_brain with the channel URL or handle, or list_brains to see what exists.',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return manifest;
|
|
42
|
+
}
|
|
43
|
+
export async function writeManifest(manifest) {
|
|
44
|
+
await ensureBrainDir(manifest.channel.channelId);
|
|
45
|
+
await writeJsonAtomic(manifestPath(manifest.channel.channelId), manifest);
|
|
46
|
+
}
|
|
47
|
+
/** Every brain on disk, newest first. Unreadable directories are skipped. */
|
|
48
|
+
export async function listManifests() {
|
|
49
|
+
if (!existsSync(brainsDir()))
|
|
50
|
+
return [];
|
|
51
|
+
const entries = await readdir(brainsDir(), { withFileTypes: true });
|
|
52
|
+
const manifests = [];
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.isDirectory())
|
|
55
|
+
continue;
|
|
56
|
+
// A directory that is not a channel id was not written by us, and passing
|
|
57
|
+
// it to `brainDir` would throw rather than skip it.
|
|
58
|
+
const manifest = await readJsonFile(join(brainsDir(), entry.name, 'manifest.json'), brainManifestSchema);
|
|
59
|
+
if (manifest !== undefined)
|
|
60
|
+
manifests.push(manifest);
|
|
61
|
+
}
|
|
62
|
+
return manifests.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
63
|
+
}
|
|
64
|
+
export async function deleteBrain(channelId) {
|
|
65
|
+
const directory = brainDir(channelId);
|
|
66
|
+
const existed = existsSync(directory);
|
|
67
|
+
await rm(directory, { recursive: true, force: true });
|
|
68
|
+
forgetBrainCorpus(channelId);
|
|
69
|
+
return existed;
|
|
70
|
+
}
|
|
71
|
+
// -- Profile -------------------------------------------------------------
|
|
72
|
+
export async function readProfile(channelId) {
|
|
73
|
+
const path = profilePath(channelId);
|
|
74
|
+
if (!existsSync(path))
|
|
75
|
+
return undefined;
|
|
76
|
+
return readFile(path, 'utf-8');
|
|
77
|
+
}
|
|
78
|
+
export async function writeProfile(channelId, content) {
|
|
79
|
+
await ensureBrainDir(channelId);
|
|
80
|
+
const path = profilePath(channelId);
|
|
81
|
+
await writeFileAtomic(path, content);
|
|
82
|
+
return path;
|
|
83
|
+
}
|
|
84
|
+
export function hasProfile(channelId) {
|
|
85
|
+
return existsSync(profilePath(channelId));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=brain-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-storage.js","sourceRoot":"","sources":["../../src/utils/brain-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { YouTubeError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Ask yt-dlp which caption tracks the video actually has, so the error can name
|
|
4
|
+
* the languages that would work instead of just saying "not found".
|
|
5
|
+
*/
|
|
6
|
+
export declare function noCaptionsError(url: string, requested: string): Promise<YouTubeError>;
|
|
7
|
+
//# sourceMappingURL=caption-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caption-probe.d.ts","sourceRoot":"","sources":["../../src/utils/caption-probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C;;;GAGG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmC3F"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { YouTubeError } from './errors.js';
|
|
2
|
+
import { parseYtDlpJson, runYtDlp } from './ytdlp.js';
|
|
3
|
+
import { captionTracksSchema } from './youtube-schemas.js';
|
|
4
|
+
/**
|
|
5
|
+
* Ask yt-dlp which caption tracks the video actually has, so the error can name
|
|
6
|
+
* the languages that would work instead of just saying "not found".
|
|
7
|
+
*/
|
|
8
|
+
export async function noCaptionsError(url, requested) {
|
|
9
|
+
let available = [];
|
|
10
|
+
try {
|
|
11
|
+
const stdout = await runYtDlp(['-j', '--skip-download'], {
|
|
12
|
+
label: 'get_transcript (caption probe)',
|
|
13
|
+
target: url,
|
|
14
|
+
});
|
|
15
|
+
const data = parseYtDlpJson(stdout, captionTracksSchema, 'caption tracks');
|
|
16
|
+
available = [
|
|
17
|
+
...Object.keys(data.subtitles ?? {}),
|
|
18
|
+
...Object.keys(data.automatic_captions ?? {}),
|
|
19
|
+
]
|
|
20
|
+
.filter((code) => !code.endsWith('-orig'))
|
|
21
|
+
.filter((code, index, all) => all.indexOf(code) === index)
|
|
22
|
+
.sort();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// The probe is a nicety; never let it mask the original problem.
|
|
26
|
+
}
|
|
27
|
+
if (available.length === 0) {
|
|
28
|
+
return new YouTubeError('NO_CAPTIONS', 'This video has no captions in any language.', {
|
|
29
|
+
nextStep: 'Try get_video_info for the description, or get_comments for viewer discussion instead.',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const shown = available.slice(0, 25).join(', ');
|
|
33
|
+
const more = available.length > 25 ? `, and ${available.length - 25} more` : '';
|
|
34
|
+
return new YouTubeError('NO_CAPTIONS', `No "${requested}" captions are available for this video.`, { nextStep: `Call get_transcript again with one of: ${shown}${more}.` });
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=caption-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caption-probe.js","sourceRoot":"","sources":["../../src/utils/caption-probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,SAAiB;IAClE,IAAI,SAAS,GAAa,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE;YACvD,KAAK,EAAE,gCAAgC;YACvC,MAAM,EAAE,GAAG;SACZ,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;QAE3E,SAAS,GAAG;YACV,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;YACpC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,IAAI,EAAE,CAAC;SAC9C;aACE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aACzC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC;aACzD,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,YAAY,CAAC,aAAa,EAAE,6CAA6C,EAAE;YACpF,QAAQ,EACN,wFAAwF;SAC3F,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,OAAO,IAAI,YAAY,CACrB,aAAa,EACb,OAAO,SAAS,0CAA0C,EAC1D,EAAE,QAAQ,EAAE,0CAA0C,KAAK,GAAG,IAAI,GAAG,EAAE,CACxE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picking a channel's avatar and banner out of the thumbnails yt-dlp lists for
|
|
3
|
+
* the channel page.
|
|
4
|
+
*
|
|
5
|
+
* Verified against yt-dlp 2026.07.04: the array holds banner crops at several
|
|
6
|
+
* widths, one `banner_uncropped`, a square avatar, and one `avatar_uncropped`.
|
|
7
|
+
* The uncropped ids are preferred; should they ever be renamed, the fallback
|
|
8
|
+
* needs nothing but widths and heights — the largest square is the avatar and
|
|
9
|
+
* the widest image more than twice as wide as it is tall is the banner.
|
|
10
|
+
*/
|
|
11
|
+
export interface ChannelImages {
|
|
12
|
+
avatarUrl?: string;
|
|
13
|
+
bannerUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function selectChannelImages(thumbnails: unknown): ChannelImages;
|
|
16
|
+
//# sourceMappingURL=channel-images.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-images.d.ts","sourceRoot":"","sources":["../../src/utils/channel-images.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8BD,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,CAkBtE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { listedImageSchema } from './flat-listing.js';
|
|
3
|
+
import { IMAGE_HOSTS } from './image-fetch.js';
|
|
4
|
+
const HOSTS = new Set(IMAGE_HOSTS);
|
|
5
|
+
function onAllowedHost(image) {
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(image.url);
|
|
8
|
+
return url.protocol === 'https:' && HOSTS.has(url.hostname.toLowerCase());
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function sized(images) {
|
|
15
|
+
return images.flatMap(({ url, width, height }) => typeof width === 'number' && typeof height === 'number' ? [{ url, width, height }] : []);
|
|
16
|
+
}
|
|
17
|
+
function largest(images, keep) {
|
|
18
|
+
return images.filter(keep).sort((a, b) => b.width * b.height - a.width * a.height)[0];
|
|
19
|
+
}
|
|
20
|
+
export function selectChannelImages(thumbnails) {
|
|
21
|
+
const parsed = z.array(listedImageSchema).safeParse(thumbnails);
|
|
22
|
+
if (!parsed.success)
|
|
23
|
+
return {};
|
|
24
|
+
const images = parsed.data.filter(onAllowedHost);
|
|
25
|
+
const measured = sized(images);
|
|
26
|
+
const avatar = images.find((image) => image.id === 'avatar_uncropped') ??
|
|
27
|
+
largest(measured, (image) => image.width === image.height);
|
|
28
|
+
const banner = images.find((image) => image.id === 'banner_uncropped') ??
|
|
29
|
+
largest(measured, (image) => image.width > 2 * image.height);
|
|
30
|
+
return {
|
|
31
|
+
...(avatar === undefined ? {} : { avatarUrl: avatar.url }),
|
|
32
|
+
...(banner === undefined ? {} : { bannerUrl: banner.url }),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=channel-images.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-images.js","sourceRoot":"","sources":["../../src/utils/channel-images.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAoB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAyB/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,WAAW,CAAC,CAAC;AAE3C,SAAS,aAAa,CAAC,KAAkB;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,MAAqB;IAClC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAC/C,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CACxF,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,MAAe,EAAE,IAA+B;IAC/D,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,UAAmB;IACrD,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAChE,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,MAAM,GACV,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,kBAAkB,CAAC;QACvD,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,MAAM,GACV,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,kBAAkB,CAAC;QACvD,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAE/D,OAAO;QACL,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;QAC1D,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-lookup.d.ts","sourceRoot":"","sources":["../../src/utils/channel-lookup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAgBhD,wBAAgB,aAAa,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,EAC9D,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,MAAM,GACd,CAAC,EAAE,CAGL"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the records that belong to a channel, from whatever the caller called it.
|
|
3
|
+
*
|
|
4
|
+
* Every local tool answers from disk, so none of them should need the network
|
|
5
|
+
* to work out which channel is meant — asking YouTube to resolve a handle
|
|
6
|
+
* before every search would put a round trip in front of a lookup that is
|
|
7
|
+
* otherwise instant, and would make the data unusable offline. A stored record
|
|
8
|
+
* already carries the channel's id, handle, name and URL, which is everything
|
|
9
|
+
* a caller is likely to type.
|
|
10
|
+
*/
|
|
11
|
+
const CHANNEL_ID_IN_TEXT = /UC[A-Za-z0-9_-]{22}/;
|
|
12
|
+
const HANDLE_IN_TEXT = /@[\w.-]+/;
|
|
13
|
+
export function findByChannel(items, channel) {
|
|
14
|
+
const wanted = candidates(channel);
|
|
15
|
+
return items.filter((item) => keysOf(item.channel).some((key) => wanted.has(key)));
|
|
16
|
+
}
|
|
17
|
+
function candidates(channel) {
|
|
18
|
+
const keys = new Set([normalize(channel)]);
|
|
19
|
+
const id = CHANNEL_ID_IN_TEXT.exec(channel)?.[0];
|
|
20
|
+
if (id !== undefined)
|
|
21
|
+
keys.add(normalize(id));
|
|
22
|
+
const handle = HANDLE_IN_TEXT.exec(channel)?.[0];
|
|
23
|
+
if (handle !== undefined) {
|
|
24
|
+
keys.add(normalize(handle));
|
|
25
|
+
keys.add(normalize(handle.slice(1)));
|
|
26
|
+
}
|
|
27
|
+
return keys;
|
|
28
|
+
}
|
|
29
|
+
function keysOf({ channelId, handle, name, channelUrl }) {
|
|
30
|
+
return [channelId, handle, handle.replace(/^@/, ''), name, channelUrl]
|
|
31
|
+
.map(normalize)
|
|
32
|
+
.filter((key) => key !== '');
|
|
33
|
+
}
|
|
34
|
+
function normalize(value) {
|
|
35
|
+
return value.trim().toLowerCase().replace(/\/+$/, '');
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=channel-lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-lookup.js","sourceRoot":"","sources":["../../src/utils/channel-lookup.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AACjD,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC,MAAM,UAAU,aAAa,CAC3B,KAAU,EACV,OAAe;IAEf,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnD,MAAM,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,EAAE,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAe;IAClE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC;SACnE,GAAG,CAAC,SAAS,CAAC;SACd,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Chapter } from './youtube.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolving a chapter name a caller typed to a chapter the video actually has.
|
|
4
|
+
*
|
|
5
|
+
* Exact title first, then a substring, both case-insensitive: people remember
|
|
6
|
+
* "the middle" of a talk, not "03 — The Middle Section (part 2)". Two tools
|
|
7
|
+
* used to carry identical copies of this; a mismatch in how they matched
|
|
8
|
+
* would have meant a chapter that clips but cannot be read, or the reverse.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveChapter(chapters: Chapter[], name: string, whenNone: string): Chapter;
|
|
11
|
+
//# sourceMappingURL=chapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapters.d.ts","sourceRoot":"","sources":["../../src/utils/chapters.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAiB3F"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { YouTubeError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolving a chapter name a caller typed to a chapter the video actually has.
|
|
4
|
+
*
|
|
5
|
+
* Exact title first, then a substring, both case-insensitive: people remember
|
|
6
|
+
* "the middle" of a talk, not "03 — The Middle Section (part 2)". Two tools
|
|
7
|
+
* used to carry identical copies of this; a mismatch in how they matched
|
|
8
|
+
* would have meant a chapter that clips but cannot be read, or the reverse.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveChapter(chapters, name, whenNone) {
|
|
11
|
+
if (chapters.length === 0) {
|
|
12
|
+
throw new YouTubeError('NOT_FOUND', 'This video has no chapters.', { nextStep: whenNone });
|
|
13
|
+
}
|
|
14
|
+
const wanted = name.toLowerCase();
|
|
15
|
+
const match = chapters.find((chapter) => chapter.title.toLowerCase() === wanted) ??
|
|
16
|
+
chapters.find((chapter) => chapter.title.toLowerCase().includes(wanted));
|
|
17
|
+
if (!match) {
|
|
18
|
+
throw new YouTubeError('NOT_FOUND', `No chapter matches "${name}".`, {
|
|
19
|
+
nextStep: `Available chapters: ${chapters.map((chapter) => chapter.title).join(', ')}`,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return match;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=chapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapters.js","sourceRoot":"","sources":["../../src/utils/chapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,QAAmB,EAAE,IAAY,EAAE,QAAgB;IAChF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,6BAA6B,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,KAAK,GACT,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;QAClE,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAE3E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,uBAAuB,IAAI,IAAI,EAAE;YACnE,QAAQ,EAAE,uBAAuB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SACvF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clips.d.ts","sourceRoot":"","sources":["../../src/utils/clips.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"clips.d.ts","sourceRoot":"","sources":["../../src/utils/clips.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBhE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAwCjF;AAMD,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,YAAY,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,UAAU,CAAC,CA2DrB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,GAAG,KAAK,CAAA;CAAE,GACrD,OAAO,CAAC,WAAW,CAAC,CAoEtB;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
package/dist/utils/clips.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { homedir } from 'node:os';
|
|
2
1
|
import { join } from 'node:path';
|
|
3
2
|
import { mkdir } from 'node:fs/promises';
|
|
4
3
|
import { execa } from 'execa';
|
|
@@ -6,8 +5,11 @@ import { YouTubeError } from './errors.js';
|
|
|
6
5
|
import { requireFfmpeg } from './preflight.js';
|
|
7
6
|
import { resolveOutputDir } from './validate.js';
|
|
8
7
|
import { TIMEOUTS, runYtDlp } from './ytdlp.js';
|
|
8
|
+
import { AFTER_MOVE_TEMPLATE, readAfterMove } from './youtube-download.js';
|
|
9
9
|
import { formatSrtTimestamp } from './transcript.js';
|
|
10
10
|
import { getChapters, getVideoInfo } from './youtube.js';
|
|
11
|
+
import { resolveChapter } from './chapters.js';
|
|
12
|
+
import { dataDir } from './paths.js';
|
|
11
13
|
/**
|
|
12
14
|
* Pulling usable excerpts out of a video for editing.
|
|
13
15
|
*
|
|
@@ -16,9 +18,9 @@ import { getChapters, getVideoInfo } from './youtube.js';
|
|
|
16
18
|
* range that covers the requested window, which is both far faster and far
|
|
17
19
|
* kinder to YouTube than pulling a three-hour file to keep 20 seconds of it.
|
|
18
20
|
*/
|
|
19
|
-
const CLIPS_DIR =
|
|
20
|
-
const FRAMES_DIR =
|
|
21
|
-
const SUBTITLES_DIR =
|
|
21
|
+
const CLIPS_DIR = dataDir('clips');
|
|
22
|
+
const FRAMES_DIR = dataDir('frames');
|
|
23
|
+
const SUBTITLES_DIR = dataDir('subtitles');
|
|
22
24
|
/**
|
|
23
25
|
* Filesystem-safe stem derived from the video title.
|
|
24
26
|
*
|
|
@@ -53,20 +55,7 @@ export async function resolveRange(video, options) {
|
|
|
53
55
|
const info = await getVideoInfo(video);
|
|
54
56
|
let range;
|
|
55
57
|
if (options.chapter !== undefined) {
|
|
56
|
-
const
|
|
57
|
-
if (chapters.length === 0) {
|
|
58
|
-
throw new YouTubeError('NOT_FOUND', 'This video has no chapters.', {
|
|
59
|
-
nextStep: 'Pass start and end instead.',
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
const wanted = options.chapter.toLowerCase();
|
|
63
|
-
const match = chapters.find((chapter) => chapter.title.toLowerCase() === wanted) ??
|
|
64
|
-
chapters.find((chapter) => chapter.title.toLowerCase().includes(wanted));
|
|
65
|
-
if (!match) {
|
|
66
|
-
throw new YouTubeError('NOT_FOUND', `No chapter matches "${options.chapter}".`, {
|
|
67
|
-
nextStep: `Available chapters: ${chapters.map((chapter) => chapter.title).join(', ')}`,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
58
|
+
const match = resolveChapter(await getChapters(video), options.chapter, 'Pass start and end instead.');
|
|
70
59
|
range = { start: match.startTime, end: match.endTime };
|
|
71
60
|
}
|
|
72
61
|
else {
|
|
@@ -123,18 +112,18 @@ export async function extractClip(video, rangeOptions, options) {
|
|
|
123
112
|
else {
|
|
124
113
|
args.push('--merge-output-format', options.container);
|
|
125
114
|
}
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
// The after_move stage fires once post-processing has produced the final
|
|
116
|
+
// file, so the path it prints is the real one — extension included — and
|
|
117
|
+
// nothing has to be spawned a second time to learn it.
|
|
118
|
+
args.push('--print', AFTER_MOVE_TEMPLATE);
|
|
119
|
+
const stdout = await runYtDlp(args, {
|
|
128
120
|
label: 'extract_clip',
|
|
129
121
|
timeoutMs: TIMEOUTS.download,
|
|
130
122
|
retry: false,
|
|
123
|
+
target: url,
|
|
131
124
|
});
|
|
132
|
-
const filenameOutput = await runYtDlp([...args.slice(0, -1), '--print', 'filename', '--skip-download', url], { label: 'extract_clip (filename)' });
|
|
133
125
|
const extension = options.audioOnly ? (options.audioFormat ?? 'mp3') : options.container;
|
|
134
|
-
const
|
|
135
|
-
const filePath = reported === ''
|
|
136
|
-
? join(targetDir, `${stem}.${extension}`)
|
|
137
|
-
: replaceExtension(reported, extension);
|
|
126
|
+
const filePath = stdout.trim() === '' ? join(targetDir, `${stem}.${extension}`) : readAfterMove(stdout).filepath;
|
|
138
127
|
return {
|
|
139
128
|
videoId,
|
|
140
129
|
title,
|
|
@@ -144,9 +133,6 @@ export async function extractClip(video, rangeOptions, options) {
|
|
|
144
133
|
duration: range.end - range.start,
|
|
145
134
|
};
|
|
146
135
|
}
|
|
147
|
-
function replaceExtension(path, extension) {
|
|
148
|
-
return path.replace(/\.[^./\\]+$/, `.${extension}`);
|
|
149
|
-
}
|
|
150
136
|
/**
|
|
151
137
|
* Grab a single still.
|
|
152
138
|
*
|
|
@@ -162,12 +148,16 @@ export async function extractFrame(video, timestamp, options) {
|
|
|
162
148
|
}
|
|
163
149
|
await mkdir(targetDir, { recursive: true });
|
|
164
150
|
const url = `https://www.youtube.com/watch?v=${info.id}`;
|
|
165
|
-
const mediaUrl = (await runYtDlp(['-f', 'bestvideo[height<=1080]/best', '--get-url', '--no-playlist'
|
|
151
|
+
const mediaUrl = (await runYtDlp(['-f', 'bestvideo[height<=1080]/best', '--get-url', '--no-playlist'], {
|
|
166
152
|
label: 'extract_frame (resolve)',
|
|
153
|
+
target: url,
|
|
167
154
|
}))
|
|
168
155
|
.trim()
|
|
169
156
|
.split('\n')[0];
|
|
170
|
-
|
|
157
|
+
// ffmpeg accepts file:, pipe:, concat: and more as inputs; the only thing
|
|
158
|
+
// yt-dlp should have resolved is an https media URL, and the allowlist
|
|
159
|
+
// below makes ffmpeg refuse anything else even if it had.
|
|
160
|
+
if (!mediaUrl?.startsWith('https://')) {
|
|
171
161
|
throw new YouTubeError('YTDLP_FAILED', 'Could not resolve a video stream for this video.', {
|
|
172
162
|
nextStep: 'Check the video is playable, or call check_health.',
|
|
173
163
|
});
|
|
@@ -175,6 +165,8 @@ export async function extractFrame(video, timestamp, options) {
|
|
|
175
165
|
const filePath = join(targetDir, `${safeStem(info.title, info.id)} [${Math.round(timestamp)}s].${options.format}`);
|
|
176
166
|
try {
|
|
177
167
|
await execa('ffmpeg', [
|
|
168
|
+
'-protocol_whitelist',
|
|
169
|
+
'https,tls,tcp,crypto',
|
|
178
170
|
// -ss before -i seeks without decoding everything up to that point.
|
|
179
171
|
'-ss',
|
|
180
172
|
String(timestamp),
|
package/dist/utils/clips.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clips.js","sourceRoot":"","sources":["../../src/utils/clips.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"clips.js","sourceRoot":"","sources":["../../src/utils/clips.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading configuration from the environment without trusting it.
|
|
3
|
+
*
|
|
4
|
+
* A bare `Number()` of an environment value turns a typo into `NaN`, and `NaN` compares
|
|
5
|
+
* false with everything: a concurrency limit of `NaN` queued every yt-dlp call
|
|
6
|
+
* forever, and a cache TTL of `NaN` never expired anything. Every numeric or
|
|
7
|
+
* enumerated setting therefore comes through here, where an unusable value
|
|
8
|
+
* falls back to the default and says so once on stderr.
|
|
9
|
+
*/
|
|
10
|
+
export interface IntBounds {
|
|
11
|
+
min?: number;
|
|
12
|
+
max?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function envString(name: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
15
|
+
export declare function envInt(name: string, fallback: number, bounds?: IntBounds, env?: NodeJS.ProcessEnv): number;
|
|
16
|
+
export declare function envBool(name: string, fallback: boolean, env?: NodeJS.ProcessEnv): boolean;
|
|
17
|
+
export declare function envList(name: string, env?: NodeJS.ProcessEnv): string[];
|
|
18
|
+
/**
|
|
19
|
+
* One of a closed set of values, or `undefined` when unset.
|
|
20
|
+
*
|
|
21
|
+
* Unlike the helpers above this throws on an unknown value: a browser name or
|
|
22
|
+
* proxy scheme that is misspelt is a configuration mistake the operator wants
|
|
23
|
+
* to hear about at boot, not a setting to quietly ignore.
|
|
24
|
+
*/
|
|
25
|
+
export declare function envEnum<T extends string>(name: string, values: readonly T[], env?: NodeJS.ProcessEnv): T | undefined;
|
|
26
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/utils/env.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAMD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAGhG;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,SAAc,EACtB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAkBR;AAKD,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAOT;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,EAAE,CAKpF;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,CAAC,GAAG,SAAS,CASf"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading configuration from the environment without trusting it.
|
|
3
|
+
*
|
|
4
|
+
* A bare `Number()` of an environment value turns a typo into `NaN`, and `NaN` compares
|
|
5
|
+
* false with everything: a concurrency limit of `NaN` queued every yt-dlp call
|
|
6
|
+
* forever, and a cache TTL of `NaN` never expired anything. Every numeric or
|
|
7
|
+
* enumerated setting therefore comes through here, where an unusable value
|
|
8
|
+
* falls back to the default and says so once on stderr.
|
|
9
|
+
*/
|
|
10
|
+
function warn(name, reason) {
|
|
11
|
+
console.error(`Ignoring ${name}: ${reason}.`);
|
|
12
|
+
}
|
|
13
|
+
export function envString(name, env = process.env) {
|
|
14
|
+
const value = env[name]?.trim();
|
|
15
|
+
return value === undefined || value === '' ? undefined : value;
|
|
16
|
+
}
|
|
17
|
+
export function envInt(name, fallback, bounds = {}, env = process.env) {
|
|
18
|
+
const raw = envString(name, env);
|
|
19
|
+
if (raw === undefined)
|
|
20
|
+
return fallback;
|
|
21
|
+
const parsed = Number(raw);
|
|
22
|
+
if (!Number.isInteger(parsed)) {
|
|
23
|
+
warn(name, `"${raw}" is not a whole number, using ${fallback}`);
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
if (bounds.min !== undefined && parsed < bounds.min) {
|
|
27
|
+
warn(name, `${parsed} is below the minimum of ${bounds.min}, using ${fallback}`);
|
|
28
|
+
return fallback;
|
|
29
|
+
}
|
|
30
|
+
if (bounds.max !== undefined && parsed > bounds.max) {
|
|
31
|
+
warn(name, `${parsed} is above the maximum of ${bounds.max}, using ${fallback}`);
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
const TRUE_WORDS = new Set(['1', 'true', 'yes', 'on']);
|
|
37
|
+
const FALSE_WORDS = new Set(['0', 'false', 'no', 'off']);
|
|
38
|
+
export function envBool(name, fallback, env = process.env) {
|
|
39
|
+
const raw = envString(name, env)?.toLowerCase();
|
|
40
|
+
if (raw === undefined)
|
|
41
|
+
return fallback;
|
|
42
|
+
if (TRUE_WORDS.has(raw))
|
|
43
|
+
return true;
|
|
44
|
+
if (FALSE_WORDS.has(raw))
|
|
45
|
+
return false;
|
|
46
|
+
warn(name, `"${raw}" is not a boolean, using ${String(fallback)}`);
|
|
47
|
+
return fallback;
|
|
48
|
+
}
|
|
49
|
+
export function envList(name, env = process.env) {
|
|
50
|
+
return (env[name] ?? '')
|
|
51
|
+
.split(',')
|
|
52
|
+
.map((value) => value.trim())
|
|
53
|
+
.filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* One of a closed set of values, or `undefined` when unset.
|
|
57
|
+
*
|
|
58
|
+
* Unlike the helpers above this throws on an unknown value: a browser name or
|
|
59
|
+
* proxy scheme that is misspelt is a configuration mistake the operator wants
|
|
60
|
+
* to hear about at boot, not a setting to quietly ignore.
|
|
61
|
+
*/
|
|
62
|
+
export function envEnum(name, values, env = process.env) {
|
|
63
|
+
const raw = envString(name, env);
|
|
64
|
+
if (raw === undefined)
|
|
65
|
+
return undefined;
|
|
66
|
+
const match = values.find((value) => value === raw.toLowerCase());
|
|
67
|
+
if (match === undefined) {
|
|
68
|
+
throw new Error(`${name} must be one of ${values.join(', ')}; got "${raw}".`);
|
|
69
|
+
}
|
|
70
|
+
return match;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/utils/env.ts"],"names":[],"mappings":"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"}
|