Online Cover Art¶
5DO can resolve cover art from a local folder and from an optional online catalog. The online service is hosted separately from the application bundles on Cloudflare R2 and is entirely optional. Local covers keep working when the network is unavailable.
Current pack: 2026.11.07 - 473 unique covers - 645 / 653 4DO game IDs mapped - 25.4 MiB of WebP images - 26.7 MiB bulk ZIP.
1. Source collection¶
The source collection in References/Screenshots contains 1,356 PNG files (about 543 MB). Many files are byte-identical duplicates saved under Redump and No-Intro names. The packager collapses them by SHA-256:
| Metric | Value |
|---|---|
| Source files | 1,356 |
| Unique images | 473 |
| Unique source bytes | 543 MiB |
| Encoded WebP q85 | 25.4 MiB |
| Bulk ZIP | 26.7 MiB |
| Mapped 4DO game IDs | 645 / 653 |
| Unmapped game IDs | 8 (homebrew/emulators with no cover) |
| Weak mappings reviewed | 5 |
| Manual overrides | 9 |
All 1,356 original names are preserved as catalog aliases, so a user file named with either the Redump or No-Intro convention resolves to the same image.
2. R2 layout¶
The catalog base URL is:
The bucket is public-read and uses a Cloudflare custom domain. No Worker is required.
/v1/catalog.json application/json, max-age=300
/v1/images/<sha256>.webp image/webp, max-age=31536000, immutable
/v1/packs/covers-v1.zip application/zip, max-age=31536000, immutable
/v1/SHA256SUMS.txt text/plain, max-age=300
/v1/report.json maintainer report, max-age=300
Image names are content hashes. A new pack must keep old hashed images available so clients with a stale catalog keep working. Only add new objects; do not delete the previous pack's images immediately.
catalog.json contains a packSha256 for the bulk ZIP. Each image is verified against its SHA-256 before it is moved into the cache.
3. Catalog schema¶
{
"schemaVersion": 1,
"packVersion": "2026.11.07",
"generatedUtc": "2026-11-07T11:52:14Z",
"noticeUrl": "https://github.com/purelogiccode/5DO",
"imagesBase": "images/",
"packFile": "packs/covers-v1.zip",
"packSize": 28044790,
"packSha256": "fa85d7fc7bacab32cffb5e9f54fb243d0c1c70810d812131c9538c5f228cd215",
"covers": [
{
"id": "7257a1b42aa0f0a4d7453c34e193db6fe4df1eaf7d53b0a2ff6bbcfdbfbbdd93",
"file": "7257a1b42aa0f0a4d7453c34e193db6fe4df1eaf7d53b0a2ff6bbcfdbfbbdd93.webp",
"name": "20th Century Video Almanac",
"aliases": [
"20th Century Video Almanac (1993)(Software Toolworks)(US)[!]",
"20th Century Video Almanac (USA)"
],
"gameIds": ["3F72700D"],
"width": 288,
"height": 600,
"size": 59382,
"regions": ["US"],
"year": "1993",
"rank": 0
}
]
}
idis the SHA-256 of the encoded WebP bytes.filemust be a bare file name whose stem equalsid; directory traversal is rejected.gameIdsare precomputed 4DO IDs. A known disc uses an exact lookup.rankis0retail,1demo/sample,2beta/proto,3unknown.regionsandyearare used only for tie-breaking.imagesBaseandpackFileare resolved relative to the catalog URL.file://catalogs are supported for offline use and tests.
4. Client cache¶
The client stores the catalog and images under the shared base data directory:
<BaseData>/covers/catalog.json
<BaseData>/covers/catalog.meta.json
<BaseData>/covers/images/<sha256>.webp
<BaseData>/covers/tmp/
<BaseData>/covers/packs/covers-v1.zip
The cache is shared across named profiles. Portable mode keeps it beside the executable. The catalog is revalidated with If-None-Match; a cached catalog is used when the server is unavailable.
5. Matching¶
Resolution order:
- Sibling image beside the disc (existing behavior).
- Exact base name in
CoverDirectory(existing behavior). - Annotation-stripped exact match in
CoverDirectory. - Catalog exact game ID.
- Catalog exact normalized/token/no-space/subtitle match.
- Local fuzzy match.
- Catalog fuzzy match.
The matcher:
- strips balanced
(),[], and{}groups; - normalizes case, punctuation,
&→and, apostrophes, and articles; - compares exact normalized names, sorted token sets, and no-space forms;
- expands
A - B - CintoB - CandCaliases; - applies Jaro-Winkler with a default threshold of 0.85 (range 0.70–0.95);
- rejects sequel-number conflicts such as
Battle ChessvsBattle Chess II; - ignores version numbers on beta/demo/version-tagged names;
- tie-breaks by region, release year, retail-over-demo rank, and name length;
- returns no cover rather than a low-confidence wrong cover.
The default threshold is intentionally higher than Simple Launcher's 0.80 because 5DO has a precomputed game-ID map and should prefer a missing cover over a wrong one.
6. Settings and CLI¶
Settings > Covers exposes:
- use online covers;
- download missing covers automatically;
- catalog URL (base or full
catalog.json); - fuzzy matching and annotation stripping;
- fuzzy threshold;
- refresh catalog, download all covers, clear cache;
- cache statistics and the legal notice.
CLI:
5do covers update
5do covers update --catalog artifacts/covers/v1/catalog.json --cache .\covers
5do covers match "Diving Spot Guide - Marine Tour"
5do covers download --folder "D:\Games\3DO"
5do covers download --all
5do covers verify --fix
5do covers cache path
5do covers cache clear
--catalog accepts a local catalog.json; relative image paths resolve beside it. This is useful for offline testing and for users who downloaded the bulk pack.
7. Building and publishing¶
Build the pack:
packaging/package-covers.ps1
# or:
dotnet run --project tools/FiveDo.CoverPackager -c Release -- `
--source References/Screenshots `
--output artifacts/covers/v1 `
--pack-version 2026.11.07 `
--overrides packaging/cover-overrides.json
The packager:
- hashes and deduplicates source files by SHA-256;
- encodes WebP q85 at up to 600 px height with SkiaSharp;
- parses file names with
GameDatabaseNameParser; - matches game IDs with
CoverCatalogIndex; - applies
packaging/cover-overrides.json; - writes
catalog.json,images/,packs/covers-v1.zip,SHA256SUMS.txt, andreport.json; - reloads the generated catalog, verifies every image hash, and checks that no game ID is mapped twice.
Review report.json before publishing. unmappedGames lists low-confidence and missing games; weakMappings are scores between the map threshold and 0.95. Add manual fixes to packaging/cover-overrides.json:
{
"version": 1,
"gameIds": {
"1AAE20E9": "Chiki Chiki Machine Mou Race - Kenken to Black Maou no Ijiwaru Daisakusen"
}
}
The value may be a unique cover display name, a unique alias, or the 64-character SHA-256 id. Unknown or ambiguous references fail the build.
Publish with rclone:
The script expects an rclone R2 remote named r2 and a bucket path such as r2:simplelauncher-thumbnails/5do/v1. It sets the immutable cache header on images and the short cache header on the catalog. The Cloudflare custom domain serves the bucket root, so the public catalog URL is https://assets.purelogiccode.com/5do/v1/catalog.json.
8. Tests¶
tests/FiveDo.Tests/Host/CoverTests.cscovers annotation stripping, normalization, Jaro-Winkler, token/no-space/subtitle matching, sequel-number guards, catalog validation, cache hash verification, local resolution, remote catalog/image downloads, and settings normalization.covers verifychecks every cached image against the catalog.- The frontend smoke test and a manual library scan validate the UI integration.
9. Rights and takedown¶
Cover art is copyrighted by the respective publishers. The online pack is provided for personal, non-commercial use and is not included in the 5DO application bundles. Rights holders can request removal through the project issue tracker:
https://github.com/purelogiccode/5DO/issues
Do not upload the pack to a public bucket without a working takedown contact.