Textractor 技术指南:Windows/Wine 游戏文本 Hook 工具的原理与实战
开发工具逆向工程桌面应用【免费下载链接】TextractorExtracts text from video games and visual novels. Highly extensible.项目地址https://gitcode.com/gh_mirrors/te/Textractor点击查看免费下载Textractor曾用名 NextHooker是一个运行于 Windows 7 及 Wine 之上的 x86/x64 开源游戏文本提取工具通过向游戏进程注入 DLL、Hook 文本输出函数并借助命名管道回传数据实现对视觉小说与各类游戏引擎文本的实时捕获。本篇以项目的俄文 README 为主线完整覆盖其下载、功能、/H 与 /R 钩子码语法、扩展机制、编译方法与整体架构并结合作用户指南 docs/TUTORIAL.md帮助读者既会用工具也理解其底层实现。项目概述Textractor是一个高度可扩展的开源文本 Hook 器最初脱胎于 ITHVNRITH VNR 引擎项目用于从视频游戏与视觉小说中提取对话与 UI 文本。它同时支持 32 位与 64 位进程并可在 Wine 环境下列为可用方案。项目提供多语言 README含英文、简体中文、俄文等十余种语言用户也可观看 docs/TUTORIAL.md 中记录的教学视频快速上手。俄文 README 列出的核心特性如下与英文版一致可直接作为功能清单高度可扩展所有后处理逻辑都以扩展Extension形式实现自动捕获可从大量游戏引擎自动 Hook 文本其中包括部分 VNR 并不支持的引擎/H hook 码通过 Hook 码拦截指定函数的参数或返回值来捕获文本兼容大多数 AGTHAnother Game Text Hooker代码/R read 码不注入 Hook而是按地址周期性直接读取目标内存实现直读式文本抽取。获取版本Textractor 的正式发行版可在项目官方 Releases 中下载更早的 ITHVNR 版本在俄文 README 中给出了存档链接英文 README 还额外提到带调试信息的实验性构建可以从持续集成平台的 Artifacts 中获取。下载后解压即可运行Textractor.exe无需额外安装。若要针对某款特定游戏长期捕获项目约定游戏根目录下可放置TextractorConfig.txt配置文件见 include/defs.h 中GAME_CONFIG_FILE的定义用于保存该游戏的 Hook 码等设置。钩子码语法/H hook 码与 /R read 码钩子码是 Textractor 的核心使用方式一行代码即可描述在哪里、按什么格式读多少字节、如何解码。所有解析逻辑集中在 host/hookcode.cpp入口函数HookCode::Parse会去掉可选的前缀/与行尾斜杠兼容 legacy/AGTH 写法再按首字母分发到ParseHCode或ParseRCode参见 host/hookcode.cpp。/H hook 码/H 码的一般结构见ParseHCode实现host/hookcode.cpp/H {类型标志} [F] [null_length] [N] [codepage#] [padding] 偏移 [*间接索引] [:分割偏移 [*分割间接索引]] 地址[:模块[:函数]]各字段的含义字段取值作用类型标志A大端长度前置按长度前缀读取定长文本B小端长度前置同上小端序SANSI 字符串直到结尾QUnicode 字符串VUTF-8 字符串MUnicode 十六进制转储HEX dump 模式F—完整字符串模式按参数实际读取整串并补换行null_length数字文本长度位于字符串指针前null_length字节处负偏移写法N—不读取调用上下文NO_CONTEXTcodepage#数字指定代码页例如936#为 GBK、65001#为 UTF-8padding十六进制读取前跳过的填充字节偏移十六进制目标寄存器/参数偏移ITH 与 AGTH 的寄存器偏移相差 4解析时会自动校正*间接索引十六进制二级指针解引用DATA_INDIRECT:分割偏移十六进制从另一寄存器取长度USING_SPLIT可再带*表示二级解引用地址十六进制要 Hook 的函数地址:模块文件名地址相对模块基址如gdi.dll:函数符号名地址相对函数入口如GetTextOutA源码中自带的测试用例给出了真实可解析的完整示例host/hookcode.cpp/HQN936#-c*C:C*1C4AA:gdi.dll:GetTextOutA ; Hook gdi.dll!GetTextOutAGBK 解码双级指针 双级长度 /HB40 ; 长度前置的 ANSI 文本 /RS65001#44 ; UTF-8 直读码GenerateHCode还支持反向生成给定HookParam与进程 ID它会把绝对地址尝试折算成模块 偏移形式通过VirtualQueryEx找到所属模块使 Hook 码在 ASLR 下更稳定host/hookcode.cpp。/R read 码/R 码描述一次内存直读结构为见 host/hookcode.cpp/R {S|Q|V|M} [null_length] [codepage#] 地址SANSI 字符串QUnicode 字符串VUTF-8MUnicode 十六进制转储null_length长度前置位置codepage#代码页如/RS65001#44表示按 UTF-8 直读0x44处的字符串非法前缀如/RW44会解析失败被拒绝。/R 码与 /H 码的差异在于/H 需要注入一小段指令到目标函数首部把参数转发出来/R 则不需要 Hook 代码适合已知剧情文本缓冲区地址的场景。扩展机制俄文 README 指出官方扩展示例项目展示了如何构建扩展而仓库内的 extensions/ 文件夹本身就是扩展功能的活文档。该目录下包含十余个用 C 编写的扩展覆盖了从文本清洗到功能增强removerepeatchar.cpp/removerepeatphrase.cpp/removerepeatsentence.cpp去除重复字符、短语与句子游戏引擎反复重绘对话时的常见问题regexfilter.cpp/regexreplacer.cpp/replacer.cpp/styler.cpp基于正则与替换规则的过滤、改写与样式化extranewlines.cpp、exnewlines/extrawindow.cpp换行处理与独立文本窗口copyclipboard.cpp/threadlinker.cpp剪贴板同步与多线程文本关联bingtranslate.cpp/googletranslate.cpp/deepltranslate.cpp/translatewrapper.cpp多种翻译服务的封装lua.cpp/devtools.cppLua 脚本扩展与开发者调试工具。从源码结构看GUI 在显示每一条文本前会先把它连同元数据分发给所有扩展GUI/mainwindow.cpp 中调用DispatchSentenceToExtensions(sentence, GetSentenceInfo(thread).data())若某个扩展返回跳过则该句不显示。扩展与宿主之间的元数据接口定义在 extensions/extension.hSentenceInfo以名字 → 整型值的数组形式向扩展暴露线程名、代码页等信息扩展也可通过抛出自定义的SKIP异常主动丢弃文本。编译项目编译 Textractor 的前置条件俄文 README Compiling 一节原文要求安装支持 CMake 的 Visual Studio安装 Qt 5.13。随后直接用 Visual Studio 打开源码文件夹、选择配置并构建产物即为Textractor.exe。从 CMakeLists.txt 可以看到这些要求在工程层面的体现项目强制 MSVC非 MSVC 工具链会直接FATAL_ERROR终止配置CMakeLists.txt全局编译选项为 C17、多核编译/MP并按目标位数链接x64libs或x86libsCMakeLists.txt通过cmake/QtUtils.cmake注册表搜索定位 Qt 5 的Core、Widgets、WinExtras、WebSockets模块CMakeLists.txt工程由host、texthook、GUI、extensions、test五个子工程组成CMakeLists.txt分别对应宿主程序、被注入 DLL、图形界面、扩展与测试。注意英文版 README 额外提示从源码构建前需先克隆仓库并初始化子模块git submodule update --init因为texthook/minhook/等目录依赖子模块内容。项目架构俄文 README 的项目架构一节描述了完整的数据通路**宿主host向目标进程注入 texthook.dll两者通过两条命名管道通信texthook 等待管道接通后向文本输出函数如TextOut、GetGlyphOutline注入少量指令把它们的输入参数转发到管道宿主对收到的文本做初步处理后交回 GUIGUI 在显示前再把文本分发给扩展。**下面结合源码逐环节拆解。两条命名管道管道名与同步对象集中定义在 include/defs.hconstexpr auto HOOK_PIPE L\\\\.\\pipe\\TEXTRACTOR_HOOK; // texthook → host constexpr auto HOST_PIPE L\\\\.\\pipe\\TEXTRACTOR_HOST; // host → texthookhostPipeTEXTRACTOR_HOST宿主写入端向被注入的 DLL 下发命令hookPipeTEXTRACTOR_HOOKtexthook 写入端回传捕获的文本、控制台日志与钩子事件。两者都以PIPE_TYPE_MESSAGE消息型管道创建保证每条消息边界完整。texthook.dll 的启动与管道线程被注入的 DLL 生命周期入口在 texthook/main.cc 的DllMain用命名互斥量VNR_HOOKMAN_pid防止对同一进程重复注入创建内核对象文件映射即 README 中所说的文件视图 / section objectVNR_SECTION_pid并把其中一段内存映射为TextHook hooks[MAX_HOOK]数组——宿主进程稍后会只读映射同一块内存从而不经过管道即可查看当前所有 Hook 的状态地址、参数、名称等初始化 MinHook 后创建独立的Pipe线程texthook/main.cc。Pipe线程的工作循环等待事件TEXTRACTOR_PIPE_AVAILABLE随后以客户端身份连接两条管道CreateFileW打开HOST_PIPE与HOOK_PIPEtexthook/main.cc先通过 hookPipe 写入自己的进程 ID宿主据此建立进程记录调用Engine::Hijack()定义于 texthook/engine/match.cc启动各引擎的自动匹配/Hook 逻辑循环读取 hostPipe 命令switch分发四种HostCommandTypeHOST_COMMAND_NEW_HOOK按用户给定的HookParam插入新 Hook名称形如UserHook1HOST_COMMAND_REMOVE_HOOK移除指定地址附近的 HookHOST_COMMAND_FIND_HOOK按SearchParam搜索——给了文本则SearchForText按已知文本反查地址否则SearchForHooks自动搜索候选 HookHOST_COMMAND_DETACH结束循环DLL 自清理并FreeLibraryAndExitThread。捕获到的文本经TextOutput打包成ThreadParam头 原文写入 hookPipetexthook/main.cc找到的 Hook 通过NotifyHookFound上报宿主会据此生成/H码并打印到控制台方便用户保存为游戏配置。宿主侧管道管理、注入与文本整理宿主逻辑在 host/host.cpp。CreatePipe为每对连接创建两条消息管道hookPipe 为PIPE_ACCESS_INBOUNDhookPipe 连接成功后先读回 4 字节进程 ID 建立ProcessRecord再递归调用自身以便支持多进程同时挂接host/host.cpp。每个ProcessRecord保存该进程的 hostPipe 句柄、对VNR_SECTION_pid的只读映射视图README 所说映射到 TextHook 类引用的对象以及保护该视图的互斥量。读取 hookPipe 的主循环按HostNotificationType分派FOUND_HOOK转换编码后回调 GUI 控制台、RMVHOOK清理对应线程、TEXT控制台输出其余情况按默认分支视为文本数据——取出ThreadParam头按进程 地址 上下文哈希定位TextThread首次出现时触发OnCreate然后把原始字节Push进线程缓冲host/host.cpp。进程注入实现在Host::InjectProcesshost/host.cpp是标准的 CreateRemoteThread 注入用VNR_HOOKMAN_pid互斥量先占位已存在则提示已注入OpenProcess(PROCESS_ALL_ACCESS)打开目标IsWow64Process检查 32/64 位匹配VirtualAllocExWriteProcessMemory写入texthook.dll的完整路径再CreateRemoteThread调用LoadLibraryW完成加载。宿主还内置了两个特殊TextThreadconsole系统日志输出与clipboardhost/host.cpp后者借助WH_GETMESSAGE钩子监听WM_CLIPBOARDUPDATE把系统剪贴板里的文本也汇入统一管线——这解释了为何许多扩展能对复制出来的游戏文本同样生效。文本缓冲的整理逻辑在 host/textthread.cpp 的TextThread::Push双字节字符集DBCS保护当一次只读到 1 字节且是 DBCS 前导字节时IsDBCSLeadByteEx先暂存等下一字节配对避免 GBK 等编码在消息边界被切断编码转换按HEX_DUMP、USING_UNICODE或codepage分支处理Unicode 直接转换ANSI 经StringToWideString按指定代码页缺省为Host::defaultCodepage转宽字符重复过滤RemoveRepetition检测整句被引擎连续重绘 N 遍的情况并只保留一句对应英文 README 提到的 issue #40每 10 毫秒的定时器队列CreateTimerQueueTimer负责把缓冲按时间窗口切分成句子sentence向上层输出。数据流总览综合以上源码README 描述的链路可还原为游戏进程 └─ texthook.dllLoadLibrary 注入 ├─ DllMain: 建 VNR_SECTION_pid 共享视图 Pipe 线程 ├─ Pipe 线程: 连接管道 → Engine::Hijack() → 处理 /H、搜索、移除、断开 └─ 文本输出: ThreadParam 原文 → hookPipe (\\.\pipe\TEXTRACTOR_HOOK) 宿主 host ├─ CreatePipe: 建立双向消息管道按 PID 维护 ProcessRecord ├─ hostPipe 下发命令插入/移除/搜索/断开 ├─ 只读映射 VNR_SECTION_pid 查看 Hook 状态 └─ TextThread: DBCS 拼接、代码页转换、去重、定时切句 GUI ├─ 显示文本线程 / 控制台 / 剪贴板线程 └─ DispatchSentenceToExtensions: 每句先过扩展再显示支持与贡献俄文 README 给出了明确的协作约定反馈渠道任何 bug、Textractor 无法 Hook 的游戏、功能请求都欢迎提出若某款游戏无法捕获作者希望通过免费下载链接或 Steam 礼物获取该游戏用于实测贡献方式关于代码库的问题可邮件联系作者PR 遵循标准流程fork → 建分支 → 提交改动 → 向 master 发起 PR翻译贡献所有界面字符串集中在 text.cpp 中按语言分组维护俄文HIJACK_ERROR等字符串就在其中翻译该文件与 README 即可完成多语言贡献贡献者名单见 docs/CREDITS.md。小结Textractor 以宿主 被注入 DLL 双管道 共享视图的经典注入架构把游戏内的文本捕获做成了可编码化/H、/R 码、可搜索自动找 Hook、可后处理C/Lua 扩展管线的完整工具链。若你要为某款游戏做文本提取实践路径是先试自动引擎匹配 → 失败则用按文本搜索或手动/H码定位TextOut*/GetGlyphOutline类调用点 → 保存 Hook 码到TextractorConfig.txt→ 用 extensions/ 中的去重、正则扩展清洗输出。仓库中的 include/defs.h、texthook/main.cc、host/host.cpp 与 host/hookcode.cpp 是深入原理时最值得精读的四份文件。赞分享开发工具逆向工程桌面应用【免费下载链接】TextractorExtracts text from video games and visual novels. Highly extensible.项目地址https://gitcode.com/gh_mirrors/te/Textractor点击查看免费下载相关推荐Textractor 技术指南游戏文本 Hook 工具的项目架构、Hook 代码机制与构建详解Textractor 技术指南游戏文本 Hook 工具的项目架构、Hook 代码机制与构建详解 本文为基于 Textractor 官方文档README_DE开发工具逆向工程桌面应用Textractor强大的Windows游戏文本提取工具完全指南Textractor强大的Windows游戏文本提取工具完全指南 Textractor是一款专为Windows系统设计的开源游戏文本钩子工具能够精准捕获游戏开发工具逆向工程桌面应用Better Auth 环境变量完全指南2 个必配项、密钥轮换与避坑速查Better Auth 环境变量完全指南2 个必配项、密钥轮换与避坑速查 Better Auth 是目前覆盖面最广的开源认证框架邮箱密码、社交登录、Pass认证鉴权后端身份认证上一篇5分钟搭建高性能Python FTP服务器pyftpdlib终极指南 下一篇LogicStack-LeetCode 题解精讲1331. 数组序号转换 —— 排序 哈希表模拟的经典模板创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

