Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled
Includes 30 custom nodes committed directly, 7 Civitai-exclusive loras stored via Git LFS, and a setup script that installs all dependencies and downloads HuggingFace-hosted models on vast.ai. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
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'
|
||||
import {toast} from "../common/toast.js";
|
||||
|
||||
const setting_id = "Comfy.EasyUse.MenuNestSub"
|
||||
let enableMenuNestSub = false
|
||||
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, enableMenuNestSub)
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
else if(getEnableMenuNestSub()){
|
||||
toast.error($t("Too many thumbnails, have closed the display"))
|
||||
}
|
||||
const existingContextMenu = LiteGraph.ContextMenu;
|
||||
LiteGraph.ContextMenu = function(values,options){
|
||||
const threshold = 10;
|
||||
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 = [];
|
||||
const add_sub_folder = (folder, folderName) => {
|
||||
let subs = []
|
||||
let less = []
|
||||
const b = folder.map(name=> {
|
||||
const _folders = {};
|
||||
const splitBy = name.indexOf('/') > -1 ? '/' : '\\';
|
||||
const valueSplit = name.split(splitBy);
|
||||
if(valueSplit.length > 1){
|
||||
const key = valueSplit.shift();
|
||||
_folders[key] = _folders[key] || [];
|
||||
_folders[key].push(valueSplit.join(splitBy));
|
||||
}
|
||||
const foldersCount = Object.values(folders).length;
|
||||
if(foldersCount > 0){
|
||||
let key = Object.keys(_folders)[0]
|
||||
if(key && _folders[key]) subs.push({key, value:_folders[key][0]})
|
||||
else{
|
||||
less.push(addContent(name,key))
|
||||
}
|
||||
}
|
||||
return addContent(name,folderName)
|
||||
})
|
||||
if(subs.length>0){
|
||||
let subs_obj = {}
|
||||
subs.forEach(item => {
|
||||
subs_obj[item.key] = subs_obj[item.key] || []
|
||||
subs_obj[item.key].push(item.value)
|
||||
})
|
||||
return [...Object.entries(subs_obj).map(f => {
|
||||
return {
|
||||
content: f[0],
|
||||
has_submenu: true,
|
||||
callback: () => {},
|
||||
submenu: {
|
||||
options: add_sub_folder(f[1], f[0]),
|
||||
}
|
||||
}
|
||||
}),...less]
|
||||
}
|
||||
else return b
|
||||
}
|
||||
|
||||
for(const [folderName,folder] of Object.entries(folders)){
|
||||
newValues.push({
|
||||
content:folderName,
|
||||
has_submenu:true,
|
||||
callback:() => {},
|
||||
submenu:{
|
||||
options:add_sub_folder(folder,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