Skip to content

feat(desktop): identify Nexus mods by content and archive hash - #30

Merged
ShulhaOleh merged 9 commits into
mainfrom
feat/nexus-mod-identification
Jul 30, 2026
Merged

feat(desktop): identify Nexus mods by content and archive hash#30
ShulhaOleh merged 9 commits into
mainfrom
feat/nexus-mod-identification

Conversation

@ShulhaOleh

@ShulhaOleh ShulhaOleh commented Jul 30, 2026

Copy link
Copy Markdown
Member

Summary

Nexus Mods installs get automatic identification everywhere ModWorkshop already had it, closing the gap that made the Nexus mod counter, update checks, and thumbnails silently unavailable for a large share of installed mods:

  • Drag-and-drop archives: install_dropped_file now MD5-hashes the whole archive and checks it against Nexus's fileHash index at install time. A unique match installs the mod already identified (real name, version, author, thumbnail) instead of as "Unknown"; ambiguous or unmatched archives fall through to the existing unidentified-install path unchanged.
  • Already-installed unidentified mods: a new content-matching engine (modFileContents) matches a mod's on-disk filename+size (File-unit games) or folder name (Directory-unit games) against Nexus's published file listings. Runs automatically once per mod the first time it's discovered unidentified (staggered, yields to foreground activity, never on the get_installed hot path), and can be retried on demand from a mod's options menu ("Identify").
  • Site: the homepage's recognized-mod counter now also shows how many mods exist on Nexus for Modrex's supported games, as a separate claim from the ModWorkshop-hash-recognized count.

Two real bugs found and fixed via live testing against real downloaded mods:

  • install_dropped_file was naming every archive-wrapped drop after the outer downloaded file (Nexus's own download-manager filename scheme) instead of the mod's real internal name — this also fed garbage into the new content-matching queries. Fixed by recovering the real name from the archive's own pak entry / extracted folder name.
  • The content-matching query sent fileSize as a strict filter to Nexus alongside fileName. A mod's currently-published file is often a newer upload than what's installed locally, so an exact byte-size match silently rejected an otherwise-unique fileName match. fileSize is now only used to disambiguate client-side when fileName alone returns more than one candidate, never sent as a request filter.

Also adds nexusDomain to the shared @modrex/games registry (cross-checked against Rust's SOURCE_REGISTRY by check-sources.mjs) so the site can query Nexus without needing desktop's IPC.

Test plan

  • cargo test
  • pnpm test:renderer
  • cargo clippy
  • cargo fmt --check
  • pnpm typecheck, pnpm lint, pnpm format:check
  • check-commands, check-i18n, check-csp, check-sources
  • Regression-tested against two real Nexus downloads (PD3 mods 52 and 239) that initially failed to identify, both bugs above were found and fixed this way
  • Manual click-through of the "Identify" button and drag-drop flow in a running app.

Nexus's fileHash lookup keys on the MD5 of the whole published
archive, not the extracted-content SHA256 Modrex already computes.
Add compute_md5 mirroring compute_sha256's streaming pattern, and
add the md-5 crate.
Add identify_mod_via_nexus_content: a user-initiated command that
runs Step 5's content matcher against one installed, unidentified
mod. Skips mods already identified or already marked missed, so a
permanent miss (~25% of mods are never indexed) is asked at most
once. Adds InstalledMod.nexus_content_missed to persist that. Reuses
the existing rate limiter; never runs on the get_installed hot path.
install_dropped_file now tries Nexus identification automatically
when the drop is a real archive (not a bare loose .pak) for a
Nexus-capable game: MD5-hashes the whole archive, looks it up via
Nexus's fileHash index, and on a unique match installs the entry
already identified (real name, version, author, thumbnail) instead
of as unidentified. uid switches to Tier 1's own
'nexus:{mod_id}:{file_id}' scheme so a later nxm:// install of the
same file reconciles onto this entry instead of duplicating it.

Ambiguous, not-found, or any lookup failure falls straight through
to the existing unidentified-install path - this only ever adds an
identity, never blocks or fails an install.

Extract apply_nexus_archive_identity as a pure, tested function
mapping a confirmed Nexus match onto an InstalledMod, separate from
the async orchestration around it.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying modrex-site-monorepo-preview with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0081624
Status: ✅  Deploy successful!
Preview URL: https://a53ec3c0.modrex-site-monorepo-preview.pages.dev
Branch Preview URL: https://feat-nexus-mod-identificatio.modrex-site-monorepo-preview.pages.dev

View logs

@ShulhaOleh
ShulhaOleh merged commit e9f26df into main Jul 30, 2026
11 of 12 checks passed
@ShulhaOleh
ShulhaOleh deleted the feat/nexus-mod-identification branch July 30, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant