PS5 游玩记录 · 拉取与每周刷新
从 PSN 官方 gamelist v2 接口拉取 PS5 / PS4 游玩记录,生成一个单文件自包含的
HTML 仪表盘(封面 base64 内嵌,双击就能看,不依赖任何服务或目录位置),
并支持每周自动增量刷新。
When to use
- 用户要求刷新 / 更新 PS5(或 PSN)游玩记录、游戏时长统计
- 用户想从零搭一套「PSN 游玩记录 → 可视化仪表盘」
- 定时任务 / 自动化的每周刷新执行,需要判读结果并汇报增量
- 校验报「缺中文名」,需要补录译名
不适用:Steam / Switch / Xbox 等其他平台(本 skill 只处理 PSN)。
两条路径
先判断用户属于哪种,别一上来就跑刷新:
| 路径 A · 首次搭建 | 路径 B · 日常刷新 | |
|---|---|---|
| 判断依据 | 没有项目目录,或目录里没有 scripts/refresh_all.py |
已有本 skill 初始化过的目录 |
| 要做什么 | 初始化目录 → 取 NPSSO → 首次跑通 | 一条命令 → 判读 → 汇报 |
路径 B · 日常刷新(最常见)
cd {项目目录}
python scripts/refresh_all.py
{项目目录} 是用户的项目路径。Python 必须用 3.11+(脚本用了 tomllib);
如果有隔离 venv 就用 venv 的解释器(封面内嵌步骤需要 Pillow)。
一条命令跑完六步:拉取 PSN → 标注中文名 → 下载缺失封面 → 封面内嵌 → 快照注入 → 13 项校验。
任一步失败即中止,不会留下半新半旧的仪表盘。
判读输出(照做,不要变通)
退出码
| 码 | 含义 | 该做什么 |
|---|---|---|
| 0 | 成功,或按规则跳过 | 正常汇报 |
| 1 | 执行失败(网络/接口),脚本已自行重试 3 次 | 汇报失败,说明已重试过 |
| 2 | NPSSO 凭据失效 | 见下方「凭据失效」,需人工 |
| 3 | 配置错误(配置/refresh.toml) |
检查配置文件 |
这几种输出是正常行为,不是故障:
距上次成功仅 X h,跳过— 距上次成功不足 144 小时,幂等保护触发已有实例在运行(pid=…),本次跳过— 文件锁生效,防止任务堆积
遇到上面两种,直接汇报跳过原因,不要加 --force 绕过。
--force 只在用户明确要求「就是要现在跑」时才用。
凭据失效(退出码 2):日志出现「凭据失效」或「NPSSO 大概过期了」。
NPSSO 有效期约 2 个月,脚本不会重试(重试无意义)。明确告诉用户需要人工更新,步骤:
- 浏览器登录 <https://www.playstation.com>(不要用无痕模式)
- 同一浏览器访问 <https://ca.account.sony.com/api/v1/ssocookie>
- 把返回 JSON 里的
npsso值写入.secrets/psn/npsso.txt - 手动跑一次刷新
绝对不要自己伪造或猜测 npsso 值。 它等价于密码。
汇报什么
用 present_files 打开 仪表盘/游戏.html,并在回复里给出:
- 本次结果(成功 / 失败 / 跳过,跳过要说明原因)
- 游戏总数与累计时长
- 相比上次的增量(脚本会打印「新增 N 款 / +X 小时」或「数据无变化」)
- 校验通过项数与警告项
- 有新增游戏时列出游戏名
缺中文名怎么办
校验若提示「缺中文名」,说明新游戏还没有官方中文译名。
列出英文标题交给用户确认,不要自己硬译。 用户确认后,补进
scripts/annotate_game_titles_zh.py 的 TITLE_NAME_ZH 映射表。
查漏(会输出可直接粘贴的映射表条目):
python scripts/annotate_game_titles_zh.py --report
译名口径:PlayStation 中国 / 港服商店的官方简中名优先;没有官方中文的保留原名。
路径 A · 首次搭建
1. 初始化目录
python {SKILL_DIR}/scripts/setup_project.py --target {项目目录}
会复制脚本 / 配置 / 仪表盘空模板,建好 .secrets/(权限 700),
并自检 Python 版本、Pillow、Node 三项依赖。
2. 取 NPSSO
浏览器登录 <https://www.playstation.com>(不要用无痕模式),
同一浏览器再访问 <https://ca.account.sony.com/api/v1/ssocookie>,
把返回 JSON 里的 npsso 值写入 {项目目录}/.secrets/psn/npsso.txt。
> NPSSO 等价于密码,有效期约 2 个月,不要外传。脚本也能容忍把整个 JSON 粘进去。
3. 首次跑通
cd {项目目录}
python scripts/refresh_all.py
首次会走完整认证、下载全部封面,比后续增量慢一些(约 1-2 分钟)。
4.(可选)装每周定时任务
python scripts/install_schedule.py # 注册 launchd(每周一 03:00)
python scripts/install_schedule.py --status # 查看状态与下次触发
python scripts/install_schedule.py --run-now # 立即触发一次,验证真实环境
python scripts/install_schedule.py --uninstall # 卸载
仅 macOS。执行周期改 配置/refresh.toml 的 [schedule](它是唯一真相源,
不要手改 plist,会被覆盖),改完重跑安装脚本。
若注册报 Bootstrap failed: 5: Input/output error,是宿主进程权限限制
(沙箱 / 非 GUI 会话无法代为注册),plist 本身合法,让用户在自己的终端 App 里执行:
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/cn.workbuddy.ps5-refresh.plist
常见坑(都是踩过的)
- 封面必须内嵌:主表
cover是相对项目根的路径,而 HTML 在仪表盘/子目录。
补../在file://下能显示,但 HTML 一旦被静态服务托管(预览面板、上传到别处),
../会跳出服务根目录返回 404,封面墙全空。所以走 base64 内嵌,做成单文件自包含。 - 定时任务是凌晨 3 点档:launchd 选凌晨是因为它在机器休眠错过触发点时会唤醒后补跑
(cron 不会)。副作用是白天手动跑常撞上 144h 冷却被跳过 —— 这是正常的。 - PSN 接口拿不到中文名:
localizedName实测设zh-Hans-CN仍返回英文,
只能靠映射表手工维护。 - 同作品多版本不要合并:PSN 用
concept_id标识同作品,主表保持一条不动,
仪表盘提供「合并同作品版本」开关在展示层合并(两种视角总时长守恒)。 - 不要跑
scripts/_selftest_make_fixture.py:它造的是示例数据,会覆盖真实抓取结果。
该脚本未随 skill 分发。 - 时长为 0 的记录:校验会警告,可能是「点开就退」或「拥有但没玩」,
需要用户确认,不要自动删除。
其他命令
python scripts/refresh_all.py --force # 忽略 144h 冷却
python scripts/refresh_all.py --dry-run # 只看将执行哪些步骤
python scripts/refresh_all.py --only import,check
python scripts/refresh_all.py --status # 看上次执行结果
python scripts/embed_game_covers.py --size 400 --quality 80 # 调封面尺寸/质量
python scripts/import_psn_play_history.py --force-auth # 令牌坏了,用 npsso 重认证
python scripts/import_psn_play_history.py --from-raw # 不联网,用已有原始数据重建主表
项目结构
{项目目录}/
├── scripts/ 8 个脚本 + 1 个校验(Node)
├── 配置/refresh.toml 唯一配置真相源(周期、重试、超时、告警)
├── 仪表盘/游戏.html 可视化,单文件自包含
├── 数据/ psn_play_histories_raw.json(原始)+ 玩过的游戏.json(主表,唯一数据源)
├── 素材/游戏封面/ps5/ 本地化封面原图
├── 日志/ 按天日志,自动轮转
└── .secrets/psn/ npsso.txt + tokens.json(权限 700,勿外传)
设计与排障细节见 references/设计与排障.md。