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).