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
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { findPrimaryMediaFile } from "videobook-engine";
|
|
4
|
+
import { notebookGridTag, notebookOccupiedSlots, NOTEBOOK_GRID_ROW_COUNT, NOTEBOOK_GRID_COLUMN_COUNT } from "videobook-engine/notebook-grid";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { INTELLIGENCE_MODEL } from "./openai-intelligence.js";
|
|
7
|
+
import { coldOpenRangeError } from "./cold-open-model.js";
|
|
8
|
+
const coldOpenSuggestionSchema = z.object({
|
|
9
|
+
sourceArtifactId: z.string().uuid(),
|
|
10
|
+
sourceObjectHash: z.string().min(1),
|
|
11
|
+
durationSeconds: z.number().finite().min(0.5),
|
|
12
|
+
fps: z.number().finite().positive(),
|
|
13
|
+
startSeconds: z.number().finite().nonnegative(),
|
|
14
|
+
endSeconds: z.number().finite().positive(),
|
|
15
|
+
reason: z.string().min(1),
|
|
16
|
+
model: z.string().min(1),
|
|
17
|
+
});
|
|
18
|
+
export async function coldOpenSource(engine, artifactId, expectedHash) {
|
|
19
|
+
const artifact = engine.artifacts.get(artifactId);
|
|
20
|
+
if (!artifact.ok)
|
|
21
|
+
throw new Error(artifact.error.message);
|
|
22
|
+
if (!["video", "final"].includes(artifact.value.kind))
|
|
23
|
+
throw new Error("Choose a video for the cold open.");
|
|
24
|
+
const manifest = await engine.files.manifest(artifactId, { includeDotfiles: true });
|
|
25
|
+
if (!manifest.ok)
|
|
26
|
+
throw new Error(manifest.error.message);
|
|
27
|
+
const file = findPrimaryMediaFile(manifest.value.files, artifact.value.kind);
|
|
28
|
+
if (!file)
|
|
29
|
+
throw new Error("The source video is missing.");
|
|
30
|
+
if (expectedHash && file.objectHash !== expectedHash)
|
|
31
|
+
throw new Error("The source video changed. Open a new cold-open review.");
|
|
32
|
+
const streams = engine.streams.list(artifactId);
|
|
33
|
+
if (!streams.ok)
|
|
34
|
+
throw new Error(streams.error.message);
|
|
35
|
+
const video = streams.value.find(stream => stream.kind === "video" && stream.sourcePath === file.name && stream.objectHash === file.objectHash);
|
|
36
|
+
if (!video)
|
|
37
|
+
throw new Error("Wait for the video to finish processing before making a cold open.");
|
|
38
|
+
const durationSeconds = video.durationTicks * video.timeBase.numerator / video.timeBase.denominator;
|
|
39
|
+
const metadata = await engine.metadata.artifacts.read(artifactId, "original");
|
|
40
|
+
const fps = metadata.ok && metadata.value.fps && metadata.value.fps > 0 ? metadata.value.fps : 30;
|
|
41
|
+
const error = coldOpenRangeError(0, durationSeconds, durationSeconds);
|
|
42
|
+
if (error)
|
|
43
|
+
throw new Error(error);
|
|
44
|
+
return { artifact: artifact.value, file, manifest: manifest.value, path: join(manifest.value.path, file.name), durationSeconds, fps };
|
|
45
|
+
}
|
|
46
|
+
export function coldOpenCacheKey(source) {
|
|
47
|
+
const inputs = source.manifest.files.filter(file => ["elevenlabs.json", ".analysis.gpt4otrans.json"].includes(file.name))
|
|
48
|
+
.map(file => [file.name, file.objectHash]).sort();
|
|
49
|
+
return `cold-open.suggestion.${createHash("sha256").update(JSON.stringify([1, INTELLIGENCE_MODEL, source.artifact.artifactId, source.file.objectHash, inputs])).digest("hex")}`;
|
|
50
|
+
}
|
|
51
|
+
export function readColdOpenSuggestion(engine, key) {
|
|
52
|
+
const parsed = coldOpenSuggestionSchema.safeParse(engine.settings.get(key));
|
|
53
|
+
if (!parsed.success || coldOpenRangeError(parsed.data.startSeconds, parsed.data.endSeconds, parsed.data.durationSeconds))
|
|
54
|
+
return null;
|
|
55
|
+
return parsed.data;
|
|
56
|
+
}
|
|
57
|
+
export function coldOpenDestination(notebook, sourceArtifactId) {
|
|
58
|
+
const occupied = new Set(notebookOccupiedSlots(notebook.cells).map(notebookGridTag));
|
|
59
|
+
const source = notebook.cells.find(cell => cell.outputArtifactId === sourceArtifactId);
|
|
60
|
+
const below = source ? { row: source.slot.row + 1, column: source.slot.column } : null;
|
|
61
|
+
if (below && below.row < NOTEBOOK_GRID_ROW_COUNT && !occupied.has(notebookGridTag(below)))
|
|
62
|
+
return below;
|
|
63
|
+
for (let row = 0; row < NOTEBOOK_GRID_ROW_COUNT; row += 1) {
|
|
64
|
+
for (let column = 0; column < NOTEBOOK_GRID_COLUMN_COUNT; column += 1) {
|
|
65
|
+
const slot = { row, column };
|
|
66
|
+
if (!occupied.has(notebookGridTag(slot)))
|
|
67
|
+
return slot;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
throw new Error("The notebook needs one empty cell for the cold-open copy.");
|
|
71
|
+
}
|
|
72
|
+
export function checkColdOpenNotebook(engine, notebookId, sourceArtifactId) {
|
|
73
|
+
if (!notebookId)
|
|
74
|
+
return;
|
|
75
|
+
const notebook = engine.notebooks.read(notebookId);
|
|
76
|
+
if (!notebook.ok)
|
|
77
|
+
throw new Error(notebook.error.message);
|
|
78
|
+
coldOpenDestination(notebook.value, sourceArtifactId);
|
|
79
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { listModels } from "./media/listing.js";
|
|
2
|
+
import { buildWorkspaceActionCatalog } from "./workspace-action-catalog.js";
|
|
3
|
+
import { WORKSPACE_ACTION_SURFACES } from "./workspace-action-surfaces.js";
|
|
4
|
+
function oneLine(value) {
|
|
5
|
+
return value.replace(/\s+/g, " ").trim();
|
|
6
|
+
}
|
|
7
|
+
function escapeTable(value) {
|
|
8
|
+
return oneLine(value).replaceAll("|", "\\|");
|
|
9
|
+
}
|
|
10
|
+
export function renderCommandReference(tools, commands) {
|
|
11
|
+
const toolLines = [...tools]
|
|
12
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
13
|
+
.map((tool) => `- \`${tool.name}\` — ${oneLine(tool.description)}`);
|
|
14
|
+
const catalog = buildWorkspaceActionCatalog(tools, commands);
|
|
15
|
+
const commandLines = [...catalog.actions]
|
|
16
|
+
.sort((a, b) => a.command.localeCompare(b.command))
|
|
17
|
+
.map((command) => {
|
|
18
|
+
const aliases = command.aliases ?? [];
|
|
19
|
+
const aliasText = aliases.length > 0 ? ` (aliases: ${aliases.map((alias) => `\`${alias}\``).join(", ")})` : "";
|
|
20
|
+
const target = command.handler.kind === "tool"
|
|
21
|
+
? `; MCP: \`${command.handler.tool}\``
|
|
22
|
+
: command.handler.kind === "ui" ? `; UI: \`${command.handler.action}\`` : "; preview or workspace operation";
|
|
23
|
+
return `- \`${command.command}\`${aliasText} — ${oneLine(command.description)}${target}`;
|
|
24
|
+
});
|
|
25
|
+
return `# Command Reference
|
|
26
|
+
|
|
27
|
+
Every current MCP endpoint and discoverable action is listed once. Use the Actions button on any screen, press Ctrl+Shift+K / Cmd+Shift+K, or type a slash in chat to browse the complete catalog. Search includes aliases and descriptions. A command with missing arguments opens its form; media, notebook, entity, track and clip selectors provide targets. Advanced provider alternatives retain shared input fields and show a cost review before generation.
|
|
28
|
+
|
|
29
|
+
Media commands \`/export\`, \`/delete\`, \`/reverse\` and \`/trim\` target media. Sequence operations use \`/export-sequence\`, \`/clip-delete\`, \`/clip-reverse\`, \`/clip-trim\`, and \`/clip-audio\`; clip timing uses frames and media trimming uses seconds. \`/clip-audio\` edits gain, mute, and fades on an audio-track clip. Explicit legacy clip IDs and \`/export @sequence-main\` remain accepted. Use grid addresses such as \`/crop @a1\`, \`/trim @a1 0 2\` or \`/insert @a1 0 60\`.
|
|
30
|
+
|
|
31
|
+
Image, video and audio generation runs through \`generate_image\`, \`generate_video\` and \`generate_audio\` with a model id from \`list_generation_models\`; see [generation-models.md](generation-models.md). Slash aliases match their canonical action in search. The legacy \`/skeleton\` shortcut opens a reviewed AI pose-guide request. Import owns upload transport and duplicate-byte checks; it uses a native file picker. Set \`VIDEOBOOK_DOWNLOADS_DIR\` to override the server's default Downloads directory.
|
|
32
|
+
|
|
33
|
+
Routine pointer actions return focus to chat. Editing fields, open dialogs, keyboard navigation and native playback retain focus. Closing a dialog restores its opener when appropriate; delayed work cannot take focus from a newer edit.
|
|
34
|
+
|
|
35
|
+
## MCP endpoints (${tools.length})
|
|
36
|
+
|
|
37
|
+
${toolLines.join("\n")}
|
|
38
|
+
|
|
39
|
+
## Slash actions (${catalog.actions.length}; ${commands.length} dedicated command routes)
|
|
40
|
+
|
|
41
|
+
${commandLines.join("\n")}
|
|
42
|
+
- \`/<project-name>\` — Switch to that project; generated dynamically for each project whose name does not conflict with a command or alias.
|
|
43
|
+
`;
|
|
44
|
+
}
|
|
45
|
+
export function renderWorkspaceActionCoverage(catalog) {
|
|
46
|
+
const rows = [...catalog.actions].sort((left, right) => left.id.localeCompare(right.id)).map((action) => {
|
|
47
|
+
const target = action.target.argument ? `${action.target.kind}${action.target.multiple ? " selection" : ""}: ${action.target.argument}` : action.target.kind;
|
|
48
|
+
const handler = action.handler.kind === "tool" ? action.handler.tool : action.handler.kind === "ui" ? action.handler.action : action.handler.command;
|
|
49
|
+
return `| \`${action.id}\` | \`${action.command}\` | ${action.aliases.join(", ")} | ${action.scope} | ${escapeTable(target)} | \`${handler}\` | ${action.surfaces.join(", ")} | ${action.focus} | ${action.confirmation} |`;
|
|
50
|
+
});
|
|
51
|
+
const surfaces = Object.entries(WORKSPACE_ACTION_SURFACES).map(([name, entry]) => `| ${name} | [${entry.component}](../${entry.component}) | ${entry.trigger} |`);
|
|
52
|
+
const workflows = catalog.tools.filter((entry) => entry.exposure === "workflow").map((entry) => `| \`${entry.tool}\` | \`${entry.actionId}\` | ${escapeTable(entry.reason)} |`);
|
|
53
|
+
return `# Workspace action coverage
|
|
54
|
+
|
|
55
|
+
Generated by \`npm run docs:commands\` from the registered tools, command definitions and surface contracts. ${catalog.tools.length} active endpoints map to ${catalog.actions.length} visible actions or their owning workflows. Unknown endpoints, handlers, aliases and missing declared surfaces fail the catalog contract.
|
|
56
|
+
|
|
57
|
+
The browser regression suite checks catalog equality, complete slash traversal, typed form discovery, named target selection, menu and slash parity, review and cancellation, real media mutations and focus. Provider generation, posting and OS clipboard integration require separate execution validation; opening a form never starts a paid job or publishes content.
|
|
58
|
+
|
|
59
|
+
## Surface entry points
|
|
60
|
+
|
|
61
|
+
| Surface | Component | Entry point |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
${surfaces.join("\n")}
|
|
64
|
+
|
|
65
|
+
## Actions
|
|
66
|
+
|
|
67
|
+
| Stable ID | Command | Aliases | Scope | Target | Handler | Surfaces | Focus | Review |
|
|
68
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
69
|
+
${rows.join("\n")}
|
|
70
|
+
|
|
71
|
+
## Transport and workflow ownership
|
|
72
|
+
|
|
73
|
+
| Endpoint | Visible owner | Reason |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
${workflows.join("\n")}
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
export function renderGenerationModels() {
|
|
79
|
+
const models = listModels({ includeHidden: true });
|
|
80
|
+
const rows = models.map((model) => {
|
|
81
|
+
const refs = model.slots.map((slot) => `${slot.role} ${slot.min}-${slot.max ?? "n"}`).join(", ") || "none";
|
|
82
|
+
const modes = model.modes.length > 1 ? model.modes.map((mode) => mode.id).join(", ") : "";
|
|
83
|
+
return `| \`${escapeTable(model.id)}\` | ${escapeTable(model.title)} | ${model.media} | ${model.entry.operations.join(", ")} | ${escapeTable(refs)} | ${modes} | ${model.entry.hidden ? "hidden" : "visible"} |`;
|
|
84
|
+
});
|
|
85
|
+
return `# Generation Models
|
|
86
|
+
|
|
87
|
+
Generated by \`npm run docs:commands\` from the media catalog (\`server/src/media/catalog.ts\`). Call \`generate_image\`, \`generate_video\` or \`generate_audio\` with one of these model ids; \`list_generation_models\` returns the same list with every option, enum, range and default read from the apicity schemas.
|
|
88
|
+
|
|
89
|
+
- Models: ${models.length}
|
|
90
|
+
|
|
91
|
+
| Model | Title | Media | Operations | Refs | Modes | Picker |
|
|
92
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
93
|
+
${rows.join("\n")}
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { B2Error, createB2 } from "@apicity/b2";
|
|
3
|
+
function createB2ContentStore(config) {
|
|
4
|
+
const provider = createB2({
|
|
5
|
+
accessKeyId: config.accessKeyId,
|
|
6
|
+
secretAccessKey: config.secretAccessKey,
|
|
7
|
+
region: config.region,
|
|
8
|
+
...(config.endpoint ? { endpoint: config.endpoint } : {}),
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
head: async (key) => {
|
|
12
|
+
try {
|
|
13
|
+
const result = await provider.objects.head({
|
|
14
|
+
bucket: config.bucket,
|
|
15
|
+
key,
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
exists: true,
|
|
19
|
+
...(result.contentLength !== undefined
|
|
20
|
+
? { size: result.contentLength }
|
|
21
|
+
: {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error instanceof B2Error && error.status === 404) {
|
|
26
|
+
return { exists: false };
|
|
27
|
+
}
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
uploadFile: async (key, sourcePath) => {
|
|
32
|
+
await provider.objects.put({
|
|
33
|
+
bucket: config.bucket,
|
|
34
|
+
key,
|
|
35
|
+
body: await readFile(sourcePath),
|
|
36
|
+
contentType: "application/octet-stream",
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
downloadFile: async (key, destinationPath) => {
|
|
40
|
+
const result = await provider.objects.get({
|
|
41
|
+
bucket: config.bucket,
|
|
42
|
+
key,
|
|
43
|
+
});
|
|
44
|
+
await writeFile(destinationPath, new Uint8Array(result.body));
|
|
45
|
+
},
|
|
46
|
+
delete: async (key) => {
|
|
47
|
+
await provider.objects.del({
|
|
48
|
+
bucket: config.bucket,
|
|
49
|
+
key,
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export function b2ContentStoreConfigFromEnvironment() {
|
|
55
|
+
const accessKeyId = process.env.B2_ACCESS_KEY_ID;
|
|
56
|
+
const secretAccessKey = process.env.B2_SECRET_ACCESS_KEY;
|
|
57
|
+
const region = process.env.B2_REGION;
|
|
58
|
+
const bucket = process.env.B2_BUCKET;
|
|
59
|
+
if (!accessKeyId || !secretAccessKey || !region || !bucket)
|
|
60
|
+
return undefined;
|
|
61
|
+
return {
|
|
62
|
+
accessKeyId,
|
|
63
|
+
secretAccessKey,
|
|
64
|
+
region,
|
|
65
|
+
bucket,
|
|
66
|
+
...(process.env.B2_ENDPOINT
|
|
67
|
+
? { endpoint: process.env.B2_ENDPOINT }
|
|
68
|
+
: {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function contentStoreFromEnvironment() {
|
|
72
|
+
const config = b2ContentStoreConfigFromEnvironment();
|
|
73
|
+
return config ? createB2ContentStore(config) : undefined;
|
|
74
|
+
}
|
package/dist/cost.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const CANONICAL_DIMS = {
|
|
2
|
+
"16:9": [1920, 1080],
|
|
3
|
+
"9:16": [1080, 1920],
|
|
4
|
+
"1:1": [1080, 1080],
|
|
5
|
+
};
|
|
6
|
+
export function cropGeometry(rect, srcW, srcH, ratio, alignment) {
|
|
7
|
+
if (!Number.isFinite(srcW) || !Number.isFinite(srcH) || srcW < alignment || srcH < alignment) {
|
|
8
|
+
throw new Error("Could not probe usable source dimensions");
|
|
9
|
+
}
|
|
10
|
+
const cropW = Math.min(Math.floor(srcW / alignment) * alignment, Math.max(alignment, Math.round(rect.w * srcW / alignment) * alignment));
|
|
11
|
+
const cropH = Math.min(Math.floor(srcH / alignment) * alignment, Math.max(alignment, Math.round(rect.h * srcH / alignment) * alignment));
|
|
12
|
+
const roundOrigin = alignment === 2 ? Math.floor : Math.round;
|
|
13
|
+
const cropX = Math.min(srcW - cropW, Math.max(0, roundOrigin(rect.x * srcW / alignment) * alignment));
|
|
14
|
+
const cropY = Math.min(srcH - cropH, Math.max(0, roundOrigin(rect.y * srcH / alignment) * alignment));
|
|
15
|
+
const [outW, outH] = CANONICAL_DIMS[ratio];
|
|
16
|
+
const cropAspect = cropW / cropH;
|
|
17
|
+
const targetAspect = outW / outH;
|
|
18
|
+
const aspectError = Math.abs(cropAspect - targetAspect) / targetAspect;
|
|
19
|
+
if (aspectError > 0.02) {
|
|
20
|
+
throw new Error(`Crop rectangle aspect ${cropAspect.toFixed(4)} (${cropW}x${cropH}) does not match target ratio ${ratio} (${targetAspect.toFixed(4)}); error ${(aspectError * 100).toFixed(1)}% > 2%`);
|
|
21
|
+
}
|
|
22
|
+
return { cropX, cropY, cropW, cropH, outW, outH };
|
|
23
|
+
}
|