PS5: use contentVersion as the version; 3-part version tags

- PS5 pkgs and game folders now use contentVersion (the game version
  including updates, e.g. 02.002.000 -> [v2.002.000]); masterVersion
  can stay at 01.00 when the game is at 2.002. masterVersion is only
  used when there's no contentVersion.
- version_tag handles any number of parts: 01.000.000 -> v1.000.000.
- db lines recorded for PS5 items with masterVersion (v1.3.0) are moved
  to the new version, keeping edits, instead of leaving stale lines.
- README / usage / option help updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bsgonzalezqandClaude Opus 5.5 committed 2026-09-30 13:27:09 -05:00
1 parent 0811065298
commit fc980f58e0
2 files changed
+24 -14

No files matched your search

+9 -6
View File
@@ -461,13 +461,16 @@ Bloodborne/
└── Bloodborne The Old Hunters [v1.00].pkg
```
- **Version:** read from the PKG's `param.sfo`, and the field used depends on the type. Leading zeros are dropped, so `01.09` becomes `v1.09`:
- **Version:** read from the PKG's `param.sfo`, or `param.json` for PS5. The field used depends on the type:
| Type | Field | Why |
|---|---|---|
| patch | `APP_VER` | the version the patch updates the game to. A patch's `VERSION` is usually `01.00` |
| base game | `VERSION` | the version the base PKG was built at, e.g. `v1.07` for a base PKG that already contains updates. A base PKG's `APP_VER` is always `01.00` |
| DLC | `VERSION` | DLC has no `APP_VER` |
| PS5 PKG or game folder | `contentVersion` | the game version including updates, e.g. `02.002.000` gives `v2.002.000`. `masterVersion` is only used if there's no `contentVersion` |
Leading zeros of the first number are dropped, and the rest is kept as is: `01.09` becomes `v1.09`, and `01.000.000` becomes `v1.000.000`.
- **Content ID:** the PKG's full content ID, `<region prefix>-<title ID>_00-<label>`. It's unique per PKG: each DLC has its own, and a base game and its patches share one. The prefix also shows the region: `UP` = USA, `EP` = EUR, `JP` = JPN, `HP` = Asia.
- **Folders:** version, content ID and type are only added to `.pkg` files and to [game folders](#game-folders-ps5-and-dumped-ps4-games). A normal game folder holds several PKGs of different versions and types, so it only gets title, ID and region, and always keeps the game title, even with `--no-title`.
- **`--no-title`:** removes the game title from `.pkg` file names and game folders only. It must be combined with `--add-id` or `--add-content-id`, so every file still says which game it belongs to. The script stops with an error otherwise. The name's first part is written without brackets, so names don't start with `[`, e.g. `CUSA00900 [v1.09] [patch].pkg`, or `v1.09 [CUSA00900] [patch].pkg` with `--order version`. A DLC keeps its own name, and a patch keeps a label you gave it in the db, so different DLC of the same game still get different names.
@@ -513,11 +516,11 @@ The default order is `title,label,id,region,console,version,cid,type`. List the
PS5 `.pkg` files, e.g. fpkgs, are renamed like PS4 PKGs, with the same parts and options:
```
UP2103-PPSA03311_00-BOIREPENTANCEPS5.pkg -> The Binding of Isaac Repentance [PPSA03311] [PS5]/The Binding of Isaac Repentance [PPSA03311] [PS5] [v1.01] [base].pkg
UP2103-PPSA03311_00-BOIREPENTANCEPS5.pkg -> The Binding of Isaac Repentance [PPSA03311] [PS5]/The Binding of Isaac Repentance [PPSA03311] [PS5] [v1.000.000] [base].pkg
```
- **How they're read:** a PS5 PKG starts with `\x7fFIH` instead of PS4's `\x7fCNT`. The value at offset `0x58` points to a PS4-style metadata block inside it, whose entry `0x2000` is the game's `param.json`. The script jumps straight there and reads a few KB, however big the PKG is.
- **What's used:** `titleId`, `contentId`, the English `titleName` and `masterVersion`, the same fields as PS5 game folders.
- **What's used:** `titleId`, `contentId`, the English `titleName` and `contentVersion`, the same fields as PS5 game folders. `contentVersion` is the game's version including updates, e.g. `02.002.000` gives `[v2.002.000]`. The PKG's `masterVersion` can stay at `01.00` even when the game is at 2.002.
- **Types:** so far only **base games** (content type `0x20`) are recognised. A PS5 patch or DLC PKG is reported as `PS5 pkg type 0x… not recognised yet` and left alone, until its type code is known.
- **Separate from PS4:** a PS5 game has its own title ID (`PPSA…`), db entry and folder. It's never merged with the PS4 version of the same title. If two games would get the same folder name, e.g. `ELDEN RING` for both PS4 and PS5 in the default style, the second one is reported with a hint to use `--add-id` or `--add-console`, and nothing is moved into the other game's folder.
@@ -527,11 +530,11 @@ Besides PKG files, the script renames **extracted game folders**: a PS5 game, or
| Folder contains | Platform | Read from it |
|---|---|---|
| `sce_sys/param.json` | PS5 | `titleId`, `contentId`, the English `titleName` under `localizedParameters`, and `masterVersion` |
| `sce_sys/param.json` | PS5 | `titleId`, `contentId`, the English `titleName` under `localizedParameters`, and `contentVersion` |
| `sce_sys/param.sfo` | PS4 dump | the same fields as a PKG's `param.sfo`. The version is `VERSION`, like a PS4 base game |
```
The Binding of Isaac Repentance 01.000 PPSA03311/ -> The Binding of Isaac Repentance [PPSA03311] [USA] [v1.01] [app]/
The Binding of Isaac Repentance 01.000 PPSA03311/ -> The Binding of Isaac Repentance [PPSA03311] [USA] [v1.000.000] [app]/
├── eboot.bin ├── eboot.bin (untouched)
├── PPSA03311.complete ├── PPSA03311.complete (untouched)
└── sce_sys/param.json └── sce_sys/param.json (untouched)
@@ -693,7 +696,7 @@ Only to look up English names for Japanese/Korean/Chinese titles, and only once
**Does it work with PS5 games?**
Yes, with both kinds:
- **PS5 `.pkg` files (fpkg):** read from the `param.json` inside them. Base games are supported so far. See [PS5 PKGs](#ps5-pkgs).
- **Extracted PS5 game folders** (`sce_sys/param.json`): renamed as one item, e.g. `The Binding of Isaac Repentance [PPSA03311] [v1.01] [app]`, with their contents never touched. Dumped PS4 games stored as folders (`sce_sys/param.sfo`) work the same way. See [Game folders](#game-folders-ps5-and-dumped-ps4-games).
- **Extracted PS5 game folders** (`sce_sys/param.json`): renamed as one item, e.g. `The Binding of Isaac Repentance [PPSA03311] [v1.000.000] [app]`, with their contents never touched. Dumped PS4 games stored as folders (`sce_sys/param.sfo`) work the same way. See [Game folders](#game-folders-ps5-and-dumped-ps4-games).
PS4 and PS5 versions of a game stay separate. Use `--add-console` to tag names `[PS4]` / `[PS5]`.
+15 -8
View File
@@ -35,7 +35,8 @@ The game title is always used, other parts are added as tags; the type tag is la
--add-id title ID tag Bloodborne [CUSA00900] [patch].pkg
--add-region region tag Bloodborne [USA] [patch].pkg
--add-console console tag (db) Bloodborne [PS4] [patch].pkg
--add-version version tag Bloodborne [v1.09] [patch].pkg (patch: APP_VER, base/DLC: VERSION)
--add-version version tag Bloodborne [v1.09] [patch].pkg (PS4 patch: APP_VER, base/DLC: VERSION;
PS5: contentVersion)
--add-content-id content ID tag Bloodborne [UP9000-CUSA00900_00-BLOODBORNE000000] [patch].pkg
--no-type no type tag Bloodborne [v1.09].pkg
--no-title no game title in .pkg CUSA00900 [v1.09] [patch].pkg (needs --add-id or --add-content-id;
@@ -46,7 +47,7 @@ The game title is always used, other parts are added as tags; the type tag is la
parts: title,label,id,region,console,version,cid,type (listed first, rest keep default order)
label = the DLC name, or a Title you edited in the db's PKGS section (works for base, patch and DLC)
Game folders (PS5 sce_sys/param.json, PS4 dump sce_sys/param.sfo) are named like a pkg with
type [app] and never entered: The Binding of Isaac Repentance [PPSA03311] [v1.01] [app]
type [app] and never entered: The Binding of Isaac Repentance [PPSA03311] [v1.000.000] [app]
Other folders: <title>[ <ID>][ <region>], always with the title; version, content ID and type
go on .pkg files and game folders only. DLC keep their DLC title: The Old Hunters [CUSA00900] [dlc].pkg
@@ -466,6 +467,11 @@ def build_db(root, path, rebuild=False, offline=False):
if kind == 'base' and old != key and old in db.pkgs and key not in db.pkgs:
db.pkgs[key] = db.pkgs.pop(old) # recorded with APP_VER (01.00) by older versions
print(f' ~ {pcid}|{old[2]} -> {ver} (base version is VERSION, not APP_VER)')
if console == 'PS5' and key not in db.pkgs:
olds = [k for k in db.pkgs if k[0] == pcid and k[1] == kind and k != key]
if len(olds) == 1: # recorded with masterVersion by v1.3.0: keep the line (and edits)
db.pkgs[key] = db.pkgs.pop(olds[0])
print(f' ~ {pcid}|{olds[0][2]} -> {ver} (PS5 version is contentVersion)')
if key not in db.pkgs:
db.pkgs[key] = (gid, (db.dlc_title(pcid) or ptitle) if kind == 'dlc' else ptitle)
new_pkgs += 1
@@ -786,8 +792,9 @@ def _pkg_tuple(cid, sfo, kind):
def ps5_version(params):
"""The version of a PS5 game: masterVersion (contentVersion if there's none)."""
return params.get('masterVersion') or params.get('contentVersion') or ''
"""The version of a PS5 game: contentVersion, the game version including updates (e.g.
02.002.000); masterVersion (the package's master version) only if there's no contentVersion."""
return params.get('contentVersion') or params.get('masterVersion') or ''
def _ps5_tuple(params, kind, cid=''):
@@ -798,9 +805,9 @@ def _ps5_tuple(params, kind, cid=''):
def version_tag(ver):
"""'01.09' -> 'v1.09'."""
m = re.fullmatch(r'0*(\d+)\.(\d+)', ver.strip())
return f'v{m.group(1)}.{m.group(2)}' if m else (f'v{ver.strip()}' if ver.strip() else '')
"""'01.09' -> 'v1.09', '01.000.000' -> 'v1.000.000' (leading zeros of the first part dropped)."""
m = re.fullmatch(r'0*(\d+)((?:\.\d+)+)', ver.strip())
return f'v{m.group(1)}{m.group(2)}' if m else (f'v{ver.strip()}' if ver.strip() else '')
def pkg_name(info, db, style, unknown, ext='.pkg'):
@@ -1466,7 +1473,7 @@ def main():
'or --add-content-id; the first part loses its brackets, e.g. "CUSA00900 [v1.09] [patch].pkg"')
ap.add_argument('--add-version', action='store_true',
help='add the pkg version to .pkg names, e.g. "Bloodborne [v1.09] [patch].pkg" '
'(patches: APP_VER; base games and DLC: VERSION)')
'(PS4 patches: APP_VER; PS4 base games and DLC: VERSION; PS5: contentVersion)')
ap.add_argument('--add-content-id', action='store_true',
help='add the content ID to .pkg names, e.g. "Bloodborne [UP9000-CUSA00900_00-BLOODBORNE000000] [base].pkg"')
ap.add_argument('--sep', default=' ', metavar='SEP',