高斯混合模型GMM聚类实战:从K-Means到软分配与scikit-learn调优

高斯混合模型GMM聚类实战:从K-Means到软分配与scikit-learn调优

1. 为什么在聚类任务里我会优先考虑高斯混合模型很多人第一次接触聚类,脑子里蹦出来的第一个算法基本都是K-Means。原因很简单,它足够直观,代码几行就能跑通,效果在大多数场景下也还过得去。但如果你做过一段时间的实际项目就会发…

2026/10/15 8:29:41 阅读更多 →
artcraft深度拆解:从创意到成品的可控随机性设计

artcraft深度拆解:从创意到成品的可控随机性设计

1. 项目缘起与整体设计思路第一次看到“artcraft”这个标题,我脑子里蹦出来的第一反应是“艺术”加“手艺”的组合词。直觉告诉我,这大概率是一个跟创意工具、手工制作、或者数字艺术生成相关的项目。后来跟几个做独立开发的朋友聊了聊,发现大…

2026/10/15 8:29:41 阅读更多 →
diagram-design:从画图到系统化图表设计实践

diagram-design:从画图到系统化图表设计实践

1. 从一张草图到一套系统:diagram-design 到底在解决什么问题第一次听到 “diagram-design” 这个词,很多人会下意识觉得它只是“画图”的另一种说法。但真正在项目里被图表折磨过的人都知道,画一张图不难,难的是让图在三个月后还…

