大概半年前,我开始折腾一个代号叫AnyPS5的个人项目。起因特别朴素:PS5 玩时间长了以后,截图和录像攒了上千份,每次想找某个游戏的某张截图,插上 U 盘导到电脑上一看,全是20250120123000这种默认数字文件名,整个人都是蒙的;想算算今年到底哪个游戏玩得最多、要不要加装一块 M.2 固态,发现每次都得翻系统菜单、找 App 记录,还是一笔糊涂账。于是我就想着,能不能把 PS5 到手之后的这些"运维琐事"——媒体文件归档、游玩时长统计、存储空间规划——统一做成一套自己用着顺手的工具。
这套工具不碰系统底层、不依赖任何破解手段,只基于 PS5 官方本来就有的功能(U盘导出、系统菜单、手动登记)加上一些外部自动化脚本,最后用一个本地网页看板做汇总。折腾下来也确实解决了不少问题,这篇就当是 AnyPS5 的完整复盘,把我从需求、选型到实现、踩坑的整个过程都展开聊一聊,给同样想给游戏主机做"数字化管理"的朋友一条能直接参考的路线。
1. 为什么会有 AnyPS5 这个项目:三个让我反复烦躁的真实场景
1.1 截图堆积如山,找一张图要翻半小时
PS5 系统默认会缓存截图和短视频,每份文件的命名基本是拍摄时间戳加一串随机字符。短时间玩一个游戏还好,一旦跨游戏、跨月份,文件就完全没法看了。我玩《怪物猎人》类刷刷刷游戏时,经常一个周末截几十张图,隔两周再想找其中一张"怪物出招瞬间"的截图,只能把所有文件按时间一张张缩略图扫过去,非常痛苦。这个痛点听起来很小,但实际体感极差——截图明明是最容易沉淀、也最值得回顾的内容,却因为管理成本太高,最后全都躺在系统里吃灰。
后来我开始思考:如果找图这件事能固化成一条流水线——导出、归类、改名、入册,把"人找图"变成"图找人",那截图的价值才会真正体现出来。AnyPS5 的第一个核心需求,就是解决媒体文件的自动归档问题。
1.2 玩过的游戏时长完全是一笔糊涂账
PS5 系统里能看到游戏的游玩时间,但只能一个游戏一个游戏地看,想对比"上个月我在哪几个游戏上花了时间"非常麻烦。PlayStation 官方 App 里也有月度回顾,但覆盖的维度偏娱乐向,数据导不出来,也没法自己算平均数、看趋势。我自己是一个数据控,很想知道一年下来每个游戏的真实投入、通关速度、峰值时段,方便规划接下来玩什么、跳不跳过某些大坑。
问题在于,PS5 并没有开放给普通用户的官方数据接口。如果我抓接口拿数据,既涉及账号安全风险,也不见得符合平台的使用规则。所以 AnyPS5 在这个模块上采用了一种"笨但稳"的路线:手动登记 + CSV 存储 + 自动汇总。别看方法土,坚持下来以后,数据的价值反而比官方接口还高,因为你可以把"今天连跪三局""这张图练了多久"这类非结构化备注也一并记进去。
1.3 系统存储动不动告警,扩容决策却全靠拍脑袋
熟悉 PS5 的朋友都知道,内置 SSD 容量空间有限,动辄一百多 GB 的次时代大作装不了几个就亮红灯。外部 USB 硬盘虽然能玩 PS4 版兼容游戏,但对 PS5 版游戏只能"存储、不能游玩",于是要不要加装 M.2 固态、装多大容量、买哪个规格,就变成了一个非常现实的消费决策。
我当时面临的状态是:内置存储只剩 60GB,想装新游戏必须删旧游戏;可删哪个、以后想玩哪个,完全没有数据支撑,每次都是凭感觉,删完就后悔。AnyPS5 的第三个定位,就是做一张持续更新的"存储规划表"——把已安装游戏、占用空间、近期游玩状态放在一起,用逻辑取代感觉来做删减和扩容决策。
1.4 项目命名的想法和整体设计原则
名字叫 AnyPS5,是因为我希望这套方法不绑定某一台主机、某一种 U 盘、某个平台的游戏库。只要能导出来、能登记上,任何一台 PS5 都能按同样的流程管理起来。后来实际用下来,它不仅对 PS5 成立,对 Switch、Steam 的截图管理同样可以套用,只是 PS5 的封闭生态特性会带来更多限制,所以这部分经验特别值得单独写。
在设计上我给自己定了三条原则:
- 不碰系统、不改机、不碰账号,只使用 PS5 官方支持的功能和用户自己的手动记录;
- 本地优先,所有数据落在本地 CSV 和 NAS 里,不依赖云服务,隐私可控;
- 流程尽可能半自动,把人工参与压缩到"插 U 盘"和"打完游戏打个勾"这两个动作上,其余全部交给脚本。
这几条原则之后帮了我大忙,很多 PS5 自动化方案走到一半失败,基本都是因为想跨越边界、去做系统不允许的事。把边界划清楚,反而能找到一个特别稳的平衡点。
2. 媒体文件自动归档:从 U 盘导出到 NAS 自动分类入库
2.1 PS5 官方导出流程与文件组织方式
PS5 导出截图和录像的官方路径是:设置 → 截屏与广播 → 媒体库 → 选择内容 → 复制到 USB 驱动器。系统要求 U 盘格式为 exFAT(FAT32 也行,但单文件超过 4GB 的录像会出现问题),导出后目录结构一般是PS5/下面按创建时间分成多个文件夹,每个文件命名类似20250120123000.jpg或20250120123000.mp4,完全看不出游戏来源。
如果你没提前做任何标记,到这个步骤就已经丢了一半信息。但 PS5 其实有个很容易被忽略的隐藏信息:媒体播放时按下控制键,界面会显示这是来自哪个游戏的截图。不过这个信息不会写进文件名,必须靠人工记忆去维护。这也是我为什么坚持要在归档阶段立刻处理,拖得越久越不可能分清。
2.2 批量分类脚本:按月份+游戏关键词自动改名
我的做法是分两阶段:先把 U 盘导出的文件统一拷贝到 NAS 的临时目录,然后跑一个 Python 脚本做分类。分类依据不指望读取图片内容,而是用"时间窗口 + 游玩日历"来反推——比如我 1 月 20 日当天玩的是某个 RPG,时间戳落在那天,就归入那个游戏的目录。
脚本逻辑核心就三步:
- 读取文件修改时间/名称时间戳;
- 匹配"日期 → 游戏名"映射表(这个映射表我每周花一分钟维护);
- 按
游戏名/YYYY-MM/目录结构移动文件,并统一重命名为YYYY-MM-DD_HHMMSS.jpg。
映射表是一个很简单的 CSV:
date,game 2025-01-20,暗黑破坏神4 2025-01-21,绝地潜兵2 2025-01-22,暗黑破坏神4脚本会在归档时自动读取这个表。如果某个日期没有映射记录,就统一丢进未分类/目录,等我月底统一补一次。实测下来,因为有游玩日历做参考,分类准确率在 95% 以上,剩下的 5% 也可以靠文件名里的时间戳快速人工定位。
2.3 接入 NAS:归档路径的设计细节
我的 NAS 目录结构是:
NAS/Media/PS5/截图/游戏名/YYYY-MM/YYYY-MM-DD_HHMMSS.jpg NAS/Media/PS5/录像/游戏名/YYYY-MM/YYYY-MM-DD_HHMMSS.mp4 NAS/Media/PS5/临时/ # U盘导出后先扔这里 NAS/Media/PS5/未分类/ # 无法匹配的留守区域这里有个关键经验:截图和录像一定要分开目录。游戏录像体积动辄几百 MB,和截图混在一起会让 NAS 的索引和缩略图生成变得很慢。另外,NAS 上的缩略图服务(比如群晖的 Synology Photos)能自动识别文件夹并生成预览,配好之后,手机上和电视上翻截图都很顺,查找效率基本达到"想找哪张图,三步内能翻到"的程度。
2.4 让脚本自动跑:U盘插入触发和定时归档
只靠手动跑脚本还是不够爽,我加了自动化层。方案是用 Python 的watchdog库监听宿主机的一个挂载点,U 盘插入后自动触发归档脚本:
pip install watchdog脚本监听逻辑不复杂:检测到 U 盘挂载 → 休眠 10 秒等系统稳定 → 调用归档函数 → 完成后弹出提示。加上日志记录,整个过程基本不用人工干预。对于没有 NAS 的玩家,也可以把目标目录设在本地磁盘,脚本逻辑完全一样,只是少了实时备份和跨设备访问的能力。
注意:初次归档建议先跑一次
--dry-run参数,只打印变动文件不实际移动,检查完再正式执行。因为 PS5 U 盘里的文件名重复率极高,如果脚本在改名时发生冲突,容易把文件覆盖掉。
3. 游玩时长与奖杯统计:不碰账号接口也能做半自动盘点
3.1 思路的转变:从抓接口变成"游戏打卡表"
一开始我也尝试过从 PlayStation 网页端找数据接口,理论上确实有人能拿到 Session ID 去查游戏时长和奖杯,但这件事有几个问题:一是账号安全风险不可忽视,二是接口随时可能变更,三是不管怎么包装,都有点踩线。想明白之后,我果断放弃了"官方数据自动同步"这条路,改用最朴素也最可靠的方式——自己登记。
具体操作是:每台 PS5 使用者的游玩结束后,在手机上一个固定入口(我用的是一个共享的腾讯文档)写上日期、游戏名、时长、备注。这套玩法的本质是"游戏打卡表",虽然每次要多花十几秒,但换来的是数据的完全自控,而且想加什么字段就加什么字段,比如"今天手感爆棚""练了这个 boss 三小时"。
3.2 用 CSV + Python 整理月度报告
打卡表导出成 CSV 后,我用一个 Python 脚本汇总:
date,game,hours,note 2025-01-20,暗黑破坏神4,2.5,刷地狱狂潮 2025-01-21,绝地潜兵2,1.0,和朋友三连 2025-01-21,暗黑破坏神4,1.5,打boss练习汇总逻辑包括:月度总时长、游戏排行、单次平均时长、最近 7 天趋势,并生成一个 Markdown 报告。用 Pandas 做数据透视其实非常快,几十行就能搞定:
import pandas as pd df = pd.read_csv("play_log.csv", parse_dates=["date"]) df["month"] = df["date"].dt.to_period("M") summary = df.groupby(["month", "game"])["hours"].sum().reset_index() summary.sort_values(["month", "hours"], ascending=[True, False], inplace=True) summary.to_csv("monthly_summary.csv", index=False)有了这个表,每个月月底我都能非常清晰地看到:上个月哪款游戏消耗了我最多时间,有没有出现"开坑无数、几乎没推进"的情况,以及本周应该优先补哪个进度。
3.3 Flask 本地看板:一眼看清最近玩了什么
光有 CSV 不够直观,我用 Flask 做了一个极简的本地 Web 面板,端口绑定局域网,手机电脑都能访问。面板主要展示三块:本月热门游戏、最近游玩记录、存储空间状态。数据实时读取 CSV,界面只用原生 HTML + 一点 CSS,不引前端框架。
看板的实际价值超过我预期。以前我想知道自己"最近在玩什么",得靠记忆;现在打开面板,一周的趋势一目了然。尤其在游戏荒的时候,翻一翻"上次玩到哪了、打了多久",特别有助于决定是继续推进还是换游戏。
3.4 周报邮件和云存档提醒
在打卡表基础上,我还加了两个小提醒:
- 每周日晚自动发送周报邮件,内容是本周各游戏时长和最近 7 天趋势。原因是"回忆一周前玩了什么"很容易失真,有了周报,月底做总结时特别轻松;
- 云存档月提醒,每个月 1 号提醒一次:检查有没有需要上传的存档、会员是否到期、要玩的游戏有没有云存档记录。别小看这个提醒,我至少有两三次差点因为会员过期丢存档,靠这个习惯才避开。
这两个功能用的是系统自带cron/launchd加 Python 脚本,整体非常轻量,没有任何外部依赖。
4. 存储空间与 M.2 扩容的量化决策
4.1 先把空间占用做成可持续更新的表
PS5 存储管理最大的问题,是系统只显示每个游戏的占用大小,不告诉你"上次什么时候玩过"。要判断"删哪个游戏最不心疼",必须把空间数据和使用频率放在一起看。
我维护的存储表字段包括:游戏名、版本类型(PS5/PS4)、安装位置(内置/扩展/外置)、占用 GB、上次游玩日期、游玩总时长。每周更新一次,数据来源就是系统菜单看一眼,手动填进表格。这样积累一个月后,"删什么"就变得非常有依据:
- 玩家次数为 0、总时长低于 2 小时,直接列为候选删除;
- 云存档完整的游戏,优先删除,未来想玩可以随时重装;
- 多人联机游戏即使时长低也保留,防止朋友约玩时临时下不了。
4.2 外置 USB 硬盘和内置 M.2 SSD 的分工策略
通过统计我发现,内置 SSD 上有一批"很少打开但体积巨大"的游戏,比如各种年货大作,移动版体积动辄 80GB 起。对于这类游戏,官方支持把它们转存到外接 USB 硬盘(只能存储,不能直接运行 PS5 版)。于是我的策略变成:
- 内置空间只放"最近 1 个月内活跃"和"随时可能开黑"的游戏;
- PS4 版兼容游戏和"玩完暂时不计划再动"的 PS5 游戏,全部转移到外置 USB;
- 扩展 M.2 SSD 用于放置"第二梯队"游戏——不是最活跃,但不想等下载时间的;
这样分层之后,内置空间的压力骤减,再没出现过为了装一个游戏必须临时删另一个的尴尬。
4.3 M.2 扩容怎么选规格、怎么避坑
PS5 官方支持扩展 M.2 SSD,但规格有严格要求:必须支持 PCIe Gen4,持续读取速度建议 5500MB/s 或以上,容量从 250GB 到 4TB。散热片版本优先,直接装进扩展仓即可,不需要额外改装。
我在选型时看实测数据比看宣传更重要。宣传标称的速度,不代表游戏加载速度。我实际比较过几款 Gen4 盘,真正影响体感的是随机读取和小文件传输性能,而不是最高顺序速度。所以在预算允许范围内,优先选知名主控、带独立 DRAM 缓存的型号,散热片厚一点也没关系,反正盖上机壳看不见。
提示:加装 M.2 SSD 不涉及主机系统修改,是官方开放的功能,不需要担心保修问题。但拆机时注意静电释放和螺丝规格,操作前先看一遍官方图解。
4.4 用了 AnyPS5 之后我的存储策略完全变了
以前我存储空间满了的第一反应是"加钱买大 SSD"或者"删最久没玩的游戏"。现在有了数据表,决策顺序变成:
- 先看表格里"谁最长没玩且云存档完整"→ 移除外置;
- 再看"谁体积大且近期无打开记录"→ 移除外置;
- 都不行才考虑"是否买新 SSD 扩容"。
这套顺序看着简单,但因为没有数据,绝大多数人会跳过前两步直接走到第三步。其实 PS5 的存储压力,一半以上靠整理就能解决,真没必要急着花钱。
5. 踩坑记录:PS5 封闭生态给自动化上的三课
5.1 时区与时间戳的错位问题
PS5 导出的截图文件名用的是设备本地时间,但如果你在归档脚本里用的是 PC 的系统时间,一旦跨时区或者夏天碰上 DST(夏令时),就会产生一小时偏差。这个 bug 特别隐蔽,尤其是晚上 23:30 到次日 0:30 之间玩的截图,很可能被误分到前一天。
我的解决方案是:归档脚本里强制用固定时区解析时间戳,不依赖系统默认时区。在 Python 里用zoneinfo明确指定时间源,这样才能保证在 NAS 和笔记本上跑出来的结果一致。
5.2 文件名和特殊字符的兼容性
PS5 游戏名里经常有拉丁字符、注音符号、特殊符号,比如"Spelunky 2"、"Hades II"这种含数字、空格的名称,如果不做清理就直接当目录名,NAS 上同步到某些平台时会出问题。我后来在命名规范里约定了两条:
- 目录名只保留
A-Za-z0-9-_(字母、数字、下划线、中划线、空格); - 特殊字符一律替换为下划线,并且做一次 Unicode 规范化(NFD 转 NFC),避免 macOS 和 NAS 之间的编码差异导致"看着同名,实际文件找不到"。
这种小坑在 Windows 上基本不会暴露,但一旦跨系统、跨 NAS 就很容易踩,也是我在归档脚本里花时间最多的一处。
5.3 U 盘供电与主机休眠导致的中断
PS5 的 U 盘导出时,如果主机 USB 口供电不稳,或者机器进入休眠,拷贝会中断,目标目录留下半截文件。我的 U 盘是普通 3.0 盘,有几次导出大量 4K 录像时出现中断,事后检查才发现文件不完整。
解决办法:改成"先导出到主机内置暂存区,再从暂存区拷到 U 盘"的流程;同时设置 PS5 不休眠的时长尽量拉长,至少保证一次性拷贝完成。对于几千张截图的大工程,分批次导出远好过一次性导出一堆,哪怕中途断了,损失也小很多。
5.4 免费的 Plan 不一定适合自己的需求
最初我用一张共享表格做打卡记录,优点是多人可以同时填,缺点是偶尔会被误改;后来我改成"表格定时导出 CSV + Git 记录变更",既保住了多人协作,又能追踪改了什么。这个调整让我更确信一个原则:方案越简单,越要在数据备份层面做冗余。AnyPS5 的所有数据,我都会定期同步到第二个位置,NAS 一份、云盘一份,做一次手动恢复演练后才踏实。
6. AnyPS5 的最终目录结构与关键代码片段
6.1 项目目录总览
现在整个项目整理下来,结构非常清爽:
anyps5/ ├── config.yaml # 游戏目录映射、路径、时区配置 ├── media_sort.py # U盘导入与媒体归档脚本 ├── stats_report.py # 游玩时长统计与周报生成 ├── flask_app.py # 本地看板服务 ├── data/ │ ├── play_log.csv # 游玩打卡表 │ ├── storage_map.csv # 存储规划表 │ └── monthly_summary.csv └── scripts/ ├── watch_usb.py # USB监听自动化 └── monthly_reminder.py写代码时我有一个习惯:尽量只依赖标准库加少量第三方库,少一个依赖,就少一个之后需要维护的"坏点"。像media_sort.py核心逻辑我刻意没有用 Pandas,纯用pathlib和shutil也能完成,这样在 NAS 上跑也不怕缺依赖。
6.2 media_sort.py 的核心片段
from pathlib import Path import csv import shutil import re def load_game_map(path="config.yaml"): mapping = {} # 读取 config.yaml 中的日期映射表 return mapping def clean_name(name: str) -> str: """只留安全字符,避免NAS/跨平台同步出问题""" name = unicodedata.normalize("NFC", name) name = re.sub(r"[^\w\- ]", "_", name) return name.strip() def sort_media(src_dir, dest_root, mapping): for f in Path(src_dir).rglob("*.jpg"): ts = f.stem # 依据文件名时间戳 date_str = ts[:8] game = mapping.get(date_str, "未分类") target = Path(dest_root) / clean_name(game) / date_str[:6] target.mkdir(parents=True, exist_ok=True) dst = target / f"{date_str}_{ts[8:]}.jpg" if not dst.exists(): shutil.move(str(f), str(dst))这段代码没有很复杂的东西,但它把"安全命名"和"日期反查"两个关键点都覆盖了,最核心的反而是mapping表的维护习惯。
6.3 flask_app.py 的看板片段
Flask 面板很简单,核心就一条路由:
from flask import Flask, render_template import pandas as pd app = Flask(__name__) @app.route("/") def index(): df = pd.read_csv("data/monthly_summary.csv") top_games = df.sort_values("hours", ascending=False).head(10) recent = pd.read_csv("data/play_log.csv").tail(15) return render_template("index.html", top=top_games, recent=recent)我不追求好看,追求信息和启动速度,整个 Flask 应用 1 秒内能起来,资源占用极低,放在一台旧迷你主机上 7×24 跑着,随时开机随时看。
6.4 现在回头看,哪些地方可以做得更好
复盘了整个项目,我自己比较满意的是"媒体归档 + 打卡统计"这套组合,它确实把日常的琐碎管理变成了可持续的习惯。但也有一些遗憾:
- 媒体分类如果做成"截图内容识别"会更强,比如用 OCR 识别游戏内文字判断所属游戏,但目前感觉成本偏高,暂时没做;
- 打卡表如果能做到从 PS App 直接读取游玩记录就更省事了,但那又回到接口合规问题,权衡之后还是维持手动。
这些留作以后的版本迭代方向,也算是这个项目还有生命力的证据。
最后分享一个我在实际使用中的个人体会:AnyPS5 最大的价值,其实不是自动化本身,而是它逼着我养成了"每周回顾一次游戏数据"的习惯。以前玩游戏是玩完就忘,现在有了记录,每个月回头翻翻截图和时长表,反而能更清晰地看见自己的游戏偏好和时间分配。对任何想做同类工具的玩家,我建议你们从最小的场景开始——哪怕只是先解决截图命名问题,先跑通一个月的打卡表——你会发现积少成多之后,这套数据会成为自己数字生活里很宝贵的一部分。