Skip to content

feat: use PICO-8 built-in cover art from .p8.png cartridge files#3119

Merged
gantoine merged 6 commits intomasterfrom
copilot/use-pico-8-cover-art
Mar 12, 2026
Merged

feat: use PICO-8 built-in cover art from .p8.png cartridge files#3119
gantoine merged 6 commits intomasterfrom
copilot/use-pico-8-cover-art

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 11, 2026

PICO-8 .p8.png cartridges are valid PNG files where the image itself is the cartridge label. RomM was ignoring this and leaving PICO-8 games with no cover art unless manually set or matched from an external source.

Changes

  • handler/filesystem/roms_handler.py — Added get_pico8_cover_url() as a method on FSRomsHandler. It returns a file:// URL pointing to the ROM file itself when platform_slug == UPS.PICO and the filename ends with .p8.png. Path construction uses self.validate_path() from FSHandler (in filesystem/base_handler) to safely resolve the absolute path and prevent directory traversal. Called from scan_rom() via fs_rom_handler after all metadata sources are resolved, only when no url_cover or path_cover_s already exists (manual/metadata-sourced covers are preserved).
def get_pico8_cover_url(self, platform_slug: str, fs_name: str, fs_path: str) -> str | None:
    if platform_slug == UPS.PICO and fs_name.endswith(PICO8_CARTRIDGE_EXTENSION):
        rom_path = self.validate_path(f"{fs_path}/{fs_name}")
        return f"file://{rom_path}"
    return None

The existing file:// URL handling in resources_handler._store_cover() already copies local files into the resources directory — no changes needed there.

  • tests/endpoints/sockets/test_scan.py — Added TestGetPico8CoverUrl covering: .p8.png on PICO platform (positive), plain .p8 text cartridge (no image), wrong platform, unrelated extension.
Original prompt

This section details on the original issue you should resolve

<issue_title>[Feature] Use pico-8s built in cover art</issue_title>
<issue_description>Is your feature request related to a problem? Please describe.
Pico-8 uses png format for the game data which stores a cover image as well.[...]

Describe the solution you'd like
Itd be cool to be able to have RomM use that for the art of the game. Attached is a visual example of one of the covers from a random file. Im not including the game itself but rather just a screenshot of the art to avoid any issues.

Describe alternatives you've considered
Manually setting the art.

Additional context

Image</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Add feature to use Pico-8 built-in cover art feat: use PICO-8 built-in cover art from .p8.png cartridge files Mar 11, 2026
@gantoine gantoine marked this pull request as ready for review March 11, 2026 23:02
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 11, 2026

Test Results (postgresql)

990 tests  +6   989 ✅ +6   2m 35s ⏱️ -11s
  1 suites ±0     1 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 744d92d. ± Comparison against base commit 6f02a4b.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 11, 2026

Test Results (mariadb)

990 tests  +6   989 ✅ +6   2m 31s ⏱️ -1s
  1 suites ±0     1 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 744d92d. ± Comparison against base commit 6f02a4b.

♻️ This comment has been updated with latest results.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 11, 2026

Greptile Summary

This PR enables RomM to use the embedded artwork from PICO-8 .p8.png cartridge files as cover art by adding FSRomsHandler.get_pico8_cover_url() and wiring it into scan_rom after all metadata sources have been queried. The approach correctly re-uses the existing file:// URL pipeline in resources_handler._store_cover, keeping the change small and consistent with the gamelist handler precedent.

Key points:

  • get_pico8_cover_url uses .lower() before endswith to handle mixed-case filenames and delegates to validate_path for path-traversal protection.
  • The scan_rom insertion point (after both cover-preservation blocks) correctly skips the PICO-8 path when any prior cover is already present for UPDATE/UNMATCHED scan types.
  • Two previously-flagged issues remain unresolved in this revision: an unhandled ValueError propagated from validate_path (which would abort the entire scan_rom coroutine for that ROM), and a COMPLETE-rescan scenario where a manually-uploaded cover can be overwritten because path_cover_s is never copied into rom_attrs for ScanType.COMPLETE.
  • The test suite covers the get_pico8_cover_url method in isolation but lacks an integration test for the scan_rom conditional path, and includes one redundant test case (test_url_starts_with_file_scheme).