2026/10/16 15:56:16 阅读更多 →

最新新闻

MATLAB EMD工具箱实战:从经验模态分解到HHT时频分析

MATLAB EMD工具箱实战:从经验模态分解到HHT时频分析

简介:Matlab EMD经验模态分解工具箱,面向信号处理、故障诊断与振动分析领域的研究人员与工程师,用于对非线性、非平稳信号做自适应分解并提取有物理意义的本征模态函数分量。压缩包共38个文件,其中10个m脚本承担核心算法与在线/局…

2026/10/16 19:42:22 阅读更多 →
教务管理系统源码解析:技术选型、数据库设计与二次开发避坑指南

教务管理系统源码解析:技术选型、数据库设计与二次开发避坑指南

简介:这是一套面向计算机专业学生与Java Web开发者的教务管理系统完整源码,适合作为课程设计、毕业设计或企业级项目练手参考,帮助理解教育管理信息化的业务逻辑与技术落地。资源包共746个文件,约5.46MB,涵盖html、css…

2026/10/16 19:42:22 阅读更多 →
E7-2 AXOS everyPON 数据服务实施:从订户模板到策略映射实战指南

E7-2 AXOS everyPON 数据服务实施:从订户模板到策略映射实战指南

简介:Calix E7-2 AXOS everyPON数据服务实施课程的官方介绍文档,面向负责二层数据服务部署的技术员、网络运营者、规划师与工程师。资源包内仅含1个PDF文件,容量74KB,以精炼篇幅浓缩了4小时讲师授课的核心内容:E7-2 AX…

