CivitAI image API returns modelVersionIds at the root level of the
response (not inside meta), containing ALL model version IDs across
all resources (checkpoint + LoRAs). Two bugs prevented LoRAs from
being discovered:
1. _download_remote_media only extracted the first modelVersionId for
enrichment, dropping the rest.
2. CivitAI API meta parsing only ran as an EXIF fallback, but most
images have embedded EXIF metadata (prompt, steps, etc.), so the
fallback was never triggered.
3. When civitai_meta_raw itself has a nested 'meta' key, unwrapping
it stripped the injected modelVersionIds.
Also fixed gen_params merge: API gen_params now overlays EXIF at the
field level instead of full replacement, preserving EXIF-only fields
like detailed generation parameters.
The method mark_not_downloaded() was misleading — it doesn't negate
'downloaded' history (the model was indeed downloaded before), but
rather sets is_deleted_override = 1 to indicate the version was
downloaded and subsequently deleted. This flag allows re-download when
the 'skip previously downloaded' setting is enabled.
Rename to mark_as_deleted() to accurately reflect its semantics.
The main Refresh button and Quick Refresh dropdown item both called refreshModels(false). Split button dropdowns should only contain alternative actions (Hick's Law). Dropdown now has only Rebuild Cache (fullRebuild=true). Removed from 2 templates, 2 JS files, 1 test fixture, and 10 locale files.
Commit 454210a4 replaced renderFunction() with widget.value setter +
widget.callback() in endDrag, so the test assertion should verify
callback invocation instead of the removed renderSpy call.
Detects when multiple model files share the same basename (causing
ambiguity in LoRA resolution), logs warnings during scanning, and
provides a "Resolve Conflicts" button in the Doctor panel. Resolution
renames duplicates with hash-prefixed unique filenames, migrates all
sidecar and preview files, and updates the cache and frontend scroller
in-place so the model modal immediately reflects the new filename.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
_split _get_records_bulk into 500-id batches so the WHERE IN clause
never exceeds SQLite's 999-parameter ceiling.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>