add:enable contextmenu auto nest subdirectories
This commit is contained in:
+1
-2
@@ -33,8 +33,7 @@
|
||||
|
||||
**v1.1.2 (2024/3/25)**
|
||||
|
||||
PS: Please update [ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus) to v2, and moved v1 models to **ComfyUI\models\ipadapter** (Otherwise, the latest model is automatically downloaded from Huggingface)
|
||||
<br>
|
||||
- Added **Enable ContextMenu Auto Nest Subdirectories** The setting item is enabled by default, and it can be classified into subdirectories, checkpoints and loras previews
|
||||
- Added `easy sv3dLoader`
|
||||
- Added `easy dynamiCrafterLoader`
|
||||
- Added `easy ipadapterApply`
|
||||
|
||||
@@ -37,8 +37,7 @@
|
||||
|
||||
**v1.1.2 (2024/3/25)**
|
||||
|
||||
PS: 请更新至最新版v2的 [ComfyUI_IPAdapter_plus](https://github.com/cubiq/ComfyUI_IPAdapter_plus), 并移动v1版本模型文件至 ComfyUI\models\ipadapter (否则会自动从huggingface下载最新模型)
|
||||
<br>
|
||||
- 增加 **启用上下文菜单自动嵌套子目录** 设置项,默认为启用状态,可分类子目录及checkpoints、loras预览图
|
||||
- 增加 `easy sv3dLoader`
|
||||
- 增加 `easy dynamiCrafterLoader`
|
||||
- 增加 `easy ipadapterApply`
|
||||
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
import torch
|
||||
import sys
|
||||
import json
|
||||
import folder_paths
|
||||
from server import PromptServer
|
||||
from .config import RESOURCES_DIR, FOOOCUS_STYLES_DIR, FOOOCUS_STYLES_SAMPLES
|
||||
from .easyNodes import easyCache
|
||||
@@ -111,6 +112,22 @@ async def getModelsList(request):
|
||||
else:
|
||||
return web.Response(status=400)
|
||||
|
||||
# get models thumbnails
|
||||
@PromptServer.instance.routes.get("/easyuse/models/thumbnail")
|
||||
async def getModelsThumbnail(request):
|
||||
checkpoints = folder_paths.get_filename_list("checkpoints_thumb")
|
||||
loras = folder_paths.get_filename_list("loras_thumb")
|
||||
checkpoints_full = []
|
||||
loras_full = []
|
||||
for index, i in enumerate(checkpoints):
|
||||
full_path = folder_paths.get_full_path('checkpoints_thumb', str(i))
|
||||
if full_path:
|
||||
checkpoints_full.append(full_path)
|
||||
for index, i in enumerate(loras):
|
||||
full_path = folder_paths.get_full_path('loras_thumb', str(i))
|
||||
if full_path:
|
||||
loras_full.append(full_path)
|
||||
return web.json_response(checkpoints_full + loras_full)
|
||||
|
||||
NODE_CLASS_MAPPINGS = {}
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {}
|
||||
@@ -30,6 +30,8 @@ from .libs.easing import EasingBase
|
||||
sampler = easySampler()
|
||||
easyCache = easyLoader()
|
||||
|
||||
image_suffixs = set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".tiff", ".svg", ".ico", ".apng", ".tif", ".hdr", ".exr"])
|
||||
|
||||
model_path = folder_paths.models_dir
|
||||
add_folder_path_and_extensions("ultralytics_bbox", [os.path.join(model_path, "ultralytics", "bbox")], folder_paths.supported_pt_extensions)
|
||||
add_folder_path_and_extensions("ultralytics_segm", [os.path.join(model_path, "ultralytics", "segm")], folder_paths.supported_pt_extensions)
|
||||
@@ -45,6 +47,9 @@ add_folder_path_and_extensions("rembg", [os.path.join(model_path, "rembg")], fol
|
||||
add_folder_path_and_extensions("ipadapter", [os.path.join(model_path, "ipadapter")], folder_paths.supported_pt_extensions)
|
||||
add_folder_path_and_extensions("dynamicrafter_models", [os.path.join(model_path, "dynamicrafter_models")], folder_paths.supported_pt_extensions)
|
||||
|
||||
add_folder_path_and_extensions("checkpoints_thumb", [os.path.join(model_path, "checkpoints")], image_suffixs)
|
||||
add_folder_path_and_extensions("loras_thumb", [os.path.join(model_path, "loras")], image_suffixs)
|
||||
|
||||
# ---------------------------------------------------------------提示词 开始----------------------------------------------------------------------#
|
||||
|
||||
# 正面提示词
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
.easyuse-model{
|
||||
position:relative;
|
||||
}
|
||||
.easyuse-model:hover img{
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
.easyuse-model img{
|
||||
position: absolute;
|
||||
z-index:1;
|
||||
right:-155px;
|
||||
top:0;
|
||||
width:150px;
|
||||
height:auto;
|
||||
display: none;
|
||||
filter:brightness(70%);
|
||||
-webkit-filter: brightness(70%);
|
||||
opacity: 0;
|
||||
transition:all 0.5s ease-in-out;
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
@import "theme.css";
|
||||
@import "dropdown.css";
|
||||
@import "selector.css";
|
||||
@import "groupmap.css";
|
||||
@import "groupmap.css";
|
||||
@import "contextmenu.css";
|
||||
@@ -10,8 +10,9 @@ const zhCN = {
|
||||
"Auto Sorting": "自动排序",
|
||||
"Toggle `Show/Hide` can set mode of group, LongPress can set group nodes to never": "点击`启用中/已忽略`可设置组模式, 长按可停用该组节点",
|
||||
// Quick
|
||||
"Enable ALT+1~9 to paste nodes from nodes template (ComfyUI-Easy-Use)": "启用ALT1~9从节点模板粘贴到工作流(ComfyUI-Easy-Use)",
|
||||
"Enable process bar in queue button (ComfyUI-Easy-Use)": "启用提示词队列进度显示条(ComfyUI-Easy-Use)"
|
||||
"Enable ALT+1~9 to paste nodes from nodes template (ComfyUI-Easy-Use)": "启用ALT1~9从节点模板粘贴到工作流 (ComfyUI-Easy-Use)",
|
||||
"Enable process bar in queue button (ComfyUI-Easy-Use)": "启用提示词队列进度显示条 (ComfyUI-Easy-Use)",
|
||||
"Enable ContextMenu Auto Nest Subdirectories (ComfyUI-Easy-Use)": "启用上下文菜单自动嵌套子目录 (ComfyUI-Easy-Use)"
|
||||
}
|
||||
|
||||
export const $t = (key) => {
|
||||
|
||||
@@ -38,4 +38,11 @@ export function deepEqual(obj1, obj2) {
|
||||
export function getLocale(){
|
||||
const locale = localStorage['AGL.Locale'] || localStorage['Comfy.Settings.AGL.Locale'] || 'en-US'
|
||||
return locale
|
||||
}
|
||||
|
||||
export function spliceExtension(fileName){
|
||||
return fileName.substring(0,fileName.lastIndexOf('.'))
|
||||
}
|
||||
export function getExtension(fileName){
|
||||
return fileName.substring(fileName.lastIndexOf('.') + 1)
|
||||
}
|
||||
+128
-116
@@ -1,116 +1,128 @@
|
||||
// import {app} from "/scripts/app.js";
|
||||
// import {api} from "/scripts/api.js";
|
||||
// import {$el} from "/scripts/ui.js";
|
||||
//
|
||||
// let script=document.createElement("script");
|
||||
// script.type="text/JavaScript";
|
||||
// script.innerHTML = `
|
||||
// function displayImage(e) {
|
||||
// console.log(e)
|
||||
// }
|
||||
// `
|
||||
// document.getElementsByTagName('head')[0].appendChild(script);
|
||||
//
|
||||
// const Loaders = ['easy fullLoader','easy a1111Loader','easy comfyLoader']
|
||||
// app.registerExtension({
|
||||
// name:"comfy.easyUse.contextMenu",
|
||||
// async setup(){
|
||||
// const existingContextMenu = LiteGraph.ContextMenu;
|
||||
// LiteGraph.ContextMenu = function(values,options){
|
||||
// const threshold = 20;
|
||||
// const enabled = true;
|
||||
// if(!enabled || (values?.length || 0) <= threshold || !(options?.callback) || values.some(i => typeof i !== 'string')){
|
||||
// if(enabled){
|
||||
// // console.log('Skipping context menu auto nesting for incompatible menu.');
|
||||
// }
|
||||
// return existingContextMenu.apply(this,[...arguments]);
|
||||
// }
|
||||
// const compatValues = values;
|
||||
// const originalValues = [...compatValues];
|
||||
// const folders = {};
|
||||
// const specialOps = [];
|
||||
// const folderless = [];
|
||||
// for(const value of compatValues){
|
||||
// const splitBy = value.indexOf('/') > -1 ? '/' : '\\';
|
||||
// const valueSplit = value.split(splitBy);
|
||||
// if(valueSplit.length > 1){
|
||||
// const key = valueSplit.shift();
|
||||
// folders[key] = folders[key] || [];
|
||||
// folders[key].push(valueSplit.join(splitBy));
|
||||
// }else if(value === 'CHOOSE' || value.startsWith('DISABLE ')){
|
||||
// specialOps.push(value);
|
||||
// }else{
|
||||
// folderless.push(value);
|
||||
// }
|
||||
// }
|
||||
// const foldersCount = Object.values(folders).length;
|
||||
// if(foldersCount > 0){
|
||||
// const oldcallback = options.callback;
|
||||
// options.callback = null;
|
||||
// const newCallback = (item,options) => {
|
||||
// if(['None','无','無','なし'].includes(item.content)) oldcallback('None',options)
|
||||
// else oldcallback(originalValues.find(i => i.endsWith(item.content),options));
|
||||
// };
|
||||
// const addContent = (content, folderName='') => {
|
||||
// const name = folderName ? `${folderName}/${content}` : content;
|
||||
// // 获取图像
|
||||
// // const imgRes = api.fetchApi(`/easyuse/model/thumbnail?name=${name}`)
|
||||
// // if (imgRes.status === 200) {
|
||||
// // let data = await imgRes.json();
|
||||
// // console.log(data)
|
||||
// // }
|
||||
//
|
||||
// const newContent = $el(
|
||||
// "span.easyuse-model",
|
||||
// {
|
||||
// $: (el) => {
|
||||
// el.onmousemove = (e) => {
|
||||
// console.log(1)
|
||||
// };
|
||||
// el.onmouseout = () => {
|
||||
// console.log(2)
|
||||
// // hiddenImage()
|
||||
// };
|
||||
// el.onmouseover = (e) => {
|
||||
// console.log(1)
|
||||
// // displayImage(el.dataset.imgName, styleName)
|
||||
// };
|
||||
// },
|
||||
// },content)
|
||||
//
|
||||
//
|
||||
// return {
|
||||
// content,
|
||||
// title:newContent.outerHTML,
|
||||
// callback: newCallback
|
||||
// }
|
||||
// }
|
||||
// const newValues = [];
|
||||
// for(const [folderName,folder] of Object.entries(folders)){
|
||||
// newValues.push({
|
||||
// content:folderName,
|
||||
// has_submenu:true,
|
||||
// callback:() => {},
|
||||
// submenu:{
|
||||
// options:folder.map(f => addContent(f,folderName)),
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// newValues.push(...folderless.map(f => ({
|
||||
// content:f,
|
||||
// callback:newCallback
|
||||
// })));
|
||||
// if(specialOps.length > 0)
|
||||
// newValues.push(...specialOps.map(f => ({
|
||||
// content:f,
|
||||
// callback:newCallback
|
||||
// })));
|
||||
// return existingContextMenu.call(this,newValues,options);
|
||||
// }
|
||||
// return existingContextMenu.apply(this,[...arguments]);
|
||||
// }
|
||||
// LiteGraph.ContextMenu.prototype = existingContextMenu.prototype;
|
||||
// },
|
||||
//
|
||||
// })
|
||||
//
|
||||
import {app} from "/scripts/app.js";
|
||||
import {api} from "/scripts/api.js";
|
||||
import {$el} from "/scripts/ui.js";
|
||||
import {$t} from "../common/i18n.js";
|
||||
import {getExtension, spliceExtension} from '../common/utils.js'
|
||||
|
||||
const setting_id = "Comfy.EasyUse.MenuNestSub"
|
||||
let enableMenuNestSub = true
|
||||
let thumbnails = []
|
||||
|
||||
export function addMenuNestSubSetting(app) {
|
||||
app.ui.settings.addSetting({
|
||||
id: setting_id,
|
||||
name: $t("Enable ContextMenu Auto Nest Subdirectories (ComfyUI-Easy-Use)"),
|
||||
type: "boolean",
|
||||
defaultValue: enableMenuNestSub,
|
||||
onChange(value) {
|
||||
enableMenuNestSub = !!value;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const getEnableMenuNestSub = _ => app.ui.settings.getSettingValue(setting_id, true)
|
||||
|
||||
const Loaders = ['easy fullLoader','easy a1111Loader','easy comfyLoader']
|
||||
app.registerExtension({
|
||||
name:"comfy.easyUse.contextMenu",
|
||||
async setup(app){
|
||||
addMenuNestSubSetting(app)
|
||||
// 获取所有模型图像
|
||||
const imgRes = await api.fetchApi(`/easyuse/models/thumbnail`)
|
||||
if (imgRes.status === 200) {
|
||||
let data = await imgRes.json();
|
||||
thumbnails = data
|
||||
}
|
||||
const existingContextMenu = LiteGraph.ContextMenu;
|
||||
LiteGraph.ContextMenu = function(values,options){
|
||||
const threshold = 15;
|
||||
const enabled = getEnableMenuNestSub();
|
||||
if(!enabled || (values?.length || 0) <= threshold || !(options?.callback) || values.some(i => typeof i !== 'string')){
|
||||
if(enabled){
|
||||
// console.log('Skipping context menu auto nesting for incompatible menu.');
|
||||
}
|
||||
return existingContextMenu.apply(this,[...arguments]);
|
||||
}
|
||||
const compatValues = values;
|
||||
const originalValues = [...compatValues];
|
||||
const folders = {};
|
||||
const specialOps = [];
|
||||
const folderless = [];
|
||||
for(const value of compatValues){
|
||||
const splitBy = value.indexOf('/') > -1 ? '/' : '\\';
|
||||
const valueSplit = value.split(splitBy);
|
||||
if(valueSplit.length > 1){
|
||||
const key = valueSplit.shift();
|
||||
folders[key] = folders[key] || [];
|
||||
folders[key].push(valueSplit.join(splitBy));
|
||||
}else if(value === 'CHOOSE' || value.startsWith('DISABLE ')){
|
||||
specialOps.push(value);
|
||||
}else{
|
||||
folderless.push(value);
|
||||
}
|
||||
}
|
||||
const foldersCount = Object.values(folders).length;
|
||||
if(foldersCount > 0){
|
||||
const oldcallback = options.callback;
|
||||
options.callback = null;
|
||||
const newCallback = (item,options) => {
|
||||
if(['None','无','無','なし'].includes(item.content)) oldcallback('None',options)
|
||||
else oldcallback(originalValues.find(i => i.endsWith(item.content),options));
|
||||
};
|
||||
const addContent = (content, folderName='') => {
|
||||
const name = folderName ? folderName + '\\' + spliceExtension(content) : spliceExtension(content);
|
||||
const ext = getExtension(content)
|
||||
const time = new Date().getTime()
|
||||
let thumbnail = ''
|
||||
if(['ckpt', 'pt', 'bin', 'pth', 'safetensors'].includes(ext)){
|
||||
for(let i=0;i<thumbnails.length;i++){
|
||||
let thumb = thumbnails[i]
|
||||
if(name && thumb && thumb.indexOf(name) != -1){
|
||||
thumbnail = thumbnails[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let newContent
|
||||
if(thumbnail){
|
||||
const protocol = window.location.protocol
|
||||
const host = window.location.host
|
||||
const base_url = `${protocol}//${host}`
|
||||
const thumb_url = thumbnail.replace(':','%3A').replace(/\\/g,'/')
|
||||
newContent = $el("div.easyuse-model", {},[$el("span",{},content + ' *'),$el("img",{src:`${base_url}/${thumb_url}?t=${time}`})])
|
||||
}else{
|
||||
newContent = $el("div.easyuse-model", {},[
|
||||
$el("span",{},content)
|
||||
])
|
||||
}
|
||||
|
||||
return {
|
||||
content,
|
||||
title:newContent.outerHTML,
|
||||
callback: newCallback
|
||||
}
|
||||
}
|
||||
const newValues = [];
|
||||
for(const [folderName,folder] of Object.entries(folders)){
|
||||
newValues.push({
|
||||
content:folderName,
|
||||
has_submenu:true,
|
||||
callback:() => {},
|
||||
submenu:{
|
||||
options:folder.map(f => addContent(f,folderName)),
|
||||
}
|
||||
});
|
||||
}
|
||||
newValues.push(...folderless.map(f => addContent(f, '')));
|
||||
if(specialOps.length > 0)
|
||||
newValues.push(...specialOps.map(f => addContent(f, '')));
|
||||
return existingContextMenu.call(this,newValues,options);
|
||||
}
|
||||
return existingContextMenu.apply(this,[...arguments]);
|
||||
}
|
||||
LiteGraph.ContextMenu.prototype = existingContextMenu.prototype;
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user