diff --git a/README.md b/README.md index d7591f8..632836b 100644 --- a/README.md +++ b/README.md @@ -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//EBOOT.PBP`; a PS1 Classic diff --git a/app/nopaystation.py b/app/nopaystation.py index e700376..2bd65d9 100644 --- a/app/nopaystation.py +++ b/app/nopaystation.py @@ -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: diff --git a/data/bin/ATTRIBUTION.md b/data/bin/ATTRIBUTION.md new file mode 100644 index 0000000..d026e82 --- /dev/null +++ b/data/bin/ATTRIBUTION.md @@ -0,0 +1,36 @@ +# pkg2zip + +The `pkg2zip.exe` binary in this folder decrypts and extracts NoPayStation +`.pkg` files (PSP / PSX / PS3 / PSVita content). + +- Project: +- 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. diff --git a/data/bin/pkg2zip.exe b/data/bin/pkg2zip.exe new file mode 100644 index 0000000..5f7f02d Binary files /dev/null and b/data/bin/pkg2zip.exe differ