Library covers used the same QThread+worker architecture as the store but
never deleted finished threads/loaders, so every reload leaked one QThread
and one CoverLoader. Library item loading leaked its QThread too.
CoverShowcase now removes + deleteLater's loaders on their finished signal
and deletes their threads on thread.finished; MainWindow.load_library deletes
the finished worker and thread instead of only untracking them.
StorePage cover/date loaders were never removed from tracking once their
thread finished, and _populate/_begin_scan dropped the whole list while
threads were still running. That garbage-collected QObjects whose QThread
had already been deleted, leaving a dangling thread affinity that crashed
Qt (SIGSEGV) when searching the store after it fully loaded.
Loaders now remove themselves and deleteLater on their finished signal, and
the tracking list is kept until each thread winds down.
- config: point SSL at certifi bundle when frozen (fixes store/NPS/TMDB SSL errors)
- gui: set app name + window icon for the taskbar
- spec: contents_directory=psp-preserve; bundle a .desktop file for Wayland launchers
- Rework Settings tab into grouped sections
- Add preferred-region matching and full-hash-by-default setting
- Replace combo-box square arrow with a proper chevron
- Fix UMD Refresh button (clicked bool was clearing the view)
- Remove pkg2zip.exe fallback (pure-Python decryptor is the primary path)
- Move LAN IP/share paths to .env; use example defaults in config
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.
- Save icon bumped to 56x40.
- Added a checkbox column for multi-select and a 'Delete selected' button.
- Right-click context menu on a row offers Export (copy the save folder to a
chosen dir) and Delete (remove from all locations, with confirmation).
The Save column now displays a small (40x32, letterboxed) icon from the
save folder's ICON0.PNG when present, using the first location (PSP,
PPSSPP, cloud) that has one.
Cancelling the store scrape now closes the dialog and drops its reference
immediately, so queued progress signals can't re-show it (QProgressDialog
re-shows on setValue while a value is pending). _scraping stays true until
the worker finishes to prevent a second concurrent scrape.
- PSP_GAMES.tsv and PSX_GAMES.tsv use different headers (PSP adds Type/RAP
columns, PSX adds Original Name). Parse the header row and map columns by
name instead of hardcoding positions — PSP names were showing as 'Minis'/
'PC Engine' (the Type column) with broken download URLs.
- GameDetailsPanel.set_item referenced is_ps1 before it was assigned, raising
UnboundLocalError and leaving the detail panel stale.
New 'NoPayStation' option in the Store tab lists PSP_GAMES.tsv and
PSX_GAMES.tsv, downloads each item's encrypted .pkg and decrypts/extracts
it with pkg2zip into a configurable output dir (<dir>/PSP/<TITLE_ID>/ and
<dir>/PSX/<TITLE_ID>/). Downloaded PSP games and PS1 Classics appear in the
Library (games/eboot and ps1/eboot respectively) and copy to the PSP as
PSP/GAME folders.
- app/nopaystation.py: TSV fetch/parse (cached) + pkg2zip discovery/extract.
- app/transfers.py: NoPayStationSource (scan + download).
- Settings: NPS output dir + pkg2zip path (QSettings nps_dir/pkg2zip_path).
- StorePage: NPS source + content-type combo (PSP Games / PS1 Classics),
per-item cover system, TSV release dates, nps-download job kind.
- Library: _nps_library_items ingest, on-PSP detection, folder copy/delete,
PPSSPP play disabled for encrypted PSP EBOOTs.
- README: document the source, pkg2zip + npdrm_free requirements.
Add a muted, selectable filename line under the title in both details
panels, with the full path as its tooltip (archive name in the Store,
disc/ISO filename in the Library).
PS1 EBOOTs install as PSP/GAME/{category}/{GAME_ID}/EBOOT.PBP, which the
PSP index ignored (it only indexed ISO games/videos), so the app never
marked them 'on PSP'. Index homebrew EBOOTs by folder id + embedded title,
match PS1 library items against them, and make 'Delete from PSP' remove the
whole game folder.
Library covers go back to libretro -> OpenVGDB -> ScreenScraper ->
Wikipedia -> IGDB (last resort) for all systems, including PS1. The EBOOT
ICON0 (ps1_art) alone now tries IGDB first for clean banner-less box art,
falling back to the normal pipeline.