@gentbajko/slopify 3.25.9 → 4.1.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/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +4 -6
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +2 -4
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +3 -2
- package/dist/adapters/explain.js +10 -12
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +21 -4
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +42 -9
- package/dist/adapters/image/fal.js +21 -53
- package/dist/adapters/image/google.js +33 -56
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +22 -48
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +21 -49
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +54 -3
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +11 -6
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +52 -99
- package/dist/adapters/llm/claude-code.js +16 -4
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-models.js +1 -1
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/document-workspace.js +3 -2
- package/dist/adapters/llm/image-workspace.js +3 -2
- package/dist/adapters/llm/openrouter.js +12 -48
- package/dist/adapters/llm/run-cli.js +9 -24
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +21 -41
- package/dist/adapters/tts/inworld-async.js +6 -2
- package/dist/adapters/tts/inworld.js +6 -2
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/adapters/tts/system.js +2 -1
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +23 -14
- package/dist/catalog/schema.js +4 -1
- package/dist/catalog/store.js +39 -0
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +11 -32
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +86 -11
- package/dist/edge/http/assistant.js +129 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +2 -4
- package/dist/edge/http/channel-memory.js +9 -22
- package/dist/edge/http/channels.js +14 -27
- package/dist/edge/http/checkpoints.js +39 -21
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +5 -14
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +5 -10
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +47 -14
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +30 -26
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +7 -14
- package/dist/edge/http/patch-notes.js +6 -12
- package/dist/edge/http/planning.js +3 -7
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +2 -1
- package/dist/edge/http/project-templates.js +31 -19
- package/dist/edge/http/projects.js +24 -16
- package/dist/edge/http/prompts.js +9 -16
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +48 -34
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +12 -25
- package/dist/edge/http/revision-files.js +6 -11
- package/dist/edge/http/revisions.js +14 -19
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +69 -40
- package/dist/edge/http/settings.js +27 -14
- package/dist/edge/http/social.js +283 -0
- package/dist/edge/http/staging.js +3 -5
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +33 -25
- package/dist/edge/http/studio.js +94 -69
- package/dist/edge/http/style-preview.js +3 -6
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +436 -0
- package/dist/edge/http/trash.js +11 -12
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +3 -4
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +29 -3
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +6 -4
- package/dist/edge/mcp/library-tools.js +9 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +11 -9
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +19 -7
- package/dist/edge/mcp/tools-planning.js +40 -21
- package/dist/edge/mcp/tools-projects.js +38 -11
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +23 -10
- package/dist/edge/mcp/tools-schedules.js +32 -8
- package/dist/edge/mcp/tools-setup.js +75 -11
- package/dist/edge/mcp/tools-social.js +47 -0
- package/dist/edge/mcp/tools-storage.js +11 -3
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/pipeline.js +12 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/ports/settings-places.js +31 -0
- package/dist/kernel/ports/system-speech.js +31 -3
- package/dist/kernel/runner/attempt.js +14 -4
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +18 -12
- package/dist/kernel/runner/standalone.js +11 -7
- package/dist/main.js +338 -21
- package/dist/model-catalog.js +20 -0
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +11 -7
- package/dist/slices/admission/rules.js +50 -15
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +86 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +344 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +8 -7
- package/dist/slices/channels/cast-images.js +3 -2
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +7 -1
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +3 -15
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +2 -28
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +130 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +223 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/document/model.js +7 -4
- package/dist/slices/document/render.js +2 -1
- package/dist/slices/document/theme-schema.js +1 -1
- package/dist/slices/document/theme.js +49 -3
- package/dist/slices/episodes/summarize.js +6 -2
- package/dist/slices/estimate/index.js +72 -28
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +5 -3
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +8 -16
- package/dist/slices/images/scenes.js +102 -28
- package/dist/slices/keywords/digest.js +85 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +5 -4
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +53 -12
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +125 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +72 -27
- package/dist/slices/model-upkeep/usage.js +39 -13
- package/dist/slices/narration/breaths.js +3 -1
- package/dist/slices/narration/clean-pieces.js +3 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +6 -4
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +4 -3
- package/dist/slices/onboarding/copy.js +21 -3
- package/dist/slices/onboarding/first-run.js +16 -40
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +6 -4
- package/dist/slices/onboarding/model.js +26 -37
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +105 -65
- package/dist/slices/onboarding/sample.js +4 -2
- package/dist/slices/onboarding/state.js +9 -11
- package/dist/slices/onboarding/template.js +8 -6
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +4 -3
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +9 -3
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/play-drafts/service.js +17 -7
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/next-chapter.js +2 -1
- package/dist/slices/project-templates/provider-defaults.js +22 -0
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +14 -1
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +32 -14
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +4 -4
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +8 -5
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +102 -31
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +19 -7
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +9 -8
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +3 -2
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +10 -9
- package/dist/slices/rebuild/runtime-article.js +7 -5
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +11 -13
- package/dist/slices/rebuild/runtime-export-bed.js +8 -12
- package/dist/slices/rebuild/runtime-export-edit.js +8 -16
- package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
- package/dist/slices/rebuild/runtime-export-short.js +9 -5
- package/dist/slices/rebuild/runtime-export.js +38 -15
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +8 -12
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +17 -22
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +13 -17
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +67 -25
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +39 -33
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +31 -50
- package/dist/slices/rebuild/runtime-store.js +20 -10
- package/dist/slices/rebuild/runtime-subtitles.js +28 -25
- package/dist/slices/rebuild/runtime-voices.js +10 -16
- package/dist/slices/rebuild/runtime-youtube.js +14 -31
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +4 -1
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +32 -11
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +4 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +9 -5
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +3 -3
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +18 -7
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +30 -21
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +57 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +53 -41
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +8 -43
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +14 -2
- package/dist/slices/settings/playback.js +34 -23
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +6 -18
- package/dist/slices/shorts/prompts.js +4 -14
- package/dist/slices/shorts/render.js +6 -2
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +132 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +56 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +129 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +22 -4
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +17 -12
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +26 -9
- package/dist/slices/studio/calendar.js +7 -2
- package/dist/slices/studio/disclosure.js +4 -4
- package/dist/slices/studio/model.js +1 -1
- package/dist/slices/studio/pack.js +9 -8
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +7 -16
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +20 -57
- package/dist/slices/studio/videos.js +35 -4
- package/dist/slices/style-preview/render.js +37 -16
- package/dist/slices/style-preview/schema.js +14 -1
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +161 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +106 -0
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +322 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +58 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +207 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +355 -0
- package/dist/slices/template-studio/quote.js +155 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +32 -0
- package/dist/slices/template-studio/schedule-sample.js +91 -0
- package/dist/slices/template-studio/schema.js +243 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +175 -0
- package/dist/slices/template-studio/status.js +191 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +169 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +4 -16
- package/dist/slices/youtube/edits-repo.js +3 -12
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +34 -33
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Backups.md +7 -7
- package/dist/tutorials/Calendar.md +17 -25
- package/dist/tutorials/Cast-Library.md +19 -19
- package/dist/tutorials/Channels.md +42 -35
- package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
- package/dist/tutorials/Create-Article.md +114 -0
- package/dist/tutorials/Create-Extras.md +112 -0
- package/dist/tutorials/Create-Images.md +165 -0
- package/dist/tutorials/Create-Narration.md +178 -0
- package/dist/tutorials/Create-Overview.md +244 -0
- package/dist/tutorials/Create-Video-and-Style.md +144 -0
- package/dist/tutorials/Docker.md +3 -3
- package/dist/tutorials/Document-Themes.md +32 -32
- package/dist/tutorials/Editing-a-Project.md +94 -94
- package/dist/tutorials/FAQ.md +18 -18
- package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
- package/dist/tutorials/Home-and-Projects.md +115 -71
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +14 -13
- package/dist/tutorials/Intros-and-Outros.md +33 -34
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +53 -21
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +27 -17
- package/dist/tutorials/Other-Languages.md +15 -15
- package/dist/tutorials/PDF-Documents.md +38 -29
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +48 -44
- package/dist/tutorials/Providers-and-Keys.md +105 -98
- package/dist/tutorials/Publishing-to-YouTube.md +31 -31
- package/dist/tutorials/Recovery-and-Retries.md +31 -31
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
- package/dist/tutorials/Schedules.md +46 -27
- package/dist/tutorials/Settings-Reference.md +194 -174
- package/dist/tutorials/Shorts.md +34 -33
- package/dist/tutorials/Start-at-Login.md +3 -3
- package/dist/tutorials/Studio-Extension.md +22 -24
- package/dist/tutorials/Template-Studio.md +128 -0
- package/dist/tutorials/Templates.md +51 -77
- package/dist/tutorials/Trash.md +4 -4
- package/dist/tutorials/Troubleshooting.md +44 -44
- package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
- package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
- package/dist/tutorials/Video-Editing.md +34 -34
- package/dist/tutorials/Where-Your-Files-Live.md +10 -10
- package/dist/tutorials/YouTube-Description.md +26 -26
- package/dist/tutorials/Your-First-Short.md +35 -35
- package/dist/tutorials/_Sidebar.md +19 -14
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-BNftKQrA.css +1 -0
- package/dist/web/assets/index-Cpa58woP.js +459 -0
- package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
- package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
- package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +6 -2
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -161
- package/dist/tutorials/Play-Narration.md +0 -167
- package/dist/tutorials/Play-Outputs.md +0 -109
- package/dist/tutorials/Play-Overview.md +0 -227
- package/dist/tutorials/Play-Title-and-Article.md +0 -136
- package/dist/tutorials/Play-Video-and-Style.md +0 -143
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
- package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
- package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
- package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
2
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
|
+
import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
|
|
2
4
|
import { outputPath } from "../storage/layout.js";
|
|
3
5
|
import { usesAmbientBed } from "../video/ambient-bed.js";
|
|
4
6
|
import { probeDurationMs } from "../video/ffmpeg.js";
|
|
@@ -17,25 +19,19 @@ export async function exportBed(deps, context, view) {
|
|
|
17
19
|
};
|
|
18
20
|
if (bed.source !== "upload")
|
|
19
21
|
return { source: { kind: "noise", preset: bed.source }, ...settings };
|
|
20
|
-
const fix =
|
|
22
|
+
const fix = `Choose another file under Ambient sound in ${editSettings.sound}, or pick Rain, Fireplace or Wind there instead.`;
|
|
21
23
|
const assetId = view.revision.content.ambientBed;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
.safeParse(assetId === undefined
|
|
25
|
-
? undefined
|
|
26
|
-
: deps.db
|
|
27
|
-
.prepare("SELECT path FROM project_assets WHERE project_id=? AND id=?")
|
|
28
|
-
.get(context.work.projectId, assetId));
|
|
29
|
-
if (!row.success)
|
|
24
|
+
const saved = assetId === undefined ? undefined : assetPathOrUndefined(deps, context.work.projectId, assetId);
|
|
25
|
+
if (saved === undefined)
|
|
30
26
|
throw new Error(`The ambient sound's audio file is no longer in the project. ${fix}`);
|
|
31
|
-
const path = outputPath(deps.paths, context.work.projectId,
|
|
27
|
+
const path = outputPath(deps.paths, context.work.projectId, saved);
|
|
32
28
|
let durationMs;
|
|
33
29
|
try {
|
|
34
30
|
durationMs = await probeDurationMs(deps.ffmpeg, path, context.signal, deps.log);
|
|
35
31
|
}
|
|
36
32
|
catch (error) {
|
|
37
33
|
context.signal.throwIfAborted();
|
|
38
|
-
throw new Error(`The ambient sound's audio file couldn't be read as audio (${
|
|
34
|
+
throw new Error(`The ambient sound's audio file couldn't be read as audio (${errorText(error)}). ${fix}`);
|
|
39
35
|
}
|
|
40
36
|
if (durationMs <= 0)
|
|
41
37
|
throw new Error(`The ambient sound's audio file holds no sound. ${fix}`);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { extname } from "node:path";
|
|
3
2
|
import { z } from "zod";
|
|
3
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
4
4
|
import { usesFigureCards, usesYoutubeDescription } from "../admission/rules.js";
|
|
5
5
|
import { captionFont, captionFontDeps } from "../fonts/coverage.js";
|
|
6
6
|
import { resolveFont } from "../fonts/index.js";
|
|
7
|
+
import { isReadyOutput, readyOutput } from "../revisions/view.js";
|
|
7
8
|
import { outputPath } from "../storage/layout.js";
|
|
8
9
|
import { headingChapters } from "../video/chapters.js";
|
|
9
10
|
import { sentenceCutPoints } from "../video/cuts.js";
|
|
10
11
|
import { usesChapterCards, usesNarrationCuts, videoEditOf, } from "../video/edit-settings.js";
|
|
11
12
|
import { probeDurationMs } from "../video/ffmpeg.js";
|
|
12
13
|
import { passageSpans } from "../video/figure-spans.js";
|
|
13
|
-
import {
|
|
14
|
+
import { readTimingWords } from "./runtime-subtitles.js";
|
|
14
15
|
// The containers an uploaded clip may come in; anything else in the images is a still.
|
|
15
16
|
const clipExtensions = new Set([".mp4", ".mov", ".m4v", ".webm", ".mkv"]);
|
|
16
17
|
export function isClipPath(path) {
|
|
@@ -19,7 +20,7 @@ export function isClipPath(path) {
|
|
|
19
20
|
export async function exportEdit(deps, context, view, images) {
|
|
20
21
|
const config = view.revision.config;
|
|
21
22
|
const order = view.revision.content.imageOrder;
|
|
22
|
-
const ready = (key) => view
|
|
23
|
+
const ready = (key) => readyOutput(view, { workKey: key });
|
|
23
24
|
// Clips: an animated image's clip first, then an uploaded clip in the image's own place.
|
|
24
25
|
const clips = [];
|
|
25
26
|
for (const [index, key] of order.entries()) {
|
|
@@ -109,15 +110,8 @@ async function titleFont(deps, config) {
|
|
|
109
110
|
...(config.titleStyle?.color === undefined ? {} : { color: config.titleStyle.color }),
|
|
110
111
|
};
|
|
111
112
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
row.available &&
|
|
115
|
-
row.state === "ready" &&
|
|
116
|
-
row.workKey === "subtitles:timing" &&
|
|
117
|
-
row.output.role === "subtitle_words");
|
|
118
|
-
if (timing === undefined)
|
|
119
|
-
throw new Error("The narration's word timing, which the video's cuts and chapter cards follow, is missing. Use More → Render the video again in the Video section, then Try again.");
|
|
120
|
-
return wordsSchema.parse(JSON.parse(readFileSync(outputPath(deps.paths, context.work.projectId, timing.output.path), "utf8"))).words;
|
|
113
|
+
function timingWords(deps, context, view) {
|
|
114
|
+
return readTimingWords(deps, context, view, "the video's cuts and chapter cards follow").words;
|
|
121
115
|
}
|
|
122
116
|
// The YouTube description's chapters when that step runs, the article's headings otherwise.
|
|
123
117
|
function chaptersOf(view, config, words) {
|
|
@@ -142,7 +136,7 @@ async function clipSeconds(deps, context, path, place) {
|
|
|
142
136
|
ms = 0;
|
|
143
137
|
}
|
|
144
138
|
if (!(ms > 0))
|
|
145
|
-
throw new Error(`Image ${String(place)} is a video clip Slopify can't read, so the video can't show it. Replace it with another clip or an image in
|
|
139
|
+
throw new Error(`Image ${String(place)} is a video clip Slopify can't read, so the video can't show it. Replace it with another clip or an image in ${editSettings.images}, then Try again.`);
|
|
146
140
|
return ms / 1000;
|
|
147
141
|
}
|
|
148
142
|
// Each card in the video's frame, shown where its description is spoken: the description's
|
|
@@ -150,9 +144,7 @@ async function clipSeconds(deps, context, path, place) {
|
|
|
150
144
|
// found in the timing is left out rather than shown at the wrong moment.
|
|
151
145
|
export function figureShots(deps, context, view, format = view.revision.config.format, words = timingWords(deps, context, view)) {
|
|
152
146
|
const cards = view.outputs
|
|
153
|
-
.filter((row) => row
|
|
154
|
-
row.available &&
|
|
155
|
-
row.state === "ready" &&
|
|
147
|
+
.filter((row) => isReadyOutput(row) &&
|
|
156
148
|
row.output.role === "figure_card" &&
|
|
157
149
|
row.workKey.startsWith("figure:card:") &&
|
|
158
150
|
(row.output.meta.format ?? view.revision.config.format) === format)
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { internalError } from "../../kernel/errors.js";
|
|
4
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
5
|
import { narrationAliasesOf, usesNarrationPreparation, usesPronunciationGlossary, } from "../admission/rules.js";
|
|
4
6
|
import { plainText } from "../article/plain.js";
|
|
5
7
|
import { splitEndMatter } from "../article/split.js";
|
|
6
8
|
import { usesLoudness } from "../loudness/model.js";
|
|
9
|
+
import { donePiece, isReadyOutput, readyOutput } from "../revisions/view.js";
|
|
7
10
|
import { outputPath } from "../storage/layout.js";
|
|
8
11
|
import { probeDurationMs } from "../video/ffmpeg.js";
|
|
9
12
|
import { audioTimeline } from "../video/plan.js";
|
|
@@ -17,11 +20,11 @@ export function exportSnapshot(deps, context, piece) {
|
|
|
17
20
|
.prepare("SELECT recipe_context FROM revision_work WHERE id=?")
|
|
18
21
|
.get(context.work.workId);
|
|
19
22
|
if (view === undefined || row === undefined)
|
|
20
|
-
throw new Error("
|
|
23
|
+
throw new Error(internalError("the project version being exported is missing"));
|
|
21
24
|
const plan = executionPlan(deps, view, savedCatalogue(row.recipe_context));
|
|
22
25
|
const recipe = plan.recipes.find((one) => one.key === piece.key && one.fingerprint === piece.fingerprint);
|
|
23
26
|
if (recipe === undefined || recipe.deferred || recipe.unresolved)
|
|
24
|
-
throw new Error("
|
|
27
|
+
throw new Error(internalError("the export no longer matches the project's saved inputs"));
|
|
25
28
|
return { view, plan };
|
|
26
29
|
}
|
|
27
30
|
export async function revisionAudio(deps, context, view,
|
|
@@ -45,25 +48,23 @@ export async function narrationAudio(deps, view, options = {}) {
|
|
|
45
48
|
const levelled = options.levelled === true && usesLoudness(config) && config.sources.audio === "generate";
|
|
46
49
|
const input = async (role) => {
|
|
47
50
|
const segment = role === "audio_body" ? "body" : role === "audio_intro" ? "intro" : "outro";
|
|
48
|
-
const row = view.outputs.find((one) => one
|
|
49
|
-
one.available &&
|
|
50
|
-
one.state === "ready" &&
|
|
51
|
+
const row = view.outputs.find((one) => isReadyOutput(one) &&
|
|
51
52
|
(levelled
|
|
52
53
|
? one.output.role === "audio_levelled" && one.workKey === levelKey(segment)
|
|
53
54
|
: one.output.role === role));
|
|
54
55
|
if (row === undefined && levelled)
|
|
55
|
-
throw new Error(`The levelled ${segment === "body" ? "narration" : segment} isn't finished yet, so the sound can't be exported at an even volume. Let the Narration stage finish (
|
|
56
|
+
throw new Error(`The levelled ${segment === "body" ? "narration" : segment} isn't finished yet, so the sound can't be exported at an even volume. Let the Narration stage finish (Continue the run, or Try again on Narration), then try this stage again; or turn off Level the volume in ${editSettings.sound}.`);
|
|
56
57
|
if (row === undefined)
|
|
57
58
|
return undefined;
|
|
58
59
|
const path = outputPath(deps.paths, view.revision.projectId, row.output.path);
|
|
59
60
|
const duration = row.output.durationMs ?? (await deps.measure(path));
|
|
60
61
|
if (!Number.isFinite(duration) || duration <= 0)
|
|
61
|
-
throw new Error(
|
|
62
|
+
throw new Error(`Slopify couldn't read the length of the narration audio, so the file may be damaged or empty. Press Make the narration again in the project's Narration section (or upload your audio file again in ${editSettings.narration}), then Try again.`);
|
|
62
63
|
return { path, seconds: duration / 1000 };
|
|
63
64
|
};
|
|
64
65
|
const body = await input("audio_body");
|
|
65
66
|
if (body === undefined)
|
|
66
|
-
throw new Error("The narration audio isn't finished yet. Let the Narration stage finish (
|
|
67
|
+
throw new Error("The narration audio isn't finished yet. Let the Narration stage finish (Continue the run, or Try again on Narration), then try this stage again.");
|
|
67
68
|
return narrationTimeline(config, {
|
|
68
69
|
body,
|
|
69
70
|
intro: speaksPart(config, "intro") ? await input("audio_intro") : undefined,
|
|
@@ -95,7 +96,7 @@ export function revisionTranscript(deps, snapshot, kind) {
|
|
|
95
96
|
const concat = plan.recipes.find((one) => one.key === (kind === "body" ? "audio:body:concat" : `audio:${kind}`));
|
|
96
97
|
if (concat !== undefined) {
|
|
97
98
|
const texts = concat.dependsOn.map((key) => {
|
|
98
|
-
const row = view
|
|
99
|
+
const row = donePiece(view, key);
|
|
99
100
|
const payload = row?.piece.payload === null || row?.piece.payload === undefined
|
|
100
101
|
? undefined
|
|
101
102
|
: z.object({ text: z.string().optional() }).parse(JSON.parse(row.piece.payload));
|
|
@@ -108,13 +109,13 @@ export function revisionTranscript(deps, snapshot, kind) {
|
|
|
108
109
|
Array.isArray(recipe.input.semantic) &&
|
|
109
110
|
typeof recipe.input.semantic[0] === "string")
|
|
110
111
|
return recipe.input.semantic[0];
|
|
111
|
-
throw new Error(
|
|
112
|
+
throw new Error(`Some narration chunks aren't finished, so the full narration text isn't available. Let the Narration stage finish (Continue the run, or Try again on Narration), or make the missing chunk again in ${editSettings.narration}.`);
|
|
112
113
|
});
|
|
113
114
|
if (texts.length > 0)
|
|
114
115
|
return texts.join("\n");
|
|
115
116
|
}
|
|
116
117
|
if (kind === "body") {
|
|
117
|
-
const row = view
|
|
118
|
+
const row = readyOutput(view, { role: "article_txt" });
|
|
118
119
|
if (row !== undefined)
|
|
119
120
|
return readFileSync(outputPath(deps.paths, view.revision.projectId, row.output.path), "utf8");
|
|
120
121
|
if (view.articleMarkdown !== null)
|
|
@@ -5,9 +5,9 @@ import { renderShort, shortFrame } from "../shorts/render.js";
|
|
|
5
5
|
import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
|
|
6
6
|
import { projectDir } from "../storage/layout.js";
|
|
7
7
|
import { probeDurationMs } from "../video/ffmpeg.js";
|
|
8
|
-
import { slideshowImages } from "./runtime-export.js";
|
|
8
|
+
import { exportMachine, slideshowImages, warningsOf, } from "./runtime-export.js";
|
|
9
9
|
import { preparedResult, preparedText, publishResult } from "./runtime-publication.js";
|
|
10
|
-
import {
|
|
10
|
+
import { readTimingWords } from "./runtime-subtitles.js";
|
|
11
11
|
// A short-mode project's video (`admission/short-mode.ts`): the whole narration timeline as
|
|
12
12
|
// one clip through the Shorts renderer, so it looks like every short Slopify cuts from a long
|
|
13
13
|
// video - the images moving as the project says, the title on top and big word-by-word
|
|
@@ -16,10 +16,10 @@ export async function executeShortExport(deps, context, piece, snapshot, timelin
|
|
|
16
16
|
const { view } = snapshot;
|
|
17
17
|
const config = view.revision.config;
|
|
18
18
|
const images = slideshowImages(deps, context, view);
|
|
19
|
-
const words =
|
|
19
|
+
const words = readTimingWords(deps, context, view, "the shorts are cut and captioned from").words;
|
|
20
20
|
const seconds = timeline.reduce((sum, segment) => sum + segment.seconds, 0);
|
|
21
21
|
if (seconds <= 0)
|
|
22
|
-
throw new Error("The short has no narration to play, so there is nothing to render. Let the Narration stage finish (
|
|
22
|
+
throw new Error("The short has no narration to play, so there is nothing to render. Let the Narration stage finish (Continue the run, or Try again on Narration), then try this stage again.");
|
|
23
23
|
const font = await resolveBoldFont(deps.paths, config.subtitles?.fontId ?? "default");
|
|
24
24
|
if (!context.maySubmit(piece.id))
|
|
25
25
|
return "held";
|
|
@@ -28,8 +28,11 @@ export async function executeShortExport(deps, context, piece, snapshot, timelin
|
|
|
28
28
|
const directory = projectDir(deps.paths, context.work.projectId);
|
|
29
29
|
const relativePath = (path) => relative(directory, path).split(sep).join("/");
|
|
30
30
|
try {
|
|
31
|
+
const machine = await exportMachine(deps, context.work.projectId);
|
|
31
32
|
const master = await renderShort({
|
|
32
33
|
bin: deps.ffmpeg,
|
|
34
|
+
machine: machine.machine,
|
|
35
|
+
notice: machine.notice,
|
|
33
36
|
master: masterGoal(config, "video"),
|
|
34
37
|
timeline,
|
|
35
38
|
start: 0,
|
|
@@ -58,6 +61,7 @@ export async function executeShortExport(deps, context, piece, snapshot, timelin
|
|
|
58
61
|
const asset = sealAsset(deps, pending);
|
|
59
62
|
prepared.push(preparedResult(deps, context, piece, "video", asset, durationMs, {
|
|
60
63
|
subtitlesMode: "off",
|
|
64
|
+
...warningsOf(machine.notices),
|
|
61
65
|
...(master === undefined ? {} : { master }),
|
|
62
66
|
}));
|
|
63
67
|
prepared.push(preparedText(deps, context, piece, "render_params", "render.json", JSON.stringify({
|
|
@@ -76,7 +80,7 @@ export async function executeShortExport(deps, context, piece, snapshot, timelin
|
|
|
76
80
|
output: pending.path,
|
|
77
81
|
})));
|
|
78
82
|
await publishResult(deps, context, piece, prepared, { totalSeconds: seconds }, asset);
|
|
79
|
-
deps.count?.("stage.completed", { stage: "video" });
|
|
83
|
+
deps.count?.("stage.completed", { stage: "video" }, context.work.projectId);
|
|
80
84
|
return "done";
|
|
81
85
|
}
|
|
82
86
|
finally {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
2
2
|
import { extname, join, relative, sep } from "node:path";
|
|
3
|
+
import { internalError } from "../../kernel/errors.js";
|
|
4
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
5
|
import { usesShortMode } from "../admission/short-mode.js";
|
|
4
6
|
import { masterFile, masterReport } from "../loudness/loudnorm.js";
|
|
5
7
|
import { masterGoal } from "../loudness/model.js";
|
|
8
|
+
import { isReadyOutput, readyOutput } from "../revisions/view.js";
|
|
6
9
|
import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
|
|
7
10
|
import { outputPath, projectDir, renderCacheDir } from "../storage/layout.js";
|
|
8
11
|
import { audioExportArgs } from "../video/audio-export.js";
|
|
@@ -18,10 +21,21 @@ import { exportSnapshot, retainedOutput, revisionAudio, } from "./runtime-export
|
|
|
18
21
|
import { executeShortExport } from "./runtime-export-short.js";
|
|
19
22
|
import { lineLevelledAudio } from "./runtime-lines.js";
|
|
20
23
|
import { preparedResult, preparedText, publishResult } from "./runtime-publication.js";
|
|
24
|
+
import { pieceAlreadyDone } from "./work-records.js";
|
|
25
|
+
// The machine settings for one render, and the notices it gathers for the project page.
|
|
26
|
+
export async function exportMachine(deps, projectId) {
|
|
27
|
+
const chosen = await deps.renderMachine?.(projectId);
|
|
28
|
+
const notices = chosen?.notice === undefined ? [] : [chosen.notice];
|
|
29
|
+
return {
|
|
30
|
+
machine: chosen?.machine,
|
|
31
|
+
notices,
|
|
32
|
+
notice: (sentence) => {
|
|
33
|
+
notices.push(sentence);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
21
37
|
export async function executeExportRecipe(deps, context, piece) {
|
|
22
|
-
if (deps.db
|
|
23
|
-
.prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
|
|
24
|
-
.get(piece.id, context.work.workId)?.state === "done")
|
|
38
|
+
if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
|
|
25
39
|
return "done";
|
|
26
40
|
if (!context.maySubmit(piece.id))
|
|
27
41
|
return "held";
|
|
@@ -31,9 +45,9 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
31
45
|
const audio = await revisionAudio(deps, context, view, { levelled: true });
|
|
32
46
|
const wav = piece.key === "export:wav";
|
|
33
47
|
if (!wav && piece.key !== "export:video")
|
|
34
|
-
throw new Error("
|
|
48
|
+
throw new Error(internalError("unknown kind of export"));
|
|
35
49
|
if (wav && audio.length === 0)
|
|
36
|
-
throw new Error(
|
|
50
|
+
throw new Error(`The audio export has nothing to export because narration is turned off for this project. Turn narration on (Narration source in ${editSettings.narration}), then Try again.`);
|
|
37
51
|
if (!wav && usesShortMode(view.revision.config))
|
|
38
52
|
return executeShortExport(deps, context, piece, snapshot, audio);
|
|
39
53
|
const filename = wav ? "audio.wav" : "video.mp4";
|
|
@@ -49,7 +63,7 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
49
63
|
const sound = linesDirectory === undefined
|
|
50
64
|
? audio
|
|
51
65
|
: await lineLevelledAudio(deps, context, view, audio, linesDirectory);
|
|
52
|
-
const captions = snapshot.view.outputs.filter((row) => row
|
|
66
|
+
const captions = snapshot.view.outputs.filter((row) => isReadyOutput(row) && row.workKey === "subtitles:files");
|
|
53
67
|
const burn = !wav && view.revision.config.subtitles?.mode === "burn-in";
|
|
54
68
|
if (burn)
|
|
55
69
|
directory = captionDirectory(deps, context, snapshot);
|
|
@@ -119,6 +133,8 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
119
133
|
};
|
|
120
134
|
if (!context.maySubmit(piece.id))
|
|
121
135
|
return "held";
|
|
136
|
+
const machine = await exportMachine(deps, context.work.projectId);
|
|
137
|
+
const priority = machine.machine?.priority;
|
|
122
138
|
const onProgress = (elapsedMs) => context.emit({
|
|
123
139
|
type: "stage.progress",
|
|
124
140
|
projectId: context.work.projectId,
|
|
@@ -139,10 +155,11 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
139
155
|
args: audioExportArgs(sound, mixed),
|
|
140
156
|
signal: context.signal,
|
|
141
157
|
log: deps.log,
|
|
158
|
+
priority,
|
|
142
159
|
onProgress,
|
|
143
160
|
});
|
|
144
161
|
if (goal !== undefined) {
|
|
145
|
-
const run = { bin: deps.ffmpeg, log: deps.log, signal: context.signal };
|
|
162
|
+
const run = { bin: deps.ffmpeg, log: deps.log, signal: context.signal, priority };
|
|
146
163
|
await masterFile(run, mixed, `${pending.absolutePath}.master.wav`, goal, {
|
|
147
164
|
sampleRate: 48000,
|
|
148
165
|
channels: 2,
|
|
@@ -167,6 +184,7 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
167
184
|
],
|
|
168
185
|
signal: context.signal,
|
|
169
186
|
log: deps.log,
|
|
187
|
+
priority,
|
|
170
188
|
onProgress: () => { },
|
|
171
189
|
});
|
|
172
190
|
master = await masterReport(run, pending.absolutePath, goal);
|
|
@@ -193,20 +211,21 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
193
211
|
log: deps.log,
|
|
194
212
|
onProgress,
|
|
195
213
|
...(goal === undefined ? {} : { master: goal }),
|
|
214
|
+
machine: machine.machine,
|
|
215
|
+
notice: machine.notice,
|
|
196
216
|
});
|
|
197
217
|
context.signal.throwIfAborted();
|
|
198
218
|
const asset = sealAsset(deps, pending);
|
|
199
219
|
prepared.push(preparedResult(deps, context, piece, wav ? "audio_export" : "video", asset, Math.round(totalSeconds * 1000), {
|
|
200
220
|
subtitlesMode: mode,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
: { warnings: edited.warnings }),
|
|
221
|
+
// An audio export encodes no picture, so the encoder's notice is not its to show.
|
|
222
|
+
...warningsOf([...(edited?.warnings ?? []), ...(wav ? [] : machine.notices)]),
|
|
204
223
|
...(master === undefined ? {} : { master }),
|
|
205
224
|
}));
|
|
206
225
|
prepared.push(preparedText(deps, context, piece, "render_params", "render.json", JSON.stringify(record)));
|
|
207
226
|
prepared.push(...captions.map((row) => retainedOutput(deps, view, row)));
|
|
208
227
|
await publishResult(deps, context, piece, prepared, { totalSeconds }, asset);
|
|
209
|
-
deps.count?.("stage.completed", { stage: "video" });
|
|
228
|
+
deps.count?.("stage.completed", { stage: "video" }, context.work.projectId);
|
|
210
229
|
return "done";
|
|
211
230
|
}
|
|
212
231
|
finally {
|
|
@@ -220,18 +239,18 @@ export async function executeExportRecipe(deps, context, piece) {
|
|
|
220
239
|
// The project's images in slideshow order, as files.
|
|
221
240
|
export function slideshowImages(deps, context, view) {
|
|
222
241
|
return view.revision.content.imageOrder.map((key) => {
|
|
223
|
-
const row = view
|
|
242
|
+
const row = readyOutput(view, { workKey: `image:${key}` });
|
|
224
243
|
if (row === undefined)
|
|
225
|
-
throw new Error(
|
|
244
|
+
throw new Error(`The video export can't find one of the slideshow images. Press Make this image again on it in the project's Images section (or replace it in ${editSettings.images}), then Try again.`);
|
|
226
245
|
return outputPath(deps.paths, context.work.projectId, row.output.path);
|
|
227
246
|
});
|
|
228
247
|
}
|
|
229
248
|
function captionDirectory(deps, context, snapshot) {
|
|
230
|
-
const find = (role) => snapshot.view
|
|
249
|
+
const find = (role) => readyOutput(snapshot.view, { role });
|
|
231
250
|
const ass = find("subtitle_ass");
|
|
232
251
|
const font = find("subtitle_font");
|
|
233
252
|
if (ass === undefined || font === undefined)
|
|
234
|
-
throw new Error(
|
|
253
|
+
throw new Error(`Burned-in captions are missing their caption file or font. Press Make the video again in the project's Video section (or choose the caption font again in ${editSettings.captions}), then Try again.`);
|
|
235
254
|
const directory = mkdtempSync(join(projectDir(deps.paths, context.work.projectId), "render-"));
|
|
236
255
|
try {
|
|
237
256
|
mkdirSync(join(directory, "fonts"), { mode: 0o700 });
|
|
@@ -244,3 +263,7 @@ function captionDirectory(deps, context, snapshot) {
|
|
|
244
263
|
throw error;
|
|
245
264
|
}
|
|
246
265
|
}
|
|
266
|
+
// What the video could not do as asked, for the project page; nothing when it did it all.
|
|
267
|
+
export function warningsOf(warnings) {
|
|
268
|
+
return warnings.length === 0 ? {} : { warnings };
|
|
269
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { internalError } from "../../kernel/errors.js";
|
|
4
5
|
import { captionFont, captionFontDeps } from "../fonts/coverage.js";
|
|
5
6
|
import { describedKinds } from "../narration/blocks.js";
|
|
6
7
|
import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
|
|
@@ -25,7 +26,7 @@ const values = z.object({
|
|
|
25
26
|
const frames = { "16:9": [1920, 1080], "9:16": [1080, 1920], "1:1": [1080, 1080] };
|
|
26
27
|
export async function executeFigureCard(deps, context, piece) {
|
|
27
28
|
if (piece.input.kind !== "local")
|
|
28
|
-
throw new Error("
|
|
29
|
+
throw new Error(internalError("a figure card step was set up wrongly"));
|
|
29
30
|
const card = values.parse(piece.input.values);
|
|
30
31
|
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
31
32
|
// The article's own picture for a figure, when the project has it as an upload.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
3
|
import { imageBlob } from "../channels/repo.js";
|
|
4
|
+
import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
|
|
4
5
|
import { outputPath } from "../storage/layout.js";
|
|
5
6
|
// The provider call an image step makes: its request, the effort when one is chosen and, while
|
|
6
7
|
// the project's Establishing image is on, that image's bytes as the visual reference.
|
|
@@ -22,27 +23,22 @@ function referenceImage(deps, projectId, input) {
|
|
|
22
23
|
if (input.reference === undefined)
|
|
23
24
|
return undefined;
|
|
24
25
|
// The step waits for the establishing image, so a missing one went away since.
|
|
25
|
-
const missing =
|
|
26
|
+
const missing = `The establishing image this image is drawn from is missing. Press Make the establishing image again in the project's Images section (or upload it again in ${editSettings.images}), then use Try again.`;
|
|
26
27
|
if (input.reference.assetId === null)
|
|
27
28
|
throw new Error(missing);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
.optional()
|
|
31
|
-
.parse(deps.db
|
|
32
|
-
.prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
|
|
33
|
-
.get(input.reference.assetId, projectId));
|
|
34
|
-
if (row === undefined)
|
|
29
|
+
const saved = assetPathOrUndefined(deps, projectId, input.reference.assetId);
|
|
30
|
+
if (saved === undefined)
|
|
35
31
|
throw new Error(missing);
|
|
36
32
|
let bytes;
|
|
37
33
|
try {
|
|
38
|
-
bytes = new Uint8Array(readFileSync(outputPath(deps.paths, projectId,
|
|
34
|
+
bytes = new Uint8Array(readFileSync(outputPath(deps.paths, projectId, saved)));
|
|
39
35
|
}
|
|
40
36
|
catch {
|
|
41
37
|
throw new Error(missing);
|
|
42
38
|
}
|
|
43
39
|
const mime = imageMime(bytes);
|
|
44
40
|
if (mime === undefined)
|
|
45
|
-
throw new Error(
|
|
41
|
+
throw new Error(`The establishing image is not a PNG or JPEG file, so it can't be sent as a reference. Upload a PNG or JPEG under Establishing image in ${editSettings.images}, then use Try again.`);
|
|
46
42
|
return { bytes, mime };
|
|
47
43
|
}
|
|
48
44
|
// The cast pictures the request names, read by hash from the database. They are never removed
|
|
@@ -56,7 +52,7 @@ function castImages(deps, input) {
|
|
|
56
52
|
images: member.images.map((sha256) => {
|
|
57
53
|
const blob = imageBlob(deps.db, sha256);
|
|
58
54
|
if (blob === undefined)
|
|
59
|
-
throw new Error(`A picture of ${member.name} that this project was started with is not in this Slopify's database, so it can't be sent as a reference. Add the picture again in Channels → Cast, then start the video again from
|
|
55
|
+
throw new Error(`A picture of ${member.name} that this project was started with is not in this Slopify's database, so it can't be sent as a reference. Add the picture again in Channels → Cast, then start the video again from Create.`);
|
|
60
56
|
return blob;
|
|
61
57
|
}),
|
|
62
58
|
}));
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
2
|
+
import { fillLateKeywords, mentionsLateKeyword } from "../keywords/fill.js";
|
|
3
|
+
import { durationText, releaseDateText } from "../keywords/values.js";
|
|
4
|
+
import { releasesOf } from "../studio/releases.js";
|
|
5
|
+
import { revisionAudio } from "./runtime-export-inputs.js";
|
|
6
|
+
import { executionView } from "./runtime-plan.js";
|
|
7
|
+
// The release date and the video's length are filled into a request only as it is sent: the
|
|
8
|
+
// planned request keeps `{{Slopify_Release_Date}}` and `{{Slopify_Duration}}`, so moving the
|
|
9
|
+
// date later, or a new length, never makes anything outdated. Every other call goes through as
|
|
10
|
+
// it was.
|
|
11
|
+
export function lateKeywordProviders(providers, values) {
|
|
12
|
+
let once;
|
|
13
|
+
const late = () => {
|
|
14
|
+
once ??= values();
|
|
15
|
+
return once;
|
|
16
|
+
};
|
|
17
|
+
const wrap = (inner) => ({
|
|
18
|
+
...inner,
|
|
19
|
+
llm: async (call, onEvent) => {
|
|
20
|
+
if (!call.messages.some((message) => mentionsLateKeyword(message.content)))
|
|
21
|
+
return inner.llm(call, onEvent);
|
|
22
|
+
const filled = await late();
|
|
23
|
+
return inner.llm({
|
|
24
|
+
...call,
|
|
25
|
+
messages: call.messages.map((message) => ({
|
|
26
|
+
...message,
|
|
27
|
+
content: fillLateKeywords(message.content, filled),
|
|
28
|
+
})),
|
|
29
|
+
}, onEvent);
|
|
30
|
+
},
|
|
31
|
+
image: async (call) => mentionsLateKeyword(call.prompt)
|
|
32
|
+
? inner.image({ ...call, prompt: fillLateKeywords(call.prompt, await late()) })
|
|
33
|
+
: inner.image(call),
|
|
34
|
+
forPiece: (pieceId) => wrap(inner.forPiece(pieceId)),
|
|
35
|
+
});
|
|
36
|
+
return wrap(providers);
|
|
37
|
+
}
|
|
38
|
+
// The long video's release time from the posting plan, and the narration's length once it is
|
|
39
|
+
// there. A length that can't be read yet (an article review runs before the narration) is
|
|
40
|
+
// blank, so its line is left out, and the reason is logged.
|
|
41
|
+
export async function lateValuesOf(deps, context) {
|
|
42
|
+
const releaseDate = releaseDateText(releasesOf(deps.db, context.work.projectId).find((release) => release.short === 0)?.at);
|
|
43
|
+
const view = executionView(deps, context.work.projectId, context.work.revisionId);
|
|
44
|
+
let duration;
|
|
45
|
+
if (view !== undefined && view.revision.config.sources.audio !== "off")
|
|
46
|
+
try {
|
|
47
|
+
const audio = await revisionAudio(deps, context, view);
|
|
48
|
+
const seconds = audio.reduce((sum, segment) => sum + segment.seconds, 0);
|
|
49
|
+
duration = seconds > 0 ? durationText(seconds) : undefined;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
deps.log.write("warn", "keywords.duration", {
|
|
53
|
+
projectId: context.work.projectId,
|
|
54
|
+
stage: context.work.kind,
|
|
55
|
+
detail: errorText(error),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return { releaseDate, duration };
|
|
59
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { join } from "node:path";
|
|
3
2
|
import { levelLines } from "../loudness/line-level.js";
|
|
4
|
-
import { outputPath } from "../storage/layout.js";
|
|
5
3
|
import { linesLevelled } from "./recipe-lines.js";
|
|
6
|
-
import {
|
|
4
|
+
import { readTimingWords } from "./runtime-subtitles.js";
|
|
7
5
|
// The sound a multi-voice run plays, with its body narration levelled line by line
|
|
8
6
|
// (`loudness/line-level.ts`) into `directory`, for the video, the audio export and the audio
|
|
9
7
|
// files alike. The words are timed on the timeline these segments lay out, so the body starts
|
|
@@ -11,14 +9,7 @@ import { wordsSchema } from "./runtime-subtitles.js";
|
|
|
11
9
|
export async function lineLevelledAudio(deps, context, view, audio, directory) {
|
|
12
10
|
if (!linesLevelled(view.revision.config))
|
|
13
11
|
return audio;
|
|
14
|
-
const
|
|
15
|
-
row.available &&
|
|
16
|
-
row.state === "ready" &&
|
|
17
|
-
row.workKey === "subtitles:timing" &&
|
|
18
|
-
row.output.role === "subtitle_words");
|
|
19
|
-
if (timing === undefined)
|
|
20
|
-
throw new Error("The narration's word timing, which evens out the speakers' volume, is missing. Use More → Render the video again in the Video section, then Try again.");
|
|
21
|
-
const { words } = wordsSchema.parse(JSON.parse(readFileSync(outputPath(deps.paths, context.work.projectId, timing.output.path), "utf8")));
|
|
12
|
+
const { words } = readTimingWords(deps, context, view, "evens out the speakers' volume");
|
|
22
13
|
const run = { bin: deps.ffmpeg, log: deps.log, signal: context.signal };
|
|
23
14
|
const levelled = [];
|
|
24
15
|
let offset = 0;
|