Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,39 @@ async def cancel_download(request):
return web.json_response({"error": str(e)}, status=500)


@PromptServer.instance.routes.post(f"/{API_PREFIX}/server_download/local_filesize")
async def get_local_filesize(request):
"""Get local file size to verify download completeness"""
try:
data = await request.json()
save_path = data.get("save_path", "").strip()
filename = data.get("filename", "").strip()

if not save_path or not filename:
return web.json_response({"error": "Missing save_path or filename"}, status=400)

mapped_folder = folder_paths.map_legacy(save_path)
if mapped_folder not in folder_paths.folder_names_and_paths:
return web.json_response({"success": True, "size": -1})

paths, _ = folder_paths.folder_names_and_paths[mapped_folder]
if not paths:
return web.json_response({"success": True, "size": -1})

# Search for the file in all configured paths
for path in paths:
file_path = os.path.join(path, filename)
resolved = os.path.realpath(file_path)
if os.path.isfile(resolved):
local_size = os.path.getsize(resolved)
return web.json_response({"success": True, "size": local_size})

return web.json_response({"success": True, "size": -1})
except Exception as e:
logging.error(f"[ComfyUI-Downloader] Error getting local filesize: {e}")
return web.json_response({"error": str(e)}, status=500)


@PromptServer.instance.routes.get(f"/{API_PREFIX}/supported_extensions")
async def get_supported_extensions(request):
"""Get supported model file extensions from folder_paths"""
Expand Down
49 changes: 46 additions & 3 deletions web/js/UI.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,27 @@ export class DownloaderUI {
}
}

/**
* Fetch local file size for a given save_path and filename
*/
async fetchLocalFileSize(savePath, filename) {
if (!savePath || !filename) return -1;
try {
const response = await api.fetchApi(`/${API_PREFIX}/server_download/local_filesize`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ save_path: savePath, filename })
});
if (!response.ok) return -1;
const data = await response.json();
if (data.success) return data.size;
return -1;
} catch (error) {
console.warn("[DownloaderUI] Error fetching local file size:", error);
return -1;
}
}

/**
* Start a server download
*/
Expand Down Expand Up @@ -838,11 +859,33 @@ export class DownloaderUI {
const modelIndex = parseInt(button.dataset.modelIndex);
const model = this.modelsInWorkflow[modelIndex];

// Check if file already exists in ComfyUI
// Check if file already exists in ComfyUI and verify completeness
const fileExists = await this.isFileDownloaded(model.directory || '', model.filenamePath);
if (fileExists) {
button.textContent = '✓ Downloaded';
button.style.backgroundColor = '#4CAF50';
const sizeSpan = listContainer.querySelector(`.downloader-filesize[data-model-index="${modelIndex}"]`);
const url = model.url || '';

if (url && model.directory) {
// Fetch remote and local sizes in parallel to verify completeness
const [remoteSize, localSize] = await Promise.all([
this.fetchFileSize(url),
this.fetchLocalFileSize(model.directory, model.filenamePath)
]);

if (remoteSize && localSize > 0 && localSize < remoteSize) {
button.textContent = '⚠ Incomplete';
button.style.backgroundColor = '#FF9800';
button.title = `Local: ${this.formatFileSize(localSize)} / Remote: ${this.formatFileSize(remoteSize)}`;
if (sizeSpan) sizeSpan.textContent = `${this.formatFileSize(localSize)} / ${this.formatFileSize(remoteSize)}`;
} else {
button.textContent = '✓ Downloaded';
button.style.backgroundColor = '#4CAF50';
if (sizeSpan && remoteSize) sizeSpan.textContent = this.formatFileSize(remoteSize) || '';
}
} else {
button.textContent = '✓ Downloaded';
button.style.backgroundColor = '#4CAF50';
}
button.disabled = false;
}

Expand Down