用Python和OCR构建PS5截图与测试数据管理工具
做主机游戏内容管理和测试数据整理这两年我一直在跟一堆命名混乱的截图和录像较劲。最初只是一时兴起想把自己的PS5游戏截图按作品归类后来发现项目测试环节也需要类似能力于是就有了AnyPS5这个工具。它解决的核心问题很简单把主机导出的媒体文件、测试用例、游戏时长和备注信息统一收进一个本地库再自动生成可读性很强的报告。如果你经常为PS5的截图录像整理头疼或者做主机游戏开发时想把手动测试过程沉淀成结构化数据这篇文章值得看完。1. 为什么需要一个叫AnyPS5的PS5资源管理工具1.1 从一团乱麻的测试截图说起先说个很实际的场景。PS5主机默认会把截图存成类似“20250101_123456_ABCD1234.PNG”的文件名这个命名包含日期、时间和一段随机编码但不会告诉你它属于哪个游戏、是在哪个关卡、对应哪条测试用例。我最早是在某开发小组里做主机游戏的手工体验验证每天都要从测试机导出一两百张截图然后人工对着用例表格一张张改文件名、填备注。一天下来光整理素材就占掉两三个小时真正用来分析问题的精力反而被压缩了。AnyPS5最开始就是想把这部分重复劳动干掉把截图从主机拷贝到电脑以后自动识别游戏信息、自动关联用例、自动生成当日报告。很多玩家朋友也有类似的痛点。明明只想整理一下自己的游玩记录但相册里几千张截图混在一起想找某个游戏某一章的画面得翻半天。工具本身不复杂关键是“整理规则”怎么定才能既符合主机平台的文件特点又不依赖任何内部接口。1.2 市面工具解决不了的三个痛点市面上的截图管理软件很多但它们大多是为手机或PC设计的对PS5平台的文件特点几乎不关心。我在试用了一轮之后发现了三个通用工具死活绕不过去的坎。第一文件名信息量不足。主机导出的文件虽然在系统相册里有完整信息但拷贝到电脑以后很多元数据会丢失你能依赖的往往只有文件名和时间戳。第二按游戏维度聚合这件事普通相册工具做不到。相册只知道“这是个图片”不知道“这张图属于某个游戏”。第三测试场景里“截图要能对应到用例”这个需求市面工具更是完全没有概念。它们能帮你建相册但不会帮你写测试用例编号。所以AnyPS5从一开始就不是一个“相册替代品”它是一个面向PS5媒体文件和管理动作的规则引擎你给它一个导入目录它按你的规则自动处理文件归属、命名、归档和报告输出。这个定位和常见工具完全不同也让它的使用逻辑更贴近实际干活的人。2. AnyPS5的整体架构与模块拆解2.1 三条数据流一个中心库AnyPS5的架构可以拆成三个数据输入口和一个核心存储。第一条数据流是“媒体文件流”也就是那些从主机拷贝过来的截图和录像。第二条是“用例描述流”测试人员事先会把用例编号、标题、预期结果整理成表格由工具导入。第三条是“人工备注流”用来处理工具识别不出、需要人来补充说明的边界情况比如同一张截图希望同时关联两个用例或者某张图有特别的意思。三条流汇入同一个SQLite数据库用统一的表结构保存文件路径、游戏名称、截图时间、用例编号、备注标签、哈希值等字段。存储层不搞复杂的概念就是一张主表和几张关联表。files_map ├── file_id ├── original_name ├── normalized_name ├── file_hash ├── game_tag ├── scene_text ├── case_id ├── shot_time ├── stored_path └── extra_tags这个中心库的好处是后续所有功能都只读这一处。生成报告、按游戏统计时长、搜索某条用例的截图都变成对这张表的查询不用到处翻文件系统。2.2 技术选型为什么是Python SQLite WatchdogAnyPS5的核心技术栈是Python辅助用SQLite做存储Watchdog做目录监听OCR部分用PaddleOCR或Tesseract都行看本机环境。选Python不是因为它语言本身有多特别而是因为整个工具链刚好都能在这一门语言里闭环。图片预览、重命名、哈希计算、OCR识别、报告模板渲染全部都有生态成熟的库不用东拼西凑去搭多语言体系。对一个要长期维护、希望别人也能一键跑起来的小项目来说多语言只会增加维护成本。SQLite则是刻意做的“缩水”选择。有人问怎么不用MySQL或PostgreSQL我的理由很实在这个工具本质上是单机应用数据量就算上万张截图也只有几百MBSQLite一个文件就能搞定备份时直接复制文件走人。没有服务器、没有网络配置、没有用户权限管理部署成本几乎为零。真到了需要多人协作的时候后续也有平滑迁移的路径这一点在扩展那一节再讲。Watchdog负责监听导入目录。实际体验是当我把主机U盘插到电脑上或者把媒体导入到专门文件夹时工具自动开始处理新文件不用反复点“开始导入”。这个功能虽然不起眼但用了就回不去属于典型的“没有它也不影响基本使用有了它舒适度提升一大截”的设计。3. 最容易被忽视的媒体文件标准化问题3.1 主机导出的文件名没有唯一标识这是AnyPS5开发过程中最让我意外的一个坑。拿到一批PS5截图后我发现文件名里的时间戳经常出现错位有些文件标的是UTC时间有些标的是本地时间还有些完全对不上拍摄顺序。如果直接用文件名里的时间作为截图时间做排序和统计结果必然混乱。正确做法是优先相信文件系统和图像自身的元数据。JPEG和PNG文件通常带有拍摄时间信息从EXIF或PNG文本块里读时间戳比文件名可靠得多。读取不到时才退回到文件名时间戳同时用文件创建时间做交叉验证取差值较小的那个作为有效值。这一步听起来很基础但实际很多工具都栽在“懒省事直接用文件名”上。AnyPS5把时间校验做成了独立模块每次处理都会打印三份时间的对比人工抽查时一眼就能看出是否有偏差。exif_time : 2025-01-01 12:35:02 file_name : 20250101_123602 crt_time : 2025-01-01 20:36:15 resolved : 2025-01-01 12:35:023.2 用OCR识别游戏内文字做自动打标文件标准化最难的部分不是时间而是“这张截图属于哪个游戏、哪个关卡”。文件名里没有游戏信息除非每张截完图立刻人工标注否则后续分类就断了线索。AnyPS5的处理方法是做两层识别。第一层是全局匹配截图画面里通常有游戏标题或者具辨识度的UI元素用OCR把画面文字提取出来再和事先维护的“游戏关键词库”做模糊匹配。第二层是局部匹配当OCR结果没有直接命中游戏名就截取画面固定区域比如左上角的关卡提示、右下角的版本号做二次识别提高准确率。我的测试数据显示纯OCR直接命中游戏名的概率差不多七成配合关键词库和场景规则之后能到九成以上剩下的一成就得靠人工备注。千万别指望OCR百分之百正确设计工具时要留出“人工兜底”的入口否则系统自动打错标签比不整理更麻烦。3.3 文件去重与哈希校验的细节导出的截图多了以后必然会出现重复文件。有些是同一画面按了两三次快捷键有些是重新导出了同一批图还有一种是文件内容完全一样但文件名不同。简单的文件名去重拦不住最后一种必须算哈希。对大文件录像做完整MD5会非常慢我采用了两级策略先用文件大小做粗筛大小完全相同再算前1MB和最后1MB的采样哈希。实践下来用这种“首尾采样法”处理4K录像片段速度比完整MD5快几十倍而且误判率极低。同一台主机导出的同一条录像首尾内容几乎不可能不一致所以这个方案在准确性和性能之间取得了很实用的平衡。唯一需要注意的是采样哈希的理论碰撞问题。对视频采集这种固定来源的文件首尾块相同但中间不同的概率很小但不是零。如果后续要拿去做正式存档或者证据材料建议还是全量计算一次完整哈希把结果存进数据库以后每次导入都能直接比对。4. 核心功能实操从媒体库到测试报告4.1 一键导入与自动归类实际操作流程比我预想的更简单所有工作都围绕一个导入目录展开。从PS5把媒体文件拷到PC上指定的“导入文件夹”AnyPS5的Watchdog进程会第一时间发现新文件然后按照“识别游戏名称 → 解析拍摄时间 → 计算哈希 → 生成标准化文件名 → 移动到归档目录”的顺序自动处理。标准化之后的文件名形如{游戏标签}_{日期}_{时间}_{用例编号}_{序号}.{ext}比如“落叶冒险_20250101_123502_CASE_013_01.png”。这样即使不打开工具光看文件名也能知道这张截图属于哪个游戏、什么时候拍的、对应哪条测试用例。归档目录则按照“游戏名称 / 日期 / 用例编号”的层级存储查找起来非常直观。导入之后命令行窗口会打印处理摘要包括新增文件数、重复文件数、识别失败数。识别失败的文件会被放进独立的待处理目录不会和正常文件混在一起避免干扰后续报告统计。4.2 用例关联与时长统计的建模用例关联是AnyPS5相对有门槛的部分。它需要一张测试计划表至少有“用例编号、模块名称、测试标题、前置条件、执行步骤、预期结果”这些列。工具读取这张表后把用例编号和导入的截图自动匹配。匹配策略是按时间窗口来做。比如一条用例从开始执行到结束大概持续30分钟那么在这个时间窗口内拍下的截图会自动绑定到这条用例。有人会觉得这个策略太粗糙但在实际测试中它已经能覆盖大部分情况。更精确的场景可以进行人工复核比如打开一个简单的TUI界面批量拖动调整截图归属。时长统计也顺手做掉了。工具会记录每条用例首次截图和最后一次截图的时间差汇总成当日各用例的实际执行时长。这个数据用来估算回归测试的工作量非常有用比让测试人员自己回忆要靠谱得多。4.3 生成Markdown/HTML测试报告所有数据入库以后报告生成就水到渠成了。AnyPS5内置两种报告输出Markdown格式适合提交到Git仓库或者粘贴进文档系统HTML格式适合直接发给相关协作成员查看带简单筛选器能按游戏、按测试人员、按日期过滤。报告内容分为三块。第一块是汇总表展示当日新增文件数、有效用例数、总测试时长、用例通过率。第二块是逐用例明细每条用例下面附上截图缩略图和OCR识别出的场景文字方便其他成员不用打开原始文件就能快速了解情况。第三块是问题清单如果某条用例关联的截图特别多或者OCR识别出大量红色警告类文字工具会自动标记为“疑似异常”。生成报告的命令只有一行anyps5 report --date 2025-01-01 --format html整个过程几十秒完成。原来我整理一天测试素材要花两三个小时现在从拷贝到拿到报告基本不超过十分钟主要时间还是花在U盘传输上。5. 实测中的意外情况与对应处理5.1 OCR把界面文字认成了乱码先说一个大家都可能遇到的坑。最初我直接用中文界面的游戏截图做OCR结果识别准确率很不理想好好的“设置”两个字被读成“设 董”关卡名更是经常变成一串不明字符。排查之后发现原因有三层。第一主机截图的分辨率虽然高但UI文字往往比较小直接缩放过再丢给OCR必然损失清晰度。第二有些游戏用了艺术字体笔画装饰很多OCR模型没学过这种字形。第三OCR组件缺针对性的中文训练数据对游戏内的黑体、宋体混排场景支持一般。对应处理是先把截图里的目标区域裁出来并放大三倍再做OCR尽量用支持中文的模型配置对常用关键词建立同义词映射表把“设 董”这种错字在匹配阶段自动映射回“设置”。这些改进加起来把准确率拉回了可接受区间。我的体会是OCR在游戏截图这种场景下只能当辅助不能当唯一依据设计流程时一定要把人工复核留出来。5.2 时区错位导致数据流失另一个比较隐蔽的问题是时区。主机系统设置为本地时间但导出到U盘后部分文件的修改时间会被系统写入成UTC时间。某一天我点开统计报表发现深夜时段有一大批截图被归类到了第二天数据的日期分布整个乱了。处理思路在第三节已经提到过优先读EXIF时间但如果文件是主机录制的视频EXIF信息就不一定可靠了视频元数据里存的时间有时也存在偏移。我最终的方案是把时间解析模块做成可配置的在配置文件中指定时区偏移量按实际测试环境校正。[timezone] source_offset 0 local_offset 8实测校正之后截图跨零点的情况不再影响归属报告里的日期分布也恢复正常。这个小问题提醒我凡是涉及时间数据的功能时区处理一定要作为一个独立设计项而不是顺手写两个时间戳就完事。5.3 重复导入导致库膨胀AnyPS5刚跑通时我往导入目录里塞了好几次同一批演示视频结果数据库里出现了大量重复记录。因为媒体文件的哈希已经计算过理论上导入模块应该直接跳过但当时的逻辑只针对单个文件比对了哈希没有处理“批内重复”。什么意思呢如果第一次导入时库里没有文件A那么A会被正常入库但同一个批次里还混着另一个文件内容和A完全一样只是文件名不同它也会被当作“新文件”走完整个流程等到入库前哈希查重才发现冲突。这就白白消耗了OCR的时间和磁盘空间。修复方法是把哈希查重提前到文件发现阶段Watchdog每发现一个新文件立刻先算采样哈希缓存到内存里再统一处理。同一批次内的重复文件可以在进入完整流程前就直接拦截。同时数据库里增加了唯一索引约束就算前面的逻辑漏了后面也会兜底拒绝写入。这个问题虽然技术上不复杂但它让我意识到一个工具的“防呆设计”往往比功能本身更能决定使用体验。6. 可以直接抄的扩展思路6.1 从单人工具到团队协作AnyPS5现在默认是单机使用但我在实际项目中已经面临多人协作的需求。最简单的方式是把SQLite换成持久化服务比如改成PostgreSQL然后给工具加一个极简的HTTP接口支持远端查询截图列表和上传备注。数据库表结构基本不用改接口也只做两件事查询报告、更新人工备注。这样测试组每个人都能在浏览器里看到当天导入的截图谁在什么时间补了备注也都有记录。如果你不想引入服务端还有个取巧的办法把SQLite文件放到一个同步目录里所有人共享一套数据文件配合工具内置的简单的锁机制避免并发写入。这种方案胜在零部署但稳定性一般更适合三五人的小组。6.2 把AnyPS5接到CI/CD流程对做主机游戏开发的人来说AnyPS5还能变成一个自动化的回归审查工具。当代码变更触发构建后自动生成一批指定关卡的截图或录像导入工具之后和上一版本的截图做对比自动标出画面差异区域。这个场景需要额外加一个图像对比模块但已有文件管理、OCR识别和报告生成这些基础能力都可以复用。我目前已经跑通了一个简单的Demo每日构建后自动拉取测试机产生的媒体生成“变更点报告”归属成员一时间就能看到哪些画面变了、哪些文本变了。这类自动化最明显的好处是把人工对比画面差异的时间彻底省掉让测试人员更专注于判断“这个变化是否符合预期”。比起从零搭建一套全新的自动化体系在已有工具上做增量扩展要快得多。6.3 未来可以做的方向后续我打算加两个方向的能力。第一个是素材检索利用已有的OCR文本和游戏标签让用户用自然语言找出目标截图例如“找到所有出现过‘暂停菜单’字样的截图”本质上是对结构化标注信息的查询优化。第二个是时长分析的进阶可以按游戏、按关卡、按用例维度统计实际游玩时长甚至产出热力图看出哪段时间测试密度最高哪些模块容易被忽略。这些方向都建立在中心库的结构化数据之上真正做到了“一处的数据沉淀多处的价值复用”。我不打算把AnyPS5做成一个功能堆砌的大平台保持小而准反而更容易长期维护。最后分享一个我自己实际用下来的体会AnyPS5这种工具最值钱的部分不是OCR也不是报告而是“规则先行”的整理思路。先把文件怎么命名、时间怎么解析、用例怎么关联这些边界条件定义清楚再写代码比边写边想省事得多。如果你也想给自己的PS5媒体库或者测试流程做一个类似的管理工具建议先花半天时间把自己的文件命名规则和整理逻辑写出来再动手写第一行代码。剩下的就算不用这个项目照着这些思路做出来的东西也不会差太多。

