The URL parser previously required the hostname to contain "civitai.com",
so CivitAI download links using the "civitai.red" domain were treated as
non-CivitAI URLs and rejected.
This extracts the host check into _is_civitai_host() and accepts both
"civitai.com" and "civitai.red" base domains, so resolve/parse flows
handle all CivitAI download links correctly.
Previously, identify_missing_models grouped missing entries only by filename,
which could merge unrelated models from different categories that happen to
share a filename. This change deduplicates by (category, filename) and tracks
all_node_refs with a reference_count so the frontend can preserve one
resolution per node reference instead of collapsing duplicates.
Frontend changes in resolve_download_methods.js iterate over all_node_refs,
and missing_browser_methods.js now shows '+ N refs' in the missing-model
label and clarifies the locate tooltip when multiple workflow references
share the same missing model.
- Merge GET and POST aria2 status handlers into one route
- Remove redundant calculate_file_sha256 wrapper and use path_utils directly
- Remove redundant _normalize_archive_image, _normalize_filename, and _similarity wrappers
- Replace urllib with requests for remote JSON fetching in model_list
- Update metadata timestamps
Add an early guard in core/sources/civitai.py to return None for non-string or empty URL inputs before calling urlparse. This prevents exceptions and unexpected behavior when callers pass None or empty values, making the parser more robust.
Replace duplicated filename-to-query logic with a single
\uild_filename_search_queries\ helper in matcher/civarchive/huggingface,
standardize Civitai URL generation in the frontend via \getCivitaiModelUrl\,
unify browser user-agent and response file-size extraction in the downloader
path, and derive workflow node-type category hints from widget categories
rather than maintaining a large static mapping.
Replace duplicated SHA256 normalization, metadata sidecar discovery, trained-words
extraction, type coercion, and cache helpers into shared modules. Clarify that the
_civitai.py/_civarchive.py/_huggingface.py/_workflow_analyzer.py refactorings are
behavior-preserving so future contributors keep behavior aligned in one place.
- Move URL model-file validation logic to type_utils.looks_like_model_file and use it from __init__.py, civarchive
- Extract remote file-size probing into type_utils.fetch_remote_file_size and replace duplicated HEAD+Range logic in civarchive and huggingface
- Extract image normalization into type_utils.normalize_model_image, replacing duplicated CivitAI/CivArchive image mapping in civarchive and civitai
- Drop redundant local wrapper functions (_as_dict, _as_list, _version_sort_key, _select_primary_model_file, _extract_primary_file, _read_json_file, _write_json_file_atomic, _get_sha256_hash, _extract_civitai_image_id, _build_civitai_image_url) in favor of existing shared implementations
- Use path_utils.read_json_safe and write_json_atomic directly in model_list
- Add clear_all_search_caches() in core/sources/__init__.py and replace 4
individual cache-clearing call sites in __init__.py with the new helper.
- Add shared parse_civitai_model_path() in core/type_utils.py and use it
from both CivitAI and CivArchive URL parsers to remove duplicated regex logic.
- Rename parse_huggingface_url() to get_huggingface_repo_and_file_from_url()
in core/resolver.py for clarity.
- Add stripModelExtension() and hasModelExtension() utilities (with a single
MODEL_EXTENSIONS_REGEX) in web/resolver/utils/render_format_methods.js
and replace repeated inline regex patterns across search_panel.js,
model_info_methods.js, tabs_loaded_methods.js, and queue_methods.js.
- Introduce get_filename_from_path in path_utils and replace repeated
os.path.basename calls across core/downloader.py, core/resolver.py,
core/sources/civarchive.py, core/sources/civitai.py, and
core/sources/huggingface.py
- Move duplicated inline HTTP response size helpers (_response_file_size,
_parse_size_header, _parse_content_range_size) into core/type_utils.py
and update civarchive.py and huggingface.py to import them
- Remove inline normalize_sha256_value from __init__.py and reuse the
existing normalize_sha256 helper
- Refactor options_methods.js localStorage read/write logic into a
SETTINGS_MAP-driven loop to reduce repetition
Extract MODEL_EXTENSIONS and format_size_bytes into core/type_utils, removing duplicates from workflow_analyzer and downloader. Add getFilenameFromPath to render_format_methods and replace inline path-splitting logic across JS resolver actions, search, and views.
Implement end-to-end hash comparison for local models and local matches.
Backend:
- Add /model_resolver/local-model-hashes API endpoint
- Add get_local_model_hash_metadata() to read sidecar SHA256 metadata
Frontend:
- Add Compare Hashes context menu item and CSS
- Pass missing_key/missing_search_key through resolveDownloadMethods
- Enhance local match rendering with hash status and context data
- Add hash normalization, formatting, and candidate collection helpers
- Wire compareLocalModelHashesWithCurrentFinding action
Also update HuggingFace author index metadata.
ComfyUI may set __name__ to hybrid OS-path values (e.g. 'E:\\...\\comfyui-model-resolver.core.sources.model_list'), which broke the existing split-by-dot logic.
This adds a pre-normalization step that converts path separators to dots, strips drive letters and .py extensions, so _normalize_module_name reliably falls back to DEFAULT_MODULE for unknown path-derived values rather than miscounting segments.
- Add FATAL (50) to LogLevel enum, LEVEL_MAP, and LEVEL_THEME (bright red #E74C3C)
- Drop legacy COLORS dict in favor of LEVEL_THEME RGB values + ANSI_RESET
- Replace hard-coded stacklevel=4 with _INTERNAL_FRAMES constant so caller
location is always correct regardless of call-chain depth
- Simplify _normalize_module_name by removing redundant path normalization
- Add fatal() to ModuleLogger, AzLogsLogger, and module-level API
- Lazily init _log in path_utils via _get_log() to avoid circular imports
- Drop manual log_debug/info/warn/error/exception stubs from core/log_system/log_funcs.py
- Remove stale re-exports of create_module_logger/logger from core/__init__.py
- Add core/log_system/__init__.py as the single public entry point for the log system
- Update huggingface-author-index metadata
Replace global log_* wrapper functions with create_module_logger(__name__)
instances across the codebase, enabling proper module-level logger
namespacing. Simplifies core/log_system/log_funcs.py by removing legacy
_normalize_module_path and cleaning up _normalize_module_name. Bumps
log_system config to 2.0.0 and introduces PROJECT_ALIASES for cleaner
log module prefix stripping.
- Add /aria2/start and /aria2/stop API endpoints for explicit daemon lifecycle control
- Track aria2 daemon state (managed/running/version/active_transfers) in get_aria2_status
- Implement idle auto-stop timer (5 minutes) with aria2_auto_stop_daemon setting
- Add start_aria2_daemon() and stop_aria2_daemon() helpers in core/downloader.py
- Migrate legacy release-* install directories to normalized versioned paths
- Normalize aria2 version strings (strip release-/v prefixes) in installer metadata
- Update aria2 archive extraction to extract-to-temp then copy into canonical dir
- Add frontend daemon controls: status display, stop button, auto-stop toggle
- New core/aria2_installer.py module downloads the latest aria2c release
from GitHub for Windows, macOS, and Linux with safe path extraction.
- New POST /model_resolver/aria2/install endpoint triggers installation
and saves the resolved aria2c_path plus download_backend=aria2.
- Options UI adds an Install aria2 button, hides aria2-specific fields
when another backend is selected, and updates status on completion.
- Includes .gitignore entry for tools/aria2/ so installed binaries are
not committed.
- Extend dynamic widget category hints to capture choice source (static/hybrid/folder_paths)
- Infer workflow schema model candidates from output category hints when widget values match known presets
- Surface auto_download_capable and auto_download_candidate flags in missing model data
- Merge these flags on duplicate missing model entries
- Add cloud-download badge UI with tooltip explaining auto-download context
- Update huggingface author index metadata timestamp
- Add __init__.py: support civitai.red domain and session token cookies
- Add core/downloader.py: build_download_headers for consistent User-Agent,
Accept, and CivitAI-specific Referer/Origin headers across download backends
- Resolve CivitAI API redirects before handing URLs to aria2
- Strip sensitive URL parameters from download logs
- Forward civitai_session_token from the frontend to the downloader
Integrates aria2c as an alternative download backend alongside the built-in
Python downloader. Adds settings for selecting the backend and configuring
the aria2c executable path, plus a status check button in the options panel.
Backend changes:
- core/downloader.py: aria2 daemon lifecycle, JSON-RPC client, pause/resume
state machine, and transfer tracking
- core/settings.py: download_backend normalization and aria2c_path setting
- __init__.py: new API routes for pause, resume, and aria2 status checks
Frontend changes:
- options_methods.js: backend selector, aria2c path input, check button,
and local storage persistence
- resolve_download_methods.js: pause/resume handlers, pending status
transitions, and progress rendering for aria2 downloads
- queue_methods.js: queue panel pause/resume buttons, backend badge, and
debounced panel updates
- search_panel.js: actionsHtml support for composite action buttons
- Expand preferred categories to include clip_vision, ipadapter, sams, ultralytics
- Add clip_gguf alias for text_encoders in both backend and frontend
- Add explicit diffusion_models/text_encoders mappings in CATEGORY_MAP
- Refactor get_model_roots to skip custom_nodes/configs, use template key
aliases, accept new folder keys from known categories, and normalize
ultralytics paths (yolo/bbox, yolo/segm, yolo -> parent)
- Pass missing object through resolve_download_methods and search_panel
so category selection can use widget hints
- Refactor frontend download target resolution:
- getMissingSupportedDownloadCategories respects widget/type hints
- getNodeTypeDownloadCategory splits exact-node map and adds
normalizeNodeCategoryToken / getNodeTypeDownloadCategoryFromTokens
for GGUF and future node families
- getSourceResultDownloadCategory and _sourceSupportLevel accept
missing for unified logic
- Prioritize dynamic widget category hints in workflow analyzer and
include category_hints/folder_key_hints on all model refs
- Add folder count badges and path normalization in missing browser
(normalizeMissingFolderRootPath handles category suffixes / bbox/segm)
Replace CivitAI-only search with a multi-source metadata resolution route using
SHA256 exact-match validation, dead-link filtering, and live download URL
probing. Unify sidecar metadata saving across all remote sources. Add
force-refresh support, local metadata import with preview detection, and
frontend source-aware UI controls.