Rename PS4 .pkg files and CUSA title-ID folders to game names, automatically. ps4-pkg-title-renamer reads the param.sfo inside each PS4 PKG. From it, the script gets the game title, title ID, type (base game, patch or DLC), version and content ID, and uses them to give every file and folder a clear, consistent name. It's a small Python script with no dependencies, and it runs on Linux, macOS and Windows.
CUSA00900/ Bloodborne [CUSA00900]/
├── CUSA00900_base.pkg -> ├── Bloodborne [CUSA00900] [v1.00] [base].pkg
├── update.pkg ├── Bloodborne [CUSA00900] [v1.09] [patch].pkg
└── Bloodborne The Old Hunters.pkg └── Bloodborne The Old Hunters [CUSA00900] [v1.00] [dlc].pkg
CUSA11253_base.pkg (loose in root) Dead Cells [CUSA11253]/
└── Dead Cells [CUSA11253] [v1.00] [base].pkg
Example with --add-id --add-version. The default is just Bloodborne [base].pkg, and every tag is optional.
- Renames by what's inside the PKG, not by its file name. It uses the title, title ID, type, version and content ID from
param.sfo, so it needs no guessing and no online title-ID database. - Recognises base games, patches and DLC (
CATEGORYgd,gp,ac) and tags them[base],[patch]and[dlc]. - Optional tags: title ID (
CUSA00900), version (v1.09), region (USA/EUR/JPN/ASIA), content ID. You can also choose the separator, write tags without brackets, or name by ID only. - Turns
CUSA/CUSAXXXXXfolders into game-name folders, and moves loose PKGs into their game's folder. - PS5 too: PS5
.pkgfiles (fpkg) are read from theparam.jsoninside them. Extracted game folders withsce_sys/param.json(PS5) orsce_sys/param.sfo(dumped PS4) are renamed as one item and never entered (PS5 PKGs, Game folders). - PS4 and PS5 versions of a game stay separate: each console's version has its own db entry, folder and files. The db records each game's console, and
--add-consoleadds it to names, e.g.ELDEN RING [PS5]. - English names for Japanese / Korean / Chinese titles, looked up online once and stored in an editable title database.
- Safe:
- Dry run by default, with a results log.
- Undo everything, only the last run, or only matching names (Undo).
- Never overwrites a file.
- Never changes the contents of a PKG, only names.
- Detects broken PKGs: those with a corrupt or missing
param.sfoare reported and left alone. - Safe for exFAT/NTFS drives: names are valid on USB drives used with a PS4, GoldHEN or Itemzflow.
- Features
- Prerequisites
- Installation
- Quick start
- Options
- Title database
- Naming scheme
- Running again
- Undo
- Logs
- FAQ
- Notes
- License
| Requirement | Why |
|---|---|
| Python 3.8+ | Runs the script. Only the standard library is used, so there's nothing to pip install |
| git | Clones and updates the repo |
| Internet access | Only needed for the English-name lookup in --build-db. Use --offline to skip it |
The prerequisites are also listed in requirements.txt, which names no packages, and checked by install_prereqs.sh (Linux/macOS) or install_prereqs.ps1 (Windows).
# 1. get git if you don't have it (Debian/Ubuntu shown; the script below handles other distros)
sudo apt-get update && sudo apt-get install -y git
# 2. clone the repo
git clone https://github.com/bsgonzalezq/ps4-pkg-title-renamer.git
cd ps4-pkg-title-renamer
# 3. install / verify Python 3.8+ and git (apt, dnf, pacman, zypper or Homebrew)
./install_prereqs.shinstall_prereqs.sh installs only what's missing, checks the Python version, and runs pip install -r requirements.txt if packages are ever added there.
If you'd rather install by hand:
| Distro | Command |
|---|---|
| Debian / Ubuntu | sudo apt-get install -y python3 git |
| Fedora / RHEL | sudo dnf install -y python3 git |
| Arch | sudo pacman -S --needed python git |
| openSUSE | sudo zypper install -y python3 git |
| macOS (Homebrew) | brew install python git |
winget install -e --id Git.Git # skip if git is installed
# reopen the terminal so git is on PATH, then:
git clone https://github.com/bsgonzalezq/ps4-pkg-title-renamer.git
cd ps4-pkg-title-renamer
powershell -ExecutionPolicy Bypass -File .\install_prereqs.ps1 # installs / checks Python 3.8+ and git
py ps4_rename.py --helpinstall_prereqs.ps1 works like install_prereqs.sh: it installs only what's missing (through winget), checks the Python version, and checks the script runs.
Using the script on Windows:
- Commands: use
pyorpythonwhere this README showspython3, and\in paths, e.g.py ps4-pkg-title-renamer\ps4_rename.py D:\PS4 --apply. - Everything else works as on Linux: a drive root like
D:\works asPATH, and the script checks the OS when it starts. It handles Windows differences automatically:- Long paths: paths longer than 260 characters work even if Windows' long-path support is off.
- Case: Windows ignores letter case in names and paths (
C:\Games=c:\games), and so does the script, including renames that only change letter case. - Names: file names that Windows can't use are made safe. That covers
:and similar characters, the reserved namesCON,NULandCOM1, and trailing dots. - Console: titles with characters like
™,Ψor Japanese text never crash the output, even when it's redirected to a file.
- Same drive on both systems: a drive renamed on Linux can be used on Windows and the other way round. Names are already safe for exFAT/NTFS, and the db and logs are plain UTF-8 text.
rename_undo.log: records full paths, so run--undoon the same OS and drive letter or mount point you used for--apply.
cd ps4-pkg-title-renamer
git pullIf you keep a copy of ps4_rename.py somewhere else, such as next to your games, copy it over again after pulling.
The script always lives in a folder named ps4-pkg-title-renamer, together with its db (ps4_titles.db) and all its logs:
- Moving itself: if you run it from a folder with any other name, it creates
ps4-pkg-title-renamer/in your current directory. It moves itself there along with its db and logs, removes the old folder if that's now empty, and carries on. So you can dropps4_rename.pyinto your games folder and run it. - Git clones: the script never moves out of a git clone.
- Existing copy: it won't overwrite a
ps4_rename.pythat's already in./ps4-pkg-title-renamer/. - Old folder name:
ps4-title-renamer, the repo's previous name, is still accepted, so existing clones keep working.
The examples use relative paths.
The script takes one optional PATH: the folder that holds your PKG folders. With no PATH it works on the current directory. PATH can be relative or absolute.
Both examples use this layout, with the script in a subfolder of the games folder:
games/ <- games folder (holds the PKG folders)
├── CUSA00900/
├── CUSA00419/
└── ps4-pkg-title-renamer/ <- script folder (a clone of this repo, or created automatically)
├── ps4_rename.py
├── ps4_titles.db
└── rename_undo.log, rename_results_*.log
Option 1: your terminal is in the games folder (games/). No PATH is needed because the current directory is already the games folder:
cd games
python3 ps4-pkg-title-renamer/ps4_rename.py --build-db # 1. create ps4_titles.db (optional, done automatically)
python3 ps4-pkg-title-renamer/ps4_rename.py # 2. dry run: shows what would change
python3 ps4-pkg-title-renamer/ps4_rename.py --apply # 3. rename
python3 ps4-pkg-title-renamer/ps4_rename.py --undo # revert everything, if needed
python3 ps4-pkg-title-renamer/ps4_rename.py --undo-last # or preview reverting just the last run (see Undo)Option 2: your terminal is in the script folder (games/ps4-pkg-title-renamer/). Pass .., the parent folder, as PATH:
cd games/ps4-pkg-title-renamer
python3 ps4_rename.py .. --build-db
python3 ps4_rename.py ..
python3 ps4_rename.py .. --apply
python3 ps4_rename.py .. --undo
python3 ps4_rename.py .. --undo-lastThe db and all logs are always kept in the script's folder, whichever PATH you process, so one db serves all your game folders.
Optional: to run it as just ps4_rename.py from anywhere, run this from the script's folder to link it into your PATH:
mkdir -p ~/.local/bin && ln -sf "$PWD/ps4_rename.py" ~/.local/bin/ps4_rename.pyRe-run the link command if you move the script.
| Option | Description |
|---|---|
PATH |
Directory to process (default: current directory) |
--apply |
Perform the renames (default is a dry run) |
--undo |
Revert all renames under PATH recorded in rename_undo.log |
--undo-last |
Revert only the most recent --apply run. Previews unless --apply is added |
--undo-match TEXT |
Revert only renames whose path contains TEXT. Previews unless --apply is added |
--add-id |
Add the title ID tag after the title: Bloodborne [CUSA00900] [patch].pkg. --keep-id still works as an old name for it |
--no-title |
Leave the game title out of .pkg file names; folders keep it. Needs --add-id or --add-content-id. The first part is written without brackets: CUSA00900 [patch].pkg |
--add-version |
Add the PKG version to .pkg names: Bloodborne [v1.09] [patch].pkg |
--add-content-id |
Add the content ID to .pkg names: Bloodborne [UP9000-CUSA00900_00-BLOODBORNE000000] [base].pkg |
--no-type |
Leave out the [base] / [patch] / [dlc] tag: Bloodborne [v1.09].pkg |
--order PARTS |
Order of the parts in .pkg file names, e.g. --order id,title gives [CUSA00900] Bloodborne [patch].pkg. See File part order |
--add-region |
Add the region tag after the title/ID: Bloodborne [CUSA00900] [USA] [patch].pkg |
--add-console |
Add the console tag (PS4, PS5, …, from the db) after the region: Bloodborne [PS4] [patch].pkg |
--sep SEP |
Use SEP instead of spaces in generated names: --sep _ gives Grand_Theft_Auto_V_[patch].pkg. "" means no separator |
--no-brackets |
Write tags without [ ]: Bloodborne CUSA00900 v1.09 patch.pkg |
--build-db |
Add games to the db from the .pkg files in PATH |
--rebuild |
With --build-db: start a fresh db, dropping old entries |
--offline |
Skip the English-name lookup when building the db |
--no-auto-db |
Don't build the db automatically when IDs are missing |
--db FILE |
Title db to use (see below) |
--log FILE |
Where to write the results log (default: the script's folder) |
--keep-logs N |
Number of results logs to keep; older ones are deleted. Default 5, and 0 keeps all |
--export-xlsx [FILE] |
Export the db as an Excel workbook and exit. The default file is ps4_titles.xlsx next to the db. See Using the db |
--clean-logs |
Delete the results logs; rename_undo.log is kept |
-h, --help |
Show help |
ps4_titles.db is a plain-text file next to the script. It has two sections, and you can edit both by hand:
# GAMES: TitleID|Title|Region|Console
CUSA00900|Bloodborne™|USA|PS4
CUSA07439|DARK SOULS™ III|EUR|PS4
CUSA10207|Battle Garegga Rev.2016|ASIA|PS4
PPSA03311|The Binding of Isaac Repentance|USA|PS5
CHTM00777|PS4 Cheats Manager|HB|PS4
# PKGS: ContentID|Version|Type|TitleID|Title
UP9000-CUSA00900_00-BLOODBORNE000000|01.00|base|CUSA00900|Bloodborne™
UP9000-CUSA00900_00-BLOODBORNE000000|01.09|patch|CUSA00900|Bloodborne™
UP9000-CUSA00900_00-SPEXPANSIONDLC03|01.00|dlc|CUSA00900|Bloodborne The Old Hunters
Every run reads each PKG's param.sfo anyway, so the db isn't a speed-up. It's there for things the PKGs alone can't give you:
| The db | Without it |
|---|---|
| Remembers English names found online for Japanese/Korean titles | Every run would repeat the online lookups: slower, rate-limited, and needs internet |
| Keeps your fixes: edit a game or DLC title and every run uses it (Using the db) | No way to change a name without editing the script |
| Keeps game titles for folders with only DLC, or no PKGs | DLC PKGs only contain the DLC's own name, so the game title would be unknown |
| Gives one title per game, taken from the base game, for all its files | Patch PKGs sometimes word the title differently |
Holds the region used by --add-region |
|
| Records every PKG you have, with content ID, version and type |
- Title: comes from the PKG's
param.sfo. The English localized title (TITLE_01) is used when the PKG has one. The title is taken from the base game PKG, or from a patch if there's no base game. Edit it to rename the game everywhere. - Region: comes from the content ID prefix:
UP= USA,EP= EUR,JP= JPN,HP= ASIA,KP= KOR. Homebrew is markedHB.--add-regionuses it. - Console:
PS4orPS5, detected from the PKG or game folder: PS4 PKGs andparam.sfogivePS4, and PS5 PKGs andparam.jsongivePS5.--add-consoleuses it.- Classics: the PKG can't reveal that a game is really a PS1 or PS2 classic repackaged for PS4, so set
PS1,PS2orPS3by hand. Your value is kept. - Older dbs: a db from before this column existed gets it filled in for every game found on the next run.
- Classics: the PKG can't reveal that a game is really a PS1 or PS2 classic repackaged for PS4, so set
- Missing games: an ID with only DLC, or only a folder name, is reported as not in the db and has to be added by hand.
- Lines: one line per PKG file and version.
- ContentID: the PKG's content ID. A base game and its patches share one, and each DLC has its own.
- Version: the version the PKG is known by. That's
APP_VERfor patches andVERSIONfor base games and DLC. See Version under Name style options. - Type:
base,patchordlc, orappfor a game folder (see Game folders). - TitleID: the game the PKG belongs to.
- Title: the title as written in that PKG. For DLC it's the DLC's name. For base games and patches it's the game title as the PKG spells it.
- What's used for naming:
- Every PKG type can be renamed through its Title, whether base game, patch or DLC. The Title's text, without the game title at its start, becomes the name's label. The label comes right after the game title by default, or wherever
--orderputs it:Bloodborne The Old Hunters [CUSA00900] [dlc].pkg,Bloodborne Complete Edition [CUSA00900] [base].pkg. - DLC: the Title is always used, since it's the DLC's name.
- Base games and patches: the Title is used only once you've edited it, i.e. it differs from the title inside the PKG. Until then it's a record, which the script also uses to recognise the original game title at the start of DLC names. See Using the db.
- Every PKG type can be renamed through its Title, whether base game, patch or DLC. The Title's text, without the game title at its start, becomes the name's label. The label comes right after the game title by default, or wherever
- What's only a record: type and version are always read from the PKG itself. The PKGS section is a record of your collection, and a newer patch simply adds a new line.
The db is plain text, so you can open it in any text editor. After editing, do a dry run to check the new names, then --apply. The examples assume the script's folder is ps4-pkg-title-renamer/ inside your games folder.
Rename a game. Edit its title in the GAMES section:
CUSA00900|Bloodborne™|USA|PS4 -> CUSA00900|Bloodborne GOTY|USA|PS4
The game's folder and all its PKGs follow, in whatever style you use: Bloodborne GOTY [CUSA00900]/Bloodborne GOTY [CUSA00900] [patch].pkg. DLC names follow too, keeping their DLC part: Bloodborne GOTY The Old Hunters [CUSA00900] [dlc].pkg. Use this to fix a lookup that missed an edition suffix, e.g. DoDonPachi DaiOuJou becomes DoDonPachi DaiOuJou Re-incarnation, or to shorten long titles.
Rename any PKG (base game, patch or DLC). Edit the last field, Title, of its PKGS line:
UP9000-CUSA00900_00-BLOODBORNE000000|01.04|base|CUSA00900|Bloodborne™
-> ...|base|CUSA00900|Bloodborne™ Complete Edition
UP1004-CUSA23501_00-GTATHREE00000001|01.08|patch|CUSA23501|Grand Theft Auto III – The Definitive Edition
-> ...|patch|CUSA23501|Grand Theft Auto III – The Definitive Edition Soundtrack Restoration Mod
UP9000-CUSA00900_00-SPEXPANSIONDLC03|01.00|dlc|CUSA00900|Bloodborne The Old Hunters
-> ...|dlc|CUSA00900|The Old Hunters Expansion
On the next --apply:
Bloodborne Complete Edition [CUSA00900] [v1.04] [base].pkg
Grand Theft Auto III – The Definitive Edition Soundtrack Restoration Mod [CUSA23501] [v1.08] [patch].pkg
Bloodborne The Old Hunters Expansion [CUSA00900] [v1.00] [dlc].pkg
- How the Title is used: the game title at the start of a Title isn't repeated. What's left is the PKG's label, placed right after the game title, or wherever
--orderputslabel. You can write the Title with or without the game title:Complete EditionandBloodborne™ Complete Editiongive the same name. - Removing a label: restore the original Title, i.e. what the PKG says.
- DLC: always use their Title. This is the way to give a Japanese-only DLC an English name, since DLC titles are never looked up online.
- Base games and patches: use their Title only once it differs from the title inside the PKG.
- New PKGs: if a PKG isn't in the db yet, run a dry run first. It adds every new PKG to the db, so you can edit the line and then
--apply. - One line per content ID, type and version: a line applies to every PKG with the same content ID, type and version. A mod patch built from an official patch usually has exactly the same
param.sfovalues as that patch. If both are on the drive, they share one line, so the label applies to both, and they'd get the same name. The second one is then reported as an error and left alone.
Change or fix a region tag (--add-region). Edit the Region field of the game. The recognised values are USA, EUR, JPN, ASIA, KOR and HB. Any other value is kept in the db but isn't added as a tag.
Name a game the script can't find. A folder or file with a title ID but no base game or patch PKG, e.g. only DLC, is reported as ID not in db. Add a GAMES line yourself and run again:
CUSA12345|My Game|USA
See what you have. The PKGS section lists every PKG, with its type and version:
grep '|patch|' ps4-pkg-title-renamer/ps4_titles.db # every patch and its version
grep '|dlc|CUSA00900|' ps4-pkg-title-renamer/ps4_titles.db # all DLC of one game
grep 'CUSA00900' ps4-pkg-title-renamer/ps4_titles.db # everything for one gameSelect-String '\|patch\|' ps4-pkg-title-renamer\ps4_titles.db # WindowsA game with several patch lines has had more than one patch version on your drive. The db keeps a line for each version it has seen.
Open it in Excel. --export-xlsx writes the db as a spreadsheet you can sort and filter:
python3 ps4-pkg-title-renamer/ps4_rename.py --export-xlsx # -> ps4-pkg-title-renamer/ps4_titles.xlsx
python3 ps4-pkg-title-renamer/ps4_rename.py --export-xlsx my_games.xlsx # or choose the file| Sheet | Columns |
|---|---|
| Games | Title ID, Title, Region, Base version, Latest patch, DLC (count) |
| PKGs | Title ID, Game, Type, Version, Content ID, Title in db (the DLC name or your label) |
- Layout: the header row is bold and stays visible when you scroll, and every column has a filter.
- Values: all values are text, so versions keep their exact form, e.g.
01.07. - Up to date: before exporting, the db is updated from
PATHthe way a normal run does it, so the workbook is complete.--no-auto-dbexports the db as it is. - Format: the file is
.xlsx, which Excel, LibreOffice, Google Sheets and Numbers all open. It's written with Python's standard library, so nothing needs installing.--export-xlsworks as another name for the option, but the file is still.xlsx, not the old binary.xlsformat. - One-way: the workbook is only an export. Edits you make in it aren't read back, so edit
ps4_titles.dbto change names.
Work offline. Once the db holds the English names, runs don't need internet. --offline skips the online lookup for any new game.
Use the same names on another machine. Copy ps4_titles.db next to the script there. Your edited titles, DLC names and English names come along. It's plain UTF-8 text, so it works on Linux, macOS and Windows.
Back up your edits. Git ignores the db, so copy ps4_titles.db somewhere safe before --build-db --rebuild. A rebuild starts from the PKGs again and discards every edit.
- Location: the db is always
ps4_titles.dbnext to the script.--db FILEoverrides this. Aps4_titles.dbleft inPATHby older versions is merged into it automatically and then removed. - Your edits are kept:
--build-dbonly adds games and PKGs that aren't in the db yet. Use--rebuildto start over. - Automatic updates: a normal run checks every PKG first. If a game or PKG isn't in the db, or there's no db yet, it runs
--build-dbbefore renaming, so you never need to run--build-dbyourself. Use--no-auto-dbto turn this off. - Older dbs: a db from an older version, with the games section only, keeps working and gets its PKGS section on the next run.
ps4_titles.db isn't part of the repo and is listed in .gitignore. It's created on the first run and grows as new games are found. Because git ignores it, it's safe to keep next to the script in a clone, and git pull never conflicts with it.
Some Asian releases only have a Japanese or Korean title. For those, --build-db searches English Wikipedia and then Wikidata, and only accepts results described as a video game:
CUSA10207: 배틀 가레가 Rev.2016 -> Battle Garegga Rev.2016
CUSA32997: 怒首領蜂大往生 臨廻転生 -> DoDonPachi DaiOuJou
- Only game descriptions accepted: results describing a studio, a person or a series are rejected, and parts of a title shorter than 2 characters aren't searched. A wrong English name is worse than none.
- Edition suffixes: the lookup often returns the original game's name, so an edition suffix may be missing. Edit the db if you want the exact PS4 name.
- Nothing found: the original title is kept.
- DLC titles are never looked up: searches for them return the base game, its studio or its director, not the DLC. A non-English DLC title stays as in the PKG, and you can edit it in the PKGS section.
- Requests are limited to about one per second to respect Wikimedia's rate limits.
Every PS4 PKG is named from its own param.sfo, whatever it's currently called. The PKG type is a tag like the others, [base], [patch] or [dlc]. In the default order, shown here, it's the last tag:
<title>[ <ID>][ <region>][ <version>][ <content ID>] [base].pkg
<title>[ <ID>][ <region>][ <version>][ <content ID>] [patch].pkg
<title> <DLC title>[ <ID>][ <region>][ <version>][ <content ID>] [dlc].pkg
<title>: the game title. It's always there, except in.pkgfile names with--no-title, where it's left out and the name starts with the DLC title or the first tag.- DLC title: comes right after the game title, before every tag, so the full name of a DLC reads as one piece, e.g.
Bloodborne The Old Hunters. - Tags:
[ID]with--add-id,[region]with--add-region, plus version and content ID. Each is joined with--sepand written in brackets unless you use--no-brackets. - Type tag: last by default.
--no-typeleaves it out. - Order:
--orderrearranges all of these parts in file names. See File part order. - Folders: named
<title>[ <ID>][ <region>], e.g.Bloodborne [CUSA00900] [USA]/.
CATEGORY in param.sfo |
Type | Default | --add-id |
--no-title --add-id |
|---|---|---|---|---|
gd, gde |
base game / app | Bloodborne [base].pkg |
Bloodborne [CUSA00900] [base].pkg |
CUSA00900 [base].pkg |
gp |
patch | Bloodborne [patch].pkg |
Bloodborne [CUSA00900] [patch].pkg |
CUSA00900 [patch].pkg |
ac |
DLC / add-on | Bloodborne The Old Hunters [dlc].pkg |
Bloodborne The Old Hunters [CUSA00900] [dlc].pkg |
The Old Hunters [CUSA00900] [dlc].pkg |
| folder | Bloodborne/ |
Bloodborne [CUSA00900]/ |
Bloodborne [CUSA00900]/ (folders keep the title) |
- DLC names: the DLC title comes from the DLC PKG's
param.sfo. It goes right after the game title, before the ID and all other tags, joined with the normal separator (a space, or--sep). If it starts with the game title, that part isn't repeated: "Bloodborne The Old Hunters" becomesBloodborne The Old Hunters [CUSA00900] [dlc].pkg, notBloodborne Bloodborne The Old Hunters …. A DLC title that doesn't start with the game title is simply added after it:Pre-orderbecomesFANTASY LIFE i - The Girl Who Steals Time Pre-order [dlc].pkg. With--no-title, only the DLC's own part is kept, since the game title is left out:The Old Hunters [CUSA00900] [dlc].pkg. - Folders:
- A folder with a title ID in its name is renamed to its game's name, keeping any other text:
CUSA00900 backup/becomesBloodborne backup/. - A folder without an ID is only renamed when its name starts with the game title and all the PKGs directly inside it belong to that game. That's what lets a folder renamed earlier as
Bloodborne/be switched toBloodborne [CUSA00900]/and back.
- A folder with a title ID in its name is renamed to its game's name, keeping any other text:
- Other files: files that aren't PS4 PKGs and have no ID, such as logs, are left alone.
- Duplicate names: two patches for the same game in one folder would both become
Bloodborne [patch].pkg. The second one is logged as an error and left as it is. Dry runs catch this too. Use--add-versionto give each patch its own name, e.g.Bloodborne [v1.04] [patch].pkgandBloodborne [v1.09] [patch].pkg. With--no-type, a base game and its patch collide the same way, so combine--no-typewith--add-version.
These options can be combined freely:
| Option | Effect | Applies to | Example |
|---|---|---|---|
--add-id |
adds the title ID after the title | folders and files | Bloodborne [CUSA00900] [patch].pkg |
--no-title |
leaves the game title out, and writes the first part without brackets. Needs --add-id or --add-content-id |
.pkg files and game folders |
CUSA00900 [patch].pkg |
--add-version |
adds a version tag before the type tag | .pkg files |
Bloodborne [v1.09] [patch].pkg |
--add-content-id |
adds a content ID tag before the type tag | .pkg files |
Bloodborne [UP9000-CUSA00900_00-BLOODBORNE000000] [patch].pkg |
--no-type |
leaves out the type tag | .pkg files |
Bloodborne [v1.09].pkg |
--add-region |
adds the region tag (from the db) after the title/ID | folders and files | Bloodborne [CUSA00900] [USA] [patch].pkg |
--add-console |
adds the console tag (from the db) after the region | folders and files | Bloodborne [CUSA00900] [PS4] [patch].pkg |
--sep SEP |
uses SEP instead of spaces, in titles and between tags |
folders and files | --sep _: Grand_Theft_Auto_V_[CUSA00419]_[patch].pkg |
--no-brackets |
writes tags without [ ] |
folders and files | Bloodborne CUSA00900 v1.09 patch.pkg |
Examples with several options:
--add-id --add-version --add-content-id
Bloodborne [CUSA00900]/
├── Bloodborne [CUSA00900] [v1.00] [UP9000-CUSA00900_00-BLOODBORNE000000] [base].pkg
├── Bloodborne [CUSA00900] [v1.09] [UP9000-CUSA00900_00-BLOODBORNE000000] [patch].pkg
└── Bloodborne The Old Hunters [CUSA00900] [v1.00] [UP9000-CUSA00900_00-SPEXPANSIONDLC03] [dlc].pkg
--add-id --add-version --sep _
Grand_Theft_Auto_V_[CUSA00419]/
└── Grand_Theft_Auto_V_[CUSA00419]_[v13.37]_[patch].pkg
--no-title --add-id --add-version
Bloodborne [CUSA00900]/
├── CUSA00900 [v1.04] [base].pkg
├── CUSA00900 [v1.09] [patch].pkg
└── The Old Hunters [CUSA00900] [v1.00] [dlc].pkg
--no-title --add-id --no-brackets --sep _
Bloodborne_CUSA00900/
├── CUSA00900_base.pkg
└── The_Old_Hunters_CUSA00900_dlc.pkg
--add-version --no-type
Bloodborne/
├── Bloodborne [v1.00].pkg
├── Bloodborne [v1.09].pkg
└── Bloodborne The Old Hunters [v1.00].pkg
-
Version: read from the PKG's
param.sfo, orparam.jsonfor PS5. The field used depends on the type:Type Field Why patch APP_VERthe version the patch updates the game to. A patch's VERSIONis usually01.00base game VERSIONthe version the base PKG was built at, e.g. v1.07for a base PKG that already contains updates. A base PKG'sAPP_VERis always01.00DLC VERSIONDLC has no APP_VERPS5 PKG or game folder contentVersionthe game version including updates, e.g. 02.002.000givesv2.002.000.masterVersionis only used if there's nocontentVersionLeading zeros of the first number are dropped, and the rest is kept as is:
01.09becomesv1.09, and01.000.000becomesv1.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
.pkgfiles and to game folders. 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.pkgfile names and game folders only. It must be combined with--add-idor--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, orv1.09 [CUSA00900] [patch].pkgwith--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. -
--sep:SEPcan be any characters that are valid in file names, e.g._,.or-.--sep ""removes spaces entirely.- It replaces the spaces the script generates, in titles, DLC titles and between tags, including before the type tag:
Bloodborne_The_Old_Hunters_[CUSA00900]_[dlc].pkg. - Text the script doesn't generate keeps its spaces, e.g.
backupinBloodborne backup/.
-
--no-brackets: tags are then separated only bySEP. The script still recognises its own names when you switch styles later. -
Switching styles: each style is applied in full on every run. See Running again.
--order sets the order of the parts in .pkg file names. Folders always keep title [ID] [region]. The parts are:
| Part | What it is | Shown when |
|---|---|---|
title |
the game title | always, except with --no-title |
label |
the DLC name, or a label from the db (see Using the db) | DLC, and PKGs you've labelled |
id |
[CUSA00900] |
--add-id |
region |
[USA] |
--add-region |
console |
[PS4] / [PS5] |
--add-console |
version |
[v1.09] |
--add-version |
cid |
[UP9000-CUSA00900_00-BLOODBORNE000000]. content-id also works as the name |
--add-content-id |
type |
[base] / [patch] / [dlc] |
unless --no-type |
The default order is title,label,id,region,console,version,cid,type. List the parts you want first. The rest follow in the default order:
--add-id --add-version Bloodborne [CUSA00900] [v1.09] [patch].pkg
--add-id --add-version --order id,title [CUSA00900] Bloodborne [v1.09] [patch].pkg
--add-id --add-version --order type,version [patch] [v1.09] Bloodborne [CUSA00900].pkg
--no-title --add-id --add-version --order version v1.09 [CUSA00900] [patch].pkg
--add-id --add-region --no-brackets --sep _ --order region,id
USA_CUSA00900_Bloodborne_The_Old_Hunters_dlc.pkg
- Positions only:
--orderonly changes where parts go. Whether a tag appears still depends on its option. - Checked: an unknown or repeated part name stops the script with an error.
- Changing order later: file names are rebuilt from
param.sfoon every run, so you can change the order at any time. Undo keeps working.
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.000.000] [base].pkg
- How they're read: a PS5 PKG starts with
\x7fFIHinstead of PS4's\x7fCNT. The value at offset0x58points to a PS4-style metadata block inside it, whose entry0x2000is the game'sparam.json. The script jumps straight there and reads a few KB, however big the PKG is. - What's used:
titleId,contentId, the EnglishtitleNameandcontentVersion, the same fields as PS5 game folders.contentVersionis the game's version including updates, e.g.02.002.000gives[v2.002.000]. The PKG'smasterVersioncan stay at01.00even 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 asPS5 pkg type 0x… not recognised yetand 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 RINGfor both PS4 and PS5 in the default style, the second one is reported with a hint to use--add-idor--add-console, and nothing is moved into the other game's folder.
Besides PKG files, the script renames extracted game folders: a PS5 game, or a dumped PS4 game, stored as a folder instead of a .pkg. It recognises them by their system file:
| Folder contains | Platform | Read from it |
|---|---|---|
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.000.000] [app]/
├── eboot.bin ├── eboot.bin (untouched)
├── PPSA03311.complete ├── PPSA03311.complete (untouched)
└── sce_sys/param.json └── sce_sys/param.json (untouched)
- One item, named like a PKG: the folder gets the same parts and options as a
.pkgfile (title, label, ID, region, version, content ID,--order,--no-title,--sep,--no-brackets), without an extension. Its type tag is[app]. A dumped PS4 patch or DLC folder gets[patch]or[dlc]. - Never entered: nothing inside a game folder is renamed or moved. That includes the game files,
sce_sys, and marker files likePPSA03311.completethat dump tools create. Loose PKGs are never moved into a game folder either. - Same db: game folders are added to
ps4_titles.dblike PKGs, as a GAMES line plus a PKGS line with typeapp. So English-name lookup, title edits and labels,--export-xlsxand every undo mode work for them too. - PS5 title IDs (
PPSA…) are recognised like PS4 ones (CUSA…), and the db records the console (PS5/PS4). - Loaders: if a PS5 loader or tool has the game registered by its folder path, you may need to add it again after renaming.
A PKG directly in PATH, rather than in a game folder, is moved into its game's folder:
- Existing folder: if one exists for that ID, like
CUSA00900/,Bloodborne [CUSA00900]/orBloodborne/, the PKG is moved there. - New folder: otherwise a folder is created, named in the current style:
Bloodborne/, orBloodborne [CUSA00900]/with--add-id. A folder holding only that game's PKGs also counts as existing. - Undo: any undo that covers the PKG, whether
--undo,--undo-lastor--undo-match, moves it back and removes the folder it created once that's empty.
Each run applies the naming options you give to everything, so re-running never renames anything twice:
-
Same options: a second run with the same options changes nothing.
-
Different options: a run with different options re-styles existing names instead of adding to them. So you can switch styles at any time:
(default) Bloodborne/Bloodborne [patch].pkg --add-id --add-version Bloodborne [CUSA00900]/Bloodborne [CUSA00900] [v1.09] [patch].pkg --no-title --add-id Bloodborne [CUSA00900]/CUSA00900 [patch].pkg --add-id --sep _ Bloodborne_[CUSA00900]/Bloodborne_[CUSA00900]_[patch].pkg (default) Bloodborne/Bloodborne [patch].pkg -
Where names come from: PKG names are rebuilt from
param.sfoevery time. Folder names are rebuilt from the title ID in the name, or from the PKGs inside. -
Undo: every switch is recorded, so undo still works across style changes.
Every --apply records each rename and move in rename_undo.log, in the script's folder, so you can reverse them later. There are three ways to undo:
| Command | Reverts | Acts |
|---|---|---|
--undo |
Everything recorded under PATH, from every --apply run |
Immediately |
--undo-last |
Only the most recent --apply run under PATH |
Preview. Add --apply to do it |
--undo-match TEXT |
Only renames whose path contains TEXT |
Preview. Add --apply to do it |
--undo-last and --undo-match can be combined, for example to undo only the matching renames from the last run. Undo always works newest first.
Run these from the games folder:
# revert everything
python3 ps4-pkg-title-renamer/ps4_rename.py --undo
# step back one --apply run at a time: preview, then do it
python3 ps4-pkg-title-renamer/ps4_rename.py --undo-last
python3 ps4-pkg-title-renamer/ps4_rename.py --undo-last --apply
# a single file
python3 ps4-pkg-title-renamer/ps4_rename.py --undo-match "Old Hunters" --apply
# one game: its folder and every file in it
python3 ps4-pkg-title-renamer/ps4_rename.py --undo-match Bloodborne --apply
# games in another folder: pass it as PATH
python3 ps4-pkg-title-renamer/ps4_rename.py ../other-games --undo-last --applyA preview lists every rename it would revert as current name -> original name and changes nothing:
/games/Bloodborne/Bloodborne The Old Hunters [dlc].pkg -> /games/Bloodborne/Bloodborne The Old Hunters.pkg (preview)
Preview only. Re-run with --apply to undo.
- What's compared: the text is compared, ignoring case, with the old and the new path of each rename, relative to
PATH. - Folder names: a game or folder name matches the folder and everything in it.
BloodbornematchesBloodborne/,Bloodborne [base].pkg,Bloodborne The Old Hunters [dlc].pkgand so on. - Title IDs: an ID only matches where it appears in the old or new name. Folders and base/patch files always had the ID in their original name. A DLC file without
--add-idusually didn't, e.g.Bloodborne The Old Hunters.pkgbecameBloodborne The Old Hunters [dlc].pkg. Use the game name to catch a whole game. - Check first: run without
--applyto see exactly what matches.
- Renamed folders: a single file can be reverted even after its folder was renamed. It's renamed back inside the folder's current name.
- Items renamed more than once: if an item was renamed again in a later run, for example a re-run with
--add-idor another style,--undo-matchreverts those later renames too. Otherwise the log would no longer match the files. - Loose PKGs: a PKG that was moved into its game folder goes back to
PATH. A folder the script created for it is removed once it's empty. If it isn't empty yet, it stays in the log and is removed by a later undo. - Several game folders: every
PATHshares the samerename_undo.log, but undo only touches entries under thePATHyou give it. Entries for other folders stay in the log. - Case-only renames: renames that only change letter case are handled on case-insensitive drives, such as NTFS and exFAT.
- Archive: reverted entries are moved to
rename_undo.log.donewith a note of what was undone and when. Entries that couldn't be restored stay inrename_undo.logso you can retry. - Runs: each
--applyrun starts with a# <timestamp>line in the log. That's how--undo-lastknows where the last run begins. - Full paths: the log records full paths. Run undo before moving or re-mounting the games folder under a different path or drive letter, and on the same OS you used for
--apply. - Never deleted automatically:
--clean-logsand log rotation never deleterename_undo.logorrename_undo.log.done. - Older versions: older versions of the script kept
rename_undo.loginPATH. It's merged into the script-folder log automatically on the next run.
All logs are kept in the script's folder, not in PATH. In a git clone, .gitignore excludes them. Every rename or undo run writes rename_results_<dryrun|apply|undo>_<timestamp>.log. Only the 5 newest are kept, and older ones are deleted automatically after each run. Use --keep-logs N to change the limit, or --keep-logs 0 to keep every log. rename_undo.log is never rotated.
=== CHANGED (143) ===
CUSA00900/CUSA00900_base.pkg -> Bloodborne [base].pkg
=== NOT CHANGED (39) ===
itemzflow/daemon.log (no game ID in name)
Bloodborne [CUSA00900]/Bloodborne [CUSA00900] [base].pkg (already named)
CUSA99999 (ID not in db: CUSA99999)
=== ERRORS (1) ===
CUSA00900/CUSA00900_patch.pkg (target already exists: Bloodborne [patch].pkg)
--apply also records every rename in rename_undo.log, which the undo options use. See Undo.
To delete old results logs:
python3 ps4_rename.py --clean-logsThis deletes every rename_results_*.log in the script's folder, plus any left in PATH by older versions. It never deletes rename_undo.log or rename_undo.log.done.
How do I rename PS4 PKG files to their game names? Put the script in your PKG folder and run a dry run, then apply:
python3 ps4-pkg-title-renamer/ps4_rename.py # preview
python3 ps4-pkg-title-renamer/ps4_rename.py --apply # renameSee Quick start for more.
What is a CUSA number / PS4 title ID?
Every PS4 game has a title ID such as CUSA00900, which is Bloodborne (USA). PKG dumps and downloads are often named only by that ID or by their content ID, e.g. UP9000-CUSA00900_00-BLOODBORNE000000. The script reads the ID and the real game title from the PKG's param.sfo and renames the files for you.
How can I tell whether a PKG is the base game, a patch (update) or DLC?
The script reads the CATEGORY field in param.sfo (gd = base game, gp = patch, ac = DLC/add-on) and tags the file [base], [patch] or [dlc]. Add --add-version to also see the version, e.g. [v1.09] for a patch.
Which version does --add-version show?
For a patch, the version it updates the game to (APP_VER in param.sfo). For a base game, the version the base PKG was built at (VERSION), because a base PKG's APP_VER is always 01.00. For example, Vice City's base PKG is v1.07 and its patch is v1.08.
Does it work with fake PKGs (fPKG), GoldHEN and Itemzflow?
It works with any PS4 PKG whose param.sfo can be read, which includes fake PKGs and homebrew. It only renames files and folders. It never changes the contents of a PKG, so the PKGs install the same way afterwards. Check whether your install tool expects the title ID in the name. If it does, use --add-id.
Can I keep the CUSA ID in the name?
Yes, --add-id gives Bloodborne [CUSA00900] [base].pkg. Add --no-title to drop the game title from file names, e.g. CUSA00900 [base].pkg, and --add-region to add [USA].
Can I undo a rename?
Yes. --undo reverts everything, --undo-last reverts the last run, and --undo-match TEXT reverts only matching names, e.g. one game or one file. See Undo.
Does it need an internet connection?
Only to look up English names for Japanese/Korean/Chinese titles, and only once per game, because results are saved in the db. Use --offline to skip the lookup.
Does it work with PS5 games? Yes, with both kinds:
- PS5
.pkgfiles (fpkg): read from theparam.jsoninside them. Base games are supported so far. See PS5 PKGs. - 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.
PS4 and PS5 versions of a game stay separate. Use --add-console to tag names [PS4] / [PS5].
Does it run on Windows? Yes, Windows 10/11, Linux and macOS, with Python 3.8+ and no other dependencies. See Installation.
-
Characters that exFAT/NTFS don't allow are replaced:
:becomes-;? * " < > |,™and®are removed or replaced. -
Existing files are never overwritten. A name collision is logged as an error and skipped.
-
Broken or unreadable PKGs: every
.pkgis checked before itsparam.sfois used. A PS4 PKG whoseparam.sfocan't be used is logged under ERRORS with the reason and left as it is. It's usually a bad or incomplete download. The possible reasons are:Reason in the log Meaning param.sfo not found in pkgthe PKG has no param.sfoentryparam.sfo corrupt or encrypted: bad signaturethe data isn't a valid, unencrypted param.sfoparam.sfo corrupt: .../pkg corrupt: ...offsets, sizes or tables point outside the file pkg unreadable: ...the file couldn't be read, e.g. permissions or a disk error - Summary: both a rename run and
--build-dbend with a count of the PKGs that couldn't be read.--build-dbalso lists each one. - Size limit: a
param.sfois never read past 1 MB, even if a corrupt header claims more. - Other
.pkgfiles: a file with a.pkgextension that isn't a PS4 PKG at all, i.e. has no PKG header, is treated like any other file. It's renamed only if its name contains a title ID, and otherwise logged asnot a PS4 pkg.
- Summary: both a rename run and
-
System Volume Information,$RECYCLE.BINand the script's own files are skipped. -
Check that your install tools don't rely on ID-only folder names: folders always include the game title. Use
--add-idto keep the ID in them too.
Copyright (C) 2026 bsgonzalezq.
This project is free software under the GNU General Public License v3.0 or, at your option, any later version (GPL-3.0-or-later):
- Free to use and share: you can use, study, change and share it freely, including commercially.
- Changes stay open: if you distribute a modified version, or a program that includes this code, it must also be released under the GPL, with its source code.
- No warranty: the software is provided as is. See LICENSE for the full terms.