2026/10/16 19:42:22 阅读更多 →
gemma-skills新手必读:Google官方两大技能如何让AI Agent具备Gemma开发与微调能力

gemma-skills新手必读:Google官方两大技能如何让AI Agent具备Gemma开发与微调能力

【免费下载链接】gemma-skills Skills for the Gemma and model/agent interactions 项目地址: https://gitcode.com/gh_mirrors/ge/gemma-skills 点击查看 免费下载 如果你是刚接触 Gemma 模型的新手,gemma-skills 会是一个绝佳的起点。这是 Google 官…

2026/10/16 19:41:22 阅读更多 →
DeepSeek-V3-W4A8-Pruing权重文件怎么读?safetensors三分片结构与index索引完全解析

DeepSeek-V3-W4A8-Pruing权重文件怎么读?safetensors三分片结构与index索引完全解析

【免费下载链接】DeepSeek-V3-W4A8-Pruing 项目地址: https://ai.gitcode.com/hf_mirrors/vllm-ascend/DeepSeek-V3-W4A8-Pruing 点击查看 免费下载 初次接触 DeepSeek-V3-W4A8-Pruing 模型仓库时,面对 3 个 safetensors 分片文件、一个 578KB 的 index…

2026/10/16 19:41:22 阅读更多 →
整车控制器开发源代码:模块划分、状态机设计与工程落地

整车控制器开发源代码:模块划分、状态机设计与工程落地

简介:整车控制器(VCU)开发源代码包主要面向电动汽车与混合动力汽车控制系统的开发者、算法工程师及嵌入式软件研究者,用于解决VCU底层驱动、控制策略、状态机管理与故障处理等核心开发问题。包内文件共88个,以C源文件、…

2026/10/16 19:40:21 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →