@gentbajko/slopify 2.0.2 → 2.0.3
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/alignment/protocol.js +11 -1
- package/dist/adapters/alignment/runner.js +4 -1
- package/dist/adapters/alignment/worker.js +28 -5
- package/dist/adapters/explain.js +93 -0
- package/dist/adapters/ffmpeg.js +3 -3
- package/dist/adapters/host-cli/index.js +9 -2
- package/dist/adapters/host-cli/transport.js +4 -4
- package/dist/adapters/image/bytes.js +2 -2
- package/dist/adapters/image/codex-output.js +12 -12
- package/dist/adapters/image/codex.js +24 -8
- package/dist/adapters/image/fal.js +12 -6
- package/dist/adapters/image/google.js +18 -8
- package/dist/adapters/image/models.js +8 -2
- package/dist/adapters/image/openai.js +15 -6
- package/dist/adapters/image/replicate.js +16 -7
- package/dist/adapters/llm/claude-code-models.js +1 -1
- package/dist/adapters/llm/claude-code.js +16 -7
- package/dist/adapters/llm/cli-login-error.js +2 -1
- package/dist/adapters/llm/codex-models.js +1 -1
- package/dist/adapters/llm/codex.js +5 -6
- package/dist/adapters/llm/document-workspace.js +2 -2
- package/dist/adapters/llm/gemini-models.js +1 -1
- package/dist/adapters/llm/gemini-workspace.js +1 -1
- package/dist/adapters/llm/gemini.js +15 -11
- package/dist/adapters/llm/openrouter.js +21 -9
- package/dist/adapters/llm/run-cli.js +14 -11
- package/dist/adapters/tts/cartesia.js +10 -3
- package/dist/adapters/tts/elevenlabs.js +18 -6
- package/dist/adapters/tts/inworld-async.js +47 -16
- package/dist/adapters/tts/inworld.js +25 -15
- package/dist/adapters/tts/openai.js +18 -6
- package/dist/catalog/registry.js +13 -10
- package/dist/catalog/store.js +1 -1
- package/dist/catalog/validate.js +13 -4
- package/dist/edge/cli.js +33 -7
- package/dist/edge/docker-launch.js +6 -6
- package/dist/edge/docker-projects/engine.js +34 -13
- package/dist/edge/docker-projects/install.js +8 -8
- package/dist/edge/docker-projects/state.js +6 -6
- package/dist/edge/docker-projects/tree.js +6 -6
- package/dist/edge/docker.js +13 -13
- package/dist/edge/http/actions.js +27 -25
- package/dist/edge/http/app.js +3 -3
- package/dist/edge/http/audio-preview.js +1 -1
- package/dist/edge/http/checkpoints.js +5 -1
- package/dist/edge/http/diagnostics.js +3 -1
- package/dist/edge/http/draft-files.js +2 -2
- package/dist/edge/http/draft-problem.js +11 -1
- package/dist/edge/http/files.js +4 -4
- package/dist/edge/http/folder-location.js +3 -3
- package/dist/edge/http/fonts.js +22 -10
- package/dist/edge/http/host-cli.js +34 -12
- package/dist/edge/http/multipart.js +7 -5
- package/dist/edge/http/open-folder.js +2 -2
- package/dist/edge/http/planning.js +4 -4
- package/dist/edge/http/problem.js +2 -2
- package/dist/edge/http/project-templates.js +7 -3
- package/dist/edge/http/projects.js +8 -8
- package/dist/edge/http/prompts.js +9 -4
- package/dist/edge/http/providers.js +15 -7
- package/dist/edge/http/revision-files.js +3 -3
- package/dist/edge/http/revisions.js +30 -4
- package/dist/edge/http/schedules.js +9 -9
- package/dist/edge/http/settings.js +15 -9
- package/dist/edge/http/staging.js +5 -5
- package/dist/edge/http/storage.js +4 -4
- package/dist/edge/http/subtitles.js +1 -1
- package/dist/edge/http/tutorial.js +2 -2
- package/dist/edge/http/update.js +3 -3
- package/dist/host-cli/install.js +28 -6
- package/dist/host-cli/paths.js +6 -6
- package/dist/host-cli/server.js +1 -1
- package/dist/host-cli/service.js +11 -11
- package/dist/host-cli/status.js +7 -3
- package/dist/kernel/config/index.js +6 -4
- package/dist/kernel/db/migrate.js +2 -1
- package/dist/kernel/db/migrations/0013-schedule-topic-queue.sql +4 -0
- package/dist/kernel/lock.js +4 -3
- package/dist/kernel/ports/subtitles.js +15 -1
- package/dist/kernel/runner/attempt.js +26 -2
- package/dist/main.js +2 -2
- package/dist/slices/admission/rules.js +32 -20
- package/dist/slices/article/continuation.js +4 -2
- package/dist/slices/article/plain.js +2 -2
- package/dist/slices/article/provided-entries.js +3 -3
- package/dist/slices/article/run.js +2 -2
- package/dist/slices/article/segments.js +5 -3
- package/dist/slices/control/providers.js +20 -7
- package/dist/slices/fonts/catalog.js +1 -1
- package/dist/slices/fonts/upload.js +1 -1
- package/dist/slices/images/run.js +5 -5
- package/dist/slices/library/lint.js +13 -7
- package/dist/slices/library/slots.js +2 -2
- package/dist/slices/narration/concat.js +1 -1
- package/dist/slices/narration/pronunciation-chunks.js +3 -3
- package/dist/slices/narration/pronunciation.js +2 -2
- package/dist/slices/narration/run.js +7 -7
- package/dist/slices/narration/steering.js +3 -3
- package/dist/slices/play-drafts/convert.js +5 -4
- package/dist/slices/play-drafts/readiness.js +12 -6
- package/dist/slices/play-drafts/review-inputs.js +7 -4
- package/dist/slices/play-drafts/review.js +3 -3
- package/dist/slices/play-drafts/service.js +3 -1
- package/dist/slices/play-drafts/uploads.js +1 -1
- package/dist/slices/rebuild/admission-repo.js +2 -2
- package/dist/slices/rebuild/recipe-legacy.js +1 -1
- package/dist/slices/rebuild/recipe-narration-text.js +1 -1
- package/dist/slices/rebuild/recipe-visual.js +1 -1
- package/dist/slices/rebuild/recovery.js +2 -2
- package/dist/slices/rebuild/repo.js +3 -3
- package/dist/slices/rebuild/runtime-admission.js +4 -4
- package/dist/slices/rebuild/runtime-article.js +5 -5
- package/dist/slices/rebuild/runtime-checkpoints.js +4 -4
- package/dist/slices/rebuild/runtime-export-inputs.js +6 -6
- package/dist/slices/rebuild/runtime-export.js +4 -4
- package/dist/slices/rebuild/runtime-local.js +6 -6
- package/dist/slices/rebuild/runtime-narration-text.js +46 -7
- package/dist/slices/rebuild/runtime-piece-label.js +62 -0
- package/dist/slices/rebuild/runtime-provider.js +6 -4
- package/dist/slices/rebuild/runtime-publication.js +3 -3
- package/dist/slices/rebuild/runtime-run.js +11 -1
- package/dist/slices/rebuild/runtime-subtitles.js +78 -15
- package/dist/slices/rebuild/transition-repo.js +6 -6
- package/dist/slices/reruns/index.js +1 -1
- package/dist/slices/research/run.js +9 -7
- package/dist/slices/research/synthesis.js +4 -2
- package/dist/slices/revisions/mutation-assets.js +26 -8
- package/dist/slices/revisions/mutation-cues.js +1 -1
- package/dist/slices/revisions/rules.js +18 -9
- package/dist/slices/revisions/schema.js +1 -1
- package/dist/slices/schedules/repo.js +55 -11
- package/dist/slices/schedules/scheduler.js +25 -8
- package/dist/slices/schedules/schema.js +19 -4
- package/dist/slices/schedules/service.js +2 -0
- package/dist/slices/settings/cli-paths.js +7 -4
- package/dist/slices/settings/models.js +4 -4
- package/dist/slices/settings/playback.js +2 -2
- package/dist/slices/storage/assets.js +5 -5
- package/dist/slices/storage/layout.js +1 -1
- package/dist/slices/subtitles/captions.js +1 -1
- package/dist/slices/subtitles/prepare.js +5 -5
- package/dist/slices/subtitles/transcript.js +1 -1
- package/dist/slices/thumbnail/run.js +8 -8
- package/dist/slices/video/audio-inputs.js +2 -2
- package/dist/slices/video/ffmpeg.js +6 -4
- package/dist/slices/video/plan.js +1 -1
- package/dist/slices/video/run.js +2 -2
- package/dist/updater/plan.js +1 -1
- package/dist/updater/service.js +4 -3
- package/dist/updater/worker.js +6 -4
- package/dist/web/assets/{index-CZNiHm8P.css → index-Bwtmu9ei.css} +1 -1
- package/dist/web/assets/index-DjhMJqMN.js +141 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-DPgGLX5m.js +0 -137
|
@@ -6,10 +6,20 @@ export function draftProblem(c, result) {
|
|
|
6
6
|
? 400
|
|
7
7
|
: 409;
|
|
8
8
|
const { ok: _ok, ...extensions } = result;
|
|
9
|
+
const details = {
|
|
10
|
+
"not-found": "This draft no longer exists; it may have been started or deleted. Reload the page to start a new one.",
|
|
11
|
+
"invalid-draft": "This saved draft could not be read. Reload the page and set the video up again in Play.",
|
|
12
|
+
conflict: "This draft changed in another tab or window. Reload the page to see the latest, then make your change again.",
|
|
13
|
+
"invalid-edit": "Some settings need fixing. Fix the highlighted fields, then try again.",
|
|
14
|
+
"pending-start": "This video is already starting. Wait a moment, then find it in Projects.",
|
|
15
|
+
"already-started": "This draft was already started. Find the video in Projects.",
|
|
16
|
+
"stale-review": "Something changed since you reviewed this video, such as a setting or a price. Choose Review and start again to see the latest.",
|
|
17
|
+
readiness: "Slopify is not ready to start this video yet. Fix the highlighted problems, then try again.",
|
|
18
|
+
};
|
|
9
19
|
return problem(c, {
|
|
10
20
|
status,
|
|
11
21
|
title: titleOf(status),
|
|
12
|
-
detail:
|
|
22
|
+
detail: details[result.reason],
|
|
13
23
|
extensions,
|
|
14
24
|
});
|
|
15
25
|
}
|
package/dist/edge/http/files.js
CHANGED
|
@@ -58,10 +58,10 @@ function disposition(filename) {
|
|
|
58
58
|
}
|
|
59
59
|
function missing(c, reason) {
|
|
60
60
|
const details = {
|
|
61
|
-
"unknown-project": "
|
|
62
|
-
"unknown-asset": "This project has no
|
|
63
|
-
"missing-file": "This file
|
|
64
|
-
"no-images": "This project has no images or thumbnail yet.",
|
|
61
|
+
"unknown-project": "This project no longer exists. Go back to Projects to pick another.",
|
|
62
|
+
"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 Re-run section on the project page to make it again.",
|
|
64
|
+
"no-images": "This project has no images or thumbnail yet. Wait for the Images step to finish, then try again.",
|
|
65
65
|
};
|
|
66
66
|
return problem(c, { status: 404, title: titleOf(404), detail: details[reason] });
|
|
67
67
|
}
|
|
@@ -10,7 +10,7 @@ export async function replyForFolder(c, deps, projectId, file) {
|
|
|
10
10
|
return problem(c, {
|
|
11
11
|
status: 503,
|
|
12
12
|
title: titleOf(503),
|
|
13
|
-
detail: "
|
|
13
|
+
detail: "Slopify cannot show where this file is on your computer because its Docker project folder was not set up. You can still use the download buttons, or run the Slopify Docker launcher again to set up the folder.",
|
|
14
14
|
});
|
|
15
15
|
try {
|
|
16
16
|
const r = relative(deps.paths.projects, file);
|
|
@@ -41,7 +41,7 @@ export async function replyForFolder(c, deps, projectId, file) {
|
|
|
41
41
|
return problem(c, {
|
|
42
42
|
status: 404,
|
|
43
43
|
title: titleOf(404),
|
|
44
|
-
detail: "This
|
|
44
|
+
detail: "This output's folder was deleted or moved. Use Re-run section on the project page to make the file again.",
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -59,7 +59,7 @@ export async function replyForFolder(c, deps, projectId, file) {
|
|
|
59
59
|
return problem(c, {
|
|
60
60
|
status: 503,
|
|
61
61
|
title: titleOf(503),
|
|
62
|
-
detail: "
|
|
62
|
+
detail: "Slopify could not open a file manager window on the computer it runs on. Make sure you are signed in to that computer's desktop, or use the download buttons instead.",
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
}
|
package/dist/edge/http/fonts.js
CHANGED
|
@@ -17,14 +17,14 @@ export function fontsRoutes(deps) {
|
|
|
17
17
|
return problem(c, {
|
|
18
18
|
status: 415,
|
|
19
19
|
title: titleOf(415),
|
|
20
|
-
detail: "
|
|
20
|
+
detail: "The font was not sent as a file. Reload the page and choose a .ttf or .otf file again.",
|
|
21
21
|
});
|
|
22
22
|
const body = c.req.raw.body;
|
|
23
23
|
if (body === null)
|
|
24
24
|
return problem(c, {
|
|
25
25
|
status: 400,
|
|
26
26
|
title: titleOf(400),
|
|
27
|
-
detail: "
|
|
27
|
+
detail: "No font file arrived. Choose a .ttf or .otf file and try again.",
|
|
28
28
|
});
|
|
29
29
|
const part = await readUpload(contentType, body);
|
|
30
30
|
if (!part.ok) {
|
|
@@ -33,8 +33,8 @@ export function fontsRoutes(deps) {
|
|
|
33
33
|
status: tooLarge ? 413 : 400,
|
|
34
34
|
title: tooLarge ? "Content Too Large" : titleOf(400),
|
|
35
35
|
detail: tooLarge
|
|
36
|
-
? "
|
|
37
|
-
: "
|
|
36
|
+
? "This font file is larger than 32 MB. Choose a smaller .ttf or .otf file."
|
|
37
|
+
: "The font upload did not arrive complete. Choose one .ttf or .otf file and try again.",
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
const result = await uploadFont(deps.paths, part.upload);
|
|
@@ -44,7 +44,11 @@ export function fontsRoutes(deps) {
|
|
|
44
44
|
})
|
|
45
45
|
.get("/:id/file", zValidator("param", idParam, (result, c) => {
|
|
46
46
|
if (!result.success)
|
|
47
|
-
return problem(c, {
|
|
47
|
+
return problem(c, {
|
|
48
|
+
status: 404,
|
|
49
|
+
title: titleOf(404),
|
|
50
|
+
detail: "This font no longer exists; it may have been deleted. Reload the page to see your current fonts.",
|
|
51
|
+
});
|
|
48
52
|
return undefined;
|
|
49
53
|
}), async (c) => {
|
|
50
54
|
try {
|
|
@@ -58,7 +62,11 @@ export function fontsRoutes(deps) {
|
|
|
58
62
|
catch (error) {
|
|
59
63
|
if (!isMissingFont(error))
|
|
60
64
|
throw error;
|
|
61
|
-
return problem(c, {
|
|
65
|
+
return problem(c, {
|
|
66
|
+
status: 404,
|
|
67
|
+
title: titleOf(404),
|
|
68
|
+
detail: "This font no longer exists; it may have been deleted. Reload the page to see your current fonts.",
|
|
69
|
+
});
|
|
62
70
|
}
|
|
63
71
|
});
|
|
64
72
|
}
|
|
@@ -127,21 +135,25 @@ function failure(reason) {
|
|
|
127
135
|
return {
|
|
128
136
|
status: 413,
|
|
129
137
|
title: "Content Too Large",
|
|
130
|
-
detail: "
|
|
138
|
+
detail: "This font file is larger than 32 MB. Choose a smaller .ttf or .otf file.",
|
|
131
139
|
};
|
|
132
140
|
case "unsupported-format":
|
|
133
|
-
return {
|
|
141
|
+
return {
|
|
142
|
+
status: 415,
|
|
143
|
+
title: titleOf(415),
|
|
144
|
+
detail: "Slopify only accepts .ttf or .otf font files. Choose a file with one of those endings.",
|
|
145
|
+
};
|
|
134
146
|
case "unsafe-filename":
|
|
135
147
|
return {
|
|
136
148
|
status: 400,
|
|
137
149
|
title: titleOf(400),
|
|
138
|
-
detail: "The font
|
|
150
|
+
detail: "The font's file name contains characters Slopify cannot use. Rename the file on your computer, then upload it again.",
|
|
139
151
|
};
|
|
140
152
|
case "invalid-font":
|
|
141
153
|
return {
|
|
142
154
|
status: 400,
|
|
143
155
|
title: titleOf(400),
|
|
144
|
-
detail: "This file is not a
|
|
156
|
+
detail: "This file is not a valid TrueType (.ttf) or OpenType (.otf) font; it may be damaged. Download the font again or choose another.",
|
|
145
157
|
};
|
|
146
158
|
}
|
|
147
159
|
}
|
|
@@ -48,14 +48,14 @@ export function hostGate() {
|
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
const unavailable = "
|
|
51
|
+
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 Retry stage.";
|
|
52
52
|
function fault(error, token) {
|
|
53
53
|
return {
|
|
54
54
|
type: "error",
|
|
55
55
|
kind: isProviderError(error) ? error.fault.kind : "unavailable",
|
|
56
56
|
message: redact(isProviderError(error)
|
|
57
57
|
? error.message
|
|
58
|
-
: "
|
|
58
|
+
: "The Slopify helper on your computer could not run the AI command-line tool. Check the tool is installed and signed in, then run the Slopify Docker launcher again.")
|
|
59
59
|
.replaceAll(token, "[redacted]")
|
|
60
60
|
.slice(0, 4096),
|
|
61
61
|
};
|
|
@@ -67,7 +67,11 @@ export function hostCliRoutes(options) {
|
|
|
67
67
|
const supplied = Buffer.from(c.req.header("authorization") ?? "");
|
|
68
68
|
const expected = Buffer.from(`Bearer ${token}`);
|
|
69
69
|
if (supplied.length !== expected.length || !timingSafeEqual(supplied, expected))
|
|
70
|
-
return c.json({
|
|
70
|
+
return c.json({
|
|
71
|
+
type: "error",
|
|
72
|
+
kind: "unavailable",
|
|
73
|
+
message: "The Slopify helper on your computer refused the connection. Run the Slopify Docker launcher again to reconnect it.",
|
|
74
|
+
}, 401);
|
|
71
75
|
c.header("Cache-Control", "no-store");
|
|
72
76
|
await next();
|
|
73
77
|
});
|
|
@@ -84,7 +88,7 @@ export function hostCliRoutes(options) {
|
|
|
84
88
|
return c.json({
|
|
85
89
|
type: "error",
|
|
86
90
|
kind: "unavailable",
|
|
87
|
-
message: "The
|
|
91
|
+
message: "The Slopify helper on your computer is busy or restarting. Wait a moment, then use Retry stage.",
|
|
88
92
|
}, 503);
|
|
89
93
|
const outgoing = c.env?.outgoing;
|
|
90
94
|
let responseEnded = !outgoing;
|
|
@@ -128,7 +132,11 @@ export function hostCliRoutes(options) {
|
|
|
128
132
|
});
|
|
129
133
|
app.use("/v1/*", bodyLimit({
|
|
130
134
|
maxSize: bridgeLimits.request,
|
|
131
|
-
onError: (c) => c.json({
|
|
135
|
+
onError: (c) => c.json({
|
|
136
|
+
type: "error",
|
|
137
|
+
kind: "unavailable",
|
|
138
|
+
message: "Slopify hit an internal error (a request to the helper on your computer was too large). Try again; if it keeps happening, use Download diagnostics in Settings and report it.",
|
|
139
|
+
}, 413),
|
|
132
140
|
}));
|
|
133
141
|
app.get("/v1/status/:provider", async (c) => {
|
|
134
142
|
const id = z.enum(hostCliIds).safeParse(c.req.param("provider"));
|
|
@@ -137,7 +145,10 @@ export function hostCliRoutes(options) {
|
|
|
137
145
|
const status = hostStatusSchema.parse(await ports.status(id.data));
|
|
138
146
|
const text = JSON.stringify(status);
|
|
139
147
|
if (Buffer.byteLength(text) > bridgeLimits.status)
|
|
140
|
-
throw providerError({
|
|
148
|
+
throw providerError({
|
|
149
|
+
kind: "unavailable",
|
|
150
|
+
message: "Slopify hit an internal error (the helper on your computer sent a status report that was too large). Try again; if it keeps happening, use Download diagnostics in Settings and report it.",
|
|
151
|
+
});
|
|
141
152
|
return c.json(status);
|
|
142
153
|
});
|
|
143
154
|
app.get("/v1/models/:provider", async (c) => {
|
|
@@ -148,7 +159,10 @@ export function hostCliRoutes(options) {
|
|
|
148
159
|
models: await (id.data === "codex-image" ? ports.image : ports.llm(id.data)).models(),
|
|
149
160
|
});
|
|
150
161
|
if (Buffer.byteLength(JSON.stringify(result)) > bridgeLimits.models)
|
|
151
|
-
throw providerError({
|
|
162
|
+
throw providerError({
|
|
163
|
+
kind: "unavailable",
|
|
164
|
+
message: "Slopify hit an internal error (the helper on your computer sent a model list that was too large). Try again; if it keeps happening, use Download diagnostics in Settings and report it.",
|
|
165
|
+
});
|
|
152
166
|
return c.json(result);
|
|
153
167
|
});
|
|
154
168
|
app.post("/v1/llm/:provider", async (c) => {
|
|
@@ -177,11 +191,11 @@ export function hostCliRoutes(options) {
|
|
|
177
191
|
timer = setTimeout(() => controller.abort(), 120_000);
|
|
178
192
|
const parsed = hostFrameSchema.parse(event);
|
|
179
193
|
if (done || parsed.type === "error")
|
|
180
|
-
throw new Error("
|
|
194
|
+
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.");
|
|
181
195
|
const frame = `${JSON.stringify(parsed)}\n`;
|
|
182
196
|
total += Buffer.byteLength(frame);
|
|
183
197
|
if (Buffer.byteLength(frame) > bridgeLimits.frame || total > bridgeLimits.stream)
|
|
184
|
-
throw new Error("
|
|
198
|
+
throw new Error("Slopify hit an internal error (the AI tool on your computer sent a reply that was too large). Try again; if it keeps happening, use Download diagnostics in Settings and report it.");
|
|
185
199
|
await output.write(frame);
|
|
186
200
|
signal.throwIfAborted();
|
|
187
201
|
done = parsed.type === "done";
|
|
@@ -217,7 +231,7 @@ export function hostCliRoutes(options) {
|
|
|
217
231
|
if (signal.aborted)
|
|
218
232
|
throw providerError({ kind: "unavailable", message: unavailable });
|
|
219
233
|
if (result.bytes.byteLength > bridgeLimits.image || sniffImage(result.bytes) !== result.mime)
|
|
220
|
-
throw new Error("
|
|
234
|
+
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.");
|
|
221
235
|
c.header("Content-Type", result.mime);
|
|
222
236
|
c.header("Content-Length", String(result.bytes.byteLength));
|
|
223
237
|
return c.body(new Uint8Array(result.bytes));
|
|
@@ -231,7 +245,11 @@ export function hostCliRoutes(options) {
|
|
|
231
245
|
}
|
|
232
246
|
});
|
|
233
247
|
app.onError((error, c) => c.json(fault(error, token), 503));
|
|
234
|
-
app.notFound((c) => c.json({
|
|
248
|
+
app.notFound((c) => c.json({
|
|
249
|
+
type: "error",
|
|
250
|
+
kind: "unavailable",
|
|
251
|
+
message: "The Slopify helper on your computer does not match this version of Slopify. Run the Slopify Docker launcher again to update it.",
|
|
252
|
+
}, 404));
|
|
235
253
|
return app;
|
|
236
254
|
}
|
|
237
255
|
async function json(request) {
|
|
@@ -243,5 +261,9 @@ async function json(request) {
|
|
|
243
261
|
}
|
|
244
262
|
}
|
|
245
263
|
function invalid(c) {
|
|
246
|
-
return c.json({
|
|
264
|
+
return c.json({
|
|
265
|
+
type: "error",
|
|
266
|
+
kind: "unavailable",
|
|
267
|
+
message: "Slopify hit an internal error (the helper on your computer received a request it could not read). Try again; if it keeps happening, use Download diagnostics in Settings and report it.",
|
|
268
|
+
}, 400);
|
|
247
269
|
}
|
|
@@ -6,10 +6,12 @@ export async function readMultipart(request, consume) {
|
|
|
6
6
|
const contentType = request.headers.get("content-type");
|
|
7
7
|
if (contentType === null || !contentType.startsWith("multipart/form-data"))
|
|
8
8
|
throw new HTTPException(415, {
|
|
9
|
-
message: "
|
|
9
|
+
message: "The upload was not sent as a file. Reload the page and choose the file again.",
|
|
10
10
|
});
|
|
11
11
|
if (request.body === null)
|
|
12
|
-
throw new HTTPException(400, {
|
|
12
|
+
throw new HTTPException(400, {
|
|
13
|
+
message: "The upload arrived empty. Choose the file again and retry.",
|
|
14
|
+
});
|
|
13
15
|
let parser;
|
|
14
16
|
try {
|
|
15
17
|
parser = new Busboy({
|
|
@@ -20,7 +22,7 @@ export async function readMultipart(request, consume) {
|
|
|
20
22
|
}
|
|
21
23
|
catch (error) {
|
|
22
24
|
throw new HTTPException(400, {
|
|
23
|
-
message: "The
|
|
25
|
+
message: "The upload did not arrive complete. Choose the file again and retry.",
|
|
24
26
|
cause: error,
|
|
25
27
|
});
|
|
26
28
|
}
|
|
@@ -43,7 +45,7 @@ export async function readMultipart(request, consume) {
|
|
|
43
45
|
};
|
|
44
46
|
source.on("error", fail);
|
|
45
47
|
parser.on("error", (error) => fail(new HTTPException(400, {
|
|
46
|
-
message: "The
|
|
48
|
+
message: "The upload did not arrive complete. Choose the file again and retry.",
|
|
47
49
|
cause: error,
|
|
48
50
|
})));
|
|
49
51
|
parser.on("finish", () => complete());
|
|
@@ -62,7 +64,7 @@ export async function readMultipart(request, consume) {
|
|
|
62
64
|
fail(error instanceof Error ? error : new Error("Upload failed", { cause: error }));
|
|
63
65
|
});
|
|
64
66
|
});
|
|
65
|
-
const abort = () => fail(new Error("
|
|
67
|
+
const abort = () => fail(new Error("The upload was interrupted before it finished. Choose the file again and retry."));
|
|
66
68
|
request.signal.addEventListener("abort", abort, { once: true });
|
|
67
69
|
if (request.signal.aborted)
|
|
68
70
|
abort();
|
|
@@ -23,7 +23,7 @@ export function openFolderRoutes(deps) {
|
|
|
23
23
|
return problem(c, {
|
|
24
24
|
status: 403,
|
|
25
25
|
title: titleOf(403),
|
|
26
|
-
detail: "
|
|
26
|
+
detail: "For your safety, folders can only be opened from the Slopify page itself. Open Slopify and try again there.",
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
const { id } = c.req.valid("param");
|
|
@@ -41,7 +41,7 @@ export function openFolderRoutes(deps) {
|
|
|
41
41
|
return problem(c, {
|
|
42
42
|
status: 404,
|
|
43
43
|
title: titleOf(404),
|
|
44
|
-
detail: "
|
|
44
|
+
detail: "This output's file was deleted or moved. Use Re-run section on the project page to make it again.",
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
return replyForFolder(c, deps, id, download.download.path);
|
|
@@ -66,7 +66,7 @@ export function planningRoutes(deps) {
|
|
|
66
66
|
return problem(c, {
|
|
67
67
|
status: 400,
|
|
68
68
|
title: titleOf(400),
|
|
69
|
-
detail: "
|
|
69
|
+
detail: "Some settings need fixing before Slopify can estimate the cost. Fix the highlighted fields.",
|
|
70
70
|
extensions: { fields },
|
|
71
71
|
});
|
|
72
72
|
return c.json({
|
|
@@ -79,7 +79,7 @@ export function planningRoutes(deps) {
|
|
|
79
79
|
return problem(c, {
|
|
80
80
|
status: 409,
|
|
81
81
|
title: titleOf(409),
|
|
82
|
-
detail: "
|
|
82
|
+
detail: "Videos with checkpoints turned on cannot be queued. Start them one at a time from Play with Review and start.",
|
|
83
83
|
});
|
|
84
84
|
if (batchExists(deps.db, input.requestId))
|
|
85
85
|
return c.json({ queue: queueEntries(deps.db, input.requestId) });
|
|
@@ -92,7 +92,7 @@ export function planningRoutes(deps) {
|
|
|
92
92
|
return problem(c, {
|
|
93
93
|
status: 400,
|
|
94
94
|
title: titleOf(400),
|
|
95
|
-
detail: "
|
|
95
|
+
detail: "The subtitle font you picked is no longer available. Choose another font before starting.",
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -102,7 +102,7 @@ export function planningRoutes(deps) {
|
|
|
102
102
|
return problem(c, {
|
|
103
103
|
status: 400,
|
|
104
104
|
title: titleOf(400),
|
|
105
|
-
detail: "No videos were queued.
|
|
105
|
+
detail: "No videos were queued. Fix the highlighted fields, then try again.",
|
|
106
106
|
extensions: { fields },
|
|
107
107
|
});
|
|
108
108
|
const queue = enqueueBatch({ ...deps, emit: (event) => deps.hub.emitGlobal(event) }, input.requestId, runs);
|
|
@@ -38,7 +38,7 @@ export function problemFromError(c, error, deps) {
|
|
|
38
38
|
return problem(c, {
|
|
39
39
|
status: 500,
|
|
40
40
|
title: titleOf(500),
|
|
41
|
-
detail: `
|
|
41
|
+
detail: `Slopify hit an internal error while handling this request. Try again; if it keeps happening, use Download diagnostics in Settings and report it (reference ${correlationId}).`,
|
|
42
42
|
extensions: { correlationId },
|
|
43
43
|
});
|
|
44
44
|
}
|
|
@@ -54,7 +54,7 @@ export function onInvalid(result, c) {
|
|
|
54
54
|
return problem(c, {
|
|
55
55
|
status: 400,
|
|
56
56
|
title: titleOf(400),
|
|
57
|
-
detail: "
|
|
57
|
+
detail: "Slopify could not read this request, which usually means the page is out of date. Reload the page and try again.",
|
|
58
58
|
extensions: {
|
|
59
59
|
errors: result.error.issues.map((issue) => ({
|
|
60
60
|
path: issue.path.join("."),
|
|
@@ -17,10 +17,14 @@ function refused(c, result) {
|
|
|
17
17
|
status,
|
|
18
18
|
title: titleOf(status),
|
|
19
19
|
detail: result.reason === "referenced-by-schedule"
|
|
20
|
-
? "
|
|
20
|
+
? "Some schedules still use this template. In Library > Schedules, cancel and delete them first; their run history is kept."
|
|
21
21
|
: result.reason === "missing-prompt"
|
|
22
|
-
? "A
|
|
23
|
-
:
|
|
22
|
+
? "A prompt or intro/outro entry this template uses was deleted. Choose another in the template, then save again."
|
|
23
|
+
: result.reason === "not-found"
|
|
24
|
+
? "This template no longer exists; it may have been deleted. Go to Library > Templates to see your templates."
|
|
25
|
+
: result.reason === "conflict"
|
|
26
|
+
? "This template or its project changed while you were editing. Reload the page to see the latest, then make your change again."
|
|
27
|
+
: "Some template settings are not valid, for example an image you supplied yourself. Check the template's settings and try again.",
|
|
24
28
|
extensions: { reason: result.reason },
|
|
25
29
|
});
|
|
26
30
|
}
|
|
@@ -60,7 +60,7 @@ export function projectRoutes(deps) {
|
|
|
60
60
|
return problem(c, {
|
|
61
61
|
status: 409,
|
|
62
62
|
title: titleOf(409),
|
|
63
|
-
detail: "
|
|
63
|
+
detail: "This project has checkpoints turned on, so it must be started from Play with Review and start.",
|
|
64
64
|
});
|
|
65
65
|
const requestedSubtitles = c.req.valid("json").subtitles;
|
|
66
66
|
if (requestedSubtitles !== undefined && requestedSubtitles.mode !== "off") {
|
|
@@ -71,12 +71,12 @@ export function projectRoutes(deps) {
|
|
|
71
71
|
return problem(c, {
|
|
72
72
|
status: 400,
|
|
73
73
|
title: titleOf(400),
|
|
74
|
-
detail: "
|
|
74
|
+
detail: "The subtitle font you picked is no longer available. Choose another font before starting.",
|
|
75
75
|
extensions: {
|
|
76
76
|
fields: [
|
|
77
77
|
{
|
|
78
78
|
field: "subtitles.fontId",
|
|
79
|
-
message: "This font is no longer available
|
|
79
|
+
message: "This font is no longer available. Choose another or upload it again in Settings.",
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
82
|
},
|
|
@@ -96,7 +96,7 @@ export function projectRoutes(deps) {
|
|
|
96
96
|
return problem(c, {
|
|
97
97
|
status: 400,
|
|
98
98
|
title: titleOf(400),
|
|
99
|
-
detail: "This
|
|
99
|
+
detail: "This video cannot start yet. Fix the highlighted fields, then try again.",
|
|
100
100
|
extensions: {
|
|
101
101
|
fields: [...picked.missing, ...modelErrors, ...(admitted.ok ? [] : admitted.fields)],
|
|
102
102
|
},
|
|
@@ -136,7 +136,7 @@ export function projectRoutes(deps) {
|
|
|
136
136
|
return problem(c, {
|
|
137
137
|
status: 404,
|
|
138
138
|
title: titleOf(404),
|
|
139
|
-
detail: "
|
|
139
|
+
detail: "This project no longer exists. Go back to Projects to pick another.",
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
142
|
if (deps.catalogue !== undefined)
|
|
@@ -171,8 +171,8 @@ const deleteStatus = {
|
|
|
171
171
|
files: 500,
|
|
172
172
|
};
|
|
173
173
|
const deleteDetails = {
|
|
174
|
-
"no-project": "
|
|
174
|
+
"no-project": "This project no longer exists. Go back to Projects to pick another.",
|
|
175
175
|
// The run has to be stopped before its files can go.
|
|
176
|
-
running: "This project is still running. Cancel the
|
|
177
|
-
files: "Some of this project's files could not be removed.",
|
|
176
|
+
running: "This project is still running. Use Cancel run on the project page first, then delete it.",
|
|
177
|
+
files: "Some of this project's files could not be removed. Close any program using files in the project folder, then try deleting again.",
|
|
178
178
|
};
|
|
@@ -50,7 +50,7 @@ export function refused(c, failure, noun) {
|
|
|
50
50
|
return problem(c, {
|
|
51
51
|
status: 400,
|
|
52
52
|
title: titleOf(400),
|
|
53
|
-
detail: `This ${noun} cannot be saved
|
|
53
|
+
detail: `This ${noun} cannot be saved yet. Fix the highlighted fields and try again.`,
|
|
54
54
|
extensions: { fields: failure.fields },
|
|
55
55
|
});
|
|
56
56
|
// The name is refused against a row that exists, and the form marks the field.
|
|
@@ -58,16 +58,21 @@ export function refused(c, failure, noun) {
|
|
|
58
58
|
return problem(c, {
|
|
59
59
|
status: 409,
|
|
60
60
|
title: titleOf(409),
|
|
61
|
-
detail: `Another ${noun} already has this name.`,
|
|
61
|
+
detail: `Another ${noun} already has this name. Choose a different name.`,
|
|
62
62
|
extensions: {
|
|
63
|
-
fields: [
|
|
63
|
+
fields: [
|
|
64
|
+
{
|
|
65
|
+
field: "name",
|
|
66
|
+
message: `Another ${noun} already has this name. Choose a different name.`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
64
69
|
},
|
|
65
70
|
});
|
|
66
71
|
case "not-found":
|
|
67
72
|
return problem(c, {
|
|
68
73
|
status: 404,
|
|
69
74
|
title: titleOf(404),
|
|
70
|
-
detail: `
|
|
75
|
+
detail: `This ${noun} no longer exists; it may have been deleted. Go back to the Library to pick another.`,
|
|
71
76
|
});
|
|
72
77
|
}
|
|
73
78
|
}
|
|
@@ -29,10 +29,16 @@ export function providerRoutes(deps) {
|
|
|
29
29
|
report: (provider) => deps.log.write("warn", "model-catalog", { detail: `Could not load models for ${provider}` }),
|
|
30
30
|
});
|
|
31
31
|
return (new Hono()
|
|
32
|
-
.get("/catalogue", (c) => c.json(deps.catalogue?.status() ?? {
|
|
32
|
+
.get("/catalogue", (c) => c.json(deps.catalogue?.status() ?? {
|
|
33
|
+
warning: "The model list (models.yaml) is not loaded yet. Wait a moment and reload the page; if it stays like this, restart Slopify.",
|
|
34
|
+
}))
|
|
33
35
|
.post("/catalogue/refresh", async (c) => {
|
|
34
36
|
if (!deps.catalogue)
|
|
35
|
-
return problem(c, {
|
|
37
|
+
return problem(c, {
|
|
38
|
+
status: 503,
|
|
39
|
+
title: titleOf(503),
|
|
40
|
+
detail: "The model list (models.yaml) is not loaded yet. Wait a moment and reload the page; if it stays like this, restart Slopify.",
|
|
41
|
+
});
|
|
36
42
|
try {
|
|
37
43
|
await deps.catalogue.refresh();
|
|
38
44
|
}
|
|
@@ -40,7 +46,7 @@ export function providerRoutes(deps) {
|
|
|
40
46
|
return problem(c, {
|
|
41
47
|
status: 502,
|
|
42
48
|
title: titleOf(502),
|
|
43
|
-
detail: "
|
|
49
|
+
detail: "Slopify could not download the latest model list. Your current list is still in use; check your internet connection and try Refresh again.",
|
|
44
50
|
});
|
|
45
51
|
}
|
|
46
52
|
return c.json(deps.catalogue.status());
|
|
@@ -104,20 +110,22 @@ function refusal(c, id, reason) {
|
|
|
104
110
|
return problem(c, {
|
|
105
111
|
status: 400,
|
|
106
112
|
title: titleOf(400),
|
|
107
|
-
detail: `${name} signs in through its own
|
|
113
|
+
detail: `${name} signs in through its own command-line tool, so it has no API key to save here. Sign in with that tool on your computer instead.`,
|
|
108
114
|
});
|
|
109
115
|
}
|
|
110
116
|
if (reason === "absent") {
|
|
111
117
|
return problem(c, {
|
|
112
118
|
status: 404,
|
|
113
119
|
title: titleOf(404),
|
|
114
|
-
detail: `
|
|
120
|
+
detail: `There is no saved API key for ${name}, so there is nothing to remove.`,
|
|
115
121
|
});
|
|
116
122
|
}
|
|
117
123
|
return problem(c, {
|
|
118
124
|
status: 400,
|
|
119
125
|
title: titleOf(400),
|
|
120
|
-
detail: "This key cannot be saved
|
|
121
|
-
extensions: {
|
|
126
|
+
detail: "This API key cannot be saved yet. Paste the key and try again.",
|
|
127
|
+
extensions: {
|
|
128
|
+
fields: [{ field: "key", message: "Paste the API key from your provider's account page." }],
|
|
129
|
+
},
|
|
122
130
|
});
|
|
123
131
|
}
|
|
@@ -47,7 +47,7 @@ export function revisionFolderRoutes(deps) {
|
|
|
47
47
|
return problem(c, {
|
|
48
48
|
status: 403,
|
|
49
49
|
title: titleOf(403),
|
|
50
|
-
detail: "
|
|
50
|
+
detail: "For your safety, folders can only be opened from the Slopify page itself. Open Slopify and try again there.",
|
|
51
51
|
});
|
|
52
52
|
const { id: projectId, revisionId, recordId } = c.req.valid("param");
|
|
53
53
|
const result = findRevisionDownload(deps, projectId, revisionId, recordId);
|
|
@@ -61,8 +61,8 @@ function unavailable(c, reason) {
|
|
|
61
61
|
status: 404,
|
|
62
62
|
title: titleOf(404),
|
|
63
63
|
detail: reason === "missing-file"
|
|
64
|
-
? "This
|
|
65
|
-
: "
|
|
64
|
+
? "This file was deleted or moved from the project folder. In the Edit tab, use Rebuild affected outputs to make it again."
|
|
65
|
+
: "This file is no longer part of the project. Reload the page to see its current files.",
|
|
66
66
|
extensions: { reason },
|
|
67
67
|
});
|
|
68
68
|
}
|