9 Commits
Author SHA1 Message Date
MihawkandClaude 67b7fed0ac Library: a name edited in the WebUI reaches RetroArch's playlists and every ES-DE rename
A rename in the WebUI was written only to the game's metadata (issue 55).
RetroArch's menus (XMB, RGUI) show the playlist label, which never changed,
and ES-DE took the new name only while its own was still the label, so a
second rename was dropped. src/scraper.cpp now rewrites the game's entry in
every playlist that lists its file (edit_playlist_entries, also for removals),
with Json::dump in src/scraper_json.h; ES-DE's adapter lets every field the
owner edited win (frontends/es-de/ps5/library_ps5.cpp).

Tests: python3 -m unittest tests.test_esde_library tests.test_scraper: 15 OK
(the label changes, the other entries and the playlist's fields stay; two
renames in a row both reach ES-DE's gamelist, its favourite kept).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-18 19:47:34 -04:00
Mihawk 0ebf7c7af5 ES-DE: its first start on a fresh install writes the library
ES-DE's library adapter writes custom_systems/es_systems.xml and the game
lists under /app0/es-de/ES-DE before ES-DE runs, but ES-DE makes that folder
itself only once it starts. On a fresh install's first start every mkdir
below it failed, all 29 writes failed (28 game lists and the systems file)
and ES-DE showed no games; from the second start on it worked. The earlier
ES-DE evidence never met this: those consoles had ES-DE's folder already.
The adapter makes the folder first.

Evidence: tests/esde_library_test.cpp's first start now begins without the
folder and checks 0 failures and a written systems file (it fails without
this change): python3 -m unittest tests.test_esde_library OK. On the
console, evidence/esde-folder-names: the first start before the change,
'28 systems, 255 games ... 29 failures', 'systems written -1'; the second,
0 failures; the first start after it (ES-DE's folder moved aside), '34
systems, 317 games ... 0 failures', 'systems written 34', every system's
path /app0/content/<name>; a home launch of a fresh install started the
picker (picker 1, es-de 1, remembered ask -> picker). python3
tools/evidence.py compare evidence: 131 replayed, 0 failed. tools/verify.sh:
all five gates PASS.
2026-10-17 19:36:17 -04:00
Mihawk 517673894c No game titles in the repository; the v2.0.0-beta-2 release note
Every game title in tracked text (test fixtures, comments, patch notes,
console evidence, the v1.0.0-beta.1 note's alt text) is now a made-up
stand-in that keeps the original's shape: its punctuation (apostrophes,
"&", " - "), region tags and, where a test depends on it, its sort order
and how a title relates to its alternate name. Evidence folders and the
Flycast pad script named after games are renamed. Only the committed
handoff/PPSA99002/eboot.bin still holds a title, inside the binary.

releases/v2.0.0-beta-2.md: PS5SX2, frame generation, RetroAchievements,
NetPlay, the WebUI in 16 languages, the library and frontend changes,
the systems tested on a Base PS5, upgrading from v1.0.0-beta.1, source
and credits. It opens with the anti-piracy banner and points, names no
game and shows no game picture: three WebUI screenshots in
assets/releases/v2.0.0-beta-2/.

Gates: format, unit (196 tests), build, evidence (127 replayed, 0
failed), check-manifest and check-notices: PASS.
2026-10-14 20:35:04 -04:00
Mihawk 33d61f4ddf ES-DE: its ROM folder is the title's content folder, from the first start (issue 33)
The owner's console had ROMDirectory "" in es_settings.xml, which ES-DE reads as ~/ROMs,
/app0/es-de/ROMs: its no-games screen pointed there. And the adapter only set its
folders once ES-DE had written a settings file, so a first start never had them.

use_title_folders, before each start: ROMDirectory = /app0/content (an empty value or
ES-DE's ~/ROMs default replaced, a folder the user chose kept) and MediaDirectory = the
shared library; with no settings file yet, one with just these is written, which
ES-DE's Settings::loadFile reads and completes when it saves.

Evidence: evidence/issue-33-system-folders (the owner's first ES-DE start with its
settings set aside: ROMDirectory=/app0/content, MediaDirectory=/app0/library, 36 systems
and 3461 games; kept after ES-DE's exit; the owner's settings then restored with only
ROMDirectory changed); tests/esde_library_test.cpp (first start, ES-DE's default
replaced, the user's folder kept). tools/verify.sh: PASS (format unit build
integration evidence).
2026-10-09 22:29:13 -04:00
Mihawk cfad33bc2e Scraping: ScreenScraper as a source, with a sign-in that stays on the console
- Sign-in: clicking ScreenScraper opens a login form. The name and password go to the
  console in a request body, are checked with ScreenScraper (ssuserInfos), then kept in
  config/private/screenscraper.cfg (0600, folder 0700, out of the 0777 repair, never
  served). No answer carries the password. A green check on the chip when signed in;
  Manage shows the quota, switches account or signs out.
- Engine: jeuInfos by CRC, file name and size, then jeuRecherche ("Name [id]"
  candidates; the same title taken unasked, others resolved from the page). Details in
  the language asked for (description, genre, developer, publisher, players, rating
  0-1, release date); media per kind and region; the account's maxthreads kept; 429
  waits; 401/403/423/426/430/431 pause the job with a message, resumable.
- The developer account: generated scrambled into build/screenscraper_dev.h from .env;
  releases carry it scrambled (owner's decision), PS5_SCREENSCRAPER_EXCLUDE=1 leaves it
  out. https only (media links upgraded, no https->http redirects). PC mode is refused
  for ScreenScraper: its media links carry the developer account, which never leaves
  the console. lint-shell fails on a plain copy in any tracked or shipped file.
- ES-DE: release dates become YYYYMMDDT000000.
- Systems table generated from ES-DE's ScreenScraper ids (MIT notice kept).

Evidence: evidence/scraper-screenscraper (6 host tests against a fake ScreenScraper API,
fake accounts, plus the leak check); reproduce with
  python3 -m unittest -v tests.test_scraper_screenscraper; bash tools/lint-shell.sh
tools/verify.sh: PASS (format unit build integration evidence).
Not verified: a live sign-in and job against api.screenscraper.fr (owner's run).
2026-10-07 12:02:10 -04:00
Mihawk ce06e66cb3 Scraping: libretro media into one library every frontend reads
The WebUI's Games page scrapes box art, screenshots, title screens and logos from
libretro's thumbnail server into /app0/library/<system>/<kind>/<game>, one store for
every frontend: RetroArch's thumbnail lookup asks it first (patch 0114, which also
gives thumbnails_directory "default" its folder: it was empty and stopped every
lookup), EmulationStation has it as its media folder and fills its game lists from
its .meta files, the Games page shows it, a future frontend calls ps5_library_media.

- src/scraper.{h,cpp}: jobs saved and resumed without repeats, exact names, exact
  titles tags aside, ranked candidates for the user, fill-missing by default; PS5 mode
  on the daemon (runs with the page and the title closed) and PC mode through
  webui/ps5-media-helper.py (the console identifies; the bytes pass through the PC).
- The page: the method asked first and remembered on the console, sources and every
  media type described, version tags on each card. ScreenScraper, LaunchBox and
  EmuMovies are listed as coming (ScreenScraper's developer credentials requested).
- The daemon's HTTP is libcurl over mbedTLS 3.6 with the shipped CA bundle (Sony's SSL
  failed every handshake from the payload, 0x8095f00c); its updater uses it too.
- The shared library: one path a game read from outside the title (14 games were
  listed twice), a disc's listed .bin dropped beside its .cue.
- The daemon: workers on 1 MiB stacks (a 64 KiB frame overflowed one), stale hand-over
  on transfers in flight rather than idle keep-alive connections, pid in its log.

Evidence: evidence/scraper-libretro (base PS5 13.40): every system in 148 s (520
complete, 28 partly, 181 kept, 61 ambiguous, 234 unmatched); cached runs fetch
nothing; HTTPS through curl; PC mode with the helper killed: 90 images each sent once;
a job finished with the title closed; 1,024 games, 0 duplicates. Not seen live:
RetroArch and ES-DE drawing the media (owner to look), updates through the daemon.
Command: build/tmp/scraper/live.py; tools/verify.sh: all five PASS.
2026-10-07 10:45:24 -04:00
Mihawk 6ad0d62cff EmulationStation lists the games in the content folders (issue 25)
ES-DE's library came from RetroArch's playlists alone, so a game copied into
content/ appeared only after a Manual Scan in RetroArch. ps5_library_load_content
now also scans content roots after the playlists (a playlist's entry still
wins): /app0/content and the USB and extended drives ShadowMountPlus mounts.
- Each folder at a root's top that names a platform the title has a core for
  is that system's; the platform table gains the systems the title now runs
  (3DO, DOS, ScummVM, Neo Geo CD, NGPC, WonderSwan Color, SuperGrafx, PC-FX,
  Virtual Boy, Pokemon Mini, Atari 5200 and Jaguar, NAOMI, Atomiswave), most
  specific first ("NeoGeo CD" is not the arcade Neo Geo).
- In it, every file a core of the platform takes; .zip and .7z too for a
  cartridge system (RetroArch opens them), not for a disc system (an archived
  disc's tracks are not extracted). Left out: firmware (named in a core's
  info, a variant of one, or [BIOS]/Kickstart/boot ROM), and the tracks of a
  folder that has a .cue, .gdi or .m3u.
- A DOS game is a folder started by the program named like it (doom/DOOM.EXE);
  a ScummVM game is a folder started from a data file in it.
- A path too long for the buffers is skipped, never truncated.
es-de.bin passes the roots (frontends/es-de/ps5/library_ps5.cpp).

Verified: tests/ps5_library_test.c (folder names, firmware, tracks, DOS,
ScummVM, a drive, archives by kind, no duplicates) and esde_library_test PASS.
On the base PS5: ES-DE lists 36 systems and 1025 games; E.T. (Fixed), found
only by the scan, starts in RetroArch (Stella) and returns to ES-DE
(evidence/issues-25-27, next commit). tools/verify.sh format and unit PASS.
2026-10-06 23:40:55 -04:00
Mihawk 5ee2d48455 ES-DE: RetroArch's favourites, history and play in its collections
The shared game library (src/ps5_library.h) now carries what RetroArch
remembers of each game:
- whether it is a favourite (playlists/builtin/content_favorites.lpl);
- its place in the history (builtin/content_history.lpl);
- its runtime log (logs/<core's corename>/<content name>.lrtl): when it
  was last played, how often, and for how long.
A game in the history with no runtime log is given a time from its
place: the history file's time, a minute earlier for each place below
the top.

ES-DE's writer (frontends/es-de/ps5/library_ps5.cpp) merges these into
each game list entry:
- favorite: a game RetroArch added or removed since ES-DE's last start
  follows RetroArch (ES-DE/ps5-favorites.txt records RetroArch's set);
  any other game keeps ES-DE's own choice. A favourite set in either
  frontend therefore shows in ES-DE.
- lastplayed, playcount, playtime: the later or larger of ES-DE's and
  RetroArch's.
On the PS5, ES-DE's automatic collections default to Favorites and Last
Played (patches/0001). An install whose settings already said none gets
them once; a marker file keeps any later choice of the user's.

Evidence: evidence/esde-collections/ (capture.json, expectation.json).
Base PS5 13.40:
  RetroArch's History tab, the game's menu, Add to Favorites (pad
    script): RetroArch's favourites held Donkey Kong Country 2
  ES-DE's next start: 1 favourite, 15 games played; CollectionSystemsAuto
    favorites,recent; Donkey Kong Country 2 favourite, playcount 8,
    playtime 838 s (the runtime log's 0:13:58), its later lastplayed kept
  ES-DE's carousel: the SNES card reads "1 GAME (1 FAVORITE)", and the
    Favorites and Last Played collections are there
The test favourite's file was removed afterwards; the console had none.
Host tests: ps5_library and esde_library PASS.
Command:
  tools/run-title.sh --no-build --no-deploy --pad-script=tests/pad/history-favourite.txt --watch 25
  tools/run-title.sh --no-build --no-deploy --relaunch-test=1 --relaunch-image=es-de/es-de.bin --frontend-capture=4 --watch 30
Gates: tools/verify.sh PASS (format unit build integration evidence).
2026-10-04 22:34:28 -04:00
Mihawk f35915abca The game library: every frontend's systems and games come from RetroArch
A frontend keeps no game library of its own. Its systems and game lists
are RetroArch's playlists, read again each time it starts, so a game
added to or removed from a playlist in RetroArch appears or goes in
every frontend. src/ps5_library.h and src/ps5_library.c are that
contract, compiled into eboot.bin and into every frontend
(tools/build-frontend.sh), like game mode's:

- Games: the entries of /app0/playlists, minus RetroArch's history,
  favourites and media lists, each game once.
- A game's system: the first known platform among its entry's
  database, the playlist's name, its folder and its core's database;
  otherwise a system of its own. A mixed playlist of DETECT entries,
  like the base console's content.lpl, is split by folder.
- A system's core: the one its entries name most, else the core
  RetroArch's core info associates with the platform. Its folder is the
  deepest folder holding all its games, and its extensions are those of
  its games and its core.
- ps5_library_command gives game mode's command line; game mode now
  reads playlists through the same reader.

ES-DE (frontends/es-de/ps5/library_ps5.cpp) writes
custom_systems/es_systems.xml and each system's gamelist.xml from the
library at every start, using ES-DE's own names and themes. A game ES-DE
already knows keeps its play count, play time, favourite and scraped
details; a game no longer in any playlist is dropped. ES-DE then runs
with --gamelist-only. The fixed table (systems.tsv, systems.py) is gone.

Evidence: evidence/game-library/ (capture.json, expectation.json,
capture-test.jsonl); base PS5 13.40: 5 playlists gave 14 systems and 16
games, 0 failures. ES-DE loaded the 14 systems, started Donkey Kong
Country 2 through game mode and came back with the play counted
(playcount 2, playtime 21); no fatal signal.
Command:
  PS5_FRONTENDS='es-de picker' tools/build-title.sh
  tools/run-title.sh --no-build --relaunch-test=1 \
    --relaunch-image=es-de/es-de.bin --frontend-capture=4,20 \
    --frontend-launch --retroarch-frames=600 --watch 80
Gates: tools/verify.sh PASS (format unit build integration evidence).
2026-10-04 18:54:38 -04:00