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
package/dist/utils/errors.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
|
7
7
|
* than a wall of yt-dlp stderr it has to guess at — and never a leaked command
|
|
8
8
|
* line or stack trace.
|
|
9
9
|
*/
|
|
10
|
-
export type YouTubeErrorCode = 'PRIVATE' | 'AGE_GATED' | 'MEMBERS_ONLY' | 'PREMIUM_ONLY' | 'LOGIN_REQUIRED' | 'NOT_FOUND' | 'NO_CAPTIONS' | 'LIVE_NOT_ENDED' | 'RATE_LIMITED' | 'TIMEOUT' | 'CANCELLED' | 'YTDLP_MISSING' | 'FFMPEG_MISSING' | 'YTDLP_FAILED' | 'MALFORMED_RESPONSE' | 'INVALID_INPUT';
|
|
10
|
+
export type YouTubeErrorCode = 'PRIVATE' | 'AGE_GATED' | 'MEMBERS_ONLY' | 'PREMIUM_ONLY' | 'LOGIN_REQUIRED' | 'BOT_CHECK' | 'NOT_FOUND' | 'NO_CAPTIONS' | 'LIVE_NOT_ENDED' | 'RATE_LIMITED' | 'TIMEOUT' | 'CANCELLED' | 'YTDLP_MISSING' | 'FFMPEG_MISSING' | 'YTDLP_FAILED' | 'FETCH_FAILED' | 'MALFORMED_RESPONSE' | 'INVALID_INPUT';
|
|
11
11
|
export interface YouTubeErrorOptions {
|
|
12
12
|
/** What the caller should try next. Shown to the model verbatim. */
|
|
13
13
|
nextStep?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,WAAW,GACX,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,SAAS,GACT,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,eAAe,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB;IAQtF,iFAAiF;IACjF,aAAa,IAAI,MAAM;CAGxB;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,WAAW,GACX,WAAW,GACX,aAAa,GACb,gBAAgB,GAChB,cAAc,GACd,SAAS,GACT,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,cAAc,GACd,oBAAoB,GACpB,eAAe,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB;IAQtF,iFAAiF;IACjF,aAAa,IAAI,MAAM;CAGxB;AAgGD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,YAAY,CAkBlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,YAAY,GAAG,SAAS,CA2C3B;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAQ3D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAM1D"}
|
package/dist/utils/errors.js
CHANGED
|
@@ -14,7 +14,25 @@ export class YouTubeError extends Error {
|
|
|
14
14
|
return this.nextStep ? `${this.message}\n\n${this.nextStep}` : this.message;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
/** The two settings that let yt-dlp read what a signed-out client cannot. */
|
|
18
|
+
const COOKIE_HINT = 'Set YOUTUBE_MCP_COOKIES_FROM_BROWSER (for example chrome) or YOUTUBE_MCP_COOKIES_FILE and restart the server; see the README section on signed-in content.';
|
|
17
19
|
const RULES = [
|
|
20
|
+
{
|
|
21
|
+
// The one YouTube-authored sentence matched here, and the reason is that
|
|
22
|
+
// it was observed rather than remembered: on 2026-09-05 every per-video
|
|
23
|
+
// read from this project's own address printed it, verbatim, while flat
|
|
24
|
+
// channel listings kept working — so it is about the client, not the
|
|
25
|
+
// video, and the remedy is different. Matched on the words before the
|
|
26
|
+
// apostrophe, which YouTube writes as U+2019. Should YouTube reword it,
|
|
27
|
+
// the login hint yt-dlp appends still lands on LOGIN_REQUIRED below, whose
|
|
28
|
+
// next step names the same cookie settings. Listed first because both
|
|
29
|
+
// strings appear in the same output.
|
|
30
|
+
code: 'BOT_CHECK',
|
|
31
|
+
emits: 'Sign in to confirm you',
|
|
32
|
+
source: 'playabilityStatus.reason, re-raised by yt_dlp/extractor/youtube/_video.py',
|
|
33
|
+
message: 'YouTube is asking this client to prove it is not a bot.',
|
|
34
|
+
nextStep: `Per-video reads from this address need a signed-in session. ${COOKIE_HINT}`,
|
|
35
|
+
},
|
|
18
36
|
{
|
|
19
37
|
code: 'RATE_LIMITED',
|
|
20
38
|
// exceptions.py formats `HTTP Error {status}: {reason}`; the reason for 429
|
|
@@ -55,7 +73,7 @@ const RULES = [
|
|
|
55
73
|
emits: 'for tips on effectively exporting YouTube cookies',
|
|
56
74
|
source: 'yt_dlp/extractor/youtube/_base.py:664',
|
|
57
75
|
message: 'This video requires a signed-in YouTube account.',
|
|
58
|
-
nextStep:
|
|
76
|
+
nextStep: `It may be private, age-restricted or members-only. ${COOKIE_HINT}`,
|
|
59
77
|
},
|
|
60
78
|
];
|
|
61
79
|
/**
|
|
@@ -108,7 +126,7 @@ export function classifyPlayability(fields) {
|
|
|
108
126
|
});
|
|
109
127
|
case 'needs_auth':
|
|
110
128
|
return new YouTubeError('AGE_GATED', 'This video is age-restricted and requires a signed-in account.', {
|
|
111
|
-
nextStep:
|
|
129
|
+
nextStep: `Age-gated videos cannot be read without authentication. ${COOKIE_HINT}`,
|
|
112
130
|
});
|
|
113
131
|
}
|
|
114
132
|
// 'is_live' is deliberately absent: a stream in progress has real metadata,
|
package/dist/utils/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { YouTubeError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Exclusive access to a directory's contents while a long job writes them.
|
|
5
|
+
*
|
|
6
|
+
* Two jobs on one channel would interleave their checkpoints, and the later
|
|
7
|
+
* write would silently drop whatever the other had recorded since it last
|
|
8
|
+
* read. A lock file rather than an in-process mutex because a second server
|
|
9
|
+
* process — a second editor window, a stray `npm start` — is the case that
|
|
10
|
+
* actually happens.
|
|
11
|
+
*/
|
|
12
|
+
/** Long enough that a slow job is never mistaken for a dead one. */
|
|
13
|
+
export declare const LOCK_STALE_MS: number;
|
|
14
|
+
export declare const lockRecordSchema: z.ZodObject<{
|
|
15
|
+
pid: z.ZodNumber;
|
|
16
|
+
startedAt: z.ZodString;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
startedAt: string;
|
|
19
|
+
pid: number;
|
|
20
|
+
}, {
|
|
21
|
+
startedAt: string;
|
|
22
|
+
pid: number;
|
|
23
|
+
}>;
|
|
24
|
+
export type LockRecord = z.infer<typeof lockRecordSchema>;
|
|
25
|
+
/**
|
|
26
|
+
* Run `work` holding the lock at `path`.
|
|
27
|
+
*
|
|
28
|
+
* It is released on any exit, including cancellation. A process killed outright
|
|
29
|
+
* leaves one behind, which is why a lock is also broken when its owner is gone
|
|
30
|
+
* or when it is simply too old to be real. `held` builds the error to throw
|
|
31
|
+
* when someone else genuinely has it, so each caller can name its own tool.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withFileLock<T>(path: string, work: () => Promise<T>, held: (existing: LockRecord | undefined) => YouTubeError): Promise<T>;
|
|
34
|
+
//# sourceMappingURL=file-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.d.ts","sourceRoot":"","sources":["../../src/utils/file-lock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD;;;;;;;;GAQG;AAEH,oEAAoE;AACpE,eAAO,MAAM,aAAa,QAAiB,CAAC;AAE5C,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,IAAI,EAAE,CAAC,QAAQ,EAAE,UAAU,GAAG,SAAS,KAAK,YAAY,GACvD,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { readJsonFile } from './json-file.js';
|
|
4
|
+
/**
|
|
5
|
+
* Exclusive access to a directory's contents while a long job writes them.
|
|
6
|
+
*
|
|
7
|
+
* Two jobs on one channel would interleave their checkpoints, and the later
|
|
8
|
+
* write would silently drop whatever the other had recorded since it last
|
|
9
|
+
* read. A lock file rather than an in-process mutex because a second server
|
|
10
|
+
* process — a second editor window, a stray `npm start` — is the case that
|
|
11
|
+
* actually happens.
|
|
12
|
+
*/
|
|
13
|
+
/** Long enough that a slow job is never mistaken for a dead one. */
|
|
14
|
+
export const LOCK_STALE_MS = 30 * 60 * 1000;
|
|
15
|
+
export const lockRecordSchema = z.object({
|
|
16
|
+
pid: z.number().int(),
|
|
17
|
+
startedAt: z.string(),
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Run `work` holding the lock at `path`.
|
|
21
|
+
*
|
|
22
|
+
* It is released on any exit, including cancellation. A process killed outright
|
|
23
|
+
* leaves one behind, which is why a lock is also broken when its owner is gone
|
|
24
|
+
* or when it is simply too old to be real. `held` builds the error to throw
|
|
25
|
+
* when someone else genuinely has it, so each caller can name its own tool.
|
|
26
|
+
*/
|
|
27
|
+
export async function withFileLock(path, work, held) {
|
|
28
|
+
if (!(await acquire(path))) {
|
|
29
|
+
const existing = await readJsonFile(path, lockRecordSchema);
|
|
30
|
+
// An unreadable lock is one being written this instant, which is as held as
|
|
31
|
+
// it gets. Only a lock whose owner is demonstrably gone gets broken.
|
|
32
|
+
if (existing === undefined || !isStale(existing))
|
|
33
|
+
throw held(existing);
|
|
34
|
+
await rm(path, { force: true });
|
|
35
|
+
// Losing this second race means another caller broke the same stale lock
|
|
36
|
+
// first, and is now the legitimate owner.
|
|
37
|
+
if (!(await acquire(path)))
|
|
38
|
+
throw held(undefined);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return await work();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
await rm(path, { force: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create the lock file, or report that someone else already has.
|
|
49
|
+
*
|
|
50
|
+
* `wx` fails when the file exists, and that check and the creation are one
|
|
51
|
+
* operation in the kernel. Reading first and writing after is not a lock: two
|
|
52
|
+
* jobs starting together both see nothing and both proceed.
|
|
53
|
+
*/
|
|
54
|
+
async function acquire(path) {
|
|
55
|
+
const lock = { pid: process.pid, startedAt: new Date().toISOString() };
|
|
56
|
+
try {
|
|
57
|
+
await writeFile(path, JSON.stringify(lock), { encoding: 'utf-8', flag: 'wx' });
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (errorCode(error) === 'EEXIST')
|
|
62
|
+
return false;
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function isStale({ pid, startedAt }) {
|
|
67
|
+
const started = Date.parse(startedAt);
|
|
68
|
+
if (Number.isNaN(started) || Date.now() - started > LOCK_STALE_MS)
|
|
69
|
+
return true;
|
|
70
|
+
return !isProcessAlive(pid);
|
|
71
|
+
}
|
|
72
|
+
function isProcessAlive(pid) {
|
|
73
|
+
try {
|
|
74
|
+
// Signal 0 performs the permission and existence checks without delivering
|
|
75
|
+
// anything.
|
|
76
|
+
process.kill(pid, 0);
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// EPERM means the process exists but belongs to another user, which for
|
|
81
|
+
// this purpose is very much alive.
|
|
82
|
+
return errorCode(error) === 'EPERM';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** The `code` a Node system error carries, when it is one. */
|
|
86
|
+
function errorCode(error) {
|
|
87
|
+
return typeof error === 'object' && error !== null && 'code' in error
|
|
88
|
+
? String(error.code)
|
|
89
|
+
: undefined;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=file-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.js","sourceRoot":"","sources":["../../src/utils/file-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { VideoListItem } from './youtube-channel.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reading a flat channel or playlist listing.
|
|
5
|
+
*
|
|
6
|
+
* `--flat-playlist` lists a channel in one request instead of one per video,
|
|
7
|
+
* and each entry carries its thumbnail URLs — which is what makes a channel's
|
|
8
|
+
* thumbnails reachable without extracting every video. Printed as one JSON
|
|
9
|
+
* object per line with exactly these fields, so a title containing a delimiter
|
|
10
|
+
* cannot shift the others, and the parser checks each field's type.
|
|
11
|
+
*
|
|
12
|
+
* Verified against yt-dlp 2026.07.04: a flat entry carries `thumbnails` but no
|
|
13
|
+
* `upload_date`, so the date stays empty here and is resolved per video by the
|
|
14
|
+
* callers that need it.
|
|
15
|
+
*/
|
|
16
|
+
export declare const FLAT_PRINT_TEMPLATE = "%(.{id,title,duration,upload_date,timestamp,view_count,live_status,availability,thumbnails})j";
|
|
17
|
+
/** One entry of a thumbnails array; sizes are absent for some channel images. */
|
|
18
|
+
export declare const listedImageSchema: z.ZodObject<{
|
|
19
|
+
id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
+
url: z.ZodString;
|
|
21
|
+
width: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
22
|
+
height: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
url: string;
|
|
25
|
+
id?: string | null | undefined;
|
|
26
|
+
width?: number | null | undefined;
|
|
27
|
+
height?: number | null | undefined;
|
|
28
|
+
}, {
|
|
29
|
+
url: string;
|
|
30
|
+
id?: string | null | undefined;
|
|
31
|
+
width?: number | null | undefined;
|
|
32
|
+
height?: number | null | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
export type ListedImage = z.infer<typeof listedImageSchema>;
|
|
35
|
+
export declare const flatEntrySchema: z.ZodObject<{
|
|
36
|
+
id: z.ZodString;
|
|
37
|
+
title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
38
|
+
duration: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
39
|
+
upload_date: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
|
+
view_count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
41
|
+
live_status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
42
|
+
thumbnails: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
43
|
+
id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
44
|
+
url: z.ZodString;
|
|
45
|
+
width: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
46
|
+
height: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
47
|
+
}, "strip", z.ZodTypeAny, {
|
|
48
|
+
url: string;
|
|
49
|
+
id?: string | null | undefined;
|
|
50
|
+
width?: number | null | undefined;
|
|
51
|
+
height?: number | null | undefined;
|
|
52
|
+
}, {
|
|
53
|
+
url: string;
|
|
54
|
+
id?: string | null | undefined;
|
|
55
|
+
width?: number | null | undefined;
|
|
56
|
+
height?: number | null | undefined;
|
|
57
|
+
}>, "many">>>;
|
|
58
|
+
}, "strip", z.ZodTypeAny, {
|
|
59
|
+
id: string;
|
|
60
|
+
title?: string | null | undefined;
|
|
61
|
+
duration?: number | null | undefined;
|
|
62
|
+
upload_date?: string | null | undefined;
|
|
63
|
+
view_count?: number | null | undefined;
|
|
64
|
+
live_status?: string | null | undefined;
|
|
65
|
+
thumbnails?: {
|
|
66
|
+
url: string;
|
|
67
|
+
id?: string | null | undefined;
|
|
68
|
+
width?: number | null | undefined;
|
|
69
|
+
height?: number | null | undefined;
|
|
70
|
+
}[] | null | undefined;
|
|
71
|
+
}, {
|
|
72
|
+
id: string;
|
|
73
|
+
title?: string | null | undefined;
|
|
74
|
+
duration?: number | null | undefined;
|
|
75
|
+
upload_date?: string | null | undefined;
|
|
76
|
+
view_count?: number | null | undefined;
|
|
77
|
+
live_status?: string | null | undefined;
|
|
78
|
+
thumbnails?: {
|
|
79
|
+
url: string;
|
|
80
|
+
id?: string | null | undefined;
|
|
81
|
+
width?: number | null | undefined;
|
|
82
|
+
height?: number | null | undefined;
|
|
83
|
+
}[] | null | undefined;
|
|
84
|
+
}>;
|
|
85
|
+
export type FlatEntry = z.infer<typeof flatEntrySchema>;
|
|
86
|
+
/** The largest image by area, then by width; `undefined` for an empty list. */
|
|
87
|
+
export declare function largestThumbnail(thumbnails: ListedImage[]): ListedImage | undefined;
|
|
88
|
+
export declare function toVideoListItem(entry: FlatEntry): VideoListItem;
|
|
89
|
+
//# sourceMappingURL=flat-listing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flat-listing.d.ts","sourceRoot":"","sources":["../../src/utils/flat-listing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,mBAAmB,kGACiE,CAAC;AAElG,iFAAiF;AACjF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;EAK5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQ1B,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,WAAW,GAAG,SAAS,CAQnF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,CAqB/D"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { formatYouTubeDate } from './format.js';
|
|
3
|
+
import { formatDuration, watchUrl } from './youtube-url.js';
|
|
4
|
+
/**
|
|
5
|
+
* Reading a flat channel or playlist listing.
|
|
6
|
+
*
|
|
7
|
+
* `--flat-playlist` lists a channel in one request instead of one per video,
|
|
8
|
+
* and each entry carries its thumbnail URLs — which is what makes a channel's
|
|
9
|
+
* thumbnails reachable without extracting every video. Printed as one JSON
|
|
10
|
+
* object per line with exactly these fields, so a title containing a delimiter
|
|
11
|
+
* cannot shift the others, and the parser checks each field's type.
|
|
12
|
+
*
|
|
13
|
+
* Verified against yt-dlp 2026.07.04: a flat entry carries `thumbnails` but no
|
|
14
|
+
* `upload_date`, so the date stays empty here and is resolved per video by the
|
|
15
|
+
* callers that need it.
|
|
16
|
+
*/
|
|
17
|
+
export const FLAT_PRINT_TEMPLATE = '%(.{id,title,duration,upload_date,timestamp,view_count,live_status,availability,thumbnails})j';
|
|
18
|
+
/** One entry of a thumbnails array; sizes are absent for some channel images. */
|
|
19
|
+
export const listedImageSchema = z.object({
|
|
20
|
+
id: z.string().nullish(),
|
|
21
|
+
url: z.string(),
|
|
22
|
+
width: z.number().nullish(),
|
|
23
|
+
height: z.number().nullish(),
|
|
24
|
+
});
|
|
25
|
+
export const flatEntrySchema = z.object({
|
|
26
|
+
id: z.string(),
|
|
27
|
+
title: z.string().nullish(),
|
|
28
|
+
duration: z.number().nullish(),
|
|
29
|
+
upload_date: z.string().nullish(),
|
|
30
|
+
view_count: z.number().nullish(),
|
|
31
|
+
live_status: z.string().nullish(),
|
|
32
|
+
thumbnails: z.array(listedImageSchema).nullish(),
|
|
33
|
+
});
|
|
34
|
+
/** The largest image by area, then by width; `undefined` for an empty list. */
|
|
35
|
+
export function largestThumbnail(thumbnails) {
|
|
36
|
+
const area = (image) => (image.width ?? 0) * (image.height ?? 0);
|
|
37
|
+
return thumbnails.reduce((best, image) => {
|
|
38
|
+
if (best === undefined)
|
|
39
|
+
return image;
|
|
40
|
+
if (area(image) > area(best))
|
|
41
|
+
return image;
|
|
42
|
+
if (area(image) === area(best) && (image.width ?? 0) > (best.width ?? 0))
|
|
43
|
+
return image;
|
|
44
|
+
return best;
|
|
45
|
+
}, undefined);
|
|
46
|
+
}
|
|
47
|
+
export function toVideoListItem(entry) {
|
|
48
|
+
const duration = entry.duration ?? 0;
|
|
49
|
+
const thumbnails = entry.thumbnails ?? [];
|
|
50
|
+
const largest = largestThumbnail(thumbnails);
|
|
51
|
+
return {
|
|
52
|
+
id: entry.id,
|
|
53
|
+
title: entry.title ?? 'Unknown title',
|
|
54
|
+
duration,
|
|
55
|
+
durationFormatted: formatDuration(duration),
|
|
56
|
+
uploadDate: formatYouTubeDate(entry.upload_date ?? ''),
|
|
57
|
+
url: watchUrl(entry.id),
|
|
58
|
+
...(largest === undefined ? {} : { thumbnailUrl: largest.url }),
|
|
59
|
+
...(thumbnails.length === 0 ? {} : { thumbnails }),
|
|
60
|
+
...(entry.view_count === null || entry.view_count === undefined
|
|
61
|
+
? {}
|
|
62
|
+
: { viewCount: entry.view_count }),
|
|
63
|
+
...(entry.live_status === null || entry.live_status === undefined
|
|
64
|
+
? {}
|
|
65
|
+
: { liveStatus: entry.live_status }),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=flat-listing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flat-listing.js","sourceRoot":"","sources":["../../src/utils/flat-listing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5D;;;;;;;;;;;;GAYG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,+FAA+F,CAAC;AAElG,iFAAiF;AACjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IACxB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;CAC7B,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC9B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAChC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE;CACjD,CAAC,CAAC;AAIH,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,UAAyB;IACxD,MAAM,IAAI,GAAG,CAAC,KAAkB,EAAU,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IACtF,OAAO,UAAU,CAAC,MAAM,CAA0B,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAChE,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACrC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QACvF,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,SAAS,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAgB;IAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;IAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAE7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,eAAe;QACrC,QAAQ;QACR,iBAAiB,EAAE,cAAc,CAAC,QAAQ,CAAC;QAC3C,UAAU,EAAE,iBAAiB,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC;QACtD,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;QAC/D,GAAG,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;QAClD,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;YAC7D,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC;QACpC,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;YAC/D,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;KACvC,CAAC;AACJ,CAAC"}
|
package/dist/utils/format.d.ts
CHANGED
|
@@ -2,13 +2,11 @@ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
|
2
2
|
export declare function formatCount(count: number): string;
|
|
3
3
|
export declare function formatYouTubeDate(yyyymmdd: string): string;
|
|
4
4
|
export declare function formatFilesize(bytes?: number): string;
|
|
5
|
-
export declare function textContent(text: string): CallToolResult;
|
|
6
5
|
/**
|
|
7
6
|
* A tool result carrying both a human-readable rendering and machine-readable
|
|
8
7
|
* data.
|
|
9
8
|
*
|
|
10
|
-
* The text block is
|
|
11
|
-
* nothing a client already displays changes; `structuredContent` is additive and
|
|
9
|
+
* The text block is what a client displays; `structuredContent` is additive and
|
|
12
10
|
* is what the tool's `outputSchema` describes. Every tool that declares an
|
|
13
11
|
* output schema must return this, because the SDK validates the two against
|
|
14
12
|
* each other.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AAOD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AAOD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,CAK5F;AAED,wEAAwE;AACxE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,QAAQ,CAS3E;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAOzE;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,cAAc,CAQhB"}
|
package/dist/utils/format.js
CHANGED
|
@@ -25,15 +25,11 @@ export function formatFilesize(bytes) {
|
|
|
25
25
|
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
26
26
|
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
27
27
|
}
|
|
28
|
-
export function textContent(text) {
|
|
29
|
-
return { content: [{ type: 'text', text }] };
|
|
30
|
-
}
|
|
31
28
|
/**
|
|
32
29
|
* A tool result carrying both a human-readable rendering and machine-readable
|
|
33
30
|
* data.
|
|
34
31
|
*
|
|
35
|
-
* The text block is
|
|
36
|
-
* nothing a client already displays changes; `structuredContent` is additive and
|
|
32
|
+
* The text block is what a client displays; `structuredContent` is additive and
|
|
37
33
|
* is what the tool's `outputSchema` describes. Every tool that declares an
|
|
38
34
|
* output schema must return this, because the SDK validates the two against
|
|
39
35
|
* each other.
|
package/dist/utils/format.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,IAAI,aAAa;QAAE,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC;IACjF,IAAI,KAAK,IAAI,SAAS;QAAE,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC;IACzE,IAAI,KAAK,IAAI,KAAK;QAAE,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC;IACjE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS;IACjC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChD,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAChF,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,IAAI,aAAa;QAAE,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC;IACjF,IAAI,KAAK,IAAI,SAAS;QAAE,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC;IACzE,IAAI,KAAK,IAAI,KAAK;QAAE,OAAO,GAAG,gBAAgB,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC;IACjE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS;IACjC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChD,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAChF,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,UAAmC;IAC1E,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;QAC1C,iBAAiB,EAAE,UAAU;KAC9B,CAAC;AACJ,CAAC;AAWD,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,KAAa,EAAE,MAAM,GAAG,CAAC;IAC/D,MAAM,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IACvC,OAAO;QACL,KAAK;QACL,KAAK;QACL,MAAM;QACN,OAAO;QACP,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnD,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,IAAY,EACZ,QAAiB;IAEjB,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,GAAG,EAAE,UAAU,QAAQ,EAAE;QACzB,IAAI;QACJ,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,UAAU,CACxB,IAAY,EACZ,UAAmC,EACnC,IAAuD;IAEvD,OAAO;QACL,OAAO,EAAE;YACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE;YAC/B,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC;SACtD;QACD,iBAAiB,EAAE,UAAU;KAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
/** Any tool handler: whatever it takes, it answers with a tool result. */
|
|
3
|
+
type ToolLike = (...args: never[]) => CallToolResult | Promise<CallToolResult>;
|
|
4
|
+
/**
|
|
5
|
+
* Wrap a tool handler, keeping its exact type.
|
|
6
|
+
*
|
|
7
|
+
* A Proxy rather than an arrow function because the SDK's `registerTool` is
|
|
8
|
+
* generic over the input schema and demands a callback of the precise type it
|
|
9
|
+
* derives from it; a new function would need a cast to claim that type, while
|
|
10
|
+
* a Proxy over the original *is* that type.
|
|
11
|
+
*/
|
|
12
|
+
export declare function guarded<F extends ToolLike>(handler: F): F;
|
|
13
|
+
/**
|
|
14
|
+
* The resource counterpart. A read that fails used to propagate whatever was
|
|
15
|
+
* thrown — an `ENOENT` carrying an absolute local path, for instance — as the
|
|
16
|
+
* JSON-RPC error message. It now carries the same `[CODE] message` a tool
|
|
17
|
+
* would show, and nothing else.
|
|
18
|
+
*/
|
|
19
|
+
export declare function guardedResource<A extends unknown[], R>(handler: (...args: A) => Promise<R>): (...args: A) => Promise<R>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/utils/guard.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAoEzE,0EAA0E;AAC1E,KAAK,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAE/E;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAazD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,CAAC,EACpD,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAClC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAc5B"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { runWithRequestContext } from './context.js';
|
|
4
|
+
import { asYouTubeError, toToolError } from './errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Wrapping every handler the server registers, once, so that each call gets a
|
|
7
|
+
* request context and no call can throw out of the server.
|
|
8
|
+
*
|
|
9
|
+
* The MCP request's AbortSignal is published to the request context so an
|
|
10
|
+
* in-flight yt-dlp is killed when the client cancels, and anything thrown is
|
|
11
|
+
* rendered as an actionable message rather than a raw stack trace, a yt-dlp
|
|
12
|
+
* command line, or a local path. Tools report failures inside the result with
|
|
13
|
+
* `isError`; resources have no such envelope, so theirs become protocol errors
|
|
14
|
+
* carrying the same normalised text.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* The parts of the SDK's `RequestHandlerExtra` this server uses.
|
|
18
|
+
*
|
|
19
|
+
* `sendNotification` is described with `z.custom` because a function is not
|
|
20
|
+
* something Zod can take apart structurally — the predicate is a real runtime
|
|
21
|
+
* check, and it is what lets the property be called without asserting a type
|
|
22
|
+
* over it.
|
|
23
|
+
*/
|
|
24
|
+
const requestExtraSchema = z.object({
|
|
25
|
+
signal: z.instanceof(AbortSignal).optional(),
|
|
26
|
+
sendNotification: z
|
|
27
|
+
.custom((value) => typeof value === 'function')
|
|
28
|
+
.optional(),
|
|
29
|
+
_meta: z.object({ progressToken: z.union([z.string(), z.number()]).optional() }).optional(),
|
|
30
|
+
});
|
|
31
|
+
/** The request context for a call, read from the SDK extra that arrives last. */
|
|
32
|
+
function contextOf(args) {
|
|
33
|
+
// Handlers declare only their own parameters; the SDK appends
|
|
34
|
+
// RequestHandlerExtra to every call, so it is whatever arrived last.
|
|
35
|
+
const parsed = requestExtraSchema.safeParse(args[args.length - 1]);
|
|
36
|
+
const extra = parsed.success ? parsed.data : undefined;
|
|
37
|
+
return {
|
|
38
|
+
signal: extra?.signal,
|
|
39
|
+
// Progress is only meaningful when the client asked for it by sending a
|
|
40
|
+
// token; without one the notification would be dropped anyway.
|
|
41
|
+
reportProgress: extra?.sendNotification && extra._meta?.progressToken !== undefined
|
|
42
|
+
? (progress, total, message) => {
|
|
43
|
+
void extra.sendNotification?.({
|
|
44
|
+
method: 'notifications/progress',
|
|
45
|
+
params: {
|
|
46
|
+
progressToken: extra._meta?.progressToken,
|
|
47
|
+
progress,
|
|
48
|
+
...(total === undefined ? {} : { total }),
|
|
49
|
+
...(message === undefined ? {} : { message }),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
: undefined,
|
|
54
|
+
log: extra?.sendNotification
|
|
55
|
+
? (level, message) => {
|
|
56
|
+
void extra.sendNotification?.({
|
|
57
|
+
method: 'notifications/message',
|
|
58
|
+
params: { level, logger: 'youtube-knowledge-mcp', data: message },
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
: undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Wrap a tool handler, keeping its exact type.
|
|
66
|
+
*
|
|
67
|
+
* A Proxy rather than an arrow function because the SDK's `registerTool` is
|
|
68
|
+
* generic over the input schema and demands a callback of the precise type it
|
|
69
|
+
* derives from it; a new function would need a cast to claim that type, while
|
|
70
|
+
* a Proxy over the original *is* that type.
|
|
71
|
+
*/
|
|
72
|
+
export function guarded(handler) {
|
|
73
|
+
const run = (args) => runWithRequestContext(contextOf(args), async () => {
|
|
74
|
+
try {
|
|
75
|
+
return await handler(...args);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return toToolError(error);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return new Proxy(handler, {
|
|
82
|
+
apply: (_target, _thisArg, args) => run(args),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The resource counterpart. A read that fails used to propagate whatever was
|
|
87
|
+
* thrown — an `ENOENT` carrying an absolute local path, for instance — as the
|
|
88
|
+
* JSON-RPC error message. It now carries the same `[CODE] message` a tool
|
|
89
|
+
* would show, and nothing else.
|
|
90
|
+
*/
|
|
91
|
+
export function guardedResource(handler) {
|
|
92
|
+
return async (...args) => runWithRequestContext(contextOf(args), async () => {
|
|
93
|
+
try {
|
|
94
|
+
return await handler(...args);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
const failure = asYouTubeError(error);
|
|
98
|
+
const code = failure.code === 'INVALID_INPUT' || failure.code === 'NOT_FOUND'
|
|
99
|
+
? ErrorCode.InvalidParams
|
|
100
|
+
: ErrorCode.InternalError;
|
|
101
|
+
throw new McpError(code, `[${failure.code}] ${failure.toToolMessage()}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/utils/guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading an image's format and size from its first bytes.
|
|
3
|
+
*
|
|
4
|
+
* The manifest a thumbnail job writes records what was actually saved — a
|
|
5
|
+
* JPEG of 1280 by 720, say — and it must not take that from the URL's name or
|
|
6
|
+
* the server's Content-Type, both of which describe what was asked for rather
|
|
7
|
+
* than what arrived. Three container formats cover what YouTube's image hosts
|
|
8
|
+
* serve; anything else is reported as unknown rather than guessed.
|
|
9
|
+
*/
|
|
10
|
+
export type ImageFormat = 'jpg' | 'png' | 'webp';
|
|
11
|
+
export interface ImageProbe {
|
|
12
|
+
format: ImageFormat;
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
mimeType: string;
|
|
16
|
+
}
|
|
17
|
+
/** The format and pixel size of an image, or `undefined` when the bytes are not one this reads. */
|
|
18
|
+
export declare function probeImage(bytes: Uint8Array): ImageProbe | undefined;
|
|
19
|
+
//# sourceMappingURL=image-dimensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-dimensions.d.ts","sourceRoot":"","sources":["../../src/utils/image-dimensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4FD,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAKpE"}
|