@gentbajko/slopify 3.25.9 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +4 -6
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +2 -4
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +3 -2
- package/dist/adapters/explain.js +10 -12
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +21 -4
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +42 -9
- package/dist/adapters/image/fal.js +21 -53
- package/dist/adapters/image/google.js +33 -56
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +22 -48
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +21 -49
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +54 -3
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +11 -6
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +52 -99
- package/dist/adapters/llm/claude-code.js +16 -4
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-models.js +1 -1
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/document-workspace.js +3 -2
- package/dist/adapters/llm/image-workspace.js +3 -2
- package/dist/adapters/llm/openrouter.js +12 -48
- package/dist/adapters/llm/run-cli.js +9 -24
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +21 -41
- package/dist/adapters/tts/inworld-async.js +6 -2
- package/dist/adapters/tts/inworld.js +6 -2
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/adapters/tts/system.js +2 -1
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +23 -14
- package/dist/catalog/schema.js +4 -1
- package/dist/catalog/store.js +39 -0
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +11 -32
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +86 -11
- package/dist/edge/http/assistant.js +129 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +2 -4
- package/dist/edge/http/channel-memory.js +9 -22
- package/dist/edge/http/channels.js +14 -27
- package/dist/edge/http/checkpoints.js +39 -21
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +5 -14
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +5 -10
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +47 -14
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +30 -26
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +7 -14
- package/dist/edge/http/patch-notes.js +6 -12
- package/dist/edge/http/planning.js +3 -7
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +2 -1
- package/dist/edge/http/project-templates.js +31 -19
- package/dist/edge/http/projects.js +24 -16
- package/dist/edge/http/prompts.js +9 -16
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +48 -34
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +12 -25
- package/dist/edge/http/revision-files.js +6 -11
- package/dist/edge/http/revisions.js +14 -19
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +69 -40
- package/dist/edge/http/settings.js +27 -14
- package/dist/edge/http/social.js +283 -0
- package/dist/edge/http/staging.js +3 -5
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +33 -25
- package/dist/edge/http/studio.js +94 -69
- package/dist/edge/http/style-preview.js +3 -6
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +436 -0
- package/dist/edge/http/trash.js +11 -12
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +3 -4
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +29 -3
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +6 -4
- package/dist/edge/mcp/library-tools.js +9 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +11 -9
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +19 -7
- package/dist/edge/mcp/tools-planning.js +40 -21
- package/dist/edge/mcp/tools-projects.js +38 -11
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +23 -10
- package/dist/edge/mcp/tools-schedules.js +32 -8
- package/dist/edge/mcp/tools-setup.js +75 -11
- package/dist/edge/mcp/tools-social.js +47 -0
- package/dist/edge/mcp/tools-storage.js +11 -3
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/pipeline.js +12 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/ports/settings-places.js +31 -0
- package/dist/kernel/ports/system-speech.js +31 -3
- package/dist/kernel/runner/attempt.js +14 -4
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +18 -12
- package/dist/kernel/runner/standalone.js +11 -7
- package/dist/main.js +338 -21
- package/dist/model-catalog.js +20 -0
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +11 -7
- package/dist/slices/admission/rules.js +50 -15
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +86 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +344 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +8 -7
- package/dist/slices/channels/cast-images.js +3 -2
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +7 -1
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +3 -15
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +2 -28
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +130 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +223 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/document/model.js +7 -4
- package/dist/slices/document/render.js +2 -1
- package/dist/slices/document/theme-schema.js +1 -1
- package/dist/slices/document/theme.js +49 -3
- package/dist/slices/episodes/summarize.js +6 -2
- package/dist/slices/estimate/index.js +72 -28
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +5 -3
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +8 -16
- package/dist/slices/images/scenes.js +102 -28
- package/dist/slices/keywords/digest.js +85 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +5 -4
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +53 -12
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +125 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +72 -27
- package/dist/slices/model-upkeep/usage.js +39 -13
- package/dist/slices/narration/breaths.js +3 -1
- package/dist/slices/narration/clean-pieces.js +3 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +6 -4
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +4 -3
- package/dist/slices/onboarding/copy.js +21 -3
- package/dist/slices/onboarding/first-run.js +16 -40
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +6 -4
- package/dist/slices/onboarding/model.js +26 -37
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +105 -65
- package/dist/slices/onboarding/sample.js +4 -2
- package/dist/slices/onboarding/state.js +9 -11
- package/dist/slices/onboarding/template.js +8 -6
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +4 -3
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +9 -3
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/play-drafts/service.js +17 -7
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/next-chapter.js +2 -1
- package/dist/slices/project-templates/provider-defaults.js +22 -0
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +14 -1
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +32 -14
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +4 -4
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +8 -5
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +102 -31
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +19 -7
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +9 -8
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +3 -2
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +10 -9
- package/dist/slices/rebuild/runtime-article.js +7 -5
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +11 -13
- package/dist/slices/rebuild/runtime-export-bed.js +8 -12
- package/dist/slices/rebuild/runtime-export-edit.js +8 -16
- package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
- package/dist/slices/rebuild/runtime-export-short.js +9 -5
- package/dist/slices/rebuild/runtime-export.js +38 -15
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +8 -12
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +17 -22
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +13 -17
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +67 -25
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +39 -33
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +31 -50
- package/dist/slices/rebuild/runtime-store.js +20 -10
- package/dist/slices/rebuild/runtime-subtitles.js +28 -25
- package/dist/slices/rebuild/runtime-voices.js +10 -16
- package/dist/slices/rebuild/runtime-youtube.js +14 -31
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +4 -1
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +32 -11
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +4 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +9 -5
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +3 -3
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +18 -7
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +30 -21
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +57 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +53 -41
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +8 -43
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +14 -2
- package/dist/slices/settings/playback.js +34 -23
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +6 -18
- package/dist/slices/shorts/prompts.js +4 -14
- package/dist/slices/shorts/render.js +6 -2
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +132 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +56 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +129 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +22 -4
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +17 -12
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +26 -9
- package/dist/slices/studio/calendar.js +7 -2
- package/dist/slices/studio/disclosure.js +4 -4
- package/dist/slices/studio/model.js +1 -1
- package/dist/slices/studio/pack.js +9 -8
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +7 -16
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +20 -57
- package/dist/slices/studio/videos.js +35 -4
- package/dist/slices/style-preview/render.js +37 -16
- package/dist/slices/style-preview/schema.js +14 -1
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +161 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +106 -0
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +322 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +58 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +207 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +355 -0
- package/dist/slices/template-studio/quote.js +155 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +32 -0
- package/dist/slices/template-studio/schedule-sample.js +91 -0
- package/dist/slices/template-studio/schema.js +243 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +175 -0
- package/dist/slices/template-studio/status.js +191 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +169 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +4 -16
- package/dist/slices/youtube/edits-repo.js +3 -12
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +34 -33
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Backups.md +7 -7
- package/dist/tutorials/Calendar.md +17 -25
- package/dist/tutorials/Cast-Library.md +19 -19
- package/dist/tutorials/Channels.md +42 -35
- package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
- package/dist/tutorials/Create-Article.md +114 -0
- package/dist/tutorials/Create-Extras.md +112 -0
- package/dist/tutorials/Create-Images.md +165 -0
- package/dist/tutorials/Create-Narration.md +178 -0
- package/dist/tutorials/Create-Overview.md +244 -0
- package/dist/tutorials/Create-Video-and-Style.md +144 -0
- package/dist/tutorials/Docker.md +3 -3
- package/dist/tutorials/Document-Themes.md +32 -32
- package/dist/tutorials/Editing-a-Project.md +94 -94
- package/dist/tutorials/FAQ.md +18 -18
- package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
- package/dist/tutorials/Home-and-Projects.md +115 -71
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +14 -13
- package/dist/tutorials/Intros-and-Outros.md +33 -34
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +53 -21
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +27 -17
- package/dist/tutorials/Other-Languages.md +15 -15
- package/dist/tutorials/PDF-Documents.md +38 -29
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +48 -44
- package/dist/tutorials/Providers-and-Keys.md +105 -98
- package/dist/tutorials/Publishing-to-YouTube.md +31 -31
- package/dist/tutorials/Recovery-and-Retries.md +31 -31
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
- package/dist/tutorials/Schedules.md +46 -27
- package/dist/tutorials/Settings-Reference.md +194 -174
- package/dist/tutorials/Shorts.md +34 -33
- package/dist/tutorials/Start-at-Login.md +3 -3
- package/dist/tutorials/Studio-Extension.md +22 -24
- package/dist/tutorials/Template-Studio.md +128 -0
- package/dist/tutorials/Templates.md +51 -77
- package/dist/tutorials/Trash.md +4 -4
- package/dist/tutorials/Troubleshooting.md +44 -44
- package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
- package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
- package/dist/tutorials/Video-Editing.md +34 -34
- package/dist/tutorials/Where-Your-Files-Live.md +10 -10
- package/dist/tutorials/YouTube-Description.md +26 -26
- package/dist/tutorials/Your-First-Short.md +35 -35
- package/dist/tutorials/_Sidebar.md +19 -14
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-BNftKQrA.css +1 -0
- package/dist/web/assets/index-Cpa58woP.js +459 -0
- package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
- package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
- package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +6 -2
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -161
- package/dist/tutorials/Play-Narration.md +0 -167
- package/dist/tutorials/Play-Outputs.md +0 -109
- package/dist/tutorials/Play-Overview.md +0 -227
- package/dist/tutorials/Play-Title-and-Article.md +0 -136
- package/dist/tutorials/Play-Video-and-Style.md +0 -143
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
- package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
- package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
- package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// A post's words: counted the way each site counts them, cut to fit at a sentence, with the
|
|
2
|
+
// hashtags and link at the end. Pure and browser-safe: Prepare upload's live counter uses it.
|
|
3
|
+
import { parseTimestamp } from "../youtube/timestamps.js";
|
|
4
|
+
const urlPattern = /https?:\/\/[^\s]+/gu;
|
|
5
|
+
// X counts a link as 23 characters, whatever its length.
|
|
6
|
+
const xUrlWeight = 23;
|
|
7
|
+
// X counts these code points once; every other (CJK, emoji) twice.
|
|
8
|
+
const xLightRanges = [
|
|
9
|
+
[0, 4351],
|
|
10
|
+
[8192, 8205],
|
|
11
|
+
[8208, 8223],
|
|
12
|
+
[8242, 8247],
|
|
13
|
+
];
|
|
14
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
15
|
+
const pictographic = /\p{Extended_Pictographic}/u;
|
|
16
|
+
function xWeight(text) {
|
|
17
|
+
let total = 0;
|
|
18
|
+
for (const { segment } of segmenter.segment(text)) {
|
|
19
|
+
if (pictographic.test(segment)) {
|
|
20
|
+
total += 2;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
for (const char of segment) {
|
|
24
|
+
const code = char.codePointAt(0) ?? 0;
|
|
25
|
+
total += xLightRanges.some(([low, high]) => code >= low && code <= high) ? 1 : 2;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return total;
|
|
29
|
+
}
|
|
30
|
+
export function countFor(text, unit) {
|
|
31
|
+
switch (unit) {
|
|
32
|
+
case "weighted": {
|
|
33
|
+
const links = text.match(urlPattern) ?? [];
|
|
34
|
+
return xWeight(text.replace(urlPattern, "")) + links.length * xUrlWeight;
|
|
35
|
+
}
|
|
36
|
+
case "graphemes":
|
|
37
|
+
return [...segmenter.segment(text)].length;
|
|
38
|
+
case "characters":
|
|
39
|
+
return text.length;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// The body, then the link and hashtags, each part on its own paragraph. A body too long is cut
|
|
43
|
+
// at the last sentence that still fits, else at the last word with "…"; the link and hashtags
|
|
44
|
+
// are never cut, but dropped (hashtags first) when even they don't fit.
|
|
45
|
+
export function fitText(input, limits, siteName) {
|
|
46
|
+
const body = input.body.trim();
|
|
47
|
+
const tagLine = input.hashtags.join(" ");
|
|
48
|
+
const join = (parts) => parts.filter((part) => part !== "").join("\n\n");
|
|
49
|
+
const count = (text) => countFor(text, limits.unit);
|
|
50
|
+
const whole = join([body, input.link ?? "", tagLine]);
|
|
51
|
+
if (count(whole) <= limits.text)
|
|
52
|
+
return { text: whole, used: count(whole) };
|
|
53
|
+
for (const tail of [[input.link ?? "", tagLine], [input.link ?? ""], []]) {
|
|
54
|
+
const tailText = join(tail);
|
|
55
|
+
const room = limits.text - (tailText === "" ? 0 : count(`\n\n${tailText}`));
|
|
56
|
+
if (room <= 0)
|
|
57
|
+
continue;
|
|
58
|
+
const cut = cutBody(body, room, count);
|
|
59
|
+
if (cut === "" && body !== "")
|
|
60
|
+
continue;
|
|
61
|
+
const text = join([cut, ...tail]);
|
|
62
|
+
const dropped = tail.length === 2
|
|
63
|
+
? ""
|
|
64
|
+
: tail.length === 1
|
|
65
|
+
? " and its hashtags"
|
|
66
|
+
: ", its hashtags and the link";
|
|
67
|
+
return {
|
|
68
|
+
text,
|
|
69
|
+
used: count(text),
|
|
70
|
+
notice: `The text was cut to fit ${siteName}'s ${String(limits.text)} characters${dropped}. Shorten it in the post's text box, or pick a shorter text source.`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const text = cutBody(body, limits.text, count);
|
|
74
|
+
return {
|
|
75
|
+
text,
|
|
76
|
+
used: count(text),
|
|
77
|
+
notice: `The text was cut to fit ${siteName}'s ${String(limits.text)} characters. Shorten it in the post's text box.`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function cutBody(body, room, count) {
|
|
81
|
+
if (count(body) <= room)
|
|
82
|
+
return body;
|
|
83
|
+
const sentences = body.match(/[^.!?\n]+(?:[.!?]+["')\]]*|\n+|$)/gu) ?? [body];
|
|
84
|
+
let kept = "";
|
|
85
|
+
for (const sentence of sentences) {
|
|
86
|
+
const next = kept + sentence;
|
|
87
|
+
if (count(next.trimEnd()) > room)
|
|
88
|
+
break;
|
|
89
|
+
kept = next;
|
|
90
|
+
}
|
|
91
|
+
if (kept.trim() !== "")
|
|
92
|
+
return kept.trim();
|
|
93
|
+
const words = body.split(/\s+/u);
|
|
94
|
+
let line = "";
|
|
95
|
+
for (const word of words) {
|
|
96
|
+
const next = line === "" ? word : `${line} ${word}`;
|
|
97
|
+
if (count(`${next}…`) > room)
|
|
98
|
+
break;
|
|
99
|
+
line = next;
|
|
100
|
+
}
|
|
101
|
+
return line === "" ? "" : `${line}…`;
|
|
102
|
+
}
|
|
103
|
+
// Hashtags for a post: the description's tags, then the shorts' hashtags, each written once as
|
|
104
|
+
// a #Word without spaces or punctuation, at most `count`.
|
|
105
|
+
export function hashtagsFor(sources, count) {
|
|
106
|
+
if (count <= 0)
|
|
107
|
+
return [];
|
|
108
|
+
const seen = new Set();
|
|
109
|
+
const tags = [];
|
|
110
|
+
for (const raw of sources.flat()) {
|
|
111
|
+
const word = raw
|
|
112
|
+
.replace(/^#+/u, "")
|
|
113
|
+
.split(/[^\p{L}\p{N}_]+/u)
|
|
114
|
+
.map((part, index) => (index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)))
|
|
115
|
+
.join("");
|
|
116
|
+
if (word === "" || /^\d+$/u.test(word))
|
|
117
|
+
continue;
|
|
118
|
+
const key = word.toLowerCase();
|
|
119
|
+
if (seen.has(key))
|
|
120
|
+
continue;
|
|
121
|
+
seen.add(key);
|
|
122
|
+
tags.push(`#${word}`);
|
|
123
|
+
if (tags.length >= count)
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
return tags;
|
|
127
|
+
}
|
|
128
|
+
// The YouTube description without what only YouTube uses: its chapter lines and their heading,
|
|
129
|
+
// and the hashtag lines at the end (the post gets its own).
|
|
130
|
+
export function stripChapters(description) {
|
|
131
|
+
const lines = description.replace(/\r\n?/gu, "\n").split("\n");
|
|
132
|
+
const isChapter = (line) => {
|
|
133
|
+
const match = /^(\S+)\s+\S/u.exec(line.trim());
|
|
134
|
+
return match !== null && parseTimestamp(match[1] ?? "") !== undefined;
|
|
135
|
+
};
|
|
136
|
+
const kept = lines.filter((line, index) => {
|
|
137
|
+
if (isChapter(line))
|
|
138
|
+
return false;
|
|
139
|
+
const heading = /^(?:chapters|timestamps|contents)\s*:?\s*$/iu.test(line.trim());
|
|
140
|
+
return !(heading && isChapter(lines[index + 1] ?? ""));
|
|
141
|
+
});
|
|
142
|
+
const trailing = (line) => line.trim() === "" || /^(?:\s*#[\p{L}\p{N}_]+\s*)+$/u.test(line);
|
|
143
|
+
while (kept.length > 0 && trailing(kept.at(-1) ?? ""))
|
|
144
|
+
kept.pop();
|
|
145
|
+
return kept
|
|
146
|
+
.join("\n")
|
|
147
|
+
.replace(/\n{3,}/gu, "\n\n")
|
|
148
|
+
.trim();
|
|
149
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmdirSync, statSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { basename, dirname, extname, join } from "node:path";
|
|
3
3
|
import { pickedShortsOf } from "../shorts/clips.js";
|
|
4
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
4
5
|
import { backupsFolderName, projectDir, renderCacheFolder } from "./layout.js";
|
|
5
6
|
// The file in each project folder that says which project it is, for when the database and
|
|
6
7
|
// the folders disagree (a restored database, a folder renamed by hand). Reconcile keeps it.
|
|
@@ -20,7 +21,8 @@ export function arrangeKeys(db) {
|
|
|
20
21
|
(SELECT count(*)||':'||COALESCE(max(a.id),'') FROM project_assets a WHERE a.project_id=p.id) AS assets,
|
|
21
22
|
(SELECT count(*)||':'||COALESCE(max(o.id),'') FROM outputs o WHERE o.project_id=p.id) AS legacy,
|
|
22
23
|
(SELECT count(*)||':'||COALESCE(max(r.id),'') FROM revision_outputs r WHERE r.project_id=p.id AND r.selected=1 AND r.revision_id=h.revision_id) AS current
|
|
23
|
-
FROM projects p LEFT JOIN project_heads h ON h.project_id=p.id
|
|
24
|
+
FROM projects p LEFT JOIN project_heads h ON h.project_id=p.id
|
|
25
|
+
WHERE ${notTemplateSample("p")}`)
|
|
24
26
|
.all())
|
|
25
27
|
keys.set(String(row.id), [
|
|
26
28
|
`layout ${layoutVersion}`,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { closeSync, fchmodSync, fstatSync, fsyncSync, mkdirSync, openSync, rmSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { basename, dirname, isAbsolute, relative, sep } from "node:path";
|
|
3
|
+
import { errorText, internalError } from "../../kernel/errors.js";
|
|
3
4
|
import { redact } from "../../kernel/log.js";
|
|
4
5
|
import { outputPath } from "./layout.js";
|
|
5
6
|
export function allocateAsset(deps, projectId, filename) {
|
|
@@ -10,7 +11,7 @@ export function allocateAsset(deps, projectId, filename) {
|
|
|
10
11
|
const absolutePath = outputPath(deps.paths, projectId, path);
|
|
11
12
|
const directory = outputPath(deps.paths, projectId, `assets/${id}`);
|
|
12
13
|
if (dirname(absolutePath) !== directory)
|
|
13
|
-
throw new Error("
|
|
14
|
+
throw new Error(internalError("a file name to save is not a plain file name"));
|
|
14
15
|
mkdirSync(outputPath(deps.paths, projectId, "assets"), { recursive: true, mode: 0o700 });
|
|
15
16
|
mkdirSync(directory, { mode: 0o700 });
|
|
16
17
|
return { id, projectId, path, absolutePath };
|
|
@@ -20,7 +21,7 @@ export function sealAsset(deps, pending) {
|
|
|
20
21
|
try {
|
|
21
22
|
const stats = fstatSync(file);
|
|
22
23
|
if (!stats.isFile())
|
|
23
|
-
throw new Error("
|
|
24
|
+
throw new Error(internalError("a saved file is not a regular file"));
|
|
24
25
|
fchmodSync(file, 0o600);
|
|
25
26
|
fsyncSync(file);
|
|
26
27
|
return {
|
|
@@ -58,7 +59,7 @@ export function discardPreparedAssets(deps, assets) {
|
|
|
58
59
|
const filename = basename(asset.path);
|
|
59
60
|
requireBasename(filename);
|
|
60
61
|
if (asset.path !== `assets/${asset.id}/${filename}`) {
|
|
61
|
-
throw new Error("
|
|
62
|
+
throw new Error(internalError("a prepared file is not in its allocated directory"));
|
|
62
63
|
}
|
|
63
64
|
const directory = outputPath(deps.paths, asset.projectId, `assets/${asset.id}`);
|
|
64
65
|
const registered = deps.db
|
|
@@ -68,7 +69,7 @@ export function discardPreparedAssets(deps, assets) {
|
|
|
68
69
|
if (row.id === asset.id)
|
|
69
70
|
return true;
|
|
70
71
|
if (typeof row.path !== "string")
|
|
71
|
-
throw new Error("
|
|
72
|
+
throw new Error(internalError("a saved file has no path"));
|
|
72
73
|
const inside = relative(directory, outputPath(deps.paths, asset.projectId, row.path));
|
|
73
74
|
return (inside === "" ||
|
|
74
75
|
(inside !== ".." && !inside.startsWith(`..${sep}`) && !isAbsolute(inside)));
|
|
@@ -92,17 +93,14 @@ function requireBasename(filename) {
|
|
|
92
93
|
}) ||
|
|
93
94
|
/[. ]$/.test(filename) ||
|
|
94
95
|
/^(?:con|prn|aux|nul|conin\$|conout\$|com[1-9¹²³]|lpt[1-9¹²³])(?:\.|$)/i.test(filename))
|
|
95
|
-
throw new Error("
|
|
96
|
-
}
|
|
97
|
-
function messageOf(error) {
|
|
98
|
-
return error instanceof Error ? error.message : String(error);
|
|
96
|
+
throw new Error(internalError("a file name to save is not allowed on every system"));
|
|
99
97
|
}
|
|
100
98
|
function warnCleanup(deps, projectId, error) {
|
|
101
99
|
try {
|
|
102
|
-
deps.log.write("warn", "asset.cleanup", { projectId, detail:
|
|
100
|
+
deps.log.write("warn", "asset.cleanup", { projectId, detail: errorText(error) });
|
|
103
101
|
}
|
|
104
102
|
catch (loggingError) {
|
|
105
103
|
// A full disk can prevent both cleanup and file logging; preserve the write error.
|
|
106
|
-
process.emitWarning(redact(`asset.cleanup ${projectId}: ${
|
|
104
|
+
process.emitWarning(redact(`asset.cleanup ${projectId}: ${errorText(error)}; logging failed: ${errorText(loggingError)}`));
|
|
107
105
|
}
|
|
108
106
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { rowsOf } from "./backup-export.js";
|
|
2
|
+
// Designs and design templates in a backup's library part. Their pictures travel with every
|
|
3
|
+
// other picture in image_blobs; the files drawn from them are a cache and never travel.
|
|
4
|
+
export const designTables = [
|
|
5
|
+
"designs",
|
|
6
|
+
"design_steps",
|
|
7
|
+
"design_templates",
|
|
8
|
+
"design_template_revisions",
|
|
9
|
+
"design_template_samples",
|
|
10
|
+
];
|
|
11
|
+
export function exportDesigns(db, put) {
|
|
12
|
+
put("designs", rowsOf(db, "SELECT * FROM designs ORDER BY rowid"));
|
|
13
|
+
put("design_steps", rowsOf(db, "SELECT * FROM design_steps ORDER BY design_id, n"));
|
|
14
|
+
put("design_templates", rowsOf(db, "SELECT * FROM design_templates ORDER BY rowid"));
|
|
15
|
+
put("design_template_revisions", rowsOf(db, "SELECT * FROM design_template_revisions ORDER BY template_id, version"));
|
|
16
|
+
put("design_template_samples", rowsOf(db, "SELECT * FROM design_template_samples ORDER BY rowid"));
|
|
17
|
+
}
|
|
18
|
+
// The project a design links to, when the one here is the backup's own (it came in with this
|
|
19
|
+
// import, or with an earlier one: same id, same creation time); a different project that only
|
|
20
|
+
// shares the id is not linked.
|
|
21
|
+
function sameProject(db, scratch, id) {
|
|
22
|
+
if (typeof id !== "string")
|
|
23
|
+
return null;
|
|
24
|
+
const here = db.prepare("SELECT created_at FROM projects WHERE id=?").get(id);
|
|
25
|
+
const there = scratch.prepare("SELECT created_at FROM projects WHERE id=?").get(id);
|
|
26
|
+
return here !== undefined && there !== undefined && here.created_at === there.created_at
|
|
27
|
+
? id
|
|
28
|
+
: null;
|
|
29
|
+
}
|
|
30
|
+
// Added beside what is here: a design or template this install already has (same id) is kept
|
|
31
|
+
// as it is. A picture the other install was still making never lands here; a sample job it was
|
|
32
|
+
// running starts over.
|
|
33
|
+
export function mergeDesigns(db, scratch, insert) {
|
|
34
|
+
const has = (sql, id) => db.prepare(sql).get(id) !== undefined;
|
|
35
|
+
const templates = { added: 0, skipped: 0 };
|
|
36
|
+
for (const row of rowsOf(scratch, "SELECT * FROM design_templates ORDER BY rowid")) {
|
|
37
|
+
const id = String(row.id);
|
|
38
|
+
if (has("SELECT 1 FROM design_templates WHERE id=?", id)) {
|
|
39
|
+
templates.skipped += 1;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
insert("design_templates", row);
|
|
43
|
+
for (const revision of rowsOf(scratch, "SELECT * FROM design_template_revisions WHERE template_id=? ORDER BY version", id))
|
|
44
|
+
insert("design_template_revisions", revision);
|
|
45
|
+
templates.added += 1;
|
|
46
|
+
}
|
|
47
|
+
const designs = { added: 0, skipped: 0 };
|
|
48
|
+
for (const row of rowsOf(scratch, "SELECT * FROM designs ORDER BY rowid")) {
|
|
49
|
+
const id = String(row.id);
|
|
50
|
+
// A template's hidden sample is not one of the person's designs, so it isn't counted.
|
|
51
|
+
if (has("SELECT 1 FROM designs WHERE id=?", id)) {
|
|
52
|
+
if (row.sample_of === null)
|
|
53
|
+
designs.skipped += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
insert("designs", { ...row, project_id: sameProject(db, scratch, row.project_id) });
|
|
57
|
+
for (const step of rowsOf(scratch, "SELECT * FROM design_steps WHERE design_id=? ORDER BY n", id))
|
|
58
|
+
insert("design_steps", step.state === "making"
|
|
59
|
+
? {
|
|
60
|
+
...step,
|
|
61
|
+
state: "failed",
|
|
62
|
+
error: "Stopped by the backup. Press Try again.",
|
|
63
|
+
settled_at: step.created_at ?? null,
|
|
64
|
+
}
|
|
65
|
+
: step);
|
|
66
|
+
if (row.sample_of === null)
|
|
67
|
+
designs.added += 1;
|
|
68
|
+
}
|
|
69
|
+
for (const row of rowsOf(scratch, "SELECT * FROM design_template_samples ORDER BY rowid"))
|
|
70
|
+
if (has("SELECT 1 FROM design_templates WHERE id=?", String(row.template_id)) &&
|
|
71
|
+
!has("SELECT 1 FROM design_template_samples WHERE template_id=?", String(row.template_id)))
|
|
72
|
+
insert("design_template_samples", row.state === "making" ? { ...row, state: "queued" } : row);
|
|
73
|
+
return { designs, templates };
|
|
74
|
+
}
|
|
@@ -3,7 +3,10 @@ import { constants, lstatSync, readdirSync } from "node:fs";
|
|
|
3
3
|
import { open } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { transact } from "../../kernel/db/tx.js";
|
|
6
|
+
import { hasErrnoCode } from "../../kernel/errors.js";
|
|
7
|
+
import { notTemplateSample } from "../template-studio/repo.js";
|
|
6
8
|
import { projectMarker } from "./arrange.js";
|
|
9
|
+
import { exportDesigns } from "./backup-designs.js";
|
|
7
10
|
import { backupFormat, backupSchemaVersion, checksumsMember, fontMember, imageMember, libraryMember, manifestMember, projectFileMember, projectMember, projectTables, safeRelativePath, stagedMember, usageMember, } from "./backup-format.js";
|
|
8
11
|
import { outputPath, projectDir, stagingPath } from "./layout.js";
|
|
9
12
|
import { exportableSettings, installedUploadedFontFiles } from "./portable.js";
|
|
@@ -36,7 +39,7 @@ export function busyProjects(deps) {
|
|
|
36
39
|
OR EXISTS(SELECT 1 FROM revision_work w WHERE w.project_id=p.id AND w.state='running')
|
|
37
40
|
OR EXISTS(SELECT 1 FROM project_queue q WHERE q.project_id=p.id AND q.state='queued')
|
|
38
41
|
AS busy
|
|
39
|
-
FROM projects p ORDER BY p.created_at, p.id`)
|
|
42
|
+
FROM projects p WHERE ${notTemplateSample("p")} ORDER BY p.created_at, p.id`)
|
|
40
43
|
.all()
|
|
41
44
|
.flatMap((row) => {
|
|
42
45
|
const id = String(row.id);
|
|
@@ -60,7 +63,7 @@ export function planBackup(deps) {
|
|
|
60
63
|
},
|
|
61
64
|
},
|
|
62
65
|
projects: deps.db
|
|
63
|
-
.prepare(
|
|
66
|
+
.prepare(`SELECT id,title FROM projects WHERE ${notTemplateSample()} ORDER BY created_at,id`)
|
|
64
67
|
.all()
|
|
65
68
|
.map((row) => projectSnapshot(deps, String(row.id), String(row.title))),
|
|
66
69
|
}));
|
|
@@ -238,7 +241,7 @@ function projectFiles(root) {
|
|
|
238
241
|
entries = readdirSync(join(root, relative), { withFileTypes: true });
|
|
239
242
|
}
|
|
240
243
|
catch (error) {
|
|
241
|
-
if (error
|
|
244
|
+
if (hasErrnoCode(error, "ENOENT"))
|
|
242
245
|
return;
|
|
243
246
|
throw error;
|
|
244
247
|
}
|
|
@@ -271,6 +274,7 @@ function librarySnapshot(deps) {
|
|
|
271
274
|
put("narration_aliases", rowsOf(db, "SELECT * FROM narration_aliases ORDER BY position,rowid"));
|
|
272
275
|
put("project_templates", rowsOf(db, "SELECT * FROM project_templates ORDER BY rowid"));
|
|
273
276
|
put("project_template_revisions", rowsOf(db, "SELECT * FROM project_template_revisions ORDER BY template_id,version"));
|
|
277
|
+
put("template_gates", rowsOf(db, "SELECT * FROM template_gates ORDER BY template_id,version"));
|
|
274
278
|
put("schedules", rowsOf(db, "SELECT * FROM schedules ORDER BY rowid"));
|
|
275
279
|
put("schedule_runs", rowsOf(db, "SELECT * FROM schedule_runs ORDER BY rowid"));
|
|
276
280
|
put("schedule_topics", rowsOf(db, "SELECT * FROM schedule_topics ORDER BY rowid"));
|
|
@@ -281,6 +285,7 @@ function librarySnapshot(deps) {
|
|
|
281
285
|
put("episode_memories", rowsOf(db, "SELECT * FROM episode_memories ORDER BY rowid"));
|
|
282
286
|
put("channel_videos", rowsOf(db, "SELECT * FROM channel_videos ORDER BY rowid"));
|
|
283
287
|
put("standalone_usage", rowsOf(db, "SELECT * FROM standalone_usage ORDER BY rowid"));
|
|
288
|
+
exportDesigns(db, put);
|
|
284
289
|
// Every picture, not only the cast's: a project's config names the pictures it was started
|
|
285
290
|
// with by hash, and a Rebuild reads them from here.
|
|
286
291
|
const images = db
|
|
@@ -75,6 +75,8 @@ export const projectTables = [
|
|
|
75
75
|
"plan_limit_readings",
|
|
76
76
|
"project_channels",
|
|
77
77
|
"project_trash",
|
|
78
|
+
// Since 4.0.0: each project's posts to other sites, their hand edits and links.
|
|
79
|
+
"social_posts",
|
|
78
80
|
];
|
|
79
81
|
export const libraryTables = [
|
|
80
82
|
"settings",
|
|
@@ -103,6 +105,14 @@ export const libraryTables = [
|
|
|
103
105
|
// Since 3.0.0: what topic generation, episode summaries and cast pictures cost, which
|
|
104
106
|
// belongs to a schedule or channel rather than a project.
|
|
105
107
|
"standalone_usage",
|
|
108
|
+
// Since 4.0.0: which template versions the template studio marked ready.
|
|
109
|
+
"template_gates",
|
|
110
|
+
// Since 4.0.0: designs with every version of their picture, and design templates.
|
|
111
|
+
"designs",
|
|
112
|
+
"design_steps",
|
|
113
|
+
"design_templates",
|
|
114
|
+
"design_template_revisions",
|
|
115
|
+
"design_template_samples",
|
|
106
116
|
];
|
|
107
117
|
export const usageTables = ["telemetry_events"];
|
|
108
118
|
// Ceilings a well-formed backup of a real install stays far below. They bound what a hostile
|
|
@@ -16,6 +16,7 @@ import { projectTemplateSchema } from "../project-templates/schema.js";
|
|
|
16
16
|
import { revisionById } from "../revisions/repo.js";
|
|
17
17
|
import { runsForSchedule, scheduleRows } from "../schedules/repo.js";
|
|
18
18
|
import { allTelemetryEvents } from "../telemetry/repo.js";
|
|
19
|
+
import { mergeDesigns } from "./backup-designs.js";
|
|
19
20
|
import { projectRows, rowsOf } from "./backup-export.js";
|
|
20
21
|
import { backupMaxJsonBytes, backupMaxManifestBytes, backupSchemaVersion, checksumsMember, checksumsSchema, fontMember, imageMember, libraryMember, libraryPartSchema, libraryTables, manifestHead, manifestMember, manifestSchema, projectFileMember, projectMember, projectPartSchema, projectTables, stagedMember, usageMember, usagePartSchema, usageTables, } from "./backup-format.js";
|
|
21
22
|
import { outputPath, projectDir, stagingPath } from "./layout.js";
|
|
@@ -382,6 +383,8 @@ function loadScratch(clock, manifest, library, usage, parts) {
|
|
|
382
383
|
// broken fails there, and the upgrade's own message would talk about downgrading.
|
|
383
384
|
throw damaged("some of its records point at records it doesn't hold.");
|
|
384
385
|
}
|
|
386
|
+
// A design only links to a project; one whose project didn't travel stays, unlinked.
|
|
387
|
+
scratch.exec("UPDATE designs SET project_id=NULL WHERE project_id NOT IN (SELECT id FROM projects)");
|
|
385
388
|
if (scratch.prepare("PRAGMA foreign_key_check").all().length > 0)
|
|
386
389
|
throw damaged("some of its records point at records it doesn't hold.");
|
|
387
390
|
return scratch;
|
|
@@ -433,7 +436,7 @@ function checkScratch(deps, scratch, library, parts) {
|
|
|
433
436
|
}
|
|
434
437
|
}
|
|
435
438
|
catch {
|
|
436
|
-
throw unreadable("a PDF
|
|
439
|
+
throw unreadable("a PDF look");
|
|
437
440
|
}
|
|
438
441
|
try {
|
|
439
442
|
for (const row of rowsOf(scratch, "SELECT id FROM channels")) {
|
|
@@ -462,7 +465,7 @@ function checkScratch(deps, scratch, library, parts) {
|
|
|
462
465
|
throw new Error("staged files");
|
|
463
466
|
}
|
|
464
467
|
catch {
|
|
465
|
-
throw unreadable("a
|
|
468
|
+
throw unreadable("a draft on Create");
|
|
466
469
|
}
|
|
467
470
|
try {
|
|
468
471
|
allTelemetryEvents(scratch);
|
|
@@ -633,6 +636,8 @@ function commit(deps, work, manifest, prepared) {
|
|
|
633
636
|
}
|
|
634
637
|
insertRow(db, "project_template_revisions", next);
|
|
635
638
|
}
|
|
639
|
+
for (const gate of rowsOf(scratch, "SELECT * FROM template_gates WHERE template_id=? ORDER BY version", id))
|
|
640
|
+
insertRow(db, "template_gates", gate);
|
|
636
641
|
if (renamed)
|
|
637
642
|
templates.renamed += 1;
|
|
638
643
|
else
|
|
@@ -640,8 +645,15 @@ function commit(deps, work, manifest, prepared) {
|
|
|
640
645
|
}
|
|
641
646
|
const schedules = { added: 0, renamed: 0, skipped: 0, paused: 0 };
|
|
642
647
|
for (const schedule of rowsOf(scratch, "SELECT * FROM schedules ORDER BY rowid")) {
|
|
643
|
-
|
|
644
|
-
|
|
648
|
+
// A design schedule's template comes in with the designs, further down.
|
|
649
|
+
const design = schedule.template_kind === "design";
|
|
650
|
+
const templateHere = design
|
|
651
|
+
? scratch
|
|
652
|
+
.prepare("SELECT 1 FROM design_templates WHERE id=?")
|
|
653
|
+
.get(String(schedule.template_id)) !== undefined ||
|
|
654
|
+
has("SELECT 1 FROM design_templates WHERE id=?", String(schedule.template_id))
|
|
655
|
+
: has("SELECT 1 FROM project_template_revisions WHERE template_id=? AND version=?", String(schedule.template_id), Number(schedule.template_version));
|
|
656
|
+
if (has("SELECT 1 FROM schedules WHERE id=?", String(schedule.id)) || !templateHere) {
|
|
645
657
|
schedules.skipped += 1;
|
|
646
658
|
continue;
|
|
647
659
|
}
|
|
@@ -732,6 +744,10 @@ function commit(deps, work, manifest, prepared) {
|
|
|
732
744
|
move(folder, projectDir(paths, listed.id));
|
|
733
745
|
imported.push({ id: listed.id, title: listed.title });
|
|
734
746
|
}
|
|
747
|
+
// After the projects, so a design keeps its link to one that came in with it.
|
|
748
|
+
const merged = mergeDesigns(db, scratch, (table, row) => {
|
|
749
|
+
insertRow(db, table, row);
|
|
750
|
+
});
|
|
735
751
|
const summary = {
|
|
736
752
|
backup: {
|
|
737
753
|
id: manifest.backupId,
|
|
@@ -748,6 +764,8 @@ function commit(deps, work, manifest, prepared) {
|
|
|
748
764
|
schedules,
|
|
749
765
|
voices: { added: voicesAdded, renamed: 0, skipped: voicesSkipped },
|
|
750
766
|
drafts,
|
|
767
|
+
designs: { ...merged.designs, renamed: 0 },
|
|
768
|
+
designTemplates: { ...merged.templates, renamed: 0 },
|
|
751
769
|
settings: { added: settingsAdded, kept: settingsKept },
|
|
752
770
|
fonts,
|
|
753
771
|
usage: { events, alreadyImported },
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { rmSync } from "node:fs";
|
|
2
|
+
import { errorText } from "../../kernel/errors.js";
|
|
2
3
|
import { derive } from "../../kernel/runner/graph.js";
|
|
3
4
|
import { stagesOf } from "../admission/repo.js";
|
|
5
|
+
import { dropReshaped } from "../social/reshape.js";
|
|
4
6
|
import { projectDir, renderCacheDir } from "./layout.js";
|
|
5
7
|
// A run in flight: a call the runner holds, or a stage running or waiting out a retry.
|
|
6
8
|
export function projectBusy(deps, projectId) {
|
|
@@ -19,13 +21,15 @@ export function deleteProject(deps, projectId) {
|
|
|
19
21
|
try {
|
|
20
22
|
rmSync(dir, { recursive: true, force: true });
|
|
21
23
|
rmSync(renderCacheDir(deps.paths, projectId), { recursive: true, force: true });
|
|
24
|
+
// The pictures cut for its posts (`slices/social/reshape.ts`).
|
|
25
|
+
dropReshaped(deps.paths, projectId);
|
|
22
26
|
}
|
|
23
27
|
catch (error) {
|
|
24
28
|
deps.log.write("warn", "project.delete", {
|
|
25
29
|
projectId,
|
|
26
|
-
detail:
|
|
30
|
+
detail: errorText(error),
|
|
27
31
|
});
|
|
28
|
-
return { ok: false, reason: "files", detail:
|
|
32
|
+
return { ok: false, reason: "files", detail: errorText(error) };
|
|
29
33
|
}
|
|
30
34
|
// Stages, attempts, pieces and outputs go with it: every one of those tables declares
|
|
31
35
|
// ON DELETE CASCADE on the project, and the connection runs with foreign keys on
|
|
@@ -36,6 +40,3 @@ export function deleteProject(deps, projectId) {
|
|
|
36
40
|
places.forget(projectId);
|
|
37
41
|
return { ok: true };
|
|
38
42
|
}
|
|
39
|
-
function messageOf(error) {
|
|
40
|
-
return error instanceof Error ? error.message : String(error);
|
|
41
|
-
}
|
|
@@ -3,8 +3,9 @@ import { createReadStream, lstatSync, readdirSync } from "node:fs";
|
|
|
3
3
|
import { access, constants, copyFile, lstat, mkdir, readdir, rename, statfs, utimes, } from "node:fs/promises";
|
|
4
4
|
import { dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
import { errorText, hasErrnoCode } from "../../kernel/errors.js";
|
|
6
7
|
import { repoint } from "../../kernel/paths.js";
|
|
7
|
-
import { readSetting, writeSetting } from "../settings/repo.js";
|
|
8
|
+
import { deleteSetting, readSetting, writeSetting } from "../settings/repo.js";
|
|
8
9
|
import { backupsFolderName, renderCacheFolder } from "./layout.js";
|
|
9
10
|
// Where the files a user looks at live: project folders, scheduled backups and anything else
|
|
10
11
|
// Slopify saves for them. New installs keep them in <Documents>/Slopify; installs from before
|
|
@@ -73,7 +74,7 @@ export async function ensureFilesFolders(layout) {
|
|
|
73
74
|
}
|
|
74
75
|
async function emptyOrMissing(path) {
|
|
75
76
|
const entries = await readdir(path).catch((error) => {
|
|
76
|
-
if (
|
|
77
|
+
if (hasErrnoCode(error, "ENOENT"))
|
|
77
78
|
return [];
|
|
78
79
|
throw error;
|
|
79
80
|
});
|
|
@@ -172,7 +173,7 @@ export function createFilesService(deps) {
|
|
|
172
173
|
finished = {
|
|
173
174
|
...current.progress,
|
|
174
175
|
phase: "failed",
|
|
175
|
-
error:
|
|
176
|
+
error: errorText(error),
|
|
176
177
|
};
|
|
177
178
|
})
|
|
178
179
|
.finally(() => {
|
|
@@ -294,7 +295,7 @@ function sourceFiles(pair) {
|
|
|
294
295
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
295
296
|
}
|
|
296
297
|
catch (error) {
|
|
297
|
-
if (
|
|
298
|
+
if (hasErrnoCode(error, "ENOENT"))
|
|
298
299
|
return;
|
|
299
300
|
throw error;
|
|
300
301
|
}
|
|
@@ -383,7 +384,7 @@ async function runMove(deps, from, target, pairs, update) {
|
|
|
383
384
|
}
|
|
384
385
|
const to = { kind: "root", root: target };
|
|
385
386
|
writeSetting(deps.db, filesLocationKey, JSON.stringify(to));
|
|
386
|
-
deps.db
|
|
387
|
+
deleteSetting(deps.db, filesMoveKey);
|
|
387
388
|
const old = from.kind === "root" ? from.root : deps.paths.projects;
|
|
388
389
|
repoint(deps.paths, filesLayoutOf(to, deps.paths.dataDir));
|
|
389
390
|
return old;
|
|
@@ -514,9 +515,6 @@ function within(root, path) {
|
|
|
514
515
|
function samePath(a, b) {
|
|
515
516
|
return relative(resolve(a), resolve(b)) === "";
|
|
516
517
|
}
|
|
517
|
-
function hasCode(error, code) {
|
|
518
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
519
|
-
}
|
|
520
518
|
function formatBytes(bytes) {
|
|
521
519
|
if (!Number.isFinite(bytes))
|
|
522
520
|
return "unknown";
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { extname, isAbsolute, relative, resolve } from "node:path";
|
|
2
|
-
|
|
2
|
+
import { internalError } from "../../kernel/errors.js";
|
|
3
|
+
import { templateSamplesDir } from "../../kernel/paths.js";
|
|
4
|
+
// A project's folder: its readable name once it has one (`places.ts`), its id until then. A
|
|
5
|
+
// template's studio sample is kept in the data dir by its id, out of the user's Projects folder.
|
|
3
6
|
export function projectDir(paths, projectId) {
|
|
7
|
+
if (paths.samples?.has(projectId) === true)
|
|
8
|
+
return contained(templateSamplesDir(paths), projectId);
|
|
4
9
|
return contained(paths.projects, paths.places?.folderOf(projectId) ?? projectId);
|
|
5
10
|
}
|
|
6
11
|
// The clips of each project's last render (`slices/video/clip-cache.ts`). Hidden, so
|
|
@@ -8,10 +13,14 @@ export function projectDir(paths, projectId) {
|
|
|
8
13
|
// files leaves it behind and a render simply encodes its clips again.
|
|
9
14
|
export const renderCacheFolder = ".render-cache";
|
|
10
15
|
export function renderCacheDir(paths, projectId) {
|
|
16
|
+
if (paths.samples?.has(projectId) === true)
|
|
17
|
+
return contained(templateSamplesDir(paths), `${renderCacheFolder}/${projectId}`);
|
|
11
18
|
return contained(paths.projects, `${renderCacheFolder}/${projectId}`);
|
|
12
19
|
}
|
|
13
20
|
// A stored path on disk: where it was moved to (`places.ts`), or the stored path itself.
|
|
14
21
|
export function outputPath(paths, projectId, relativePath) {
|
|
22
|
+
if (paths.samples?.has(projectId) === true)
|
|
23
|
+
return contained(projectDir(paths, projectId), relativePath);
|
|
15
24
|
return contained(projectDir(paths, projectId), paths.places?.placeOf(projectId, relativePath) ?? relativePath);
|
|
16
25
|
}
|
|
17
26
|
// Scheduled backups (slices/backups) land in paths.backups unless the user picks another
|
|
@@ -31,7 +40,7 @@ function contained(root, path) {
|
|
|
31
40
|
const target = resolve(root, path);
|
|
32
41
|
const inside = relative(root, target);
|
|
33
42
|
if (inside === "" || inside.startsWith("..") || isAbsolute(inside)) {
|
|
34
|
-
throw new Error(`
|
|
43
|
+
throw new Error(internalError(`the saved file path ${path} resolves outside ${root}`));
|
|
35
44
|
}
|
|
36
45
|
return target;
|
|
37
46
|
}
|
|
@@ -111,6 +120,8 @@ export function outputFileName(role, index, extension, stageKind) {
|
|
|
111
120
|
return `audio-levelled${extension}`;
|
|
112
121
|
case "reference":
|
|
113
122
|
return `reference${extension}`;
|
|
123
|
+
case "social_post":
|
|
124
|
+
return `social/post-${String(index).padStart(2, "0")}.txt`;
|
|
114
125
|
case "image":
|
|
115
126
|
return `images/${String(index).padStart(3, "0")}${extension}`;
|
|
116
127
|
}
|
|
@@ -52,5 +52,8 @@ export const outputRoles = [
|
|
|
52
52
|
// Level the volume: a narration segment joined again from its pieces, each brought to one
|
|
53
53
|
// loudness first (`meta.segment` says which). The exports play it in place of the plain join.
|
|
54
54
|
"audio_levelled",
|
|
55
|
+
// A post for another site written by a Library prompt of kind "post" (`slices/social`);
|
|
56
|
+
// `meta.platform` says which site.
|
|
57
|
+
"social_post",
|
|
55
58
|
];
|
|
56
59
|
export const stagedFileStates = ["copying", "staged"];
|