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 POST /model_resolver/local-matches-by-hash backend endpoint
- expand local hash lookup sources to lora_manager_archive, popular, and model_list
- deduplicate backend hash matches by SHA256 value instead of source-hash tuple
- add frontend sync for remote hash matches and hash-label disambiguation
- propagate sha256, file_info, selected_file, and selected_version in model selection/download flows
- render local match status with consistent hash labels across search panel and resolvers
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.
- Add getHashCompareSourceLabel to normalize source display names
- Add getHashCompareResultName and getHashCompareResultUrl helpers
- Collect and dedupe hash compare matches instead of returning boolean
- Show success notification listing matched sources when local model hash matches online results
Replace duplicated inline drag handlers in queue_methods.js and
missing_browser_methods.js with a new startSplitterDrag() helper in
web/resolver/utils/splitter_drag.js.
The utility centralizes pointer/mouse event binding, RAF throttling,
and touch-cancellation cleanup, cutting net code across the two
callers while preserving existing behaviour (bounds, edge-open
threshold, collapse preview, and settle/cleanup timing).
- Introduce JobProgressTracker in __init__.py to consolidate the duplicated
thread-safe progress/cancellation state and cleanup logic previously
implemented separately for search and hash jobs.
- Extract shared pollHashCalculation method in model_info_methods.js to
centralize hash polling, abort checking, and error handling across all
call sites.
- Use getMissingModelKey in search_panel.js to eliminate inline key
construction duplication.
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.
Avoid full list re-render on row selection by passing selectionOnly flag
to displayMissingModels, which now selectively updates row classes and
detail pane instead of rebuilding the entire DOM. Also removed an eager
ensureLocalModelsThenPopulate('') call on combo list presence, and added
a click listener alongside focus so the combo list reliably populates on
both interaction types.