Skip to content

Commit 1651af3

Browse files
authored
Merge pull request #2 from andshrew/develop
Add PKG header parsing, param.sfo download
2 parents dabb23e + 612019c commit 1651af3

6 files changed

Lines changed: 559 additions & 87 deletions

File tree

.github/workflows/publish-test-pypi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ jobs:
3636
- name: Publish to TestPyPI
3737
uses: pypa/gh-action-pypi-publish@release/v1
3838
with:
39-
repository_url: https://test.pypi.org/legacy/
39+
repository-url: https://test.pypi.org/legacy/
4040
password: ${{ secrets.TEST_PYPI_API_TOKEN }}

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2023 andshrew
3+
Copyright (c) 2023, 2025 andshrew
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pip install ps4-updates
88
```
99

1010
## Typical Usage
11-
Create a `Ps4TitleUpdate` object by specifying a PS4 Title Id (eg. `CUSA00001_00` or `CUSA00001`).
11+
Create a `Ps4TitleUpdate` object by specifying a PS4 Title Id (eg. `CUSA00001_00` or `CUSA00001`). A list of known Title Ids is [available here](https://andshrew.github.io/PlayStation-Titles/?platform=ps4&hasContentId).
1212

1313
Invoke `get_update()` on the object to begin retrieving information about the update. If an update is available it will try to retrieve the following:
1414

@@ -19,11 +19,12 @@ Invoke `get_update()` on the object to begin retrieving information about the up
1919
* Download Size
2020
* Update Creation Date
2121
* changeinfo.xml (developer included update notes)
22+
* param.sfo update pkg parameters
2223

2324
## Limitations
2425
Only information about the current update version can be retrieved.
2526

26-
It is not a guarantee that changeinfo.xml will be included within the updates pkg file. The file is typically located at the start of the file, however it does not appear to be in a fixed location. This package attempts to locate it by downloading up to the first 30MB of the pkg file. You can increase (or decrease) this search range by setting `byte_limit` when creating a `Ps4TitleUpdate` object.
27+
It is not a guarantee that `changeinfo.xml` will be included within the updates pkg file. This package attempts to locate it (and `param.sfo`) by parsing the update PKG file header. By default it will download up to the first 50MB of the PKG file, but if either the `changeinfo.xml` or `param.sfo` are located beyond this range then neither will be downloaded and no more data will be downloaded beyond the range of the PKG header. You can increase (or decrease) this limit by setting the `byte_limit` when creating a `Ps4TitleUpdate` object.
2728

2829
## Usage Examples
2930

@@ -49,7 +50,6 @@ title.print_update_info()
4950

5051
#### Console Output
5152
```
52-
vscode ➜ /workspaces/PS4-Updates-Python (main) $ python app.py
5353
Title Id: CUSA00001
5454
Update Url: http://gs-sec.ww.np.dl.playstation.net/plo/np/CUSA00001/1123f23c1f00810a5e43fcb409ada7823bc5ad21b357817e314b6c4832cf6f9f/CUSA00001-ver.xml
5555
Title Name: THE PLAYROOM
@@ -122,12 +122,68 @@ You can manually invoke `_get_partial_pkg_file()`, which makes the following ava
122122
| update_pkg_exists | `True` if some data was found in pkg file at `update_pkg_url` |
123123
| update_pkg_cdate | Update creation date as string YYYYMMDD |
124124
| update_pkg_cdate_as_date | Update creation date as datetime |
125+
| update_pkg_param_sfo | An `SFO` object if the pkg param.sfo file was found and parsed |
126+
| update_pkg_bytes_exceeded | `True` if the pkg file header was parsed but data exists beyond the range of the specified `bytes_limit` |
125127
| changeinfo_exists | `True` if changeinfo.xml was found |
126128
| changeinfo | List of dicts for each change in changeinfo.xml |
127129
| changeinfo_count | Number of changes in changeinfo.xml |
128130
| changeinfo_current_exists | `True` if a change matching the current version number was in changeinfo.xml |
129131
| changeinfo_current | List of dicts for change matching the current version |
130132
| changeinfo_xml | Full XML for changeinfo.xml
131133

