From 8f14800b3cb520aacc125dfed5da84a436f2fea9 Mon Sep 17 00:00:00 2001 From: rgthree Date: Tue, 18 Aug 2026 12:01:56 -0400 Subject: [PATCH] Lora Loader fixes: mute video audio, add option for autoplay previews, fix wrapping in notes, etc. --- pyproject.toml | 2 +- rgthree_config.json.default | 3 +- src_web/comfyui/config.ts | 6 +++ src_web/comfyui/dialog_info.ts | 56 +++++++++++++++++++++-- src_web/common/css/dialog_model_info.scss | 43 ++++++++++++++++- src_web/common/media/svgs.ts | 23 ++++++++++ web/comfyui/config.js | 6 +++ web/comfyui/dialog_info.js | 51 +++++++++++++++++++-- web/common/css/dialog_model_info.css | 44 +++++++++++++++++- web/common/media/svgs.js | 15 ++++++ 10 files changed, 235 insertions(+), 14 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 54958ac..3e4834e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "rgthree-comfy" description = "Making ComfyUI more comfortable." -version = "1.0.2607232129" +version = "1.0.2608181201" license = { file = "LICENSE" } dependencies = [] diff --git a/rgthree_config.json.default b/rgthree_config.json.default index e8da96f..6f95bbb 100644 --- a/rgthree_config.json.default +++ b/rgthree_config.json.default @@ -57,7 +57,8 @@ } }, "power_lora_loader": { - "show_info_badge": true + "show_info_badge": true, + "info_autoplay_video": true } }, "announcements": { diff --git a/src_web/comfyui/config.ts b/src_web/comfyui/config.ts index 6593d0f..cc3b204 100644 --- a/src_web/comfyui/config.ts +++ b/src_web/comfyui/config.ts @@ -152,6 +152,12 @@ const CONFIGURABLE: { [key: string]: ConfigurationSchema[] } = { label: "Show info badge/button", description: "Show an info badge/button on each lora row to signal and open lora details.", }, + { + key: "nodes.power_lora_loader.info_autoplay_video", + type: ConfigType.BOOLEAN, + label: "Autoplay video previews in info dialog.", + description: "In the info dialog, autoplay video preview images.", + }, ], advanced: [ { diff --git a/src_web/comfyui/dialog_info.ts b/src_web/comfyui/dialog_info.ts index 6c8b02a..4cdd8cb 100644 --- a/src_web/comfyui/dialog_info.ts +++ b/src_web/comfyui/dialog_info.ts @@ -14,9 +14,14 @@ import { pencilColored, diskColored, dotdotdot, + play, + pause, + volumeHigh, + volumeMute, } from "rgthree/common/media/svgs.js"; import {RgthreeModelInfo} from "typings/rgthree.js"; import {CHECKPOINT_INFO_SERVICE, LORA_INFO_SERVICE} from "rgthree/common/model_info_service.js"; +import {SERVICE as CONFIG_SERVICE} from "./services/config_service.js"; import {rgthree} from "./rgthree.js"; import {MenuButton} from "rgthree/common/menu.js"; import {generateId, injectCss} from "rgthree/common/shared_utils.js"; @@ -257,10 +262,17 @@ abstract class RgthreeInfoDialog extends RgthreeDialog { (img) => `
  • ${ - img.type === 'video' - ? `` + img.type === "video" + ? `` : `` - } + } + + + +
    ${imgInfoField( "", @@ -302,6 +314,42 @@ abstract class RgthreeInfoDialog extends RgthreeDialog { const div = $el("div", {html}); + // Add functionality to the videos to play/pause and toggle mute. + for (const fig of queryAll("figure", div)) { + const video = query("video", fig); + if (!video) continue; + video.addEventListener("play", () => { + video.classList.add("-rgthree-is-playing"); + }); + video.addEventListener("pause", () => { + video.classList.remove("-rgthree-is-playing"); + }); + query('[data-action="video-play-pause"]', fig)!.addEventListener("click", () => { + const isPlaying = !!( + video.currentTime > 0 && + !video.paused && + !video.ended && + video.readyState > 2 + ); + if (isPlaying) { + video.pause(); + } else { + video.play(); + } + }); + video.volume = 0; + video.classList.add("-rgthree-is-muted"); + query('[data-action="video-toggle-mute"]', fig)!.addEventListener("click", () => { + if (!video.volume) { + video.volume = 0.66; + video.classList.remove("-rgthree-is-muted"); + } else { + video.volume = 0; + video.classList.add("-rgthree-is-muted"); + } + }); + } + if (rgthree.isDevMode()) { setAttributes(query('[stub="menu"]', div)!, { children: [ @@ -314,7 +362,7 @@ abstract class RgthreeInfoDialog extends RgthreeDialog { callback: async (e: PointerEvent) => { if (this.modelInfo?.file) { window.open( - `rgthree/api/loras/info?file=${encodeURIComponent(this.modelInfo.file)}`, + `rgthree/api/loras/info?files=${encodeURIComponent(this.modelInfo.file)}`, ); } }, diff --git a/src_web/common/css/dialog_model_info.scss b/src_web/common/css/dialog_model_info.scss index 247cdc0..5e15137 100644 --- a/src_web/common/css/dialog_model_info.scss +++ b/src_web/common/css/dialog_model_info.scss @@ -183,7 +183,7 @@ } tr[data-field-name="userNote"] td > span:first-child { - white-space: pre; + white-space: pre-wrap; } tr.rgthree-info-table-break-row td { @@ -317,6 +317,43 @@ max-height: 45vh; } + menu {display: none;} + + video:not(#fakeid) { + ~ menu { + display: block; + + button { + position: absolute; + top: 8px; + width: 24px; + height: 24px; + } + svg { + position: absolute; + inset: 0; + filter: drop-shadow(1px 1px 3px black); + } + svg + svg { + display: none; + } + .rgthree-info-btn-play-pause { + left: 8px; + } + .rgthree-info-btn-mute { + right: 8px; + } + } + &.-rgthree-is-playing ~ menu { + .rgthree-info-btn-play-pause svg {display: none;} + .rgthree-info-btn-play-pause svg + svg {display: block;} + } + &.-rgthree-is-muted ~ menu { + .rgthree-info-btn-mute svg {display: none;} + .rgthree-info-btn-mute svg + svg {display: block;} + } + } + figcaption { position: absolute; left: 0; @@ -326,8 +363,10 @@ font-size: 12px; background: rgba(0,0,0,0.85); opacity: 0; + max-height: 90%; + overflow: auto; transform: translateY(50px); - transition: all 0.25s ease-in-out; + transition: transform 0.25s ease-in-out, opacity 0.25s ease-in-out; > span { display: inline-block; diff --git a/src_web/common/media/svgs.ts b/src_web/common/media/svgs.ts index b468cd0..feb5e21 100644 --- a/src_web/common/media/svgs.ts +++ b/src_web/common/media/svgs.ts @@ -33,6 +33,29 @@ export async function logoRgthreeAsync(): Promise { // Kick it off to cache upfront. logoRgthreeAsync(); +/* https://www.svgrepo.com/svg/514197/play */ +export const play = ` + + `; + +/* https://www.svgrepo.com/svg/514191/pause */ +export const pause = ` + + `; + +/* https://www.svgrepo.com/svg/442732/volume-mute */ +export const volumeMute = ` + + + `; + +/* https://www.svgrepo.com/svg/442730/volume-high */ +export const volumeHigh = ` + + + + `; + export const github = ``; diff --git a/web/comfyui/config.js b/web/comfyui/config.js index 698d425..0647d49 100644 --- a/web/comfyui/config.js +++ b/web/comfyui/config.js @@ -128,6 +128,12 @@ const CONFIGURABLE = { label: "Show info badge/button", description: "Show an info badge/button on each lora row to signal and open lora details.", }, + { + key: "nodes.power_lora_loader.info_autoplay_video", + type: ConfigType.BOOLEAN, + label: "Autoplay video previews in info dialog.", + description: "In the info dialog, autoplay video preview images.", + }, ], advanced: [ { diff --git a/web/comfyui/dialog_info.js b/web/comfyui/dialog_info.js index f2679b6..3906e65 100644 --- a/web/comfyui/dialog_info.js +++ b/web/comfyui/dialog_info.js @@ -1,7 +1,8 @@ import { RgthreeDialog } from "../../rgthree/common/dialog.js"; import { createElement as $el, empty, appendChildren, getClosestOrSelf, query, queryAll, setAttributes, } from "../../rgthree/common/utils_dom.js"; -import { logoCivitai, link, pencilColored, diskColored, dotdotdot, } from "../../rgthree/common/media/svgs.js"; +import { logoCivitai, link, pencilColored, diskColored, dotdotdot, play, pause, volumeHigh, volumeMute, } from "../../rgthree/common/media/svgs.js"; import { CHECKPOINT_INFO_SERVICE, LORA_INFO_SERVICE } from "../../rgthree/common/model_info_service.js"; +import { SERVICE as CONFIG_SERVICE } from "./services/config_service.js"; import { rgthree } from "./rgthree.js"; import { MenuButton } from "../../rgthree/common/menu.js"; import { generateId, injectCss } from "../../rgthree/common/shared_utils.js"; @@ -166,9 +167,16 @@ class RgthreeInfoDialog extends RgthreeDialog {
      ${(_y = (_x = info.images) === null || _x === void 0 ? void 0 : _x.map((img) => `
    • -
      ${img.type === 'video' - ? `` +
      ${img.type === "video" + ? `` : ``} + + + +
      ${imgInfoField("", img.civitaiUrl ? `civitai${link}` @@ -185,6 +193,41 @@ class RgthreeInfoDialog extends RgthreeDialog {
    • `).join("")) !== null && _y !== void 0 ? _y : ""}
    `; const div = $el("div", { html }); + for (const fig of queryAll("figure", div)) { + const video = query("video", fig); + if (!video) + continue; + video.addEventListener("play", () => { + video.classList.add("-rgthree-is-playing"); + }); + video.addEventListener("pause", () => { + video.classList.remove("-rgthree-is-playing"); + }); + query('[data-action="video-play-pause"]', fig).addEventListener("click", () => { + const isPlaying = !!(video.currentTime > 0 && + !video.paused && + !video.ended && + video.readyState > 2); + if (isPlaying) { + video.pause(); + } + else { + video.play(); + } + }); + video.volume = 0; + video.classList.add("-rgthree-is-muted"); + query('[data-action="video-toggle-mute"]', fig).addEventListener("click", () => { + if (!video.volume) { + video.volume = 0.66; + video.classList.remove("-rgthree-is-muted"); + } + else { + video.volume = 0; + video.classList.add("-rgthree-is-muted"); + } + }); + } if (rgthree.isDevMode()) { setAttributes(query('[stub="menu"]', div), { children: [ @@ -197,7 +240,7 @@ class RgthreeInfoDialog extends RgthreeDialog { callback: async (e) => { var _a; if ((_a = this.modelInfo) === null || _a === void 0 ? void 0 : _a.file) { - window.open(`rgthree/api/loras/info?file=${encodeURIComponent(this.modelInfo.file)}`); + window.open(`rgthree/api/loras/info?files=${encodeURIComponent(this.modelInfo.file)}`); } }, }, diff --git a/web/common/css/dialog_model_info.css b/web/common/css/dialog_model_info.css index 5edee06..811fbd4 100644 --- a/web/common/css/dialog_model_info.css +++ b/web/common/css/dialog_model_info.css @@ -149,7 +149,7 @@ margin: 2px; } .rgthree-info-dialog .rgthree-info-table tr[data-field-name=userNote] td > span:first-child { - white-space: pre; + white-space: pre-wrap; } .rgthree-info-dialog .rgthree-info-table tr.rgthree-info-table-break-row td { border: 0; @@ -268,6 +268,44 @@ .rgthree-info-dialog .rgthree-info-images > li figure video, .rgthree-info-dialog .rgthree-info-images > li figure img { max-height: 45vh; } +.rgthree-info-dialog .rgthree-info-images > li figure menu { + display: none; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid) ~ menu { + display: block; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid) ~ menu button { + position: absolute; + top: 8px; + width: 24px; + height: 24px; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid) ~ menu svg { + position: absolute; + inset: 0; + filter: drop-shadow(1px 1px 3px black); +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid) ~ menu svg + svg { + display: none; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid) ~ menu .rgthree-info-btn-play-pause { + left: 8px; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid) ~ menu .rgthree-info-btn-mute { + right: 8px; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid).-rgthree-is-playing ~ menu .rgthree-info-btn-play-pause svg { + display: none; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid).-rgthree-is-playing ~ menu .rgthree-info-btn-play-pause svg + svg { + display: block; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid).-rgthree-is-muted ~ menu .rgthree-info-btn-mute svg { + display: none; +} +.rgthree-info-dialog .rgthree-info-images > li figure video:not(#fakeid).-rgthree-is-muted ~ menu .rgthree-info-btn-mute svg + svg { + display: block; +} .rgthree-info-dialog .rgthree-info-images > li figure figcaption { position: absolute; left: 0; @@ -277,8 +315,10 @@ font-size: 12px; background: rgba(0, 0, 0, 0.85); opacity: 0; + max-height: 90%; + overflow: auto; transform: translateY(50px); - transition: all 0.25s ease-in-out; + transition: transform 0.25s ease-in-out, opacity 0.25s ease-in-out; } .rgthree-info-dialog .rgthree-info-images > li figure figcaption > span { display: inline-block; diff --git a/web/common/media/svgs.js b/web/common/media/svgs.js index 2bd2522..c92ae27 100644 --- a/web/common/media/svgs.js +++ b/web/common/media/svgs.js @@ -28,6 +28,21 @@ export async function logoRgthreeAsync() { }); } logoRgthreeAsync(); +export const play = ` + + `; +export const pause = ` + + `; +export const volumeMute = ` + + + `; +export const volumeHigh = ` + + + + `; export const github = ``;