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 = ``;