134+
## `SFO` and `SFO_Entry` Object Reference
135+
By default, if an update exists then `get_update()` will download and attempt to parse the beginning of the updates pkg file. If the [`param.sfo`](https://www.psdevwiki.com/ps4/Param.sfo) file is located then the entries that it contains will be parsed into `SFO_Entry` objects and attached to a single `SFO` object that is then accessible from the `update_pkg_param_sfo` attribute of a `Ps4TitleUpdate` object.
136+
137+
For details of the information that might be in these objects, see the [Parameter Descriptions on psdevwiki.com](https://www.psdevwiki.com/ps4/Param.sfo#Parameters_Descriptions).
138+
139+
The entries data (as bytes) is saved in the `SFO_Entry` objects `data_bytes` attribute. Your application will need to further parse this information into a usable format.
140+
141+
### Example for parsing the SAVE_DATA_TRANSFER_TITLE_ID_LIST parameter
142+
There will be an entry in the param.sfo file named `SAVE_DATA_TRANSFER_TITLE_ID_LIST` if the title supports reading another titles save data files (ie. for save transfer between games).
143+
144+
This example will print a titles update information to the screen, and then additionally print information from this specific SFO entry (if it exists).
145+
146+
```python
147+
from ps4_updates import title as ps4up
148+
149+
title = ps4up.Ps4TitleUpdate('CUSA00897')
150+
title.get_update()
151+
title.print_update_info()
152+
153+
if title.update_pkg_exists is True:
154+
entry = next((x for x in title.update_pkg_param_sfo.entries if x.name == "SAVE_DATA_TRANSFER_TITLE_ID_LIST"), None)
155+
if entry is not None:
156+
entry = entry.data_bytes.decode().strip('\x00').split('\n')
157+
if len(entry) == 1:
158+
print(f'This title shares save data with {len(entry)} title:')
159+
if len(entry) > 1:
160+
print(f'This title shares save data with {len(entry)} titles:')
161+
if len(entry) > 0:
162+
entry = sorted(entry, key=lambda x: x)
163+
for i in entry:
164+
print(f'\t{i}')
165+
```
166+
#### Console Output
167+
```
168+
Title Id: CUSA00897
169+
Update Url: http://gs-sec.ww.np.dl.playstation.net/plo/np/CUSA00897/7d49cb7e0fd38b63970664874c3f4149fd86446456cc020a6555afaa79a10239/CUSA00897-ver.xml
170+
Title Name: inFAMOUS™ First Light
171+
Content Id: EP9000-CUSA00897_00-FIRSTLIGHTSHIP00
172+
Current Version: 01.04
173+
Download Size: 2.38 GB
174+
Creation Date: Fri, 18-Nov-2016
175+
176+
01.04
177+
- Graphics Bug Fixes
178+
179+
This title shares save data with 5 titles:
180+
CUSA00004
181+
CUSA00223
182+
CUSA00263
183+
CUSA00305
184+
CUSA00309
185+
```
186+
132187
## Additional Thanks
133-
[Zer0xFF](https://gist.github.com/Zer0xFF/d94818f15e3e85b0b4d48000a4be1c73) - sharing the method for generating a title update URL
188+
[Zer0xFF](https://gist.github.com/Zer0xFF/d94818f15e3e85b0b4d48000a4be1c73) - sharing the method for generating a title update URL
189+
[psdevwiki](https://www.psdevwiki.com/ps4) - documentation on [PKG file format](https://www.psdevwiki.com/ps4/PKG_files) and [param.sfo files](https://www.psdevwiki.com/ps4/Param.sfo)

0 commit comments

Comments
 (0)