Remade download tab.
This commit is contained in:
26
README.md
26
README.md
@@ -12,22 +12,34 @@ Currently it is still missing some features it should have.
|
|||||||
|
|
||||||
## Fork Improvements
|
## Fork Improvements
|
||||||
|
|
||||||
|
### Download Tab
|
||||||
|
|
||||||
|
- Remade download tab.
|
||||||
|
- View multiple models connected to url.
|
||||||
|
- Download preview images.
|
||||||
|
- Civitai and HuggingFace API token configurable in `server_settings.yaml`.
|
||||||
|
|
||||||
|
### Models Tab
|
||||||
|
|
||||||
- Search bar in models tab.
|
- Search bar in models tab.
|
||||||
- Advanced keyword search using `"multiple words in quotes"` or a minus sign to `-exclude`.
|
- Advanced keyword search using `"multiple words in quotes"` or a minus sign to `-exclude`.
|
||||||
- Search `/`subdirectories of model directories based on your file structure (for example, `/0/1.5/styles/clothing`).
|
- Search `/`subdirectories of model directories based on your file structure (for example, `/0/1.5/styles/clothing`).
|
||||||
- Add `/` at the start of the search bar to see auto-complete suggestions.
|
- Add `/` at the start of the search bar to see auto-complete suggestions.
|
||||||
- Include models listed in ComfyUI's `extra_model_paths.yaml` or added in `ComfyUI/models`.
|
- Include models listed in ComfyUI's `extra_model_paths.yaml` or added in `ComfyUI/models`.
|
||||||
- Sort for models (Date Created, Date Modified, Name).
|
- Sort for models (Date Created, Date Modified, Name).
|
||||||
|
|
||||||
|
### ComfyUI Node Graph
|
||||||
|
|
||||||
- Button to copy a model to the ComfyUI clipboard or embedding to system clipboard. (Embedding copying requires secure http connection.)
|
- Button to copy a model to the ComfyUI clipboard or embedding to system clipboard. (Embedding copying requires secure http connection.)
|
||||||
- Button to add model to ComfyUI graph or embedding to selected nodes. (For small screens/low resolution.)
|
- Button to add model to ComfyUI graph or embedding to selected nodes. (For small screens/low resolution.)
|
||||||
- Right, left, top and bottom toggleable sidebar modes.
|
- Right, left, top and bottom toggleable sidebar modes.
|
||||||
- Drag a model onto the graph to add a new node.
|
- Drag a model onto the graph to add a new node.
|
||||||
- Drag a model onto an existing node to set the model field.
|
- Drag a model onto an existing node to set the model field.
|
||||||
- Drag an embedding onto a text area to add it to the end.
|
- Drag an embedding onto a text area to add it to the end.
|
||||||
- Increased supported preview image types.
|
|
||||||
|
### Settings Tab
|
||||||
|
|
||||||
- Correctly change colors using ComfyUI's theme colors.
|
- Correctly change colors using ComfyUI's theme colors.
|
||||||
- Simplified UI.
|
|
||||||
- Civitai and HuggingFace API token configurable in `server_settings.yaml`.
|
|
||||||
- Settings tab saved in `ui_settings.yaml`.
|
- Settings tab saved in `ui_settings.yaml`.
|
||||||
- Hide/Show 'add' and 'copy-to-clipboard' buttons.
|
- Hide/Show 'add' and 'copy-to-clipboard' buttons.
|
||||||
- Text to always search.
|
- Text to always search.
|
||||||
@@ -89,11 +101,3 @@ Currently it is still missing some features it should have.
|
|||||||
### Sidebar
|
### Sidebar
|
||||||
|
|
||||||
- ☐ Drag sidebar width/height dynamically.
|
- ☐ Drag sidebar width/height dynamically.
|
||||||
|
|
||||||
### Directory Browser and Downloading tab
|
|
||||||
|
|
||||||
(NOTE: It is a impossible to put a model automatically in the correct folder if model type information is not given or ambigious. To fully solve this requires making a file browser where files can be moved around.)
|
|
||||||
|
|
||||||
- ☐ Replace Install tab with Downloading tab (more practical IMO).
|
|
||||||
- ☐ Download a model from a url.
|
|
||||||
- ☐ Choose save path/directory to download within vaild model directories. (Alert Yes/No if need to create new dirs?)
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item {
|
.model-manager .item {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 230px;
|
width: 230px;
|
||||||
height: 345px;
|
height: 345px;
|
||||||
@@ -64,12 +64,29 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item img {
|
.model-manager .item img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-manager .model-preview-button-left,
|
||||||
|
.model-manager .model-preview-button-right {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-manager .model-preview-button-right {
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-manager .model-preview-button-left {
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.comfy-grid .model-label {
|
.comfy-grid .model-label {
|
||||||
background-color: #000a;
|
background-color: #000a;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -99,7 +116,7 @@
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-grid .item .model-preview-overlay {
|
.model-manager .item .model-preview-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -306,13 +323,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.model-manager .row {
|
.model-manager .row {
|
||||||
position: sticky;
|
position: relative;
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
margin-top: -2px;
|
margin-top: -2px;
|
||||||
padding-bottom: 18px;
|
padding-bottom: 18px;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
top: -1px;
|
top: -1px;
|
||||||
background-color: var(--comfy-input-bg);
|
background-color: var(--comfy-input-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-manager [data-name="Install"] .row,
|
||||||
|
.model-manager [data-name="Models"] .row {
|
||||||
|
position: sticky;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,9 +369,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.model-manager .search-text-area,
|
.model-manager .search-text-area,
|
||||||
.model-manager .source-text-area,
|
.model-manager .plain-text-area,
|
||||||
.model-manager .model-select-dropdown {
|
.model-manager .model-select-dropdown {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-height: 36px;
|
||||||
|
padding-block: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-manager .model-select-dropdown {
|
||||||
|
min-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.model-manager .search-dropdown {
|
.model-manager .search-dropdown {
|
||||||
@@ -424,3 +452,12 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-manager [data-name="Download"] summary {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-manager .download-details {
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 0px 16px 0px 16px;
|
||||||
|
}
|
||||||
@@ -1439,10 +1439,10 @@ class ModelManager extends ComfyDialog {
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
$tabs([
|
$tabs([
|
||||||
$tab("Install", this.#createSourceInstall()),
|
$tab("Download", [this.#downloadTab_new()]),
|
||||||
|
//$tab("Install", this.#createSourceInstall()),
|
||||||
$tab("Models", this.#modelTab_new()),
|
$tab("Models", this.#modelTab_new()),
|
||||||
$tab("Settings", [this.#settingsTab_new()]),
|
$tab("Settings", [this.#settingsTab_new()]),
|
||||||
//$tab("Download2", [this.#downloadTab_new()]),
|
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
@@ -1453,7 +1453,7 @@ class ModelManager extends ComfyDialog {
|
|||||||
|
|
||||||
#init() {
|
#init() {
|
||||||
this.#settingsTab_reload(false);
|
this.#settingsTab_reload(false);
|
||||||
this.#refreshSourceList();
|
//this.#refreshSourceList();
|
||||||
this.#modelTab_updateModels();
|
this.#modelTab_updateModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1471,7 +1471,7 @@ class ModelManager extends ComfyDialog {
|
|||||||
$: (el) => (this.#el.loadSourceBtn = el),
|
$: (el) => (this.#el.loadSourceBtn = el),
|
||||||
onclick: () => this.#refreshSourceList(),
|
onclick: () => this.#refreshSourceList(),
|
||||||
}),
|
}),
|
||||||
$el("input.source-text-area", {
|
$el("input.plain-text-area", {
|
||||||
$: (el) => (this.#el.loadSourceFromInput = el),
|
$: (el) => (this.#el.loadSourceFromInput = el),
|
||||||
placeholder: "https://ComfyUI-Model-Manager/index.json",
|
placeholder: "https://ComfyUI-Model-Manager/index.json",
|
||||||
}),
|
}),
|
||||||
@@ -1718,7 +1718,7 @@ class ModelManager extends ComfyDialog {
|
|||||||
|
|
||||||
if (reloadData) {
|
if (reloadData) {
|
||||||
// Is this slow?
|
// Is this slow?
|
||||||
this.#refreshSourceList();
|
//this.#refreshSourceList();
|
||||||
this.#modelTab_updateModels();
|
this.#modelTab_updateModels();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1940,11 +1940,11 @@ class ModelManager extends ComfyDialog {
|
|||||||
* @param {String[]} modelTypes
|
* @param {String[]} modelTypes
|
||||||
* @param {DirectoryItem[]} modelDirectories
|
* @param {DirectoryItem[]} modelDirectories
|
||||||
* @param {String} sep
|
* @param {String} sep
|
||||||
|
* @param {int} id
|
||||||
* @returns {HTMLDivElement}
|
* @returns {HTMLDivElement}
|
||||||
*/
|
*/
|
||||||
#downloadTab_modelInfo(info, modelTypes, modelDirectories, sep) {
|
#downloadTab_modelInfo(info, modelTypes, modelDirectories, sep, id) {
|
||||||
// TODO: use passed in info
|
// TODO: use passed in info
|
||||||
const RADIO_MODEL_PREVIEW_GROUP_NAME = "model-download-info-preview-model";
|
|
||||||
const RADIO_MODEL_PREVIEW_DEFAULT = "Default Preview";
|
const RADIO_MODEL_PREVIEW_DEFAULT = "Default Preview";
|
||||||
const RADIO_MODEL_PREVIEW_CUSTOM = "Custom Preview Url";
|
const RADIO_MODEL_PREVIEW_CUSTOM = "Custom Preview Url";
|
||||||
|
|
||||||
@@ -1962,14 +1962,14 @@ class ModelManager extends ComfyDialog {
|
|||||||
filename: null,
|
filename: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
$el("input", {
|
$el("input.search-text-area", {
|
||||||
$: (el) => (els.saveDirectoryPath = el),
|
$: (el) => (els.saveDirectoryPath = el),
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "/0",
|
placeholder: "/0",
|
||||||
value: "/0",
|
value: "/0",
|
||||||
});
|
});
|
||||||
|
|
||||||
$el("select", {
|
$el("select.model-select-dropdown", {
|
||||||
$: (el) => (els.modelTypeSelect = el),
|
$: (el) => (els.modelTypeSelect = el),
|
||||||
}, (() => {
|
}, (() => {
|
||||||
const options = [$el("option", { value: "" }, ["-- Model Type --"])];
|
const options = [$el("option", { value: "" }, ["-- Model Type --"])];
|
||||||
@@ -1997,172 +1997,208 @@ class ModelManager extends ComfyDialog {
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const radioGroupName = "model-download-info-preview-model" + "-" + id;
|
||||||
|
const radioGroup = $radioGroup({
|
||||||
|
name: radioGroupName,
|
||||||
|
onchange: (value) => {
|
||||||
|
switch (value) {
|
||||||
|
case RADIO_MODEL_PREVIEW_DEFAULT:
|
||||||
|
const bottonStyleDisplay = els.previewImgs.children.length > 1 ? "block" : "none";
|
||||||
|
els.buttonLeft.style.display = bottonStyleDisplay;
|
||||||
|
els.buttonRight.style.display = bottonStyleDisplay;
|
||||||
|
els.modelPreviewContainer.style.display = "block";
|
||||||
|
els.customPreviewContainer.style.display = "none";
|
||||||
|
break;
|
||||||
|
case RADIO_MODEL_PREVIEW_CUSTOM:
|
||||||
|
els.modelPreviewContainer.style.display = "none";
|
||||||
|
els.customPreviewContainer.style.display = "flex";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
els.modelPreviewContainer.style.display = "none";
|
||||||
|
els.customPreviewContainer.style.display = "none";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: (() => {
|
||||||
|
const radios = [];
|
||||||
|
radios.push({ value: "No Preview" });
|
||||||
|
if (info["images"].length > 0) {
|
||||||
|
radios.push({ value: RADIO_MODEL_PREVIEW_DEFAULT });
|
||||||
|
}
|
||||||
|
radios.push({ value: RADIO_MODEL_PREVIEW_CUSTOM });
|
||||||
|
return radios;
|
||||||
|
})(),
|
||||||
|
});
|
||||||
|
|
||||||
const filepath = info["downloadFilePath"];
|
const filepath = info["downloadFilePath"];
|
||||||
const modelInfo = $el("details", [
|
const modelInfo = $el("details.download-details", [
|
||||||
$el("summary", [filepath + info["fileName"]]),
|
$el("summary", [filepath + info["fileName"]]),
|
||||||
$el("div", [
|
$el("div", {
|
||||||
$el("div", [
|
style: { display: "flex", gap: "16px" },
|
||||||
$el("button", {
|
}, [
|
||||||
onclick: async (e) => {
|
$el("div.item", {
|
||||||
const record = {};
|
$: (el) => (els.modelPreviewContainer = el),
|
||||||
record["download"] = info["downloadUrl"];
|
style: { display: "none" },
|
||||||
record["type"] = els.modelTypeSelect.value;
|
}, [
|
||||||
if (record["type"] === "") { return; } // TODO: notify user in app
|
$el("div", {
|
||||||
record["path"] = els.saveDirectoryPath.value;
|
$: (el) => (els.previewImgs = el),
|
||||||
if (record["path"] === "/") { return; } // TODO: notify user in app
|
}, (() => {
|
||||||
record["name"] = (() => {
|
const imgs = info["images"].map((url) => {
|
||||||
const filename = info["fileName"];
|
return $el("img", {
|
||||||
const name = els.filename.value;
|
src: url,
|
||||||
if (name === "") {
|
style: { display: "none" },
|
||||||
return filename;
|
loading: "lazy",
|
||||||
}
|
|
||||||
const ext = MODEL_EXTENSIONS.find((ext) => {
|
|
||||||
return filename.endsWith(ext);
|
|
||||||
}) ?? "";
|
|
||||||
return name + ext;
|
|
||||||
})();
|
|
||||||
record["image"] = (() => {
|
|
||||||
const value = document.querySelector(`input[name="${RADIO_MODEL_PREVIEW_GROUP_NAME}"]:checked`).value;
|
|
||||||
switch (value) {
|
|
||||||
case RADIO_MODEL_PREVIEW_DEFAULT:
|
|
||||||
const children = els.previewImgs.children;
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
|
||||||
const child = children[i];
|
|
||||||
if (child.style.display !== "none") {
|
|
||||||
return child.src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
case RADIO_MODEL_PREVIEW_CUSTOM:
|
|
||||||
return els.customPreviewUrl.value;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
})();
|
|
||||||
record["overwrite"] = true; // TODO: add to UI
|
|
||||||
e.disabled = true;
|
|
||||||
await request(
|
|
||||||
"/model-manager/download",
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(record),
|
|
||||||
}
|
|
||||||
).then(data => {
|
|
||||||
if (data["success"] !== true) {
|
|
||||||
// TODO: notify user in app
|
|
||||||
console.error('Failed to download model:', data);
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
// TODO: notify user in app
|
|
||||||
console.error('Failed to download model:', err);
|
|
||||||
});
|
});
|
||||||
e.disabled = false;
|
});
|
||||||
},
|
if (imgs.length > 0) {
|
||||||
}, ["Download"]),
|
imgs[0].style.display = "block";
|
||||||
els.modelTypeSelect,
|
}
|
||||||
$el("div", [
|
return imgs;
|
||||||
els.saveDirectoryPath,
|
})()),
|
||||||
searchDropdown.element,
|
$el("div.model-preview-overlay", [
|
||||||
|
$el("button.icon-button.model-preview-button-left", {
|
||||||
|
$: (el) => (els.buttonLeft = el),
|
||||||
|
onclick: () => ModelManager.#downloadTab_updatePreview(els.previewImgs, -1),
|
||||||
|
textContent: "←",
|
||||||
|
}),
|
||||||
|
$el("button.icon-button.model-preview-button-right", {
|
||||||
|
$: (el) => (els.buttonRight = el),
|
||||||
|
onclick: () => ModelManager.#downloadTab_updatePreview(els.previewImgs, 1),
|
||||||
|
textContent: "→",
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
$el("input", {
|
|
||||||
$: (el) => (els.filename = el),
|
|
||||||
type: "text",
|
|
||||||
placeholder: (() => {
|
|
||||||
const filename = info["fileName"];
|
|
||||||
// TODO: only remove valid model file extensions
|
|
||||||
const i = filename.lastIndexOf(".");
|
|
||||||
return i === - 1 ? filename : filename.substring(0, i);
|
|
||||||
})(),
|
|
||||||
}),
|
|
||||||
]),
|
]),
|
||||||
/*
|
$el("div", [
|
||||||
$el("div", (() => {
|
$el("div", {
|
||||||
return Object.entries(info["details"]).filter(([, value]) => {
|
style: { "margin-top": "8px" }
|
||||||
return value !== undefined && value !== null;
|
}, [
|
||||||
}).map(([key, value]) => {
|
$el("div.model-preview-select-radio-container", [
|
||||||
const el = document.createElement("p");
|
$el("div.row.tab-header-flex-block", [radioGroup]),
|
||||||
el.innerText = key + ": " + value;
|
|
||||||
return el;
|
|
||||||
});
|
|
||||||
})()),
|
|
||||||
*/
|
|
||||||
$el("div.model-preview-select-radio-container", [
|
|
||||||
$radioGroup({
|
|
||||||
name: RADIO_MODEL_PREVIEW_GROUP_NAME,
|
|
||||||
onchange: (value) => {
|
|
||||||
switch (value) {
|
|
||||||
case RADIO_MODEL_PREVIEW_DEFAULT:
|
|
||||||
const bottonStyleDisplay = els.previewImgs.children.length > 1 ? "block" : "none";
|
|
||||||
els.buttonLeft.style.display = bottonStyleDisplay;
|
|
||||||
els.buttonRight.style.display = bottonStyleDisplay;
|
|
||||||
els.modelPreviewContainer.style.display = "block";
|
|
||||||
els.customPreviewContainer.style.display = "none";
|
|
||||||
break;
|
|
||||||
case RADIO_MODEL_PREVIEW_CUSTOM:
|
|
||||||
els.modelPreviewContainer.style.display = "none";
|
|
||||||
els.customPreviewContainer.style.display = "block";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
els.modelPreviewContainer.style.display = "none";
|
|
||||||
els.customPreviewContainer.style.display = "none";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options: (() => {
|
|
||||||
const radios = [];
|
|
||||||
radios.push({ value: "No Preview" });
|
|
||||||
if (info["images"].length > 0) {
|
|
||||||
radios.push({ value: RADIO_MODEL_PREVIEW_DEFAULT });
|
|
||||||
}
|
|
||||||
radios.push({ value: RADIO_MODEL_PREVIEW_CUSTOM });
|
|
||||||
return radios;
|
|
||||||
})(),
|
|
||||||
}),
|
|
||||||
$el("div", [
|
|
||||||
$el("div", {
|
|
||||||
$: (el) => (els.modelPreviewContainer = el),
|
|
||||||
style: { display: "none" },
|
|
||||||
}, [
|
|
||||||
$el("div", {
|
|
||||||
$: (el) => (els.previewImgs = el),
|
|
||||||
}, (() => {
|
|
||||||
const imgs = info["images"].map((url) => {
|
|
||||||
return $el("img", {
|
|
||||||
src: url,
|
|
||||||
style: { display: "none" },
|
|
||||||
loading: "lazy",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (imgs.length > 0) {
|
|
||||||
imgs[0].style.display = "block";
|
|
||||||
}
|
|
||||||
return imgs;
|
|
||||||
})()),
|
|
||||||
$el("div", [
|
$el("div", [
|
||||||
$el("button", {
|
$el("div.row.tab-header-flex-block", {
|
||||||
$: (el) => (els.buttonLeft = el),
|
$: (el) => (els.customPreviewContainer = el),
|
||||||
onclick: () => ModelManager.#downloadTab_updatePreview(els.previewImgs, -1),
|
style: { display: "none" },
|
||||||
}, ["LEFT"]),
|
}, [
|
||||||
$el("button", {
|
$el("input.search-text-area", {
|
||||||
$: (el) => (els.buttonRight = el),
|
$: (el) => (els.customPreviewUrl = el),
|
||||||
onclick: () => ModelManager.#downloadTab_updatePreview(els.previewImgs, 1),
|
type: "text",
|
||||||
}, ["RIGHT"]),
|
placeholder: "https://custom-image-preview.png"
|
||||||
|
}),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
$el("div", {
|
$el("div.row.tab-header-flex-block", [
|
||||||
$: (el) => (els.customPreviewContainer = el),
|
els.modelTypeSelect,
|
||||||
style: { display: "none" },
|
]),
|
||||||
}, [
|
$el("div.row.tab-header-flex-block", [
|
||||||
$el("input.search-text-area", {
|
els.saveDirectoryPath,
|
||||||
$: (el) => (els.customPreviewUrl = el),
|
searchDropdown.element,
|
||||||
|
]),
|
||||||
|
$el("div.row.tab-header-flex-block", [
|
||||||
|
$el("button.icon-button", {
|
||||||
|
textContent: "📥︎",
|
||||||
|
onclick: async (e) => {
|
||||||
|
const record = {};
|
||||||
|
record["download"] = info["downloadUrl"];
|
||||||
|
record["type"] = els.modelTypeSelect.value;
|
||||||
|
if (record["type"] === "") { return; } // TODO: notify user in app
|
||||||
|
record["path"] = els.saveDirectoryPath.value;
|
||||||
|
if (record["path"] === "/") { return; } // TODO: notify user in app
|
||||||
|
record["name"] = (() => {
|
||||||
|
const filename = info["fileName"];
|
||||||
|
const name = els.filename.value;
|
||||||
|
if (name === "") {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
const ext = MODEL_EXTENSIONS.find((ext) => {
|
||||||
|
return filename.endsWith(ext);
|
||||||
|
}) ?? "";
|
||||||
|
return name + ext;
|
||||||
|
})();
|
||||||
|
record["image"] = (() => {
|
||||||
|
const value = document.querySelector(`input[name="${radioGroupName}"]:checked`).value;
|
||||||
|
switch (value) {
|
||||||
|
case RADIO_MODEL_PREVIEW_DEFAULT:
|
||||||
|
const children = els.previewImgs.children;
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
const child = children[i];
|
||||||
|
if (child.style.display !== "none") {
|
||||||
|
return child.src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
case RADIO_MODEL_PREVIEW_CUSTOM:
|
||||||
|
return els.customPreviewUrl.value;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
})();
|
||||||
|
record["overwrite"] = false; // TODO: add to UI
|
||||||
|
e.target.disabled = true;
|
||||||
|
let success = true;
|
||||||
|
let resultText = "✔";
|
||||||
|
await request(
|
||||||
|
"/model-manager/download",
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(record),
|
||||||
|
}
|
||||||
|
).then(data => {
|
||||||
|
if (data["success"] !== true) {
|
||||||
|
// TODO: notify user in app
|
||||||
|
console.error('Failed to download model:', data);
|
||||||
|
success = false;
|
||||||
|
resultText = "📥︎";
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
// TODO: notify user in app
|
||||||
|
console.error('Failed to download model:', err);
|
||||||
|
success = false;
|
||||||
|
resultText = "📥︎";
|
||||||
|
});
|
||||||
|
buttonAlert(e.target, success, "✔", "✖", resultText);
|
||||||
|
e.target.disabled = success;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
$el("input.plain-text-area", {
|
||||||
|
$: (el) => (els.filename = el),
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "(preview image url)"
|
placeholder: (() => {
|
||||||
|
const filename = info["fileName"];
|
||||||
|
// TODO: only remove valid model file extensions
|
||||||
|
const i = filename.lastIndexOf(".");
|
||||||
|
return i === - 1 ? filename : filename.substring(0, i);
|
||||||
|
})(),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
|
/*
|
||||||
|
$el("div", (() => {
|
||||||
|
return Object.entries(info["details"]).filter(([, value]) => {
|
||||||
|
return value !== undefined && value !== null;
|
||||||
|
}).map(([key, value]) => {
|
||||||
|
const el = document.createElement("p");
|
||||||
|
el.innerText = key + ": " + value;
|
||||||
|
return el;
|
||||||
|
});
|
||||||
|
})()),
|
||||||
|
*/
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (info["images"].length > 0) {
|
||||||
|
const children = radioGroup.children;
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
const child = children[i];
|
||||||
|
const radioButton = child.children[0];
|
||||||
|
if (radioButton.value === RADIO_MODEL_PREVIEW_DEFAULT) {
|
||||||
|
els.modelPreviewContainer.style.display = "block";
|
||||||
|
radioButton.checked = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const modelTypeSelect = els.modelTypeSelect;
|
const modelTypeSelect = els.modelTypeSelect;
|
||||||
modelTypeSelect.selectedIndex = 0; // reset
|
modelTypeSelect.selectedIndex = 0; // reset
|
||||||
const comfyUIModelType = (
|
const comfyUIModelType = (
|
||||||
@@ -2257,12 +2293,13 @@ class ModelManager extends ComfyDialog {
|
|||||||
return MODEL_EXTENSIONS.find((ext) => {
|
return MODEL_EXTENSIONS.find((ext) => {
|
||||||
return filename.endsWith(ext);
|
return filename.endsWith(ext);
|
||||||
}) ?? false;
|
}) ?? false;
|
||||||
}).map((modelInfo) => {
|
}).map((modelInfo, id) => {
|
||||||
return this.#downloadTab_modelInfo(
|
return this.#downloadTab_modelInfo(
|
||||||
modelInfo,
|
modelInfo,
|
||||||
modelTypes,
|
modelTypes,
|
||||||
this.#data.modelDirectories,
|
this.#data.modelDirectories,
|
||||||
this.#sep,
|
this.#sep,
|
||||||
|
id,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (modelInfos.length === 0) {
|
if (modelInfos.length === 0) {
|
||||||
@@ -2279,11 +2316,11 @@ class ModelManager extends ComfyDialog {
|
|||||||
*/
|
*/
|
||||||
#downloadTab_new() {
|
#downloadTab_new() {
|
||||||
return $el("div", [
|
return $el("div", [
|
||||||
$el("div", [
|
$el("div.row.tab-header-flex-block", [
|
||||||
$el("input.search-text-area", {
|
$el("input.search-text-area", {
|
||||||
$: (el) => (this.#el.modelInfoUrl = el),
|
$: (el) => (this.#el.modelInfoUrl = el),
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "Civitai or HuggingFace model",
|
placeholder: "example: https://civitai.com/models/207992/stable-video-diffusion-svd",
|
||||||
onkeydown: (e) => {
|
onkeydown: (e) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -2291,13 +2328,16 @@ class ModelManager extends ComfyDialog {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
$el("button", {
|
$el("button.icon-button", {
|
||||||
onclick: () => this.#downloadTab_search(),
|
onclick: () => this.#downloadTab_search(),
|
||||||
}, ["Search"]),
|
textContent: "🔍︎",
|
||||||
|
}),
|
||||||
]),
|
]),
|
||||||
$el("div", {
|
$el("div", {
|
||||||
$: (el) => (this.#el.modelInfos = el),
|
$: (el) => (this.#el.modelInfos = el),
|
||||||
}),
|
}, [
|
||||||
|
$el("div", ["Input a URL to view download settings."]),
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user