@gentbajko/slopify 3.25.8 → 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/3.25.9.md +5 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +12 -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 +34 -50
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { templateById } from "../project-templates/repo.js";
|
|
2
2
|
import { scheduleRows } from "../schedules/repo.js";
|
|
3
|
-
import {
|
|
3
|
+
import { readJsonSetting, writeSetting } from "../settings/repo.js";
|
|
4
4
|
// The posting plan: a week of long-video slots, each with its shorts. Each schedule sets its
|
|
5
5
|
// own (its release times, one line per day it runs, in its time zone); lines saved in Settings
|
|
6
6
|
// before that are kept in the plan's time zone. A finished project takes the next free slot when its
|
|
@@ -20,20 +20,11 @@ export function localTimeZone() {
|
|
|
20
20
|
}
|
|
21
21
|
// The plan as stored in Settings: the lines made before schedules had release times.
|
|
22
22
|
export function readStoredPlan(db) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
...parsed.data,
|
|
30
|
-
rows: parsed.data.rows.filter((row) => row.schedule === undefined),
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// A broken setting reads as no plan.
|
|
35
|
-
}
|
|
36
|
-
return emptyPlan(localTimeZone());
|
|
23
|
+
// A broken setting reads as no plan.
|
|
24
|
+
const stored = readJsonSetting(db, key, postingPlanSchema, undefined);
|
|
25
|
+
if (stored === undefined)
|
|
26
|
+
return emptyPlan(localTimeZone());
|
|
27
|
+
return { ...stored, rows: stored.rows.filter((row) => row.schedule === undefined) };
|
|
37
28
|
}
|
|
38
29
|
// The series of a schedule's template, from its project title ("{{Topic}} | Stories" →
|
|
39
30
|
// "Stories"); "" when the template is gone or its title names none.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { deleteSetting, readJsonSetting, writeSetting } from "../settings/repo.js";
|
|
4
4
|
import { studioFillQueuePrefix, studioPairing } from "./settings.js";
|
|
5
5
|
// What Fill in YouTube Studio chose, waiting for the extension: one entry per video or short,
|
|
6
6
|
// oldest first. Each new upload dialog in Studio is filled from the first entry, which then
|
|
@@ -22,24 +22,13 @@ function queueKey(db) {
|
|
|
22
22
|
}
|
|
23
23
|
function write(db, key, entries) {
|
|
24
24
|
if (entries.length === 0)
|
|
25
|
-
db
|
|
25
|
+
deleteSetting(db, key);
|
|
26
26
|
else
|
|
27
27
|
writeSetting(db, key, JSON.stringify(entries));
|
|
28
28
|
}
|
|
29
29
|
// The waiting entries, oldest first, without the stale ones.
|
|
30
30
|
export function readFillQueue(db, now) {
|
|
31
|
-
const
|
|
32
|
-
if (stored === undefined)
|
|
33
|
-
return [];
|
|
34
|
-
let raw;
|
|
35
|
-
try {
|
|
36
|
-
raw = JSON.parse(stored);
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
if (!Array.isArray(raw))
|
|
42
|
-
return [];
|
|
31
|
+
const raw = readJsonSetting(db, queueKey(db), z.array(z.unknown()), []);
|
|
43
32
|
return raw.flatMap((one) => {
|
|
44
33
|
const parsed = entrySchema.safeParse(one);
|
|
45
34
|
if (!parsed.success)
|
|
@@ -63,6 +63,32 @@ export function lineSlots(plan, from, until) {
|
|
|
63
63
|
})))
|
|
64
64
|
.toSorted((left, right) => Date.parse(left.longAt) - Date.parse(right.longAt));
|
|
65
65
|
}
|
|
66
|
+
// The short times a line gives the video released at `longAt`: each short the line's first
|
|
67
|
+
// time after the one before it, the way a project's shorts are planned (other releases aside).
|
|
68
|
+
export function lineShortTimes(plan, row, longAt, shorts) {
|
|
69
|
+
const line = plan.rows.find((one) => one.name === row);
|
|
70
|
+
if (line === undefined)
|
|
71
|
+
return [];
|
|
72
|
+
const start = Date.parse(longAt);
|
|
73
|
+
const times = line.shorts
|
|
74
|
+
.flatMap((slot) => zonedTimes(zoneOf(plan, line), slot, new Date(start), new Date(start + 5 * 7 * 24 * hourMs)))
|
|
75
|
+
.toSorted((left, right) => left.getTime() - right.getTime());
|
|
76
|
+
const out = [];
|
|
77
|
+
let after = start;
|
|
78
|
+
for (let short = 1; short <= (shorts ?? line.shorts.length); short += 1) {
|
|
79
|
+
const at = times.find((time) => time.getTime() > after);
|
|
80
|
+
if (at === undefined)
|
|
81
|
+
break;
|
|
82
|
+
after = at.getTime();
|
|
83
|
+
out.push(at.toISOString());
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
// The time zone a line's times are read in: its schedule's, else the plan's.
|
|
88
|
+
export function lineZone(plan, row) {
|
|
89
|
+
const line = plan.rows.find((one) => one.name === row);
|
|
90
|
+
return line === undefined ? plan.timeZone : zoneOf(plan, line);
|
|
91
|
+
}
|
|
66
92
|
// The coming long-video times a project may take: far enough ahead to upload in time, of a
|
|
67
93
|
// line that takes it, in an hour no other release has.
|
|
68
94
|
export function freeSlots(db, plan, who, now, count, exceptProject) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { deleteSetting, readJsonSetting, stringListSchema, writeSetting, } from "../settings/repo.js";
|
|
4
4
|
import { playlistUses, studioPlaylistMax, } from "./model.js";
|
|
5
5
|
// Rows of the key/value `settings` table. The playlists travel with a backup; the
|
|
6
6
|
// pairing stays on this machine (`slices/storage/portable.ts`): its token is what lets the
|
|
@@ -58,20 +58,12 @@ export function readChannelPlaylists(db) {
|
|
|
58
58
|
return out;
|
|
59
59
|
}
|
|
60
60
|
function storedPlaylists(db, key) {
|
|
61
|
-
const stored =
|
|
62
|
-
if (stored ===
|
|
61
|
+
const stored = readJsonSetting(db, key, storedPlaylistsSchema, null);
|
|
62
|
+
if (stored === null)
|
|
63
63
|
return null;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return null;
|
|
68
|
-
if (typeof parsed.data === "string")
|
|
69
|
-
return parsed.data.trim() === "" ? null : [{ name: parsed.data.trim(), byDefault: true }];
|
|
70
|
-
return parsed.data.length === 0 ? null : parsed.data;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
64
|
+
if (typeof stored === "string")
|
|
65
|
+
return stored.trim() === "" ? null : [{ name: stored.trim(), byDefault: true }];
|
|
66
|
+
return stored.length === 0 ? null : stored;
|
|
75
67
|
}
|
|
76
68
|
// Why a list can't be saved, in words for Settings → YouTube Studio; undefined when it can.
|
|
77
69
|
export function studioPlaylistsProblem(list) {
|
|
@@ -100,7 +92,7 @@ export function saveStudioPlaylists(db, list, channelId) {
|
|
|
100
92
|
.filter((one) => one.name !== "");
|
|
101
93
|
const key = playlistKey(channelId);
|
|
102
94
|
if (value.length === 0) {
|
|
103
|
-
db
|
|
95
|
+
deleteSetting(db, key);
|
|
104
96
|
return [];
|
|
105
97
|
}
|
|
106
98
|
writeSetting(db, key, JSON.stringify(value));
|
|
@@ -111,16 +103,7 @@ export function saveStudioPlaylists(db, list, channelId) {
|
|
|
111
103
|
export const studioProjectPlaylistsKey = "studio.projectPlaylists";
|
|
112
104
|
export const storedProjectPlaylistsSchema = z.record(z.string().max(64), z.array(z.string().max(studioPlaylistMax)).max(studioPlaylistsMax));
|
|
113
105
|
function projectChoices(db) {
|
|
114
|
-
|
|
115
|
-
if (stored === undefined)
|
|
116
|
-
return {};
|
|
117
|
-
try {
|
|
118
|
-
const parsed = storedProjectPlaylistsSchema.safeParse(JSON.parse(stored));
|
|
119
|
-
return parsed.success ? parsed.data : {};
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
return {};
|
|
123
|
-
}
|
|
106
|
+
return readJsonSetting(db, studioProjectPlaylistsKey, storedProjectPlaylistsSchema, {});
|
|
124
107
|
}
|
|
125
108
|
// The channel's playlists, each ticked as this project goes into it: the project's own choice
|
|
126
109
|
// when it made one (a playlist the channel no longer lists is dropped), else the defaults.
|
|
@@ -139,7 +122,7 @@ export function saveProjectPlaylists(db, projectId, names) {
|
|
|
139
122
|
const { [projectId]: _previous, ...others } = projectChoices(db);
|
|
140
123
|
const next = names === null ? others : { ...others, [projectId]: [...names] };
|
|
141
124
|
if (Object.keys(next).length === 0)
|
|
142
|
-
db
|
|
125
|
+
deleteSetting(db, studioProjectPlaylistsKey);
|
|
143
126
|
else
|
|
144
127
|
writeSetting(db, studioProjectPlaylistsKey, JSON.stringify(next));
|
|
145
128
|
}
|
|
@@ -150,18 +133,8 @@ export const studioRealFootageKey = "studio.realFootage";
|
|
|
150
133
|
// "on" or "off": whether the extension posts and pins each video's comment once it is public.
|
|
151
134
|
export const autoCommentKey = "studio.autoComment";
|
|
152
135
|
function realFootageIds(db) {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
return [];
|
|
156
|
-
try {
|
|
157
|
-
const value = JSON.parse(stored);
|
|
158
|
-
return Array.isArray(value)
|
|
159
|
-
? value.filter((one) => typeof one === "string")
|
|
160
|
-
: [];
|
|
161
|
-
}
|
|
162
|
-
catch {
|
|
163
|
-
return [];
|
|
164
|
-
}
|
|
136
|
+
const value = readJsonSetting(db, studioRealFootageKey, stringListSchema, []);
|
|
137
|
+
return value;
|
|
165
138
|
}
|
|
166
139
|
export function readRealFootage(db, projectId) {
|
|
167
140
|
return realFootageIds(db).includes(projectId);
|
|
@@ -170,25 +143,15 @@ export function saveRealFootage(db, projectId, on) {
|
|
|
170
143
|
const others = realFootageIds(db).filter((one) => one !== projectId);
|
|
171
144
|
const next = on ? [...others, projectId].sort() : others;
|
|
172
145
|
if (next.length === 0)
|
|
173
|
-
db
|
|
146
|
+
deleteSetting(db, studioRealFootageKey);
|
|
174
147
|
else
|
|
175
148
|
writeSetting(db, studioRealFootageKey, JSON.stringify(next));
|
|
176
149
|
}
|
|
177
150
|
// The pairing token, made on first read. One per install: a new one (Settings → YouTube
|
|
178
151
|
// Studio → New pairing token) forgets the extension that used the old one.
|
|
179
152
|
export function studioPairing(db) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
const parsed = pairingSchema.safeParse(JSON.parse(stored));
|
|
184
|
-
if (parsed.success)
|
|
185
|
-
return parsed.data;
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// A damaged row is replaced below.
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return resetStudioPairing(db);
|
|
153
|
+
// A damaged row is replaced.
|
|
154
|
+
return readJsonSetting(db, studioPairingKey, pairingSchema, undefined) ?? resetStudioPairing(db);
|
|
192
155
|
}
|
|
193
156
|
// What is waiting to be filled in Studio is kept per pairing (`queue.ts`): one row,
|
|
194
157
|
// `studio.fillQueue.<token hash>`, so a new token starts with nothing waiting.
|
|
@@ -63,6 +63,18 @@ export function videoOf(db, projectId, short) {
|
|
|
63
63
|
.get(projectId, slot(short));
|
|
64
64
|
return row === undefined ? undefined : rowOf(row);
|
|
65
65
|
}
|
|
66
|
+
// What the extension reported after setting up Studio's A/B Testing on the video's Details page,
|
|
67
|
+
// asked for from On YouTube or its popup: "started" once filled (the person presses Set test),
|
|
68
|
+
// "failed" with its reason. A failed later attempt keeps a test already set up ("started"), so
|
|
69
|
+
// its result is still read. False when the project has no video recorded for that upload.
|
|
70
|
+
export function setAbState(db, projectId, short, state, message, at) {
|
|
71
|
+
return (db
|
|
72
|
+
.prepare(`UPDATE youtube_videos SET
|
|
73
|
+
ab_state=CASE WHEN ?='failed' AND ab_state='started' THEN 'started' ELSE ? END,
|
|
74
|
+
ab_message=?, ab_at=?
|
|
75
|
+
WHERE project_id=? AND short=?`)
|
|
76
|
+
.run(state, state, message, at, projectId, slot(short)).changes > 0);
|
|
77
|
+
}
|
|
66
78
|
export function setTaskState(db, task, projectId, short, state, message) {
|
|
67
79
|
const column = task === "finish" ? "finish" : "comment";
|
|
68
80
|
db.prepare(`UPDATE youtube_videos SET ${column}_state=?, ${column}_message=? WHERE project_id=? AND short=?`).run(state, message, projectId, slot(short));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { errorText } from "../../kernel/errors.js";
|
|
3
4
|
import { defaultMotionStyle, defaultZoomPercent } from "../admission/rules.js";
|
|
4
5
|
import { isMissingFont, resolveBoldFont, resolveFont } from "../fonts/index.js";
|
|
5
6
|
import { renderShort } from "../shorts/render.js";
|
|
@@ -9,7 +10,7 @@ import { planRender } from "../video/plan.js";
|
|
|
9
10
|
import { renderSlideshow } from "../video/slideshow.js";
|
|
10
11
|
import { bundledSampleAssets, sampleNarrationSeconds } from "./narration.js";
|
|
11
12
|
import { stylePreviewSeconds } from "./schema.js";
|
|
12
|
-
import { previewCues, previewWords } from "./settings.js";
|
|
13
|
+
import { previewCues, previewShots, previewWords } from "./settings.js";
|
|
13
14
|
export class StylePreviewError extends Error {
|
|
14
15
|
reason;
|
|
15
16
|
constructor(reason, message) {
|
|
@@ -25,7 +26,6 @@ const previewFrame = {
|
|
|
25
26
|
"9:16": { width: 270, height: 480 },
|
|
26
27
|
"1:1": { width: 360, height: 360 },
|
|
27
28
|
};
|
|
28
|
-
const shotSeconds = stylePreviewSeconds / 3;
|
|
29
29
|
const chapterTitle = "Chapter one";
|
|
30
30
|
export function ffmpegStylePreview(deps) {
|
|
31
31
|
const assets = deps.assets ?? bundledSampleAssets();
|
|
@@ -33,25 +33,32 @@ export function ffmpegStylePreview(deps) {
|
|
|
33
33
|
try {
|
|
34
34
|
// A real picture is shown for all three shots: the motion, the Look and the captions read
|
|
35
35
|
// on it, and the transition and chapter card still show at the cuts.
|
|
36
|
-
const
|
|
36
|
+
const stills = picture !== undefined
|
|
37
37
|
? [picture, picture, picture]
|
|
38
38
|
: settings.format === "9:16"
|
|
39
39
|
? assets.tall
|
|
40
40
|
: assets.wide;
|
|
41
|
+
// A longer preview shows the stills again in turn.
|
|
42
|
+
const { shots } = previewShots(settings);
|
|
43
|
+
const images = settings.short !== undefined
|
|
44
|
+
? stills
|
|
45
|
+
: Array.from({ length: shots }, (_, index) => stills[index % stills.length] ?? "");
|
|
46
|
+
const machine = await deps.machine?.();
|
|
41
47
|
if (settings.short !== undefined)
|
|
42
|
-
await renderShortPreview(deps, settings, settings.short, assets, images, output, signal);
|
|
48
|
+
await renderShortPreview(deps, settings, settings.short, assets, images, output, signal, machine);
|
|
43
49
|
else
|
|
44
|
-
await renderPreview(deps, settings, assets, images, output, signal);
|
|
50
|
+
await renderPreview(deps, settings, assets, images, output, signal, machine);
|
|
45
51
|
}
|
|
46
52
|
catch (error) {
|
|
47
53
|
throw explained(deps.log, error);
|
|
48
54
|
}
|
|
49
55
|
};
|
|
50
56
|
}
|
|
51
|
-
async function renderPreview(deps, settings, assets, images, output, signal) {
|
|
57
|
+
async function renderPreview(deps, settings, assets, images, output, signal, machine) {
|
|
52
58
|
mkdirSync(deps.dir, { recursive: true, mode: 0o700 });
|
|
53
59
|
const workspace = mkdtempSync(join(deps.dir, "work-"));
|
|
54
60
|
try {
|
|
61
|
+
const { shotSeconds } = previewShots(settings);
|
|
55
62
|
const cardFont = settings.chapterCard === null
|
|
56
63
|
? undefined
|
|
57
64
|
: await resolveFont(deps.paths, settings.chapterCard.fontId);
|
|
@@ -60,8 +67,8 @@ async function renderPreview(deps, settings, assets, images, output, signal) {
|
|
|
60
67
|
gapSeconds: 0,
|
|
61
68
|
edgeSeconds: 0,
|
|
62
69
|
imageSeconds: shotSeconds,
|
|
63
|
-
zoomPercent: defaultZoomPercent,
|
|
64
|
-
motionStyle: defaultMotionStyle,
|
|
70
|
+
zoomPercent: settings.timing?.zoomPercent ?? defaultZoomPercent,
|
|
71
|
+
motionStyle: settings.timing?.motionStyle ?? defaultMotionStyle,
|
|
65
72
|
images,
|
|
66
73
|
output,
|
|
67
74
|
edit: {
|
|
@@ -81,14 +88,14 @@ async function renderPreview(deps, settings, assets, images, output, signal) {
|
|
|
81
88
|
const edit = {
|
|
82
89
|
...plan.editList,
|
|
83
90
|
...previewFrame[settings.format],
|
|
84
|
-
audio:
|
|
91
|
+
audio: narrationFor(assets.narration, plan.totalSeconds),
|
|
85
92
|
};
|
|
86
93
|
const captions = settings.captions;
|
|
87
94
|
if (captions !== null) {
|
|
88
95
|
const font = await resolveFont(deps.paths, captions.fontId);
|
|
89
96
|
mkdirSync(join(workspace, "fonts"), { mode: 0o700 });
|
|
90
97
|
copyFileSync(font.path, join(workspace, "fonts", `selected${font.extension}`));
|
|
91
|
-
writeFileSync(join(workspace, "subtitles.ass"), serializeAss(previewCues(captions.text), {
|
|
98
|
+
writeFileSync(join(workspace, "subtitles.ass"), serializeAss(previewCues(captions.text, plan.totalSeconds), {
|
|
92
99
|
...subtitleFrame(settings.format),
|
|
93
100
|
fontName: font.assName,
|
|
94
101
|
fontSize: captions.fontSize,
|
|
@@ -105,6 +112,7 @@ async function renderPreview(deps, settings, assets, images, output, signal) {
|
|
|
105
112
|
signal,
|
|
106
113
|
log: deps.log,
|
|
107
114
|
onProgress: () => { },
|
|
115
|
+
machine,
|
|
108
116
|
});
|
|
109
117
|
}
|
|
110
118
|
finally {
|
|
@@ -113,7 +121,7 @@ async function renderPreview(deps, settings, assets, images, output, signal) {
|
|
|
113
121
|
}
|
|
114
122
|
// The Shorts layout, drawn at the preview's size: the same audio cut, image timing, captions
|
|
115
123
|
// and headline a short gets, from the sample narration.
|
|
116
|
-
async function renderShortPreview(deps, settings, short, assets, images, output, signal) {
|
|
124
|
+
async function renderShortPreview(deps, settings, short, assets, images, output, signal, machine) {
|
|
117
125
|
mkdirSync(deps.dir, { recursive: true, mode: 0o700 });
|
|
118
126
|
await renderShort({
|
|
119
127
|
bin: deps.ffmpeg,
|
|
@@ -121,7 +129,7 @@ async function renderShortPreview(deps, settings, short, assets, images, output,
|
|
|
121
129
|
start: 0,
|
|
122
130
|
end: sampleNarrationSeconds,
|
|
123
131
|
images,
|
|
124
|
-
imageSeconds:
|
|
132
|
+
imageSeconds: stylePreviewSeconds / 3,
|
|
125
133
|
motionStyle: defaultMotionStyle,
|
|
126
134
|
zoomPercent: defaultZoomPercent,
|
|
127
135
|
words: previewWords(short.text),
|
|
@@ -134,12 +142,25 @@ async function renderShortPreview(deps, settings, short, assets, images, output,
|
|
|
134
142
|
signal,
|
|
135
143
|
log: deps.log,
|
|
136
144
|
onProgress: () => { },
|
|
145
|
+
machine,
|
|
137
146
|
});
|
|
138
147
|
}
|
|
148
|
+
// The six seconds of sample narration back to back under a longer preview, the last cut to
|
|
149
|
+
// what is left.
|
|
150
|
+
function narrationFor(path, seconds) {
|
|
151
|
+
const pieces = [];
|
|
152
|
+
for (let at = 0; at < seconds - 0.001; at += sampleNarrationSeconds)
|
|
153
|
+
pieces.push({
|
|
154
|
+
kind: "body",
|
|
155
|
+
path,
|
|
156
|
+
seconds: Math.round(Math.min(sampleNarrationSeconds, seconds - at) * 1000) / 1000,
|
|
157
|
+
});
|
|
158
|
+
return pieces;
|
|
159
|
+
}
|
|
139
160
|
function explained(log, error) {
|
|
140
161
|
if (error instanceof StylePreviewError)
|
|
141
162
|
return error;
|
|
142
|
-
const message =
|
|
163
|
+
const message = errorText(error);
|
|
143
164
|
if (isMissingFont(error))
|
|
144
165
|
return new StylePreviewError("font-missing", "The style preview couldn't render because the chosen caption font is no longer available; it may have been uninstalled or deleted. Choose another font under Subtitles, then press Render again.");
|
|
145
166
|
if (message.startsWith("Slopify could not start ffmpeg") || /\bENOENT\b/.test(message))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formats } from "../../kernel/pipeline.js";
|
|
3
|
+
import { motionStyles } from "../admission/model.js";
|
|
3
4
|
import { videoEditSchema } from "../admission/schema.js";
|
|
4
5
|
import { subtitleModes, subtitlePositions } from "../subtitles/model.js";
|
|
5
6
|
// "See it before you make it": a few seconds rendered by the real renderer with a project's
|
|
@@ -8,6 +9,8 @@ import { subtitleModes, subtitlePositions } from "../subtitles/model.js";
|
|
|
8
9
|
// How long the preview runs: three images of two seconds, so a transition and a chapter
|
|
9
10
|
// card both show, under six seconds of the sample narration.
|
|
10
11
|
export const stylePreviewSeconds = 6;
|
|
12
|
+
// The longest preview: the template studio's 30-second video sample.
|
|
13
|
+
export const stylePreviewSecondsMax = 30;
|
|
11
14
|
export const stylePreviewTextMax = 200;
|
|
12
15
|
// The sample text Play starts with. It, or no text, captions the sample narration with its own
|
|
13
16
|
// words; any other text is spread over the stretches the narration speaks.
|
|
@@ -47,6 +50,16 @@ export const stylePreviewRequestSchema = z.object({
|
|
|
47
50
|
title: z.string().max(shortTitlePreviewMax).optional(),
|
|
48
51
|
})
|
|
49
52
|
.optional(),
|
|
53
|
+
// How long it runs, in whole seconds; absent is six. The Shorts layout ignores it.
|
|
54
|
+
seconds: z.number().int().min(stylePreviewSeconds).max(stylePreviewSecondsMax).optional(),
|
|
55
|
+
// The run's own picture timing and motion; absent is two-second shots with the defaults.
|
|
56
|
+
timing: z
|
|
57
|
+
.object({
|
|
58
|
+
imageSeconds: z.number().finite().min(1).max(120),
|
|
59
|
+
zoomPercent: z.number().finite().min(0).max(100),
|
|
60
|
+
motionStyle: z.enum(motionStyles),
|
|
61
|
+
})
|
|
62
|
+
.optional(),
|
|
50
63
|
// Render again even when this exact preview is already saved.
|
|
51
64
|
force: z.boolean().optional(),
|
|
52
65
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { mkdirSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { errorText } from "../../kernel/errors.js";
|
|
4
5
|
import { normalizeStylePreview, previewSeconds, stylePreviewHash } from "./settings.js";
|
|
5
6
|
// Rendered previews are kept in the data folder by the hash of their settings, so a setting
|
|
6
7
|
// changed back, or the same style in another project, plays at once. `force` renders again
|
|
@@ -86,7 +87,7 @@ function prune(deps) {
|
|
|
86
87
|
}
|
|
87
88
|
catch (error) {
|
|
88
89
|
deps.log.write("warn", "style-preview.prune", {
|
|
89
|
-
detail:
|
|
90
|
+
detail: errorText(error),
|
|
90
91
|
});
|
|
91
92
|
}
|
|
92
93
|
}
|
|
@@ -61,8 +61,27 @@ image) {
|
|
|
61
61
|
},
|
|
62
62
|
chapterCard: edit.chapterCards ? { fontId: subtitles.fontId } : null,
|
|
63
63
|
...(image === undefined ? {} : { image }),
|
|
64
|
+
...(request.seconds === undefined || request.seconds === stylePreviewSeconds
|
|
65
|
+
? {}
|
|
66
|
+
: { seconds: request.seconds }),
|
|
67
|
+
...(request.timing === undefined
|
|
68
|
+
? {}
|
|
69
|
+
: {
|
|
70
|
+
timing: {
|
|
71
|
+
imageSeconds: Math.round(request.timing.imageSeconds * 10) / 10,
|
|
72
|
+
zoomPercent: Math.round(request.timing.zoomPercent * 10) / 10,
|
|
73
|
+
motionStyle: request.timing.motionStyle,
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
64
76
|
};
|
|
65
77
|
}
|
|
78
|
+
// The shots a preview is cut into: two seconds each by default, else the run's own picture
|
|
79
|
+
// length, as many as fill its seconds (at least one).
|
|
80
|
+
export function previewShots(settings) {
|
|
81
|
+
const seconds = settings.seconds ?? stylePreviewSeconds;
|
|
82
|
+
const shotSeconds = settings.timing?.imageSeconds ?? stylePreviewSeconds / 3;
|
|
83
|
+
return { shotSeconds, shots: Math.max(1, Math.round(seconds / shotSeconds)) };
|
|
84
|
+
}
|
|
66
85
|
// JSON with every object's keys in order, so equal settings always hash alike.
|
|
67
86
|
export function stableJson(value) {
|
|
68
87
|
if (Array.isArray(value))
|
|
@@ -80,9 +99,10 @@ export function stylePreviewHash(settings) {
|
|
|
80
99
|
}
|
|
81
100
|
// How long the rendered preview runs: a Shorts preview at a higher speed is shorter.
|
|
82
101
|
export function previewSeconds(settings) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
if (settings.short !== undefined)
|
|
103
|
+
return round(stylePreviewSeconds / settings.short.speed);
|
|
104
|
+
const { shotSeconds, shots } = previewShots(settings);
|
|
105
|
+
return round(shotSeconds * shots);
|
|
86
106
|
}
|
|
87
107
|
// ceiling: a pause this long between two words of the sample narration starts a new phrase,
|
|
88
108
|
// the same pause `captionCues` starts a new cue at.
|
|
@@ -131,8 +151,16 @@ export function previewWords(text, narration = sampleNarrationWords) {
|
|
|
131
151
|
}
|
|
132
152
|
return timed;
|
|
133
153
|
}
|
|
134
|
-
|
|
135
|
-
|
|
154
|
+
// The captions of `seconds` of preview: the six seconds' words again every six seconds, as the
|
|
155
|
+
// sample narration repeats under a longer preview.
|
|
156
|
+
export function previewCues(text, seconds = stylePreviewSeconds) {
|
|
157
|
+
const once = previewWords(text);
|
|
158
|
+
const words = [];
|
|
159
|
+
for (let start = 0; start < seconds; start += stylePreviewSeconds)
|
|
160
|
+
for (const word of once)
|
|
161
|
+
if (start + word.end <= seconds)
|
|
162
|
+
words.push({ ...word, start: round(start + word.start), end: round(start + word.end) });
|
|
163
|
+
return captionCues(words);
|
|
136
164
|
}
|
|
137
165
|
function round(value) {
|
|
138
166
|
return Math.round(value * 1000) / 1000;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
1
2
|
// The collector URL is built into the release and is not user
|
|
2
3
|
// configurable. The environment variable below is a test seam, not a documented knob:
|
|
3
4
|
// packages/app/test/telemetry-flush.test.ts points it at a fake collector.
|
|
@@ -42,10 +43,7 @@ export function httpPostEvents(endpoint, timeoutMs) {
|
|
|
42
43
|
catch (error) {
|
|
43
44
|
// Offline is the ordinary case, not a fault: the events stay queued and the user is
|
|
44
45
|
// told nothing.
|
|
45
|
-
return { ok: false, retriable: true, reason:
|
|
46
|
+
return { ok: false, retriable: true, reason: errorText(error) };
|
|
46
47
|
}
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
|
-
function messageOf(error) {
|
|
50
|
-
return error instanceof Error ? error.message : String(error);
|
|
51
|
-
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
1
2
|
import { machineOf, markDelivered, undeliveredEvents } from "./repo.js";
|
|
2
3
|
// ceiling: 200 events per request against the collector's cap of 500, and at most 25
|
|
3
4
|
// requests per flush. A queue longer than 5000 undelivered events drains over several
|
|
@@ -75,7 +76,7 @@ export function createFlusher(deps, delayMs) {
|
|
|
75
76
|
.catch((error) => {
|
|
76
77
|
// The timer has no caller to fail: a broken flush is logged and the next one
|
|
77
78
|
// tries again.
|
|
78
|
-
deps.log.write("warn", "telemetry.flush", { detail:
|
|
79
|
+
deps.log.write("warn", "telemetry.flush", { detail: errorText(error) });
|
|
79
80
|
})
|
|
80
81
|
.finally(() => {
|
|
81
82
|
running = false;
|
|
@@ -106,6 +107,3 @@ function envelope(event, machineId) {
|
|
|
106
107
|
createdAt: event.createdAt,
|
|
107
108
|
};
|
|
108
109
|
}
|
|
109
|
-
function messageOf(error) {
|
|
110
|
-
return error instanceof Error ? error.message : String(error);
|
|
111
|
-
}
|
|
@@ -8,13 +8,6 @@ export const telemetryEventTypes = ["install", "project.created", "stage.complet
|
|
|
8
8
|
// writes the intro and outro texts, the audio stage narrates all three - so the event type
|
|
9
9
|
// stays `stage.completed` and the pair (stage, segment) says which unit it is.
|
|
10
10
|
export const audioSegments = ["body", "intro", "outro"];
|
|
11
|
-
export const noTokens = { tokensIn: 0, tokensOut: 0 };
|
|
12
|
-
export function plusUsage(tokens, usage) {
|
|
13
|
-
return {
|
|
14
|
-
tokensIn: tokens.tokensIn + (usage?.inputTokens ?? 0),
|
|
15
|
-
tokensOut: tokens.tokensOut + (usage?.outputTokens ?? 0),
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
11
|
// The whole privacy surface. API keys, prompt bodies, keyword values, titles, article and
|
|
19
12
|
// research text, files, filenames, OS, locale and hardware are all barred from a payload,
|
|
20
13
|
// which is exactly what the first-run notice promises. The schema below is strict, so a
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { errorText } from "../../kernel/errors.js";
|
|
1
2
|
import { payloadSchema } from "./model.js";
|
|
2
3
|
import { insertTelemetryEvent, machineOf } from "./repo.js";
|
|
3
4
|
// Appends one row to the local queue and hands it back. Throws: the notice dismissal
|
|
@@ -32,10 +33,16 @@ export function record(deps, type, counters) {
|
|
|
32
33
|
}
|
|
33
34
|
catch (error) {
|
|
34
35
|
deps.log.write("warn", "telemetry.record", {
|
|
35
|
-
detail: `${type}: ${
|
|
36
|
+
detail: `${type}: ${errorText(error)}`,
|
|
36
37
|
});
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
// A template studio sample (or bake-off copy) is the studio's, not a video of the person's:
|
|
41
|
+
// Settings → Usage and the public counters leave its stages out.
|
|
42
|
+
export function skippingProjects(count, skipped) {
|
|
43
|
+
return (type, counters, projectId) => {
|
|
44
|
+
if (projectId !== undefined && skipped(projectId))
|
|
45
|
+
return;
|
|
46
|
+
count(type, counters, projectId);
|
|
47
|
+
};
|
|
41
48
|
}
|