feat(roms): filter games by matched metadata provider#3615
Open
Spinnich wants to merge 1 commit into
Open
Conversation
Adds a "Metadata provider" gallery filter so a library can be narrowed by which providers each ROM matched (IGDB, MobyGames, ScreenScraper, etc.), mirroring the existing multi-value filters (player count, age rating). Backend: - New `_filter_by_metadata_providers` keyed off each provider's id column on Rom, with any/all/none logic; wired through filter_roms, get_roms_scalar, the /roms endpoint, and the unscoped cache gate. - Smart collections apply the criterion via get_smart_collection_roms. - Unknown provider slugs are ignored (no-op) so stale bookmarks or hand-edited URLs don't error. Frontend (v1 + v2): - Shared METADATA_PROVIDER_OPTIONS registry; provider list is a fixed set rather than data-derived, so options are static. - Wired into the galleryFilter store, rom API service, request cache key, both filter drawers, v2 URL persistence, the v2 refetch watcher, and smart-collection serialization/summary. - Added the `platform.metadata-provider` key to all locales. Tests: - Backend handler, endpoint, and smart-collection coverage (any/all/none plus unknown-slug). - Frontend smartCollectionCriteria serialization/summary coverage. Also normalized collections_handler.py to LF (it was the only CRLF file in the backend, which tripped git-diff-check on the edited lines). AI assistance: implemented with Claude Code (Anthropic). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Resolves #3439. Adds a Metadata provider gallery filter so a library can be
narrowed by which providers each game matched (IGDB, MobyGames, ScreenScraper,
RetroAchievements, LaunchBox, Hasheous, Flashpoint, HowLongToBeat, ES-DE,
Libretro), mirroring the existing multi-value filters (Player count, Age rating)
with the same
any/all/nonelogic toggle.The filter is exposed everywhere the other multi-value filters already live:
the classic (v1) and v2 gallery filter drawers, bookmarkable URL state, the
request cache key, and smart-collection create/serialize/summary. Provider
values are slugs that line up 1:1 across the backend column map, the shared
frontend options registry, and the
MetadataSourceenum.Why static options? Unlike genres/age-ratings, the provider set is a fixed
enum, not derived from library content, so the drawer always offers all 10. This
is intentional and supports the curation use case in the issue (e.g. find games
with no IGDB match by selecting IGDB +
none).Files modified
Backend
backend/handler/database/roms_handler.py—METADATA_PROVIDER_COLUMNSslug→column map and_filter_by_metadata_providers(any=OR,all=AND,none=NOT-OR over each provider's id column); wired throughfilter_romsandget_roms_scalar. Unknown slugs are ignored.backend/endpoints/roms/__init__.py—metadata_providers+metadata_providers_logicquery params onGET /roms, passed tofilter_roms, and added to the unscoped-cache gate.backend/handler/database/collections_handler.py— smart collections apply the criterion viaget_smart_collection_roms. NOTE: this file was the only CRLF file in the backend; it has been normalized to LF, which is why its diff is large (it's almost entirely line-ending).backend/tests/handler/test_db_handler.py— handler filter coverage (any/all/none+ unknown-slug no-op).backend/tests/endpoints/roms/test_rom.py— endpoint coverage (filter +nonelogic).backend/tests/handler/database/test_collections_handler.py— smart-collection pass-through coverage.Frontend (shared)
frontend/src/utils/index.ts— sharedMETADATA_PROVIDER_OPTIONSregistry (slug + brand-name title) used by both UIs.frontend/src/stores/galleryFilter.ts—selectedMetadataProviders/metadataProvidersLogicstate, setters,isFiltered()/resetFilters().frontend/src/services/api/rom.ts—metadata_providersrequest params.frontend/src/services/cache/api.ts— provider selection folded into the request cache key (prevents stale-cache collisions).Frontend (v1 classic UI)
frontend/src/stores/roms.ts— passes the new filter togetRoms.frontend/src/components/Gallery/AppBar/common/FilterDrawer/Base.vue— new drawer row + URL read/write.Frontend (v2 UI)
frontend/src/v2/stores/galleryRoms.ts— passes the new filter togetRoms.frontend/src/v2/components/Gallery/FilterDrawer.vue— new multi-select section (slugs as values, brand names as titles) + logic toggle.frontend/src/v2/components/Gallery/GalleryShell.vue— added to the refetch watcher and active-filter count.frontend/src/v2/composables/useGalleryFilterUrl/index.ts—?metadataProviders=…&metadataProvidersLogic=…URL round-trip (v1↔v2 compatible).frontend/src/v2/utils/smartCollectionCriteria.ts— serialization + human-readable summary field.frontend/src/v2/components/Dialogs/CreateSmartCollectionDialog.vue— snapshot includes the new fields.frontend/src/v2/utils/smartCollectionCriteria.test.ts— new unit tests (serialization + summary).i18n
frontend/src/locales/*/platform.json(18 locales) —platform.metadata-providerkey (translated; parity check passes).Testing notes
-p no:randomlyfor deterministic ordering).vue-tsctypecheck clean.trunk fmt && trunk check: no issues.check_i18n_locales.py: all complete.any/all/nonelogic, the unknown-slug no-op, the endpoint, the smart-collection pass-through, and smart-collection serialization/summary.test_filter_by_search_term_*fail in a random-ordered run, it's pre-existing InnoDBMATCH...AGAINSTflakiness (passes deterministically and in isolation; unrelated to this change).Reviewer attention
metadataProviders.ts) — what users actually see next to a ROM — which excludestgdb/sgdband includeshltb/gamelist/libretro. The existing_filter_by_matchedtoggle uses a different 8-provider set (includestgdb, excludeshltb/gamelist/libretro). Please confirm aligning the filter with the chip registry (rather than the toggle) is the intended mapping.filter_values— all 10 providers always show even on platforms with zero matches for some.metadata_providersis now wired intoget_smart_collection_roms;player_countsremains a pre-existing gap there and was intentionally left out of scope.collections_handler.pyCRLF→LF: review with whitespace hidden (?w=1) — the logical change is just 2 added lines.RomFiltersDictis untouched); request params are built manually inrom.ts.AI assistance disclosure: this change was implemented with Claude Code (Anthropic), reviewed by the author.
Checklist