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.
- 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.
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.
- 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.
- Add local_only endpoint mode: returns basic file info (filename, size, path,
location, sha256) without querying CivitAI or computing file hashes
- Validate provided sha256/hash inputs (must be 64-char hex) and fall back to
empty string when invalid
- Refactor monolithic info response builder into build_info_response() helper
used across all result paths (local, CivitAI success, CivitAI fallback,
not-found), reducing duplication
- Add get_model_info_for_file(local_only=True) early return in CivitAI source
that builds a minimal local-only result without hash lookup
- Split frontend fetchModelInfoForDialog into:
- fetchLocalModelInfoForDialog: opens dialog with local data immediately,
marks civitai_checked=false
- fetchCivitaiModelInfoForDialog: async CivitAI lookup triggered by user
- Add 'Fetch with CivitAI' button in info dialog when local file exists but
CivitAI has not been checked yet
- Infer model_type from category in both backend and frontend to reduce
reliance on upstream data shape
- Fix sidecar metadata condition (was skipping save when path already existed)
- Add cursor/disabled styles for info dialog CivitAI link button
Add a /model_resolver/search-cancel/{progress_id} endpoint with a
SearchCancelled exception so in-flight source searches abort cleanly on
batch cancel. Track sourceProgressIds alongside sourceControllers so the
frontend can cancel backend progress polls. Rework CivArchive extraction
with robust __NEXT_DATA__ parsing, hash-page file resolution, model-link
scraping, confidence-based candidate filtering, and expanded type maps.
Add conftest.py for pytest path setup, update .gitignore for scratch/,
and refresh huggingface-author-index.json.
- Add get_comfy_root_path() to core/path_utils.py and use it in __init__.py and core/downloader.py instead of inline logic
- Add select_primary_model_file(), parse_size_to_bytes(), get_version_sort_key(), and check_credential_http() to core/type_utils.py
- Replace duplicated credential-check helpers in civitai.py, huggingface.py with check_credential_http()
- Replace duplicated size parsing and version sorting in civarchive.py, civitai.py with shared utilities
- Replace duplicated primary-file selection in civarchive.py, civitai.py, lora_manager_archive.py with select_primary_model_file()
- Replace inline tempfile-based JSON writes in popular.py with write_json_atomic()
- Remove dead reload_model_list() from model_list.py
- Fix workflow_analyzer.py hint prioritization for diffusion_models vs specific output hints
- Add first_non_empty() and to_int() to core/type_utils.py
- Add get_filename_from_path() and METADATA_DIR to core/path_utils.py
- Replace inline implementations across resolver, downloader, and sources
with calls to the shared utilities
- Move strip_known_model_extension from resolver to matcher
- Refactor __init__.py: extract run_source_search and execute_search_with_fallback
helpers to eliminate duplicated progress-tracking, logging, and error-handling
patterns across local, HuggingFace, CivitAI, CivArchive, and LoRA archive
source search tasks; also fix URN variable shadowing in CivitAI/CivArchive
- Update metadata/huggingface-author-index.json with refreshed Comfy-Org
author index (new repos and model entries)
Extract repeated path normalization and identity logic from __init__.py,
core/resolver.py, core/downloader.py, and core/scanner.py into a shared
core/path_utils module. Also add a loading state to the local model picker
so it waits for models to load before rendering options.
Add early-return optimizations so both backend and frontend avoid unnecessary
URL extraction and disk scanning when a workflow has no nodes or contains
no potential model references.
Also tighten API input validation by rejecting non-object workflow_json.
Frontend now polls a new backend endpoint (/model_resolver/search-progress/{progress_id})
to display real-time, per-source progress messages and percentages during model searches,
replacing static 'Searching...' indicators with granular status updates.
When a model search returns no results for a specific base_model, retry the
same query with base_model_context=None so the provider can match any model.
Fallback matches are marked with any_model_match and base_model_fallback on
the result payload. The UI reports 'Found (Any Model)' when a result came
from this fallback path, and the cancel/progress button styling is tightened
to 16x16px with border-radius.
- Add force_rescan end-to-end so callers can bypass the short-lived local model scan cache: backend entry in __init__.py and core/resolver.py, lifecycle_graph_methods forwards it through the workflow analysis body, and download_target_methods passes ?force=1 from the refresh flow.
- Rewrite combo dropdown lifecycle in missing_browser_methods with show/hide helpers, pointer-capture tracking, and a capture-phase outside-click listener so the list stays open during drag/hover and closes reliably otherwise.
- Animate refresh buttons (CSS keyframes + JS Web Animations) with reduced-motion fallback.
- Encode selected model path into the selected-bar data-model attribute and wire contextmenu so users can open the containing folder from the selection.
- Fix XSS risk in selected-bar label by escaping label HTML; change queue/selected Remove buttons to danger style.
- Increase max missing-browser model column width clamp from 430 to 820 and stop truncating missing-filename display; show full filename with tooltip instead.
- Update huggingface-author-index.json metadata timestamp/counts (1 file changed, 1 line).
Add support for additional ComfyUI model types including diffusers, gligen,
style models (latent/regular upscale), audio encoders, background removal,
frame interpolation, geometry estimation, detection, model patches/photomaker,
and optical flow models.
Backend changes:
- Extend CATEGORY_MAP, URN_TYPE_MAP, and node type hints in workflow analyzer
to cover dozens of new loader node types and singular/plural aliases.
- Add MODEL_OUTPUT_TYPE_TO_CATEGORY and get_node_output_category_hint() so
loader output types can contribute category hints.
- Make widget name matching normalize underscores, hyphens, and spaces.
- Improve directory discovery to enumerate folders from folder_paths while
filtering unsupported categories.
- Include folders as model entries in directory scanning (with a diffusers
guard requiring model_index.json).
Frontend changes:
- Update download target category maps, display names, token name maps, and
per-node widget index lists to match the expanded backend coverage.
Implements a new download path configuration UI and backend logic:
- Add Subfolder fill mode: Suggested (existing), Template, Manual
- Add Base Model Path Mappings to override detected base-model folders
- Add Default Root settings to control root directory per category
- Add Detect From Existing Folders button that infers templates and mappings from local model folders
- Add backend /model_resolver/root-directories and /model_resolver/path-template-suggestions routes
- Refactor resolver settings into core/settings.py for shared frontend/backend use
- Extract path template inference logic into core/path_templates.py
- Update download panel, context menu, and loading flow to use new path settings
- Add frontend_logs_enabled/frontend_log_level and backend_logs_enabled/backend_log_level
toggles and selectors in the Options panel (web/resolver/views/options_methods.js)
- Sync frontend logging settings from localStorage / server settings into the
frontend logger on startup and settings load (download_target_methods.js)
- Apply backend logging settings from server settings in the Python backend
(__init__.py), loading control state on startup and after saves
- Make frontend Logger resilient to stored configs that lack an 'enabled' flag
and to legacy/invalid moduleSettings levels (logger.js)
- Guard default module logger level initialization against undefined settings
(log_funcs.js)
- Replace scattered console.log/usages with module-level log.debug calls across
resolve_download_methods.js, model_resolver.js, and workflow_state_methods.js
- Bump log system package version to 1.5.6 (core + web)
Pass available_models through to the workflow analyzer, enabling
case-sensitive relative path lookups against scanned model data.
Normalize paths for comparison while preserving letter casing.
Skip irrelevant categories (custom_nodes, configs) upfront.
Fall back gracefully when no scanner data is available.
Also ignore the tests/ directory in .gitignore.
- Replace CivitAI-specific subfolder suggestion with broadened logic that derives candidates from model metadata, filename patterns, and existing folder structure
- Add getSuggestedModelSubfolderCandidates / getSuggestedExistingSubfolderByModelName helpers
- Normalize download category consistently via normalize_download_category in backend and frontend
- Backend now walks actual ComfyUI folder paths dynamically instead of hardcoded category mapping
- Rename frontend methods to applySuggestedDownloadSubfolder / forceSuggestedDownloadSubfolder
- Update Auto-fill subfolder tooltip to reflect expanded scope across all model categories
Add a shared normalize_download_category helper (with CATEGORY_MAP) in Python
and use it in get_download_directory to prefer redirected paths and to rank
diffusion_models above legacy unet folders. Mirror the same normalization in
the JS downloadTargetMethods, applying it consistently when coalescing
downloadDirectories, building dropdown keys, and reading/writing selections.
Also fix display labels to use 'diffusion_models' instead of 'unet'.