diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3b11859ce..ec8acd79c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,7 +2,7 @@ **Description** -Explain the changes or enhancements you are proposing with this pull request. +Explain the changes or enhancements you are proposing with this pull request. **Checklist** Please check all that apply. @@ -12,4 +12,4 @@ - [ ] I've assigned reviewers for this PR - [ ] I've added unit tests that cover the changes -#### Screenshots +#### Screenshots (if applicable) diff --git a/backend/endpoints/rom.py b/backend/endpoints/rom.py index 23190caf9..84dda0c8d 100644 --- a/backend/endpoints/rom.py +++ b/backend/endpoints/rom.py @@ -448,6 +448,78 @@ async def download_roms( ) +@protected_route( + router.get, + "/by-metadata-provider", + [] if DISABLE_DOWNLOAD_ENDPOINT_AUTH else [Scope.ROMS_READ], + responses={status.HTTP_404_NOT_FOUND: {}}, +) +def get_rom_by_metadata( + request: Request, + igdb: Annotated[int | None, Query(description="IGDB ID to search by")] = None, + moby: Annotated[int | None, Query(description="MobyGames ID to search by")] = None, + ss: Annotated[ + int | None, Query(description="ScreenScraper ID to search by") + ] = None, + ra: Annotated[ + int | None, Query(description="RetroAchievements ID to search by") + ] = None, + launchbox: Annotated[ + int | None, Query(description="LaunchBox ID to search by") + ] = None, + hasheous: Annotated[ + int | None, Query(description="Hasheous ID to search by") + ] = None, + tgdb: Annotated[int | None, Query(description="TGDB ID to search by")] = None, + flashpoint: Annotated[ + str | None, Query(description="Flashpoint ID to search by") + ] = None, + hltb: Annotated[int | None, Query(description="HLTB ID to search by")] = None, +) -> DetailedRomSchema: + """Retrieve a rom by metadata ID.""" + + rom = db_rom_handler.get_rom_by_metadata_id( + igdb=igdb, + moby=moby, + ss=ss, + ra=ra, + launchbox=launchbox, + hasheous=hasheous, + tgdb=tgdb, + flashpoint=flashpoint, + hltb=hltb, + ) + + if not rom: + provided_ids = { + "igdb_id": igdb, + "moby_id": moby, + "ss_id": ss, + "ra_id": ra, + "launchbox_id": launchbox, + "hasheous_id": hasheous, + "tgdb_id": tgdb, + "flashpoint_id": flashpoint, + "hltb_id": hltb, + } + metadata_info = [ + f"{key}={value}" for key, value in provided_ids.items() if value is not None + ] + + if not metadata_info: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="At least one metadata ID must be provided", + ) + + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"ROM not found with metadata: {', '.join(metadata_info)}", + ) + + return DetailedRomSchema.from_orm_with_request(rom, request) + + @protected_route( router.get, "/{id}", @@ -938,7 +1010,7 @@ async def update_rom( path_manual = await fs_resource_handler.get_manual( rom=rom, overwrite=True, - url_manual=url_manual, + url_manual=str(url_manual) if url_manual else None, ) cleaned_data.update( { diff --git a/backend/handler/database/roms_handler.py b/backend/handler/database/roms_handler.py index 32a79e8a7..c972e04cf 100644 --- a/backend/handler/database/roms_handler.py +++ b/backend/handler/database/roms_handler.py @@ -977,3 +977,44 @@ class DBRomsHandler(DBBaseHandler): ) ) return result.rowcount > 0 + + @begin_session + @with_details + def get_rom_by_metadata_id( + self, + igdb: int | None = None, + moby: int | None = None, + ss: int | None = None, + ra: int | None = None, + launchbox: int | None = None, + hasheous: int | None = None, + tgdb: int | None = None, + flashpoint: str | None = None, + hltb: int | None = None, + *, + query: Query = None, + session: Session = None, + ) -> Rom | None: + """Get a ROM by any metadata ID.""" + filters = [] + param_map = [ + (igdb, Rom.igdb_id), + (moby, Rom.moby_id), + (ss, Rom.ss_id), + (ra, Rom.ra_id), + (launchbox, Rom.launchbox_id), + (hasheous, Rom.hasheous_id), + (tgdb, Rom.tgdb_id), + (flashpoint, Rom.flashpoint_id), + (hltb, Rom.hltb_id), + ] + + for value, column in param_map: + if value is not None: + filters.append(column == value) + + if not filters: + return None + + # Use OR to find ROM matching any of the provided metadata IDs + return session.scalar(query.filter(or_(*filters)).limit(1)) diff --git a/frontend/src/components/common/Game/Card/Related.vue b/frontend/src/components/common/Game/Card/Related.vue index e52ff91b1..cc189edb5 100644 --- a/frontend/src/components/common/Game/Card/Related.vue +++ b/frontend/src/components/common/Game/Card/Related.vue @@ -1,6 +1,7 @@