@gentbajko/slopify 3.25.9 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/cache.js +3 -5
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +0 -3
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/worker.js +2 -1
- package/dist/adapters/explain.js +0 -3
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +19 -3
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/codex.js +36 -4
- package/dist/adapters/image/fal.js +17 -50
- package/dist/adapters/image/google.js +31 -55
- package/dist/adapters/image/openai.js +20 -47
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +18 -47
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +53 -2
- package/dist/adapters/llm/antigravity.js +4 -0
- 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 +51 -98
- package/dist/adapters/llm/claude-code.js +13 -2
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/openrouter.js +10 -47
- package/dist/adapters/llm/run-cli.js +6 -22
- 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 +19 -40
- package/dist/adapters/tts/inworld-async.js +4 -1
- package/dist/adapters/tts/inworld.js +3 -0
- package/dist/adapters/tts/openai.js +20 -50
- 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 +3 -1
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +39 -0
- 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 +4 -25
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +85 -10
- package/dist/edge/http/assistant.js +127 -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 +1 -3
- package/dist/edge/http/channel-memory.js +7 -20
- package/dist/edge/http/channels.js +13 -26
- package/dist/edge/http/checkpoints.js +33 -17
- 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 +2 -11
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +4 -9
- 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 +38 -13
- 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 +1 -14
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +4 -12
- package/dist/edge/http/patch-notes.js +4 -10
- package/dist/edge/http/planning.js +2 -6
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +1 -0
- package/dist/edge/http/project-templates.js +29 -17
- package/dist/edge/http/projects.js +2 -12
- package/dist/edge/http/prompts.js +7 -14
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +39 -24
- 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 +11 -24
- package/dist/edge/http/revision-files.js +5 -10
- package/dist/edge/http/revisions.js +10 -15
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +59 -32
- package/dist/edge/http/settings.js +22 -13
- package/dist/edge/http/social.js +282 -0
- package/dist/edge/http/staging.js +2 -4
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +23 -23
- package/dist/edge/http/studio.js +23 -50
- package/dist/edge/http/style-preview.js +1 -4
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +433 -0
- package/dist/edge/http/trash.js +10 -11
- 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 +2 -3
- 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 +25 -0
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +5 -3
- package/dist/edge/mcp/library-tools.js +1 -0
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +2 -0
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +14 -2
- package/dist/edge/mcp/tools-planning.js +23 -4
- package/dist/edge/mcp/tools-projects.js +28 -1
- package/dist/edge/mcp/tools-runs.js +14 -1
- package/dist/edge/mcp/tools-schedules.js +28 -4
- package/dist/edge/mcp/tools-setup.js +61 -3
- package/dist/edge/mcp/tools-social.js +46 -0
- package/dist/edge/mcp/tools-storage.js +8 -0
- 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/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/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/runner/attempt.js +3 -1
- 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 +15 -10
- package/dist/kernel/runner/standalone.js +9 -5
- package/dist/main.js +334 -19
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/repo.js +2 -1
- package/dist/slices/admission/rules.js +43 -8
- 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/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 +79 -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 +342 -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 +4 -3
- package/dist/slices/channels/cast-images.js +2 -1
- 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 +6 -0
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +2 -14
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +0 -26
- 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 +128 -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 +222 -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/episodes/summarize.js +5 -1
- package/dist/slices/estimate/index.js +45 -7
- package/dist/slices/fonts/catalog.js +3 -2
- 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 +6 -15
- package/dist/slices/images/scenes.js +100 -27
- package/dist/slices/keywords/digest.js +84 -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 +2 -1
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +51 -11
- 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 +112 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/switch.js +70 -25
- package/dist/slices/model-upkeep/usage.js +26 -11
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +3 -2
- 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 +2 -1
- package/dist/slices/onboarding/copy.js +2 -1
- package/dist/slices/onboarding/first-run.js +3 -2
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +4 -3
- package/dist/slices/onboarding/model.js +0 -16
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/quick-short.js +2 -1
- package/dist/slices/onboarding/sample.js +0 -1
- package/dist/slices/onboarding/state.js +2 -11
- package/dist/slices/onboarding/template.js +2 -1
- package/dist/slices/patch-notes/library.js +3 -2
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/review-inputs.js +8 -2
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup.js +8 -0
- 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 +27 -9
- 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 +3 -3
- 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 +6 -3
- 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 +98 -28
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-work.js +15 -3
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +3 -2
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +2 -1
- 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 +9 -8
- package/dist/slices/rebuild/runtime-article.js +3 -2
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +8 -11
- package/dist/slices/rebuild/runtime-export-bed.js +6 -11
- package/dist/slices/rebuild/runtime-export-edit.js +6 -15
- package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
- package/dist/slices/rebuild/runtime-export-short.js +8 -4
- package/dist/slices/rebuild/runtime-export.js +34 -12
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +4 -9
- 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 +14 -20
- 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 +10 -15
- 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 +60 -19
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +33 -28
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +25 -45
- package/dist/slices/rebuild/runtime-store.js +3 -8
- package/dist/slices/rebuild/runtime-subtitles.js +16 -14
- package/dist/slices/rebuild/runtime-voices.js +8 -15
- package/dist/slices/rebuild/runtime-youtube.js +11 -29
- 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/reviews/external-model.js +3 -0
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/model.js +26 -8
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +1 -0
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/mutation-assets.js +7 -4
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +0 -1
- 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 +11 -2
- 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 +24 -16
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +54 -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 +48 -36
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +2 -11
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +10 -0
- package/dist/slices/settings/playback.js +33 -22
- 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/pick.js +2 -15
- package/dist/slices/shorts/prompts.js +2 -13
- package/dist/slices/shorts/render.js +3 -0
- 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 +131 -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 +55 -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 +128 -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 +20 -2
- 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 +16 -11
- 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 +10 -3
- package/dist/slices/studio/calendar.js +4 -1
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +6 -15
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +14 -51
- package/dist/slices/studio/videos.js +12 -0
- package/dist/slices/style-preview/render.js +34 -13
- package/dist/slices/style-preview/schema.js +13 -0
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- 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 +118 -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 +103 -0
- package/dist/slices/template-studio/checks.js +273 -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 +54 -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 +205 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +348 -0
- package/dist/slices/template-studio/quote.js +148 -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 +30 -0
- package/dist/slices/template-studio/schedule-sample.js +87 -0
- package/dist/slices/template-studio/schema.js +218 -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 +173 -0
- package/dist/slices/template-studio/status.js +174 -0
- package/dist/slices/template-studio/topic.js +223 -0
- 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/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/encoding.js +160 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/youtube/answer.js +2 -15
- package/dist/slices/youtube/edits-repo.js +2 -11
- package/dist/tutorials/Agents-MCP.md +2 -1
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Channels.md +2 -0
- package/dist/tutorials/Home-and-Projects.md +19 -0
- package/dist/tutorials/Install.md +1 -0
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +33 -1
- package/dist/tutorials/Notifications.md +6 -0
- package/dist/tutorials/Play-Images.md +4 -0
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Prompts.md +10 -6
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
- package/dist/tutorials/Schedules.md +21 -1
- package/dist/tutorials/Settings-Reference.md +50 -8
- package/dist/tutorials/Template-Studio.md +125 -0
- package/dist/tutorials/Templates.md +3 -0
- package/dist/tutorials/_Sidebar.md +5 -0
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-CkAI_2E7.css +1 -0
- package/dist/web/assets/index-DcD0cdfo.js +334 -0
- package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -1
- 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/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { transact } from "../../kernel/db/tx.js";
|
|
4
|
+
import { templateById } from "../project-templates/repo.js";
|
|
5
|
+
import { readJsonSetting, writeSetting } from "../settings/repo.js";
|
|
6
|
+
import { budgetWords } from "./budget.js";
|
|
7
|
+
import { enqueueJob, queuedJob, runningJob } from "./jobs.js";
|
|
8
|
+
import { quoteSample } from "./quote.js";
|
|
9
|
+
import { sampleOf, sampleVersions, setSampleVersion, upsertSample } from "./repo.js";
|
|
10
|
+
import { exceedsAcknowledged } from "./save.js";
|
|
11
|
+
import { withDependents } from "./sections.js";
|
|
12
|
+
import { defaultSampleTopic, templateSchedules } from "./service.js";
|
|
13
|
+
// The sample's topic and its full script, changed in the studio. Either remakes paid samples,
|
|
14
|
+
// so it is priced first and refused, with the new quote, at a higher price, unaccepted unknown
|
|
15
|
+
// prices or past today's budget, exactly as Save is.
|
|
16
|
+
const price = {
|
|
17
|
+
// The price the button showed for the change.
|
|
18
|
+
acknowledgedHigh: z.number().finite().min(0).max(10_000),
|
|
19
|
+
acknowledgedUnknown: z.boolean().optional(),
|
|
20
|
+
};
|
|
21
|
+
export const topicSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
// A topic typed by the person, "next-queued" (the next topic a schedule of this template
|
|
24
|
+
// has queued) or "fixed" (back to the topic every template's sample starts on).
|
|
25
|
+
topic: z.string().trim().min(1).max(300),
|
|
26
|
+
// The same id sent again (a retry after a lost answer) answers what it did the first time.
|
|
27
|
+
mutationId: z.uuid().optional(),
|
|
28
|
+
...price,
|
|
29
|
+
})
|
|
30
|
+
.strict()
|
|
31
|
+
.readonly();
|
|
32
|
+
export const fullScriptSchema = z
|
|
33
|
+
.object({ fullScript: z.boolean(), ...price })
|
|
34
|
+
.strict()
|
|
35
|
+
.readonly();
|
|
36
|
+
const money = (value) => `$${value.toFixed(2)}`;
|
|
37
|
+
// The topic a request names, with where it came from, or why there is none.
|
|
38
|
+
export function topicOf(deps, templateId, asked) {
|
|
39
|
+
if (asked === "fixed")
|
|
40
|
+
return { ok: true, topic: defaultSampleTopic(deps.db), source: "fixed" };
|
|
41
|
+
if (asked === "next-queued") {
|
|
42
|
+
const queued = templateSchedules(deps.db, templateId)
|
|
43
|
+
.flatMap((schedule) => schedule.items)
|
|
44
|
+
.find((item) => item.title.trim() !== "");
|
|
45
|
+
return queued === undefined
|
|
46
|
+
? {
|
|
47
|
+
ok: false,
|
|
48
|
+
message: "No schedule of this template has a topic queued. Add topics in Calendar → Schedules, or type a topic for the sample.",
|
|
49
|
+
}
|
|
50
|
+
: { ok: true, topic: queued.title.trim(), source: "queued" };
|
|
51
|
+
}
|
|
52
|
+
return { ok: true, topic: asked, source: "fixed" };
|
|
53
|
+
}
|
|
54
|
+
async function change(deps, id, next, sections, ack, kind) {
|
|
55
|
+
const template = templateById(deps.db, id);
|
|
56
|
+
if (template === undefined)
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
reason: "not-found",
|
|
60
|
+
message: "This template no longer exists; it may have been deleted. Go to Library → Templates to see your templates.",
|
|
61
|
+
};
|
|
62
|
+
const quoted = await quoteSample(deps, id, {
|
|
63
|
+
topic: next.topic,
|
|
64
|
+
fullScript: next.fullScript,
|
|
65
|
+
sections,
|
|
66
|
+
});
|
|
67
|
+
if (!quoted.ok)
|
|
68
|
+
return quoted;
|
|
69
|
+
const quote = quoted.value;
|
|
70
|
+
const value = { topic: next.topic, topicSource: next.source, fullScript: next.fullScript, quote };
|
|
71
|
+
// A second press (a double click) of what the sample is already made, or being made, of:
|
|
72
|
+
// nothing more is made or spent.
|
|
73
|
+
if (alreadyMade(deps, id, template.version, next))
|
|
74
|
+
return { ok: true, value };
|
|
75
|
+
if (quote.problem !== null)
|
|
76
|
+
return { ok: false, reason: "invalid-input", message: quote.problem, quote };
|
|
77
|
+
if (exceedsAcknowledged(quote.high, ack.acknowledgedHigh))
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
reason: "cost-changed",
|
|
81
|
+
message: `This change now costs about ${money(quote.high)}, more than the ${money(ack.acknowledgedHigh)} you saw. Press it again to accept the new price.`,
|
|
82
|
+
quote,
|
|
83
|
+
};
|
|
84
|
+
if (quote.unknown > 0 && ack.acknowledgedUnknown !== true)
|
|
85
|
+
return {
|
|
86
|
+
ok: false,
|
|
87
|
+
reason: "cost-changed",
|
|
88
|
+
message: `${String(quote.unknown)} ${quote.unknown === 1 ? "step of this sample has" : "steps of this sample have"} no known price. Tick that you accept unknown costs, then press it again.`,
|
|
89
|
+
quote,
|
|
90
|
+
};
|
|
91
|
+
if (!quote.fits)
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
reason: "over-budget",
|
|
95
|
+
message: `${budgetWords(quote.budget, quote, "This")}, or try again tomorrow.`,
|
|
96
|
+
quote,
|
|
97
|
+
};
|
|
98
|
+
const at = deps.clock.now().toISOString();
|
|
99
|
+
transact(deps.db, () => {
|
|
100
|
+
const record = sampleOf(deps.db, id);
|
|
101
|
+
// A template with no sample yet keeps the topic for its first one, under the id its
|
|
102
|
+
// project will get.
|
|
103
|
+
upsertSample(deps.db, id, {
|
|
104
|
+
projectId: record?.projectId ?? deps.review.ids.next(),
|
|
105
|
+
topic: next.topic,
|
|
106
|
+
topicSource: next.source,
|
|
107
|
+
fullScript: next.fullScript,
|
|
108
|
+
at,
|
|
109
|
+
});
|
|
110
|
+
setSampleVersion(deps.db, id, template.version, {
|
|
111
|
+
state: "queued",
|
|
112
|
+
at,
|
|
113
|
+
quotedHigh: quote.high,
|
|
114
|
+
heldReason: null,
|
|
115
|
+
});
|
|
116
|
+
if (ack.acknowledgedUnknown === true || quote.unknown === 0)
|
|
117
|
+
deps.acks.accept(id, template.version);
|
|
118
|
+
enqueueJob(deps.db, {
|
|
119
|
+
templateId: id,
|
|
120
|
+
templateVersion: template.version,
|
|
121
|
+
ackHigh: ack.acknowledgedHigh,
|
|
122
|
+
kind,
|
|
123
|
+
requestedAt: at,
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
return { ok: true, value };
|
|
127
|
+
}
|
|
128
|
+
function alreadyMade(deps, id, version, next) {
|
|
129
|
+
const record = sampleOf(deps.db, id);
|
|
130
|
+
if (record === undefined ||
|
|
131
|
+
record.topic !== next.topic ||
|
|
132
|
+
record.topicSource !== next.source ||
|
|
133
|
+
record.fullScript !== next.fullScript)
|
|
134
|
+
return false;
|
|
135
|
+
const job = queuedJob(deps.db, id) ?? runningJob(deps.db);
|
|
136
|
+
if (job !== undefined &&
|
|
137
|
+
job.templateId === id &&
|
|
138
|
+
job.templateVersion === version &&
|
|
139
|
+
job.kind !== "free")
|
|
140
|
+
return true;
|
|
141
|
+
const state = sampleVersions(deps.db, id).find((one) => one.templateVersion === version)?.state;
|
|
142
|
+
return state === "queued" || state === "making" || state === "done";
|
|
143
|
+
}
|
|
144
|
+
// PUT /:id/topic: a new topic remakes every section's sample.
|
|
145
|
+
export async function setSampleTopic(deps, id, raw) {
|
|
146
|
+
const parsed = topicSchema.safeParse(raw);
|
|
147
|
+
if (!parsed.success)
|
|
148
|
+
return {
|
|
149
|
+
ok: false,
|
|
150
|
+
reason: "invalid-input",
|
|
151
|
+
message: "Type a topic of 1 to 300 characters for the sample, then press Use topic.",
|
|
152
|
+
};
|
|
153
|
+
const { mutationId, ...ask } = parsed.data;
|
|
154
|
+
const hash = createHash("sha256").update(JSON.stringify(ask)).digest("hex");
|
|
155
|
+
const key = `${topicMutationKey}${id}`;
|
|
156
|
+
const last = readJsonSetting(deps.db, key, topicMutationSchema, null);
|
|
157
|
+
if (mutationId !== undefined && last?.mutationId === mutationId) {
|
|
158
|
+
if (last.hash !== hash)
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
reason: "conflict",
|
|
162
|
+
message: "This topic change was already sent with another topic or price. Reload the studio to see the sample's topic, then change it again.",
|
|
163
|
+
};
|
|
164
|
+
const replayed = await quoteSample(deps, id, {
|
|
165
|
+
topic: last.topic,
|
|
166
|
+
fullScript: last.fullScript,
|
|
167
|
+
sections: "all",
|
|
168
|
+
});
|
|
169
|
+
if (!replayed.ok)
|
|
170
|
+
return replayed;
|
|
171
|
+
return {
|
|
172
|
+
ok: true,
|
|
173
|
+
value: {
|
|
174
|
+
topic: last.topic,
|
|
175
|
+
topicSource: last.topicSource,
|
|
176
|
+
fullScript: last.fullScript,
|
|
177
|
+
quote: replayed.value,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const named = topicOf(deps, id, ask.topic);
|
|
182
|
+
if (!named.ok)
|
|
183
|
+
return { ok: false, reason: "invalid-input", message: named.message };
|
|
184
|
+
const record = sampleOf(deps.db, id);
|
|
185
|
+
const result = await change(deps, id, { topic: named.topic, source: named.source, fullScript: record?.fullScript ?? false }, "all", ask, "topic");
|
|
186
|
+
if (result.ok && mutationId !== undefined)
|
|
187
|
+
writeSetting(deps.db, key, JSON.stringify({
|
|
188
|
+
mutationId,
|
|
189
|
+
hash,
|
|
190
|
+
topic: named.topic,
|
|
191
|
+
topicSource: named.source,
|
|
192
|
+
fullScript: record?.fullScript ?? false,
|
|
193
|
+
}));
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
// The last topic change of each template that named a mutation id, to answer its retry.
|
|
197
|
+
const topicMutationKey = "templateStudio.topicMutation.";
|
|
198
|
+
const topicMutationSchema = z
|
|
199
|
+
.object({
|
|
200
|
+
mutationId: z.string(),
|
|
201
|
+
hash: z.string(),
|
|
202
|
+
topic: z.string(),
|
|
203
|
+
topicSource: z.enum(["fixed", "queued"]),
|
|
204
|
+
fullScript: z.boolean(),
|
|
205
|
+
})
|
|
206
|
+
.nullable();
|
|
207
|
+
// POST /:id/full-script: the whole script, or back to the outline and first chapter, remakes
|
|
208
|
+
// the script and what is made from it.
|
|
209
|
+
export async function setFullScript(deps, id, raw) {
|
|
210
|
+
const parsed = fullScriptSchema.safeParse(raw);
|
|
211
|
+
if (!parsed.success)
|
|
212
|
+
return {
|
|
213
|
+
ok: false,
|
|
214
|
+
reason: "invalid-input",
|
|
215
|
+
message: "The studio sent a request Slopify couldn't read. Reload the page and try again.",
|
|
216
|
+
};
|
|
217
|
+
const record = sampleOf(deps.db, id);
|
|
218
|
+
return change(deps, id, {
|
|
219
|
+
topic: record?.topic ?? defaultSampleTopic(deps.db),
|
|
220
|
+
source: record?.topicSource ?? "fixed",
|
|
221
|
+
fullScript: parsed.data.fullScript,
|
|
222
|
+
}, withDependents(["script"]), parsed.data, "full-script");
|
|
223
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { transact } from "../../kernel/db/tx.js";
|
|
2
|
+
import { deleteRenders } from "../designs/render.js";
|
|
3
|
+
// Designs and design templates in the trash. A design keeps its stamp in its own `deleted_at`;
|
|
4
|
+
// removing it for good removes its versions (they cascade) and every file drawn from it. The
|
|
5
|
+
// pictures stay in image_blobs, as a cast member's do: a schedule run or another design may
|
|
6
|
+
// still name them. A template's hidden sample goes with the template.
|
|
7
|
+
export function trashDesign(deps, id) {
|
|
8
|
+
const changed = deps.db
|
|
9
|
+
.prepare("UPDATE designs SET deleted_at=?, updated_at=? WHERE id=? AND deleted_at IS NULL AND sample_of IS NULL")
|
|
10
|
+
.run(deps.clock.now().toISOString(), deps.clock.now().toISOString(), id).changes;
|
|
11
|
+
return Number(changed) === 0 ? { ok: false, reason: "not-found" } : { ok: true, value: null };
|
|
12
|
+
}
|
|
13
|
+
export function trashDesignTemplate(deps, id) {
|
|
14
|
+
const changed = deps.db
|
|
15
|
+
.prepare("UPDATE design_templates SET deleted_at=? WHERE id=? AND deleted_at IS NULL")
|
|
16
|
+
.run(deps.clock.now().toISOString(), id).changes;
|
|
17
|
+
return Number(changed) === 0 ? { ok: false, reason: "not-found" } : { ok: true, value: null };
|
|
18
|
+
}
|
|
19
|
+
export function restoreDesign(deps, id) {
|
|
20
|
+
const found = deps.db
|
|
21
|
+
.prepare("SELECT name FROM designs WHERE id=? AND deleted_at IS NOT NULL")
|
|
22
|
+
.get(id);
|
|
23
|
+
if (typeof found?.name !== "string")
|
|
24
|
+
return { ok: false, reason: "not-found" };
|
|
25
|
+
deps.db
|
|
26
|
+
.prepare("UPDATE designs SET deleted_at=NULL, updated_at=? WHERE id=?")
|
|
27
|
+
.run(deps.clock.now().toISOString(), id);
|
|
28
|
+
return { ok: true, value: { kind: "design", id, name: found.name, renamedFrom: null } };
|
|
29
|
+
}
|
|
30
|
+
export function restoreDesignTemplate(deps, id) {
|
|
31
|
+
const found = deps.db
|
|
32
|
+
.prepare(`SELECT r.name FROM design_templates t
|
|
33
|
+
JOIN design_template_revisions r ON r.template_id = t.id AND r.version = t.head_version
|
|
34
|
+
WHERE t.id=? AND t.deleted_at IS NOT NULL`)
|
|
35
|
+
.get(id);
|
|
36
|
+
if (typeof found?.name !== "string")
|
|
37
|
+
return { ok: false, reason: "not-found" };
|
|
38
|
+
deps.db.prepare("UPDATE design_templates SET deleted_at=NULL WHERE id=?").run(id);
|
|
39
|
+
return { ok: true, value: { kind: "design-template", id, name: found.name, renamedFrom: null } };
|
|
40
|
+
}
|
|
41
|
+
export function deleteDesignNow(deps, id) {
|
|
42
|
+
const changed = deps.db
|
|
43
|
+
.prepare("DELETE FROM designs WHERE id=? AND deleted_at IS NOT NULL")
|
|
44
|
+
.run(id).changes;
|
|
45
|
+
if (Number(changed) === 0)
|
|
46
|
+
return { ok: false, reason: "not-found" };
|
|
47
|
+
deleteRenders(deps.paths, id);
|
|
48
|
+
return { ok: true, value: null };
|
|
49
|
+
}
|
|
50
|
+
export function deleteDesignTemplateNow(deps, id) {
|
|
51
|
+
const samples = transact(deps.db, () => {
|
|
52
|
+
const changed = deps.db
|
|
53
|
+
.prepare("DELETE FROM design_templates WHERE id=? AND deleted_at IS NOT NULL")
|
|
54
|
+
.run(id).changes;
|
|
55
|
+
if (Number(changed) === 0)
|
|
56
|
+
return undefined;
|
|
57
|
+
const ids = deps.db
|
|
58
|
+
.prepare("SELECT id FROM designs WHERE sample_of=?")
|
|
59
|
+
.all(id)
|
|
60
|
+
.map((row) => String(row.id));
|
|
61
|
+
deps.db.prepare("DELETE FROM designs WHERE sample_of=?").run(id);
|
|
62
|
+
return ids;
|
|
63
|
+
});
|
|
64
|
+
if (samples === undefined)
|
|
65
|
+
return { ok: false, reason: "not-found" };
|
|
66
|
+
for (const sample of samples)
|
|
67
|
+
deleteRenders(deps.paths, sample);
|
|
68
|
+
return { ok: true, value: null };
|
|
69
|
+
}
|
|
70
|
+
export const trashedDesignRows = `
|
|
71
|
+
UNION ALL SELECT 'design', id, name, kind, deleted_at FROM designs
|
|
72
|
+
WHERE deleted_at IS NOT NULL AND sample_of IS NULL
|
|
73
|
+
UNION ALL SELECT 'design-template', t.id, r.name, NULL, t.deleted_at
|
|
74
|
+
FROM design_templates t
|
|
75
|
+
JOIN design_template_revisions r ON r.template_id = t.id AND r.version = t.head_version
|
|
76
|
+
WHERE t.deleted_at IS NOT NULL`;
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
// Settings → Trash. Deleting a project, a Library prompt or intro/outro, a template
|
|
3
|
-
// schedule stamps it instead of removing it; it stays here this long, then the daily purge
|
|
2
|
+
// Settings → Trash. Deleting a project, a Library prompt or intro/outro, a template, a
|
|
3
|
+
// schedule, a design or a design template stamps it instead of removing it; it stays here this long, then the daily purge
|
|
4
4
|
// removes it for good (a project's folder with it).
|
|
5
5
|
export const trashDays = 30;
|
|
6
6
|
export const trashMs = trashDays * 24 * 60 * 60_000;
|
|
7
|
-
export const trashKinds = [
|
|
7
|
+
export const trashKinds = [
|
|
8
|
+
"project",
|
|
9
|
+
"prompt",
|
|
10
|
+
"entry",
|
|
11
|
+
"template",
|
|
12
|
+
"schedule",
|
|
13
|
+
"design",
|
|
14
|
+
"design-template",
|
|
15
|
+
];
|
|
8
16
|
export const trashItemSchema = z.object({
|
|
9
17
|
kind: z.enum(trashKinds),
|
|
10
18
|
id: z.string(),
|
|
11
19
|
name: z.string(),
|
|
12
|
-
// What sort of prompt ("article", "image"…)
|
|
20
|
+
// What sort of prompt ("article", "image"…), entry ("intro", "outro") or design ("edit",
|
|
21
|
+
// "design"); null otherwise.
|
|
13
22
|
detail: z.string().nullable(),
|
|
14
23
|
deletedAt: z.string(),
|
|
15
24
|
// When the daily purge removes it for good.
|
|
@@ -4,6 +4,11 @@ import { deleteVersions, recordVersion } from "../library/history.js";
|
|
|
4
4
|
import { nameMax } from "../library/model.js";
|
|
5
5
|
import { entryById, promptById } from "../library/repo.js";
|
|
6
6
|
import { deleteProject, projectBusy } from "../storage/delete-project.js";
|
|
7
|
+
import { bakeoffOf, clonesOf } from "../template-studio/bakeoff-repo.js";
|
|
8
|
+
import { removeHiddenProject } from "../template-studio/hidden.js";
|
|
9
|
+
import { removePackSamples } from "../template-studio/pack-samples.js";
|
|
10
|
+
import { carryGateOnto, notTemplateSample, sampleOf } from "../template-studio/repo.js";
|
|
11
|
+
import { deleteDesignNow, deleteDesignTemplateNow, restoreDesign, restoreDesignTemplate, trashedDesignRows, } from "./designs.js";
|
|
7
12
|
import { trashKinds, trashMs, } from "./model.js";
|
|
8
13
|
// Settings → Trash: what was deleted in the last 30 days, put back or removed for good.
|
|
9
14
|
//
|
|
@@ -24,6 +29,7 @@ const row = z.object({
|
|
|
24
29
|
const trashedRows = `
|
|
25
30
|
SELECT 'project' AS kind, p.id, p.title AS name, NULL AS detail, t.deleted_at
|
|
26
31
|
FROM project_trash t JOIN projects p ON p.id = t.project_id
|
|
32
|
+
WHERE ${notTemplateSample("p")}
|
|
27
33
|
UNION ALL SELECT 'prompt', id, name, kind, deleted_at FROM prompts WHERE deleted_at IS NOT NULL
|
|
28
34
|
UNION ALL SELECT 'entry', id, name, category, deleted_at FROM entries WHERE deleted_at IS NOT NULL
|
|
29
35
|
UNION ALL SELECT 'template', t.id, r.name, NULL, t.deleted_at
|
|
@@ -31,7 +37,7 @@ const trashedRows = `
|
|
|
31
37
|
JOIN project_template_revisions r ON r.template_id = t.id AND r.version = t.head_version
|
|
32
38
|
WHERE t.deleted_at IS NOT NULL
|
|
33
39
|
UNION ALL SELECT 'schedule', id, name, NULL, deleted_at FROM schedules
|
|
34
|
-
WHERE deleted_at IS NOT NULL AND purged_at IS NULL`;
|
|
40
|
+
WHERE deleted_at IS NOT NULL AND purged_at IS NULL${trashedDesignRows}`;
|
|
35
41
|
export function listTrash(deps) {
|
|
36
42
|
const now = deps.clock.now().valueOf();
|
|
37
43
|
return deps.db
|
|
@@ -90,6 +96,10 @@ export function restoreItem(deps, kind, id) {
|
|
|
90
96
|
return restoreTemplate(deps, id);
|
|
91
97
|
case "schedule":
|
|
92
98
|
return restoreSchedule(deps, id);
|
|
99
|
+
case "design":
|
|
100
|
+
return restoreDesign(deps, id);
|
|
101
|
+
case "design-template":
|
|
102
|
+
return restoreDesignTemplate(deps, id);
|
|
93
103
|
}
|
|
94
104
|
});
|
|
95
105
|
}
|
|
@@ -151,6 +161,8 @@ function restoreTemplate(deps, id) {
|
|
|
151
161
|
.prepare("INSERT INTO project_template_revisions(template_id,version,name,document_json,created_at) VALUES (?,?,?,?,?)")
|
|
152
162
|
.run(id, version, name, found.document_json, deps.clock.now().toISOString());
|
|
153
163
|
deps.db.prepare("UPDATE project_templates SET head_version = ? WHERE id = ?").run(version, id);
|
|
164
|
+
// Only the name changed: a schedule running the version it was keeps running.
|
|
165
|
+
carryGateOnto(deps.db, id, found.version, version);
|
|
154
166
|
}
|
|
155
167
|
return {
|
|
156
168
|
ok: true,
|
|
@@ -210,12 +222,46 @@ export function deleteNow(deps, kind, id) {
|
|
|
210
222
|
return { ok: true, value: null };
|
|
211
223
|
});
|
|
212
224
|
case "template": {
|
|
225
|
+
if (deps.db
|
|
226
|
+
.prepare("SELECT 1 FROM project_templates WHERE id = ? AND deleted_at IS NOT NULL")
|
|
227
|
+
.get(id) === undefined)
|
|
228
|
+
return { ok: false, reason: "not-found" };
|
|
229
|
+
// Its studio sample goes first, folder and all, while its row still says the folder is
|
|
230
|
+
// in the data dir; a sample still being made keeps the template in the trash.
|
|
231
|
+
const sample = sampleOf(deps.db, id);
|
|
232
|
+
if (sample !== undefined) {
|
|
233
|
+
const removed = removeHiddenProject(deps, sample.projectId);
|
|
234
|
+
if (!removed.ok && removed.reason !== "no-project")
|
|
235
|
+
return {
|
|
236
|
+
ok: false,
|
|
237
|
+
reason: removed.reason,
|
|
238
|
+
...(removed.detail === undefined ? {} : { detail: removed.detail }),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// Its bake-off copies go the same way: their rows go with the template, and a copy
|
|
242
|
+
// left behind would show up as an ordinary project.
|
|
243
|
+
const bakeoff = bakeoffOf(deps.db, id);
|
|
244
|
+
for (const clone of bakeoff === undefined ? [] : clonesOf(deps.db, bakeoff.id)) {
|
|
245
|
+
if (clone.projectId === null)
|
|
246
|
+
continue;
|
|
247
|
+
const removed = removeHiddenProject(deps, clone.projectId);
|
|
248
|
+
if (!removed.ok && removed.reason !== "no-project")
|
|
249
|
+
return {
|
|
250
|
+
ok: false,
|
|
251
|
+
reason: removed.reason,
|
|
252
|
+
...(removed.detail === undefined ? {} : { detail: removed.detail }),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
213
255
|
// Revisions cascade. A schedule in the trash may still name it: that schedule can then
|
|
214
256
|
// no longer be restored (`restoreSchedule`), only removed.
|
|
215
257
|
const changed = deps.db
|
|
216
258
|
.prepare("DELETE FROM project_templates WHERE id = ? AND deleted_at IS NOT NULL")
|
|
217
259
|
.run(id).changes;
|
|
218
|
-
|
|
260
|
+
if (Number(changed) === 0)
|
|
261
|
+
return { ok: false, reason: "not-found" };
|
|
262
|
+
// The samples an imported pack came with go with it.
|
|
263
|
+
removePackSamples(deps.paths, id);
|
|
264
|
+
return { ok: true, value: null };
|
|
219
265
|
}
|
|
220
266
|
case "schedule": {
|
|
221
267
|
// Gone from the trash; the row stays as the history Schedules lists under Deleted.
|
|
@@ -224,6 +270,10 @@ export function deleteNow(deps, kind, id) {
|
|
|
224
270
|
.run(deps.clock.now().toISOString(), id).changes;
|
|
225
271
|
return Number(changed) === 0 ? { ok: false, reason: "not-found" } : { ok: true, value: null };
|
|
226
272
|
}
|
|
273
|
+
case "design":
|
|
274
|
+
return deleteDesignNow(deps, id);
|
|
275
|
+
case "design-template":
|
|
276
|
+
return deleteDesignTemplateNow(deps, id);
|
|
227
277
|
}
|
|
228
278
|
}
|
|
229
279
|
// The daily purge: everything deleted more than 30 days ago goes for good. A failure on one
|
|
@@ -2,6 +2,7 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { readdir, readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { hasErrnoCode } from "../../kernel/errors.js";
|
|
5
6
|
import { pageTitleOf, tutorialHeadings, tutorialPageIdPattern } from "./anchors.js";
|
|
6
7
|
// dist/tutorials when running the build; the repository's docs/wiki when running from source
|
|
7
8
|
// (tests, `tsx`).
|
|
@@ -43,7 +44,7 @@ export async function loadTutorials(dir) {
|
|
|
43
44
|
names = await readdir(dir);
|
|
44
45
|
}
|
|
45
46
|
catch (error) {
|
|
46
|
-
if (error
|
|
47
|
+
if (hasErrnoCode(error, "ENOENT"))
|
|
47
48
|
throw new TutorialsMissing("This copy of Slopify has no tutorials: its docs/wiki folder is missing. Reinstall Slopify (or run npm run build) and reload the page.");
|
|
48
49
|
throw error;
|
|
49
50
|
}
|
|
@@ -57,7 +58,7 @@ export async function loadTutorials(dir) {
|
|
|
57
58
|
if (!pages.has("Home"))
|
|
58
59
|
throw new TutorialsMissing("This copy of Slopify has damaged tutorials: docs/wiki/Home.md is missing. Reinstall Slopify (or run npm run build) and reload the page.");
|
|
59
60
|
const extra = async (name) => readFile(join(dir, name), "utf8").catch((error) => {
|
|
60
|
-
if (error
|
|
61
|
+
if (hasErrnoCode(error, "ENOENT"))
|
|
61
62
|
return "";
|
|
62
63
|
throw error;
|
|
63
64
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Text as libass draws it literally: braces and backslashes escaped rather than read as
|
|
2
|
+
// override tags; code keeps its spaces, prose has them collapsed. Shared by the figure cards
|
|
3
|
+
// and the designs' text layer, so a name, date or price is drawn exactly as typed.
|
|
4
|
+
export function assText(value, keepSpaces = false) {
|
|
5
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/\{/g, "\\{").replace(/\}/g, "\\}");
|
|
6
|
+
return keepSpaces
|
|
7
|
+
? escaped.replace(/ {2,}/g, (run) => "\\h".repeat(run.length))
|
|
8
|
+
: escaped.replace(/\s+/g, " ");
|
|
9
|
+
}
|
|
10
|
+
// #RRGGBB as ASS writes a colour: &HBBGGRR&. Anything else draws white.
|
|
11
|
+
export function assColour(hex) {
|
|
12
|
+
const match = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/.exec(hex);
|
|
13
|
+
if (match === null)
|
|
14
|
+
return "&HFFFFFF&";
|
|
15
|
+
const [, r, g, b] = match;
|
|
16
|
+
return `&H${(b ?? "").toUpperCase()}${(g ?? "").toUpperCase()}${(r ?? "").toUpperCase()}&`;
|
|
17
|
+
}
|
|
@@ -1,65 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { relative } from "node:path";
|
|
4
|
-
import { outputPath, projectDir } from "../storage/layout.js";
|
|
5
|
-
import { outputsOf } from "../storage/repo.js";
|
|
6
|
-
import { prepareSubtitles } from "../subtitles/prepare.js";
|
|
7
|
-
import { audioExportArgs } from "./audio-export-args.js";
|
|
8
|
-
import { audioInputs } from "./audio-inputs.js";
|
|
9
|
-
import { runFfmpeg } from "./ffmpeg.js";
|
|
10
|
-
import { audioTimeline } from "./plan.js";
|
|
11
|
-
import { reusableAudioExport } from "./reuse-audio.js";
|
|
12
|
-
import { writeExport } from "./write-export.js";
|
|
13
|
-
import { writeSubtitles } from "./write-subtitles.js";
|
|
1
|
+
// `rebuild/runtime-export.ts` still imports the arguments from here; new code imports
|
|
2
|
+
// `audio-export-args.ts`.
|
|
14
3
|
export { audioExportArgs } from "./audio-export-args.js";
|
|
15
|
-
const rate = 48000;
|
|
16
|
-
export async function exportAudioWav(deps, context, gapSeconds, edgeSeconds) {
|
|
17
|
-
const { projectId } = context.stage;
|
|
18
|
-
const outputs = outputsOf(deps.db, projectId);
|
|
19
|
-
const input = await audioInputs(deps, projectId, outputs, context.signal);
|
|
20
|
-
const audio = audioTimeline({ ...input, gapSeconds, edgeSeconds }, 1 / rate);
|
|
21
|
-
const totalSeconds = audio.reduce((sum, segment) => sum + segment.seconds, 0);
|
|
22
|
-
const dir = projectDir(deps.paths, projectId);
|
|
23
|
-
const sources = outputs.filter((output) => ["audio_body", "audio_intro", "audio_outro"].includes(output.role));
|
|
24
|
-
const plan = {
|
|
25
|
-
sampleRate: rate,
|
|
26
|
-
channels: 2,
|
|
27
|
-
codec: "pcm_s16le",
|
|
28
|
-
gapSeconds,
|
|
29
|
-
edgeSeconds,
|
|
30
|
-
totalSeconds,
|
|
31
|
-
audio: audio.map((segment) => ({
|
|
32
|
-
...segment,
|
|
33
|
-
path: segment.path === null ? null : relative(dir, segment.path),
|
|
34
|
-
})),
|
|
35
|
-
output: "audio.wav",
|
|
36
|
-
sourceIds: sources.map((output) => output.id),
|
|
37
|
-
sourceHashes: sources.map((output) => ({
|
|
38
|
-
id: output.id,
|
|
39
|
-
sha256: createHash("sha256")
|
|
40
|
-
.update(readFileSync(outputPath(deps.paths, projectId, output.path)))
|
|
41
|
-
.digest("hex"),
|
|
42
|
-
})),
|
|
43
|
-
};
|
|
44
|
-
const existing = reusableAudioExport(deps.paths, projectId, outputs, plan);
|
|
45
|
-
const subtitles = await prepareSubtitles(deps, context, audio, { width: 1920, height: 1080 });
|
|
46
|
-
if (existing !== undefined) {
|
|
47
|
-
writeSubtitles(deps, context, existing, subtitles);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
await writeExport(deps, context, {
|
|
51
|
-
role: "audio_export",
|
|
52
|
-
filename: "audio.wav",
|
|
53
|
-
partName: "audio.part.wav",
|
|
54
|
-
totalSeconds,
|
|
55
|
-
record: plan,
|
|
56
|
-
subtitles,
|
|
57
|
-
render: (part, onProgress) => runFfmpeg({
|
|
58
|
-
bin: deps.ffmpeg,
|
|
59
|
-
args: audioExportArgs(audio, part),
|
|
60
|
-
signal: context.signal,
|
|
61
|
-
log: deps.log,
|
|
62
|
-
onProgress,
|
|
63
|
-
}),
|
|
64
|
-
});
|
|
65
|
-
}
|