☰
手搓PS5游戏管理面板:SQLite数据建模与PWA部署实践
2026/10/9 4:49:18 网站建设 项目流程

打开PS5主界面,看着满屏游戏封面的时候,我突然有种“仓库管理员”的错觉。头一年入手PS5,我的数字资产膨胀得相当夸张:PS+会员库塞了几百个游戏,打折促销的购物车里又躺了十几款,想把它们分类整理,却发现主机自带的“游戏库”功能根本不够用。它只会按字母排序列出你拥有或领取过的游戏,至于“我新买的卧龙到底占了多大空间”“上个月打折入手的双人成行到底钱花值不值”“那些被会员库覆盖但还没玩的游戏什么时候会下线”这类问题,主机一概给不了答案。

所以我花了两周做了一个自己用得上的小工具,取名 AnyPS5。先声明一下,它不是破解主机、不是模拟器、不是外挂,只是一个跑在局域网里的个人游戏管理面板。它能帮你把游戏库、存储空间、购买价格、游玩时长都记下来,还能在你想清理硬盘的时候告诉你“删哪个最不心疼”。这篇文章就是把整个项目从立项、设计、开发到实测三个月的完整过程拆给你看,包括了数据表怎么建、为什么不用自动化采集、以及在真实使用里踩到的一堆坑。如果你也是那种游戏买得比玩得多、硬盘天天报警的人,这篇应该对你有点用。

1. 从一次“删游戏恐慌”说起:AnyPS5想解决的不只是存储

先把这个项目的动机交代清楚。很多人以为游戏管理工具的痛点是“存储不够”,其实真正让人难受的是“存了却不记得,删了又怕后悔”。

1.1 那晚我对着SSD里只剩32GB发呆

那是某个周五的晚上,我刚通完一个段落准备开新坑,系统提示:可用空间不足32GB。当时我的PS5装了战地全系列、几个还没通关的RPG、一堆随时随地就想打开的格斗游戏,赛博朋克2077的回滚大小一度占到100GB以上。我盯着主机界面翻来翻去,不知道删哪个好——不是没空间,而是删错了就意味着下次想玩的时候要用流量重新下载,时间成本比空间成本更贵。

我当时大可像很多人那样做个简单的计算:装了多少就删多少,留着最近玩的那批。但问题在于,PS5自己的存储设置页面虽然能按游戏排序,却不能告诉我:某款游戏是我打折时39块放进来的,还是PS+会员白嫖的,还是重要的双人派对备选项目。它也不会告诉我“这个游戏我已经通关了,删掉毫无心理负担”。这些信息全在我脑子里,而我的脑子被工作和生活塞得太满,根本想不起来。

1.2 官方界面的缺口,就是这类工具的出发点

如果你长期用PS5,会知道系统里其实有一个“游戏库”入口,能够筛选PS4/PS5、已安装/未安装,但这套界面的定位是“让你找到游戏并启动”,不是“让你管理整个数字资产账本”。它没有价格历史,没有购买渠道标记,也看不见DLC占掉的空间,更别提把多区服账号买过的同一款游戏合并成一个条目。

我也试过用Excel记,第一条游戏记录写得极其认真,第二周就开始漏,后来整个表变成半死不活的状态。为什么?因为Excel的问题是打开路径太深:先解锁手机、找表格App、翻目录、点开文件、再滚动到目标行。步骤一多,习惯就没了。当时我就想做一个小程序,点开就是今天的“游戏财务摘要”,大不了只维护三五个常用字段,一分钟录完一条数据。

1.3 项目定位:一张可以装进口袋的个人游戏账本

AnyPS5这个名字,本意是“在任何设备上看清自己的PS5库存”。它可以部署在树莓派、旧笔记本或者NAS里,通过浏览器访问。数据全部落在本地文件里,备份就是拷走一个SQLite数据库文件和导出JSON。

一开始我没有画产品原型,只写了一个需求清单:能记录游戏名称和别名、能记录数字/实体版本和区服、能记录占用空间大小、能记录购买来源和价格快照、能记录每次游玩的起止时间、能按“占位大小”和“最近游玩时间”排序、能在列表上直接进行“已通关/未通关/弃坑”标记。后来的开发过程证明,这七条足够了,正是从这七条里长出了AnyPS5的核心结构。

