From 33e5f3d85d6cb8c7911246a650219aab040ec795 Mon Sep 17 00:00:00 2001 From: Will Miao Date: Mon, 18 May 2026 18:30:33 +0800 Subject: [PATCH] fix(#933): compute SHA256 locally when CivitAI API returns empty hashes --- py/services/download_manager.py | 8 ++++++-- py/services/model_scanner.py | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/py/services/download_manager.py b/py/services/download_manager.py index cf4225ab..a9f7bb3a 100644 --- a/py/services/download_manager.py +++ b/py/services/download_manager.py @@ -18,6 +18,7 @@ from ..utils.constants import ( VALID_LORA_TYPES, ) from ..utils.civitai_utils import normalize_civitai_download_url, rewrite_preview_url +from ..utils.file_utils import calculate_sha256 from ..utils.preview_selection import resolve_mature_threshold, select_preview_media from ..utils.utils import sanitize_folder_name from ..utils.exif_utils import ExifUtils @@ -2239,8 +2240,11 @@ class DownloadManager: entry.file_name = os.path.splitext(os.path.basename(file_path))[0] # Update size to actual downloaded file size entry.size = os.path.getsize(file_path) - # Use SHA256 from API metadata (already set in from_civitai_info) - # Do not recalculate to avoid blocking during ComfyUI execution + # Compute SHA256 locally when the API response didn't include it + if not entry.sha256: + sha256 = await calculate_sha256(file_path) + if sha256: + entry.sha256 = sha256.lower() entries.append(entry) return entries diff --git a/py/services/model_scanner.py b/py/services/model_scanner.py index e2257674..7d4d659e 100644 --- a/py/services/model_scanner.py +++ b/py/services/model_scanner.py @@ -9,7 +9,7 @@ from typing import Any, Awaitable, Callable, Dict, List, Mapping, Optional, Set, from ..utils.models import BaseModelMetadata from ..config import config -from ..utils.file_utils import find_preview_file, get_preview_extension +from ..utils.file_utils import find_preview_file, get_preview_extension, calculate_sha256 from ..utils.metadata_manager import MetadataManager from ..utils.civitai_utils import resolve_license_info from .model_cache import ModelCache @@ -1067,6 +1067,19 @@ class ModelScanner: model_data = self._build_cache_entry(metadata, folder=normalized_folder) + # Compute SHA256 hash when metadata provided none (e.g., CivitAI API response has empty hashes) + if not model_data.get('sha256') and file_path: + try: + logger.info(f"Computing SHA256 hash for {file_path} (was empty from metadata)") + sha256 = await calculate_sha256(file_path) + if sha256: + model_data['sha256'] = sha256.lower() + if isinstance(metadata, BaseModelMetadata): + metadata.sha256 = sha256.lower() + await MetadataManager.save_metadata(file_path, metadata) + except Exception as e: + logger.error(f"Failed to compute SHA256 for {file_path}: {e}") + # Skip excluded models if model_data.get('exclude', False): excluded_models.append(model_data['file_path']) @@ -1476,6 +1489,15 @@ class ModelScanner: file_path_override=normalized_new_path, ) + # Ensure sha256 is populated even when metadata doesn't have it + if not cache_entry.get('sha256') and normalized_new_path and os.path.exists(normalized_new_path): + try: + sha256 = await calculate_sha256(normalized_new_path) + if sha256: + cache_entry['sha256'] = sha256.lower() + except Exception as e: + logger.error(f"Failed to compute SHA256 for {normalized_new_path}: {e}") + if recalculate_type: cache_entry = self.adjust_cached_entry(cache_entry)