An outpaint whose new area still shows the plain fill color used to come back as a finished-looking picture with bars. Stitch Inpaint now measures how much of the new area is still flat at the fill color, beyond what the source picture itself has, and when a quarter of it (or half of any checked frame) is left, says so in the console and in a toast. The check lives in its own helper, works for images and video and for any fill color, and stays quiet on dark scenes that are painted.
70 lines
2.8 KiB
JavaScript
70 lines
2.8 KiB
JavaScript
// Notifications 🆎 — a soft two-note chime when the queue finishes, and a
|
|
// toast for the notices nodes send with their results.
|
|
//
|
|
// The chime is off by default (a sound nobody asked for is a surprise); one boolean
|
|
// setting turns it on. The chime is built once as a small WAV in memory
|
|
// and played through an ordinary audio element, so the pack ships no sound
|
|
// file and nothing is built until the first chime plays.
|
|
import { api } from "/scripts/api.js";
|
|
import { app } from "/scripts/app.js";
|
|
import { showToast } from "../shared/index.mjs";
|
|
import { noticesFromExecuted, queueRemaining, shouldChime } from "../shared/notify.mjs";
|
|
import { chimeSamples, wavBytes } from "./chime.mjs";
|
|
|
|
const SETTING_ID = "AusBoss.Notifications.CompletionSound";
|
|
|
|
let enabled = false;
|
|
// Start at 0 so a page opened onto an idle queue never chimes; the first
|
|
// queued prompt raises it and the run's final 0 triggers the chime.
|
|
let lastRemaining = 0;
|
|
let chimeUrl = null;
|
|
|
|
function playChime() {
|
|
try {
|
|
chimeUrl ??= URL.createObjectURL(new Blob([wavBytes(chimeSamples())], { type: "audio/wav" }));
|
|
// Queuing a prompt was a click, so the page may play sound by the time
|
|
// a run finishes; a refusal is swallowed like any other failure.
|
|
new Audio(chimeUrl).play()?.catch?.(() => {});
|
|
} catch (_error) {
|
|
// No audio device or playback blocked: the chime is advice, not a
|
|
// feature — never let it break the status stream.
|
|
}
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "AusBoss.Notify",
|
|
settings: [
|
|
{
|
|
id: SETTING_ID,
|
|
name: "Completion sound",
|
|
type: "boolean",
|
|
defaultValue: false,
|
|
tooltip:
|
|
"Plays a soft two-note chime when the prompt queue empties, so a "
|
|
+ "long video render can run in another window without being "
|
|
+ "watched. Off keeps ComfyUI silent.",
|
|
category: ["🆎 AusBoss", "Notifications", "Completion sound"],
|
|
onChange(value) {
|
|
enabled = !!value;
|
|
},
|
|
},
|
|
],
|
|
setup() {
|
|
// onChange only fires on later edits, so seed from the stored value here.
|
|
enabled = !!app.ui?.settings?.getSettingValue?.(SETTING_ID);
|
|
// Notices a node sends with its result (an outpaint that came back
|
|
// unpainted) show as a toast, so they are not lost in the console.
|
|
api.addEventListener("executed", (event) => {
|
|
for (const { source, text } of noticesFromExecuted(event?.detail)) {
|
|
showToast({ severity: "warn", summary: source ? `${source} \u{1F18E}` : "AusBoss", detail: text, life: 20000 });
|
|
}
|
|
});
|
|
api.addEventListener("status", (event) => {
|
|
const next = queueRemaining(event?.detail);
|
|
if (next === null) return; // disconnects and unknown shapes stay silent
|
|
if (shouldChime(enabled, lastRemaining, next)) playChime();
|
|
lastRemaining = next;
|
|
});
|
|
},
|
|
});
|