Confidence Score: 3/5

  • Safe to merge for new PICO-8 ROMs, but two previously-flagged regressions (ValueError propagation, COMPLETE-rescan cover overwrite) remain open.
  • The happy path is implemented correctly and consistently with the existing codebase patterns. The case-insensitivity fix and symlink-safe test assertion from earlier review rounds are both present. However, two previously-reported logic issues — the unhandled ValueError from validate_path that can abort scan_rom, and the COMPLETE-rescan scenario that silently overwrites a manually-uploaded cover — were explicitly called out with requested fixes but have not been addressed in this revision. These lower confidence from an otherwise clean implementation.
  • backend/handler/scan_handler.py lines 768-776 — the two unresolved issues from prior review threads both manifest here.

Important Files Changed

Filename Overview
backend/handler/filesystem/roms_handler.py Adds get_pico8_cover_url method and PICO8_CARTRIDGE_EXTENSION constant; case-insensitive .lower() check is correctly applied; validate_path provides path-traversal protection; no new issues found in this file itself.
backend/handler/scan_handler.py PICO-8 block inserted after cover-preservation guards; correctly skips when url_cover or path_cover_s are set via non-COMPLETE scan paths; however, previously-flagged issues (unhandled ValueError from validate_path, manual cover overwritten during COMPLETE rescan) remain unresolved in this revision.
backend/tests/endpoints/sockets/test_scan.py Six unit tests added for get_pico8_cover_url; symlink-safe expected URL uses Path(...).resolve() (previous review issue addressed); test_url_starts_with_file_scheme is redundant; no integration test for the scan_handler conditional path.

Sequence Diagram

sequenceDiagram
    participant SC as scan.py (_identify_rom)
    participant SH as scan_handler (scan_rom)
    participant FS as FSRomsHandler.get_pico8_cover_url
    participant VP as FSHandler.validate_path
    participant RH as resources_handler._store_cover

    SC->>SH: scan_rom(platform, rom, fs_rom, ...)
    SH->>SH: Populate rom_attrs (fs_name, fs_path, ...)
    SH->>SH: Fetch metadata from all sources
    SH->>SH: Apply UPDATE/UNMATCHED cover preservation block
    alt no url_cover AND no path_cover_s in rom_attrs
        SH->>FS: get_pico8_cover_url(platform.slug, fs_name, fs_path)
        alt platform == "pico" AND fs_name.lower().endswith(".p8.png")
            FS->>VP: validate_path("{fs_path}/{fs_name}")
            VP-->>FS: resolved Path (or raises ValueError)
            FS-->>SH: "file:///library/.../game.p8.png"
        else
            FS-->>SH: None
        end
        SH->>SH: rom_attrs["url_cover"] = pico8_url
    end
    SH-->>SC: Rom (with url_cover set)
    SC->>RH: _store_cover(rom, url_cover, SMALL/LARGE)
    RH->>RH: Strip "file://", AnyioPath.exists()
    RH->>RH: copy_file(rom_path → resources/cover/s.png)
    RH->>RH: PIL resize for SMALL cover
Loading

Last reviewed commit: 744d92d

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 12, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
14242 9630 68% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
backend/handler/filesystem/roms_handler.py 79% 🟢
backend/handler/scan_handler.py 58% 🟢
TOTAL 68% 🟢

updated for commit: 744d92d by action🐍

@gantoine gantoine merged commit fcfb74a into master Mar 12, 2026
11 checks passed
@gantoine gantoine deleted the copilot/use-pico-8-cover-art branch March 12, 2026 01:22
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.

[Feature] Use pico-8s built in cover art

2 participants