@gentbajko/slopify 4.0.0 → 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 +1 -1
- package/dist/adapters/alignment/audio.js +1 -1
- package/dist/adapters/alignment/cache.js +1 -1
- package/dist/adapters/alignment/multilingual.js +2 -1
- package/dist/adapters/alignment/runner.js +1 -1
- package/dist/adapters/alignment/worker.js +1 -1
- package/dist/adapters/explain.js +10 -9
- package/dist/adapters/host-cli/index.js +2 -1
- package/dist/adapters/host-cli/transport.js +2 -1
- package/dist/adapters/image/bytes.js +2 -1
- package/dist/adapters/image/codex.js +6 -5
- package/dist/adapters/image/fal.js +4 -3
- package/dist/adapters/image/google.js +3 -2
- package/dist/adapters/image/models.js +2 -2
- package/dist/adapters/image/openai.js +2 -1
- package/dist/adapters/image/replicate.js +3 -2
- package/dist/adapters/image/video.js +2 -1
- package/dist/adapters/key-probes.js +1 -1
- package/dist/adapters/llm/antigravity-models.js +1 -1
- package/dist/adapters/llm/antigravity.js +7 -6
- package/dist/adapters/llm/assistant-cli.js +1 -1
- package/dist/adapters/llm/claude-code-models.js +1 -1
- package/dist/adapters/llm/claude-code.js +3 -2
- package/dist/adapters/llm/codex-models.js +1 -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 +2 -1
- package/dist/adapters/llm/run-cli.js +3 -2
- package/dist/adapters/tts/gemini.js +2 -1
- package/dist/adapters/tts/inworld-async.js +2 -1
- package/dist/adapters/tts/inworld.js +3 -2
- package/dist/adapters/tts/system.js +2 -1
- package/dist/catalog/registry.js +20 -13
- package/dist/catalog/schema.js +2 -1
- package/dist/catalog/validate.js +5 -2
- package/dist/edge/http/actions.js +7 -7
- package/dist/edge/http/app.js +3 -3
- package/dist/edge/http/assistant.js +3 -1
- package/dist/edge/http/backups.js +1 -1
- package/dist/edge/http/channel-memory.js +2 -2
- package/dist/edge/http/channels.js +1 -1
- package/dist/edge/http/checkpoints.js +7 -5
- package/dist/edge/http/design-templates.js +3 -3
- package/dist/edge/http/designs.js +1 -1
- package/dist/edge/http/document-themes.js +3 -3
- package/dist/edge/http/draft-problem.js +1 -1
- package/dist/edge/http/extension-auth.js +1 -1
- package/dist/edge/http/home.js +9 -1
- package/dist/edge/http/model-checks.js +4 -4
- package/dist/edge/http/onboarding.js +29 -12
- package/dist/edge/http/outputs.js +3 -2
- package/dist/edge/http/patch-notes.js +2 -2
- package/dist/edge/http/planning.js +1 -1
- package/dist/edge/http/project-create.js +1 -1
- package/dist/edge/http/project-templates.js +2 -2
- package/dist/edge/http/projects.js +22 -4
- package/dist/edge/http/prompts.js +2 -2
- package/dist/edge/http/providers.js +9 -10
- package/dist/edge/http/refusal.js +1 -1
- package/dist/edge/http/remote-access.js +4 -4
- package/dist/edge/http/remote-guard.js +2 -2
- package/dist/edge/http/reviews.js +1 -1
- package/dist/edge/http/revision-files.js +1 -1
- package/dist/edge/http/revisions.js +4 -4
- package/dist/edge/http/schedules.js +13 -11
- package/dist/edge/http/settings.js +6 -2
- package/dist/edge/http/social.js +5 -4
- package/dist/edge/http/staging.js +1 -1
- package/dist/edge/http/storage.js +12 -4
- package/dist/edge/http/studio.js +71 -19
- package/dist/edge/http/style-preview.js +2 -2
- package/dist/edge/http/template-studio.js +12 -9
- package/dist/edge/http/trash.js +1 -1
- package/dist/edge/http/youtube-edits.js +1 -1
- package/dist/edge/mcp/excluded-routes.js +4 -3
- package/dist/edge/mcp/instructions.js +3 -3
- package/dist/edge/mcp/library-tools.js +8 -5
- package/dist/edge/mcp/remake-tools.js +7 -4
- package/dist/edge/mcp/server.js +1 -1
- package/dist/edge/mcp/tools-channels.js +9 -9
- package/dist/edge/mcp/tools-designs.js +9 -9
- package/dist/edge/mcp/tools-library.js +7 -7
- package/dist/edge/mcp/tools-planning.js +18 -18
- package/dist/edge/mcp/tools-projects.js +10 -10
- package/dist/edge/mcp/tools-publishing.js +9 -9
- package/dist/edge/mcp/tools-runs.js +9 -9
- package/dist/edge/mcp/tools-schedules.js +6 -6
- package/dist/edge/mcp/tools-setup.js +20 -14
- package/dist/edge/mcp/tools-social.js +5 -4
- package/dist/edge/mcp/tools-storage.js +3 -3
- package/dist/edge/mcp/tools-template-studio.js +18 -18
- package/dist/edge/remote-access/model.js +1 -1
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
- package/dist/kernel/pipeline.js +12 -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 +11 -3
- package/dist/kernel/runner/providers.js +3 -2
- package/dist/kernel/runner/standalone.js +2 -2
- package/dist/main.js +5 -3
- package/dist/model-catalog.js +20 -0
- package/dist/patch-notes/4.0.0.md +13 -13
- package/dist/patch-notes/4.1.0.md +42 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/listing-facts.js +95 -0
- package/dist/slices/admission/repo.js +9 -6
- package/dist/slices/admission/rules.js +7 -7
- package/dist/slices/admission/state-words.js +34 -5
- package/dist/slices/assistant/cost.js +1 -1
- package/dist/slices/assistant/model.js +10 -3
- package/dist/slices/assistant/turn.js +5 -3
- package/dist/slices/autopilot/warnings.js +1 -1
- package/dist/slices/backups/service.js +5 -5
- package/dist/slices/channels/cast-images.js +1 -1
- package/dist/slices/channels/schema.js +1 -1
- package/dist/slices/channels/videos.js +1 -1
- package/dist/slices/control/providers.js +2 -2
- package/dist/slices/designs/budget.js +1 -1
- package/dist/slices/designs/calls.js +2 -2
- package/dist/slices/designs/check-context.js +4 -4
- package/dist/slices/designs/fields.js +4 -4
- package/dist/slices/designs/gate.js +7 -5
- package/dist/slices/designs/render-input.js +1 -1
- package/dist/slices/designs/requests.js +1 -1
- package/dist/slices/designs/runner.js +1 -1
- package/dist/slices/designs/sample.js +2 -1
- package/dist/slices/designs/service.js +1 -1
- package/dist/slices/designs/template-checks.js +2 -2
- package/dist/slices/designs/template-make.js +3 -3
- package/dist/slices/designs/templates.js +3 -3
- package/dist/slices/document/fonts.js +1 -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 +2 -2
- package/dist/slices/estimate/index.js +28 -22
- package/dist/slices/estimate/requests.js +4 -4
- package/dist/slices/fixes/rules.js +3 -1
- package/dist/slices/fonts/catalog.js +2 -1
- package/dist/slices/fonts/coverage.js +2 -1
- package/dist/slices/images/appearance.js +2 -1
- package/dist/slices/images/scenes.js +2 -1
- package/dist/slices/keywords/digest.js +2 -1
- package/dist/slices/keywords/rules.js +2 -2
- package/dist/slices/keywords/specs.js +5 -5
- package/dist/slices/keywords/values.js +1 -1
- package/dist/slices/library/transfer.js +3 -3
- package/dist/slices/loudness/loudnorm.js +2 -1
- package/dist/slices/loudness/model.js +3 -2
- package/dist/slices/loudness/sentence-level.js +2 -1
- package/dist/slices/model-checks/rules.js +13 -0
- package/dist/slices/model-upkeep/model.js +1 -1
- package/dist/slices/model-upkeep/switch.js +3 -3
- package/dist/slices/model-upkeep/usage.js +13 -2
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/pauses-model.js +3 -2
- package/dist/slices/narration/pronunciation.js +3 -2
- package/dist/slices/notifications/subject.js +2 -2
- package/dist/slices/onboarding/copy.js +19 -2
- package/dist/slices/onboarding/first-run.js +13 -38
- package/dist/slices/onboarding/install.js +2 -1
- package/dist/slices/onboarding/model.js +26 -21
- package/dist/slices/onboarding/preferred-model.js +14 -0
- package/dist/slices/onboarding/quick-short.js +103 -64
- package/dist/slices/onboarding/sample.js +4 -1
- package/dist/slices/onboarding/state.js +7 -0
- package/dist/slices/onboarding/template.js +6 -5
- package/dist/slices/outputs/add.js +3 -2
- package/dist/slices/outputs/service.js +2 -2
- package/dist/slices/patch-notes/library.js +1 -1
- package/dist/slices/play-drafts/readiness.js +3 -3
- package/dist/slices/play-drafts/review-inputs.js +1 -1
- package/dist/slices/play-drafts/service.js +17 -7
- 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/setup-sections.js +26 -0
- package/dist/slices/project-templates/setup.js +6 -1
- package/dist/slices/rebuild/preview-details.js +5 -5
- package/dist/slices/rebuild/recipe-preparation.js +1 -1
- package/dist/slices/rebuild/recipe-save.js +2 -2
- package/dist/slices/rebuild/recipe-validation.js +5 -4
- package/dist/slices/rebuild/recipe-voices.js +3 -2
- package/dist/slices/rebuild/recipe-work.js +4 -4
- package/dist/slices/rebuild/recovery.js +6 -6
- package/dist/slices/rebuild/remake-outdated.js +5 -5
- package/dist/slices/rebuild/review-redo.js +1 -1
- package/dist/slices/rebuild/runtime-animate.js +2 -2
- package/dist/slices/rebuild/runtime-article.js +4 -3
- package/dist/slices/rebuild/runtime-document.js +5 -4
- package/dist/slices/rebuild/runtime-export-bed.js +2 -1
- package/dist/slices/rebuild/runtime-export-edit.js +2 -1
- package/dist/slices/rebuild/runtime-export-inputs.js +5 -4
- package/dist/slices/rebuild/runtime-export-short.js +1 -1
- package/dist/slices/rebuild/runtime-export.js +4 -3
- package/dist/slices/rebuild/runtime-image.js +4 -3
- package/dist/slices/rebuild/runtime-local.js +3 -2
- package/dist/slices/rebuild/runtime-narration-text.js +3 -2
- package/dist/slices/rebuild/runtime-provider.js +7 -6
- package/dist/slices/rebuild/runtime-review.js +6 -5
- package/dist/slices/rebuild/runtime-shorts.js +6 -5
- package/dist/slices/rebuild/runtime-store.js +17 -2
- package/dist/slices/rebuild/runtime-subtitles.js +13 -12
- package/dist/slices/rebuild/runtime-voices.js +2 -1
- package/dist/slices/rebuild/runtime-youtube.js +3 -2
- package/dist/slices/rebuild/service-readiness.js +11 -3
- package/dist/slices/research/synthesis.js +3 -2
- package/dist/slices/reviews/external-model.js +1 -1
- package/dist/slices/reviews/holds.js +5 -4
- package/dist/slices/reviews/model.js +8 -5
- package/dist/slices/reviews/rules.js +3 -3
- package/dist/slices/reviews/verdict.js +2 -1
- package/dist/slices/revisions/image-plan.js +1 -1
- package/dist/slices/revisions/mutation-assets.js +2 -1
- package/dist/slices/revisions/mutations.js +3 -2
- package/dist/slices/schedules/agenda.js +7 -5
- package/dist/slices/schedules/design-check.js +4 -4
- package/dist/slices/schedules/design-run.js +3 -3
- package/dist/slices/schedules/repo.js +6 -5
- package/dist/slices/schedules/schema.js +3 -0
- package/dist/slices/schedules/topics.js +5 -5
- package/dist/slices/settings/first-run.js +6 -32
- package/dist/slices/settings/health.js +30 -15
- package/dist/slices/settings/key-test.js +1 -1
- package/dist/slices/settings/model.js +4 -2
- package/dist/slices/settings/playback.js +2 -2
- package/dist/slices/shorts/keep.js +2 -1
- package/dist/slices/shorts/pick.js +4 -3
- package/dist/slices/shorts/prompts.js +2 -1
- package/dist/slices/shorts/render.js +3 -2
- package/dist/slices/social/media.js +5 -4
- package/dist/slices/social/pack.js +1 -1
- package/dist/slices/social/post-prompt.js +2 -1
- package/dist/slices/social/reshape.js +2 -2
- package/dist/slices/social/serve.js +1 -1
- package/dist/slices/social/service.js +3 -2
- package/dist/slices/social/state.js +1 -1
- package/dist/slices/storage/backup-import.js +2 -2
- package/dist/slices/storage/portable.js +1 -1
- package/dist/slices/storage/trim.js +23 -13
- package/dist/slices/studio/calendar.js +3 -1
- 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/plan.js +1 -1
- package/dist/slices/studio/settings.js +6 -6
- package/dist/slices/studio/videos.js +23 -4
- package/dist/slices/style-preview/render.js +3 -3
- package/dist/slices/style-preview/schema.js +1 -1
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/template-studio/anatomy-view.js +46 -3
- package/dist/slices/template-studio/bakeoff.js +3 -3
- package/dist/slices/template-studio/budget.js +6 -3
- package/dist/slices/template-studio/cards.js +78 -0
- package/dist/slices/template-studio/checks.js +99 -50
- package/dist/slices/template-studio/for-all.js +5 -5
- package/dist/slices/template-studio/free-video.js +1 -1
- package/dist/slices/template-studio/free.js +5 -5
- package/dist/slices/template-studio/model.js +19 -15
- package/dist/slices/template-studio/pack-import.js +14 -14
- package/dist/slices/template-studio/pack.js +9 -7
- package/dist/slices/template-studio/paid.js +12 -5
- package/dist/slices/template-studio/quote.js +18 -11
- package/dist/slices/template-studio/ready.js +7 -7
- package/dist/slices/template-studio/runner.js +1 -1
- package/dist/slices/template-studio/save.js +12 -12
- package/dist/slices/template-studio/say-it-as.js +3 -3
- package/dist/slices/template-studio/schedule-gate.js +1 -1
- package/dist/slices/template-studio/schedule-price.js +3 -1
- package/dist/slices/template-studio/schedule-sample.js +5 -1
- package/dist/slices/template-studio/schema.js +25 -0
- package/dist/slices/template-studio/service.js +3 -1
- package/dist/slices/template-studio/status.js +26 -9
- package/dist/slices/template-studio/topic.js +3 -3
- package/dist/slices/thumbnail/by-llm.js +1 -1
- package/dist/slices/uploads/repo.js +37 -1
- package/dist/slices/uploads/rules.js +3 -2
- package/dist/slices/video/edit-list.js +2 -2
- package/dist/slices/video/edit-settings.js +1 -1
- package/dist/slices/video/encoding.js +14 -5
- package/dist/slices/video/ffmpeg.js +2 -2
- package/dist/slices/video/plan.js +2 -1
- package/dist/slices/video/slideshow.js +1 -1
- package/dist/slices/voices/attribution.js +3 -2
- package/dist/slices/voices/model.js +9 -8
- package/dist/slices/voices/script.js +2 -1
- package/dist/slices/youtube/answer.js +2 -1
- package/dist/slices/youtube/edits-repo.js +1 -1
- package/dist/tutorials/AI-CLIs.md +25 -25
- package/dist/tutorials/Agents-MCP.md +32 -32
- package/dist/tutorials/Assistant.md +5 -5
- 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 +40 -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 +101 -76
- package/dist/tutorials/Home.md +33 -33
- package/dist/tutorials/Install.md +13 -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 +21 -21
- package/dist/tutorials/Models.md +27 -27
- package/dist/tutorials/Multiple-Voices.md +41 -40
- package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
- package/dist/tutorials/Notifications.md +21 -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 +12 -12
- package/dist/tutorials/Project-Page.md +118 -120
- package/dist/tutorials/Prompts-and-Templates.md +84 -0
- package/dist/tutorials/Prompts.md +45 -45
- 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 +2 -2
- package/dist/tutorials/Reviews-and-Checkpoints.md +90 -93
- package/dist/tutorials/Schedules.md +27 -28
- package/dist/tutorials/Settings-Reference.md +182 -204
- 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 +45 -42
- package/dist/tutorials/Templates.md +50 -79
- 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 +15 -15
- 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 +2 -2
- package/dist/tutorials/Library-Overview.md +0 -76
- package/dist/tutorials/Play-Images.md +0 -165
- 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-CkAI_2E7.css +0 -1
- package/dist/web/assets/index-DcD0cdfo.js +0 -334
- package/dist/web/assets/pdf-TODRwF31.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
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { zValidator } from "@hono/zod-validator";
|
|
3
3
|
import { Hono } from "hono";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { defaultSpeechVoice, detectSpeechCached, primaryLanguage, } from "../../kernel/ports/system-speech.js";
|
|
5
|
+
import { defaultSpeechVoice, detectSpeechCached, forgetDetectedSpeech, primaryLanguage, speechInstall, } from "../../kernel/ports/system-speech.js";
|
|
6
6
|
import { loudnessOfDefault } from "../../slices/loudness/model.js";
|
|
7
7
|
import { firstRunView } from "../../slices/onboarding/first-run.js";
|
|
8
8
|
import { fullVideoDraft } from "../../slices/onboarding/full-video.js";
|
|
@@ -15,9 +15,10 @@ import { dismissFirstRun, recordShortRequest, shortRequestProject, } from "../..
|
|
|
15
15
|
import { systemVoiceProvider } from "../../slices/settings/model.js";
|
|
16
16
|
import { readSettings } from "../../slices/settings/playback.js";
|
|
17
17
|
import { providerStatuses } from "../../slices/settings/readiness.js";
|
|
18
|
-
import { listVoices } from "../../slices/settings/repo.js";
|
|
18
|
+
import { listVoices, writeSetting } from "../../slices/settings/repo.js";
|
|
19
19
|
import { addVoice } from "../../slices/settings/voices.js";
|
|
20
20
|
import { projectTitle } from "../../slices/storage/repo.js";
|
|
21
|
+
import { autostartAnsweredKey } from "../autostart/model.js";
|
|
21
22
|
import { onInvalid, problem } from "./problem.js";
|
|
22
23
|
import { createProject } from "./project-create.js";
|
|
23
24
|
const packParam = z.object({ id: z.string().min(1).max(40) });
|
|
@@ -30,7 +31,16 @@ export function onboardingRoutes(deps) {
|
|
|
30
31
|
hostCliStatus: deps.hostCliStatus,
|
|
31
32
|
host: deps.speechHost,
|
|
32
33
|
});
|
|
33
|
-
const
|
|
34
|
+
const host = deps.speechHost ?? process;
|
|
35
|
+
const speech = () => detectSpeechCached(deps.probe, host);
|
|
36
|
+
const view = async () => firstRunView(deps.db, await statuses(), speechInstall(host));
|
|
37
|
+
// Done with the first-run screen (Skip, Done, a first short, or a project made elsewhere):
|
|
38
|
+
// it also answers "Start Slopify when I log in" as No, so a fresh install is never asked it
|
|
39
|
+
// in a dialog over Home. The screen's own row and Settings → General still turn it on.
|
|
40
|
+
const doneWithFirstRun = () => {
|
|
41
|
+
dismissFirstRun(deps.db, deps.clock.now().toISOString());
|
|
42
|
+
writeSetting(deps.db, autostartAnsweredKey, "1");
|
|
43
|
+
};
|
|
34
44
|
// The best speech program found and its English voice, for a short made without a voice key.
|
|
35
45
|
const systemVoicePick = async () => {
|
|
36
46
|
const engine = (await speech()).engines[0];
|
|
@@ -53,10 +63,16 @@ export function onboardingRoutes(deps) {
|
|
|
53
63
|
return new Hono()
|
|
54
64
|
.get("/", async (c) => {
|
|
55
65
|
c.header("Cache-Control", "no-store");
|
|
56
|
-
return c.json(
|
|
66
|
+
return c.json(await view());
|
|
67
|
+
})
|
|
68
|
+
.post("/check", async (c) => {
|
|
69
|
+
// The checklist's Check again: looks for a speech program afresh instead of answering
|
|
70
|
+
// from the last minute's look, so a program installed a moment ago is found.
|
|
71
|
+
forgetDetectedSpeech(deps.probe);
|
|
72
|
+
return c.json(await view());
|
|
57
73
|
})
|
|
58
74
|
.post("/dismiss", (c) => {
|
|
59
|
-
|
|
75
|
+
doneWithFirstRun();
|
|
60
76
|
return c.json({ dismissed: true });
|
|
61
77
|
})
|
|
62
78
|
.post("/packs/:id", zValidator("param", packParam, onInvalid), (c) => {
|
|
@@ -64,7 +80,7 @@ export function onboardingRoutes(deps) {
|
|
|
64
80
|
if (!installed.ok)
|
|
65
81
|
return problem(c, {
|
|
66
82
|
status: 404,
|
|
67
|
-
detail: "Slopify doesn't have that starter
|
|
83
|
+
detail: "Slopify doesn't have that starter template. Reload the page and pick one of the templates listed.",
|
|
68
84
|
});
|
|
69
85
|
return c.json(installed.value);
|
|
70
86
|
})
|
|
@@ -77,7 +93,7 @@ export function onboardingRoutes(deps) {
|
|
|
77
93
|
if (pack === undefined)
|
|
78
94
|
return problem(c, {
|
|
79
95
|
status: 404,
|
|
80
|
-
detail: "Slopify doesn't have that starter
|
|
96
|
+
detail: "Slopify doesn't have that starter template. Reload the page and pick one of the templates listed.",
|
|
81
97
|
});
|
|
82
98
|
const modelsFor = deps.modelsFor;
|
|
83
99
|
if (modelsFor === undefined)
|
|
@@ -91,6 +107,7 @@ export function onboardingRoutes(deps) {
|
|
|
91
107
|
modelsFor,
|
|
92
108
|
suggested: pack.voice,
|
|
93
109
|
systemVoice: await systemVoicePick(),
|
|
110
|
+
install: speechInstall(host),
|
|
94
111
|
});
|
|
95
112
|
if (!plan.ok)
|
|
96
113
|
return problem(c, {
|
|
@@ -102,7 +119,7 @@ export function onboardingRoutes(deps) {
|
|
|
102
119
|
if (!installed.ok)
|
|
103
120
|
return problem(c, {
|
|
104
121
|
status: 404,
|
|
105
|
-
detail: "Slopify doesn't have that starter
|
|
122
|
+
detail: "Slopify doesn't have that starter template. Reload the page and pick one of the templates listed.",
|
|
106
123
|
});
|
|
107
124
|
// The computer's voice is saved like any other, so Play and a later rebuild offer it.
|
|
108
125
|
const audio = plan.providers.audio;
|
|
@@ -135,7 +152,7 @@ export function onboardingRoutes(deps) {
|
|
|
135
152
|
});
|
|
136
153
|
recordShortRequest(deps.db, input.requestId, created.project.id);
|
|
137
154
|
// A real project now exists, so the first-run screen is done with.
|
|
138
|
-
|
|
155
|
+
doneWithFirstRun();
|
|
139
156
|
return c.json({ projectId: created.project.id, replayed: false }, 201);
|
|
140
157
|
})
|
|
141
158
|
.post("/full-video", zValidator("json", fullVideoInputSchema, onInvalid), (c) => {
|
|
@@ -145,16 +162,16 @@ export function onboardingRoutes(deps) {
|
|
|
145
162
|
if (made.reason === "not-found")
|
|
146
163
|
return problem(c, {
|
|
147
164
|
status: 404,
|
|
148
|
-
detail: "This short or its starter
|
|
165
|
+
detail: "This short or its starter template is no longer here, so Create couldn't be set up from it. Open Create and pick a template yourself.",
|
|
149
166
|
});
|
|
150
167
|
if (made.reason === "not-short")
|
|
151
168
|
return problem(c, {
|
|
152
169
|
status: 409,
|
|
153
|
-
detail: "This project is already a long video. Open
|
|
170
|
+
detail: "This project is already a long video. Open Create to start another one on a new topic.",
|
|
154
171
|
});
|
|
155
172
|
return problem(c, {
|
|
156
173
|
status: 409,
|
|
157
|
-
detail: "Slopify couldn't open a
|
|
174
|
+
detail: "Slopify couldn't open a draft on Create for the full video. Press Make the full video on this topic again; if it keeps failing, press Make a video on the starter template in Templates.",
|
|
158
175
|
extensions: { reason: made.reason },
|
|
159
176
|
});
|
|
160
177
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
|
+
import { editSettings } from "../../kernel/ports/settings-places.js";
|
|
3
4
|
import { addOutputPreviewRequestSchema, addOutputRequestSchema, } from "../../slices/outputs/model.js";
|
|
4
5
|
import { addOutput, previewAddedOutput, } from "../../slices/outputs/service.js";
|
|
5
6
|
import { currentRevisionId } from "../../slices/revisions/repo.js";
|
|
@@ -21,10 +22,10 @@ const details = {
|
|
|
21
22
|
"no-revision": "This saved version of the project no longer exists. Reload the page, then open Add another output again.",
|
|
22
23
|
conflict: "This project changed while you were choosing. Reload the page, then open Add another output again.",
|
|
23
24
|
"idempotency-conflict": "This output was already requested with different details. Reload the page, then try again.",
|
|
24
|
-
"invalid-edit": "This project is missing a choice the new output needs. Set the fields listed in
|
|
25
|
+
"invalid-edit": "This project is missing a choice the new output needs. Set the fields listed in Edit settings, save, then add the output again.",
|
|
25
26
|
already: "This project already makes that output. Find it in its section on the left.",
|
|
26
27
|
"needs-article": "That output is made from the article, which this project does not have yet. Wait for the Article step to finish, then add it.",
|
|
27
|
-
"narration-taken":
|
|
28
|
+
"narration-taken": `This project already has narration, and a project has one. Keep it, or change its format under Speakers in ${editSettings.narration}.`,
|
|
28
29
|
"adaptation-not-accepted": 'This output rewrites your article as a conversation. Tick "Adapt my article into a conversation" in Add another output, then add it.',
|
|
29
30
|
};
|
|
30
31
|
// Add another output: what it reuses, makes and costs, then the revision that switches it on.
|
|
@@ -3,7 +3,7 @@ import { bundledPatchNotesDir, PatchNotesMissing, readPatchNote, } from "../../s
|
|
|
3
3
|
import { markPatchNotesSeen, readPatchNotes } from "../../slices/patch-notes/seen.js";
|
|
4
4
|
import { problem } from "./problem.js";
|
|
5
5
|
import { bundleMissing } from "./refusal.js";
|
|
6
|
-
// Settings →
|
|
6
|
+
// Settings → What's new: the list (with which note is due to open by itself), one note's
|
|
7
7
|
// Markdown, and recording that the note that opened by itself was closed.
|
|
8
8
|
// Preserve Hono's inferred route types for the web client.
|
|
9
9
|
export function patchNotesRoutes(deps) {
|
|
@@ -32,7 +32,7 @@ export function patchNotesRoutes(deps) {
|
|
|
32
32
|
if (markdown === undefined)
|
|
33
33
|
return problem(c, {
|
|
34
34
|
status: 404,
|
|
35
|
-
detail: "These patch notes are not in this version of Slopify. Open Settings →
|
|
35
|
+
detail: "These patch notes are not in this version of Slopify. Open Settings → What's new and pick one from the list.",
|
|
36
36
|
});
|
|
37
37
|
return c.body(markdown, 200, { "content-type": "text/markdown; charset=utf-8" });
|
|
38
38
|
});
|
|
@@ -94,7 +94,7 @@ export function planningRoutes(deps) {
|
|
|
94
94
|
if (input.draft.checkpoints?.length)
|
|
95
95
|
return problem(c, {
|
|
96
96
|
status: 409,
|
|
97
|
-
detail: "Videos
|
|
97
|
+
detail: "Videos that pause for your review (Pauses and checks) can't be queued. Make them one at a time from Create.",
|
|
98
98
|
});
|
|
99
99
|
if (batchExists(deps.db, input.requestId))
|
|
100
100
|
return c.json({ queue: queueEntries(deps.db, input.requestId) });
|
|
@@ -18,7 +18,7 @@ export async function createProject(deps, sent) {
|
|
|
18
18
|
return {
|
|
19
19
|
ok: false,
|
|
20
20
|
status: 409,
|
|
21
|
-
detail: "This project
|
|
21
|
+
detail: "This project pauses for your review (Pauses and checks), so it starts from Create: press Make the video there.",
|
|
22
22
|
fields: [],
|
|
23
23
|
};
|
|
24
24
|
const subtitles = draft.subtitles;
|
|
@@ -23,11 +23,11 @@ function refused(c, result) {
|
|
|
23
23
|
statuses: { "not-found": 404, conflict: 409, "referenced-by-schedule": 409 },
|
|
24
24
|
otherwise: 400,
|
|
25
25
|
detail: result.reason === "referenced-by-schedule"
|
|
26
|
-
? "Some schedules still use this template. In
|
|
26
|
+
? "Some schedules still use this template. In Calendar → Schedules, cancel and delete them first; their run history is kept."
|
|
27
27
|
: result.reason === "missing-prompt"
|
|
28
28
|
? "A prompt or intro/outro entry this template uses was deleted. Choose another in the template, then save again."
|
|
29
29
|
: result.reason === "not-found"
|
|
30
|
-
? "This template no longer exists; it may have been deleted. Go to
|
|
30
|
+
? "This template no longer exists; it may have been deleted. Go to Templates to see your templates."
|
|
31
31
|
: result.reason === "conflict"
|
|
32
32
|
? "This template or its project changed while you were editing. Reload the page to see the latest, then make your change again."
|
|
33
33
|
: "Some template settings are not valid, for example an image you supplied yourself. Check the template's settings and try again.",
|
|
@@ -4,13 +4,15 @@ import { z } from "zod";
|
|
|
4
4
|
import { transact } from "../../kernel/db/tx.js";
|
|
5
5
|
import { derive, progressOf } from "../../kernel/runner/graph.js";
|
|
6
6
|
import { listProjectHeads } from "../../slices/admission/heads.js";
|
|
7
|
+
import { listingFacts } from "../../slices/admission/listing-facts.js";
|
|
7
8
|
import { projectById, projectTrashed, runDraftSchema, stageStandingsByProject, stagesOf, stepFailuresByProject, } from "../../slices/admission/repo.js";
|
|
8
|
-
import { readsByWaitBesideFailure, stepFailedWhileWaiting, } from "../../slices/admission/state-words.js";
|
|
9
|
+
import { readsByWaitBesideFailure, retryingAt, stepFailedWhileWaiting, } from "../../slices/admission/state-words.js";
|
|
9
10
|
import { lastStarter } from "../../slices/agents/repo.js";
|
|
10
11
|
import { defaultChannelId } from "../../slices/channels/model.js";
|
|
11
12
|
import { channelById, projectChannels, setProjectChannel } from "../../slices/channels/repo.js";
|
|
12
13
|
import { withProjectControl } from "../../slices/control/lock.js";
|
|
13
14
|
import { stagesWithEta } from "../../slices/eta/view.js";
|
|
15
|
+
import { sampleProjectIds } from "../../slices/onboarding/sample.js";
|
|
14
16
|
import { videoActivity } from "../../slices/rebuild/activity.js";
|
|
15
17
|
import { projectHolds } from "../../slices/reviews/holds.js";
|
|
16
18
|
import { adoptBaseline } from "../../slices/revisions/adopt.js";
|
|
@@ -18,7 +20,7 @@ import { currentRevisionId } from "../../slices/revisions/repo.js";
|
|
|
18
20
|
import { limitWaitsByProject, listingWait } from "../../slices/run-cost/panel.js";
|
|
19
21
|
import { outputsOf } from "../../slices/storage/repo.js";
|
|
20
22
|
import { trashProject } from "../../slices/trash/service.js";
|
|
21
|
-
import { setAsideProjects,
|
|
23
|
+
import { setAsideProjects, settledProjects, uploadedProjects } from "../../slices/uploads/repo.js";
|
|
22
24
|
import { settledStatus } from "../../slices/uploads/rules.js";
|
|
23
25
|
import { idParam } from "./ids.js";
|
|
24
26
|
import { onInvalid, problem } from "./problem.js";
|
|
@@ -35,7 +37,7 @@ export function projectRoutes(deps) {
|
|
|
35
37
|
};
|
|
36
38
|
const summarise = (project) => {
|
|
37
39
|
const stages = stagesOf(deps.db, project.id);
|
|
38
|
-
const status = settledStatus(derive(stages, project.paused),
|
|
40
|
+
const status = settledStatus(derive(stages, project.paused), settledProjects(deps.db, project.id).has(project.id));
|
|
39
41
|
return {
|
|
40
42
|
...project,
|
|
41
43
|
status,
|
|
@@ -65,15 +67,20 @@ export function projectRoutes(deps) {
|
|
|
65
67
|
const channels = projectChannels(deps.db);
|
|
66
68
|
const uploads = uploadedProjects(deps.db);
|
|
67
69
|
const aside = setAsideProjects(deps.db);
|
|
68
|
-
const settled =
|
|
70
|
+
const settled = settledProjects(deps.db);
|
|
69
71
|
const holds = projectHolds(deps.db, { standings, settled });
|
|
70
72
|
const waits = limitWaitsByProject(deps.db);
|
|
71
73
|
const failures = stepFailuresByProject(deps.db);
|
|
74
|
+
const samples = new Set(Object.values(sampleProjectIds(deps.db)));
|
|
75
|
+
const facts = listingFacts(deps.db);
|
|
72
76
|
const projects = listProjectHeads(deps.db).map((project) => {
|
|
73
77
|
const stages = standings.get(project.id) ?? [];
|
|
74
78
|
const waiting = waits.get(project.id);
|
|
75
79
|
const holding = holds.holding.get(project.id);
|
|
76
80
|
const status = settledStatus(derive(stages, project.paused), settled.has(project.id));
|
|
81
|
+
const made = facts.get(project.id);
|
|
82
|
+
const finished = status === "done" || status === "partial";
|
|
83
|
+
const retry = status === "running" ? retryingAt(stages) : undefined;
|
|
77
84
|
return {
|
|
78
85
|
...project,
|
|
79
86
|
status,
|
|
@@ -89,7 +96,18 @@ export function projectRoutes(deps) {
|
|
|
89
96
|
? { stepFailures: failures.get(project.id) ?? [] }
|
|
90
97
|
: {}),
|
|
91
98
|
...(holding === undefined ? {} : { holding }),
|
|
99
|
+
...(retry === undefined ? {} : { retryAt: retry }),
|
|
92
100
|
...(waiting === undefined ? {} : { limitWaits: waiting.map(listingWait) }),
|
|
101
|
+
...(samples.has(project.id) ? { sample: true } : {}),
|
|
102
|
+
...(finished && made?.finishedAt !== undefined ? { finishedAt: made.finishedAt } : {}),
|
|
103
|
+
...(made?.durationSeconds === undefined
|
|
104
|
+
? {}
|
|
105
|
+
: { durationSeconds: made.durationSeconds }),
|
|
106
|
+
...(made?.outputs === undefined ? {} : { outputs: made.outputs }),
|
|
107
|
+
...(status === "partial" && made?.failedSteps !== undefined
|
|
108
|
+
? { failedSteps: made.failedSteps }
|
|
109
|
+
: {}),
|
|
110
|
+
...(made?.outdated === true ? { outdated: true } : {}),
|
|
93
111
|
};
|
|
94
112
|
});
|
|
95
113
|
return c.json({ projects });
|
|
@@ -47,7 +47,7 @@ export function promptRoutes(deps) {
|
|
|
47
47
|
? refused(c, { ok: false, reason: "not-found" }, "prompt")
|
|
48
48
|
: problem(c, {
|
|
49
49
|
status: 400,
|
|
50
|
-
detail: "Only an Image prompt can be marked photorealistic. Open the prompt
|
|
50
|
+
detail: "Only an Image prompt can be marked photorealistic. Open the prompt under Image in Prompts.",
|
|
51
51
|
});
|
|
52
52
|
})
|
|
53
53
|
// Every saved version, newest first (`slices/library/history.ts`).
|
|
@@ -103,7 +103,7 @@ export function refused(c, failure, noun) {
|
|
|
103
103
|
case "not-found":
|
|
104
104
|
return problem(c, {
|
|
105
105
|
status: 404,
|
|
106
|
-
detail: `This ${noun} no longer exists; it may have been deleted. Go back to
|
|
106
|
+
detail: `This ${noun} no longer exists; it may have been deleted. Go back to Prompts to pick another.`,
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -5,11 +5,11 @@ import { z } from "zod";
|
|
|
5
5
|
import { keyProbes } from "../../adapters/key-probes.js";
|
|
6
6
|
import { catalogueModelInfo } from "../../catalog/model-info.js";
|
|
7
7
|
import { videoModelsOf } from "../../catalog/schema.js";
|
|
8
|
-
import { defaultSpeechVoice, detectSpeechCached } from "../../kernel/ports/system-speech.js";
|
|
8
|
+
import { defaultSpeechVoice, detectSpeechCached, speechInstall, } from "../../kernel/ports/system-speech.js";
|
|
9
9
|
import { switchAllRetired, switchRetiredModel } from "../../slices/model-upkeep/switch.js";
|
|
10
10
|
import { retiredModelUsage, usageKinds, usageSlots } from "../../slices/model-upkeep/usage.js";
|
|
11
11
|
import { cliPathMaxLength, saveCliPath } from "../../slices/settings/cli-paths.js";
|
|
12
|
-
import {
|
|
12
|
+
import { firstRunStatus } from "../../slices/settings/first-run.js";
|
|
13
13
|
import { checkProviderHealth } from "../../slices/settings/health.js";
|
|
14
14
|
import { keyGuides } from "../../slices/settings/key-guides.js";
|
|
15
15
|
import { testProviderKey } from "../../slices/settings/key-test.js";
|
|
@@ -63,16 +63,12 @@ export function providerRoutes(deps) {
|
|
|
63
63
|
};
|
|
64
64
|
const standingsOf = (id, models) => deps.modelChecks?.standings(id, models);
|
|
65
65
|
return (new Hono()
|
|
66
|
-
// The step lists Settings →
|
|
66
|
+
// The step lists Settings → Keys & services shows beside each key field.
|
|
67
67
|
.get("/key-guides", (c) => c.json({ guides: keyGuides }))
|
|
68
68
|
// What the first launch found, and the providers Play picks by default.
|
|
69
69
|
.get("/first-run", async (c) => {
|
|
70
70
|
c.header("Cache-Control", "no-store");
|
|
71
71
|
return c.json(await firstRunStatus({ db: deps.db, ...(deps.modelsFor === undefined ? {} : { modelsFor: deps.modelsFor }) }, await providerStatuses(readiness)));
|
|
72
|
-
})
|
|
73
|
-
.post("/first-run/dismiss", (c) => {
|
|
74
|
-
dismissFirstRun(deps.db);
|
|
75
|
-
return c.body(null, 204);
|
|
76
72
|
})
|
|
77
73
|
// "Check all": every CLI signed in, every key valid, every chosen model still offered and
|
|
78
74
|
// answering for the key. `?provider=codex` checks that one only (its row's Check again,
|
|
@@ -146,9 +142,11 @@ export function providerRoutes(deps) {
|
|
|
146
142
|
// What Settings draws its rails from and Play its dropdowns: every provider, with
|
|
147
143
|
// the one fact that decides whether it is selectable.
|
|
148
144
|
.get("/", async (c) => c.json({ providers: await providerStatuses(readiness) }))
|
|
149
|
-
// The system voice's speech programs and their voices, for Settings → Voices' picker
|
|
145
|
+
// The system voice's speech programs and their voices, for Settings → Voices' picker, and
|
|
146
|
+
// with none, how to install one from a terminal (the commands apart from the sentence).
|
|
150
147
|
.get("/system-voice/voices", async (c) => {
|
|
151
|
-
const
|
|
148
|
+
const host = deps.speechHost ?? process;
|
|
149
|
+
const found = await detectSpeechCached(deps.probe, host);
|
|
152
150
|
return c.json({
|
|
153
151
|
engines: found.engines.map((engine) => ({
|
|
154
152
|
id: engine.id,
|
|
@@ -157,6 +155,7 @@ export function providerRoutes(deps) {
|
|
|
157
155
|
defaultVoice: defaultSpeechVoice(engine)?.id ?? null,
|
|
158
156
|
})),
|
|
159
157
|
issue: found.issue ?? null,
|
|
158
|
+
install: found.engines.length === 0 ? (speechInstall(host) ?? null) : null,
|
|
160
159
|
});
|
|
161
160
|
})
|
|
162
161
|
.get("/:id/models", zValidator("param", providerParam, onInvalid), async (c) => {
|
|
@@ -228,7 +227,7 @@ export function providerRoutes(deps) {
|
|
|
228
227
|
if (candidate !== undefined && !candidate.success)
|
|
229
228
|
return problem(c, {
|
|
230
229
|
status: 400,
|
|
231
|
-
detail: `The pasted ${providerById(id).displayName} key could not be tested: it is empty or longer than any key. Paste the whole key in Settings →
|
|
230
|
+
detail: `The pasted ${providerById(id).displayName} key could not be tested: it is empty or longer than any key. Paste the whole key in Settings → Keys & services → ${providerById(id).displayName}, then choose Test again.`,
|
|
232
231
|
});
|
|
233
232
|
return c.json(await testProviderKey({ db: deps.db, clock: deps.clock, fetch: deps.fetch, probes: keyProbes }, id, candidate?.data.key));
|
|
234
233
|
})
|
|
@@ -9,7 +9,7 @@ export function refusal(c, reason, rules) {
|
|
|
9
9
|
export function revisionRequired(c) {
|
|
10
10
|
return problem(c, {
|
|
11
11
|
status: 409,
|
|
12
|
-
detail: "This change is now made
|
|
12
|
+
detail: "This change is now made in Edit settings: save it there, then use Choose what to make again (in the project's More menu).",
|
|
13
13
|
extensions: { reason: "revision-required" },
|
|
14
14
|
});
|
|
15
15
|
}
|
|
@@ -8,11 +8,11 @@ const body = z.object({
|
|
|
8
8
|
enabled: z.boolean(),
|
|
9
9
|
httpsPort: z.number().int().min(1).max(65535).optional(),
|
|
10
10
|
});
|
|
11
|
-
// Settings →
|
|
11
|
+
// Settings → Remote access: Slopify's page on the person's other devices through
|
|
12
12
|
// Tailscale serve. Reading it is open to agents (get_remote_access); turning it on or off is
|
|
13
13
|
// the person's alone, from this computer.
|
|
14
14
|
export function remoteAccessRoutes(service) {
|
|
15
|
-
const unavailable = "Remote access can't be set from this Slopify. Start it with npx @gentbajko/slopify and try Settings →
|
|
15
|
+
const unavailable = "Remote access can't be set from this Slopify. Start it with npx @gentbajko/slopify and try Settings → Remote access again.";
|
|
16
16
|
return new Hono()
|
|
17
17
|
.get("/", async (c) => {
|
|
18
18
|
if (service === undefined)
|
|
@@ -27,12 +27,12 @@ export function remoteAccessRoutes(service) {
|
|
|
27
27
|
if (actorOf(c) !== "person")
|
|
28
28
|
return problem(c, {
|
|
29
29
|
status: 403,
|
|
30
|
-
detail: "Remote access is the person's to turn on or off, in Settings →
|
|
30
|
+
detail: "Remote access is the person's to turn on or off, in Settings → Remote access. Agents and the assistant can only read it (get_remote_access).",
|
|
31
31
|
});
|
|
32
32
|
if (viaProxy(c.req.raw.headers))
|
|
33
33
|
return problem(c, {
|
|
34
34
|
status: 403,
|
|
35
|
-
detail: "Remote access is turned on or off only on the computer Slopify runs on. Open Settings →
|
|
35
|
+
detail: "Remote access is turned on or off only on the computer Slopify runs on. Open Settings → Remote access there, at http://127.0.0.1 and Slopify's port.",
|
|
36
36
|
});
|
|
37
37
|
const { enabled, httpsPort } = c.req.valid("json");
|
|
38
38
|
return c.json(await service.set(enabled, httpsPort));
|
|
@@ -5,12 +5,12 @@ export const hostOnlyWrites = [
|
|
|
5
5
|
{
|
|
6
6
|
method: "PUT|DELETE",
|
|
7
7
|
path: new RegExp(`^/api/providers/${id}/key/?$`),
|
|
8
|
-
what: "Provider keys are saved and removed (Settings →
|
|
8
|
+
what: "Provider keys are saved and removed (Settings → Keys & services)",
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
method: "PUT",
|
|
12
12
|
path: new RegExp(`^/api/providers/${id}/path/?$`),
|
|
13
|
-
what: "A CLI's path is set (Settings →
|
|
13
|
+
what: "A CLI's path is set (Settings → Keys & services)",
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
method: "PUT",
|
|
@@ -134,7 +134,7 @@ export function reviewRoutes(deps) {
|
|
|
134
134
|
const lead = result.reason === "running"
|
|
135
135
|
? "This item, or work that depends on it, is still running. Wait for it to finish, or Pause the project, then use Redo again."
|
|
136
136
|
: result.reason === "readiness"
|
|
137
|
-
? "Slopify can't make this item again yet. Fix what is listed in Settings →
|
|
137
|
+
? "Slopify can't make this item again yet. Fix what is listed in Settings → Keys & services or Edit settings, then use Redo again."
|
|
138
138
|
: result.reason === "conflict" || result.reason === "control-changed"
|
|
139
139
|
? "This project changed since the page loaded. Reload the project page, then use Redo again."
|
|
140
140
|
: result.reason === "invalid-selection"
|
|
@@ -80,7 +80,7 @@ function unavailable(c, reason) {
|
|
|
80
80
|
return problem(c, {
|
|
81
81
|
status: 404,
|
|
82
82
|
detail: reason === "missing-file"
|
|
83
|
-
? "This file was deleted or moved from the project folder.
|
|
83
|
+
? "This file was deleted or moved from the project folder. Use Choose what to make again (in the project's More menu) to make it again."
|
|
84
84
|
: reason === "no-images"
|
|
85
85
|
? "There are no saved files of this kind to put in the zip yet. Wait for the step that makes them to finish, then download again."
|
|
86
86
|
: "This file is no longer part of the project. Reload the page to see its current files.",
|
|
@@ -36,11 +36,11 @@ const details = {
|
|
|
36
36
|
conflict: "This project changed while you were editing. Reload the page to see the latest, then make your change again.",
|
|
37
37
|
"idempotency-conflict": "This change was already sent with different details. Reload the page, then try again.",
|
|
38
38
|
"invalid-edit": "Some of your changes are not valid. Fix the highlighted fields and save again.",
|
|
39
|
-
"stale-preview": "What needs rebuilding changed since you opened this review. Cancel it and open Choose what to
|
|
39
|
+
"stale-preview": "What needs rebuilding changed since you opened this review. Cancel it and open Choose what to make again (in the project's More menu) again to see the latest.",
|
|
40
40
|
"invalid-selection": "Some of the outputs you picked can no longer be rebuilt. Reload the page and choose again.",
|
|
41
|
-
"review-required":
|
|
42
|
-
"cost-ack-required": "Some
|
|
43
|
-
readiness: "
|
|
41
|
+
"review-required": "This touches content you supplied yourself. Tick “Keep the provided content” for each item in the review, then press the button that makes them again.",
|
|
42
|
+
"cost-ack-required": "Some prices aren't known in advance. Tick “Start even though …” in the review, then press the button that makes them again.",
|
|
43
|
+
readiness: "This can't start yet. Fix the items listed, then try again.",
|
|
44
44
|
};
|
|
45
45
|
function refused(c, deps, projectId, value) {
|
|
46
46
|
return refusal(c, value.reason, {
|
|
@@ -2,6 +2,7 @@ import { zValidator } from "@hono/zod-validator";
|
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { HTTPException } from "hono/http-exception";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { setupSectionNames } from "../../slices/project-templates/setup-sections.js";
|
|
5
6
|
import { calendarRange } from "../../slices/schedules/agenda.js";
|
|
6
7
|
import { rejectHeldTopics, restoreRejectedTopics } from "../../slices/schedules/held-bulk.js";
|
|
7
8
|
import { preparedTopics, prepareTopic } from "../../slices/schedules/prepare.js";
|
|
@@ -40,14 +41,14 @@ function refused(c, result) {
|
|
|
40
41
|
conflict: "This schedule changed while you were editing, possibly because a run just started. Reload the page to see the latest, then make your change again.",
|
|
41
42
|
"cancel-required": "This schedule is still active. Cancel it first, then delete it. Completed schedules can be deleted straight away.",
|
|
42
43
|
"missing-template": "The template you picked was deleted or changed. Choose a template again, then save.",
|
|
43
|
-
"unsupported-media":
|
|
44
|
+
"unsupported-media": `This template uses audio, images, a thumbnail, shorts background music or an ambient sound file you supplied, so it cannot run on a schedule: a scheduled run has no one to attach the file again. Pick a template that generates these instead, or open this one in Edit template, remove the music under ${setupSectionNames.shorts} (or pick Rain, Fireplace or Wind as the Ambient sound under ${setupSectionNames.video}) and save it again.`,
|
|
44
45
|
"not-due": "This one-off time has already passed. Choose a time in the future.",
|
|
45
46
|
"spend-limit": "The estimated cost is above this schedule's spend limit, or some prices are unknown. Raise the spend limit or choose models with known prices.",
|
|
46
|
-
readiness: "A provider this template needs is not ready, for example a missing API key, model or voice. Check Settings →
|
|
47
|
+
readiness: "A provider this template needs is not ready, for example a missing API key, model or voice. Check Settings → Keys & services, then try again.",
|
|
47
48
|
"queue-full": `A schedule's topic queue holds at most ${String(queueMax)} topics. Remove some under Schedules → Edit, then try again.`,
|
|
48
49
|
"topic-not-found": "This topic was already approved, turned down or used. Reload the page to see the topics waiting now.",
|
|
49
50
|
busy: "Slopify is already generating topics for this schedule. Wait for it to finish, then try again.",
|
|
50
|
-
"not-ready": "This schedule's template has no version
|
|
51
|
+
"not-ready": "This schedule's template has no version approved for schedules. Open it from Templates with Edit template, then choose More → Approve for schedules.",
|
|
51
52
|
"invalid-topics": "Some topics name keywords this template does not use. Check each topic under Schedules → Edit and save again.",
|
|
52
53
|
};
|
|
53
54
|
return refusal(c, result.reason, {
|
|
@@ -165,7 +166,8 @@ function routes(deps) {
|
|
|
165
166
|
})
|
|
166
167
|
// Which queued topics are prepared ahead, and their projects.
|
|
167
168
|
.get("/:id/prepared", zValidator("param", id, onInvalid), (c) => c.json({ prepared: preparedTopics(service(), c.req.valid("param").id) }))
|
|
168
|
-
//
|
|
169
|
+
// Make ahead one queued topic: everything but the video now, which its scheduled day puts
|
|
170
|
+
// together.
|
|
169
171
|
.post("/:id/topics/prepare", zValidator("param", id, onInvalid), zValidator("json", prepareTopicBody, onInvalid), async (c) => {
|
|
170
172
|
const result = await prepareTopic(service(), {
|
|
171
173
|
scheduleId: c.req.valid("param").id,
|
|
@@ -175,19 +177,19 @@ function routes(deps) {
|
|
|
175
177
|
return c.json({ projectId: result.projectId, title: result.title }, 201);
|
|
176
178
|
const detail = {
|
|
177
179
|
"not-found": "This topic is no longer in the schedule's queue. Reload the page to see the queue as it is now.",
|
|
178
|
-
"already-prepared": "This topic is already
|
|
179
|
-
paused: "Its schedule is paused, so it makes nothing, ahead or on its day. Resume it under Calendar → Schedules, then press
|
|
180
|
-
"missing-template": "This schedule's template was deleted, so there is nothing to
|
|
181
|
-
"spend-limit": "
|
|
182
|
-
design: "A
|
|
180
|
+
"already-prepared": "This topic is already made ahead: its project is in Projects under the same title.",
|
|
181
|
+
paused: "Its schedule is paused, so it makes nothing, ahead or on its day. Resume it under Calendar → Schedules, then press Make ahead again.",
|
|
182
|
+
"missing-template": "This schedule's template was deleted, so there is nothing to make it from. Choose another template under Edit.",
|
|
183
|
+
"spend-limit": "Making it ahead would go over this schedule's spend limit. Raise the limit under Edit, or make it from Create instead.",
|
|
184
|
+
design: "A poster schedule makes each poster on its day, so there is nothing to make ahead. To have one now, open its poster template (Templates → Poster templates) and press Make a poster; to have it sooner on a schedule, give its row an earlier date in the Schedule section.",
|
|
183
185
|
};
|
|
184
186
|
return problem(c, {
|
|
185
187
|
status: result.reason === "not-found" ? 404 : 409,
|
|
186
188
|
detail: (result.reason === "not-ready" ? result.detail : undefined) ??
|
|
187
189
|
detail[result.reason] ??
|
|
188
190
|
(result.detail === undefined
|
|
189
|
-
? `This topic couldn't be
|
|
190
|
-
: `This topic couldn't be
|
|
191
|
+
? `This topic couldn't be made ahead (${result.reason}). Open Create with the schedule's template to see what the setup needs, then try again.`
|
|
192
|
+
: `This topic couldn't be made ahead: ${result.detail} Fix it in the schedule's template (Templates → Edit template), then try again.`),
|
|
191
193
|
extensions: { reason: result.reason },
|
|
192
194
|
});
|
|
193
195
|
})
|
|
@@ -88,7 +88,11 @@ export function settingsRoutes(deps) {
|
|
|
88
88
|
return c.json({
|
|
89
89
|
nvidia: status.available
|
|
90
90
|
? { available: true }
|
|
91
|
-
: {
|
|
91
|
+
: {
|
|
92
|
+
available: false,
|
|
93
|
+
reason: status.reason,
|
|
94
|
+
...(status.detail === undefined ? {} : { detail: status.detail }),
|
|
95
|
+
},
|
|
92
96
|
});
|
|
93
97
|
})
|
|
94
98
|
// The named links `{{Name}}` placeholders in YouTube descriptions fill from
|
|
@@ -100,7 +104,7 @@ export function settingsRoutes(deps) {
|
|
|
100
104
|
if (refused !== undefined)
|
|
101
105
|
return problem(c, {
|
|
102
106
|
status: 400,
|
|
103
|
-
detail: `The channel links weren't saved: ${refused} Then press Save in Settings →
|
|
107
|
+
detail: `The channel links weren't saved: ${refused} Then press Save in Settings → YouTube Studio and posting.`,
|
|
104
108
|
});
|
|
105
109
|
writeChannelLinks(deps.db, links);
|
|
106
110
|
return c.json({ links: readChannelLinks(deps.db) });
|
package/dist/edge/http/social.js
CHANGED
|
@@ -5,6 +5,7 @@ import { projectById } from "../../slices/admission/repo.js";
|
|
|
5
5
|
import { webhookBody } from "../../slices/notifications/address.js";
|
|
6
6
|
import { sendFailureText } from "../../slices/notifications/send.js";
|
|
7
7
|
import { readNotificationUrl } from "../../slices/notifications/settings.js";
|
|
8
|
+
import { setupSectionNames } from "../../slices/project-templates/setup-sections.js";
|
|
8
9
|
import { waitsForRelease } from "../../slices/social/due.js";
|
|
9
10
|
import { postingExtension, writeExtensionSites } from "../../slices/social/extension.js";
|
|
10
11
|
import { platformLabels } from "../../slices/social/model.js";
|
|
@@ -50,7 +51,7 @@ export function socialRoutes(deps) {
|
|
|
50
51
|
: {
|
|
51
52
|
ok: false,
|
|
52
53
|
sentence: drawn?.message ??
|
|
53
|
-
"The design couldn't be drawn. Open it in
|
|
54
|
+
"The design couldn't be drawn. Open it in Designs to check it, then close Copy for YouTube Studio and open it again.",
|
|
54
55
|
};
|
|
55
56
|
},
|
|
56
57
|
}),
|
|
@@ -110,7 +111,7 @@ export function socialRoutes(deps) {
|
|
|
110
111
|
config?.text !== "prompt")
|
|
111
112
|
return problem(c, {
|
|
112
113
|
status: 409,
|
|
113
|
-
detail: `A post written by a post prompt is a paid step, so it is picked in the template, in
|
|
114
|
+
detail: `A post written by a post prompt is a paid step, so it is picked in the template, in Edit template → ${setupSectionNames.youtube}, where Save shows its cost. For this project, pick a free text source in Copy for YouTube Studio → ${platformLabels[platform]} → Settings.`,
|
|
114
115
|
});
|
|
115
116
|
writeChoice(deps.db, { projectId, platform }, choice, deps.clock.now());
|
|
116
117
|
changed(projectId);
|
|
@@ -204,7 +205,7 @@ export function socialRoutes(deps) {
|
|
|
204
205
|
if (next === undefined)
|
|
205
206
|
return problem(c, {
|
|
206
207
|
status: 404,
|
|
207
|
-
detail: "Nothing is waiting to be filled on this site. In Slopify, open the project, press
|
|
208
|
+
detail: "Nothing is waiting to be filled on this site. In Slopify, open the project, press Copy for YouTube Studio, then Fill in the site's post.",
|
|
208
209
|
});
|
|
209
210
|
changed(next.pack.projectId);
|
|
210
211
|
return c.json(next);
|
|
@@ -277,6 +278,6 @@ function unknownProject(c) {
|
|
|
277
278
|
function unknownPost(c) {
|
|
278
279
|
return problem(c, {
|
|
279
280
|
status: 404,
|
|
280
|
-
detail: "That project no longer posts to this site. In Slopify, open the project's
|
|
281
|
+
detail: "That project no longer posts to this site. In Slopify, open the project's Copy for YouTube Studio and press Fill again.",
|
|
281
282
|
});
|
|
282
283
|
}
|
|
@@ -47,7 +47,7 @@ export function stagingRoutes(deps) {
|
|
|
47
47
|
return problem(c, {
|
|
48
48
|
status: result.reason === "in-use" ? 409 : 404,
|
|
49
49
|
detail: result.reason === "in-use"
|
|
50
|
-
? "This file is still attached to a draft
|
|
50
|
+
? "This file is still attached to a draft on Create. Remove it from the draft first."
|
|
51
51
|
: "This uploaded file no longer exists; it may have been removed already. Reload the page.",
|
|
52
52
|
});
|
|
53
53
|
}
|