add:enable contextmenu auto nest subdirectories

This commit is contained in:
yolain
2024-04-03 14:59:23 +08:00
parent 96b3897f95
commit cd5fcd1f70
9 changed files with 184 additions and 123 deletions
+1 -2
View File
@@ -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`
+1 -2
View File
@@ -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`
+17
View File
@@ -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 = {}
+5
View File
@@ -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)
# ---------------------------------------------------------------提示词 开始----------------------------------------------------------------------#
# 正面提示词
+20
View File
@@ -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
View File
@@ -1,4 +1,5 @@
@import "theme.css";
@import "dropdown.css";
@import "selector.css";
@import "groupmap.css";
@import "groupmap.css";
@import "contextmenu.css";
+3 -2
View File
@@ -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) => {
+7
View File
@@ -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
View File
@@ -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;
},
})