fix NoPayStation PSP parsing + detail-panel UnboundLocalError
- 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.
This commit is contained in:
+1
-1
@@ -682,13 +682,13 @@ class GameDetailsPanel(QWidget):
|
|||||||
self.system = item.get("system")
|
self.system = item.get("system")
|
||||||
self._ps1_kind = item.get("ps1_kind")
|
self._ps1_kind = item.get("ps1_kind")
|
||||||
path = item.get("path") or ""
|
path = item.get("path") or ""
|
||||||
|
is_ps1 = item.get("system") == "ps1"
|
||||||
if (is_ps1 and item.get("ps1_kind") == "eboot") or item.get("psp_kind") == "eboot":
|
if (is_ps1 and item.get("ps1_kind") == "eboot") or item.get("psp_kind") == "eboot":
|
||||||
self.filename.setText(Path(path).parent.name if path else "")
|
self.filename.setText(Path(path).parent.name if path else "")
|
||||||
else:
|
else:
|
||||||
self.filename.setText(Path(path).name if path else "")
|
self.filename.setText(Path(path).name if path else "")
|
||||||
self.filename.setToolTip(path)
|
self.filename.setToolTip(path)
|
||||||
self.filename.setVisible(bool(path))
|
self.filename.setVisible(bool(path))
|
||||||
is_ps1 = item.get("system") == "ps1"
|
|
||||||
is_ps1_disc = is_ps1 and item.get("ps1_kind") == "disc"
|
is_ps1_disc = is_ps1 and item.get("ps1_kind") == "disc"
|
||||||
self.play_btn.setEnabled(
|
self.play_btn.setEnabled(
|
||||||
(item.get("system") == "games" and bool(path) and Path(path).suffix.lower() == ".iso")
|
(item.get("system") == "games" and bool(path) and Path(path).suffix.lower() == ".iso")
|
||||||
|
|||||||
+36
-19
@@ -23,11 +23,24 @@ log = logging.getLogger("nopaystation")
|
|||||||
|
|
||||||
_TSV_NAMES = {"psp": "PSP_GAMES.tsv", "psx": "PSX_GAMES.tsv"}
|
_TSV_NAMES = {"psp": "PSP_GAMES.tsv", "psx": "PSX_GAMES.tsv"}
|
||||||
|
|
||||||
# TSV columns (tab-separated), in order.
|
# NoPayStation TSVs are tab-separated with a header row whose exact columns
|
||||||
_COLUMNS = (
|
# differ per platform (PSP has "Type"/"RAP" columns, PSX has "Original Name").
|
||||||
"title_id", "region", "name", "pkg_url", "zrif", "content_id",
|
# Map header names to canonical keys instead of relying on fixed positions.
|
||||||
"date", "size", "sha256",
|
_HEADER_ALIASES = {
|
||||||
)
|
"title id": "title_id",
|
||||||
|
"region": "region",
|
||||||
|
"name": "name",
|
||||||
|
"pkg direct link": "pkg_url",
|
||||||
|
"content id": "content_id",
|
||||||
|
"last modification date": "date",
|
||||||
|
"file size": "size",
|
||||||
|
"sha256": "sha256",
|
||||||
|
"zrif": "zrif",
|
||||||
|
"rap": "rap",
|
||||||
|
"download .rap file": "rap_url",
|
||||||
|
"type": "content_kind",
|
||||||
|
"original name": "original_name",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def tsv_url(content_type: str, base: str = "") -> str:
|
def tsv_url(content_type: str, base: str = "") -> str:
|
||||||
@@ -57,29 +70,32 @@ def _parse_date(value: str) -> str:
|
|||||||
def parse_tsv(text: str, content_type: str) -> List[dict]:
|
def parse_tsv(text: str, content_type: str) -> List[dict]:
|
||||||
"""Parse a NoPayStation TSV into store item dicts.
|
"""Parse a NoPayStation TSV into store item dicts.
|
||||||
|
|
||||||
Each item carries the fields the Store page expects (``name``, ``size``,
|
The header row drives column mapping (PSP and PSX TSVs differ). Each item
|
||||||
|
carries the fields the Store page expects (``name``, ``size``,
|
||||||
``release_date``, ``mtime_ns``) plus ``title_id``, ``pkg_url``, ``sha256``,
|
``release_date``, ``mtime_ns``) plus ``title_id``, ``pkg_url``, ``sha256``,
|
||||||
``content_type`` and the cover ``system`` ("games" for PSP, "ps1" for PSX).
|
``content_type`` and the cover ``system`` ("games" for PSP, "ps1" for PSX).
|
||||||
"""
|
"""
|
||||||
system = "games" if content_type == "psp" else "ps1"
|
system = "games" if content_type == "psp" else "ps1"
|
||||||
items: List[dict] = []
|
items: List[dict] = []
|
||||||
lines = text.splitlines()
|
header = None
|
||||||
for line in lines:
|
for line in text.splitlines():
|
||||||
line = line.rstrip("\r\n")
|
line = line.rstrip("\r\n")
|
||||||
if not line.strip():
|
if not line.strip():
|
||||||
continue
|
continue
|
||||||
cols = line.split("\t")
|
cols = line.split("\t")
|
||||||
# Skip the header row.
|
if header is None:
|
||||||
if cols and cols[0].strip().lower() == "title id":
|
header = [c.strip().lower() for c in cols]
|
||||||
continue
|
continue
|
||||||
if len(cols) < 5:
|
row = {}
|
||||||
continue
|
for i, key in enumerate(header):
|
||||||
row = dict(zip(_COLUMNS, cols))
|
canon = _HEADER_ALIASES.get(key)
|
||||||
name = (row.get("name") or "").strip()
|
if canon and i < len(cols):
|
||||||
pkg_url = (row.get("pkg_url") or "").strip()
|
row[canon] = cols[i].strip()
|
||||||
title_id = (row.get("title_id") or "").strip()
|
name = row.get("name") or ""
|
||||||
|
pkg_url = row.get("pkg_url") or ""
|
||||||
if not name or not pkg_url:
|
if not name or not pkg_url:
|
||||||
continue
|
continue
|
||||||
|
title_id = row.get("title_id") or ""
|
||||||
try:
|
try:
|
||||||
size = int(float(row.get("size") or 0))
|
size = int(float(row.get("size") or 0))
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
@@ -92,16 +108,17 @@ def parse_tsv(text: str, content_type: str) -> List[dict]:
|
|||||||
items.append({
|
items.append({
|
||||||
"name": name,
|
"name": name,
|
||||||
"title_id": title_id,
|
"title_id": title_id,
|
||||||
"region": (row.get("region") or "").strip(),
|
"region": row.get("region") or "",
|
||||||
"pkg_url": pkg_url,
|
"pkg_url": pkg_url,
|
||||||
"zrif": (row.get("zrif") or "").strip(),
|
"zrif": row.get("zrif") or "",
|
||||||
"content_id": (row.get("content_id") or "").strip(),
|
"content_id": row.get("content_id") or "",
|
||||||
"size": size,
|
"size": size,
|
||||||
"sha256": (row.get("sha256") or "").strip().lower(),
|
"sha256": (row.get("sha256") or "").strip().lower(),
|
||||||
"release_date": date,
|
"release_date": date,
|
||||||
"mtime_ns": mtime_ns,
|
"mtime_ns": mtime_ns,
|
||||||
"content_type": content_type,
|
"content_type": content_type,
|
||||||
"system": system,
|
"system": system,
|
||||||
|
"content_kind": row.get("content_kind") or "",
|
||||||
})
|
})
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user