相关新闻

婚礼互动游戏风险防控与危机处理实战指南

婚礼互动游戏风险防控与危机处理实战指南

1. 婚礼互动游戏背后的商业逻辑这个看似荒诞的婚礼故事,实际上揭示了现代商业活动中常见的"测试型营销"策略。当新人把摇一摇互动游戏作为婚礼暖场环节时,他们可能没想到会摇出"债主",但这恰恰是甲方精心设计的商业考验。…

2026/10/13 6:15:45 阅读更多 →
从单向到双向:有限元多场耦合优化的关键技术与工程实践

从单向到双向:有限元多场耦合优化的关键技术与工程实践

我刚开始做多场耦合那阵子,最头疼的不是网格画不好,也不是单元选不对,而是单物理场算什么都正常,一把温度、电磁、结构放到一起就算不出来,要么振荡发散,要么算出一个看起来“很漂亮”但跟实测对不上的数。…

2026/10/13 6:15:45 阅读更多 →
YOLOv5 TensorRT DLL封装:Windows上C++/C#/Python集成与避坑

YOLOv5 TensorRT DLL封装:Windows上C++/C#/Python集成与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 6:14:45 阅读更多 →

最新新闻

Spring Boot 3.x API密钥轮换机制:从状态机设计到平滑过渡