2. 需求围栏:AnyPS5只做四件事,多余一概不做

做个人项目最怕的是功能越加越多,最后变成“全屋智能中控台”。AnyPS5从立项那天起就给自己划了四条业务线,每条线对应一个具体的高频场景。

2.1 空间账本:主机上装了什么、如果全装还缺多少

第一件事是回答“我的硬盘还能撑多久”。每次往游戏库里添加一条游戏记录,我就会顺手填上它的安装空间,单位心里默认为GB。随着条目增加,AnyPS5会自动累加所有“已安装”游戏的占位总和,并和主机总容量对账。如果一款游戏有PS4和PS5两个版本,我会把它们作为两个独立条目,毕竟它们的体积和是否需要外接硬盘完全不一样。

这条业务线的补充场景是“重建场景”。比如你换了主机或者删空了机器,想重新知道“如果要装回所有持有游戏,需要多大硬盘”,AnyPS5会把你打上“未安装”标记的那批也汇总出体积。这个数字往往很吓人,但对决定是否加装M.2 SSD有非常直接的参考意义。

2.2 价格时间线:最低价、折扣价、入手价分开记

第二件事是记录我到底“花没花冤枉钱”。我买过的游戏里有不少是从各个平台的低价信息里淘来的,但人的记忆会美化和失真,半年后可能连自己多少钱入手的都忘了。所以我加了一张价格表,每个游戏可以有多个价格快照,例如:

  • 观察日期和价格;
  • 折扣比例(可选);
  • 数据来源(“区服商店”“网页下单页”“邮件收据”);
  • 备注(例如“黑五折后价”“首次打折”)。

之后首页会显示每个游戏最后一次记录的“到手价”和“历史最低价”,如果最低价不是自己实际支付价格,就会看到那个让人血压升高的差值。这个功能不是为了让你焦虑,是为了在剁手下一个游戏前三秒钟想一下这个差值值不值。

2.3 会话账本:补上官方“游玩时间”统计的盲区

PS5自己的主界面确实能看游玩时间,但那个统计挺粗糙的,有时候我挂着游戏去吃饭,它也会把时间算进去。AnyPS5做的“会话账本”是另一个思路:每一次打开游戏前,记录“开始”,结束游戏时记录“结束”,系统算出当次时长,累计成总时长。最开始我以为这会很麻烦,实际用下来只需要每次玩完顺手点一下“结束”,手感上来说比打一个“已通关”标记还快。

这套数据还衍生出一个有趣的排序维度:按“单次平均时长”排序。你会发现有些游戏经常开,但每次就打十分钟,有些游戏一次能沉浸两小时。这对“碎片时间选什么游戏玩”特别有用,比单纯看总时长更符合现代玩家的真实作息。

2.4 交易与订阅状态:数字版、盘、DLC、PS+ 去留

第四件事是把整个持有状态说清楚。实体盘和数字版要分开,因为盘可以出二手,数字版则永久绑定账号。DLC也不能被忽略,有些游戏的DLC比本体还大,比如某些历时几年的服务型游戏,后续更新包动辄几十GB。AnyPS5在每一条游戏记录上加了“类型”字段(本体/DLC/季票/会免领取),还会标记当前是否可用。这个“可用状态”是应对订阅制游戏的:PS+会员库的游戏说下线就下线,但账号库里的记录不能跟着消失,至少要知道自己“曾经拥有并玩过”。

这四件事做完之后,AnyPS5的首页变成了一个能回答四个高密度问题的仪表盘:硬盘还能装什么、我最常玩什么、我买贵了多少、哪些游戏即将从会员库里消失。

3. 第一版的数据骨架:三张表加一个文件就够

任何管理类工具的核心都是数据模型。AnyPS5的数据模型一开始就没设计得很复杂,因为我知道个人项目的维护成本必须压到最低。整个数据库就是一个SQLite文件,三个核心表加一个配置项。

3.1 从对象到表:Game、PlaySession、PriceRecord 怎么划分

我在设计表结构时没有搞什么复杂的三范式论证,纯粹按照“一次操作对应一张表”的直觉来的。Game表负责描述一款游戏的基本信息,PlaySession表负责记录每一次游玩,PriceRecord表负责保存价格历史的每一笔观察。SQLite的建表语句大概是这样的:

CREATE TABLE games ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, alias TEXT, region TEXT DEFAULT 'CN', game_type TEXT DEFAULT 'base_game', -- base_game / dlc / season_pass / ps_plus platform TEXT DEFAULT 'PS5', storage_size_mb INTEGER DEFAULT 0, installed INTEGER DEFAULT 0, status TEXT DEFAULT 'backlog', -- playing / finished / abandoned / backlog purchase_channel TEXT, purchase_price_cents INTEGER DEFAULT 0, purchase_date TEXT, note TEXT ); CREATE TABLE play_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, game_id INTEGER NOT NULL, started_at TEXT NOT NULL, ended_at TEXT, note TEXT ); CREATE TABLE price_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, game_id INTEGER NOT NULL, observed_on TEXT NOT NULL, price_cents INTEGER NOT NULL, region TEXT, source TEXT, note TEXT );

每次打开任意页面,我最关心的永远是查询“我到底有哪些游戏”,所以games表里的大部分字段都会出现在列表查询里。PlaySession表只存起止时间,不冗余游戏标题;PriceRecord表只存价格观察值和来源,防止之后想统计“黑五平均降价幅度”时没数据可用。

3.2 为什么“别名”字段是中文区用户刚需

这是我实际用了两周后才加的重要字段。之前我往库里加“最终幻想7:重生”时,用的标题是“FF7 Rebirth”,后来在手机里写成了“最终幻想7重生”,系统认定它们是两个游戏。吃过这个亏之后,我把games表加了alias字段,用来存放游戏在不同语言下的常见叫法。这样无论我下次输入的是“FF7RB”还是“重瓣版”,搜索都能命中同一个条目。

以后谁要做类似项目,建议第一次建表就把alias放进去。游戏名在不同来源里的表达差异超出你的预期,简体中文、繁体中文、英文名称、社区简称,很容易让信息管理工具变成一串重复垃圾数据。

3.3 录入流程设计:一次完整录入不超过20秒

光有表结构还不行,得让数据能长期进得来。我把新增游戏的操作设计成一条流:搜索框输入标题,如果库里已有同名记录就弹出合并提示;如果没有,就直接跳到表单页,表单字段经过裁剪只保留七样:标题、平台、类型、区域、存储大小、购买渠道、入手价格。写得快的人十秒能完成,慢一点也能控制在20秒内。

对于已经安装到主机里的游戏,我会先把系统的“存储”页面打开当作参照,直接按页面上显示的数字填进去。输入的时候注意:系统里的单位是GB,录入后保存到数据库时统一换算成MB,避免后面计算时出现十进制二进制混着用的尴尬。这个细节后面会再提,因为它真的是个大坑。

4. 前端和部署:一台老旧设备也能跑起来的轻量方案

这个项目一个人用,没必要为了“技术时髦感”上一套微服务和容器编排。AnyPS5的目标是低门槛、耐折腾、恢复成本低。部署逻辑很简单:一个Node.js进程提供静态文件和接口,一个SQLite数据库文件负责落盘。

4.1 技术栈选型的两个硬约束

我在选型时的第一个硬约束是“老设备能跑”。当时手边有一台吃灰多年的旧笔记本,双核CPU,连风扇都滋滋响。让我把这套东西部署在Kubernetes集群上是完全不现实的想法。最终我选了Express + better-sqlite3的组合,因为better-sqlite3是同步操作,不需要管理一堆异步回调,代码量可以减掉一大截。

第二个硬约束是“拆掉容易”。我不想在NAS和路由器上装任何需要常驻后台的大组件。直接把项目丢到任意一台有小容量存储的设备里,安装Node.js后跑npm install && npm start,整个应用就能起来。我连数据库迁移工具都没用,因为个人工具的表结构很少变动,真改了直接改建表语句然后从旧库里导出JSON再导入就行。

