浏览器里的 RoboMaster 助手,持续扩展 RM 的使用体验与无限可能。
源代码 · 演示视频 · 软件说明书 · Microsoft Edge Add-ons · Chrome Web Store
RM Extension 是一个面向 RoboMaster 社区的可持续扩展型浏览器助手。它以浏览器扩展为统一载体,连接 RoboMaster 官网、论坛以及 RMer 日常使用的协作平台,逐步解决资料发布、赛事观看和社区使用中的重复操作与体验问题。
项目当前落地了两项能力:一是将飞书文档或整个知识库迁移到 RoboMaster 论坛,二是通过 RMLive 增强官网直播体验。飞书迁移是目前功能最完整、技术积累最集中的模块,也是当前技术实现最完整的能力;它不代表 RM Extension 的最终功能边界,后续能力将继续围绕真实的 RoboMaster 社区需求扩展。
截至 2026-08-23,项目已有以下公开成果:
| 指标 | 结果 | 数据来源 |
|---|---|---|
| 论坛站内引用 | 114 次 | 软件说明书 |
| Bilibili 演示 | 4,792 播放、470 点赞、235 投币、260 收藏 | 视频页面 |
| Edge 扩展 | 283 名用户 | 商店页面 |
| Chrome 扩展 | 114 名用户 | 商店页面 |
| Microsoft Edge Add-ons · 283 名用户 | Chrome Web Store · 114 名用户 |
|---|---|
![]() | ![]() |
- 结构级转换:将飞书 Block 和富文本样式映射到论坛编辑器使用的 HTML,而非依赖反复复制粘贴。
- 完整资源迁移:自动下载图片、视频和附件,上传至论坛使用的 OSS,并可在更新文章时复用已有对象。
- 目录级迁移:读取飞书知识库树,根据插入、覆盖、空节点或跳过策略重建论坛 Wiki 层级和顺序。
项目名称中的 Extension 有双重含义:它首先是一款 Browser Extension(浏览器扩展),以浏览器为载体接入 RoboMaster 官网、论坛和外部服务;同时也代表 Extension of Possibilities(可能性的扩展),希望不断拓展 RMer 使用工具、共享知识和参与赛事的方式。这正是“扩展 RM 无限可能”的由来。
“扩展 RM 无限可能”不仅是项目名称,也是 RM Extension 的长期目标。RoboMaster 用户需要在官网、论坛、协作文档、赛事直播和其他工具之间频繁切换,其中仍有许多可以由浏览器扩展连接、自动化或重新设计的环节。RM Extension 采用模块化入口和按站点加载的 Content Script,使新能力可以逐步加入同一扩展,而不必把项目限定成单一用途的转换工具。
RoboMaster 战队常用飞书沉淀机械、嵌入式、算法和运营资料,但论坛开源通常需要再次整理。队员已经习惯在在线文档中多人协作,转到论坛编辑时却难以继续同步编辑;外部图片通常还要先下载、再重新上传。一个赛季专栏可能包含 30~50 篇文档,逐篇复制、校对和重建目录会形成大量重复劳动。
手工搬运不仅要复制正文,还要重新处理标题、列表、表格、公式、图片、附件和目录。内容规模越大、格式越复杂,搬运成本和人工疏漏风险就越高。
飞书迁移模块面向已经完成内容创作、希望发布到 RoboMaster 论坛的成员,目标是减少机械操作,同时尽可能保留原始结构。它不是通用飞书备份器,也不会把飞书在线表格、多维表格或画板转换成可编辑的论坛对象。这些限制只描述当前模块,并不限制 RM Extension 未来增加其他 RoboMaster 场景能力。
| 方案 | 格式保留 | 图片/附件 | 知识库目录 | 目标平台适配 |
|---|---|---|---|---|
| 手工复制粘贴 | 需要逐项检查 | 手工重传 | 手工重建 | 人工调整 |
| 通用文档导出 | 取决于导出格式 | 通常导出到本地 | 通常变为文件目录 | 仍需再次导入 |
| RM Extension | 按 Block 转换 | 自动迁移并支持复用 | 自动映射和重建 | 直接生成论坛编辑器数据 |
赛季规划、技术报告和开源专栏往往由多名队员在在线文档中共同编辑,最终再发布到论坛。因此,本项目需要同时满足四项约束:降低非开发者的使用门槛,尽量保留文档结构,避免把战队未公开资料中转到第三方服务器,并为后续 RoboMaster 场景保留扩展空间。
| 实现形态 | 优势 | 主要代价 | 结论 |
|---|---|---|---|
| 命令行工具 | 轻量,易于复用现有转换库 | 需要安装运行时、配置参数并理解命令,难以面向全队推广 | 适合开发者,不适合作为默认产品形态 |
| Web 站点 | 界面友好,易于集中更新 | 后端需要承担转换和运维;文档内容可能经过项目方服务器 | 与战队资料的隐私边界不匹配 |
| 桌面应用 | 可在本地执行并提供完整 UI | 需要分发、安装和维护多平台客户端,与论坛页面交互仍需额外授权 | 能实现,但产品和维护成本更高 |
| 浏览器扩展 | 安装后可以在用户浏览器内直接交互,可访问目标页面上下文,同一代码库可构建多浏览器版本 | 受扩展权限、后台生命周期和浏览器 API 约束 | 采用 |
RM Extension 使用浏览器扩展作为执行边界:凭证保存在 Extension Storage,文档读取、结构转换和媒体搬运由用户浏览器直接调用飞书、RoboMaster 论坛和 OSS 接口,项目不设中转业务服务器。这一选择不仅解决当前的文档迁移,也允许通过 Popup、Background 或按站点加载的 Content Script 继续增加 RMLive 等相互独立的能力。
下列能力代表当前版本,而不是项目的最终功能清单。新的功能可以通过 Popup 入口、Background 任务或面向特定 RoboMaster 页面加载的 Content Script 接入。
- 将飞书 Docx 或 Wiki 页面导入为论坛文章、FAQ 或 Wiki 页面。
- 支持发布内容、保持草稿状态以及更新已有内容。
- 转换富文本、标题、多级列表、代码、引用、待办、表格、图片、文件、视频和行内公式。
- 可复用文章中已经上传的媒体对象,减少重复下载和上传。
- 可将
@用户的 Open ID 转换为可读用户名,并可强制为表格生成表头。
- 递归读取飞书知识库目录,并与目标论坛 Wiki 树进行匹配。
- 对每个节点选择覆盖、插入、新建空节点或不处理。
- 根据父节点和前序兄弟关系重建页面层级与顺序。
- 展示总任务、当前文档和媒体 I/O 进度。
- 支持主动取消,并区分成功、失败与已取消状态。
RMLive 是与文档迁移并列、相互独立的当前能力。启用后,扩展会在 RoboMaster 官网直播页加载增强直播界面,并把页面请求所需的论坛身份信息通过限定来源的 postMessage 传给 RMLive。它体现了 RM Extension 除内容迁移之外,还能够通过页面集成改善官网使用体验。下文以成熟度更高的飞书迁移模块介绍核心技术实现,不代表产品只服务于文档转换。
| 支持程度 | 飞书内容 | 转换结果 |
|---|---|---|
| 完整转换 | Page、普通文本、1–9 级标题、项目符号、有序列表、代码、引用、待办、Callout、分割线、文件、图片、表格、分栏、Iframe、View | 转换为论坛编辑器 HTML;图片和文件同时迁移 |
| 尽力转换 | 群聊卡片、流程图、部分嵌入内容 | 保留可提取的标题、链接或说明 |
| 明确降级 | 多维表格、电子表格、思维笔记、任务、OKR、画板、Jira、同步块、子页面列表、AI 模板等 | 在正文中写入“不支持”提示,不静默丢弃 |
《不必按烂 CV 键,RM Extension 助你一键搬运飞书文档到论坛》展示了从飞书内容到 RoboMaster 论坛的实际操作过程。
下图左侧为飞书原始文档,右侧为转换后的 RoboMaster 论坛 Wiki 页面,可对比正文结构、富文本样式、链接、代码、颜色、用户与文档提及、日期提醒、公式以及目录层级。
- Edge、Chrome 或 Firefox 桌面浏览器。
- 一个可发布并获得管理员批准的飞书企业自建应用。
- 机器人对源文档或知识库具有读取权限。
- 当前浏览器已登录 RoboMaster 论坛,并对目标文章、FAQ 或 Wiki 具有编辑权限。
Edge 用户可从 Microsoft Edge Add-ons 安装,Chrome 用户可从 Chrome Web Store 安装。Firefox 或需要调试的用户可按“开发与构建”章节从源码构建。
- 在飞书开放平台创建企业自建应用并添加机器人能力。
- 为应用开通文档、云盘、知识库和群聊只读权限;以飞书开放平台当前展示的权限名称为准。
- 创建版本、申请发布并等待企业管理员批准。
- 将机器人加入能够访问目标文档的群,并为该群授予对应文档或知识库权限。
- 打开扩展的“选项”页,填入 App ID 和 App Secret,点击“测试连接”。
App Secret 会写入浏览器扩展的本地存储。不要在公共电脑配置,不要把包含凭证的浏览器配置目录或调试日志公开。
- 在浏览器打开有权编辑的论坛文章、FAQ、Wiki 页面或已保存的草稿。
- 打开扩展,选择“飞书文档转 RM 论坛文章”。
- 粘贴飞书 Docx 或 Wiki 页面链接并等待解析。
- 选择是否保持草稿、复用资源、转换用户名称和强制表头。
- 开始执行,完成后检查标题、正文、图片、附件和页面状态。
- 打开目标论坛 Wiki 中任意页面。
- 在扩展中选择“飞书知识库转论坛专栏”,粘贴飞书知识库页面链接。
- 在目录中选择待迁移页面;同名节点默认覆盖,不存在的节点默认插入。
- 确认设置后执行,并在关闭 Popup 后重新打开扩展查看当前任务。
| 现象 | 检查项 |
|---|---|
| 飞书连接失败 | App ID/Secret、应用是否发布、机器人权限、企业管理员审批 |
| 无法解析飞书链接 | 使用 /docx/ 或 /wiki/ 页面链接,并确认机器人能够读取 |
| 无法识别论坛目标 | 确保域名为 bbs.robomaster.com,目标页面可编辑;新草稿需先保存以取得 draftId |
| 图片或附件失败 | 检查网络、飞书资源权限、论坛登录状态和 OSS 临时凭证获取 |
| 页面出现“不支持” | 对照格式兼容表;原始 Block 未被静默删除,而是降级为提示文字 |
以下命令于 2026-08-23 在 macOS ARM64、Node.js 20.20.2、pnpm 10.33.0 下验证。项目使用 TypeScript 5.9、WXT 0.20、React 19;建议从 Node.js 20 LTS 开始复现。
git clone https://github.com/scutrobotlab/rm-extension.git
cd rm-extension
pnpm install --frozen-lockfile
pnpm compile
pnpm build常用命令:
| 命令 | 用途 |
|---|---|
pnpm dev |
启动 Chromium 开发模式 |
pnpm dev:firefox |
启动 Firefox 开发模式 |
pnpm compile |
TypeScript 静态检查,不输出文件 |
pnpm build / pnpm build:firefox |
构建 Chromium / Firefox 扩展 |
pnpm zip / pnpm zip:firefox |
生成商店提交压缩包 |
pnpm api:lark / pnpm api:robomaster |
根据 OpenAPI 描述重新生成客户端;需要另行安装 OpenAPI Generator |
开发调试可使用以下环境变量覆盖本地存储中的飞书凭证;不要提交真实值:
WXT_LARK_APP_ID=
WXT_LARK_APP_SECRET=
WXT_LARK_ACCESS_TOKEN=WXT 默认把构建结果写入 .output/。Chromium 可在扩展管理页开启开发者模式并加载对应的 unpacked 目录;Firefox 可通过 about:debugging 临时加载构建产物。
rm-extension/
├── entrypoints/
│ ├── background/ # 长任务、飞书转换编排和论坛写入
│ ├── popup/ # 功能入口、表单、目录选择和进度 UI
│ ├── options/ # 飞书 App ID / App Secret 配置
│ ├── robomaster.content/ # RMLive 官网内容脚本
│ └── message.ts # Popup 与 Background 的消息契约
├── components/ # 跨页面 React 组件
├── utils/
│ ├── lark/ # 飞书认证、Block 转换、下载和状态模型
│ ├── robomaster/ # 论坛 URL、Wiki 树、OSS 和论坛接口
│ └── common/ # MD5 等通用能力
├── public/ # 扩展可公开访问的注入资源
├── assets/ # 图标与 README 资源
└── wxt.config.ts # WXT 与扩展 Manifest 配置
utils/lark/openapi 与 utils/robomaster/openapi 是由接口描述生成的客户端;业务修改应优先发生在生成目录之外,接口更新时再统一重新生成。
flowchart LR
U[用户] --> P[Popup React UI]
U --> O[Options 配置页]
O --> S[(Extension Storage)]
P <-->|消息与进度| B[Background]
B --> L[飞书开放平台]
B --> R[RoboMaster 论坛 API]
B --> A[阿里云 OSS]
C[Content Script] --> W[RoboMaster 官网直播页]
C --> I[RMLive iframe]
W --> C
Popup 只负责收集参数和展示状态;耗时转换在 Background 中执行,避免用户界面组件卸载后任务立即中断。Options 保存飞书凭证,Content Script 仅负责 RMLive 这一独立功能。
flowchart LR
A[飞书链接] --> B[读取文档<br/>解析 Block]
B --> C[建立结构<br/>转换 HTML]
C --> D[处理媒体]
D --> E[组装文章数据]
E --> F[写入文章<br/>FAQ / Wiki]
媒体处理分支:
flowchart LR
A{包含媒体?} -->|否| E[继续组装文章]
A -->|是| B[下载飞书资源]
B --> C{MD5 匹配<br/>已有对象?}
C -->|是| E
C -->|否| D[获取 STS<br/>上传 OSS]
D --> E
flowchart TD
A[读取飞书 Wiki 树] --> B[读取论坛 Wiki 树]
B --> C[按标题匹配节点]
C --> D{用户策略}
D -->|覆盖| E[更新已有页面]
D -->|插入| F[转换并创建页面]
D -->|空节点| G[创建目录占位页面]
D -->|跳过| H[不处理]
E --> I[更新节点映射]
F --> I
G --> I
I --> J[按 parentId / prevId 重建顺序]
飞书返回的是带 block_id、children 和 block_type 的 Block 列表。DocxConverter 首先建立 block_id → Block 映射,再从 Page Block 递归遍历。每种 Block 交给对应转换方法,文本元素则继续映射粗体、斜体、删除线、下划线、链接、颜色、对齐方式和缩进。从数据模型看,这是一个“扁平节点集合 → 有根文档树 → 目标 HTML 树”的模型变换过程;Map 使子节点按 ID 查找保持常数期望时间,整体遍历与 Block 数量近似线性增长。
相比先转 Markdown 再导入,直接从 Block 语义映射论坛 HTML 可避免在中间表示中过早丢失表格合并、提及、颜色和媒体元数据。按 Block 类型分派又使结构遍历与具体渲染规则分离,新类型可通过独立转换函数加入。无法转换的类型会生成清晰提示,这是采用“显式降级”而非静默丢弃,防止发布者误判迁移完整性。
转换器通过飞书临时下载地址读取媒体,并用流式读取反馈下载进度。上传前计算 MD5,从论坛取得短期 OSS 凭证后执行分片上传,最终生成论坛编辑器需要的图片、附件或视频 HTML 以及 fileItems 元数据。这条管线将“内容转换”与“二进制对象迁移”分开:HTML 负责引用关系,headImg 和 fileItems 保留论坛发布接口需要的结构化元数据。
更新已有文章时,转换器会用飞书资源 Token 在旧的 headImg 与 fileItems 中查找对象;用户启用复用后可跳过重复传输。该策略类似内容寻址与幂等更新:先识别已存在对象,再决定是否执行有副作用的上传。它减少网络 I/O,也避免同一文章反复更新产生过多对象;MD5 用于传输与完整性校验,不承担密码学安全功能。
论坛节点位置由 parentId 和 prevId 共同决定。buildWikiNodeMap 深度优先遍历论坛树,为每个 postsId 记录父节点和前序兄弟;批量任务再根据飞书目录和用户策略创建或覆盖页面。从数据结构上看,飞书与论坛都是有序树,但对顺序的表达不同:前者以子节点列表表达次序,后者以父节点和前驱节点表达插入位置。迁移的本质是在保持父子关系与兄弟顺序的前提下,完成两种树表示之间的同构映射。
创建节点会改变论坛树,因此任务在必要时重新读取并更新映射,避免使用已失效的位置索引。插入过程逆序处理同级节点,是由目标接口的 prevId 约束导出的顺序策略,使新节点的插入不会破坏尚未处理的兄弟位置,最终得到与飞书一致的可见顺序。
Popup 通过 webext-bridge 发出转换、取消和状态查询消息。Background 维护 Ready → Converting → Success / Failed / Canceled 状态,在文档转换和每次 I/O 前检查取消标志,并把总进度、子进度和文件进度推送给 Popup。这里采用消息驱动和显式有限状态模型:Popup 是可随时关闭的短生命周期视图,Background 才是任务状态的唯一事实来源。界面重新打开后通过查询消息恢复展示,避免把长任务绑定到 React 组件生命周期。
该取消机制是协作式取消:它在安全点检查标志并阻止后续步骤,无需强行中断正在执行的 API 调用。代价是它不能撤销已经写入论坛或上传 OSS 的数据,因此该流程提供的是“停止继续执行”而非跨系统事务回滚。知识库任务取消后,应检查已完成节点。
| 设计思想 | 代码落点 | 实际收益 |
|---|---|---|
| 转换器 | DocxConverter |
把飞书 Block、媒体状态和最终论坛 HTML 聚合在明确边界内 |
| 策略式分派 | ConvertBlockToHTML 根据 BlockType 选择转换方法 |
新增 Block 时可增加独立转换函数,不必改写整条迁移流程 |
| 适配器 | 飞书 Block/媒体模型 → 论坛 HTML、headImg、fileItems |
隔离两个平台的数据模型差异 |
| 消息驱动 | Popup 消息契约与 Background 处理器 | UI 生命周期与长任务解耦,并统一进度及取消入口 |
| 显式状态机 | LarkConvertState |
UI 对初始化、就绪、转换、成功、失败和取消状态进行穷举展示 |
| 生成式 API 边界 | 两套 OpenAPI 客户端 | 业务代码不手写大量请求/响应类型,接口变更可集中再生成 |
增加飞书 Block 支持时,应扩展 BlockType 映射并实现单一转换方法。若未来增加新的发布平台,建议保留飞书读取层,把论坛专用 HTML 和媒体上传抽象为目标适配器,而不是继续扩张单个转换器。
- 业务代码使用 TypeScript,消息请求、转换任务、论坛目标和状态都有显式类型。
- React 组件使用 PascalCase,函数和变量使用 camelCase;既有跨模块公共函数中仍有部分 PascalCase 命名,后续将逐步统一。
- 关键转换、目录遍历、媒体上传和取消检查包含目的性注释;生成代码不作为人工注释质量样本。
pnpm compile是当前静态质量门禁。utils/**/openapi为生成代码,不直接进行零散手工修改。
从产品形态看,RM Extension 把浏览器作为连接 RoboMaster 生态的能力入口:无需要求用户迁移到新的桌面客户端,便可针对官网、论坛和外部协作服务逐步增加功能。飞书迁移与 RMLive 分别验证了“跨平台工作流自动化”和“官网体验增强”两条不同方向,也证明项目结构可以承载更多相互独立的 RM 场景。
以当前最完整的飞书模块为例,RM Extension 的价值不只是“少按几次 Ctrl+C/Ctrl+V”,而是把战队内部知识发布所需的结构转换、资源搬运和目录维护组合成可重复流程。它针对 RoboMaster 论坛编辑器的数据结构处理表格、公式、附件和视频,并能以论坛 Wiki 节点关系重建飞书知识库。
对其他队伍而言,它降低了将内部资料整理为公共开源内容的边际成本:作者可以继续在熟悉的飞书环境协作,再把完成稿迁移到论坛。转换器的 Block 分派、对象复用和目录映射也为“协作文档 → 社区发布平台”类工具提供了可复用实现参考。
114 次论坛引用表明 RM Extension 已在社区内容中形成广泛关联,体现了项目的实际应用价值与传播影响力。
- 多维表格、电子表格、思维笔记、画板、任务、OKR 等复杂 Block 尚未转换为可编辑内容。
- 用户必须自行创建和授权飞书企业应用,初次配置成本高于只依赖 Cookie 的工具。
- 大型知识库受飞书接口频率、网络质量、OSS 上传和浏览器 Background 生命周期影响。
- 取消是协作式取消,不能回滚已完成的论坛写入和对象上传。
- App Secret 当前保存在扩展本地存储中,安全性取决于浏览器配置和设备环境。
- 将 RM Search 无缝集成到 RoboMaster 论坛,减少资料检索时的页面切换。
- 建设常驻浏览器的 RM 工具箱,逐步汇集官网、论坛、赛事与战队协作场景中的高频能力。
- 优化大型知识库迁移,支持请求限流、节点失败重试、断点恢复和任务记录。
- 支持电子表格、画板和思维笔记等高优先级飞书 Block。
- 增加转换前预览及更新前差异检查。
本项目采用 Apache License 2.0 开源。该许可证允许在保留版权、许可证声明并标明修改的前提下使用、修改和分发项目代码,同时包含明确的专利授权条款。项目名称、标识及第三方依赖不因该许可证自动获得额外授权。
欢迎通过 GitHub Issues 报告问题。请附浏览器与扩展版本、源文档 Block 类型、可复现步骤、预期结果和脱敏后的错误信息;不要提交 App Secret、Access Token、论坛 Cookie 或包含个人资料的文档。
感谢 RoboMaster 社区,以及所有参与反馈和内容开源的 RMer。
华南理工大学机器人未来创新实验室 华南虎战队
软件开发组 & 宣传运营组 出品
项目成员:
- 产品经理 & 软件开发:常霆钰
- Logo 设计:杜雨潼
- 视频制作 & 视频配音:常霆钰
- 视频封面:杨卓石
特别感谢以下队伍对项目的支持:
- 合肥工业大学(宣城校区)WDR 战队
- 东莞理工学院 ACE 战队
- 东北大学 T-DT 战队
- 湖南大学跃鹿战队
特别感谢以下个人对项目的帮助:
- 东莞理工学院 黄煜翔
- 合肥工业大学 郑雅文
- 华中科技大学 周晗