Spring Boot 3.x API密钥轮换机制:从状态机设计到平滑过渡

做后端开发这几年,只要接口走的是 API 密钥认证,密钥轮换就是一个绕不开的话题。Spring Boot 3.x 项目里,密钥轮换的坑尤其隐蔽:表面上看,更新一下数据库里的 key,客户端换一下配置就行,但实际一…

2026/10/13 7:38:09 阅读更多 →
深度学习优化算法与参数初始化:从梯度下降到动量实战

深度学习优化算法与参数初始化:从梯度下降到动量实战

2020年2月16日,我的深度学习笔记写到第八篇。上一篇从经验风险最小化聊到泛化误差,基本把“优化目标”讲清楚了;但目标归目标,真正让模型训练起来的是优化算法本身。这篇笔记把镜头拉到更新公式这一层,重点拆两块&…

2026/10/13 7:38:09 阅读更多 →
真三MOD专用蓝宝石渲染管线2.2b优化指南

真三MOD专用蓝宝石渲染管线2.2b优化指南

简介:本资源是魔兽争霸III玩家专用的自定义地图优化版本,面向熟悉真三国无双类RPG地图的中高级玩家,解决原版平衡性不足、技能冗余或运行卡顿等问题。压缩包为RAR格式,共2个文件:核心地图文件BT蓝宝石专署2.2b.w3x&…

