diff --git a/app/ui/features/generate/index.js b/app/ui/features/generate/index.js index 8576d8d9..60df2ded 100644 --- a/app/ui/features/generate/index.js +++ b/app/ui/features/generate/index.js @@ -35,6 +35,7 @@ export default { busy = true; stopped = false; draw(); const pid = p.project.id; let made = 0; + said = false; try { for (const unit of units) { if (stopped) break; @@ -61,7 +62,7 @@ export default { if (!images.length) { tell("ComfyUI finished without a result (a cached run makes none). Change the prompt or seed and try again."); break; } record(pid, unit, images[images.length - 1]); } - if (!made && !stopped) tell("Nothing to generate: every scene is left out or is a video clip."); + if (!made && !stopped && !said) tell("Nothing to generate: every scene is left out or is a video clip."); } finally { busy = false; draw(); } } const unitsOf = (scenes) => [...new Set(scenes.map(genUnitId))]; diff --git a/app/ui/features/inspector/index.js b/app/ui/features/inspector/index.js index 388159c7..0b3b5b6b 100644 --- a/app/ui/features/inspector/index.js +++ b/app/ui/features/inspector/index.js @@ -25,15 +25,15 @@ const videoRows = (p, slots) => (slots || []).flatMap((slot) => (slot.roles || [ const now = field ? p.project[field] : p.video[role.input] ?? (slot.inputs || {})[role.input]; if (!Number.isInteger(now)) return null; // the project file keeps whole numbers only const label = role.label || role.input; - return c.settingsRow.default({ label, control: c.number.md({ label, min: 1, value: now, - onChange: (v) => (field ? p.setField(field, v) : p.setVideo(role.input, v)) }) }); -}).filter(Boolean)); + return { key: field || role.input, row: c.settingsRow.default({ label, control: c.number.md({ label, min: 1, step: 1, precision: 0, value: now, + onChange: (v) => (field ? p.setField(field, v) : p.setVideo(role.input, v)) }) }) }; +}).filter(Boolean)).filter((r, i, all) => all.findIndex((x) => x.key === r.key) === i).map((r) => r.row); // one row per thing edited const projectRows = (p, slots) => { const open = p.project; if (!open) return [c.emptyState.default({ icon: "▭", title: "No project", hint: "Open or create one." })]; const rows = videoRows(p, slots); - const num = (label, key, fallback, min) => c.settingsRow.default({ label, control: c.number.md({ label, min, value: open[key] || fallback, + const num = (label, key, fallback, min) => c.settingsRow.default({ label, control: c.number.md({ label, min, step: 1, precision: 0, value: open[key] || fallback, onChange: (v) => p.setField(key, v) }) }); return [ c.label.section({ text: "Project" }), diff --git a/app/ui/features/preview/index.js b/app/ui/features/preview/index.js index 174d0346..f4c7bc33 100644 --- a/app/ui/features/preview/index.js +++ b/app/ui/features/preview/index.js @@ -1,7 +1,6 @@ // The monitor: plays the render of the selected scene. import { composer as c } from "../../composer/composer.js"; import { viewUrl } from "../../shell/run.js"; -import { seconds } from "../../shell/scenes.js"; const start = (sc, r, open) => (r.inSec || 0) + (sc.source_in || 0); // where this clip begins in its render @@ -16,7 +15,7 @@ export default { let shown = ""; const draw = () => { const sc = p.selected, media = sc && p.project && (p.project.scene_renders || {})[sc.id]; - const src = media && media.media ? `${viewUrl(media.media)}#t=${start(sc, media, p.project)},${start(sc, media, p.project) + seconds(sc, p.project)}` : ""; // a split clip starts where its half does + const src = media && media.media ? `${viewUrl(media.media)}#t=${start(sc, media, p.project)}` : ""; // a split clip starts where its half does if (src === shown) return; // a keystroke elsewhere must not restart the video shown = src; viewer.setSource(src || null, "video", src ? media.media : null);