videobook 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/LICENSE +21 -0
- package/README.md +195 -2
- package/bin/videobook.js +7 -0
- package/dist/acestep/client.js +203 -0
- package/dist/acestep/config.js +62 -0
- package/dist/acestep/errors.js +8 -0
- package/dist/acestep/process.js +175 -0
- package/dist/alive-captions/analyze.js +117 -0
- package/dist/alive-captions/audio.js +179 -0
- package/dist/alive-captions/frames.js +59 -0
- package/dist/alive-captions/model.js +37 -0
- package/dist/alive-captions/schema.js +49 -0
- package/dist/alive-captions/track.js +9 -0
- package/dist/api-key.js +33 -0
- package/dist/app-state.js +56 -0
- package/dist/app.js +257 -0
- package/dist/archive-b2.js +332 -0
- package/dist/archive-store.js +169 -0
- package/dist/artifact-label.js +36 -0
- package/dist/artifact-refs.js +49 -0
- package/dist/asset-tag-extraction.js +169 -0
- package/dist/asset-tags.js +228 -0
- package/dist/asset-usage.js +23 -0
- package/dist/audio-cue.js +71 -0
- package/dist/audio-encoding.js +32 -0
- package/dist/audio-sync-request.js +1 -0
- package/dist/audio-sync.js +223 -0
- package/dist/audio-trim-range.js +31 -0
- package/dist/book-context.js +31 -0
- package/dist/book-manager.js +374 -0
- package/dist/catalog-gc.js +26 -0
- package/dist/chain-executor.js +815 -0
- package/dist/chain-generation.js +115 -0
- package/dist/chain-plan.js +746 -0
- package/dist/chain-step-review.js +60 -0
- package/dist/character-name.js +25 -0
- package/dist/chat-generation-routing.js +73 -0
- package/dist/chat-generation-settings.js +78 -0
- package/dist/chat-models.js +44 -0
- package/dist/chat-prompt-rewrite.js +67 -0
- package/dist/chat-router.js +628 -0
- package/dist/chat-view-actions.js +49 -0
- package/dist/cli/args.js +242 -0
- package/dist/cli/config-command.js +103 -0
- package/dist/cli/doctor-command.js +289 -0
- package/dist/cli/entry.js +2 -0
- package/dist/cli/key-report.js +16 -0
- package/dist/cli/main.js +104 -0
- package/dist/cli/mcp-command.js +88 -0
- package/dist/cli/mcp-relay.js +51 -0
- package/dist/cli/open-browser.js +14 -0
- package/dist/cli/run-command.js +231 -0
- package/dist/cli/serve-command.js +62 -0
- package/dist/cli/setup-command.js +60 -0
- package/dist/cli/stdio-guard.js +8 -0
- package/dist/cold-open-model.js +7 -0
- package/dist/cold-open.js +79 -0
- package/dist/command-reference.js +95 -0
- package/dist/content-store.js +74 -0
- package/dist/cost.js +8 -0
- package/dist/crop-geometry.js +23 -0
- package/dist/dancing-workflow.js +447 -0
- package/dist/data-home.js +44 -0
- package/dist/diagnostics.js +109 -0
- package/dist/dialog-quality.js +34 -0
- package/dist/downloads-dest.js +56 -0
- package/dist/editing-moments.js +194 -0
- package/dist/elevenlabs-audio-extension.js +66 -0
- package/dist/engine.js +54 -0
- package/dist/env-file.js +91 -0
- package/dist/env-secrets.js +148 -0
- package/dist/ffmpeg-binary.js +12 -0
- package/dist/ffmpeg.js +425 -0
- package/dist/ffprobe-binary.js +77 -0
- package/dist/forget-asset.js +216 -0
- package/dist/frame-utils.js +27 -0
- package/dist/generation-credit-error.js +11 -0
- package/dist/generation-input-mentions.js +117 -0
- package/dist/generation-input-policy.js +68 -0
- package/dist/generation-reference-mentions.js +97 -0
- package/dist/goal-characters.js +49 -0
- package/dist/goal-plan-v3.js +273 -0
- package/dist/goal-plan.js +220 -0
- package/dist/goal-planner-prompt.js +28 -0
- package/dist/goal-prompt-budget.js +4 -0
- package/dist/goal-reference-images.js +25 -0
- package/dist/goal-state.js +261 -0
- package/dist/goal-stills.js +153 -0
- package/dist/goal-store.js +144 -0
- package/dist/goal-styles.js +144 -0
- package/dist/goal-v3-runtime.js +157 -0
- package/dist/guides/character_schema_guide.md +70 -0
- package/dist/guides/gpt_image_2_5_prompting_guide.md +21 -0
- package/dist/guides/grok_imagine_prompting_guide.md +72 -0
- package/dist/guides/image_reproduction_guide.md +84 -0
- package/dist/guides/kling_3_0_prompting_guide.md +136 -0
- package/dist/guides/nano_banana_pro_prompting_guide.md +28 -0
- package/dist/guides/seedance_2_prompting_guide.md +172 -0
- package/dist/http-access.js +49 -0
- package/dist/http-byte-range.js +31 -0
- package/dist/hydration.js +56 -0
- package/dist/image-compress.js +77 -0
- package/dist/image-edit-default.js +1 -0
- package/dist/image-edit-models.js +41 -0
- package/dist/image-edit-settings.js +11 -0
- package/dist/image-region-edit.js +32 -0
- package/dist/image-subject-map.js +523 -0
- package/dist/image.js +46 -0
- package/dist/index.js +12 -0
- package/dist/job-deadline.js +60 -0
- package/dist/jobs/_alibaba-upload.js +30 -0
- package/dist/jobs/_audio-chunks.js +31 -0
- package/dist/jobs/_download-into-asset.js +15 -0
- package/dist/jobs/_fal-shared.js +22 -0
- package/dist/jobs/_fal-upload.js +35 -0
- package/dist/jobs/_image-edit-adapter.js +213 -0
- package/dist/jobs/_kie-poll.js +119 -0
- package/dist/jobs/_kie-upload.js +32 -0
- package/dist/jobs/_lease.js +163 -0
- package/dist/jobs/_persist-output.js +19 -0
- package/dist/jobs/_storage-retry.js +21 -0
- package/dist/jobs/_transcribe.js +245 -0
- package/dist/jobs/_translate-transcript.js +270 -0
- package/dist/jobs/analyze-alive-captions.js +10 -0
- package/dist/jobs/analyze-editing-moments.js +104 -0
- package/dist/jobs/analyze-jokes.js +143 -0
- package/dist/jobs/analyze-keyword-placement.js +155 -0
- package/dist/jobs/analyze-music.js +14 -0
- package/dist/jobs/analyze-video.js +282 -0
- package/dist/jobs/apply-cuts.js +83 -0
- package/dist/jobs/apply-sfx.js +107 -0
- package/dist/jobs/archive-clip.js +458 -0
- package/dist/jobs/assemble-goal.js +98 -0
- package/dist/jobs/audio-boost.js +71 -0
- package/dist/jobs/audio-mix.js +161 -0
- package/dist/jobs/backfill-asset-tags.js +144 -0
- package/dist/jobs/burn-watermark.js +316 -0
- package/dist/jobs/change-video-speed.js +176 -0
- package/dist/jobs/clean-video-audio.js +207 -0
- package/dist/jobs/cold-open.js +166 -0
- package/dist/jobs/combine-goal.js +108 -0
- package/dist/jobs/complete-provider-task.js +185 -0
- package/dist/jobs/copy-library-asset.js +33 -0
- package/dist/jobs/cost-estimate-assessment.js +113 -0
- package/dist/jobs/crop-image.js +47 -0
- package/dist/jobs/crop-video.js +71 -0
- package/dist/jobs/describe-image.js +181 -0
- package/dist/jobs/detect-scenes.js +33 -0
- package/dist/jobs/doctor-fix.js +100 -0
- package/dist/jobs/download-video.js +427 -0
- package/dist/jobs/enqueue-search-index.js +24 -0
- package/dist/jobs/even-split.js +122 -0
- package/dist/jobs/export-sequence.js +365 -0
- package/dist/jobs/extend-audio.js +229 -0
- package/dist/jobs/extract-audio.js +72 -0
- package/dist/jobs/extract-frame.js +58 -0
- package/dist/jobs/extract-notebook-audio.js +82 -0
- package/dist/jobs/extract-notebook-frame.js +93 -0
- package/dist/jobs/extract-video-clip.js +8 -0
- package/dist/jobs/extract-video-poster.js +55 -0
- package/dist/jobs/extract-waveform.js +25 -0
- package/dist/jobs/finish-goal.js +255 -0
- package/dist/jobs/forget-asset.js +11 -0
- package/dist/jobs/generate-acestep-cover.js +219 -0
- package/dist/jobs/generate-media.js +70 -0
- package/dist/jobs/image-subjects.js +1059 -0
- package/dist/jobs/index.js +18 -0
- package/dist/jobs/inject-first-frame.js +175 -0
- package/dist/jobs/isolate-vocals.js +69 -0
- package/dist/jobs/kie-paygate.js +177 -0
- package/dist/jobs/label-music-sections.js +5 -0
- package/dist/jobs/osg-placement.js +135 -0
- package/dist/jobs/pad-video.js +72 -0
- package/dist/jobs/plan-goal.js +97 -0
- package/dist/jobs/post-record.js +21 -0
- package/dist/jobs/post-to-x.js +21 -0
- package/dist/jobs/prepare-search-reference.js +190 -0
- package/dist/jobs/prepare-temporal-search.js +16 -0
- package/dist/jobs/process-audio.js +67 -0
- package/dist/jobs/process-image.js +58 -0
- package/dist/jobs/process-upload.js +166 -0
- package/dist/jobs/process-video.js +438 -0
- package/dist/jobs/register-all.js +161 -0
- package/dist/jobs/relayout-notebook.js +78 -0
- package/dist/jobs/remove-sound.js +299 -0
- package/dist/jobs/render-project.js +380 -0
- package/dist/jobs/render-qr-outro.js +138 -0
- package/dist/jobs/render-timeline.js +283 -0
- package/dist/jobs/repair-search-indexes.js +42 -0
- package/dist/jobs/replace-video-audio.js +64 -0
- package/dist/jobs/restore-archive-clip.js +53 -0
- package/dist/jobs/reverse-video.js +53 -0
- package/dist/jobs/rewrite-script.js +173 -0
- package/dist/jobs/run-notebook.js +3335 -0
- package/dist/jobs/semantic-index.js +797 -0
- package/dist/jobs/smooth-scene-concat.js +257 -0
- package/dist/jobs/splice-video.js +280 -0
- package/dist/jobs/split-video.js +127 -0
- package/dist/jobs/suggest-cuts.js +149 -0
- package/dist/jobs/suggest-sfx.js +135 -0
- package/dist/jobs/sync-video-to-audio.js +329 -0
- package/dist/jobs/tag-asset.js +266 -0
- package/dist/jobs/task-failure.js +16 -0
- package/dist/jobs/timewarp-video.js +152 -0
- package/dist/jobs/transcribe-video-audio.js +117 -0
- package/dist/jobs/transcribe.js +35 -0
- package/dist/jobs/translate-transcript.js +55 -0
- package/dist/jobs/trim-audio.js +133 -0
- package/dist/jobs/trim-video.js +291 -0
- package/dist/jobs/xai-paygate.js +26 -0
- package/dist/keyword-placement-cache.js +74 -0
- package/dist/lazy-render.js +142 -0
- package/dist/library-browse.js +78 -0
- package/dist/lightning-defaults.js +206 -0
- package/dist/load-env.js +12 -0
- package/dist/local-search-models.js +206 -0
- package/dist/local-upload.js +318 -0
- package/dist/logger.js +69 -0
- package/dist/media/adapters/alibaba.js +20 -0
- package/dist/media/adapters/elevenlabs.js +58 -0
- package/dist/media/adapters/fal.js +45 -0
- package/dist/media/adapters/index.js +26 -0
- package/dist/media/adapters/kie.js +120 -0
- package/dist/media/adapters/pending.js +21 -0
- package/dist/media/adapters/types.js +5 -0
- package/dist/media/adapters/xai.js +18 -0
- package/dist/media/catalog.js +236 -0
- package/dist/media/complete.js +191 -0
- package/dist/media/cost.js +45 -0
- package/dist/media/descriptor.js +157 -0
- package/dist/media/endpoints.js +11 -0
- package/dist/media/frame-options.js +18 -0
- package/dist/media/insert-video-timing.js +17 -0
- package/dist/media/json-schema.js +75 -0
- package/dist/media/legacy-task-types.js +129 -0
- package/dist/media/listing.js +24 -0
- package/dist/media/model-id.js +14 -0
- package/dist/media/preview.js +86 -0
- package/dist/media/prompt-dialects.js +65 -0
- package/dist/media/ref-fields.js +106 -0
- package/dist/media/refs.js +131 -0
- package/dist/media/request.js +188 -0
- package/dist/media/types.js +6 -0
- package/dist/media/wire.js +161 -0
- package/dist/media-library.js +535 -0
- package/dist/media-output-path.js +33 -0
- package/dist/multyculty-workflow.js +757 -0
- package/dist/notebook-action-catalog.js +608 -0
- package/dist/notebook-cell-outputs.js +726 -0
- package/dist/notebook-credit-retry.js +45 -0
- package/dist/notebook-fixtures.js +8 -0
- package/dist/notebook-generation-contract.js +77 -0
- package/dist/notebook-generation-controls.js +145 -0
- package/dist/notebook-goal-layout.js +40 -0
- package/dist/notebook-graph.js +37 -0
- package/dist/notebook-image-edit.js +84 -0
- package/dist/notebook-initial-generation-prompt.js +222 -0
- package/dist/notebook-live-analysis.js +941 -0
- package/dist/notebook-media-ops.js +579 -0
- package/dist/notebook-mutations.js +20 -0
- package/dist/notebook-placement.js +41 -0
- package/dist/notebook-provider-failure.js +87 -0
- package/dist/notebook-published-post.js +26 -0
- package/dist/notebook-reference-resolver.js +227 -0
- package/dist/notebook-relayout.js +270 -0
- package/dist/notebook-run-plan.js +519 -0
- package/dist/notebook-shots.js +162 -0
- package/dist/notebook-workflow.js +856 -0
- package/dist/one-password.js +200 -0
- package/dist/openai-intelligence.js +99 -0
- package/dist/original-media-file.js +12 -0
- package/dist/osg-assets.js +36 -0
- package/dist/osg-placement-cache.js +64 -0
- package/dist/osg-settings.js +27 -0
- package/dist/paid-tools.js +22 -0
- package/dist/platform-guidance.js +26 -0
- package/dist/posts/dropbox-auth.js +91 -0
- package/dist/posts/dropbox-upload.js +132 -0
- package/dist/posts/icloud-drive.js +134 -0
- package/dist/posts/icloud-status.js +64 -0
- package/dist/posts/post-contract.js +2 -0
- package/dist/posts/post-copy-format.js +43 -0
- package/dist/posts/post-copy.js +193 -0
- package/dist/posts/post-folder.js +18 -0
- package/dist/posts/post-metrics.js +119 -0
- package/dist/posts/post-store.js +340 -0
- package/dist/posts/x-post-target.js +43 -0
- package/dist/preview-payload.js +90 -0
- package/dist/prompt-surfaces.js +22 -0
- package/dist/provider-prompt-transform.js +77 -0
- package/dist/provider-status-link.js +21 -0
- package/dist/provider-task-record.js +78 -0
- package/dist/provider-task-status.js +47 -0
- package/dist/provider-usage.js +294 -0
- package/dist/queue.js +810 -0
- package/dist/reference-video-duration.js +17 -0
- package/dist/remotion/BlurFillVideo.js +51 -0
- package/dist/remotion/KeywordGraphicsOverlay.js +68 -0
- package/dist/remotion/OsgOverlay.js +30 -0
- package/dist/remotion/QrOutroComposition.js +47 -0
- package/dist/remotion/RenderComposition.js +11 -0
- package/dist/remotion/browser.js +59 -0
- package/dist/remotion/constants.js +35 -0
- package/dist/remotion/index.js +66 -0
- package/dist/remotion/keyword-graphics.js +151 -0
- package/dist/remotion/keyword-placement.js +182 -0
- package/dist/remotion/osg-spec.js +198 -0
- package/dist/remotion/public/qr-outro-impact.wav +0 -0
- package/dist/remotion/qr-outro-audio.js +1 -0
- package/dist/remotion/qr-outro-spec.js +211 -0
- package/dist/remotion/shared-bundle.js +37 -0
- package/dist/remotion/subtitles/AliveCaptions.js +83 -0
- package/dist/remotion/subtitles/Highlight.js +58 -0
- package/dist/remotion/subtitles/Impact.js +67 -0
- package/dist/remotion/subtitles/SubtitleOverlay.js +9 -0
- package/dist/remotion/subtitles/alive-layout.js +321 -0
- package/dist/remotion/subtitles/alive-types.js +17 -0
- package/dist/remotion/subtitles/chunker.js +68 -0
- package/dist/remotion/subtitles/segments.js +42 -0
- package/dist/remotion/subtitles/styles.js +4 -0
- package/dist/remotion/subtitles/types.js +1 -0
- package/dist/remotion/util.js +18 -0
- package/dist/remotion-cancellation.js +15 -0
- package/dist/rename-helpers.js +204 -0
- package/dist/rhythm/analyze.js +128 -0
- package/dist/rhythm/contract.js +14 -0
- package/dist/rhythm/draft-model.js +19 -0
- package/dist/rhythm/energy.js +133 -0
- package/dist/rhythm/fft.js +44 -0
- package/dist/rhythm/model.js +71 -0
- package/dist/rhythm/music-analysis.js +124 -0
- package/dist/rhythm/music-draft.js +261 -0
- package/dist/rhythm/onset.js +101 -0
- package/dist/rhythm/run-worker.js +51 -0
- package/dist/rhythm/score.js +47 -0
- package/dist/rhythm/section-labels.js +168 -0
- package/dist/rhythm/sequence-rhythm.js +67 -0
- package/dist/rhythm/synthesize.js +103 -0
- package/dist/rhythm/timing.js +98 -0
- package/dist/rhythm/track.js +320 -0
- package/dist/rhythm/visual-fit.js +4 -0
- package/dist/rhythm/worker.js +25 -0
- package/dist/scene-detect.js +200 -0
- package/dist/scene-transition.js +12 -0
- package/dist/scheduled-posts.js +200 -0
- package/dist/search-index-coverage.js +13 -0
- package/dist/search-index-media.js +71 -0
- package/dist/search-reference-store.js +60 -0
- package/dist/search-scoring.js +17 -0
- package/dist/serve.js +125 -0
- package/dist/server-lock.js +143 -0
- package/dist/server.js +42 -0
- package/dist/srt.js +16 -0
- package/dist/tag-backfill-state.js +121 -0
- package/dist/tag-settings.js +30 -0
- package/dist/tag-vocabulary.js +237 -0
- package/dist/test-queue-cleanup.js +1 -0
- package/dist/time-parse.js +50 -0
- package/dist/timeline-helpers.js +554 -0
- package/dist/timewarp.js +87 -0
- package/dist/tools/_image-inputs.js +9 -0
- package/dist/tools/_media-refs.js +84 -0
- package/dist/tools/_shared.js +59 -0
- package/dist/tools/_suggest-shared.js +279 -0
- package/dist/tools/add-timeline-audio.js +73 -0
- package/dist/tools/alive-captions.js +157 -0
- package/dist/tools/analyze-jokes.js +56 -0
- package/dist/tools/analyze-video.js +66 -0
- package/dist/tools/animate-keywords.js +217 -0
- package/dist/tools/api-status.js +42 -0
- package/dist/tools/application-commands.js +34 -0
- package/dist/tools/apply-cuts.js +112 -0
- package/dist/tools/apply-sfx.js +152 -0
- package/dist/tools/apply-watermark.js +670 -0
- package/dist/tools/archive-clip.js +74 -0
- package/dist/tools/asset-history.js +61 -0
- package/dist/tools/asset-manifest.js +24 -0
- package/dist/tools/asset-tags.js +151 -0
- package/dist/tools/assign-slot.js +97 -0
- package/dist/tools/audio-boost.js +107 -0
- package/dist/tools/audio-mix.js +121 -0
- package/dist/tools/book-usage.js +16 -0
- package/dist/tools/chain.js +136 -0
- package/dist/tools/change-video-speed.js +105 -0
- package/dist/tools/chat-history.js +5 -0
- package/dist/tools/chat.js +848 -0
- package/dist/tools/clean-video-audio.js +97 -0
- package/dist/tools/clear-failed-tasks.js +66 -0
- package/dist/tools/cold-open.js +114 -0
- package/dist/tools/command-plan.js +1680 -0
- package/dist/tools/commands.js +1666 -0
- package/dist/tools/concat-images.js +236 -0
- package/dist/tools/connect-service.js +55 -0
- package/dist/tools/copy-file-to-clipboard.js +58 -0
- package/dist/tools/create-character.js +114 -0
- package/dist/tools/create-qart.js +253 -0
- package/dist/tools/create-qr-outro.js +149 -0
- package/dist/tools/create-qrbtf.js +215 -0
- package/dist/tools/create-watermark.js +97 -0
- package/dist/tools/crop-asset.js +18 -0
- package/dist/tools/crop-image.js +120 -0
- package/dist/tools/crop-video.js +97 -0
- package/dist/tools/delete-asset.js +104 -0
- package/dist/tools/describe-image.js +69 -0
- package/dist/tools/detect-scenes.js +44 -0
- package/dist/tools/doctor.js +126 -0
- package/dist/tools/download-video.js +114 -0
- package/dist/tools/duplicate-asset.js +184 -0
- package/dist/tools/edit-timeline.js +59 -0
- package/dist/tools/editing-moments.js +105 -0
- package/dist/tools/estimate-cost.js +171 -0
- package/dist/tools/even-split.js +295 -0
- package/dist/tools/export-asset-file.js +22 -0
- package/dist/tools/export-asset.js +140 -0
- package/dist/tools/export-sequence.js +250 -0
- package/dist/tools/export-to-downloads.js +54 -0
- package/dist/tools/export-transcript-srt.js +79 -0
- package/dist/tools/extend-audio.js +100 -0
- package/dist/tools/extract-audio.js +174 -0
- package/dist/tools/extract-frame.js +108 -0
- package/dist/tools/extract-notebook-audio.js +173 -0
- package/dist/tools/extract-notebook-frame.js +160 -0
- package/dist/tools/extract-video-clip.js +101 -0
- package/dist/tools/generate-media.js +157 -0
- package/dist/tools/generation-payload.js +48 -0
- package/dist/tools/get-timeline.js +12 -0
- package/dist/tools/get-watermark-config.js +38 -0
- package/dist/tools/goal.js +644 -0
- package/dist/tools/image-subjects.js +711 -0
- package/dist/tools/index.js +323 -0
- package/dist/tools/inject-first-frame.js +154 -0
- package/dist/tools/invert-image.js +70 -0
- package/dist/tools/isolate-vocals.js +66 -0
- package/dist/tools/list-assets.js +98 -0
- package/dist/tools/list-cell-generations.js +225 -0
- package/dist/tools/list-elevenlabs-voices.js +163 -0
- package/dist/tools/log-wrapper.js +29 -0
- package/dist/tools/make-cover-song.js +95 -0
- package/dist/tools/mark-asset-seen.js +23 -0
- package/dist/tools/media-library.js +245 -0
- package/dist/tools/move-timeline-audio.js +35 -0
- package/dist/tools/music-analysis.js +60 -0
- package/dist/tools/music-draft.js +29 -0
- package/dist/tools/pad-video.js +87 -0
- package/dist/tools/post-record.js +83 -0
- package/dist/tools/post.js +168 -0
- package/dist/tools/prompt-history.js +164 -0
- package/dist/tools/provider-key-status.js +248 -0
- package/dist/tools/qrbtf-render.js +849 -0
- package/dist/tools/read-asset-metadata.js +26 -0
- package/dist/tools/read-file-at-commit.js +29 -0
- package/dist/tools/read-transcript.js +41 -0
- package/dist/tools/reconcile-project-work.js +1452 -0
- package/dist/tools/recover-asset.js +28 -0
- package/dist/tools/remove-sound.js +72 -0
- package/dist/tools/remove-timeline-audio.js +34 -0
- package/dist/tools/remove-timeline-slot.js +40 -0
- package/dist/tools/rename-all.js +434 -0
- package/dist/tools/rename-asset.js +34 -0
- package/dist/tools/render-settings.js +47 -0
- package/dist/tools/render-timeline.js +120 -0
- package/dist/tools/render.js +384 -0
- package/dist/tools/reorder-character-images.js +45 -0
- package/dist/tools/replace-video-audio.js +133 -0
- package/dist/tools/restore-archive-clips.js +209 -0
- package/dist/tools/restore-asset-version.js +37 -0
- package/dist/tools/retry-generation.js +54 -0
- package/dist/tools/reverse-video.js +74 -0
- package/dist/tools/rewrite-prompt.js +388 -0
- package/dist/tools/rewrite-script.js +67 -0
- package/dist/tools/schema-from-apicity.js +66 -0
- package/dist/tools/search-archive.js +150 -0
- package/dist/tools/semantic-search.js +1214 -0
- package/dist/tools/sequence-rhythm.js +43 -0
- package/dist/tools/set-character-metadata.js +84 -0
- package/dist/tools/set-env-secret.js +40 -0
- package/dist/tools/set-osg.js +143 -0
- package/dist/tools/show-folder.js +37 -0
- package/dist/tools/smooth-scene-concat.js +122 -0
- package/dist/tools/splice-video.js +149 -0
- package/dist/tools/split-video.js +202 -0
- package/dist/tools/suggest-cuts.js +45 -0
- package/dist/tools/suggest-sfx.js +43 -0
- package/dist/tools/sync-video-to-audio.js +115 -0
- package/dist/tools/tag-backfill.js +177 -0
- package/dist/tools/timewarp-video.js +85 -0
- package/dist/tools/tool-def.js +1 -0
- package/dist/tools/tool-json-schema.js +116 -0
- package/dist/tools/transcribe.js +90 -0
- package/dist/tools/translate-subtitles.js +59 -0
- package/dist/tools/trim-audio.js +139 -0
- package/dist/tools/trim-video.js +168 -0
- package/dist/tools/update-script.js +25 -0
- package/dist/tools/update-timeline-audio.js +40 -0
- package/dist/tools/upload-file.js +41 -0
- package/dist/tools/verify-x-mentions.js +141 -0
- package/dist/tools/video-editing-command-contract.js +291 -0
- package/dist/tools/video-source-reference.js +30 -0
- package/dist/tools/video-time-input.js +18 -0
- package/dist/tools/videobook-domain.js +2021 -0
- package/dist/tools/wait-for-asset-ready.js +143 -0
- package/dist/tools/workspace-actions.js +54 -0
- package/dist/transcript-projection.js +202 -0
- package/dist/transcript-srt.js +33 -0
- package/dist/upload.js +76 -0
- package/dist/usage-providers.js +25 -0
- package/dist/video-analysis-projection.js +46 -0
- package/dist/video-poster.js +33 -0
- package/dist/video-proxy.js +99 -0
- package/dist/vision-regions.js +111 -0
- package/dist/voice-actions.js +90 -0
- package/dist/voice-audio.js +55 -0
- package/dist/voice-config.js +122 -0
- package/dist/voice-continuation.js +54 -0
- package/dist/voice-contract.js +1 -0
- package/dist/voice-http.js +145 -0
- package/dist/voice-reply-progress.js +55 -0
- package/dist/voice-session.js +992 -0
- package/dist/watermark-badge.js +259 -0
- package/dist/watermark-config.js +111 -0
- package/dist/watermark-handle-position.js +55 -0
- package/dist/watermark-platform.js +15 -0
- package/dist/watermark-timing.js +16 -0
- package/dist/workspace-action-catalog.js +315 -0
- package/dist/workspace-action-contract.js +21 -0
- package/dist/workspace-action-groups.js +98 -0
- package/dist/workspace-action-surfaces.js +7 -0
- package/dist/x/account.js +88 -0
- package/dist/x/authenticated-handle.js +30 -0
- package/dist/x/oauth-flow.js +191 -0
- package/dist/x/post-contract.js +1 -0
- package/dist/x/post-metadata.js +44 -0
- package/dist/x/post-to-x.js +456 -0
- package/dist/x/published-post-cell.js +90 -0
- package/dist/x/x-tokens.js +69 -0
- package/dist/ytdlp-binary.js +65 -0
- package/dist/zod-slots.js +334 -0
- package/package.json +84 -4
- package/ui/assets/alive-captions-BWb5nLKj.css +1 -0
- package/ui/assets/alive-captions-DPEr1nKM.js +1 -0
- package/ui/assets/confirm-bodies-D8ouHXKy.js +1 -0
- package/ui/assets/confirm-bodies-DrMhaXC6.css +1 -0
- package/ui/assets/fullscreen-B7nw4YbE.js +1 -0
- package/ui/assets/goal-ui-DK-xTCK0.js +2 -0
- package/ui/assets/goal-ui-DXdUM2KF.css +1 -0
- package/ui/assets/index-DzPAnCUj.css +1 -0
- package/ui/assets/index-kS1905s5.js +37 -0
- package/ui/assets/inspector-MlzQbTVo.js +1 -0
- package/ui/assets/jobs-ui-CoinOWx0.js +1 -0
- package/ui/assets/music-video-Cbe80kmQ.js +1 -0
- package/ui/assets/music-video-DPaiKKEq.css +1 -0
- package/ui/assets/ui-Oirr9VOf.css +1 -0
- package/ui/assets/ui-xo_Y1yQg.js +2 -0
- package/ui/assets/vendor-D2rfiZ5j.css +1 -0
- package/ui/assets/vendor-DfTCWgKm.js +19 -0
- package/ui/assets/vendor-flow-BXbeWxW7.js +7 -0
- package/ui/assets/vendor-flow-BnuhLJ6X.css +1 -0
- package/ui/assets/vendor-icons-CGqhCIXV.js +1 -0
- package/ui/assets/vendor-mcp-BTlEJcHV.js +67 -0
- package/ui/assets/vendor-react-Dj7D1fD4.js +9 -0
- package/ui/assets/vendor-remotion-CH1HXrlc.js +95 -0
- package/ui/assets/videobook-Qlp9HQFu.js +20 -0
- package/ui/favicon.svg +8 -0
- package/ui/index.html +126 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `videobook` npm package are documented here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and the package uses [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-10-19
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `videobook config` lists where every provider key comes from, with secret
|
|
14
|
+
values masked; `config get`, `config set` and `config unset` edit the
|
|
15
|
+
data-home `.env` atomically.
|
|
16
|
+
- 1Password support: `op://` references in the environment or `.env` resolve
|
|
17
|
+
through the 1Password CLI when a server starts, and
|
|
18
|
+
`videobook setup 1password --op-vault <vault>` reads every key from a vault
|
|
19
|
+
whose items are named after the keys. `videobook doctor` reports the setup
|
|
20
|
+
and which keys 1Password supplied.
|
|
21
|
+
- `VIDEOBOOK_YTDLP_PATH` selects the yt-dlp binary.
|
|
22
|
+
- `list_jobs` accepts `job_keys`, the `job_id` strings other tools return.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- ffprobe now comes from `@ffprobe-installer/ffprobe`, which installs one
|
|
27
|
+
native build for the current platform instead of `ffprobe-static`'s builds
|
|
28
|
+
for every platform. Apple Silicon and Linux arm64 get a bundled ffprobe, and
|
|
29
|
+
the install is about 300 MB smaller. When npm skips the package's chmod
|
|
30
|
+
script, videobook marks the binary executable itself.
|
|
31
|
+
- The npm page no longer links to the private source repository, which
|
|
32
|
+
anonymous visitors cannot open; its homepage is the npm package page.
|
|
33
|
+
- The README states that Windows is not supported yet, and why, instead of
|
|
34
|
+
calling it untested.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- Downloading videos from URLs works when npm blocked the yt-dlp download:
|
|
39
|
+
videobook falls back to `yt-dlp` on `PATH`, passes yt-dlp the resolved
|
|
40
|
+
ffmpeg so format merges work, and fails with install instructions when no
|
|
41
|
+
yt-dlp exists. `videobook doctor` shows which yt-dlp is used.
|
|
42
|
+
- `videobook run` waits for queued jobs on an already running server too,
|
|
43
|
+
instead of returning while the job runs, and reports how the job ended.
|
|
44
|
+
|
|
45
|
+
## [0.1.0] - 2026-10-19
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- `videobook` command-line interface: `serve` runs the MCP server with the
|
|
50
|
+
bundled web UI (or `--headless` for MCP and API only), `mcp` serves MCP over
|
|
51
|
+
stdio for agent hosts, `run` and `tools` call MCP tools from the shell,
|
|
52
|
+
`gc-books` reclaims catalog storage, and `doctor` checks the local
|
|
53
|
+
environment.
|
|
54
|
+
- Installed data defaults to `~/.videobook`, overridable with `VIDEOBOOK_HOME`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Justin Tanner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,196 @@
|
|
|
1
|
-
#
|
|
1
|
+
# videobook
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Videobook is a local-first notebook studio for generative media: images,
|
|
4
|
+
videos, audio, prompts, characters and scenes live as cells in an executable
|
|
5
|
+
graph, and every change is recorded as a revision. This package installs one
|
|
6
|
+
`videobook` command that runs the Videobook MCP server three ways:
|
|
7
|
+
|
|
8
|
+
- with the web UI at `http://127.0.0.1:3001/`
|
|
9
|
+
- headless, serving MCP and the HTTP API only
|
|
10
|
+
- over stdio, for agent hosts such as Claude Code
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- Node.js 22 or newer.
|
|
15
|
+
- macOS (Apple Silicon or Intel) or Linux (x64 or arm64). Windows is not
|
|
16
|
+
supported yet; see the platform notes.
|
|
17
|
+
- About 800 MB of disk. Installing downloads the ffmpeg and yt-dlp binaries
|
|
18
|
+
from GitHub, and the first video render downloads Chrome Headless Shell
|
|
19
|
+
(about 150 MB) into `~/.cache/videobook/remotion`.
|
|
20
|
+
- Native ffmpeg, ffprobe and yt-dlp builds come with the package. Every
|
|
21
|
+
platform falls back to `ffmpeg`, `ffprobe` and `yt-dlp` on `PATH` when a
|
|
22
|
+
bundled binary is missing.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g videobook
|
|
28
|
+
videobook doctor
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
npm 12 and newer skip dependency install scripts unless you approve them.
|
|
32
|
+
Approve the six that videobook needs, either per install or once for your
|
|
33
|
+
user:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install -g videobook --allow-scripts=ffmpeg-static,ytdlp-nodejs,@dolthub/doltlite,usearch,onnxruntime-node,esbuild
|
|
37
|
+
npm config set allow-scripts=ffmpeg-static,ytdlp-nodejs,@dolthub/doltlite,usearch,onnxruntime-node,esbuild --location=user
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- `ffmpeg-static` downloads ffmpeg, which every media operation needs.
|
|
41
|
+
- `ytdlp-nodejs` downloads yt-dlp, which downloading videos from URLs needs.
|
|
42
|
+
Without it, videobook uses `yt-dlp` on `PATH` or `VIDEOBOOK_YTDLP_PATH`.
|
|
43
|
+
- `@dolthub/doltlite`, `usearch` and `onnxruntime-node` use prebuilt native
|
|
44
|
+
binaries and only compile or fetch extras on unusual platforms.
|
|
45
|
+
- `esbuild` checks its platform binary for the Remotion renderer.
|
|
46
|
+
|
|
47
|
+
npm also reports the install script of `@ffprobe-installer/<platform>`, for
|
|
48
|
+
example `@ffprobe-installer/darwin-arm64`. It only marks ffprobe executable,
|
|
49
|
+
which videobook does itself when it starts, so it can stay unapproved. With
|
|
50
|
+
`--strict-allow-scripts`, approve it too.
|
|
51
|
+
|
|
52
|
+
`videobook doctor` reports anything missing and prints the fix.
|
|
53
|
+
|
|
54
|
+
## Run
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
videobook # same as videobook serve
|
|
58
|
+
videobook serve --open # serve MCP and the web UI, open a browser
|
|
59
|
+
videobook serve --headless # MCP and HTTP API only
|
|
60
|
+
videobook mcp # MCP over stdio for agent hosts
|
|
61
|
+
videobook run list_books # call one MCP tool and print its result
|
|
62
|
+
videobook run create_book name=demo
|
|
63
|
+
videobook tools # list tools and their parameters
|
|
64
|
+
videobook gc-books # reclaim catalog storage in every book
|
|
65
|
+
videobook doctor # check Node, binaries, native modules and keys
|
|
66
|
+
videobook config # show where each provider key comes from
|
|
67
|
+
videobook config set FAL_API_KEY op://Private/FAL_API_KEY/password
|
|
68
|
+
videobook setup 1password --op-vault Private
|
|
69
|
+
videobook --version
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Every command accepts `--port <n>` (default 3001), `--library <dir>`,
|
|
73
|
+
`--home <dir>` and `--log-level <silent|error|warn|info|debug>`. Tool
|
|
74
|
+
arguments are `key=value`; values that parse as JSON are passed as JSON. When
|
|
75
|
+
a tool queues a job, `run` waits for it to finish, up to `--timeout <s>`
|
|
76
|
+
(default 600), and exits 1 if the job fails. `--no-wait` returns at once,
|
|
77
|
+
except on a server that `run` started for itself, which stops when `run`
|
|
78
|
+
exits. Exit codes are 0 for success, 1 for a failure and 2 for a usage error.
|
|
79
|
+
|
|
80
|
+
## Agent hosts
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
claude mcp add videobook -- videobook mcp
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Other hosts take the same command, for example
|
|
87
|
+
`{ "command": "videobook", "args": ["mcp"] }`. stdio accepts clients that
|
|
88
|
+
start with the 2025-era `initialize` and clients that use MCP 2026-07-28.
|
|
89
|
+
While `videobook serve` runs, HTTP clients can connect to
|
|
90
|
+
`http://127.0.0.1:3001/mcp`, which speaks MCP 2026-07-28 only.
|
|
91
|
+
|
|
92
|
+
## One server per library
|
|
93
|
+
|
|
94
|
+
A library is owned by one videobook process at a time, recorded in
|
|
95
|
+
`<library>/.videobook-server.json`. A second `videobook serve` for the same
|
|
96
|
+
library exits and names the running URL. `videobook mcp` and `videobook run`
|
|
97
|
+
relay to the running server when there is one; otherwise they start one in
|
|
98
|
+
their own process, which `videobook mcp` keeps serving HTTP and the web UI
|
|
99
|
+
for as long as the agent host keeps it open. `videobook gc-books` refuses to
|
|
100
|
+
run while a server owns the library.
|
|
101
|
+
|
|
102
|
+
## Data and configuration
|
|
103
|
+
|
|
104
|
+
Installed data lives in `~/.videobook`:
|
|
105
|
+
|
|
106
|
+
- `books/`, the library of books
|
|
107
|
+
- `app-state.json`, connected X and Dropbox accounts
|
|
108
|
+
- `.env`, provider keys, also editable from Settings in the web UI
|
|
109
|
+
|
|
110
|
+
`VIDEOBOOK_HOME` or `--home` moves all three. `VIDEOBOOK_LIBRARY_DIR`,
|
|
111
|
+
`VIDEOBOOK_APP_STATE_PATH` and `VIDEOBOOK_ENV_PATH` move one each; `--home`
|
|
112
|
+
overrides any of them inherited from your shell. Set `VIDEOBOOK_HOME` and
|
|
113
|
+
`VIDEOBOOK_ENV_PATH` in the environment, not in `.env`, because they decide
|
|
114
|
+
which `.env` is read.
|
|
115
|
+
|
|
116
|
+
Caches live in `~/.cache/videobook`. Other settings: `PORT`,
|
|
117
|
+
`VIDEOBOOK_FFMPEG_PATH`, `VIDEOBOOK_FFPROBE_PATH`, `VIDEOBOOK_YTDLP_PATH`,
|
|
118
|
+
`VIDEOBOOK_REMOTION_CACHE_DIR`, `VIDEOBOOK_MODEL_CACHE_DIR`,
|
|
119
|
+
`VIDEOBOOK_DOWNLOADS_DIR` and `VIDEOBOOK_LOG_LEVEL`.
|
|
120
|
+
|
|
121
|
+
## Provider keys
|
|
122
|
+
|
|
123
|
+
The keys are `OPENAI_API_KEY`, `KIE_API_KEY`, `XAI_API_KEY`, `FAL_API_KEY`,
|
|
124
|
+
`DASHSCOPE_API_KEY`, `ELEVENLABS_API_KEY`, `KIMI_CODING_API_KEY`,
|
|
125
|
+
`X_CLIENT_ID` and `X_CLIENT_SECRET`, `DROPBOX_CLIENT_ID` and
|
|
126
|
+
`DROPBOX_CLIENT_SECRET`, and the `B2_*` storage settings. The server starts
|
|
127
|
+
without any of them; tools that need one report which.
|
|
128
|
+
|
|
129
|
+
A key can come from four places. The first one that has it wins:
|
|
130
|
+
|
|
131
|
+
1. The environment of the videobook process.
|
|
132
|
+
2. A value in `.env`, set with `videobook config set <KEY> <value>` or from
|
|
133
|
+
Settings in the web UI.
|
|
134
|
+
3. A 1Password secret reference in `.env`, such as
|
|
135
|
+
`op://Private/FAL_API_KEY/password`.
|
|
136
|
+
4. A 1Password vault whose items are named after the keys.
|
|
137
|
+
|
|
138
|
+
`videobook config` lists every key with its source and masks secret values.
|
|
139
|
+
`config get`, `config set` and `config unset` work on one key and edit
|
|
140
|
+
`.env` atomically. `config set` refuses a key that your shell already
|
|
141
|
+
exports, because the exported value would win.
|
|
142
|
+
|
|
143
|
+
### 1Password
|
|
144
|
+
|
|
145
|
+
References and vaults need the [1Password CLI](https://developer.1password.com/docs/cli/)
|
|
146
|
+
(`op`). When a server starts, videobook resolves every `op://` value in the
|
|
147
|
+
environment and `.env`, and every key the vault has, in one `op inject` run.
|
|
148
|
+
`videobook run` and `videobook mcp` skip this when they relay to a running
|
|
149
|
+
server.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
videobook setup 1password --op-vault Private # use op's own sign-in
|
|
153
|
+
videobook setup 1password --op-vault Apicity --op-token env:OP_SERVICE_ACCOUNT_TOKEN
|
|
154
|
+
videobook doctor # shows which keys came from 1Password
|
|
155
|
+
videobook setup 1password --remove
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`setup 1password` saves `VIDEOBOOK_OP_VAULT` and `VIDEOBOOK_OP_SERVICE_TOKEN`
|
|
159
|
+
in `.env`, then lists the vault to report which keys it holds; `--no-verify`
|
|
160
|
+
skips the listing. A vault item supplies a key when its title is the key name,
|
|
161
|
+
and the value is read from its `password` field, for example
|
|
162
|
+
`op://Apicity/OPENAI_API_KEY/password`.
|
|
163
|
+
|
|
164
|
+
The token setting takes `env:VAR`, `$VAR` or a literal service-account
|
|
165
|
+
token. Prefer `env:VAR`, which keeps the token out of the file. When
|
|
166
|
+
`OP_SERVICE_ACCOUNT_TOKEN` is exported, setup records
|
|
167
|
+
`env:OP_SERVICE_ACCOUNT_TOKEN`. Without a token, `op` uses its own sign-in.
|
|
168
|
+
The token reaches `op` only through its environment, never its arguments.
|
|
169
|
+
|
|
170
|
+
A reference that does not resolve is left unset, so it is never sent to a
|
|
171
|
+
provider as a key. The server and `videobook doctor` report it. Keys that
|
|
172
|
+
come from 1Password are read-only in Settings.
|
|
173
|
+
|
|
174
|
+
## Platform notes
|
|
175
|
+
|
|
176
|
+
- macOS on Apple Silicon is the primary platform.
|
|
177
|
+
- macOS on Intel works, but ONNX Runtime has no Intel Mac build, so semantic
|
|
178
|
+
search is unavailable there.
|
|
179
|
+
- Linux x64 and arm64 are supported.
|
|
180
|
+
- Windows is not supported yet. Every native dependency has a Windows x64
|
|
181
|
+
build, but the release smoke test has not passed on Windows. Windows has no
|
|
182
|
+
SIGTERM, so stopping `videobook serve` from another process ends it without
|
|
183
|
+
a clean shutdown, and the next start replaces the lock file it leaves. The
|
|
184
|
+
Release check workflow runs the smoke test on Windows for every release tag
|
|
185
|
+
without blocking the release.
|
|
186
|
+
|
|
187
|
+
## Security
|
|
188
|
+
|
|
189
|
+
Videobook is a local, single-user service. It listens on `127.0.0.1` only and
|
|
190
|
+
accepts requests from loopback hosts and origins. It has no user
|
|
191
|
+
authentication, so do not expose it to other machines or share it between
|
|
192
|
+
users.
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
package/bin/videobook.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
3
|
+
if (major < 22) {
|
|
4
|
+
process.stderr.write(`videobook needs Node.js 22 or newer; this is ${process.version}.\nInstall Node.js 22+ from https://nodejs.org or your version manager, then run videobook again.\n`);
|
|
5
|
+
process.exit(1);
|
|
6
|
+
}
|
|
7
|
+
await import(new URL("../dist/cli/entry.js", import.meta.url).href);
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { AceStepError } from "./errors.js";
|
|
3
|
+
// The live ace-server job flow (tools/ace-server.cpp, verified against version
|
|
4
|
+
// 9761469): POST /synth returns {"id"} immediately, a FIFO worker thread runs
|
|
5
|
+
// the GPU job, GET /job?id reports running|done|failed|cancelled, GET
|
|
6
|
+
// /job?id&result=1 serves the multipart/mixed body (fixed boundary
|
|
7
|
+
// "ace-batch-boundary": one audio part plus one latent part per track), and
|
|
8
|
+
// POST /job?id&cancel=1 cancels a running job. Completed jobs are evicted FIFO
|
|
9
|
+
// past 32, so the result is fetched immediately after the poll reports done.
|
|
10
|
+
const DEFAULT_SYNTH_TIMEOUT_MS = 30 * 60_000;
|
|
11
|
+
const DEFAULT_POLL_INTERVAL_MS = 3_000;
|
|
12
|
+
const SUBMIT_TIMEOUT_MS = 60_000;
|
|
13
|
+
const POLL_TIMEOUT_MS = 5_000;
|
|
14
|
+
const RESULT_TIMEOUT_MS = 120_000;
|
|
15
|
+
const ERROR_BODY_PREVIEW_CHARS = 500;
|
|
16
|
+
export async function isHealthy(baseUrl, timeoutMs = 500) {
|
|
17
|
+
try {
|
|
18
|
+
const response = await fetch(`${baseUrl}/health`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
19
|
+
return response.ok;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function wireRequest(request) {
|
|
26
|
+
return {
|
|
27
|
+
caption: request.caption,
|
|
28
|
+
lyrics: request.lyrics,
|
|
29
|
+
task_type: request.taskType,
|
|
30
|
+
output_format: request.outputFormat,
|
|
31
|
+
seed: request.seed,
|
|
32
|
+
inference_steps: request.inferenceSteps,
|
|
33
|
+
audio_cover_strength: request.audioCoverStrength,
|
|
34
|
+
synth_batch_size: request.synthBatchSize,
|
|
35
|
+
synth_model: request.synthModel,
|
|
36
|
+
duration: request.duration,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function headerRecord(headerBlock) {
|
|
40
|
+
const headers = {};
|
|
41
|
+
for (const line of headerBlock.split("\r\n")) {
|
|
42
|
+
const colon = line.indexOf(":");
|
|
43
|
+
if (colon === -1)
|
|
44
|
+
continue;
|
|
45
|
+
headers[line.slice(0, colon).trim().toLowerCase()] = line.slice(colon + 1).trim();
|
|
46
|
+
}
|
|
47
|
+
return headers;
|
|
48
|
+
}
|
|
49
|
+
export function parseMultipartMixed(body, contentType) {
|
|
50
|
+
const boundaryMatch = /boundary="?([^";]+)"?/u.exec(contentType);
|
|
51
|
+
if (boundaryMatch === null) {
|
|
52
|
+
throw new AceStepError("malformed_response", `ace-server response has no multipart boundary (content-type: "${contentType}")`);
|
|
53
|
+
}
|
|
54
|
+
const delimiter = Buffer.from(`--${boundaryMatch[1]}`);
|
|
55
|
+
const parts = [];
|
|
56
|
+
let offset = body.indexOf(delimiter);
|
|
57
|
+
while (offset !== -1) {
|
|
58
|
+
const afterDelimiter = offset + delimiter.length;
|
|
59
|
+
if (body.subarray(afterDelimiter, afterDelimiter + 2).toString("latin1") === "--")
|
|
60
|
+
break;
|
|
61
|
+
const boundaryLineEnd = body.indexOf("\r\n", afterDelimiter);
|
|
62
|
+
const headerEnd = body.indexOf("\r\n\r\n", afterDelimiter);
|
|
63
|
+
const next = headerEnd === -1 ? -1 : body.indexOf(delimiter, headerEnd + 4);
|
|
64
|
+
if (boundaryLineEnd === -1 || headerEnd === -1 || next === -1) {
|
|
65
|
+
throw new AceStepError("malformed_response", "ace-server multipart response is truncated");
|
|
66
|
+
}
|
|
67
|
+
const headerBlock = body.subarray(boundaryLineEnd + 2, headerEnd).toString("utf8");
|
|
68
|
+
let dataEnd = next;
|
|
69
|
+
if (body.subarray(dataEnd - 2, dataEnd).toString("latin1") === "\r\n")
|
|
70
|
+
dataEnd -= 2;
|
|
71
|
+
parts.push({ headers: headerRecord(headerBlock), data: body.subarray(headerEnd + 4, dataEnd) });
|
|
72
|
+
offset = next;
|
|
73
|
+
}
|
|
74
|
+
if (parts.length === 0) {
|
|
75
|
+
throw new AceStepError("malformed_response", "ace-server multipart response contained no parts");
|
|
76
|
+
}
|
|
77
|
+
return parts;
|
|
78
|
+
}
|
|
79
|
+
function describeFetchError(error) {
|
|
80
|
+
if (error instanceof Error) {
|
|
81
|
+
const cause = error.cause instanceof Error ? `: ${error.cause.message}` : "";
|
|
82
|
+
return `${error.message}${cause}`;
|
|
83
|
+
}
|
|
84
|
+
return String(error);
|
|
85
|
+
}
|
|
86
|
+
async function readErrorPreview(response) {
|
|
87
|
+
const bodyText = await response.text().catch(() => "");
|
|
88
|
+
return bodyText.slice(0, ERROR_BODY_PREVIEW_CHARS);
|
|
89
|
+
}
|
|
90
|
+
async function submitSynthJob(baseUrl, srcWavPath, request, signal) {
|
|
91
|
+
const sourceBytes = await readFile(srcWavPath);
|
|
92
|
+
const form = new FormData();
|
|
93
|
+
form.set("request", new Blob([JSON.stringify(wireRequest(request))], { type: "application/json" }), "request.json");
|
|
94
|
+
form.set("audio", new Blob([sourceBytes], { type: "audio/wav" }), "source.wav");
|
|
95
|
+
const response = await fetch(`${baseUrl}/synth`, { method: "POST", body: form, signal });
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
throw new AceStepError("synth_http_error", `ace-server /synth returned ${response.status}: ${await readErrorPreview(response)}`);
|
|
98
|
+
}
|
|
99
|
+
const body = (await response.json().catch(() => null));
|
|
100
|
+
if (typeof body?.id !== "string" || body.id.length === 0) {
|
|
101
|
+
throw new AceStepError("malformed_response", "ace-server /synth returned no job id");
|
|
102
|
+
}
|
|
103
|
+
return body.id;
|
|
104
|
+
}
|
|
105
|
+
async function readJobStatus(baseUrl, jobId) {
|
|
106
|
+
const response = await fetch(`${baseUrl}/job?id=${encodeURIComponent(jobId)}`, {
|
|
107
|
+
signal: AbortSignal.timeout(POLL_TIMEOUT_MS),
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new AceStepError("synth_http_error", `ace-server /job returned ${response.status}: ${await readErrorPreview(response)}`);
|
|
111
|
+
}
|
|
112
|
+
const body = (await response.json().catch(() => null));
|
|
113
|
+
if (typeof body?.status !== "string") {
|
|
114
|
+
throw new AceStepError("malformed_response", "ace-server /job returned no status");
|
|
115
|
+
}
|
|
116
|
+
return body.status;
|
|
117
|
+
}
|
|
118
|
+
async function cancelSynthJob(baseUrl, jobId) {
|
|
119
|
+
try {
|
|
120
|
+
await fetch(`${baseUrl}/job?id=${encodeURIComponent(jobId)}&cancel=1`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
signal: AbortSignal.timeout(POLL_TIMEOUT_MS),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Best-effort: the job also dies with the server, and an orphaned
|
|
127
|
+
// generation is discarded when its result is never fetched.
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function fetchSynthResult(baseUrl, jobId) {
|
|
131
|
+
const response = await fetch(`${baseUrl}/job?id=${encodeURIComponent(jobId)}&result=1`, {
|
|
132
|
+
signal: AbortSignal.timeout(RESULT_TIMEOUT_MS),
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new AceStepError("synth_http_error", `ace-server /job result returned ${response.status}: ${await readErrorPreview(response)}`);
|
|
136
|
+
}
|
|
137
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
138
|
+
const body = Buffer.from(await response.arrayBuffer());
|
|
139
|
+
if (contentType.startsWith("audio/")) {
|
|
140
|
+
return { audio: body, audioContentType: contentType, latents: null };
|
|
141
|
+
}
|
|
142
|
+
const parts = parseMultipartMixed(body, contentType);
|
|
143
|
+
const audioPart = parts.find((part) => (part.headers["content-type"] ?? "").startsWith("audio/"));
|
|
144
|
+
if (audioPart === undefined) {
|
|
145
|
+
throw new AceStepError("malformed_response", "ace-server synth result contained no audio part");
|
|
146
|
+
}
|
|
147
|
+
const latentPart = parts.find((part) => (part.headers["content-type"] ?? "").startsWith("application/octet-stream"));
|
|
148
|
+
return {
|
|
149
|
+
audio: audioPart.data,
|
|
150
|
+
audioContentType: audioPart.headers["content-type"] ?? "audio/wav",
|
|
151
|
+
latents: latentPart?.data ?? null,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
async function delay(ms, signal) {
|
|
155
|
+
await new Promise((resolve, reject) => {
|
|
156
|
+
const timer = setTimeout(() => {
|
|
157
|
+
signal.removeEventListener("abort", onAbort);
|
|
158
|
+
resolve();
|
|
159
|
+
}, ms);
|
|
160
|
+
const onAbort = () => {
|
|
161
|
+
clearTimeout(timer);
|
|
162
|
+
reject(signal.reason instanceof Error ? signal.reason : new Error("Aborted"));
|
|
163
|
+
};
|
|
164
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
export async function synthCover(baseUrl, srcWavPath, request, options = {}) {
|
|
168
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_SYNTH_TIMEOUT_MS;
|
|
169
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
170
|
+
const deadlineSignal = AbortSignal.timeout(timeoutMs);
|
|
171
|
+
const signal = options.signal
|
|
172
|
+
? AbortSignal.any([options.signal, deadlineSignal])
|
|
173
|
+
: deadlineSignal;
|
|
174
|
+
let jobId = null;
|
|
175
|
+
try {
|
|
176
|
+
jobId = await submitSynthJob(baseUrl, srcWavPath, request, AbortSignal.any([signal, AbortSignal.timeout(SUBMIT_TIMEOUT_MS)]));
|
|
177
|
+
for (;;) {
|
|
178
|
+
const status = await readJobStatus(baseUrl, jobId);
|
|
179
|
+
if (status === "done")
|
|
180
|
+
return await fetchSynthResult(baseUrl, jobId);
|
|
181
|
+
if (status === "failed") {
|
|
182
|
+
throw new AceStepError("synth_failed", "ace-server reported the cover synthesis job as failed; the reason is in the [ace-step] logs above");
|
|
183
|
+
}
|
|
184
|
+
if (status === "cancelled") {
|
|
185
|
+
throw new AceStepError("synth_failed", "ace-server cancelled the cover synthesis job");
|
|
186
|
+
}
|
|
187
|
+
signal.throwIfAborted();
|
|
188
|
+
await delay(pollIntervalMs, signal);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (error instanceof AceStepError)
|
|
193
|
+
throw error;
|
|
194
|
+
if (jobId !== null && signal.aborted)
|
|
195
|
+
await cancelSynthJob(baseUrl, jobId);
|
|
196
|
+
if (options.signal?.aborted)
|
|
197
|
+
throw error;
|
|
198
|
+
if (deadlineSignal.aborted) {
|
|
199
|
+
throw new AceStepError("synth_timeout", `ace-server cover synthesis did not finish within ${timeoutMs}ms`);
|
|
200
|
+
}
|
|
201
|
+
throw new AceStepError("server_exited", `ace-server request failed: ${describeFetchError(error)}. The server may have crashed or been stopped; check [ace-step] logs.`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { isHealthy } from "./client.js";
|
|
5
|
+
const DEFAULT_PORT = 8317;
|
|
6
|
+
const DEFAULT_MODEL = "acestep-v15-turbo-Q4_K_M.gguf";
|
|
7
|
+
const TEXT_ENCODER_MODEL = "Qwen3-Embedding-0.6B-Q8_0.gguf";
|
|
8
|
+
const VAE_MODEL = "vae-BF16.gguf";
|
|
9
|
+
const GATE_HEALTH_TIMEOUT_MS = 500;
|
|
10
|
+
function acestepRoot() {
|
|
11
|
+
return join(homedir(), ".cache", "videobook", "acestep");
|
|
12
|
+
}
|
|
13
|
+
export function aceStepConfig() {
|
|
14
|
+
const baseUrl = process.env.VIDEOBOOK_ACESTEP_BASE_URL?.trim();
|
|
15
|
+
const parsedPort = Number.parseInt(process.env.VIDEOBOOK_ACESTEP_PORT ?? "", 10);
|
|
16
|
+
return {
|
|
17
|
+
baseUrl: baseUrl ? baseUrl.replace(/\/+$/u, "") : null,
|
|
18
|
+
serverPath: process.env.VIDEOBOOK_ACESTEP_SERVER_PATH?.trim() || join(acestepRoot(), "bin", "ace-server"),
|
|
19
|
+
modelsDir: process.env.VIDEOBOOK_ACESTEP_MODELS_DIR?.trim() || join(acestepRoot(), "models"),
|
|
20
|
+
port: Number.isFinite(parsedPort) && parsedPort > 0 ? parsedPort : DEFAULT_PORT,
|
|
21
|
+
model: process.env.VIDEOBOOK_ACESTEP_MODEL?.trim() || DEFAULT_MODEL,
|
|
22
|
+
keepLoaded: process.env.VIDEOBOOK_ACESTEP_KEEP_LOADED === "1",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function requiredModelFiles(config = aceStepConfig()) {
|
|
26
|
+
return [config.model, TEXT_ENCODER_MODEL, VAE_MODEL];
|
|
27
|
+
}
|
|
28
|
+
export function checkLocalAvailability(config = aceStepConfig()) {
|
|
29
|
+
if (!existsSync(config.serverPath)) {
|
|
30
|
+
return {
|
|
31
|
+
available: false,
|
|
32
|
+
kind: "binary_missing",
|
|
33
|
+
reason: `acestep.cpp runtime is not installed: ace-server not found at ${config.serverPath}. ` +
|
|
34
|
+
`Run "npm run install:acestep", or set VIDEOBOOK_ACESTEP_SERVER_PATH / VIDEOBOOK_ACESTEP_BASE_URL.`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const missing = requiredModelFiles(config).filter((name) => !existsSync(join(config.modelsDir, name)));
|
|
38
|
+
if (missing.length > 0) {
|
|
39
|
+
return {
|
|
40
|
+
available: false,
|
|
41
|
+
kind: "models_missing",
|
|
42
|
+
reason: `ACE-Step models missing from ${config.modelsDir}: ${missing.join(", ")}. Run "npm run install:acestep".`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { available: true };
|
|
46
|
+
}
|
|
47
|
+
export async function checkAceStepAvailability() {
|
|
48
|
+
const config = aceStepConfig();
|
|
49
|
+
if (config.baseUrl !== null) {
|
|
50
|
+
const healthy = await isHealthy(config.baseUrl, GATE_HEALTH_TIMEOUT_MS);
|
|
51
|
+
if (!healthy) {
|
|
52
|
+
return {
|
|
53
|
+
available: false,
|
|
54
|
+
kind: "unreachable",
|
|
55
|
+
reason: `ace-server at ${config.baseUrl} did not answer /health within ${GATE_HEALTH_TIMEOUT_MS}ms ` +
|
|
56
|
+
`(VIDEOBOOK_ACESTEP_BASE_URL). Start it or unset the variable.`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return { available: true };
|
|
60
|
+
}
|
|
61
|
+
return checkLocalAvailability(config);
|
|
62
|
+
}
|