2026/10/13 7:38:09 阅读更多 →
SpringBoot毕业生就业去向登记管理系统:毕设源码与二次开发指南

SpringBoot毕业生就业去向登记管理系统:毕设源码与二次开发指南

简介:这份资源是面向计算机专业毕业生与Java初学者的一套完整就业去向登记管理系统源码,可直接作为毕业设计或课程设计参考。系统基于SpringBoot框架开发,覆盖需求分析、总体设计、详细设计与功能测试全流程,包含功能结构、数据结…

2026/10/13 7:38:09 阅读更多 →
Spring Boot 3.x API密钥认证与密钥轮换实战指南

Spring Boot 3.x API密钥认证与密钥轮换实战指南

“你的服务对接了十几个下游调用方,大家约定好每次请求头里带一个 API Key,服务端校验通过才放行。密钥用了一年,安全团队突然要求立即轮换,你改配置、重启、发通知,结果重启期间服务不可用,调用方新旧密钥…

2026/10/13 7:38:09 阅读更多 →
链表分解:从内存布局到指针偏移的底层实践

链表分解:从内存布局到指针偏移的底层实践

1. 项目概述:这不是“拆链子”,而是把链表“掰开揉碎”讲清楚 “链表的分解”这五个字,乍看像一道算法题的标题,但实际在一线教学、代码评审和系统调试中,它代表一种极其关键的底层思维训练——不是单纯地写个反转或删…

2026/10/13 7:37:09 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →