Added dynamic routing to REST API: preview/get/{path} and model/info/{path}.

- Fixed issue interacting with Imagus stripping out query parameters and getting invalid preview url. Fixed by using dynamic routing.
- Changed return format of preview string to no longer encode the uri on the server. There were issues with how python's urllib.parse.quote and .quote_plus functions interacted with slash and space characters.
This commit is contained in:
Christian Bastian
2024-09-10 00:30:44 -04:00
parent 5521e696e5
commit 35878d8514
2 changed files with 40 additions and 34 deletions

View File

@@ -414,9 +414,9 @@ def get_auto_thumbnail_format(original_format):
return "JPEG" # default fallback return "JPEG" # default fallback
@server.PromptServer.instance.routes.get("/model-manager/preview/get") @server.PromptServer.instance.routes.get("/model-manager/preview/get/{uri}")
async def get_model_preview(request): async def get_model_preview(request):
uri = request.query.get("uri", None) uri = request.match_info["uri"]
if uri is None: # BUG: this should never happen if uri is None: # BUG: this should never happen
print(f"Invalid uri! Request url: {request.url}") print(f"Invalid uri! Request url: {request.url}")
uri = "no-preview" uri = "no-preview"
@@ -800,8 +800,8 @@ async def get_model_list(request):
if image is not None: if image is not None:
raw_post = os.path.join(model_type, str(base_path_index), rel_path, image) raw_post = os.path.join(model_type, str(base_path_index), rel_path, image)
item["preview"] = { item["preview"] = {
"path": urllib.parse.quote_plus(raw_post), "path": raw_post,
"dateModified": urllib.parse.quote_plus(str(image_modified)), "dateModified": str(image_modified),
} }
model_items.append(item) model_items.append(item)
@@ -975,13 +975,13 @@ def bytes_to_size(total_bytes):
return "{:.2f}".format(total_bytes / (1 << (i * 10))) + " " + units[i] return "{:.2f}".format(total_bytes / (1 << (i * 10))) + " " + units[i]
@server.PromptServer.instance.routes.get("/model-manager/model/info") @server.PromptServer.instance.routes.get("/model-manager/model/info/{path}")
async def get_model_info(request): async def get_model_info(request):
result = { "success": False } result = { "success": False }
model_path = request.query.get("path", None) model_path = request.match_info["path"]
if model_path is None: if model_path is None:
result["alert"] = "Missing model path!" result["alert"] = "Invalid model path!"
return web.json_response(result) return web.json_response(result)
model_path = urllib.parse.unquote(model_path) model_path = urllib.parse.unquote(model_path)
@@ -1010,8 +1010,8 @@ async def get_model_info(request):
preview_path, _ = split_valid_ext(model_path, model_extensions) preview_path, _ = split_valid_ext(model_path, model_extensions)
preview_modified = pathlib.Path(maybe_preview).stat().st_mtime_ns preview_modified = pathlib.Path(maybe_preview).stat().st_mtime_ns
info["Preview"] = { info["Preview"] = {
"path": urllib.parse.quote_plus(preview_path + extension), "path": preview_path + extension,
"dateModified": urllib.parse.quote_plus(str(preview_modified)), "dateModified": str(preview_modified),
} }
break break
@@ -1096,22 +1096,25 @@ async def get_model_info(request):
result["notes"] = notes result["notes"] = notes
return web.json_response(result) return web.json_response(result)
@server.PromptServer.instance.routes.get("/model-manager/model/web-url")
async def get_model_info(request):
result = { "success": False }
@server.PromptServer.instance.routes.get("/model-manager/model/info/web-url")
async def get_model_web_url(request):
model_path = request.query.get("path", None) model_path = request.query.get("path", None)
if model_path is None: if model_path is None:
raise ValueError("Missing model path!") result["alert"] = "Invalid model path!"
return web.json_response(result)
model_path = urllib.parse.unquote(model_path) model_path = urllib.parse.unquote(model_path)
abs_path, model_type = search_path_to_system_path(model_path) abs_path, model_type = search_path_to_system_path(model_path)
if abs_path is None: if abs_path is None:
raise ValueError("Invalid model path!") result["alert"] = "Invalid model path!"
return web.json_response(result)
sha256_hash = hash_file(abs_path) sha256_hash = hash_file(abs_path)
url = search_web_for_model_url(sha256_hash) web_url = search_web_for_model_url(sha256_hash)
return web.json_response({ "url": url }) return web.json_response({ "url": web_url })
@server.PromptServer.instance.routes.get("/model-manager/system-separator") @server.PromptServer.instance.routes.get("/model-manager/system-separator")

View File

@@ -137,9 +137,8 @@ function elementFromDragEvent(event) {
* @param {string} url * @param {string} url
*/ */
async function loadWorkflow(url) { async function loadWorkflow(url) {
const uri = (new URL(url)).searchParams.get("uri"); const fileNameIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\")) + 1;
const fileNameIndex = Math.max(uri.lastIndexOf("/"), uri.lastIndexOf("\\")) + 1; const fileName = url.substring(fileNameIndex);
const fileName = uri.substring(fileNameIndex);
const response = await fetch(url); const response = await fetch(url);
const data = await response.blob(); const data = await response.blob();
const file = new File([data], fileName, { type: data.type }); const file = new File([data], fileName, { type: data.type });
@@ -152,7 +151,7 @@ async function loadWorkflow(url) {
*/ */
async function tryOpenModelUrl(modelSearchPath) { async function tryOpenModelUrl(modelSearchPath) {
const encodedPath = encodeURIComponent(modelSearchPath); const encodedPath = encodeURIComponent(modelSearchPath);
const requestUrl = `/model-manager/model/info/web-url?path=${encodedPath}`; const requestUrl = `/model-manager/model/web-url?path=${encodedPath}`;
const webUrlResponse = await comfyRequest(requestUrl); const webUrlResponse = await comfyRequest(requestUrl);
let modelUrl; let modelUrl;
try { try {
@@ -282,28 +281,32 @@ class SearchPath {
} }
/** /**
* @param {string | undefined} [searchPath=undefined] * @param {string | undefined} [imageUriSearchPath=undefined]
* @param {string | undefined} [dateImageModified=undefined] * @param {string | undefined} [dateImageModified=undefined]
* @param {string | undefined} [width=undefined] * @param {string | undefined} [width=undefined]
* @param {string | undefined} [height=undefined] * @param {string | undefined} [height=undefined]
* @param {string | undefined} [imageFormat=undefined] * @param {string | undefined} [imageFormat=undefined]
* @returns {string} * @returns {string}
*/ */
function imageUri(imageSearchPath = undefined, dateImageModified = undefined, width = undefined, height = undefined, imageFormat = undefined) { function imageUri(imageUriSearchPath = undefined, dateImageModified = undefined, width = undefined, height = undefined, imageFormat = undefined) {
const path = imageSearchPath ?? "no-preview"; const params = [];
const date = dateImageModified;
let uri = `/model-manager/preview/get?uri=${path}`;
if (width !== undefined && width !== null) { if (width !== undefined && width !== null) {
uri += `&width=${width}`; params.push(`width=${width}`);
} }
if (height !== undefined && height !== null) { if (height !== undefined && height !== null) {
uri += `&height=${height}`; params.push(`height=${height}`);
} }
if (date !== undefined && date !== null) { if (dateImageModified !== undefined && dateImageModified !== null) {
uri += `&v=${date}`; params.push(`v=${dateImageModified}`);
} }
if (imageFormat !== undefined && imageFormat !== null) { if (imageFormat !== undefined && imageFormat !== null) {
uri += `&image-format=${imageFormat}`; params.push(`image-format=${imageFormat}`);
}
const path = imageUriSearchPath ?? "no-preview";
const uri = `/model-manager/preview/get/${path}`;
if (params.length > 0) {
return uri + '?' + params.join('&');
} }
return uri; return uri;
} }
@@ -1947,8 +1950,8 @@ class ModelGrid {
const previewThumbnail = $el("img.model-preview", { const previewThumbnail = $el("img.model-preview", {
loading: "lazy", /* `loading` BEFORE `src`; Known bug in Firefox 124.0.2 and Safari for iOS 17.4.1 (https://stackoverflow.com/a/76252772) */ loading: "lazy", /* `loading` BEFORE `src`; Known bug in Firefox 124.0.2 and Safari for iOS 17.4.1 (https://stackoverflow.com/a/76252772) */
src: imageUri( src: imageUri(
previewInfo?.path, previewInfo?.path ? encodeURIComponent(previewInfo.path) : undefined,
previewInfo?.dateModified, previewInfo?.dateModified ? encodeURIComponent(previewInfo.dateModified) : undefined,
PREVIEW_THUMBNAIL_WIDTH, PREVIEW_THUMBNAIL_WIDTH,
PREVIEW_THUMBNAIL_HEIGHT, PREVIEW_THUMBNAIL_HEIGHT,
previewThumbnailFormat, previewThumbnailFormat,
@@ -2440,7 +2443,7 @@ class ModelInfo {
*/ */
async update(searchPath, updateModels, searchSeparator) { async update(searchPath, updateModels, searchSeparator) {
const path = encodeURIComponent(searchPath); const path = encodeURIComponent(searchPath);
const [info, metadata, tags, noteText] = await comfyRequest(`/model-manager/model/info?path=${path}`) const [info, metadata, tags, noteText] = await comfyRequest(`/model-manager/model/info/${path}`)
.then((result) => { .then((result) => {
const success = result["success"]; const success = result["success"];
const message = result["alert"]; const message = result["alert"];
@@ -2552,8 +2555,8 @@ class ModelInfo {
const previewSelect = this.previewSelect; const previewSelect = this.previewSelect;
const defaultUrl = previewSelect.elements.defaultUrl; const defaultUrl = previewSelect.elements.defaultUrl;
if (info["Preview"]) { if (info["Preview"]) {
const imagePath = info["Preview"]["path"]; const imagePath = encodeURIComponent(info["Preview"]["path"]);
const imageDateModified = info["Preview"]["dateModified"]; const imageDateModified = encodeURIComponent(info["Preview"]["dateModified"]);
defaultUrl.dataset.noimage = imageUri(imagePath, imageDateModified); defaultUrl.dataset.noimage = imageUri(imagePath, imageDateModified);
} }
else { else {