自制AnyPS5:多台PS5的数据聚合与媒体管理服务实战

📅 发布时间:2026/10/12 4:57:20
自制AnyPS5:多台PS5的数据聚合与媒体管理服务实战
去年有两件小事凑到了一起一是我手头常打游戏的机器有三台 PS5客厅一台、书房一台、朋友那边还放了一台二是某次想在书房查一下客厅那台的存储余量和最近截的图发现居然没有任何顺手的方式能把这些信息聚到一处。PS5 自带的 App 能看奖杯和商店但我想要的是自己主机上的实际游戏库、录像截图和游玩流水最好还能导出成一份能长期归档的数据。折腾了一阵子之后我干脆自己写了一个小项目名字就叫AnyPS5。AnyPS5 不是一个模拟器也不是什么魔改插件。它是一个自托管的“PS5 信息聚合与媒体管理”服务通过局域网协议读取主机当前运行的游戏、通过 PSN 账号授权同步数字版游戏和奖杯状态、再把从主机导出的截图视频整理成可检索的本地图库。整个过程不拆机、不碰系统固件、不做任何违反平台规则的操作纯粹是把散落在各处的数据归拢到自己手里。如果你也对“数据应该属于自己”这件事有执念或者你家里有两台以上 PS5、平时喜欢导截图做剪辑、想统计自己的游玩时间那这篇文章应该能给你一点参考。下面我把这个项目的来龙去脉、技术选型、部署步骤和踩坑清单全部摊开讲一遍。1. 为什么要做 AnyPS5多主机场景下的“信息孤岛”到底有多烦先说清楚我遇到的问题否则你可能会觉得这项目是无病呻吟。1.1 我遇到的实际场景三台 PS5 的用途不同客厅那台是主力接电视玩剧情向的大作书房那台接采集卡专门录素材朋友家那台则是一起联机时用的。问题就在于三台机器各自有各自的存档、截图和游戏安装状态。我最常碰到的几个尴尬时刻想在书房确认客厅那台还有没有空间装某个新游戏必须亲自走过去开机看。打完一款游戏想找一张某年某月截的图PS5 机身里的媒体库只能按游戏翻跨主机找图基本靠记忆。想统计一年里到底玩了哪些游戏、各花了多少小时官方 App 里没有现成的维度。买了新主机之后旧主机上的截图视频导出到 U 盘结果 U 盘里的目录结构和 PS5 上的浏览顺序完全对不上。这些问题单个看都不大但放在一起就很糟心。最关键的是这些数据明明都存在只是被锁在每台主机各自的生态里没有统一的出口。1.2 AnyPS5 到底解决什么问题我给 AnyPS5 定的目标是三句话一台主机都不漏局域网内所有 PS5 的状态、存储和当前活动都能被自动发现并记录。一份数据多处用PSN 账号层面能拿到数字版游戏库、奖杯主机层面能拿到本机安装列表和媒体两边合并成一份统一的数据底座。一套系统算到底截图、录像、游戏时长、存储分配全部落到本地数据库可以用 Web 界面查也可以导出给别的工具用。所以它本质上是一个“个人游戏数据中心”而不是又一个花哨的管理界面。这也是我为啥坚持用“AnyPS5”这个名字——它不挑 PS5 的具体型号也不挑固件版本只要能跑起来就能纳管。这个项目比较适合的人群也很清晰家里有多台 PS5 的玩家、喜欢把截图和录像归档做二次创作的博主、以及想用 Grafana 之类的工具做个人游玩统计的极客。如果你只有一台 PS5 而且从来不导截图那它对你帮助不大可以跳过。2. 核心链路拆解不拆机、不改固件数据到底从哪来很多朋友一听“读取 PS5 信息”第一反应就是“是不是要越狱、是不是要装改机芯片”。这其实是个误解。PS5 本身向外提供了三条完全合法的数据通路AnyPS5 就是把这三条通路接起来。2.1 局域网采集层从 Remote Play 握手拿到“正在玩什么”PS5 自带的“远程游玩”功能本质上是一条经过 TLS 加密的局域网数据通道。主机端会监听一个固定的端口等待客户端发起握手。这里的关键点是握手过程会交换一批主机状态信息包括主机当前运行的游戏 ID、游戏标题、系统版本、主机名称等等。AnyPS5 的采集器做的事情就是以一个“虚拟远程游玩客户端”的身份在局域网内用 UDP/TCP 探测并完成握手拿到这批元数据后立刻断开并不真正建立画面串流。这就像你去敲一下门问“在家吗、现在在看哪部片”对方答完你转头就走全程不进屋也不动屋里的东西。这条链路的优势是延迟极低几秒钟就能扫完整片局域网缺点是主机必须开机或者处于待机唤醒状态。好在这一块有解我后面在踩坑章节会细说。2.2 云端资料层PSN 账号授权后同步数字库局域网层能告诉我“这台机器上装了什么、正在玩什么”但它给不了我在商店里买过哪些数字版游戏也给不了奖杯进度。要拿这部分数据只能走 PSN 账号授权。PSN 的授权流程和我平时写第三方登录时遇到的 OAuth 很像先在开发者侧登记一个客户端应用拿到 Client ID 和重定向地址然后引导用户跳转到账号登录页完成授权拿回 Access Token 和 Refresh Token。之后就能用 Access Token 去查询账号维度的游戏列表、奖杯列表和个人资料信息。这一层的好处是数据最完整跟具体哪一台主机无关买过的游戏跑不掉坏处是它一次只能对一个账号操作。如果你像我一样一个主机上挂了两个账号那就得分别授权然后在数据库里做合并。2.3 USB 离线介质层截图视频的命名与时区陷阱最后的通路就是 U 盘。PS5 提供了把截图和录像批量复制到 U 盘的功能这也目前唯一能把原始媒体文件完整搬出来的方式。AnyPS5 负责的是把这些文件从 U 盘里“读懂”。PS5 导出到 U 盘之后目录结构大体是按“PlayStation 5 截图/某年某月创建/游戏标题/文件”这样的层级来组织的文件名里自带时间戳例如20240101-203000.JPG这种格式。听起来很规整对吧但里面埋着两个坑一是文件名里的时间是主机本地时间而部分图片的 EXIF 信息里用的却是 UTC二是主机按“创建时间”归档可一旦你跨年、跨时区使用目录归类和实际拍摄时间会错位。AnyPS5 在导入媒体时不会直接信任文件名而是同时读取文件名时间戳、EXIF 原始时间、文件系统修改时间三份数据通过交叉比对推算出真正的拍摄时间再把文件按照统一的拍摄日期/主机/游戏结构重排到本地媒体库。这一步看起来不起眼实际做下来才知道有多磨人。下面这张表总结了三条通路的定位数据通路来源能拿到的信息主要限制局域网采集器远程游玩握手协议主机在线状态、当前运行游戏、本机已装应用主机需开机或可待机唤醒PSN 授权同步PSN 账号 OAuth 授权数字版游戏库、奖杯、基本个人资料一次只能处理一个账号USB 媒体导入主机媒体库导出截图、录像原文件及元数据需要手动插拔复制三条通路合在一起才覆盖了我上面列的“游戏—状态—媒体”三件套。缺了任何一条AnyPS5 都会变成一个跛脚的玩具。3. 架构与关键技术选型一个“采集器 数据库 仪表盘”的极简单体AnyPS5 从一开始就没打算做成微服务全家桶。它更像一个精心安排的单体应用几个采集器定时把数据写进同一个数据库一个 Web 界面负责查询和展示。本小节我把关键选型和理由讲透。3.1 整体架构一览项目结构按功能拆成五个包但部署时只有一个进程anyps5/ ├─ packages/ │ ├─ collector/ # 局域网探测 Remote Play 握手采集 │ ├─ psn/ # PSN 授权、令牌刷新、游戏与奖杯同步 │ ├─ media/ # USB 媒体导入、去重、EXIF 时间修正 │ ├─ hub/ # Web 仪表盘列表 统计 搜索 │ └─ shared/ # 类型定义、时间处理、游戏 ID 去重规则 ├─ docker-compose.yml ├─ .env.example └─ README.md运行时选的是 Node.js TypeScript数据库用 SQLite。理由很朴素采集器是一个 IO 密集型而不是 CPU 密集型的场景Node 的异步模型处理几十台设备的并发握手特别顺手SQLite 则让整个项目的部署门槛降到了“一个文件”的程度不用单独维护数据库服务。对于个人场景这个组合的成本最低数据备份也最简单直接把.db文件复制走就行。3.2 数据结构设计游戏、媒体、统计三张核心表数据库核心就三张表但字段设计上花了点心思。第一张是games记录游戏条目。关键字段包括title_idCUSA 编号或 App ID、name、platform、source来自 PSN 库还是本机安装以及一个dedup_key。dedup_key是我处理 PS 会免版和零售版、跨区重复购买这类情况时的核心它由“title_id 规范化 英文名小写 发行商”拼接后再做哈希生成。这样同一款游戏即使在不同账号、不同来源下被抓了三次也能在展示层合并成一张卡片。第二张是media记录截图和录像。重点字段是taken_at修正后的真实拍摄时间、source_host来自哪台主机、game_id、file_hash、file_path。file_hash是导入去重的关键我用文件内容的 SHA-256而不是文件名因为同一张图在不同主机上导出的文件名可能完全不一样。第三张是play_sessions记录每次采集时发现的“正在运行的游戏”。每个会话包含主机 ID、游戏 title_id、发现时间。这张表是游玩时间统计的原材料当连续两次采集发现同一游戏在跑我就把这中间的时长累加到该游戏上。它不是一个精确的计时器但对于“最近两周我都在玩什么”这种问题已经非常够用了。3.3 增量同步策略我特别在意功耗和隐私所以同步策略没有做成“每 5 秒疯狂扫一次”而是分了三档节奏局域网采集默认每 30 分钟一次。每次只做一次快速探测只有发现主机在线时才完成完整握手。全部设备扫描一轮的时间控制在 3 秒内。PSN 同步默认每 6 小时一次并且只在有有效令牌时执行。游戏库和奖杯的数据变化频率很低没必要高频刷新。媒体导入完全手动触发。U 盘插入后执行一次扫描导入之后保持安静。每一轮同步的结果都会写入sync_logs表。做完一轮之后仪表盘上能清楚看到“上次同步时间”“本次新增游戏”“本次新增媒体”等信息。这种可观测性帮了我大忙至少能分辨“是没扫到”还是“真没变化”。4. 从 0 到 1 实操部署一台小主机跑起来也就半小时下面这部分是给想直接复现的朋友的我按完整的实操顺序来写。4.1 环境准备与目录规划硬件上我没有用太夸张的东西一台常开的迷你主机或者旧笔记本就够了。AnyPS5 对 CPU 非常不敏感真正占资源的是后续图片缩略图生成那部分我也做成了可选的独立任务默认不启用。准备工作三步装好 Node.js 20 LTS 以上版本以及 npm/yarn/pnpm 任意一个包管理器。从仓库克隆代码git clone 你的仓库地址 anyps5 cd anyps5安装依赖并启动初始化脚本npm install npm run init初始化脚本会自动生成.env文件模板和data目录。.env长这样# PSN 授权配置 PSN_CLIENT_ID替换成你的客户端ID PSN_REDIRECT_URIhttp://localhost:8080/callback # 局域网探测范围支持 CIDR DEVICE_SCAN_SUBNET192.168.1.0/24 # 同步节奏单位分钟 SYNC_INTERVAL_MIN30 PSN_SYNC_INTERVAL_MIN360 # 数据库位置 DB_PATH./data/anyps5.db这里有个容易被忽略的坑局域网探测的 CIDR 一定要和你主机所在网段一致。如果你家的网络分了 VLAN 或者用了 AP 隔离采集器可能永远发现不了主机。我后来就直接写了个npm run scan命令先打印出本机所有网卡 IP再让你根据结果填子网。4.2 配置 PSN 授权与网络检测PSN 授权是整套部署里最绕的一步因为你需要有一个“客户端 ID”。这一步没法给出通用的一键方案我的做法是到 PSN 的开发者门户网站登记一个个人应用把重定向地址设成http://localhost:8080/callback拿回 Client ID 填进环境变量。填好之后执行npm run auth脚本会启动一个本地 HTTP 服务并给出一个授权链接你在浏览器里用目标 PSN 账号登录并同意授权流程走完后令牌会自动写进本地数据库。这里切记令牌和账号绑定谁授权谁就同步谁的库。如果你的 PS5 上有多个账号重复执行npm run auth就能叠加多个账号授权。网络检测这一块我集成了一个最简单的命令npm run network:check它会依次报告三件事局域网内发现了几台 PS5、每台主机是否可握手、上次握手拿到的游戏标题是什么。我建议在配置完所有内容之后先跑这个命令确保三条链路都通再放手让它后台定时跑。4.3 跑通一次完整同步确认网络和授权都没问题之后第一次完整同步我建议手动执行方便观察日志npm run sync:all这条命令会依次执行局域网扫描 → 游戏和会话入库 → PSN 增量同步 → 汇总统计。整个流程的日志会输出每一阶段处理了多少条数据。同步完成后启动 Web 仪表盘npm run hub打开http://localhost:8080就能看到仪表盘首页。我故意把页面做得极简左边是主机列表和在线状态中间是最近在玩的游戏右边是媒体瀑布流顶部是一个搜索框。搜索框支持按游戏名、标题 ID、日期范围过滤截图和录像实测中这是我最常用的功能。4.4 用 Docker 封装一劳永逸如果不想手动管理 Node 进程可以走 Docker Compose。我的docker-compose.yml长这样services: anyps5: image: anyps5:local build: . restart: unless-stopped ports: - 8080:8080 volumes: - ./data:/app/data - ./media:/app/media environment: - TZAsia/Shanghai - DB_PATH/app/data/anyps5.db这里特意把TZ环境变量显式设置成你自己的时区原因我在 2.3 里提过媒体文件的时间修正依赖时区信息容器如果不指定时区默认是 UTC会让截图时间整体偏移好几个小时。这是我在部署到第三台机器时才意识到的问题非常典型。5. 踩坑实录五个让人萌生退意的坎如果说前面是“怎么做”那这一节就是“做的时候到底会栽在哪”。以下五个问题全是我实际撞上过的按从低级到隐蔽排序。5.1 主机进入休眠后局域网握手失败第一次跑通 demo 之后我把采集器设成了每半小时跑一次结果第二天一早看日志发现从晚上一点开始就全部采集失败。检查之后发现问题很简单PS5 默认的休眠策略会把网络功能一起关掉这个时候我那个“虚拟远程游玩客户端”根本敲不开门。解决办法是去主机的“设置 → 系统 → 待机模式”里把“与互联网保持连接”和“允许通过网络开启主机”两项都打开。设置之后主机在待机状态下依然保有网络唤醒能力采集器就能把它从休眠中叫醒完成握手然后再让它睡回去。这里要提醒一句网络唤醒会略微增加待机功耗实测大概一天多零点几度电可以接受。如果你的部署环境对功耗极度敏感那就把局域网采集频率调低或者只在特定时间段开启。5.2 时区与文件名“差 8 小时”的诡异现象媒体导入是我在实现时最怀疑人生的模块。第一次从 U 盘导一批截图导入后按日期归档发现所有图片都被分到了前一天。排查链路是这样的先看文件名时间戳显示是晚上 22:00。再看 EXIF 里的原始时间变成了 14:00。最后看文件系统修改时间又是 22:00 左右。三个时间两两矛盾根本原因是 PS5 在写入 EXIF 时用了 UTC而文件名用的是主机本地时间。我的机器设在东八区所以恰好差 8 小时。这个问题的解决逻辑不是说“取哪个时间才对”而是要看业务上下文用户想按“拍摄那一刻的本地时间”来归档那么应该以文件名为准把 EXIF 里缺时区的字段按主机时区解释而不是按 UTC 解释。从这之后我在 AnyPS5 里定了一条铁律任何时间字段入库前必须先显式标注时区未标注的一律按配置的主机时区处理。这也直接影响了 4.4 里 Docker 必须配置TZ的决策。5.3 多账号聚合时游戏库疯狂重复我有一个账号是港区为主、偶尔领了美区的会免朋友那台机器上有他的账号。第一次做 PSN 双账号同步后游戏列表直接翻倍同一款游戏出现了三四个条目。排查下来原因有三层跨区购买同一个 title_id 在不同商店的展示名称可能带后缀。版本不同本体、豪华版、导剪版的 title_id 不同但归属同一款游戏。会免与零售重复同一个游戏既在会免库里也在购买列表里。我的解决办法是建立“规范名称层”先把游戏名里的™、®、Edition 后缀、标点符号全部去掉转成小写再用 title_id 去掉区域尾缀后的值与该规范化名做双向匹配命中就算同款。最终落到dedup_key字段上展示层统一合并。这个规则目前在我自己的库里准确率大概在 95% 左右剩下的 5% 是同一系列游戏比如“年货”续作的名字过于相似导致的误合并所以合并操作我都设计成可回退的。5.4 PSN 令牌刷新Access Token 过期干掉整个同步PSN 授权的 Access Token 有效期不算长Refresh Token 才是长期凭证。我一开始只在启动时拉了一次令牌结果第二天下午的定时同步就报 401。这个坑的本质是我把“授权”当成了一次性的而实际上应该把它当成一个持续维护的会话。修复方案是写一个令牌守卫每次同步前先检查 Access Token 的剩余有效期如果小于 10 分钟就先用 Refresh Token 换新换新失败则标记该账号进入“待重新授权”状态仪表盘上会对这个账号显示红点。另外我还犯过一个低级错误把 Refresh Token 存进了代码仓库的配置里。后来迁移到数据库存储并用文件权限锁住才彻底放心。凭据泄漏这种事情真的是做过一次就再也不想做了。5.5 截图库上万文件后页面卡成 PPT媒体导入坚持用了一周之后我的截图文件到了大概一万张。此时 Web 仪表盘打开就卡搜索一次要好几秒。定位性能瓶颈的思路是先看数据库索引有没有生效再看是不是查询把所有文件都加载进内存了。结果发现两个问题同时存在media表的game_id和taken_at字段在建表时没有建索引导致按日期范围过滤时每次都全表扫描。前端瀑布流一次把全部媒体文件渲染出来而不是按滚动懒加载。修复动作也很直接给查询字段补上复合索引前端改成“按滚动分批加载 图片懒加载 只加载缩略图”。缩略图默认不生成只有请求时才生成并缓存到磁盘。修复之后一万张截图的库搜索响应时间从 5 秒级降到了百毫秒级。6. 实测效果三台主机跑了一个月后的数据长这样理论讲再多都不如看实际数据。我把 AnyPS5 挂在自己那三台 PS5 上跑了一个月把一些有代表性的结果列出来。6.1 主机纳管与可用性表现指标客厅主力机书房采集机朋友家联机机局域网发现耗时约 1 秒约 1 秒约 2 秒完整握手成功率98.7%99.2%96.4%平均每次采集耗时460ms410ms520ms待机唤醒可用是是否对方关闭了唤醒朋友那台机器的握手成功率相对较低原因有两个一是它在另一个网段中间跨了一层路由二是对方偶尔断了外网导致主机状态异常。跨网段场景下我目前的做法是在那台机器的局域网内再放一个轻量采集节点把数据通过安全通道回传到主库相当于一个分号。这也是 AnyPS5 设计上预留的扩展点。6.2 游戏与媒体归档效果一个月跑下来数据库里累积了游戏条目去重后 327 款来自 PSN 数字库和本机安装的混合来源。游玩会话1980 条按游戏聚合后发现某开放世界游戏的累计时长远超我的预期这个数字以前完全没地方看。媒体文件导入 4287 张截图和 156 段录像按拍摄日期归档后我终于能一次看到整个夏天的游戏截图时间线。最让我意外的是“游戏常驻时长”这个指标。在此之前我一直以为自己雨露均沾但数据打脸一个月里 60% 的游玩时间都花在 3 款游戏上。没有统计就没有认知这话放在个人游戏习惯上同样成立。6.3 后续想做的扩展方向当前版本其实只是第一步。我自己列了几个后续想做但还没做的方向存档提醒利用 PSN 数据追加每条游戏上次同步的时间在仪表盘上提示“某游戏超过 N 天未备份存档”。缩略图墙生成全部截图的脸部/场景缩略图做一个可缩放时间轴浏览类似照片软件的“回忆”视图。游玩报告月底自动生成一份当月游玩报告并导出为图片分享给一起玩的朋友。媒体离线上传在采集节点上接入网盘或 NAS 接口U 盘导入后直接在服务端推送到统一存储。这些方向都不复杂但每一条都能把 AnyPS5 从“数据库”进一步推向“个人游戏工作台”。按照我个人经验这个项目最值的部分其实不是那几张统计报表而是它让我意识到游戏主机产出的数据量远比想象中大而大多数数据一直都静静地躺在那里没有人把它们串起来。AnyPS5 只是我做的一次串联尝试。如果你也准备动手做类似的个人数据项目我唯一的建议是先把“数据从哪来、多久来一次、怎么确认它没坏”这三个问题想清楚再谈界面和功能。数据通道稳了后面的一切都只是锦上添花。