fix: a picture gone from the media bin is dropped from its scene at Generate (said), not sent to fail in ComfyUI; the References field names it (deleted)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1576730c52
commit
03cd77e0cd
@@ -185,3 +185,14 @@ test("a scene removed while it was being made: the result is not dropped in sile
|
||||
await app.runner.units(["a"]);
|
||||
assert.match(document.body.textContent.replace(before, ""), /was removed while it was being made.*a\.mp4/);
|
||||
});
|
||||
|
||||
test("a picture no longer in the media bin is dropped from the scene before the run, and said, instead of failing in ComfyUI", async () => {
|
||||
const { app, doc } = rig("idle", { generate: async () => true });
|
||||
doc.scenes[0].references = ["deadbeef0000", "aaaaaaaaaaaa"];
|
||||
doc.scenes[0].source_image = "deadbeef0001";
|
||||
app.api.media = async () => ({ media: [{ id: "aaaaaaaaaaaa" }] });
|
||||
await app.runner.units(["a"], 1);
|
||||
assert.deepEqual(doc.scenes[0].references, ["aaaaaaaaaaaa"]);
|
||||
assert.equal(doc.scenes[0].source_image, "");
|
||||
assert.match(document.body.textContent, /no longer in the media bin/);
|
||||
});
|
||||
|
||||
@@ -70,6 +70,16 @@ export default {
|
||||
if (times > 1 && !rolesAt(frozen, "generation.seed").length) { tell("This pipeline has no seed input the app controls, so the takes would all come out the same."); return; }
|
||||
// The project too: text, lengths and references edited after the click reach the next Generate, not this one's later shots.
|
||||
const snap = structuredClone(p.project);
|
||||
// A picture deleted from the bin (in another project, or on another machine) is still named by id here: it would fail the run in ComfyUI.
|
||||
const bin = await Promise.resolve().then(() => app.api.media()).then((r) => new Set((r.media || []).map((m) => m.id)), () => null);
|
||||
const dead = (id) => bin && id && !bin.has(id);
|
||||
const prune = (pr) => pr.scenes.reduce((hit, s) => {
|
||||
const had = dead(s.source_image) || (s.references || []).some(dead);
|
||||
if (dead(s.source_image)) s.source_image = "";
|
||||
if (had) s.references = (s.references || []).filter((r) => !dead(r));
|
||||
return hit || had;
|
||||
}, false);
|
||||
if (prune(snap)) { tell("Some pictures this project used are no longer in the media bin; they were removed from their scenes."); p.edit(prune); }
|
||||
const drawn = new Map();
|
||||
const same = times > 1 ? (body) => { const key = JSON.stringify(body); if (!drawn.has(key)) drawn.set(key, expand(body)); return drawn.get(key); } : expand;
|
||||
for (const unit of Array.from({ length: times }, () => units).flat()) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// The media bin as a choice, for fields that need one picture or several: a window listing what is in it.
|
||||
import { composer as c } from "../../composer/composer.js";
|
||||
|
||||
import { learn, names } from "../../shell/bin.js";
|
||||
import { bin, learn, names } from "../../shell/bin.js";
|
||||
|
||||
let asked = false;
|
||||
|
||||
@@ -14,15 +14,15 @@ export async function look(api) {
|
||||
/** The names behind some ids; looks the bin up once if any are not known yet, then says so with `again`. */
|
||||
export function namesOf(ids, api, again) {
|
||||
if (!asked && ids.some((id) => !names.has(id))) { asked = true; look(api).then(again, () => { asked = false; }); }
|
||||
return ids.map((id) => names.get(id) || "…");
|
||||
return ids.map((id) => names.get(id) || (bin.version ? "(deleted)" : "…")); // a listing has been seen and this id was not in it
|
||||
}
|
||||
|
||||
/** -> the chosen ids in the order picked, or null when the window was closed. `multiple` false gives at most one. */
|
||||
export async function pick(api, { title, kinds, multiple, current = [] }) {
|
||||
asked = false;
|
||||
const bin = (await look(api)).filter((m) => kinds.includes(m.kind));
|
||||
if (!bin.length) { c.toast.warn({ text: `Nothing to pick: the media bin has no ${kinds.join(" or ")} yet.` }); return null; }
|
||||
const items = bin.map((m) => ({ value: m.id, label: `${m.name} (${m.kind})` }));
|
||||
const found = (await look(api)).filter((m) => kinds.includes(m.kind));
|
||||
if (!found.length) { c.toast.warn({ text: `Nothing to pick: the media bin has no ${kinds.join(" or ")} yet.` }); return null; }
|
||||
const items = found.map((m) => ({ value: m.id, label: `${m.name} (${m.kind})` }));
|
||||
return new Promise((resolve) => {
|
||||
let chosen = multiple ? current.filter((id) => names.has(id)) : [];
|
||||
const body = multiple ? c.checklist.default({ label: title, items, values: chosen, onChange: (v) => { chosen = v; } })
|
||||
|
||||
Reference in New Issue
Block a user