4.2 离线优先的PWA思路

前端我最初做了一个纯粹的服务端渲染页面,后来觉得手机上用起来还是不够顺畅,就把页面改成响应式单页应用,并加了一个很轻的manifest配置,让它在手机上能“添加到主屏幕”。这样从主屏点开就是独立窗口,看起来像一个原生App。

同时,我把页面静态资源完全缓存到浏览器,后端接口不可用时列表依然能显示最近一次加载过的数据。这个过程中没有引入复杂的PWA框架,毕竟核心只是离线缓存。对于一个家庭局域网里的工具,这个可靠程度已经非常高,哪怕NAS临时重启,手机的快捷入口也不会白屏报错。

4.3 数据安全边界:文件备份和不联网原则

从一开始我就确定了AnyPS5的数据不联网原则。整站不添加任何所谓的“云统计”、不接入第三方登录、不给公网开端口。你只需要让它跑在自己的局域网里,或者绑定到自己的内网域名后面。备份方式也更简单粗暴:直接把data目录里的数据库文件复制走。

个人工具最忌讳的就是“数据被锁死在别人服务器上”。我见过很多好用的管理服务,结果折腾半天发现导入导出只能走他们定义的格式,甚至还有账号体系绑定。AnyPS5的做法是提供两个导出按钮:一个导出现状套用的SQLite文件,另一个把整个数据库的内容转成一个可读性很好的JSON。两个导出文件就是我全部数据的所有权凭证。

5. 三个月实测,踩过的七个坑跟你们逐一汇报

工具上线不代表能用,真正有价值的部分是在真实使用里被磨出来的。这三个月我几乎每个星期都会打开AnyPS5录入或回顾数据,踩了不少坑,下面这七个是典型的,按照影响程度从轻到重排。

5.1 同名游戏在不同语言下的重复录入

这个坑在第三节里提过,实际发生频率非常高。同一个《马力欧》游戏在不同地区商店里叫法都不一样,更别提中文互联网社区里还流行各种简称。修复方案就是前面说的alias字段,另外我在搜索接口里做了简单的“去掉空格和标点再比较”的逻辑,不然“FF7 Rebirth”和“FF7Rebirth”还是会变成两条记录。

5.2 容量单位换算的隐形地雷

有一段时间我在首页统计“全部游戏占位总和”时,发现数字比我主机上真实可用容量大了一圈,排查半天才发现问题出来:早期录入的时候,有些游戏我填了GB数,例如80GB直接存成了80,没有乘以1024换算成MB。后来有两个游戏我填的是按M.2页面显示的GB,却因为眼残写成了“8000MB”。底层单位必须统一,这一点我交了一次学费。

建议所有做存储记录的朋友,在设计字段时就把它定义成最小统一单位,比如MB。录入界面上可以给人看GB的小数点视图,但数据库里永远只能存一个整数。

5.3 不同区服的同款游戏价格被混算

因为我会在港服、日服和某些地区的实体店之间横跳,同一款游戏的价格来源跨越多个区。结果就是历史最低价计算时把不同区服的价格混在一起,得出了“我竟然亏了这么多”的错误结论。后来我把PriceRecord表也加上region字段,统计历史最低价时强制按当前游戏优化出来的region范围过滤。这个逻辑加得很早,所以后续没再被误导过。

5.4 官方统计时长和自记时差的迷思

PS5会显示“游玩时间”,但它的口径和我用会话账本算出来的完全是两回事。官方那边是把应用处于前台的时间都算进去,哪怕是挂机看地图也算;我的会话账本记录的是“一次主动开始和主动结束”之间的时间所以对那种“开游戏然后去回微信”场景的记录会更干净。

如果你也想做类似工具,建议别指望官方统计能给你完美的数据。自己记一次就玩一次的时长会有漏记,但漏记的比例远比官方口径里的“假装在玩”低。

5.5 DLC与主体游戏的边界模糊

