@gentbajko/slopify 2.5.0 → 3.0.1
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/LICENSE +201 -21
- package/NOTICE +12 -0
- package/README.md +24 -41
- package/SUBTITLES.md +1 -1
- package/dist/adapter-registry.js +31 -0
- package/dist/adapters/alignment/cache.js +4 -1
- package/dist/adapters/alignment/ctc.js +25 -23
- package/dist/adapters/alignment/index.js +37 -6
- package/dist/adapters/alignment/multilingual.js +267 -0
- package/dist/adapters/alignment/protocol.js +11 -0
- package/dist/adapters/alignment/quality.js +4 -3
- package/dist/adapters/alignment/sentences.js +95 -0
- package/dist/adapters/alignment/spec.js +24 -0
- package/dist/adapters/alignment/spell.js +769 -0
- package/dist/adapters/alignment/text.js +56 -9
- package/dist/adapters/alignment/window.js +34 -30
- package/dist/adapters/alignment/worker.js +23 -21
- package/dist/adapters/explain.js +11 -11
- package/dist/adapters/host-cli/index.js +44 -5
- package/dist/adapters/host-cli/transport.js +7 -5
- package/dist/adapters/image/bytes.js +2 -2
- package/dist/adapters/image/codex-output.js +1 -1
- package/dist/adapters/image/codex.js +87 -22
- package/dist/adapters/image/fal.js +13 -5
- package/dist/adapters/image/google.js +11 -8
- package/dist/adapters/image/openai.js +14 -7
- package/dist/adapters/image/reference.js +34 -0
- package/dist/adapters/image/replicate.js +7 -2
- package/dist/adapters/image/video.js +2 -2
- package/dist/adapters/key-probes.js +85 -0
- package/dist/adapters/llm/claude-code.js +168 -32
- package/dist/adapters/llm/cli-login-error.js +1 -1
- package/dist/adapters/llm/codex-limits.js +157 -0
- package/dist/adapters/llm/codex.js +99 -12
- package/dist/adapters/llm/document-workspace.js +2 -2
- package/dist/adapters/llm/gemini-workspace.js +1 -1
- package/dist/adapters/llm/gemini.js +16 -3
- package/dist/adapters/llm/image-workspace.js +58 -0
- package/dist/adapters/llm/openrouter.js +11 -3
- package/dist/adapters/llm/run-cli.js +12 -7
- package/dist/adapters/tts/cartesia.js +10 -0
- package/dist/adapters/tts/elevenlabs.js +31 -9
- package/dist/adapters/tts/gemini.js +206 -0
- package/dist/adapters/tts/inworld-async.js +9 -5
- package/dist/adapters/tts/inworld.js +17 -3
- package/dist/adapters/tts/openai.js +3 -0
- package/dist/adapters/tts/pcm-mp3.js +62 -0
- package/dist/adapters/tts/system.js +147 -0
- package/dist/adapters/tts/voice-languages.js +80 -0
- package/dist/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansArabic-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansDevanagari-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansHebrew-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/NotoSansThai-Regular.ttf +0 -0
- package/dist/assets/fonts/noto/OFL.txt +93 -0
- package/dist/assets/fonts/noto/SOURCE.txt +18 -0
- package/dist/assets/models.yaml +38 -0
- package/dist/assets/sample/sample-audiobook.tar +0 -0
- package/dist/assets/sample/sample-podcast.tar +0 -0
- package/dist/assets/sample/sample-project.tar +0 -0
- package/dist/assets/style-preview/narration.mp3 +0 -0
- package/dist/assets/style-preview/tall-1.jpg +0 -0
- package/dist/assets/style-preview/tall-2.jpg +0 -0
- package/dist/assets/style-preview/tall-3.jpg +0 -0
- package/dist/assets/style-preview/wide-1.jpg +0 -0
- package/dist/assets/style-preview/wide-2.jpg +0 -0
- package/dist/assets/style-preview/wide-3.jpg +0 -0
- package/dist/catalog/merge.js +132 -0
- package/dist/catalog/registry.js +17 -14
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +147 -8
- package/dist/catalog/validate.js +2 -2
- package/dist/compose.yaml +71 -0
- package/dist/edge/autostart/docker-record.js +32 -0
- package/dist/edge/autostart/docker.js +118 -0
- package/dist/edge/autostart/index.js +78 -0
- package/dist/edge/autostart/launcher.js +176 -0
- package/dist/edge/autostart/model.js +3 -0
- package/dist/edge/autostart/native.js +210 -0
- package/dist/edge/autostart/prompt.js +72 -0
- package/dist/edge/autostart/service.js +90 -0
- package/dist/edge/cli-args.js +71 -0
- package/dist/edge/cli.js +64 -63
- package/dist/edge/docker-install/activation.js +56 -0
- package/dist/edge/docker-install/apply.js +458 -0
- package/dist/edge/docker-install/engine.js +362 -0
- package/dist/edge/docker-install/run.js +160 -0
- package/dist/edge/docker-install/state.js +146 -0
- package/dist/edge/{docker-projects → docker-install}/volume.js +1 -5
- package/dist/edge/docker.js +14 -22
- package/dist/edge/events/hub.js +3 -1
- package/dist/edge/host-cli.js +1 -1
- package/dist/edge/http/actions.js +38 -11
- package/dist/edge/http/app.js +60 -2
- package/dist/edge/http/auditions.js +70 -0
- package/dist/edge/http/autostart.js +37 -0
- package/dist/edge/http/byte-range.js +42 -0
- package/dist/edge/http/channel-memory.js +92 -0
- package/dist/edge/http/channels.js +128 -0
- package/dist/edge/http/diagnostics.js +1 -0
- package/dist/edge/http/draft-files.js +2 -4
- package/dist/edge/http/entries.js +22 -3
- package/dist/edge/http/files.js +11 -7
- package/dist/edge/http/folder-location.js +1 -1
- package/dist/edge/http/home.js +39 -0
- package/dist/edge/http/host-cli.js +29 -5
- package/dist/edge/http/narration-peaks.js +76 -0
- package/dist/edge/http/onboarding.js +212 -0
- package/dist/edge/http/open-folder.js +1 -1
- package/dist/edge/http/patch-notes.js +45 -0
- package/dist/edge/http/planning.js +4 -2
- package/dist/edge/http/project-create.js +87 -0
- package/dist/edge/http/project-templates.js +19 -2
- package/dist/edge/http/projects.js +37 -100
- package/dist/edge/http/prompts.js +40 -3
- package/dist/edge/http/pronunciations.js +23 -4
- package/dist/edge/http/providers.js +119 -3
- package/dist/edge/http/reviews.js +131 -0
- package/dist/edge/http/revision-files.js +3 -5
- package/dist/edge/http/revisions.js +1 -1
- package/dist/edge/http/run-cost.js +25 -0
- package/dist/edge/http/schedules.js +115 -6
- package/dist/edge/http/settings.js +84 -6
- package/dist/edge/http/storage-files.js +50 -0
- package/dist/edge/http/storage.js +43 -2
- package/dist/edge/http/studio.js +287 -0
- package/dist/edge/http/style-preview.js +61 -0
- package/dist/edge/http/subtitles.js +1 -1
- package/dist/edge/http/trash.js +69 -0
- package/dist/edge/http/tutorials.js +59 -0
- package/dist/edge/http/update.js +24 -3
- package/dist/edge/http/whats-new.js +15 -0
- package/dist/edge/http/youtube-edits.js +92 -0
- package/dist/edge/native-update.js +62 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/gemini-login.js +83 -0
- package/dist/host-cli/open-folder.js +10 -10
- package/dist/host-cli/runtime.js +9 -1
- package/dist/host-cli/status.js +4 -2
- package/dist/kernel/db/migrations/0025-automatic-reviews.sql +40 -0
- package/dist/kernel/db/migrations/0026-schedule-topic-generation.sql +23 -0
- package/dist/kernel/db/migrations/0027-run-cost.sql +58 -0
- package/dist/kernel/db/migrations/0030-automatic-retries.sql +18 -0
- package/dist/kernel/db/migrations/0031-prompt-history-and-description-edits.sql +33 -0
- package/dist/kernel/db/migrations/0032-channels.sql +65 -0
- package/dist/kernel/db/migrations/0034-script-prompts.sql +23 -0
- package/dist/kernel/db/migrations/0035-narration-aliases.sql +13 -0
- package/dist/kernel/db/migrations/0037-project-uploads.sql +8 -0
- package/dist/kernel/db/migrations/0038-voice-languages.sql +7 -0
- package/dist/kernel/db/migrations/0039-channel-essentials.sql +64 -0
- package/dist/kernel/db/migrations/0040-standalone-usage.sql +35 -0
- package/dist/kernel/db/migrations/0041-cast-hosts.sql +3 -0
- package/dist/kernel/paths.js +27 -6
- package/dist/kernel/pipeline.js +4 -1
- package/dist/kernel/ports/host-cli.js +122 -14
- package/dist/kernel/ports/key-probe.js +1 -0
- package/dist/kernel/ports/languages.js +157 -0
- package/dist/kernel/ports/model.js +10 -5
- package/dist/kernel/ports/narration-aliases.js +60 -0
- package/dist/kernel/ports/plan-limits.js +36 -0
- package/dist/kernel/ports/system-speech.js +203 -0
- package/dist/kernel/runner/attempt.js +17 -8
- package/dist/kernel/runner/audition.js +36 -0
- package/dist/kernel/runner/graph.js +40 -5
- package/dist/kernel/runner/index.js +39 -9
- package/dist/kernel/runner/meter.js +1 -0
- package/dist/kernel/runner/providers.js +142 -7
- package/dist/kernel/runner/retry-policy.js +43 -0
- package/dist/kernel/runner/standalone.js +134 -0
- package/dist/kernel/runner/work-authority.js +28 -2
- package/dist/main.js +277 -16
- package/dist/model-catalog.js +2 -0
- package/dist/patch-notes/0.4.2-to-1.0.md +93 -0
- package/dist/patch-notes/1.0-to-2.0.md +74 -0
- package/dist/patch-notes/2.0-to-3.0.md +257 -0
- package/dist/patch-notes/3.0.0.md +70 -0
- package/dist/patch-notes/3.0.1.md +105 -0
- package/dist/patch-notes/index.json +32 -0
- package/dist/slices/admission/model.js +27 -0
- package/dist/slices/admission/repo.js +24 -4
- package/dist/slices/admission/rules.js +80 -2
- package/dist/slices/admission/schema.js +58 -1
- package/dist/slices/admission/short-mode.js +47 -0
- package/dist/slices/admission/start.js +42 -6
- package/dist/slices/article/continuation.js +2 -2
- package/dist/slices/article/provided-entries.js +2 -2
- package/dist/slices/article/run.js +6 -2
- package/dist/slices/article/segments.js +3 -3
- package/dist/slices/backups/folder.js +14 -6
- package/dist/slices/batch/index.js +7 -2
- package/dist/slices/cancel/index.js +1 -1
- package/dist/slices/channels/cast-images.js +110 -0
- package/dist/slices/channels/cast-match.js +32 -0
- package/dist/slices/channels/images.js +19 -0
- package/dist/slices/channels/model.js +5 -0
- package/dist/slices/channels/rebrand.js +100 -0
- package/dist/slices/channels/repo.js +221 -0
- package/dist/slices/channels/runs.js +129 -0
- package/dist/slices/channels/schema.js +152 -0
- package/dist/slices/channels/service.js +180 -0
- package/dist/slices/channels/studio-csv.js +110 -0
- package/dist/slices/channels/videos.js +120 -0
- package/dist/slices/checkpoints/recovery.js +10 -0
- package/dist/slices/control/index.js +5 -2
- package/dist/slices/control/providers.js +4 -1
- package/dist/slices/document/fonts.js +1 -1
- package/dist/slices/document/render.js +1 -1
- package/dist/slices/episodes/related.js +90 -0
- package/dist/slices/episodes/repo.js +60 -0
- package/dist/slices/episodes/service.js +58 -0
- package/dist/slices/episodes/summarize.js +170 -0
- package/dist/slices/estimate/index.js +109 -28
- package/dist/slices/estimate/requests.js +68 -2
- package/dist/slices/eta/history.js +56 -0
- package/dist/slices/eta/model.js +63 -0
- package/dist/slices/eta/view.js +25 -0
- package/dist/slices/fixes/rules.js +73 -0
- package/dist/slices/fonts/coverage.js +82 -0
- package/dist/slices/fonts/sfnt.js +74 -0
- package/dist/slices/images/run.js +8 -5
- package/dist/slices/images/scale.js +84 -0
- package/dist/slices/library/diff.js +122 -0
- package/dist/slices/library/history.js +100 -0
- package/dist/slices/library/model.js +3 -0
- package/dist/slices/library/photorealistic.js +49 -0
- package/dist/slices/library/repo.js +19 -14
- package/dist/slices/library/save.js +62 -12
- package/dist/slices/library/slots.js +7 -1
- package/dist/slices/library/used-by.js +153 -0
- package/dist/slices/loudness/level-pieces.js +41 -0
- package/dist/slices/loudness/loudnorm.js +164 -0
- package/dist/slices/loudness/model.js +153 -0
- package/dist/slices/model-upkeep/model.js +10 -0
- package/dist/slices/model-upkeep/switch.js +217 -0
- package/dist/slices/model-upkeep/usage.js +185 -0
- package/dist/slices/narration/aliases-library.js +31 -0
- package/dist/slices/narration/aliases-schema.js +53 -0
- package/dist/slices/narration/aliases.js +49 -0
- package/dist/slices/narration/blocks.js +352 -0
- package/dist/slices/narration/chunk.js +19 -7
- package/dist/slices/narration/concat.js +2 -2
- package/dist/slices/narration/describe.js +45 -0
- package/dist/slices/narration/pauses-model.js +63 -0
- package/dist/slices/narration/pauses.js +269 -0
- package/dist/slices/narration/peaks-model.js +1 -0
- package/dist/slices/narration/peaks.js +94 -0
- package/dist/slices/narration/preparation.js +21 -3
- package/dist/slices/narration/pronunciation-chunks.js +3 -3
- package/dist/slices/narration/pronunciation.js +72 -25
- package/dist/slices/narration/run.js +6 -6
- package/dist/slices/narration/shared-glossary.js +1 -1
- package/dist/slices/narration/steering.js +15 -4
- package/dist/slices/notifications/notifier.js +47 -3
- package/dist/slices/notifications/rules.js +48 -3
- package/dist/slices/onboarding/copy.js +143 -0
- package/dist/slices/onboarding/first-run.js +72 -0
- package/dist/slices/onboarding/full-video.js +81 -0
- package/dist/slices/onboarding/install.js +119 -0
- package/dist/slices/onboarding/model.js +85 -0
- package/dist/slices/onboarding/packs.js +491 -0
- package/dist/slices/onboarding/quick-short.js +144 -0
- package/dist/slices/onboarding/sample.js +132 -0
- package/dist/slices/onboarding/state.js +68 -0
- package/dist/slices/onboarding/template.js +73 -0
- package/dist/slices/patch-notes/library.js +73 -0
- package/dist/slices/patch-notes/seen.js +77 -0
- package/dist/slices/play-drafts/convert.js +127 -8
- package/dist/slices/play-drafts/readiness.js +4 -1
- package/dist/slices/play-drafts/repo.js +2 -0
- package/dist/slices/play-drafts/review-inputs.js +20 -3
- package/dist/slices/play-drafts/schema.js +89 -0
- package/dist/slices/play-drafts/service.js +4 -1
- package/dist/slices/play-drafts/start.js +43 -18
- package/dist/slices/project-templates/from-project.js +59 -6
- package/dist/slices/project-templates/next-chapter.js +94 -0
- package/dist/slices/project-templates/one-off.js +26 -0
- package/dist/slices/project-templates/repo.js +2 -1
- package/dist/slices/project-templates/schema.js +7 -1
- package/dist/slices/project-templates/service.js +15 -4
- package/dist/slices/project-templates/setup.js +18 -2
- package/dist/slices/rebuild/admission-repo.js +1 -1
- package/dist/slices/rebuild/model.js +6 -0
- package/dist/slices/rebuild/preview-details.js +46 -3
- package/dist/slices/rebuild/preview-plan.js +13 -6
- package/dist/slices/rebuild/recipe-audio-parts.js +40 -7
- package/dist/slices/rebuild/recipe-audio.js +66 -12
- package/dist/slices/rebuild/recipe-build.js +8 -4
- package/dist/slices/rebuild/recipe-cast.js +18 -0
- package/dist/slices/rebuild/recipe-checkpoints.js +11 -9
- package/dist/slices/rebuild/recipe-describe.js +93 -0
- package/dist/slices/rebuild/recipe-edit.js +13 -1
- package/dist/slices/rebuild/recipe-exports.js +67 -8
- package/dist/slices/rebuild/recipe-input-schema.js +35 -0
- package/dist/slices/rebuild/recipe-legacy.js +9 -0
- package/dist/slices/rebuild/recipe-loudness.js +45 -0
- package/dist/slices/rebuild/recipe-model.js +25 -6
- package/dist/slices/rebuild/recipe-pauses.js +7 -0
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-provider-choice.js +11 -1
- package/dist/slices/rebuild/recipe-reference.js +15 -1
- package/dist/slices/rebuild/recipe-reviews.js +117 -0
- package/dist/slices/rebuild/recipe-save.js +4 -1
- package/dist/slices/rebuild/recipe-shorts.js +23 -3
- package/dist/slices/rebuild/recipe-text.js +114 -19
- package/dist/slices/rebuild/recipe-validation.js +14 -2
- package/dist/slices/rebuild/recipe-visual.js +96 -33
- package/dist/slices/rebuild/recipe-voices.js +286 -0
- package/dist/slices/rebuild/recipe-work.js +77 -6
- package/dist/slices/rebuild/recipe-youtube.js +2 -0
- package/dist/slices/rebuild/recovery-conflict.js +7 -3
- package/dist/slices/rebuild/recovery-model.js +3 -0
- package/dist/slices/rebuild/recovery-selection.js +28 -2
- package/dist/slices/rebuild/recovery.js +35 -17
- package/dist/slices/rebuild/repo.js +3 -3
- package/dist/slices/rebuild/retry.js +18 -0
- package/dist/slices/rebuild/review-redo.js +125 -0
- package/dist/slices/rebuild/runtime-actions.js +5 -0
- package/dist/slices/rebuild/runtime-admission.js +4 -1
- package/dist/slices/rebuild/runtime-animate.js +4 -4
- package/dist/slices/rebuild/runtime-article.js +5 -5
- package/dist/slices/rebuild/runtime-document.js +4 -4
- package/dist/slices/rebuild/runtime-export-bed.js +43 -0
- package/dist/slices/rebuild/runtime-export-edit.js +70 -11
- package/dist/slices/rebuild/runtime-export-inputs.js +52 -10
- package/dist/slices/rebuild/runtime-export-short.js +85 -0
- package/dist/slices/rebuild/runtime-export.js +84 -19
- package/dist/slices/rebuild/runtime-figure-card.js +87 -0
- package/dist/slices/rebuild/runtime-image.js +21 -2
- package/dist/slices/rebuild/runtime-local.js +148 -24
- package/dist/slices/rebuild/runtime-materialize.js +8 -0
- package/dist/slices/rebuild/runtime-narration-reuse.js +2 -1
- package/dist/slices/rebuild/runtime-narration-text.js +7 -7
- package/dist/slices/rebuild/runtime-pictures.js +28 -0
- package/dist/slices/rebuild/runtime-piece-label.js +27 -0
- package/dist/slices/rebuild/runtime-provider.js +126 -18
- package/dist/slices/rebuild/runtime-publication.js +21 -5
- package/dist/slices/rebuild/runtime-review.js +267 -0
- package/dist/slices/rebuild/runtime-run.js +17 -11
- package/dist/slices/rebuild/runtime-shorts.js +44 -17
- package/dist/slices/rebuild/runtime-store.js +62 -11
- package/dist/slices/rebuild/runtime-subtitles.js +72 -19
- package/dist/slices/rebuild/runtime-voices.js +103 -0
- package/dist/slices/rebuild/runtime-youtube.js +7 -6
- package/dist/slices/rebuild/service-readiness.js +3 -3
- package/dist/slices/rebuild/soften.js +49 -0
- package/dist/slices/rebuild/transition-repo.js +9 -2
- package/dist/slices/research/run.js +4 -4
- package/dist/slices/research/synthesis.js +2 -2
- package/dist/slices/reviews/model.js +105 -0
- package/dist/slices/reviews/outcome.js +22 -0
- package/dist/slices/reviews/repo.js +118 -0
- package/dist/slices/reviews/rules.js +63 -0
- package/dist/slices/reviews/verdict.js +71 -0
- package/dist/slices/reviews/view.js +30 -0
- package/dist/slices/revisions/adopt-content.js +5 -2
- package/dist/slices/revisions/adopt.js +3 -1
- package/dist/slices/revisions/downloads.js +7 -1
- package/dist/slices/revisions/image-plan.js +183 -0
- package/dist/slices/revisions/mutation-assets.js +10 -0
- package/dist/slices/revisions/mutation-cues.js +71 -0
- package/dist/slices/revisions/mutation-request.js +2 -1
- package/dist/slices/revisions/mutations.js +97 -3
- package/dist/slices/revisions/schema.js +11 -1
- package/dist/slices/run-cost/limits.js +128 -0
- package/dist/slices/run-cost/meter.js +47 -0
- package/dist/slices/run-cost/panel.js +256 -0
- package/dist/slices/run-cost/pricing.js +95 -0
- package/dist/slices/run-cost/week.js +108 -0
- package/dist/slices/schedules/agenda.js +222 -0
- package/dist/slices/schedules/repo.js +58 -18
- package/dist/slices/schedules/scheduler.js +68 -17
- package/dist/slices/schedules/schema.js +179 -1
- package/dist/slices/schedules/service.js +43 -4
- package/dist/slices/schedules/similar.js +128 -0
- package/dist/slices/schedules/topic-list.js +163 -0
- package/dist/slices/schedules/topics.js +523 -0
- package/dist/slices/settings/first-run.js +106 -0
- package/dist/slices/settings/health.js +247 -0
- package/dist/slices/settings/key-guides.js +138 -0
- package/dist/slices/settings/key-test.js +93 -0
- package/dist/slices/settings/keys.js +10 -5
- package/dist/slices/settings/model-reach.js +52 -0
- package/dist/slices/settings/model.js +55 -1
- package/dist/slices/settings/models.js +5 -1
- package/dist/slices/settings/playback.js +15 -0
- package/dist/slices/settings/readiness.js +14 -2
- package/dist/slices/settings/repo.js +17 -3
- package/dist/slices/settings/tutorial-schema.js +5 -0
- package/dist/slices/settings/voices.js +64 -4
- package/dist/slices/settings/whats-new.js +64 -0
- package/dist/slices/shorts/captions.js +9 -0
- package/dist/slices/shorts/pick.js +3 -3
- package/dist/slices/shorts/prompts.js +1 -1
- package/dist/slices/shorts/render.js +63 -13
- package/dist/slices/storage/asset-name.js +3 -0
- package/dist/slices/storage/backup-export.js +48 -9
- package/dist/slices/storage/backup-format.js +38 -1
- package/dist/slices/storage/backup-import.js +191 -19
- package/dist/slices/storage/delete-project.js +7 -4
- package/dist/slices/storage/documents.js +87 -0
- package/dist/slices/storage/downloads.js +33 -1
- package/dist/slices/storage/files-location.js +531 -0
- package/dist/slices/storage/layout.js +14 -4
- package/dist/slices/storage/model.js +11 -0
- package/dist/slices/storage/portable.js +94 -12
- package/dist/slices/storage/reconcile.js +14 -1
- package/dist/slices/storage/repo.js +4 -1
- package/dist/slices/storage/schema.js +11 -0
- package/dist/slices/storage/trim.js +146 -0
- package/dist/slices/studio/disclosure.js +74 -0
- package/dist/slices/studio/model.js +30 -0
- package/dist/slices/studio/pack.js +211 -0
- package/dist/slices/studio/queue.js +69 -0
- package/dist/slices/studio/settings.js +170 -0
- package/dist/slices/style-preview/images.js +61 -0
- package/dist/slices/style-preview/narration.js +33 -0
- package/dist/slices/style-preview/render.js +148 -0
- package/dist/slices/style-preview/schema.js +59 -0
- package/dist/slices/style-preview/service.js +92 -0
- package/dist/slices/style-preview/settings.js +139 -0
- package/dist/slices/subtitles/captions.js +42 -9
- package/dist/slices/subtitles/model.js +22 -0
- package/dist/slices/subtitles/prepare.js +27 -16
- package/dist/slices/subtitles/transcript.js +1 -1
- package/dist/slices/thumbnail/run.js +7 -7
- package/dist/slices/trash/model.js +25 -0
- package/dist/slices/trash/service.js +273 -0
- package/dist/slices/tutorials/anchors.js +57 -0
- package/dist/slices/tutorials/library.js +185 -0
- package/dist/slices/uploads/repo.js +20 -0
- package/dist/slices/video/ambient-bed-schema.js +15 -0
- package/dist/slices/video/ambient-bed.js +95 -0
- package/dist/slices/video/ambient-mix.js +72 -0
- package/dist/slices/video/audio-inputs.js +2 -2
- package/dist/slices/video/cards.js +5 -2
- package/dist/slices/video/edit-list.js +23 -2
- package/dist/slices/video/edit-settings.js +13 -3
- package/dist/slices/video/ffmpeg.js +63 -9
- package/dist/slices/video/figure-card.js +492 -0
- package/dist/slices/video/figure-spans.js +51 -0
- package/dist/slices/video/plan.js +125 -13
- package/dist/slices/video/run.js +14 -12
- package/dist/slices/video/slideshow.js +39 -4
- package/dist/slices/voices/attribution.js +69 -0
- package/dist/slices/voices/audio-files.js +87 -0
- package/dist/slices/voices/audition.js +25 -0
- package/dist/slices/voices/cast.js +74 -0
- package/dist/slices/voices/grouping.js +59 -0
- package/dist/slices/voices/join.js +35 -0
- package/dist/slices/voices/languages.js +25 -0
- package/dist/slices/voices/model.js +218 -0
- package/dist/slices/voices/palette.js +26 -0
- package/dist/slices/voices/panel.js +91 -0
- package/dist/slices/voices/portraits.js +55 -0
- package/dist/slices/voices/script.js +136 -0
- package/dist/slices/voices/timing.js +58 -0
- package/dist/slices/youtube/answer.js +1 -1
- package/dist/slices/youtube/chapters.js +126 -0
- package/dist/slices/youtube/edits-repo.js +84 -0
- package/dist/slices/youtube/edits.js +89 -0
- package/dist/slices/youtube/placeholders.js +98 -0
- package/dist/slices/youtube/transcript.js +11 -4
- package/dist/tutorials/AI-CLIs.md +146 -0
- package/dist/tutorials/Backups.md +121 -0
- package/dist/tutorials/Calendar.md +103 -0
- package/dist/tutorials/Cast-Library.md +112 -0
- package/dist/tutorials/Channels.md +148 -0
- package/dist/tutorials/Costs-and-Run-Cost.md +136 -0
- package/dist/tutorials/Docker.md +171 -0
- package/dist/tutorials/Document-Themes.md +207 -0
- package/dist/tutorials/Editing-a-Project.md +204 -0
- package/dist/tutorials/FAQ.md +134 -0
- package/dist/tutorials/First-Launch-and-Welcome.md +153 -0
- package/dist/tutorials/Home-and-Projects.md +174 -0
- package/dist/tutorials/Home.md +119 -0
- package/dist/tutorials/Install.md +154 -0
- package/dist/tutorials/Intros-and-Outros.md +86 -0
- package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +215 -0
- package/dist/tutorials/Library-Overview.md +75 -0
- package/dist/tutorials/Models.md +133 -0
- package/dist/tutorials/Multiple-Voices.md +161 -0
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +129 -0
- package/dist/tutorials/Notifications.md +86 -0
- package/dist/tutorials/Other-Languages.md +110 -0
- package/dist/tutorials/PDF-Documents.md +100 -0
- package/dist/tutorials/Play-Images.md +135 -0
- package/dist/tutorials/Play-Narration.md +167 -0
- package/dist/tutorials/Play-Outputs.md +109 -0
- package/dist/tutorials/Play-Overview.md +216 -0
- package/dist/tutorials/Play-Title-and-Article.md +135 -0
- package/dist/tutorials/Play-Video-and-Style.md +143 -0
- package/dist/tutorials/Project-Page.md +228 -0
- package/dist/tutorials/Prompts.md +136 -0
- package/dist/tutorials/Providers-and-Keys.md +290 -0
- package/dist/tutorials/Publishing-to-YouTube.md +135 -0
- package/dist/tutorials/Recovery-and-Retries.md +141 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +143 -0
- package/dist/tutorials/Schedules.md +154 -0
- package/dist/tutorials/Settings-Reference.md +258 -0
- package/dist/tutorials/Shorts.md +116 -0
- package/dist/tutorials/Start-at-Login.md +126 -0
- package/dist/tutorials/Studio-Extension.md +146 -0
- package/dist/tutorials/Templates.md +146 -0
- package/dist/tutorials/Trash.md +87 -0
- package/dist/tutorials/Troubleshooting.md +149 -0
- package/dist/tutorials/Uninstalling-and-Moving.md +113 -0
- package/dist/tutorials/Updating-and-Patch-Notes.md +120 -0
- package/dist/tutorials/Video-Editing.md +135 -0
- package/dist/tutorials/Where-Your-Files-Live.md +149 -0
- package/dist/tutorials/YouTube-Description.md +132 -0
- package/dist/tutorials/Your-First-Short.md +125 -0
- package/dist/tutorials/_Footer.md +1 -0
- package/dist/tutorials/_Sidebar.md +69 -0
- package/dist/updater/service.js +66 -21
- package/dist/web/assets/index-DBLSfqA-.css +1 -0
- package/dist/web/assets/index-DFdIhmm0.js +307 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/web/assets/{pdf-BLF2i8c2.js → pdf-B9OY1ioX.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -5
- package/dist/edge/docker-launch.js +0 -81
- package/dist/edge/docker-projects/activation.js +0 -35
- package/dist/edge/docker-projects/claims.js +0 -85
- package/dist/edge/docker-projects/committed.js +0 -40
- package/dist/edge/docker-projects/engine.js +0 -461
- package/dist/edge/docker-projects/install.js +0 -254
- package/dist/edge/docker-projects/prune.js +0 -66
- package/dist/edge/docker-projects/recover.js +0 -100
- package/dist/edge/docker-projects/state.js +0 -225
- package/dist/web/assets/index-CktpxlJd.js +0 -171
- package/dist/web/assets/index-DB-vOnGU.css +0 -1
- package/scripts/docker-run.sh +0 -3
- /package/dist/edge/{docker-projects → docker-install}/tree.js +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { zValidator } from "@hono/zod-validator";
|
|
3
|
+
import { Hono } from "hono";
|
|
4
|
+
import { bodyLimit } from "hono/body-limit";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { deleteCastImage, generateCastImage, uploadCastImage, } from "../../slices/channels/cast-images.js";
|
|
7
|
+
import { castImageMaxBytes } from "../../slices/channels/images.js";
|
|
8
|
+
import { imageBlob } from "../../slices/channels/repo.js";
|
|
9
|
+
import { createCastMember, createChannel, deleteCastMember, deleteChannel, listChannels, moveTemplate, readChannel, setChannelAiDisclosure, updateCastMember, updateChannel, } from "../../slices/channels/service.js";
|
|
10
|
+
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
11
|
+
const idParam = z.object({ id: z.uuid() });
|
|
12
|
+
const memberParam = z.object({ memberId: z.uuid() });
|
|
13
|
+
const imageParam = memberParam.extend({ imageId: z.uuid() });
|
|
14
|
+
const pictureParam = z.object({ sha256: z.string().regex(/^[0-9a-f]{64}$/) });
|
|
15
|
+
const templateParam = z.object({ templateId: z.uuid() });
|
|
16
|
+
// Channels: the channels, their brand kit, series brief and cast, and which channel
|
|
17
|
+
// each template belongs to. The bodies are checked by the slice, so a refusal names the field.
|
|
18
|
+
export function channelRoutes(deps) {
|
|
19
|
+
const service = {
|
|
20
|
+
db: deps.db,
|
|
21
|
+
clock: deps.clock,
|
|
22
|
+
uuid: randomUUID,
|
|
23
|
+
generateImage: deps.generateCastImage,
|
|
24
|
+
log: deps.log,
|
|
25
|
+
};
|
|
26
|
+
return (new Hono()
|
|
27
|
+
.get("/", (c) => c.json({ channels: listChannels(service) }))
|
|
28
|
+
.post("/", async (c) => {
|
|
29
|
+
const result = createChannel(service, await body(c));
|
|
30
|
+
return result.ok ? c.json(result.value, 201) : refused(c, result);
|
|
31
|
+
})
|
|
32
|
+
// The pictures by content hash: they never change, so the browser may keep them.
|
|
33
|
+
.get("/pictures/:sha256", zValidator("param", pictureParam, onInvalid), (c) => {
|
|
34
|
+
const blob = imageBlob(deps.db, c.req.valid("param").sha256);
|
|
35
|
+
if (blob === undefined)
|
|
36
|
+
return refused(c, { ok: false, reason: "not-found" });
|
|
37
|
+
return c.body(new Uint8Array(blob.bytes), 200, {
|
|
38
|
+
"Content-Type": blob.mime,
|
|
39
|
+
"Cache-Control": "private, max-age=31536000, immutable",
|
|
40
|
+
"X-Content-Type-Options": "nosniff",
|
|
41
|
+
});
|
|
42
|
+
})
|
|
43
|
+
.put("/templates/:templateId", zValidator("param", templateParam, onInvalid), async (c) => {
|
|
44
|
+
const result = moveTemplate(service, c.req.valid("param").templateId, await body(c));
|
|
45
|
+
return result.ok ? c.json(result.value) : refused(c, result);
|
|
46
|
+
})
|
|
47
|
+
.put("/cast/:memberId", zValidator("param", memberParam, onInvalid), async (c) => {
|
|
48
|
+
const result = updateCastMember(service, c.req.valid("param").memberId, await body(c));
|
|
49
|
+
return result.ok ? c.json(result.value) : refused(c, result);
|
|
50
|
+
})
|
|
51
|
+
.delete("/cast/:memberId", zValidator("param", memberParam, onInvalid), (c) => {
|
|
52
|
+
const result = deleteCastMember(service, c.req.valid("param").memberId);
|
|
53
|
+
return result.ok ? c.body(null, 204) : refused(c, result);
|
|
54
|
+
})
|
|
55
|
+
// The picture's bytes are the body, as the file input read them.
|
|
56
|
+
.post("/cast/:memberId/images", zValidator("param", memberParam, onInvalid), bodyLimit({
|
|
57
|
+
maxSize: castImageMaxBytes,
|
|
58
|
+
onError: (c) => refused(c, {
|
|
59
|
+
ok: false,
|
|
60
|
+
reason: "not-an-image",
|
|
61
|
+
message: `This picture is larger than ${String(castImageMaxBytes / 1024 / 1024)} MB. Save it smaller (for example as a JPEG) and upload it again.`,
|
|
62
|
+
}),
|
|
63
|
+
}), async (c) => {
|
|
64
|
+
const bytes = new Uint8Array(await c.req.arrayBuffer());
|
|
65
|
+
const result = uploadCastImage(service, c.req.valid("param").memberId, bytes);
|
|
66
|
+
return result.ok ? c.json(result.value, 201) : refused(c, result);
|
|
67
|
+
})
|
|
68
|
+
.post("/cast/:memberId/generate", zValidator("param", memberParam, onInvalid), async (c) => {
|
|
69
|
+
const result = generateCastImage(service, c.req.valid("param").memberId, await body(c));
|
|
70
|
+
return result.ok ? c.json(result.value, 202) : refused(c, result);
|
|
71
|
+
})
|
|
72
|
+
.delete("/cast/:memberId/images/:imageId", zValidator("param", imageParam, onInvalid), (c) => {
|
|
73
|
+
const { memberId, imageId } = c.req.valid("param");
|
|
74
|
+
const result = deleteCastImage(service, memberId, imageId);
|
|
75
|
+
return result.ok ? c.body(null, 204) : refused(c, result);
|
|
76
|
+
})
|
|
77
|
+
.get("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
78
|
+
const result = readChannel(service, c.req.valid("param").id);
|
|
79
|
+
return result.ok ? c.json(result.value) : refused(c, result);
|
|
80
|
+
})
|
|
81
|
+
.put("/:id", zValidator("param", idParam, onInvalid), async (c) => {
|
|
82
|
+
const result = updateChannel(service, c.req.valid("param").id, await body(c));
|
|
83
|
+
return result.ok ? c.json(result.value) : refused(c, result);
|
|
84
|
+
})
|
|
85
|
+
.put("/:id/ai-disclosure", zValidator("param", idParam, onInvalid), async (c) => {
|
|
86
|
+
const result = setChannelAiDisclosure(service, c.req.valid("param").id, await body(c));
|
|
87
|
+
return result.ok ? c.json(result.value) : refused(c, result);
|
|
88
|
+
})
|
|
89
|
+
.delete("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
90
|
+
const result = deleteChannel(service, c.req.valid("param").id);
|
|
91
|
+
return result.ok ? c.body(null, 204) : refused(c, result);
|
|
92
|
+
})
|
|
93
|
+
.post("/:id/cast", zValidator("param", idParam, onInvalid), async (c) => {
|
|
94
|
+
const result = createCastMember(service, c.req.valid("param").id, await body(c));
|
|
95
|
+
return result.ok ? c.json(result.value, 201) : refused(c, result);
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
async function body(c) {
|
|
99
|
+
try {
|
|
100
|
+
return await c.req.json();
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const details = {
|
|
107
|
+
"not-found": "This channel, cast member or picture no longer exists; it may have been deleted in another tab. Go back to Channels.",
|
|
108
|
+
conflict: "This changed in another tab while you were editing. Reload the page to see the latest, then make your change again.",
|
|
109
|
+
"invalid-input": "Some of these settings are not valid. Check the highlighted fields and try again.",
|
|
110
|
+
"default-channel": "The default channel can't be deleted; projects and templates without a channel belong to it. Rename it in its Brand tab instead.",
|
|
111
|
+
"has-templates": "This channel still has templates. Move them to another channel in its Templates tab, or delete them, then delete the channel.",
|
|
112
|
+
"not-an-image": "This file is not a PNG or JPEG picture. Upload a PNG or JPEG file.",
|
|
113
|
+
"too-many-images": "This cast member already has the most pictures it can keep. Delete one first.",
|
|
114
|
+
"no-image-provider": "Slopify can't make pictures here yet. Set up an image provider in Settings → Providers, or upload a picture instead.",
|
|
115
|
+
};
|
|
116
|
+
function refused(c, result) {
|
|
117
|
+
const status = result.reason === "not-found"
|
|
118
|
+
? 404
|
|
119
|
+
: result.reason === "conflict" || result.reason === "has-templates"
|
|
120
|
+
? 409
|
|
121
|
+
: 400;
|
|
122
|
+
return problem(c, {
|
|
123
|
+
status,
|
|
124
|
+
title: titleOf(status),
|
|
125
|
+
detail: result.message ?? details[result.reason],
|
|
126
|
+
extensions: { reason: result.reason },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -11,6 +11,7 @@ export function diagnosticsRoutes(deps) {
|
|
|
11
11
|
db: deps.db,
|
|
12
12
|
probe: deps.probe,
|
|
13
13
|
hostCliStatus: deps.hostCliStatus,
|
|
14
|
+
host: deps.speechHost,
|
|
14
15
|
});
|
|
15
16
|
const projectCount = deps.db.prepare("SELECT count(*) AS count FROM projects").get();
|
|
16
17
|
const schema = deps.db.prepare("SELECT max(version) AS version FROM schema_migrations").get();
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { createReadStream } from "node:fs";
|
|
2
1
|
import { extname } from "node:path";
|
|
3
|
-
import { Readable } from "node:stream";
|
|
4
2
|
import { zValidator } from "@hono/zod-validator";
|
|
5
3
|
import { Hono } from "hono";
|
|
6
4
|
import { z } from "zod";
|
|
@@ -9,6 +7,7 @@ import { readDraft } from "../../slices/play-drafts/service.js";
|
|
|
9
7
|
import { uploadDraftAttachment } from "../../slices/play-drafts/uploads.js";
|
|
10
8
|
import { stagingPath } from "../../slices/storage/layout.js";
|
|
11
9
|
import { stagedFileById } from "../../slices/storage/repo.js";
|
|
10
|
+
import { fileResponse } from "./byte-range.js";
|
|
12
11
|
import { draftProblem } from "./draft-problem.js";
|
|
13
12
|
import { readMultipart } from "./multipart.js";
|
|
14
13
|
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
@@ -59,9 +58,8 @@ export function draftFileRoutes(service) {
|
|
|
59
58
|
title: titleOf(404),
|
|
60
59
|
detail: "This attached file has not finished uploading, so it cannot be previewed yet. Wait a moment or attach it again.",
|
|
61
60
|
});
|
|
62
|
-
return c
|
|
61
|
+
return fileResponse(c, stagingPath(deps.paths, staged.path), staged.bytes, {
|
|
63
62
|
"content-type": contentType,
|
|
64
|
-
"content-length": String(staged.bytes),
|
|
65
63
|
"x-content-type-options": "nosniff",
|
|
66
64
|
"cache-control": "no-store",
|
|
67
65
|
});
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { versionsOrCurrent } from "../../slices/library/history.js";
|
|
4
5
|
import { entryCategories, entryModes } from "../../slices/library/model.js";
|
|
5
|
-
import { listEntries } from "../../slices/library/repo.js";
|
|
6
|
-
import { createEntry, removeEntry, updateEntry } from "../../slices/library/save.js";
|
|
6
|
+
import { entryById, listEntries } from "../../slices/library/repo.js";
|
|
7
|
+
import { createEntry, removeEntry, restoreEntry, updateEntry } from "../../slices/library/save.js";
|
|
8
|
+
import { usedBy } from "../../slices/library/used-by.js";
|
|
7
9
|
import { onInvalid } from "./problem.js";
|
|
8
10
|
// One rule set for prompts and entries, so one refusal mapping too.
|
|
9
|
-
import { refused } from "./prompts.js";
|
|
11
|
+
import { refused, versionParam } from "./prompts.js";
|
|
10
12
|
const idParam = z.object({
|
|
11
13
|
id: z
|
|
12
14
|
.string()
|
|
@@ -33,6 +35,23 @@ export function entryRoutes(deps) {
|
|
|
33
35
|
.put("/:id", zValidator("param", idParam, onInvalid), zValidator("json", entryBody, onInvalid), (c) => {
|
|
34
36
|
const result = updateEntry(library, c.req.valid("param").id, c.req.valid("json"));
|
|
35
37
|
return result.ok ? c.json(result.value) : refused(c, result, "entry");
|
|
38
|
+
})
|
|
39
|
+
.get("/:id/history", zValidator("param", idParam, onInvalid), (c) => {
|
|
40
|
+
const entry = entryById(deps.db, c.req.valid("param").id);
|
|
41
|
+
return entry === undefined
|
|
42
|
+
? refused(c, { ok: false, reason: "not-found" }, "entry")
|
|
43
|
+
: c.json({ versions: versionsOrCurrent(deps.db, "entry", entry) });
|
|
44
|
+
})
|
|
45
|
+
.post("/:id/history/:version/restore", zValidator("param", versionParam, onInvalid), (c) => {
|
|
46
|
+
const { id, version } = c.req.valid("param");
|
|
47
|
+
const result = restoreEntry(library, id, version);
|
|
48
|
+
return result.ok ? c.json(result.value) : refused(c, result, "entry");
|
|
49
|
+
})
|
|
50
|
+
.get("/:id/used-by", zValidator("param", idParam, onInvalid), (c) => {
|
|
51
|
+
const entry = entryById(deps.db, c.req.valid("param").id);
|
|
52
|
+
return entry === undefined
|
|
53
|
+
? refused(c, { ok: false, reason: "not-found" }, "entry")
|
|
54
|
+
: c.json(usedBy(deps.db, { item: "entry", category: entry.category, name: entry.name }));
|
|
36
55
|
})
|
|
37
56
|
.delete("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
38
57
|
const result = removeEntry(library, c.req.valid("param").id);
|
package/dist/edge/http/files.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { createReadStream } from "node:fs";
|
|
2
|
-
import { Readable } from "node:stream";
|
|
3
1
|
import { zValidator } from "@hono/zod-validator";
|
|
4
2
|
import { Hono } from "hono";
|
|
5
3
|
import { z } from "zod";
|
|
6
4
|
import { findDownload, imagesZip } from "../../slices/storage/downloads.js";
|
|
5
|
+
import { fileResponse } from "./byte-range.js";
|
|
7
6
|
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
8
7
|
const projectParam = z.object({
|
|
9
8
|
projectId: z
|
|
@@ -42,11 +41,16 @@ export function fileRoutes(deps) {
|
|
|
42
41
|
return missing(c, result.reason);
|
|
43
42
|
}
|
|
44
43
|
const { download } = result;
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
// The YouTube description and tags as the page shows them, edits and links in.
|
|
45
|
+
if (download.text !== undefined)
|
|
46
|
+
return c.body(download.text, 200, {
|
|
47
|
+
"content-type": download.contentType,
|
|
48
|
+
"content-length": String(download.text.byteLength),
|
|
49
|
+
"content-disposition": disposition(download.filename),
|
|
50
|
+
});
|
|
51
|
+
// Byte ranges, so the players can jump to any time in the video or narration.
|
|
52
|
+
return fileResponse(c, download.path, download.bytes, {
|
|
48
53
|
"content-type": download.contentType,
|
|
49
|
-
"content-length": String(download.bytes),
|
|
50
54
|
"content-disposition": disposition(download.filename),
|
|
51
55
|
});
|
|
52
56
|
}));
|
|
@@ -60,7 +64,7 @@ function missing(c, reason) {
|
|
|
60
64
|
const details = {
|
|
61
65
|
"unknown-project": "This project no longer exists. Go back to Projects to pick another.",
|
|
62
66
|
"unknown-asset": "This project has no file by that name. Reload the page to see its current files.",
|
|
63
|
-
"missing-file": "This file was deleted or moved from the project folder. Use
|
|
67
|
+
"missing-file": "This file was deleted or moved from the project folder. Use More → make it again in its section on the project page to make it again.",
|
|
64
68
|
"no-images": "This project has no images or thumbnail yet. Wait for the Images step to finish, then try again.",
|
|
65
69
|
};
|
|
66
70
|
return problem(c, { status: 404, title: titleOf(404), detail: details[reason] });
|
|
@@ -46,7 +46,7 @@ export async function replyForFolder(c, deps, projectId, file) {
|
|
|
46
46
|
return problem(c, {
|
|
47
47
|
status: 404,
|
|
48
48
|
title: titleOf(404),
|
|
49
|
-
detail: "This output's folder was deleted or moved. Use
|
|
49
|
+
detail: "This output's folder was deleted or moved. Use More → make it again in its section on the project page to make the file again.",
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { weekSummary } from "../../slices/run-cost/week.js";
|
|
5
|
+
import { markUploaded } from "../../slices/uploads/repo.js";
|
|
6
|
+
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
7
|
+
const weekQuery = z.object({
|
|
8
|
+
since: z.iso.datetime({ offset: true }),
|
|
9
|
+
channelId: z.string().min(1).max(64).optional(),
|
|
10
|
+
});
|
|
11
|
+
// Home's "This week": videos made, spend and the API equivalent since `since` (the browser's
|
|
12
|
+
// own Monday), for one channel or all of them, and where each CLI plan's windows stand.
|
|
13
|
+
export function homeRoutes(deps) {
|
|
14
|
+
return new Hono().get("/week", zValidator("query", weekQuery, onInvalid), (c) => {
|
|
15
|
+
const { since, channelId } = c.req.valid("query");
|
|
16
|
+
return c.json(weekSummary(deps.db, new Date(since).toISOString(), channelId));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const idParam = z.object({
|
|
20
|
+
id: z
|
|
21
|
+
.string()
|
|
22
|
+
.min(1)
|
|
23
|
+
.max(64)
|
|
24
|
+
.regex(/^[0-9A-Za-z_-]+$/),
|
|
25
|
+
});
|
|
26
|
+
// Home's "Mark uploaded" and its undo. Slopify never uploads, so this only records what the
|
|
27
|
+
// person says they did.
|
|
28
|
+
export function uploadedRoutes(deps) {
|
|
29
|
+
return new Hono().put("/:id/uploaded", zValidator("param", idParam, onInvalid), zValidator("json", z.object({ uploaded: z.boolean() }).strict(), onInvalid), (c) => {
|
|
30
|
+
const result = markUploaded(deps.db, c.req.valid("param").id, c.req.valid("json").uploaded, deps.clock.now().toISOString());
|
|
31
|
+
if (!result.ok)
|
|
32
|
+
return problem(c, {
|
|
33
|
+
status: 404,
|
|
34
|
+
title: titleOf(404),
|
|
35
|
+
detail: "This project no longer exists. Go back to Projects to pick another.",
|
|
36
|
+
});
|
|
37
|
+
return c.json({ uploadedAt: result.uploadedAt });
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -5,7 +5,7 @@ import { stream } from "hono/streaming";
|
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { sniffImage } from "../../adapters/image/bytes.js";
|
|
7
7
|
import { redact } from "../../kernel/log.js";
|
|
8
|
-
import { bridgeLimits, HostFolderRefused, hostCliIds, hostCliProtocol, hostFrameSchema, hostImageSchema, hostLlmIds, hostLlmSchema, hostModelsSchema, hostOpenFolderSchema, hostStatusSchema, } from "../../kernel/ports/host-cli.js";
|
|
8
|
+
import { bridgeLimits, encodeHostImageReport, HostFolderRefused, hostCliIds, hostCliProtocol, hostDoneFrame, hostFrameSchema, hostFramesHeader, hostImageReportHeader, hostImageSchema, hostLlmIds, hostLlmSchema, hostModelsSchema, hostOpenFolderSchema, hostStatusSchema, } from "../../kernel/ports/host-cli.js";
|
|
9
9
|
import { agentImageTimeoutMs } from "../../kernel/ports/image.js";
|
|
10
10
|
import { isProviderError, providerError } from "../../kernel/ports/model.js";
|
|
11
11
|
export function hostGate() {
|
|
@@ -49,7 +49,7 @@ export function hostGate() {
|
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
|
-
const unavailable = "The AI command-line tool on your computer stopped before it finished, so this result is uncertain. Check the section's outputs on the project page, then use
|
|
52
|
+
const unavailable = "The AI command-line tool on your computer stopped before it finished, so this result is uncertain. Check the section's outputs on the project page, then use Try again.";
|
|
53
53
|
function fault(error, token) {
|
|
54
54
|
return {
|
|
55
55
|
type: "error",
|
|
@@ -90,7 +90,7 @@ export function hostCliRoutes(options) {
|
|
|
90
90
|
return c.json({
|
|
91
91
|
type: "error",
|
|
92
92
|
kind: "unavailable",
|
|
93
|
-
message: "The Slopify helper on your computer is busy or restarting. Wait a moment, then use
|
|
93
|
+
message: "The Slopify helper on your computer is busy or restarting. Wait a moment, then use Try again.",
|
|
94
94
|
}, 503);
|
|
95
95
|
const outgoing = c.env?.outgoing;
|
|
96
96
|
let responseEnded = !outgoing;
|
|
@@ -174,6 +174,8 @@ export function hostCliRoutes(options) {
|
|
|
174
174
|
const body = hostLlmSchema.safeParse(await json(c.req.raw));
|
|
175
175
|
if (!body.success)
|
|
176
176
|
return invalid(c);
|
|
177
|
+
// An app that sends no header reads the original frames (version 1).
|
|
178
|
+
const frames = Number(c.req.header(hostFramesHeader) ?? 1);
|
|
177
179
|
const job = c.get("job");
|
|
178
180
|
job.holdStream();
|
|
179
181
|
const controller = new AbortController();
|
|
@@ -191,7 +193,14 @@ export function hostCliRoutes(options) {
|
|
|
191
193
|
signal.throwIfAborted();
|
|
192
194
|
clearTimeout(timer);
|
|
193
195
|
timer = setTimeout(() => controller.abort(), 120_000);
|
|
194
|
-
|
|
196
|
+
// The cached-token count, the answering model and the plan windows cross only to
|
|
197
|
+
// an app that asked for frame version 2; an older app rejects fields it does not
|
|
198
|
+
// know. Typed-ahead text stays here: the bridge carries the committed answer only.
|
|
199
|
+
const parsed = hostFrameSchema.parse(event.type === "done"
|
|
200
|
+
? hostDoneFrame(event, frames)
|
|
201
|
+
: event.type === "partial"
|
|
202
|
+
? { type: "activity" }
|
|
203
|
+
: event);
|
|
195
204
|
if (done || parsed.type === "error")
|
|
196
205
|
throw new Error("Slopify hit an internal error (the AI tool on your computer sent a reply Slopify could not read). Try again; if it keeps happening, use Download diagnostics in Settings and report it.");
|
|
197
206
|
const frame = `${JSON.stringify(parsed)}\n`;
|
|
@@ -229,7 +238,17 @@ export function hostCliRoutes(options) {
|
|
|
229
238
|
const signal = AbortSignal.any([job.signal, controller.signal]);
|
|
230
239
|
const timer = setTimeout(() => controller.abort(), agentImageTimeoutMs);
|
|
231
240
|
try {
|
|
232
|
-
const { reference, thinking, ...rest } = body.data;
|
|
241
|
+
const { reference, thinking, cast: bridgedCast, ...rest } = body.data;
|
|
242
|
+
const cast = bridgedCast?.map((member) => ({
|
|
243
|
+
name: member.name,
|
|
244
|
+
description: member.description,
|
|
245
|
+
images: member.images.map((picture) => ({
|
|
246
|
+
bytes: new Uint8Array(Buffer.from(picture.base64, "base64")),
|
|
247
|
+
mime: picture.mime,
|
|
248
|
+
})),
|
|
249
|
+
}));
|
|
250
|
+
if (cast?.some((member) => member.images.some((picture) => sniffImage(picture.bytes) !== picture.mime)))
|
|
251
|
+
return invalid(c);
|
|
233
252
|
const image = reference === undefined
|
|
234
253
|
? undefined
|
|
235
254
|
: {
|
|
@@ -242,6 +261,7 @@ export function hostCliRoutes(options) {
|
|
|
242
261
|
...rest,
|
|
243
262
|
...(thinking === undefined ? {} : { thinking }),
|
|
244
263
|
...(image === undefined ? {} : { reference: image }),
|
|
264
|
+
...(cast === undefined ? {} : { cast }),
|
|
245
265
|
signal,
|
|
246
266
|
});
|
|
247
267
|
if (signal.aborted)
|
|
@@ -250,6 +270,10 @@ export function hostCliRoutes(options) {
|
|
|
250
270
|
throw new Error("Slopify hit an internal error (the image made on your computer was too large or not a valid image). Try again; if it keeps happening, use Download diagnostics in Settings and report it.");
|
|
251
271
|
c.header("Content-Type", result.mime);
|
|
252
272
|
c.header("Content-Length", String(result.bytes.byteLength));
|
|
273
|
+
// Any app may get this: one from before it ignores headers it does not know.
|
|
274
|
+
const report = encodeHostImageReport(result);
|
|
275
|
+
if (report !== undefined)
|
|
276
|
+
c.header(hostImageReportHeader, report);
|
|
253
277
|
return c.body(new Uint8Array(result.bytes));
|
|
254
278
|
}
|
|
255
279
|
catch (error) {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { narrationAudio } from "../../slices/narration/peaks.js";
|
|
5
|
+
import { assetPath } from "../../slices/revisions/mutation-assets.js";
|
|
6
|
+
import { currentRevisionId } from "../../slices/revisions/repo.js";
|
|
7
|
+
import { getRevisionView } from "../../slices/revisions/view.js";
|
|
8
|
+
import { outputPath } from "../../slices/storage/layout.js";
|
|
9
|
+
import { projectTitle } from "../../slices/storage/repo.js";
|
|
10
|
+
import { onInvalid, problem, titleOf } from "./problem.js";
|
|
11
|
+
const projectParam = z.object({
|
|
12
|
+
projectId: z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(64)
|
|
16
|
+
.regex(/^[0-9A-Za-z_-]+$/),
|
|
17
|
+
});
|
|
18
|
+
// ceiling: a few projects' worth of pieces. An asset never changes, so a cached row is never
|
|
19
|
+
// stale; the oldest goes first.
|
|
20
|
+
const cachedPieces = 400;
|
|
21
|
+
// The live view's waveform: the peaks of every finished narration piece of the current
|
|
22
|
+
// version, fetched again each time a `narration.piece` event says one landed.
|
|
23
|
+
export function narrationPeakRoutes(deps) {
|
|
24
|
+
const cache = new Map();
|
|
25
|
+
return new Hono().get("/:projectId/narration/peaks", zValidator("param", projectParam, onInvalid), async (c) => {
|
|
26
|
+
const { projectId } = c.req.valid("param");
|
|
27
|
+
if (projectTitle(deps.db, projectId) === undefined)
|
|
28
|
+
return problem(c, {
|
|
29
|
+
status: 404,
|
|
30
|
+
title: titleOf(404),
|
|
31
|
+
detail: "This project no longer exists. Go back to Projects to pick another.",
|
|
32
|
+
});
|
|
33
|
+
c.header("Cache-Control", "no-store");
|
|
34
|
+
const revisionId = currentRevisionId(deps.db, projectId);
|
|
35
|
+
const view = revisionId === undefined ? undefined : getRevisionView(deps, projectId, revisionId);
|
|
36
|
+
if (revisionId === undefined || view === undefined)
|
|
37
|
+
return c.json({
|
|
38
|
+
revisionId: null,
|
|
39
|
+
complete: false,
|
|
40
|
+
pieces: [],
|
|
41
|
+
});
|
|
42
|
+
const decode = deps.decodePeaks;
|
|
43
|
+
if (decode === undefined)
|
|
44
|
+
return problem(c, {
|
|
45
|
+
status: 503,
|
|
46
|
+
title: titleOf(503),
|
|
47
|
+
detail: "Slopify can't draw the narration waveform because ffmpeg isn't available. Restart Slopify; if it keeps happening, use Download diagnostics in Settings and report it.",
|
|
48
|
+
});
|
|
49
|
+
const audio = narrationAudio(view);
|
|
50
|
+
const pieces = [];
|
|
51
|
+
for (const piece of audio.pieces) {
|
|
52
|
+
let peaks = cache.get(piece.assetId);
|
|
53
|
+
if (peaks === undefined) {
|
|
54
|
+
try {
|
|
55
|
+
peaks = await decode(outputPath(deps.paths, projectId, assetPath(deps, projectId, piece.assetId)), c.req.raw.signal);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
deps.log.write("warn", "narration.peaks", {
|
|
59
|
+
projectId,
|
|
60
|
+
stage: "audio",
|
|
61
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
cache.set(piece.assetId, peaks);
|
|
66
|
+
while (cache.size > cachedPieces) {
|
|
67
|
+
const oldest = cache.keys().next().value;
|
|
68
|
+
if (oldest !== undefined)
|
|
69
|
+
cache.delete(oldest);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
pieces.push({ key: piece.key, seconds: peaks.seconds, peaks: peaks.peaks });
|
|
73
|
+
}
|
|
74
|
+
return c.json({ revisionId, complete: audio.complete, pieces });
|
|
75
|
+
});
|
|
76
|
+
}
|