Files
knutwurst--ps5-patchdl/web
Knutwurst 289688f727 Rescan on its own, track installs, verify and clean up packages
Library
- Rescan when /user/app or Sony's app.db changes, after an install, and on
  the Refresh button (which also asks Sony for updates again). Later scans
  keep a handle to the system root and use relative paths instead of
  swapping the process root while other threads run; app.db is copied out
  first because SQLite resolves relative paths with getcwd(). The scan
  thread gets a 1 MB stack (the default made reads fail with EFAULT).
- Take the newer of app.db and appmeta param.json as installed version:
  app.db lags behind until the game is started.
- A package header decides "fake"; the installer's "fake": true marker
  only says the package didn't come from Sony's CDN, and PatchDL's own
  installs set it too.
- PS4 titles are listed as not supported.

Downloads
- Fetch the manifest's .crc next to the package; the console asks for it.
- Keep the sidecar (with the version) after a download completes, so a
  restart still knows the package is whole.
- A package already on disk without a matching sidecar is hashed against
  the manifest piece by piece; only pieces that don't match are fetched.
  Install refuses an unverified package.

Installs
- One install per title: a second request (another tab, a double click)
  gets install_running; an installed version gets already_installed.
  Download, Cancel and Delete wait until the console is done reading.
- Progress comes from the bytes PatchDL serves to the console (distinct
  ranges), since Sony's status query fails for these installs. Phases:
  waiting, reading with percent, finishing, done or stalled. Each title
  is tracked on its own.
- After an install: check that the installed version matches and the new
  app.json names this package and its size. With "Delete PKG after
  install" on, delete the package only then. The setting existed but was
  never read; the old cleanup trusted app.db alone and deleted packages
  that were never applied.

UI
- Settings list every package on the console with size, version and
  whether it is installed, newer or for a game that's gone, with Delete.
  The storage tile links there.
- The list reloads quietly when the server reports a change.
- Bigger covers on wide screens, "Updates on/off" on the switch, no
  "Shared master" badge, no endless auto-install retries.
2026-10-16 12:04:49 +02:00
..

PatchDL Web UI

Standalone static UI for the planned PS5 patchdl.elf web server.

Open index.html directly for the mock UI, or serve this directory from the ELF web server. The JavaScript first tries the real API and falls back to demo data when the API is not available.

The embedded ELF server serves this UI on port 12880 by default.

Expected API

GET  /api/status
GET  /api/config
POST /api/config
GET  /api/titles
GET  /api/downloads
GET  /api/installstatus
GET  /api/pkgmeta/:title_id
GET  /api/pkgverify/:title_id
POST /api/titles/:title_id/check
POST /api/titles/:title_id/download
POST /api/titles/:title_id/install
POST /api/titles/:title_id/enable
POST /api/titles/:title_id/disable

Policy Model

The UI assumes deny-by-default behavior:

{
  "default_policy": "deny",
  "download_dir": "/data/patchdl (internal)",
  "install_after_download": false,
  "delete_pkg_after_install": true,
  "source_policy": {
    "official": { "allow_check": true, "allow_download": true, "allow_install": true },
    "external": { "allow_check": true, "allow_download": true, "allow_install": true },
    "shadowmount": { "allow_check": true, "allow_download": false, "allow_install": false },
    "unknown": { "allow_check": true, "allow_download": false, "allow_install": false },
    "fake": { "allow_check": true, "allow_download": false, "allow_install": false }
  },
  "cdn_allowlist": [
    "sgst.prod.dl.playstation.net",
    "gst.prod.dl.playstation.net",
    "gs2.ww.prod.dl.playstation.net"
  ]
}

Per-title modes:

disabled
download_only
latest_compatible
pin
check_only

Per-title source fields:

{
  "title_id": "PPSA90001_00",
  "name": "Shadowmounted Test Title",
  "source_type": "shadowmount",
  "source_path": "/system_ex/app/PPSA90001_00",
  "mount_from": "/mnt/usb0/itemzflow/Shadowmounted Test Title",
  "enabled": true,
  "mode": "disabled"
}

Supported source_type values:

official
external
shadowmount
unknown

The frontend lists shadowmount, unknown and fake titles under Not supported and offers neither download nor install for them. The backend refuses both as well, even if a client sends a forged request.

For PS5 game updates, the backend may turn a Sony manifest_url into a merged local .pkg by downloading all manifest pieces. The delta_url *-DP.pkg is not shown as a separate user action because it can bootstrap the storage/master title instead of the installed regional target.

If patch_storage_match is false, the CDN stores the patch pieces under another regional (master) title id. That is fine: the merged .pkg assembled from the manifest carries the installed title's own content id, and AppInstUtil AppInstallPkg installs it onto that title. The UI only adds a "Shared master" label.