youtube-knowledge-mcp 2.2.0 → 3.0.1
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 +126 -36
- package/dist/brain-schemas.d.ts +10 -0
- package/dist/brain-schemas.d.ts.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 +111 -0
- package/dist/harvest-schemas.js.map +1 -0
- package/dist/registry/brain-tools.d.ts.map +1 -1
- package/dist/registry/brain-tools.js +16 -0
- package/dist/registry/brain-tools.js.map +1 -1
- package/dist/registry/channel-tools.d.ts.map +1 -1
- package/dist/registry/channel-tools.js +16 -0
- package/dist/registry/channel-tools.js.map +1 -1
- 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.map +1 -1
- package/dist/registry/health-tools.js +18 -0
- package/dist/registry/health-tools.js.map +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +6 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/media-tools.d.ts.map +1 -1
- package/dist/registry/media-tools.js +31 -0
- package/dist/registry/media-tools.js.map +1 -1
- package/dist/registry/store-tools.d.ts +9 -0
- package/dist/registry/store-tools.d.ts.map +1 -0
- package/dist/registry/store-tools.js +59 -0
- package/dist/registry/store-tools.js.map +1 -0
- package/dist/registry/transcript-tools.d.ts +4 -1
- package/dist/registry/transcript-tools.d.ts.map +1 -1
- package/dist/registry/transcript-tools.js +20 -1
- package/dist/registry/transcript-tools.js.map +1 -1
- package/dist/registry/video-tools.d.ts.map +1 -1
- package/dist/registry/video-tools.js +49 -1
- package/dist/registry/video-tools.js.map +1 -1
- package/dist/registry/vision-tools.d.ts +7 -0
- package/dist/registry/vision-tools.d.ts.map +1 -0
- package/dist/registry/vision-tools.js +55 -0
- package/dist/registry/vision-tools.js.map +1 -0
- package/dist/schemas.d.ts +245 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +58 -0
- package/dist/schemas.js.map +1 -1
- package/dist/thumbnail-schemas.d.ts +38 -28
- package/dist/thumbnail-schemas.d.ts.map +1 -1
- package/dist/tools/ask-brain.js +1 -1
- package/dist/tools/ask-brain.js.map +1 -1
- package/dist/tools/ask-brains.d.ts +66 -0
- package/dist/tools/ask-brains.d.ts.map +1 -0
- package/dist/tools/ask-brains.js +111 -0
- package/dist/tools/ask-brains.js.map +1 -0
- package/dist/tools/brain-info.js +1 -1
- package/dist/tools/brain-info.js.map +1 -1
- package/dist/tools/check-health.d.ts +75 -6
- package/dist/tools/check-health.d.ts.map +1 -1
- package/dist/tools/check-health.js +114 -6
- package/dist/tools/check-health.js.map +1 -1
- package/dist/tools/check-new-uploads.d.ts +55 -0
- package/dist/tools/check-new-uploads.d.ts.map +1 -0
- package/dist/tools/check-new-uploads.js +74 -0
- package/dist/tools/check-new-uploads.js.map +1 -0
- package/dist/tools/clips.d.ts +15 -0
- package/dist/tools/clips.d.ts.map +1 -1
- package/dist/tools/clips.js +5 -5
- package/dist/tools/clips.js.map +1 -1
- package/dist/tools/detect-scenes.d.ts +38 -0
- package/dist/tools/detect-scenes.d.ts.map +1 -0
- package/dist/tools/detect-scenes.js +66 -0
- package/dist/tools/detect-scenes.js.map +1 -0
- package/dist/tools/export-data.d.ts +85 -0
- package/dist/tools/export-data.d.ts.map +1 -0
- package/dist/tools/export-data.js +99 -0
- package/dist/tools/export-data.js.map +1 -0
- package/dist/tools/fetch-channel-thumbnails.d.ts +8 -8
- package/dist/tools/fetch-videos.d.ts +15 -4
- package/dist/tools/fetch-videos.d.ts.map +1 -1
- package/dist/tools/fetch-videos.js +63 -22
- package/dist/tools/fetch-videos.js.map +1 -1
- package/dist/tools/frames-subtitles.d.ts.map +1 -1
- package/dist/tools/frames-subtitles.js +16 -8
- package/dist/tools/frames-subtitles.js.map +1 -1
- package/dist/tools/frames.d.ts +73 -0
- package/dist/tools/frames.d.ts.map +1 -0
- package/dist/tools/frames.js +136 -0
- package/dist/tools/frames.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 +4 -0
- 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-sponsor-segments.d.ts +49 -0
- package/dist/tools/get-sponsor-segments.d.ts.map +1 -0
- package/dist/tools/get-sponsor-segments.js +61 -0
- package/dist/tools/get-sponsor-segments.js.map +1 -0
- package/dist/tools/get-thumbnail.d.ts.map +1 -1
- package/dist/tools/get-thumbnail.js +2 -1
- package/dist/tools/get-thumbnail.js.map +1 -1
- package/dist/tools/get-transcript.d.ts +1 -0
- package/dist/tools/get-transcript.d.ts.map +1 -1
- package/dist/tools/get-transcript.js +11 -4
- package/dist/tools/get-transcript.js.map +1 -1
- package/dist/tools/get-video-details.d.ts +118 -0
- package/dist/tools/get-video-details.d.ts.map +1 -0
- package/dist/tools/get-video-details.js +147 -0
- package/dist/tools/get-video-details.js.map +1 -0
- package/dist/tools/gif-concat.d.ts +49 -0
- package/dist/tools/gif-concat.d.ts.map +1 -0
- package/dist/tools/gif-concat.js +96 -0
- package/dist/tools/gif-concat.js.map +1 -0
- 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/harvest-details.d.ts +84 -0
- package/dist/tools/harvest-details.d.ts.map +1 -0
- package/dist/tools/harvest-details.js +71 -0
- package/dist/tools/harvest-details.js.map +1 -0
- package/dist/tools/library.js +1 -1
- package/dist/tools/library.js.map +1 -1
- package/dist/tools/list-captions.d.ts +17 -0
- package/dist/tools/list-captions.d.ts.map +1 -0
- package/dist/tools/list-captions.js +60 -0
- package/dist/tools/list-captions.js.map +1 -0
- package/dist/tools/list-channel-playlists.d.ts +30 -0
- package/dist/tools/list-channel-playlists.d.ts.map +1 -0
- package/dist/tools/list-channel-playlists.js +44 -0
- package/dist/tools/list-channel-playlists.js.map +1 -0
- package/dist/tools/list-channel-thumbnails.d.ts +10 -10
- package/dist/tools/list-channel-thumbnails.js +1 -1
- package/dist/tools/list-channel-thumbnails.js.map +1 -1
- 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/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-videos.js +1 -1
- package/dist/tools/search-videos.js.map +1 -1
- package/dist/tools/transcribe-video.d.ts +28 -0
- package/dist/tools/transcribe-video.d.ts.map +1 -0
- package/dist/tools/transcribe-video.js +52 -0
- package/dist/tools/transcribe-video.js.map +1 -0
- package/dist/utils/brain-fusion.d.ts +24 -0
- package/dist/utils/brain-fusion.d.ts.map +1 -0
- package/dist/utils/brain-fusion.js +18 -0
- package/dist/utils/brain-fusion.js.map +1 -0
- package/dist/utils/channel-playlists.d.ts +21 -0
- package/dist/utils/channel-playlists.d.ts.map +1 -0
- package/dist/utils/channel-playlists.js +56 -0
- package/dist/utils/channel-playlists.js.map +1 -0
- package/dist/utils/clips.d.ts.map +1 -1
- package/dist/utils/clips.js +3 -17
- 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/concat.d.ts +19 -0
- package/dist/utils/concat.d.ts.map +1 -0
- package/dist/utils/concat.js +135 -0
- package/dist/utils/concat.js.map +1 -0
- package/dist/utils/contact-sheet.d.ts +28 -0
- package/dist/utils/contact-sheet.d.ts.map +1 -0
- package/dist/utils/contact-sheet.js +65 -0
- package/dist/utils/contact-sheet.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/detail-batch.d.ts +25 -0
- package/dist/utils/detail-batch.d.ts.map +1 -0
- package/dist/utils/detail-batch.js +58 -0
- package/dist/utils/detail-batch.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 +19 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/export-data.d.ts +41 -0
- package/dist/utils/export-data.d.ts.map +1 -0
- package/dist/utils/export-data.js +114 -0
- package/dist/utils/export-data.js.map +1 -0
- package/dist/utils/export-format.d.ts +23 -0
- package/dist/utils/export-format.d.ts.map +1 -0
- package/dist/utils/export-format.js +59 -0
- package/dist/utils/export-format.js.map +1 -0
- package/dist/utils/export-load.d.ts +28 -0
- package/dist/utils/export-load.d.ts.map +1 -0
- package/dist/utils/export-load.js +70 -0
- package/dist/utils/export-load.js.map +1 -0
- package/dist/utils/export-rows.d.ts +35 -0
- package/dist/utils/export-rows.d.ts.map +1 -0
- package/dist/utils/export-rows.js +69 -0
- package/dist/utils/export-rows.js.map +1 -0
- package/dist/utils/ffmpeg.d.ts +26 -0
- package/dist/utils/ffmpeg.d.ts.map +1 -0
- package/dist/utils/ffmpeg.js +28 -0
- package/dist/utils/ffmpeg.js.map +1 -0
- package/dist/utils/format.d.ts +23 -1
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/format.js +5 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/frame-plan.d.ts +24 -0
- package/dist/utils/frame-plan.d.ts.map +1 -0
- package/dist/utils/frame-plan.js +58 -0
- package/dist/utils/frame-plan.js.map +1 -0
- package/dist/utils/frames.d.ts +32 -0
- package/dist/utils/frames.d.ts.map +1 -0
- package/dist/utils/frames.js +60 -0
- package/dist/utils/frames.js.map +1 -0
- package/dist/utils/gif.d.ts +31 -0
- package/dist/utils/gif.d.ts.map +1 -0
- package/dist/utils/gif.js +77 -0
- package/dist/utils/gif.js.map +1 -0
- package/dist/utils/harvest-catalog.d.ts +54 -0
- package/dist/utils/harvest-catalog.d.ts.map +1 -0
- package/dist/utils/harvest-catalog.js +173 -0
- package/dist/utils/harvest-catalog.js.map +1 -0
- package/dist/utils/harvest-details.d.ts +30 -0
- package/dist/utils/harvest-details.d.ts.map +1 -0
- package/dist/utils/harvest-details.js +98 -0
- package/dist/utils/harvest-details.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/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/local-transcription.d.ts +14 -0
- package/dist/utils/local-transcription.d.ts.map +1 -0
- package/dist/utils/local-transcription.js +85 -0
- package/dist/utils/local-transcription.js.map +1 -0
- package/dist/utils/moment.d.ts +24 -0
- package/dist/utils/moment.d.ts.map +1 -0
- package/dist/utils/moment.js +22 -0
- package/dist/utils/moment.js.map +1 -0
- package/dist/utils/most-replayed.d.ts +15 -0
- package/dist/utils/most-replayed.d.ts.map +1 -0
- package/dist/utils/most-replayed.js +25 -0
- package/dist/utils/most-replayed.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/scenes.d.ts +39 -0
- package/dist/utils/scenes.d.ts.map +1 -0
- package/dist/utils/scenes.js +83 -0
- package/dist/utils/scenes.js.map +1 -0
- package/dist/utils/seconds.d.ts +5 -0
- package/dist/utils/seconds.d.ts.map +1 -0
- package/dist/utils/seconds.js +7 -0
- package/dist/utils/seconds.js.map +1 -0
- 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/sponsorblock.d.ts +24 -0
- package/dist/utils/sponsorblock.d.ts.map +1 -0
- package/dist/utils/sponsorblock.js +153 -0
- package/dist/utils/sponsorblock.js.map +1 -0
- 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/transcript-cache.d.ts +5 -1
- package/dist/utils/transcript-cache.d.ts.map +1 -1
- package/dist/utils/transcript-cache.js +31 -50
- package/dist/utils/transcript-cache.js.map +1 -1
- package/dist/utils/transcript-files.d.ts +24 -0
- package/dist/utils/transcript-files.d.ts.map +1 -0
- package/dist/utils/transcript-files.js +61 -0
- package/dist/utils/transcript-files.js.map +1 -0
- package/dist/utils/transcript.d.ts +3 -0
- package/dist/utils/transcript.d.ts.map +1 -1
- package/dist/utils/transcript.js +2 -0
- package/dist/utils/transcript.js.map +1 -1
- package/dist/utils/upload-check.d.ts +38 -0
- package/dist/utils/upload-check.d.ts.map +1 -0
- package/dist/utils/upload-check.js +93 -0
- package/dist/utils/upload-check.js.map +1 -0
- package/dist/utils/validate.d.ts +2 -0
- package/dist/utils/validate.d.ts.map +1 -1
- package/dist/utils/validate.js +4 -0
- package/dist/utils/validate.js.map +1 -1
- package/dist/utils/video-detail-store.d.ts +47 -0
- package/dist/utils/video-detail-store.d.ts.map +1 -0
- package/dist/utils/video-detail-store.js +89 -0
- package/dist/utils/video-detail-store.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-schema.d.ts +187 -0
- package/dist/utils/video-stats-schema.d.ts.map +1 -0
- package/dist/utils/video-stats-schema.js +50 -0
- package/dist/utils/video-stats-schema.js.map +1 -0
- package/dist/utils/video-stats-storage.d.ts +16 -0
- package/dist/utils/video-stats-storage.d.ts.map +1 -0
- package/dist/utils/video-stats-storage.js +37 -0
- package/dist/utils/video-stats-storage.js.map +1 -0
- package/dist/utils/video-stats.d.ts +82 -0
- package/dist/utils/video-stats.d.ts.map +1 -0
- package/dist/utils/video-stats.js +108 -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/video-stream.d.ts +21 -0
- package/dist/utils/video-stream.d.ts.map +1 -0
- package/dist/utils/video-stream.js +36 -0
- package/dist/utils/video-stream.js.map +1 -0
- package/dist/utils/whisper.d.ts +39 -0
- package/dist/utils/whisper.d.ts.map +1 -0
- package/dist/utils/whisper.js +137 -0
- package/dist/utils/whisper.js.map +1 -0
- package/dist/utils/youtube-channel.d.ts +13 -2
- package/dist/utils/youtube-channel.d.ts.map +1 -1
- package/dist/utils/youtube-channel.js +39 -3
- package/dist/utils/youtube-channel.js.map +1 -1
- package/dist/utils/youtube-schemas.d.ts +104 -0
- package/dist/utils/youtube-schemas.d.ts.map +1 -1
- package/dist/utils/youtube-schemas.js +32 -0
- package/dist/utils/youtube-schemas.js.map +1 -1
- package/dist/utils/youtube-video.d.ts +22 -1
- package/dist/utils/youtube-video.d.ts.map +1 -1
- package/dist/utils/youtube-video.js +40 -28
- package/dist/utils/youtube-video.js.map +1 -1
- package/dist/utils/ytdlp-limiter.d.ts +3 -0
- package/dist/utils/ytdlp-limiter.d.ts.map +1 -1
- package/dist/utils/ytdlp-limiter.js +19 -3
- package/dist/utils/ytdlp-limiter.js.map +1 -1
- 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-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 +10 -0
- package/dist/utils/ytdlp.d.ts.map +1 -1
- package/dist/utils/ytdlp.js +36 -25
- package/dist/utils/ytdlp.js.map +1 -1
- package/package.json +10 -4
|
@@ -5,67 +5,40 @@ import { YouTubeError } from './errors.js';
|
|
|
5
5
|
import { TIMEOUTS, runYtDlp } from './ytdlp.js';
|
|
6
6
|
import { noCaptionsError } from './caption-probe.js';
|
|
7
7
|
import { assertLanguageTag } from './validate.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { TRANSCRIPT_CACHE_VERSION, cachedTranscriptSchema, parseVtt, segmentsToText, } from './transcript.js';
|
|
8
|
+
import { ensurePrivateDir } from './paths.js';
|
|
9
|
+
import { TRANSCRIPT_DIR, asrPath, captionsPath, readTranscriptFile, writeTranscriptFile, } from './transcript-files.js';
|
|
10
|
+
import { TRANSCRIPT_CACHE_VERSION, parseVtt, segmentsToText, } from './transcript.js';
|
|
12
11
|
import { extractVideoId, watchUrl } from './youtube-url.js';
|
|
13
|
-
/** Fetching a transcript from YouTube and keeping it on disk. */
|
|
14
|
-
const CACHE_DIR = dataDir('transcripts');
|
|
15
|
-
/** Captions rarely change, but a cache with no expiry is a cache that goes wrong. */
|
|
16
|
-
const TRANSCRIPT_TTL_MS = envInt('YOUTUBE_MCP_TRANSCRIPT_TTL_MS', 30 * 86_400_000, { min: 0 });
|
|
17
|
-
function cachePath(videoId, language) {
|
|
18
|
-
return join(CACHE_DIR, `${videoId}.${language}.json`);
|
|
19
|
-
}
|
|
20
|
-
async function readCachedTranscript(videoId, language) {
|
|
21
|
-
const path = cachePath(videoId, language);
|
|
22
|
-
if (!existsSync(path))
|
|
23
|
-
return undefined;
|
|
24
|
-
try {
|
|
25
|
-
const parsed = cachedTranscriptSchema.safeParse(JSON.parse(await readFile(path, 'utf-8')));
|
|
26
|
-
// Anything unreadable — an older layout, a truncated write, a hand-edit —
|
|
27
|
-
// is treated as absent and refetched, rather than half-trusted.
|
|
28
|
-
if (!parsed.success)
|
|
29
|
-
return undefined;
|
|
30
|
-
const cached = parsed.data;
|
|
31
|
-
// A cache written by an older version holds untimed text; regenerate it
|
|
32
|
-
// rather than reading it back as if it had timings.
|
|
33
|
-
if (cached.version !== TRANSCRIPT_CACHE_VERSION)
|
|
34
|
-
return undefined;
|
|
35
|
-
const fetchedAt = Date.parse(cached.fetchedAt);
|
|
36
|
-
if (Number.isFinite(fetchedAt) && Date.now() - fetchedAt > TRANSCRIPT_TTL_MS)
|
|
37
|
-
return undefined;
|
|
38
|
-
return cached;
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
12
|
/** True when a usable transcript is already on disk, in any language. */
|
|
45
13
|
export function hasCachedTranscript(videoId) {
|
|
46
|
-
if (!existsSync(
|
|
14
|
+
if (!existsSync(TRANSCRIPT_DIR))
|
|
47
15
|
return false;
|
|
48
|
-
return readdirSync(
|
|
16
|
+
return readdirSync(TRANSCRIPT_DIR).some((name) => name.startsWith(`${videoId}.`) && name.endsWith('.json'));
|
|
17
|
+
}
|
|
18
|
+
export function resultFromEntry(entry, videoId, source) {
|
|
19
|
+
return {
|
|
20
|
+
transcript: segmentsToText(entry.segments),
|
|
21
|
+
segments: entry.segments,
|
|
22
|
+
language: entry.language,
|
|
23
|
+
videoId,
|
|
24
|
+
cached: true,
|
|
25
|
+
source,
|
|
26
|
+
};
|
|
49
27
|
}
|
|
50
28
|
export async function getTranscript(urlOrId, options = {}) {
|
|
51
29
|
const preferredLang = options.language ?? 'en';
|
|
52
30
|
const videoId = extractVideoId(urlOrId);
|
|
53
31
|
assertLanguageTag(preferredLang);
|
|
54
32
|
const url = watchUrl(videoId);
|
|
55
|
-
await ensurePrivateDir(
|
|
33
|
+
await ensurePrivateDir(TRANSCRIPT_DIR);
|
|
56
34
|
if (!options.refresh) {
|
|
57
|
-
const cached = await
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
language: cached.language,
|
|
63
|
-
videoId,
|
|
64
|
-
cached: true,
|
|
65
|
-
};
|
|
66
|
-
}
|
|
35
|
+
const cached = await readTranscriptFile(captionsPath(videoId, preferredLang), {
|
|
36
|
+
expires: true,
|
|
37
|
+
});
|
|
38
|
+
if (cached)
|
|
39
|
+
return resultFromEntry(cached, videoId, 'captions');
|
|
67
40
|
}
|
|
68
|
-
const tempDir = join(
|
|
41
|
+
const tempDir = join(TRANSCRIPT_DIR, 'temp');
|
|
69
42
|
await ensurePrivateDir(tempDir);
|
|
70
43
|
const outputTemplate = join(tempDir, videoId);
|
|
71
44
|
try {
|
|
@@ -103,7 +76,7 @@ export async function getTranscript(urlOrId, options = {}) {
|
|
|
103
76
|
fetchedAt: new Date().toISOString(),
|
|
104
77
|
segments,
|
|
105
78
|
};
|
|
106
|
-
await
|
|
79
|
+
await writeTranscriptFile(captionsPath(videoId, preferredLang), entry);
|
|
107
80
|
await unlink(found.file).catch(() => undefined);
|
|
108
81
|
return {
|
|
109
82
|
transcript: segmentsToText(segments),
|
|
@@ -111,9 +84,17 @@ export async function getTranscript(urlOrId, options = {}) {
|
|
|
111
84
|
language: found.language,
|
|
112
85
|
videoId,
|
|
113
86
|
cached: false,
|
|
87
|
+
source: 'captions',
|
|
114
88
|
};
|
|
115
89
|
}
|
|
116
90
|
catch (error) {
|
|
91
|
+
if (error instanceof YouTubeError && error.code === 'NO_CAPTIONS') {
|
|
92
|
+
// A transcription made locally stands in only when the video has no captions
|
|
93
|
+
// at all, so real captions are never displaced by a machine's guess.
|
|
94
|
+
const heard = await readTranscriptFile(asrPath(videoId, preferredLang), { expires: false });
|
|
95
|
+
if (heard)
|
|
96
|
+
return resultFromEntry(heard, videoId, 'local-asr');
|
|
97
|
+
}
|
|
117
98
|
// Already typed and actionable — pass it through rather than flattening it
|
|
118
99
|
// into a generic string, which is what the old wrapper did to every failure.
|
|
119
100
|
if (error instanceof YouTubeError)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-cache.js","sourceRoot":"","sources":["../../src/utils/transcript-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"transcript-cache.js","sourceRoot":"","sources":["../../src/utils/transcript-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type CachedTranscript } from './transcript.js';
|
|
2
|
+
/**
|
|
3
|
+
* Transcripts on disk: where they live and how they are read back.
|
|
4
|
+
*
|
|
5
|
+
* Captions and local transcriptions sit side by side but never overwrite each other:
|
|
6
|
+
* `<id>.<lang>.json` holds what YouTube's captions said, `<id>.<lang>.asr.json` what
|
|
7
|
+
* whisper heard. Real captions are always preferred, so a machine transcription can
|
|
8
|
+
* never replace the better source.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TRANSCRIPT_DIR: string;
|
|
11
|
+
export declare function captionsPath(videoId: string, language: string): string;
|
|
12
|
+
export declare function asrPath(videoId: string, language: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* A transcript read back from `path`, or undefined when there is nothing usable.
|
|
15
|
+
*
|
|
16
|
+
* Anything unreadable — an older layout, a truncated write, a hand-edit — counts as
|
|
17
|
+
* absent rather than half-trusted. Captions expire; a local transcription does not,
|
|
18
|
+
* because it is deterministic and costs minutes to redo.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readTranscriptFile(path: string, options: {
|
|
21
|
+
expires: boolean;
|
|
22
|
+
}): Promise<CachedTranscript | undefined>;
|
|
23
|
+
export declare function writeTranscriptFile(path: string, entry: CachedTranscript): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=transcript-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcript-files.d.ts","sourceRoot":"","sources":["../../src/utils/transcript-files.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;GAOG;AAEH,eAAO,MAAM,cAAc,QAAyB,CAAC;AAWrD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAC5B,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAwBvC;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9F"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { envInt } from './env.js';
|
|
5
|
+
import { writeJsonAtomic } from './json-file.js';
|
|
6
|
+
import { dataDir } from './paths.js';
|
|
7
|
+
import { TRANSCRIPT_CACHE_VERSION, cachedTranscriptSchema, } from './transcript.js';
|
|
8
|
+
/**
|
|
9
|
+
* Transcripts on disk: where they live and how they are read back.
|
|
10
|
+
*
|
|
11
|
+
* Captions and local transcriptions sit side by side but never overwrite each other:
|
|
12
|
+
* `<id>.<lang>.json` holds what YouTube's captions said, `<id>.<lang>.asr.json` what
|
|
13
|
+
* whisper heard. Real captions are always preferred, so a machine transcription can
|
|
14
|
+
* never replace the better source.
|
|
15
|
+
*/
|
|
16
|
+
export const TRANSCRIPT_DIR = dataDir('transcripts');
|
|
17
|
+
/** Captions rarely change, but a cache with no expiry is a cache that goes wrong. */
|
|
18
|
+
const MS_PER_DAY = 86_400_000;
|
|
19
|
+
const DEFAULT_TRANSCRIPT_TTL_DAYS = 30;
|
|
20
|
+
const TRANSCRIPT_TTL_MS = envInt('YOUTUBE_MCP_TRANSCRIPT_TTL_MS', DEFAULT_TRANSCRIPT_TTL_DAYS * MS_PER_DAY, { min: 0 });
|
|
21
|
+
export function captionsPath(videoId, language) {
|
|
22
|
+
return join(TRANSCRIPT_DIR, `${videoId}.${language}.json`);
|
|
23
|
+
}
|
|
24
|
+
export function asrPath(videoId, language) {
|
|
25
|
+
return join(TRANSCRIPT_DIR, `${videoId}.${language}.asr.json`);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A transcript read back from `path`, or undefined when there is nothing usable.
|
|
29
|
+
*
|
|
30
|
+
* Anything unreadable — an older layout, a truncated write, a hand-edit — counts as
|
|
31
|
+
* absent rather than half-trusted. Captions expire; a local transcription does not,
|
|
32
|
+
* because it is deterministic and costs minutes to redo.
|
|
33
|
+
*/
|
|
34
|
+
export async function readTranscriptFile(path, options) {
|
|
35
|
+
if (!existsSync(path))
|
|
36
|
+
return undefined;
|
|
37
|
+
try {
|
|
38
|
+
const parsed = cachedTranscriptSchema.safeParse(JSON.parse(await readFile(path, 'utf-8')));
|
|
39
|
+
if (!parsed.success)
|
|
40
|
+
return undefined;
|
|
41
|
+
const cached = parsed.data;
|
|
42
|
+
// A cache written by an older version holds untimed text; regenerate it
|
|
43
|
+
// rather than reading it back as if it had timings.
|
|
44
|
+
if (cached.version !== TRANSCRIPT_CACHE_VERSION)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (options.expires) {
|
|
47
|
+
const fetchedAt = Date.parse(cached.fetchedAt);
|
|
48
|
+
if (Number.isFinite(fetchedAt) && Date.now() - fetchedAt > TRANSCRIPT_TTL_MS) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return cached;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function writeTranscriptFile(path, entry) {
|
|
59
|
+
await writeJsonAtomic(path, entry, { pretty: false });
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=transcript-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcript-files.js","sourceRoot":"","sources":["../../src/utils/transcript-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EACL,wBAAwB,EACxB,sBAAsB,GAEvB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAErD,qFAAqF;AACrF,MAAM,UAAU,GAAG,UAAU,CAAC;AAC9B,MAAM,2BAA2B,GAAG,EAAE,CAAC;AACvC,MAAM,iBAAiB,GAAG,MAAM,CAC9B,+BAA+B,EAC/B,2BAA2B,GAAG,UAAU,EACxC,EAAE,GAAG,EAAE,CAAC,EAAE,CACX,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,QAAgB;IAC5D,OAAO,IAAI,CAAC,cAAc,EAAE,GAAG,OAAO,IAAI,QAAQ,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,QAAgB;IACvD,OAAO,IAAI,CAAC,cAAc,EAAE,GAAG,OAAO,IAAI,QAAQ,WAAW,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,OAA6B;IAE7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3F,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAEtC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;QAE3B,wEAAwE;QACxE,oDAAoD;QACpD,IAAI,MAAM,CAAC,OAAO,KAAK,wBAAwB;YAAE,OAAO,SAAS,CAAC;QAElE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,iBAAiB,EAAE,CAAC;gBAC7E,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY,EAAE,KAAuB;IAC7E,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -23,6 +23,9 @@ export declare const transcriptSegmentSchema: z.ZodObject<{
|
|
|
23
23
|
start: number;
|
|
24
24
|
}>;
|
|
25
25
|
export type TranscriptSegment = z.infer<typeof transcriptSegmentSchema>;
|
|
26
|
+
/** Where a transcript's words came from. A machine's guess must never pass as captions. */
|
|
27
|
+
export declare const TRANSCRIPT_SOURCES: readonly ["captions", "local-asr"];
|
|
28
|
+
export type TranscriptSource = (typeof TRANSCRIPT_SOURCES)[number];
|
|
26
29
|
/** Bumped whenever the cache representation changes, so old files are refetched. */
|
|
27
30
|
export declare const TRANSCRIPT_CACHE_VERSION = 2;
|
|
28
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;GAQG;AAEH,eAAO,MAAM,uBAAuB;IAClC,2CAA2C;;;;;;;;;;;;EAI3C,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;
|
|
1
|
+
{"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;GAQG;AAEH,eAAO,MAAM,uBAAuB;IAClC,2CAA2C;;;;;;;;;;;;EAI3C,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,oCAAqC,CAAC;AACrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;QAxBjC,2CAA2C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8B3C,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAS5D;AA0BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA4BhE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAMpE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAI3E;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,iBAAiB,EAAE,CAOrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAcxF;AAED,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC"}
|
package/dist/utils/transcript.js
CHANGED
|
@@ -15,6 +15,8 @@ export const transcriptSegmentSchema = z.object({
|
|
|
15
15
|
end: z.number(),
|
|
16
16
|
text: z.string(),
|
|
17
17
|
});
|
|
18
|
+
/** Where a transcript's words came from. A machine's guess must never pass as captions. */
|
|
19
|
+
export const TRANSCRIPT_SOURCES = ['captions', 'local-asr'];
|
|
18
20
|
/** Bumped whenever the cache representation changes, so old files are refetched. */
|
|
19
21
|
export const TRANSCRIPT_CACHE_VERSION = 2;
|
|
20
22
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { type HarvestTab } from './harvest-catalog.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a channel has published since its catalogue was made.
|
|
5
|
+
*
|
|
6
|
+
* Looks at the newest few videos of each tab and names the ones the store has never
|
|
7
|
+
* seen. It reads and compares; it does not add, so what is new can be inspected
|
|
8
|
+
* before deciding to catalogue it. A channel is not watched: this runs when asked.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_LOOKBACK = 30;
|
|
11
|
+
export declare const MAX_LOOKBACK = 200;
|
|
12
|
+
export interface CheckedTab {
|
|
13
|
+
tab: HarvestTab;
|
|
14
|
+
listed: number;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface NewUpload {
|
|
18
|
+
videoId: string;
|
|
19
|
+
title: string;
|
|
20
|
+
tab: HarvestTab;
|
|
21
|
+
url: string;
|
|
22
|
+
durationSeconds?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface UploadCheck {
|
|
25
|
+
channelId: string;
|
|
26
|
+
name: string;
|
|
27
|
+
handle: string;
|
|
28
|
+
lookback: number;
|
|
29
|
+
checked: CheckedTab[];
|
|
30
|
+
newVideos: NewUpload[];
|
|
31
|
+
/** When the catalogue was last written, so "nothing new" can be read against its age. */
|
|
32
|
+
catalogHarvestedAt?: string;
|
|
33
|
+
catalogComplete: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare function checkNewUploads(database: DatabaseSync, channel: string, options: {
|
|
36
|
+
lookback: number;
|
|
37
|
+
}): Promise<UploadCheck>;
|
|
38
|
+
//# sourceMappingURL=upload-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-check.d.ts","sourceRoot":"","sources":["../../src/utils/upload-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKhD,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAQ3F;;;;;;GAMG;AAEH,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,YAAY,MAAM,CAAC;AAEhC,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,UAAU,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,UAAU,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAkCD,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC5B,OAAO,CAAC,WAAW,CAAC,CAwDtB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { throwIfAborted } from './context.js';
|
|
3
|
+
import { YouTubeError } from './errors.js';
|
|
4
|
+
import { flatEntrySchema, toVideoListItem } from './flat-listing.js';
|
|
5
|
+
import { HARVEST_TABS, isAbsentTab, listTab } from './harvest-catalog.js';
|
|
6
|
+
import { readReceipt } from './harvest-receipts.js';
|
|
7
|
+
import { queryRows } from './store-rows.js';
|
|
8
|
+
import { catalogCounts } from './video-detail-store.js';
|
|
9
|
+
import { getChannelInfo } from './youtube-channel.js';
|
|
10
|
+
import { watchUrl } from './youtube-url.js';
|
|
11
|
+
import { parseYtDlpJsonLines } from './ytdlp-parse.js';
|
|
12
|
+
/**
|
|
13
|
+
* What a channel has published since its catalogue was made.
|
|
14
|
+
*
|
|
15
|
+
* Looks at the newest few videos of each tab and names the ones the store has never
|
|
16
|
+
* seen. It reads and compares; it does not add, so what is new can be inspected
|
|
17
|
+
* before deciding to catalogue it. A channel is not watched: this runs when asked.
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_LOOKBACK = 30;
|
|
20
|
+
export const MAX_LOOKBACK = 200;
|
|
21
|
+
async function listRecent(channelUrl, tab, lookback) {
|
|
22
|
+
try {
|
|
23
|
+
const stdout = await listTab(channelUrl, tab, lookback, `check_new_uploads:${tab}`);
|
|
24
|
+
return { tab, entries: parseYtDlpJsonLines(stdout, flatEntrySchema).map(toVideoListItem) };
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (isAbsentTab(error))
|
|
28
|
+
return { tab, entries: [] };
|
|
29
|
+
const failure = error instanceof YouTubeError
|
|
30
|
+
? error
|
|
31
|
+
: new YouTubeError('YTDLP_FAILED', String(error), { cause: error });
|
|
32
|
+
return { tab, entries: [], error: failure };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function knownIds(database, ids) {
|
|
36
|
+
if (ids.length === 0)
|
|
37
|
+
return new Set();
|
|
38
|
+
const placeholders = ids.map(() => '?').join(', ');
|
|
39
|
+
return new Set(queryRows(database.prepare(`SELECT video_id FROM video WHERE video_id IN (${placeholders})`), z.object({ video_id: z.string() }), ...ids).map((row) => row.video_id));
|
|
40
|
+
}
|
|
41
|
+
export async function checkNewUploads(database, channel, options) {
|
|
42
|
+
const { lookback } = options;
|
|
43
|
+
const info = await getChannelInfo(channel);
|
|
44
|
+
if (catalogCounts(database, info.channelId).videos === 0) {
|
|
45
|
+
throw new YouTubeError('NOT_FOUND', `${info.name} has not been catalogued yet.`, {
|
|
46
|
+
nextStep: 'Call harvest_channel first: there is nothing to compare new uploads against.',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const listed = [];
|
|
50
|
+
for (const tab of HARVEST_TABS) {
|
|
51
|
+
throwIfAborted();
|
|
52
|
+
listed.push(await listRecent(info.channelUrl, tab, lookback));
|
|
53
|
+
}
|
|
54
|
+
const failed = listed.flatMap((tab) => (tab.error === undefined ? [] : [tab.error]));
|
|
55
|
+
const [firstFailure] = failed;
|
|
56
|
+
if (firstFailure !== undefined && failed.length === listed.length)
|
|
57
|
+
throw firstFailure;
|
|
58
|
+
const known = knownIds(database, [
|
|
59
|
+
...new Set(listed.flatMap((tab) => tab.entries.map((entry) => entry.id))),
|
|
60
|
+
]);
|
|
61
|
+
const seen = new Set();
|
|
62
|
+
const newVideos = [];
|
|
63
|
+
for (const { tab, entries } of listed) {
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
if (known.has(entry.id) || seen.has(entry.id))
|
|
66
|
+
continue;
|
|
67
|
+
seen.add(entry.id);
|
|
68
|
+
newVideos.push({
|
|
69
|
+
videoId: entry.id,
|
|
70
|
+
title: entry.title,
|
|
71
|
+
tab,
|
|
72
|
+
url: watchUrl(entry.id),
|
|
73
|
+
...(entry.duration > 0 ? { durationSeconds: entry.duration } : {}),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const receipt = readReceipt(database, 'channel-catalog', info.channelId);
|
|
78
|
+
return {
|
|
79
|
+
channelId: info.channelId,
|
|
80
|
+
name: info.name,
|
|
81
|
+
handle: info.handle,
|
|
82
|
+
lookback,
|
|
83
|
+
checked: listed.map(({ tab, entries, error }) => ({
|
|
84
|
+
tab,
|
|
85
|
+
listed: entries.length,
|
|
86
|
+
...(error === undefined ? {} : { error: error.message }),
|
|
87
|
+
})),
|
|
88
|
+
newVideos,
|
|
89
|
+
...(receipt === undefined ? {} : { catalogHarvestedAt: receipt.harvestedAt }),
|
|
90
|
+
catalogComplete: receipt?.complete === true,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=upload-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-check.js","sourceRoot":"","sources":["../../src/utils/upload-check.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/validate.d.ts
CHANGED
|
@@ -20,5 +20,7 @@ export declare function resolveOutputDir(outputDir: string | undefined, fallback
|
|
|
20
20
|
export declare function assertLanguageTag(language: string): string;
|
|
21
21
|
/** Accepts `90`, `1:30`, `01:02:03`, `1:30.5` and returns seconds. */
|
|
22
22
|
export declare function parseTimestamp(value: string | number, field: string): number;
|
|
23
|
+
/** `parseTimestamp` for a field the caller may leave out. */
|
|
24
|
+
export declare function parseOptionalTimestamp(value: string | number | undefined, field: string): number | undefined;
|
|
23
25
|
export * from './validate-youtube.js';
|
|
24
26
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBpE;AAkBD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxF;AAKD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB5E;AAED,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBpE;AAkBD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxF;AAKD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB5E;AAED,6DAA6D;AAC7D,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,EAClC,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,SAAS,CAEpB;AAED,cAAc,uBAAuB,CAAC"}
|
package/dist/utils/validate.js
CHANGED
|
@@ -85,5 +85,9 @@ export function parseTimestamp(value, field) {
|
|
|
85
85
|
// The hours group is optional, so it is genuinely absent for "MM:SS" input.
|
|
86
86
|
return Number(match[1] ?? 0) * 3600 + Number(match[2] ?? 0) * 60 + Number(match[3] ?? 0);
|
|
87
87
|
}
|
|
88
|
+
/** `parseTimestamp` for a field the caller may leave out. */
|
|
89
|
+
export function parseOptionalTimestamp(value, field) {
|
|
90
|
+
return value === undefined ? undefined : parseTimestamp(value, field);
|
|
91
|
+
}
|
|
88
92
|
export * from './validate-youtube.js';
|
|
89
93
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { type videoStatsRowSchema } from './video-stats.js';
|
|
4
|
+
/**
|
|
5
|
+
* Keeping what a full read of a video said, on the catalogue row that names it.
|
|
6
|
+
*
|
|
7
|
+
* A flat listing knows a title, a duration and a view count. Reading the video itself
|
|
8
|
+
* adds what the listing cannot: the record, the replay heatmap, and the counts YouTube
|
|
9
|
+
* states, which a comment receipt is measured against. Until now those columns
|
|
10
|
+
* existed and nothing wrote them, so a video was never "detailed".
|
|
11
|
+
*/
|
|
12
|
+
type StatsRow = z.infer<typeof videoStatsRowSchema>;
|
|
13
|
+
/** Writes a read onto the video's catalogue row. A video the catalogue has not seen is left alone. */
|
|
14
|
+
export declare function saveVideoDetail(database: DatabaseSync, row: StatsRow, now: number): void;
|
|
15
|
+
/**
|
|
16
|
+
* What a video's `availability` is set to when it could not be read, by the error it
|
|
17
|
+
* gave. These videos are skipped from then on: left in the queue they would be tried
|
|
18
|
+
* first, fail first, and starve every video behind them on every run.
|
|
19
|
+
*/
|
|
20
|
+
export declare const UNREADABLE_AVAILABILITY: {
|
|
21
|
+
readonly PRIVATE: "private";
|
|
22
|
+
readonly MEMBERS_ONLY: "subscriber_only";
|
|
23
|
+
readonly PREMIUM_ONLY: "premium_only";
|
|
24
|
+
readonly NOT_FOUND: "unavailable";
|
|
25
|
+
readonly AGE_GATED: "needs_auth";
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* For a failure that is not one of those: a live stream not over, a timeout, an error
|
|
29
|
+
* yt-dlp could not explain. It may well pass later, so it is told apart from the above,
|
|
30
|
+
* but it is skipped all the same, or a video that keeps failing would hold the queue.
|
|
31
|
+
*/
|
|
32
|
+
export declare const READ_FAILED_AVAILABILITY = "read_failed";
|
|
33
|
+
export type UnreadableAvailability = (typeof UNREADABLE_AVAILABILITY)[keyof typeof UNREADABLE_AVAILABILITY] | typeof READ_FAILED_AVAILABILITY;
|
|
34
|
+
/** Remembers that this video cannot be read, without pretending it was. */
|
|
35
|
+
export declare function markUnreadable(database: DatabaseSync, videoId: string, availability: UnreadableAvailability): void;
|
|
36
|
+
/** The channel's catalogued videos not yet read, in catalogue order. */
|
|
37
|
+
export declare function pendingVideoIds(database: DatabaseSync, channelId: string, limit: number, options?: {
|
|
38
|
+
includeUnreadable?: boolean;
|
|
39
|
+
}): string[];
|
|
40
|
+
/** How many of the channel's videos are known to be unreadable, and so never queued. */
|
|
41
|
+
export declare function unreadableCount(database: DatabaseSync, channelId: string): number;
|
|
42
|
+
export declare function catalogCounts(database: DatabaseSync, channelId: string): {
|
|
43
|
+
videos: number;
|
|
44
|
+
detailed: number;
|
|
45
|
+
};
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=video-detail-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video-detail-store.d.ts","sourceRoot":"","sources":["../../src/utils/video-detail-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAA0C,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEpG;;;;;;;GAOG;AAEH,KAAK,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAmCpD,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAmBxF;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;;;;;CAM1B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAEtD,MAAM,MAAM,sBAAsB,GAC9B,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,OAAO,uBAAuB,CAAC,GACtE,OAAO,wBAAwB,CAAC;AAQpC,2EAA2E;AAC3E,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,sBAAsB,GACnC,IAAI,CAIN;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5C,MAAM,EAAE,CAgBV;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAUjF;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,MAAM,GAChB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAStC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { queryRow, queryRows } from './store-rows.js';
|
|
3
|
+
import { MAX_DETAIL_JSON_BYTES, stripForStorage } from './video-stats.js';
|
|
4
|
+
/** Parts of a record, bulkiest first, given up before a record is cut down to its identity. */
|
|
5
|
+
const DROPPED_WHEN_TOO_LARGE = ['description', 'chapters', 'tags', 'categories'];
|
|
6
|
+
const UPDATE = `
|
|
7
|
+
UPDATE video SET
|
|
8
|
+
duration_s = COALESCE(?, duration_s),
|
|
9
|
+
upload_date = COALESCE(?, upload_date),
|
|
10
|
+
view_count = COALESCE(?, view_count),
|
|
11
|
+
like_count = COALESCE(?, like_count),
|
|
12
|
+
comment_count = COALESCE(?, comment_count),
|
|
13
|
+
live_status = COALESCE(?, live_status),
|
|
14
|
+
availability = COALESCE(?, availability),
|
|
15
|
+
thumbnail_url = COALESCE(?, thumbnail_url),
|
|
16
|
+
detail_at = ?,
|
|
17
|
+
detail_json = ?,
|
|
18
|
+
heatmap_json = ?
|
|
19
|
+
WHERE video_id = ?`;
|
|
20
|
+
/** The record as JSON that fits the cap, losing the least that is needed to fit. */
|
|
21
|
+
function recordJson(row) {
|
|
22
|
+
const record = stripForStorage({ ...row });
|
|
23
|
+
let json = JSON.stringify(record);
|
|
24
|
+
if (Buffer.byteLength(json) <= MAX_DETAIL_JSON_BYTES)
|
|
25
|
+
return json;
|
|
26
|
+
const trimmed = { ...record, detail_truncated: true };
|
|
27
|
+
for (const key of DROPPED_WHEN_TOO_LARGE) {
|
|
28
|
+
Reflect.deleteProperty(trimmed, key);
|
|
29
|
+
json = JSON.stringify(trimmed);
|
|
30
|
+
if (Buffer.byteLength(json) <= MAX_DETAIL_JSON_BYTES)
|
|
31
|
+
return json;
|
|
32
|
+
}
|
|
33
|
+
return JSON.stringify({ id: row.id, title: row.title ?? null, detail_truncated: true });
|
|
34
|
+
}
|
|
35
|
+
/** Writes a read onto the video's catalogue row. A video the catalogue has not seen is left alone. */
|
|
36
|
+
export function saveVideoDetail(database, row, now) {
|
|
37
|
+
const heatmap = row.heatmap ?? [];
|
|
38
|
+
database
|
|
39
|
+
.prepare(UPDATE)
|
|
40
|
+
.run(row.duration === null || row.duration === undefined ? null : Math.round(row.duration), row.upload_date ?? null, row.view_count ?? null, row.like_count ?? null, row.comment_count ?? null, row.live_status ?? null, row.availability ?? null, row.thumbnail ?? null, now, recordJson(row), heatmap.length === 0 ? null : JSON.stringify(heatmap), row.id);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* What a video's `availability` is set to when it could not be read, by the error it
|
|
44
|
+
* gave. These videos are skipped from then on: left in the queue they would be tried
|
|
45
|
+
* first, fail first, and starve every video behind them on every run.
|
|
46
|
+
*/
|
|
47
|
+
export const UNREADABLE_AVAILABILITY = {
|
|
48
|
+
PRIVATE: 'private',
|
|
49
|
+
MEMBERS_ONLY: 'subscriber_only',
|
|
50
|
+
PREMIUM_ONLY: 'premium_only',
|
|
51
|
+
NOT_FOUND: 'unavailable',
|
|
52
|
+
AGE_GATED: 'needs_auth',
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* For a failure that is not one of those: a live stream not over, a timeout, an error
|
|
56
|
+
* yt-dlp could not explain. It may well pass later, so it is told apart from the above,
|
|
57
|
+
* but it is skipped all the same, or a video that keeps failing would hold the queue.
|
|
58
|
+
*/
|
|
59
|
+
export const READ_FAILED_AVAILABILITY = 'read_failed';
|
|
60
|
+
const UNREADABLE_VALUES = [
|
|
61
|
+
...Object.values(UNREADABLE_AVAILABILITY),
|
|
62
|
+
READ_FAILED_AVAILABILITY,
|
|
63
|
+
];
|
|
64
|
+
const NOT_UNREADABLE = `(availability IS NULL OR availability NOT IN (${UNREADABLE_VALUES.map(() => '?').join(', ')}))`;
|
|
65
|
+
/** Remembers that this video cannot be read, without pretending it was. */
|
|
66
|
+
export function markUnreadable(database, videoId, availability) {
|
|
67
|
+
database
|
|
68
|
+
.prepare('UPDATE video SET availability = ? WHERE video_id = ?')
|
|
69
|
+
.run(availability, videoId);
|
|
70
|
+
}
|
|
71
|
+
/** The channel's catalogued videos not yet read, in catalogue order. */
|
|
72
|
+
export function pendingVideoIds(database, channelId, limit, options = {}) {
|
|
73
|
+
const unreadable = options.includeUnreadable === true ? '' : ` AND ${NOT_UNREADABLE}`;
|
|
74
|
+
const params = options.includeUnreadable === true ? [] : UNREADABLE_VALUES;
|
|
75
|
+
return queryRows(database.prepare(`SELECT video_id FROM video
|
|
76
|
+
WHERE channel_id = ? AND detail_at IS NULL${unreadable}
|
|
77
|
+
ORDER BY catalog_rank ASC NULLS LAST, video_id
|
|
78
|
+
LIMIT ?`), z.object({ video_id: z.string() }), channelId, ...params, limit).map((row) => row.video_id);
|
|
79
|
+
}
|
|
80
|
+
/** How many of the channel's videos are known to be unreadable, and so never queued. */
|
|
81
|
+
export function unreadableCount(database, channelId) {
|
|
82
|
+
const row = queryRow(database.prepare(`SELECT COUNT(*) AS n FROM video WHERE channel_id = ? AND detail_at IS NULL AND NOT ${NOT_UNREADABLE}`), z.object({ n: z.number() }), channelId, ...UNREADABLE_VALUES);
|
|
83
|
+
return row?.n ?? 0;
|
|
84
|
+
}
|
|
85
|
+
export function catalogCounts(database, channelId) {
|
|
86
|
+
const row = queryRow(database.prepare('SELECT COUNT(*) AS videos, COUNT(detail_at) AS detailed FROM video WHERE channel_id = ?'), z.object({ videos: z.number(), detailed: z.number() }), channelId);
|
|
87
|
+
return { videos: row?.videos ?? 0, detailed: row?.detailed ?? 0 };
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=video-detail-store.js.map
|