有的DLC和主体根本分不开,比如《艾尔登法环》的黄金树幽影,在我心里它就是个新游戏。可在存储统计时,它又确实只作为主体游戏的一条扩展记录。我的解决方式是:在DLC条目里新增一个base_game_id字段,标注它挂在哪个主体下;存储统计时DLC单独算体积,但在查找时能通过主体游戏入口关联到。这个方案不完美,但比把DLC硬塞进主体游戏的某个备注字段里要在数据上干净得多。

5.6 订阅制游戏会“过期”,但记录不该消失

PS+会员游戏的下架是很现实的事。有一款我很喜欢的游戏,入库时没标记可用的到期时间,结果某天想点开玩发现它已经不在会员库里了。如果我不做AnyPS5记录,这段拥有经历和游玩记忆就彻底没了。现在我给games表预留了一个是否订阅领取的标记,并在备注里写清楚它是哪个会免月的,而不是简单地打勾“已领取”。至少未来回顾自己玩过什么时,库是完整的。

5.7 工具用着用着懒了,怎么逼自己保持输入习惯

最后一个坑不是技术问题,是习惯养成。我再喜欢用表格和面板,也没有动力每周定期去录入游玩时长。后来我给AnyPS5的首页加了一个“今天想开哪个小游戏”的随机按钮,它会从标记为backlog、且安装过的游戏里挑一个出来。这种一点点游戏化的诱导反而很有效,每天打开首页自带一种“抽卡”的趣味,顺路就更新掉当天的游玩记录。

6. 下一版规划:不做更多功能,只做月度过账

AnyPS5目前版本用得很稳定,我也在思考下一步往哪走。这里顺便聊聊我的取舍思路,也给打算做同类个人工具的朋友一个参考坐标。

6.1 玩家反馈里出现频率最高的需求

陆续给几个朋友用过之后,他们反馈最多的不是“存储统计”,而是“月度花费报告”。很多人跟我一样,看到折扣就手痒,但根本不知道自己一个月在游戏上花了多少钱。AnyPS5有购买记录和价格快照,完全能按月生成一张消费汇总表:这个月买了几款游戏、花了多少、实际游玩时长多少、每小时的娱乐成本约合多少。

这个需求比我想象的要有价值,因为大脑在面对“每小时成本0.5元”这种数字时会产生一种非常清晰的心理反馈。而平时我们只会看到“打折:-30%”的红色标签,并不知道自己真正打开过几次。

6.2 月度报告的交互设计思路

我计划在月末生成的报告里只放三个区块:本月新增游戏列表及总支出、本月游玩时间最长的五款游戏、上个月购入但至今未打开的游戏列表。第三块是重点,它专门用来治疗“买过=玩过”的幻觉。界面会做成一张长条卡片,便于截图分享,既能让自己的消费冲动被量化,也能纳入朋友之间互相调侃的谈资。

同时我准备给所有记录增加一个“手动修正”按钮,因为月度汇总的对账周期很长,难免有当月的记录后来才发现填错了。工具不应该拿数据逼人,它应该始终允许数据被人类修正。

6.3 我的维护原则:能离线绝不联网,能导出绝不锁死

接下来无论AnyPS5怎么迭代,有两根红线我不会碰。第一是不做账号系统,就算以后有人在network环境里用,也只是共用一份本地数据,不能被单一账号绑架;第二是不做自动后台采集,游戏价格和游戏名称都不会爬别人的网站,宁可留一个手动吸光按钮,由用户自己决定什么时候把键盘里的内容放进库里。守住这两条,工具就永远是工具,不会变成另一种需要你去维护的负担。

最后分享一点这三个月的体会。AnyPS5一开始的目标只是解决“硬盘不够”的烦躁,真正坚持用下来,它带来的最大变化是让我对“买游戏”这件事的认知清醒了不少。以前看到打折就想囤,现在下单之前会下意识想一下它会不会成为月度报告里那个“至今未打开”的条目。数字不会替你做决定,也不会阻止你消费,但它能强迫你看见自己真正的游戏习惯。如果你也经常被数字版游戏塞满硬盘还舍不得删,不妨也试着建一个属于自己的游戏账本——不用写代码,用表格工具就行,关键是开始记录,并且在月底愿意回头看它一眼。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询