nps: bundle pkg2zip binary and run it via Wine
pkg2zip's prebuilt releases are Windows-only, so ship pkg2zip.exe in data/bin/ (MIT, mmozeiko) and invoke it through Wine on Linux. find_pkg2zip prefers the bundled binary, then a configured path, then a native pkg2zip on PATH. Adds data/bin/ATTRIBUTION.md and README credit.
This commit is contained in:
@@ -38,8 +38,8 @@ converts PlayStation 1 ISO/CUE/BIN rips into PSP `EBOOT.PBP` homebrew.
|
||||
- Linux + Python 3
|
||||
- `PySide6` — the only Python dependency (`pip install -r requirements.txt`)
|
||||
- `7z` (p7zip) — used to peek/extract disc images from store archives
|
||||
- `pkg2zip` (optional) — decrypts NoPayStation `.pkg` files (see
|
||||
[NoPayStation](#4-nopaystation))
|
||||
- `pkg2zip` (bundled in `data/bin/`, run via Wine on Linux) — decrypts
|
||||
NoPayStation `.pkg` files (see [NoPayStation](#4-nopaystation))
|
||||
- PPSSPP (optional) — to launch discs from the details panel
|
||||
|
||||
## Install
|
||||
@@ -105,6 +105,8 @@ Discs are matched by hash first (most precise), then serial, then filename.
|
||||
to drawn art when they're absent.
|
||||
- `data/nps/` — NoPayStation TSV lists (cached here on first store scan; drop
|
||||
`PSP_GAMES.tsv` / `PSX_GAMES.tsv` manually to work offline).
|
||||
- `data/bin/pkg2zip.exe` — bundled `pkg2zip` binary (MIT, by mmozeiko) used to
|
||||
decrypt NoPayStation `.pkg` files; see `data/bin/ATTRIBUTION.md`.
|
||||
- State dir (`~/.local/state/psp-preserve/` by default, or `$XDG_STATE_HOME/psp-preserve`):
|
||||
- `library.sqlite` — the catalog + library database.
|
||||
- `covers/` — downloaded cover cache.
|
||||
@@ -274,10 +276,10 @@ next to the source selector.
|
||||
|
||||
Requirements & behaviour:
|
||||
|
||||
1. Install [`pkg2zip`](https://github.com/mmozeiko/pkg2zip) (the same tool the
|
||||
pkgi family uses) and either put it on `PATH` or set its path in
|
||||
**Settings → Store**. NoPayStation `.pkg` files are encrypted PSN packages,
|
||||
not ZIPs — `pkg2zip` decrypts them.
|
||||
1. `pkg2zip` decrypts the `.pkg` files (they're encrypted PSN packages, not
|
||||
ZIPs). A copy ships in `data/bin/pkg2zip.exe` and runs via **Wine** on
|
||||
Linux — just make sure Wine is installed. You can also put a native
|
||||
`pkg2zip` on `PATH` or set its path in **Settings → Store**.
|
||||
2. Set **NoPayStation output dir** in **Settings → Store** (default
|
||||
`$PSP_STATE_DIR/nps`).
|
||||
3. Downloading a PSP game writes `PSP/<TITLE_ID>/EBOOT.PBP`; a PS1 Classic
|
||||
|
||||
+23
-3
@@ -9,6 +9,7 @@ folder.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import urllib.parse
|
||||
@@ -142,14 +143,30 @@ def fetch_items(content_type: str, url: str = "", timeout: int = 60) -> List[dic
|
||||
|
||||
|
||||
def find_pkg2zip(configured_path: str = "") -> Optional[Path]:
|
||||
"""Locate the pkg2zip binary (configured path, else PATH)."""
|
||||
"""Locate pkg2zip: configured path, then the bundled binary, then PATH."""
|
||||
if configured_path:
|
||||
p = Path(configured_path)
|
||||
return p if p.is_file() else None
|
||||
bundled = config.DATA_DIR / "bin" / "pkg2zip.exe"
|
||||
if bundled.is_file():
|
||||
return bundled
|
||||
found = shutil.which("pkg2zip")
|
||||
return Path(found) if found else None
|
||||
|
||||
|
||||
def _pkg2zip_cmd(pkg2zip: Path) -> List[str]:
|
||||
"""Command prefix for pkg2zip, wrapping the bundled .exe in Wine on Linux."""
|
||||
if pkg2zip.suffix.lower() == ".exe" and os.name != "nt":
|
||||
wine = shutil.which("wine") or shutil.which("wine64")
|
||||
if not wine:
|
||||
raise RuntimeError(
|
||||
"The bundled pkg2zip is a Windows binary and Wine is not installed — "
|
||||
"install Wine (or point Settings → Store at a native pkg2zip)."
|
||||
)
|
||||
return [wine, str(pkg2zip)]
|
||||
return [str(pkg2zip)]
|
||||
|
||||
|
||||
def _safe_folder(value: str) -> str:
|
||||
import re
|
||||
cleaned = re.sub(r"[^A-Za-z0-9]", "", value or "").upper()
|
||||
@@ -180,10 +197,13 @@ def extract_pkg(pkg_path, title_id: str, dest_dir, pkg2zip: Path,
|
||||
if progress_cb is not None:
|
||||
progress_cb("Extracting", 0.0, "")
|
||||
try:
|
||||
cmd = _pkg2zip_cmd(pkg2zip) + ["-x", str(pkg_path)]
|
||||
env = dict(os.environ)
|
||||
env["WINEDEBUG"] = "-all" # silence Wine's console chatter
|
||||
proc = subprocess.Popen(
|
||||
[str(pkg2zip), "-x", str(pkg_path)],
|
||||
cmd,
|
||||
cwd=str(tmp), stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
text=True, bufsize=1,
|
||||
text=True, bufsize=1, env=env,
|
||||
)
|
||||
assert proc.stdout is not None
|
||||
for _line in proc.stdout:
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# pkg2zip
|
||||
|
||||
The `pkg2zip.exe` binary in this folder decrypts and extracts NoPayStation
|
||||
`.pkg` files (PSP / PSX / PS3 / PSVita content).
|
||||
|
||||
- Project: <https://github.com/mmozeiko/pkg2zip>
|
||||
- Author: Marcin Mikołajczak (mmozeiko)
|
||||
- Version: v1.8 (bundled)
|
||||
- License: MIT
|
||||
|
||||
The Windows binary is run through Wine on Linux/macOS (see
|
||||
`app/nopaystation.py`).
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Marcin Mikołajczak (mmozeiko)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Binary file not shown.
Reference in New Issue
Block a user