youtube-knowledge-mcp 2.1.0 → 3.0.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 +153 -38
- package/dist/brain-schemas.d.ts +10 -10
- package/dist/brain-schemas.d.ts.map +1 -1
- package/dist/brain-schemas.js +0 -4
- package/dist/brain-schemas.js.map +1 -1
- package/dist/harvest-schemas.d.ts +75 -0
- package/dist/harvest-schemas.d.ts.map +1 -0
- package/dist/harvest-schemas.js +106 -0
- package/dist/harvest-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 -517
- 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 -100
- 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/harvest-tools.d.ts +10 -0
- package/dist/registry/harvest-tools.d.ts.map +1 -0
- package/dist/registry/harvest-tools.js +109 -0
- package/dist/registry/harvest-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 +39 -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 +29 -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 +13 -10
- package/dist/resources.js.map +1 -1
- package/dist/schemas.d.ts +250 -2
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +61 -0
- 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.js +1 -1
- package/dist/tools/ask-brain.js.map +1 -1
- package/dist/tools/batch.js +1 -1
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/brain-info.js +1 -1
- package/dist/tools/brain-info.js.map +1 -1
- package/dist/tools/build-brain.js +1 -1
- package/dist/tools/build-brain.js.map +1 -1
- package/dist/tools/check-health.d.ts +61 -0
- package/dist/tools/check-health.d.ts.map +1 -1
- package/dist/tools/check-health.js +94 -6
- package/dist/tools/check-health.js.map +1 -1
- package/dist/tools/clips.d.ts +9 -41
- 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 +18 -4
- package/dist/tools/fetch-videos.d.ts.map +1 -1
- package/dist/tools/fetch-videos.js +64 -20
- 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-comments.d.ts +238 -6
- package/dist/tools/get-comments.d.ts.map +1 -1
- package/dist/tools/get-comments.js +85 -21
- package/dist/tools/get-comments.js.map +1 -1
- package/dist/tools/get-coverage.d.ts +122 -0
- package/dist/tools/get-coverage.d.ts.map +1 -0
- package/dist/tools/get-coverage.js +105 -0
- package/dist/tools/get-coverage.js.map +1 -0
- 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.map +1 -1
- package/dist/tools/get-transcript.js +2 -14
- package/dist/tools/get-transcript.js.map +1 -1
- package/dist/tools/harvest-channel.d.ts +92 -0
- package/dist/tools/harvest-channel.d.ts.map +1 -0
- package/dist/tools/harvest-channel.js +62 -0
- package/dist/tools/harvest-channel.js.map +1 -0
- package/dist/tools/harvest-comments.d.ts +81 -0
- package/dist/tools/harvest-comments.d.ts.map +1 -0
- package/dist/tools/harvest-comments.js +115 -0
- package/dist/tools/harvest-comments.js.map +1 -0
- package/dist/tools/library.d.ts.map +1 -1
- package/dist/tools/library.js +14 -4
- 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.js +1 -1
- package/dist/tools/list-library.js.map +1 -1
- package/dist/tools/prune-harvest.d.ts +59 -0
- package/dist/tools/prune-harvest.d.ts.map +1 -0
- package/dist/tools/prune-harvest.js +108 -0
- package/dist/tools/prune-harvest.js.map +1 -0
- package/dist/tools/query-comments.d.ts +125 -0
- package/dist/tools/query-comments.d.ts.map +1 -0
- package/dist/tools/query-comments.js +106 -0
- package/dist/tools/query-comments.js.map +1 -0
- package/dist/tools/query-videos.d.ts +118 -0
- package/dist/tools/query-videos.d.ts.map +1 -0
- package/dist/tools/query-videos.js +97 -0
- package/dist/tools/query-videos.js.map +1 -0
- package/dist/tools/repair-store.d.ts +34 -0
- package/dist/tools/repair-store.d.ts.map +1 -0
- package/dist/tools/repair-store.js +58 -0
- package/dist/tools/repair-store.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 +6 -0
- package/dist/tools/search-channels.d.ts.map +1 -1
- package/dist/tools/search-channels.js +5 -1
- package/dist/tools/search-channels.js.map +1 -1
- 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 +3 -0
- package/dist/tools/search-videos.d.ts.map +1 -1
- package/dist/tools/search-videos.js +1 -1
- package/dist/tools/search-videos.js.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.map +1 -1
- package/dist/utils/brain-build.js +1 -12
- package/dist/utils/brain-build.js.map +1 -1
- package/dist/utils/brain-index.d.ts.map +1 -1
- package/dist/utils/brain-index.js +3 -2
- package/dist/utils/brain-index.js.map +1 -1
- package/dist/utils/brain-lock.d.ts +2 -18
- package/dist/utils/brain-lock.d.ts.map +1 -1
- package/dist/utils/brain-lock.js +4 -80
- package/dist/utils/brain-lock.js.map +1 -1
- package/dist/utils/brain-lookup.d.ts +8 -0
- package/dist/utils/brain-lookup.d.ts.map +1 -1
- package/dist/utils/brain-lookup.js +5 -31
- package/dist/utils/brain-lookup.js.map +1 -1
- package/dist/utils/brain-storage.d.ts.map +1 -1
- package/dist/utils/brain-storage.js +5 -5
- package/dist/utils/brain-storage.js.map +1 -1
- 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 +18 -26
- package/dist/utils/clips.js.map +1 -1
- package/dist/utils/comment-store.d.ts +71 -0
- package/dist/utils/comment-store.d.ts.map +1 -0
- package/dist/utils/comment-store.js +129 -0
- package/dist/utils/comment-store.js.map +1 -0
- package/dist/utils/comment-threads.d.ts +51 -0
- package/dist/utils/comment-threads.d.ts.map +1 -0
- package/dist/utils/comment-threads.js +76 -0
- package/dist/utils/comment-threads.js.map +1 -0
- package/dist/utils/coverage-text.d.ts +3 -0
- package/dist/utils/coverage-text.d.ts.map +1 -0
- package/dist/utils/coverage-text.js +62 -0
- package/dist/utils/coverage-text.js.map +1 -0
- package/dist/utils/coverage.d.ts +57 -0
- package/dist/utils/coverage.d.ts.map +1 -0
- package/dist/utils/coverage.js +142 -0
- package/dist/utils/coverage.js.map +1 -0
- 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 +28 -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 +18 -4
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +2 -6
- 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/harvest-catalog.d.ts +44 -0
- package/dist/utils/harvest-catalog.d.ts.map +1 -0
- package/dist/utils/harvest-catalog.js +164 -0
- package/dist/utils/harvest-catalog.js.map +1 -0
- package/dist/utils/harvest-lock.d.ts +3 -0
- package/dist/utils/harvest-lock.d.ts.map +1 -0
- package/dist/utils/harvest-lock.js +26 -0
- package/dist/utils/harvest-lock.js.map +1 -0
- package/dist/utils/harvest-receipts.d.ts +14 -0
- package/dist/utils/harvest-receipts.d.ts.map +1 -0
- package/dist/utils/harvest-receipts.js +110 -0
- package/dist/utils/harvest-receipts.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 +14 -5
- package/dist/utils/json-file.d.ts.map +1 -1
- package/dist/utils/json-file.js +24 -9
- package/dist/utils/json-file.js.map +1 -1
- package/dist/utils/listing-cursor.d.ts +31 -0
- package/dist/utils/listing-cursor.d.ts.map +1 -0
- package/dist/utils/listing-cursor.js +39 -0
- package/dist/utils/listing-cursor.js.map +1 -0
- package/dist/utils/paths.d.ts +10 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -0
- package/dist/utils/paths.js.map +1 -1
- 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/pot-preflight.d.ts +53 -0
- package/dist/utils/pot-preflight.d.ts.map +1 -0
- package/dist/utils/pot-preflight.js +146 -0
- package/dist/utils/pot-preflight.js.map +1 -0
- package/dist/utils/search-index.d.ts.map +1 -1
- package/dist/utils/search-index.js +9 -4
- package/dist/utils/search-index.js.map +1 -1
- package/dist/utils/sleep.d.ts +9 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +25 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/storage.d.ts.map +1 -1
- package/dist/utils/storage.js +14 -8
- package/dist/utils/storage.js.map +1 -1
- package/dist/utils/store-health.d.ts +37 -0
- package/dist/utils/store-health.d.ts.map +1 -0
- package/dist/utils/store-health.js +92 -0
- package/dist/utils/store-health.js.map +1 -0
- package/dist/utils/store-migrations.d.ts +33 -0
- package/dist/utils/store-migrations.d.ts.map +1 -0
- package/dist/utils/store-migrations.js +41 -0
- package/dist/utils/store-migrations.js.map +1 -0
- package/dist/utils/store-paths.d.ts +33 -0
- package/dist/utils/store-paths.d.ts.map +1 -0
- package/dist/utils/store-paths.js +48 -0
- package/dist/utils/store-paths.js.map +1 -0
- package/dist/utils/store-rows.d.ts +22 -0
- package/dist/utils/store-rows.d.ts.map +1 -0
- package/dist/utils/store-rows.js +62 -0
- package/dist/utils/store-rows.js.map +1 -0
- package/dist/utils/store-schema.d.ts +16 -0
- package/dist/utils/store-schema.d.ts.map +1 -0
- package/dist/utils/store-schema.js +168 -0
- package/dist/utils/store-schema.js.map +1 -0
- package/dist/utils/store.d.ts +34 -0
- package/dist/utils/store.d.ts.map +1 -0
- package/dist/utils/store.js +157 -0
- package/dist/utils/store.js.map +1 -0
- 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 +10 -31
- package/dist/utils/transcript.d.ts.map +1 -1
- package/dist/utils/transcript.js +2 -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 -4
- package/dist/utils/validate.d.ts.map +1 -1
- package/dist/utils/validate.js +43 -36
- 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/video-stats-cache.d.ts +16 -0
- package/dist/utils/video-stats-cache.d.ts.map +1 -0
- package/dist/utils/video-stats-cache.js +81 -0
- package/dist/utils/video-stats-cache.js.map +1 -0
- package/dist/utils/video-stats.d.ts +186 -0
- package/dist/utils/video-stats.d.ts.map +1 -0
- package/dist/utils/video-stats.js +168 -0
- package/dist/utils/video-stats.js.map +1 -0
- package/dist/utils/video-store.d.ts +69 -0
- package/dist/utils/video-store.d.ts.map +1 -0
- package/dist/utils/video-store.js +77 -0
- package/dist/utils/video-store.js.map +1 -0
- package/dist/utils/youtube-channel.d.ts +51 -0
- package/dist/utils/youtube-channel.d.ts.map +1 -0
- package/dist/utils/youtube-channel.js +91 -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 +492 -0
- package/dist/utils/youtube-schemas.d.ts.map +1 -0
- package/dist/utils/youtube-schemas.js +148 -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 +68 -0
- package/dist/utils/youtube-video.d.ts.map +1 -0
- package/dist/utils/youtube-video.js +110 -0
- package/dist/utils/youtube-video.js.map +1 -0
- package/dist/utils/youtube.d.ts +10 -122
- package/dist/utils/youtube.d.ts.map +1 -1
- package/dist/utils/youtube.js +11 -486
- 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 +27 -0
- package/dist/utils/ytdlp-limiter.d.ts.map +1 -0
- package/dist/utils/ytdlp-limiter.js +85 -0
- package/dist/utils/ytdlp-limiter.js.map +1 -0
- package/dist/utils/ytdlp-pacer.d.ts +64 -0
- package/dist/utils/ytdlp-pacer.d.ts.map +1 -0
- package/dist/utils/ytdlp-pacer.js +165 -0
- package/dist/utils/ytdlp-pacer.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-stream.d.ts +32 -0
- package/dist/utils/ytdlp-stream.d.ts.map +1 -0
- package/dist/utils/ytdlp-stream.js +61 -0
- package/dist/utils/ytdlp-stream.js.map +1 -0
- package/dist/utils/ytdlp.d.ts +23 -18
- package/dist/utils/ytdlp.d.ts.map +1 -1
- package/dist/utils/ytdlp.js +56 -134
- package/dist/utils/ytdlp.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import { createInterface } from 'node:readline';
|
|
3
|
+
import { currentContext } from './context.js';
|
|
4
|
+
import { acquireSlot, releaseSlot } from './ytdlp-limiter.js';
|
|
5
|
+
import { readYtDlpEnv } from './ytdlp-env.js';
|
|
6
|
+
import { YouTubeError } from './errors.js';
|
|
7
|
+
import { SOCKET_TIMEOUT_S } from './ytdlp.js';
|
|
8
|
+
/**
|
|
9
|
+
* Streams stdout line by line.
|
|
10
|
+
*
|
|
11
|
+
* A failure part-way through is not thrown away: the caller keeps every line
|
|
12
|
+
* delivered so far and is told the walk did not complete, which is the whole
|
|
13
|
+
* point of streaming rather than buffering.
|
|
14
|
+
*/
|
|
15
|
+
export async function runYtDlpLines(args, options) {
|
|
16
|
+
const { timeoutMs = 0, target, onLine } = options;
|
|
17
|
+
const { signal } = currentContext();
|
|
18
|
+
if (signal?.aborted === true) {
|
|
19
|
+
throw new YouTubeError('CANCELLED', 'The request was cancelled.');
|
|
20
|
+
}
|
|
21
|
+
await acquireSlot(signal);
|
|
22
|
+
let lines = 0;
|
|
23
|
+
try {
|
|
24
|
+
const argv = [
|
|
25
|
+
'--socket-timeout',
|
|
26
|
+
SOCKET_TIMEOUT_S,
|
|
27
|
+
...readYtDlpEnv().args,
|
|
28
|
+
...args,
|
|
29
|
+
'--',
|
|
30
|
+
target,
|
|
31
|
+
];
|
|
32
|
+
const child = execa('yt-dlp', argv, {
|
|
33
|
+
timeout: timeoutMs > 0 ? timeoutMs : undefined,
|
|
34
|
+
cancelSignal: signal,
|
|
35
|
+
buffer: false,
|
|
36
|
+
stdout: 'pipe',
|
|
37
|
+
});
|
|
38
|
+
// `stdout: 'pipe'` with `buffer: false` guarantees a stream here, so there
|
|
39
|
+
// is nothing to guard against.
|
|
40
|
+
const reader = createInterface({ input: child.stdout, crlfDelay: Infinity });
|
|
41
|
+
for await (const line of reader) {
|
|
42
|
+
if (line.trim() === '')
|
|
43
|
+
continue;
|
|
44
|
+
onLine(line);
|
|
45
|
+
lines += 1;
|
|
46
|
+
}
|
|
47
|
+
await child;
|
|
48
|
+
return { lines, completed: true };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// Everything delivered so far is already the caller's. Reporting how far
|
|
52
|
+
// it got matters more than the reason, which the caller can classify.
|
|
53
|
+
if (error instanceof YouTubeError)
|
|
54
|
+
throw error;
|
|
55
|
+
return { lines, completed: false };
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
releaseSlot();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=ytdlp-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ytdlp-stream.js","sourceRoot":"","sources":["../../src/utils/ytdlp-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA4B9C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc,EAAE,OAAsB;IACxE,MAAM,EAAE,SAAS,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAClD,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAEpC,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,IAAI,CAAC;QACH,MAAM,IAAI,GAAG;YACX,kBAAkB;YAClB,gBAAgB;YAChB,GAAG,YAAY,EAAE,CAAC,IAAI;YACtB,GAAG,IAAI;YACP,IAAI;YACJ,MAAM;SACP,CAAC;QAEF,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE;YAClC,OAAO,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAC9C,YAAY,EAAE,MAAM;YACpB,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,2EAA2E;QAC3E,+BAA+B;QAC/B,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7E,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAChC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,SAAS;YACjC,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;QAED,MAAM,KAAK,CAAC;QACZ,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,sEAAsE;QACtE,IAAI,KAAK,YAAY,YAAY;YAAE,MAAM,KAAK,CAAC;QAC/C,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACrC,CAAC;YAAS,CAAC;QACT,WAAW,EAAE,CAAC;IAChB,CAAC;AACH,CAAC"}
|
package/dist/utils/ytdlp.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { concurrencyState } from './ytdlp-limiter.js';
|
|
2
|
+
export { parseYtDlpJson, parseYtDlpJsonLines } from './ytdlp-parse.js';
|
|
1
3
|
/**
|
|
2
4
|
* The single place this server spawns yt-dlp.
|
|
3
5
|
*
|
|
@@ -17,12 +19,16 @@ export declare const TIMEOUTS: {
|
|
|
17
19
|
/** Media transfers: unbounded here; cancellation is the client's lever. */
|
|
18
20
|
readonly download: 0;
|
|
19
21
|
};
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Seconds of socket inactivity before yt-dlp gives up on a connection.
|
|
24
|
+
*
|
|
25
|
+
* Media transfers deliberately run without a wall-clock timeout — a long clip
|
|
26
|
+
* is allowed to take as long as it honestly takes — which left a dead
|
|
27
|
+
* connection indistinguishable from a slow one, holding its concurrency slot
|
|
28
|
+
* forever. This bounds the silence, not the work: a transfer still making
|
|
29
|
+
* progress is never interrupted.
|
|
30
|
+
*/
|
|
31
|
+
export declare const SOCKET_TIMEOUT_S = "30";
|
|
26
32
|
export interface RunOptions {
|
|
27
33
|
/** Milliseconds before the child is killed. 0 disables the timeout. */
|
|
28
34
|
timeoutMs?: number;
|
|
@@ -30,22 +36,21 @@ export interface RunOptions {
|
|
|
30
36
|
retry?: boolean;
|
|
31
37
|
/** Human-readable operation name, used in log lines. */
|
|
32
38
|
label?: string;
|
|
39
|
+
/**
|
|
40
|
+
* The URL, search expression or id yt-dlp operates on.
|
|
41
|
+
*
|
|
42
|
+
* Always the last argument and always preceded by a literal `--`, so a value
|
|
43
|
+
* that begins with a dash is a target yt-dlp fails to fetch, never an option
|
|
44
|
+
* it obeys. Required rather than defaulted: a call site cannot forget it.
|
|
45
|
+
*/
|
|
46
|
+
target: string;
|
|
33
47
|
}
|
|
34
48
|
/**
|
|
35
49
|
* Run yt-dlp and return its stdout.
|
|
36
50
|
*
|
|
37
51
|
* Arguments are always passed as an array — never a shell string — so video
|
|
38
|
-
* titles and user-supplied queries cannot become shell metacharacters.
|
|
39
|
-
|
|
40
|
-
export declare function runYtDlp(args: string[], options?: RunOptions): Promise<string>;
|
|
41
|
-
/**
|
|
42
|
-
* Parse yt-dlp JSON output behind a type guard.
|
|
43
|
-
*
|
|
44
|
-
* Every JSON.parse in this codebase used to be unguarded, so a truncated or
|
|
45
|
-
* non-JSON response surfaced as a raw SyntaxError.
|
|
52
|
+
* titles and user-supplied queries cannot become shell metacharacters. The
|
|
53
|
+
* target follows a `--` terminator, so it cannot become a yt-dlp option either.
|
|
46
54
|
*/
|
|
47
|
-
export declare function
|
|
48
|
-
/** Parse newline-delimited JSON, skipping unparseable lines rather than failing the call. */
|
|
49
|
-
export declare function parseYtDlpJsonLines<T>(stdout: string, guard: (value: unknown) => value is T): T[];
|
|
50
|
-
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
55
|
+
export declare function runYtDlp(args: string[], options: RunOptions): Promise<string>;
|
|
51
56
|
//# sourceMappingURL=ytdlp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ytdlp.d.ts","sourceRoot":"","sources":["../../src/utils/ytdlp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ytdlp.d.ts","sourceRoot":"","sources":["../../src/utils/ytdlp.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvE;;;;;;;GAOG;AAEH,kFAAkF;AAClF,eAAO,MAAM,QAAQ;IACnB,wDAAwD;;IAExD,gDAAgD;;IAEhD,iEAAiE;;IAEjE,2EAA2E;;CAEnE,CAAC;AAMX;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8DnF"}
|
package/dist/utils/ytdlp.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { execa, ExecaError } from 'execa';
|
|
2
2
|
import { currentContext, log } from './context.js';
|
|
3
|
+
import { sleep } from './sleep.js';
|
|
4
|
+
import { circuitOpen, onFailure, onSuccess, waitMs } from './ytdlp-pacer.js';
|
|
3
5
|
import { YouTubeError, classifyYtDlpFailure } from './errors.js';
|
|
6
|
+
import { acquireSlot, releaseSlot } from './ytdlp-limiter.js';
|
|
7
|
+
import { readYtDlpEnv } from './ytdlp-env.js';
|
|
8
|
+
export { concurrencyState } from './ytdlp-limiter.js';
|
|
9
|
+
export { parseYtDlpJson, parseYtDlpJsonLines } from './ytdlp-parse.js';
|
|
4
10
|
/**
|
|
5
11
|
* The single place this server spawns yt-dlp.
|
|
6
12
|
*
|
|
@@ -20,9 +26,7 @@ export const TIMEOUTS = {
|
|
|
20
26
|
/** Media transfers: unbounded here; cancellation is the client's lever. */
|
|
21
27
|
download: 0,
|
|
22
28
|
};
|
|
23
|
-
const MAX_CONCURRENT = Number(process.env.YOUTUBE_MCP_MAX_CONCURRENCY ?? '3');
|
|
24
29
|
const MAX_ATTEMPTS = 3;
|
|
25
|
-
const BASE_BACKOFF_MS = 750;
|
|
26
30
|
/** Guards against a pathological video description blowing up memory. */
|
|
27
31
|
const MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
28
32
|
/**
|
|
@@ -34,91 +38,16 @@ const MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
|
34
38
|
* forever. This bounds the silence, not the work: a transfer still making
|
|
35
39
|
* progress is never interrupted.
|
|
36
40
|
*/
|
|
37
|
-
const SOCKET_TIMEOUT_S = '30';
|
|
38
|
-
let active = 0;
|
|
39
|
-
const waiting = [];
|
|
40
|
-
/**
|
|
41
|
-
* Takes a concurrency slot, waiting for one when the limiter is full.
|
|
42
|
-
*
|
|
43
|
-
* The wait honours the request's abort signal. It used to be a bare promise
|
|
44
|
-
* with no way out, so a client that gave up stayed queued forever — and since a
|
|
45
|
-
* media transfer runs without a wall-clock timeout, three stalled downloads
|
|
46
|
-
* held every slot and every later call queued behind them, uncancellable. The
|
|
47
|
-
* server was not slow, it was wedged, and no tool could run again.
|
|
48
|
-
*/
|
|
49
|
-
async function acquireSlot(signal) {
|
|
50
|
-
// No already-aborted check here: `runYtDlp` makes it before every attempt and
|
|
51
|
-
// nothing awaits in between, so a second one could never fire — an
|
|
52
|
-
// unreachable guard that reads like a reachable one.
|
|
53
|
-
if (active < MAX_CONCURRENT) {
|
|
54
|
-
active++;
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
await new Promise((resolve, reject) => {
|
|
58
|
-
const waiter = {
|
|
59
|
-
grant: () => {
|
|
60
|
-
signal?.removeEventListener('abort', onAbort);
|
|
61
|
-
resolve();
|
|
62
|
-
},
|
|
63
|
-
cancel: (error) => {
|
|
64
|
-
signal?.removeEventListener('abort', onAbort);
|
|
65
|
-
reject(error);
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
function onAbort() {
|
|
69
|
-
const index = waiting.indexOf(waiter);
|
|
70
|
-
if (index !== -1)
|
|
71
|
-
waiting.splice(index, 1);
|
|
72
|
-
waiter.cancel(new YouTubeError('CANCELLED', 'The request was cancelled.'));
|
|
73
|
-
}
|
|
74
|
-
signal?.addEventListener('abort', onAbort, { once: true });
|
|
75
|
-
waiting.push(waiter);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Hands the slot to the next waiter rather than freeing it and letting them
|
|
80
|
-
* race for it: decrementing first left `active` below the limit for a tick, so
|
|
81
|
-
* a fresh caller could take the slot the queue was already promised and the
|
|
82
|
-
* limiter would run over its own ceiling.
|
|
83
|
-
*/
|
|
84
|
-
function releaseSlot() {
|
|
85
|
-
const next = waiting.shift();
|
|
86
|
-
if (next) {
|
|
87
|
-
next.grant();
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
active--;
|
|
91
|
-
}
|
|
92
|
-
/** Test seam: lets the suite assert the limiter without spawning processes. */
|
|
93
|
-
export function concurrencyState() {
|
|
94
|
-
return { active, queued: waiting.length, limit: MAX_CONCURRENT };
|
|
95
|
-
}
|
|
96
|
-
function backoffDelay(attempt) {
|
|
97
|
-
// Exponential with full jitter, so parallel callers do not retry in lockstep.
|
|
98
|
-
const ceiling = BASE_BACKOFF_MS * 2 ** (attempt - 1);
|
|
99
|
-
return Math.round(Math.random() * ceiling);
|
|
100
|
-
}
|
|
101
|
-
async function sleep(ms, signal) {
|
|
102
|
-
await new Promise((resolve, reject) => {
|
|
103
|
-
const timer = setTimeout(() => {
|
|
104
|
-
signal?.removeEventListener('abort', onAbort);
|
|
105
|
-
resolve();
|
|
106
|
-
}, ms);
|
|
107
|
-
const onAbort = () => {
|
|
108
|
-
clearTimeout(timer);
|
|
109
|
-
reject(new YouTubeError('CANCELLED', 'The request was cancelled.'));
|
|
110
|
-
};
|
|
111
|
-
signal?.addEventListener('abort', onAbort, { once: true });
|
|
112
|
-
});
|
|
113
|
-
}
|
|
41
|
+
export const SOCKET_TIMEOUT_S = '30';
|
|
114
42
|
/**
|
|
115
43
|
* Run yt-dlp and return its stdout.
|
|
116
44
|
*
|
|
117
45
|
* Arguments are always passed as an array — never a shell string — so video
|
|
118
|
-
* titles and user-supplied queries cannot become shell metacharacters.
|
|
46
|
+
* titles and user-supplied queries cannot become shell metacharacters. The
|
|
47
|
+
* target follows a `--` terminator, so it cannot become a yt-dlp option either.
|
|
119
48
|
*/
|
|
120
|
-
export async function runYtDlp(args, options
|
|
121
|
-
const { timeoutMs = TIMEOUTS.metadata, retry = true, label = 'yt-dlp' } = options;
|
|
49
|
+
export async function runYtDlp(args, options) {
|
|
50
|
+
const { timeoutMs = TIMEOUTS.metadata, retry = true, label = 'yt-dlp', target } = options;
|
|
122
51
|
const { signal } = currentContext();
|
|
123
52
|
const maxAttempts = retry ? MAX_ATTEMPTS : 1;
|
|
124
53
|
for (let attempt = 1;; attempt++) {
|
|
@@ -128,25 +57,63 @@ export async function runYtDlp(args, options = {}) {
|
|
|
128
57
|
if (signal?.aborted === true) {
|
|
129
58
|
throw new YouTubeError('CANCELLED', 'The request was cancelled.');
|
|
130
59
|
}
|
|
60
|
+
// The cooldown gates NEW work, not this call's own retries: it applies on
|
|
61
|
+
// the first attempt only. Mixing the two would make a single call's latency
|
|
62
|
+
// unbounded — its retry would wait out a global cooldown that exists to
|
|
63
|
+
// slow the *next* caller down. Retries use the backoff.
|
|
64
|
+
//
|
|
65
|
+
// Deliberately outside the try: an open circuit is this server's own
|
|
66
|
+
// decision, not a spawn failure, and letting the catch below translate and
|
|
67
|
+
// retry it would spawn the very request the circuit exists to prevent.
|
|
68
|
+
// Waiting also happens before a slot is taken, so a cooling-down server
|
|
69
|
+
// does not sit on the concurrency queue while it waits.
|
|
70
|
+
const wait = attempt === 1 ? waitMs() : 0;
|
|
71
|
+
if (wait > 0) {
|
|
72
|
+
if (circuitOpen()) {
|
|
73
|
+
throw new YouTubeError('RATE_LIMITED', 'YouTube has refused this client repeatedly, so requests are paused.', {
|
|
74
|
+
nextStep: `Wait about ${String(Math.ceil(wait / 60_000))} minutes. If it persists this address is likely being gated: check check_health for the cookie and PO token provider settings.`,
|
|
75
|
+
retryable: true,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
log('info', `${label} waiting ${String(wait)}ms before spawning`);
|
|
79
|
+
await sleep(wait, signal);
|
|
80
|
+
}
|
|
131
81
|
try {
|
|
132
|
-
|
|
82
|
+
const stdout = await spawnOnce(args, target, timeoutMs, signal);
|
|
83
|
+
onSuccess();
|
|
84
|
+
return stdout;
|
|
133
85
|
}
|
|
134
86
|
catch (error) {
|
|
135
87
|
const failure = translateExecaFailure(error, timeoutMs);
|
|
136
|
-
|
|
88
|
+
const decision = onFailure(failure.code, attempt);
|
|
89
|
+
// The error's own `retryable` wins over the pacer's policy. The
|
|
90
|
+
// classifier read the stderr and knows whether a retry can help; the
|
|
91
|
+
// pacer only knows the code. Dropping this gate made every unclassified
|
|
92
|
+
// YTDLP_FAILED retry, doubling requests on exactly the failures we cannot
|
|
93
|
+
// diagnose — the opposite of the point.
|
|
94
|
+
if (!failure.retryable || decision.giveUp || attempt >= maxAttempts)
|
|
137
95
|
throw failure;
|
|
138
|
-
|
|
139
|
-
log('warning', `${label} failed (${failure.code}), retrying in ${delay}ms`);
|
|
96
|
+
log('warning', `${label} failed (${failure.code}), retrying in ${String(decision.delayMs)}ms`);
|
|
140
97
|
// The slot is already released, so the backoff does not hold the queue.
|
|
141
|
-
await sleep(
|
|
98
|
+
await sleep(decision.delayMs, signal);
|
|
142
99
|
}
|
|
143
100
|
}
|
|
144
101
|
}
|
|
145
102
|
/** One attempt, holding a concurrency slot for exactly its duration. */
|
|
146
|
-
async function spawnOnce(args, timeoutMs, signal) {
|
|
103
|
+
async function spawnOnce(args, target, timeoutMs, signal) {
|
|
147
104
|
await acquireSlot(signal);
|
|
148
105
|
try {
|
|
149
|
-
|
|
106
|
+
// Session flags (cookies, proxy, pacing) go first so a caller's argument can
|
|
107
|
+
// never be read as their value; the target goes last, behind `--`.
|
|
108
|
+
const argv = [
|
|
109
|
+
'--socket-timeout',
|
|
110
|
+
SOCKET_TIMEOUT_S,
|
|
111
|
+
...readYtDlpEnv().args,
|
|
112
|
+
...args,
|
|
113
|
+
'--',
|
|
114
|
+
target,
|
|
115
|
+
];
|
|
116
|
+
const { stdout } = await execa('yt-dlp', argv, {
|
|
150
117
|
timeout: timeoutMs > 0 ? timeoutMs : undefined,
|
|
151
118
|
cancelSignal: signal,
|
|
152
119
|
maxBuffer: MAX_OUTPUT_BYTES,
|
|
@@ -193,49 +160,4 @@ function asText(value) {
|
|
|
193
160
|
}
|
|
194
161
|
return '';
|
|
195
162
|
}
|
|
196
|
-
/**
|
|
197
|
-
* Parse yt-dlp JSON output behind a type guard.
|
|
198
|
-
*
|
|
199
|
-
* Every JSON.parse in this codebase used to be unguarded, so a truncated or
|
|
200
|
-
* non-JSON response surfaced as a raw SyntaxError.
|
|
201
|
-
*/
|
|
202
|
-
export function parseYtDlpJson(stdout, guard, what) {
|
|
203
|
-
let parsed;
|
|
204
|
-
try {
|
|
205
|
-
parsed = JSON.parse(stdout);
|
|
206
|
-
}
|
|
207
|
-
catch (error) {
|
|
208
|
-
throw new YouTubeError('MALFORMED_RESPONSE', `yt-dlp returned unreadable output for ${what}.`, {
|
|
209
|
-
nextStep: 'This usually means yt-dlp is out of date. Run `yt-dlp -U` and try again.',
|
|
210
|
-
retryable: true,
|
|
211
|
-
cause: error,
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
if (!guard(parsed)) {
|
|
215
|
-
throw new YouTubeError('MALFORMED_RESPONSE', `yt-dlp returned an unexpected shape for ${what}.`, {
|
|
216
|
-
nextStep: 'This usually means yt-dlp is out of date. Run `yt-dlp -U` and try again.',
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
return parsed;
|
|
220
|
-
}
|
|
221
|
-
/** Parse newline-delimited JSON, skipping unparseable lines rather than failing the call. */
|
|
222
|
-
export function parseYtDlpJsonLines(stdout, guard) {
|
|
223
|
-
const results = [];
|
|
224
|
-
for (const line of stdout.trim().split('\n')) {
|
|
225
|
-
if (!line.trim())
|
|
226
|
-
continue;
|
|
227
|
-
try {
|
|
228
|
-
const parsed = JSON.parse(line);
|
|
229
|
-
if (guard(parsed))
|
|
230
|
-
results.push(parsed);
|
|
231
|
-
}
|
|
232
|
-
catch {
|
|
233
|
-
// A single malformed row should not lose the whole result set.
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return results;
|
|
237
|
-
}
|
|
238
|
-
export function isRecord(value) {
|
|
239
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
240
|
-
}
|
|
241
163
|
//# sourceMappingURL=ytdlp.js.map
|
package/dist/utils/ytdlp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ytdlp.js","sourceRoot":"","sources":["../../src/utils/ytdlp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ytdlp.js","sourceRoot":"","sources":["../../src/utils/ytdlp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvE;;;;;;;GAOG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,wDAAwD;IACxD,QAAQ,EAAE,MAAM;IAChB,gDAAgD;IAChD,UAAU,EAAE,MAAM;IAClB,iEAAiE;IACjE,QAAQ,EAAE,OAAO;IACjB,2EAA2E;IAC3E,QAAQ,EAAE,CAAC;CACH,CAAC;AAEX,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,yEAAyE;AACzE,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAmBrC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAc,EAAE,OAAmB;IAChE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC1F,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7C,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,wEAAwE;QACxE,uEAAuE;QACvE,8DAA8D;QAC9D,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC;QACpE,CAAC;QAED,0EAA0E;QAC1E,4EAA4E;QAC5E,wEAAwE;QACxE,wDAAwD;QACxD,EAAE;QACF,qEAAqE;QACrE,2EAA2E;QAC3E,uEAAuE;QACvE,wEAAwE;QACxE,wDAAwD;QACxD,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACb,IAAI,WAAW,EAAE,EAAE,CAAC;gBAClB,MAAM,IAAI,YAAY,CACpB,cAAc,EACd,qEAAqE,EACrE;oBACE,QAAQ,EAAE,cAAc,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,gIAAgI;oBACxL,SAAS,EAAE,IAAI;iBAChB,CACF,CAAC;YACJ,CAAC;YACD,GAAG,CAAC,MAAM,EAAE,GAAG,KAAK,YAAY,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YAClE,MAAM,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAChE,SAAS,EAAE,CAAC;YACZ,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAElD,gEAAgE;YAChE,qEAAqE;YACrE,wEAAwE;YACxE,0EAA0E;YAC1E,wCAAwC;YACxC,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,MAAM,IAAI,OAAO,IAAI,WAAW;gBAAE,MAAM,OAAO,CAAC;YAEnF,GAAG,CACD,SAAS,EACT,GAAG,KAAK,YAAY,OAAO,CAAC,IAAI,kBAAkB,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAC/E,CAAC;YACF,wEAAwE;YACxE,MAAM,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,KAAK,UAAU,SAAS,CACtB,IAAc,EACd,MAAc,EACd,SAAiB,EACjB,MAA+B;IAE/B,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,IAAI,CAAC;QACH,6EAA6E;QAC7E,mEAAmE;QACnE,MAAM,IAAI,GAAG;YACX,kBAAkB;YAClB,gBAAgB;YAChB,GAAG,YAAY,EAAE,CAAC,IAAI;YACtB,GAAG,IAAI;YACP,IAAI;YACJ,MAAM;SACP,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE;YAC7C,OAAO,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YAC9C,YAAY,EAAE,MAAM;YACpB,SAAS,EAAE,gBAAgB;YAC3B,iBAAiB,EAAE,IAAI;SACxB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,WAAW,EAAE,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc,EAAE,SAAiB;IAC9D,IAAI,KAAK,YAAY,YAAY;QAAE,OAAO,KAAK,CAAC;IAEhD,IAAI,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,EAAE,CAAC;QACnC,OAAO,oBAAoB,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,4BAA4B,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO,IAAI,YAAY,CACrB,SAAS,EACT,iCAAiC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,EACjE;YACE,QAAQ,EACN,0FAA0F;YAC5F,SAAS,EAAE,IAAI;YACf,KAAK,EAAE,KAAK;SACb,CACF,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,IAAI,YAAY,CAAC,eAAe,EAAE,yCAAyC,EAAE;YAClF,QAAQ,EACN,yHAAyH;YAC3H,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;IAED,sEAAsE;IACtE,MAAM,SAAS,GAAY,KAAK,CAAC,MAAM,CAAC;IACxC,MAAM,UAAU,GAAY,KAAK,CAAC,YAAY,CAAC;IAC/C,OAAO,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "youtube-knowledge-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "MCP Server for extracting and managing YouTube video knowledge",
|
|
5
5
|
"author": "teobouancheau",
|
|
6
6
|
"repository": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"test": "vitest run",
|
|
41
41
|
"test:watch": "vitest",
|
|
42
42
|
"test:coverage": "vitest run --coverage",
|
|
43
|
+
"test:e2e": "npm run build && vitest run -c vitest.e2e.config.ts",
|
|
43
44
|
"typecheck": "tsc --noEmit",
|
|
44
45
|
"validate": "npm run typecheck && npm run lint && npm run format:check && npm run test:coverage",
|
|
45
46
|
"prepare": "husky",
|
|
@@ -82,6 +83,6 @@
|
|
|
82
83
|
"vitest": "^4.1.10"
|
|
83
84
|
},
|
|
84
85
|
"engines": {
|
|
85
|
-
"node": ">=22.
|
|
86
|
+
"node": ">=22.13.0"
|
|
86
87
|
}
|
|
87
88
|
}
|