Hello! 欢迎来到阿珏酱のBlog!

MoeKoeMusic-Plugins设计理念


avatar
阿珏 2026-06-20 10

一开始做 MoeKoe Music 插件生态的时候,还没有在线插件市场这个功能
后来在社区的建议下便有了这个插件市场 增加官方/社区插件仓库以扩展产品功能

插件可以由社区开发,那插件市场应该怎么管?

最直接的做法当然是把所有插件源码都收进一个大仓库里。但这个方案越想越别扭。每个插件都有自己的作者、自己的发布节奏、自己的构建方式。把它们全塞进官方仓库,不仅维护成本高,也会把责任边界搞得很模糊。

所以这个仓库最后没有被设计成“插件源码仓库”,而是变成了一个“插件登记与索引仓库”。它只做几件事:

  • 接收插件上架、更新、下架和举报申请
  • 自动做一轮基础校验和静态识别
  • 把人工审核通过时的插件快照记录下来
  • 维护客户端可以读取的 plugins.json
  • 顺手把 README 里的插件列表更新出来,方便人看

一个可追溯的登记簿:谁提交的、审核的是哪个版本、下载地址是什么、是否有网络或文件权限,都落在一份清楚的数据里。

市场索引,而不是源码仓库

仓库根目录最重要的文件是 plugins.json。它就是插件市场真正消费的数据源。

{
  "id": "custom-app-background",
  "name": "自定义背景图",
  "description": "为MoeKoe Music提供自定义背景图能力,支持透明度调节。",
  "iconUrl": "...",
  "version": "1.0.0",
  "minversion": "1.6.1",
  "...":"....",
  "buildRequired": false,
  "networkAccess": false,
  "fileAccess": false,
  "binaryContent": false,
  "snapshot": {
    "iconUrl": "...",
    "repository": "MoeKoeMusic/custom-app-background-plugin",
    "commitSha": "dbf72d38c8cf6b1d1cefdf8ce15798d565678995",
    "downloadUrl": "hxx.zip",
    "release": null
  }
}

我不想让市场记录永远指向插件仓库“当前最新代码”。因为作者今天提交的代码,和审核那天看到的代码,可能已经不是同一份东西了。插件市场真正应该承认的是:审核通过时的那个版本。

所以这个项目里面有一个核心原则:

上架的不是一个会漂移的仓库地址,而是一个已经锁定的快照。

对于不需要编译的插件,快照锁到默认分支当时的 commit。对于需要编译的插件,快照锁到对应的 Release tag 和发行附件。这样后面真出了问题,也能回头知道当时到底审核了什么。

Action 先跑,人最后拍板

用户提交 Issue 时,需要选择:

  • 是“新上架”还是“更新插件”
  • GitHub 仓库地址
  • 安装前是否需要编译

Action做自动校验,然后把结果写回 Issue 评论,同时给 Issue 打上 check-passedcheck-failed 标签。

自动化负责整理事实,人负责做最终判断:

  1. 用户用 Issue 模板提交插件
  2. Action 解析 Issue 表单
  3. 校验仓库、manifest、版本、作者权限
  4. 锁定插件快照
  5. 自动评论校验结果
  6. 维护者人工查看
  7. 维护者用 Close as completed 关闭 Issue
  8. 另一个 Action 读取校验结果,生成更新 plugins.jsonREADME.md 的 PR
  9. PR 合并后,插件正式进入市场索引

这里的“关闭方式”也被利用起来了。如果 Issue 是 Close as not planned,脚本不会执行入库。也就是说,GitHub 原生的 Issue 状态就被拿来当成了审核按钮。

快照机制

如果用户说“安装前不需要编译”:

  • 读取仓库默认分支
  • 拿到当前 commit sha
  • 用这个 commit 去读取 manifest.json
  • 生成固定 commit 的源码 zip 地址
  • 下载 zip,解压后做权限扫描
  • 生成 repository-tree 类型快照

如果用户说“需要编译”:

  • 找最新可用 Release
  • 取 Release 里的第一个附件
  • 下载发行附件
  • 解压附件并读取其中的 manifest.json
  • 生成 release-asset 类型快照

这两个路径解决的是同一个问题:不管插件源头怎么发布,最后都要得到一份可审核、可下载、可追溯的快照,不会因为最新仓库的变动而导致用户下载的插件非审核时的.

权限识别

安全审核这件事,不能只靠脚本拍脑袋。但脚本可以先帮维护者把风险点标出来:

  • manifest 里声明了什么权限
  • 源码或发行包里是否出现了典型 API 或可执行文件

它不是只给出“有风险”这几个字,而是会告诉你为什么判断有这个能力,比如:

  • manifest 声明了网络访问
  • 源码里用了 fetch
  • 发现了 .exe.dll.node 之类可执行内容
  • 源码里用了 localStorageindexedDB

这当然不是完美的安全扫描。它会有漏报,也可能有误报。但它的定位不是取代人工审核,而是把维护者最应该多看一眼的地方提前圈出来。

它不是“审判官”,更像“标注笔”。

隐藏快照数据

校验完成后,会在 Issue 下写一条评论。评论里除了人能读懂的校验结果,还有一个隐藏的 payload。

它会生成类似这样的 HTML 注释:

<!-- plugin-publish-snapshot:base64... -->

这个设计挺巧的。因为 GitHub Actions 的不同 workflow 之间不是一直共享内存的。上架校验发生在 Issue 创建或编辑时,真正入库发生在 Issue 被关闭时。中间可能隔了几小时甚至几天。

那关闭时怎么知道当初校验通过的是哪个快照?

答案就是:从 Issue 评论里读回来。

这让 Issue 评论不只是“提示信息”,还变成了一份轻量的审核记录。它不需要额外数据库,也不用搭服务,直接借用了 GitHub 本身的记录能力。

入库动作

真正写入 plugins.json 的脚本是 scripts/publish-plugin-close.js

它先做几道门:

  • 当前事件必须是 publish 类 Issue
  • Issue 必须是 state_reason === 'completed'
  • 关闭 Issue 的用户必须是仓库维护者
  • 校验评论里的 payload 必须是 check-passed
  • payload 必须有锁定的 downloadUrl

这几道门保证了一个事情:普通用户不能靠关闭 Issue 或伪造流程把插件写进市场。

这里有一个细节:更新插件时,会保留原作者,不会因为别人提交更新 Issue 就改掉作者字段。同时更新必须由原作者本人提交,仓库地址也必须和现有记录一致。

新的或更新后的插件会放到列表最前面。这个选择也挺符合插件市场的直觉:最新通过审核的内容排在前面,用户和维护者都更容易看到最近变化。

最后用当前 plugins.json 生成 Markdown 表格替换 README 中的插件列表。

下架和举报

它的流程和上架很像:

  1. 用户创建下架或举报 Issue
  2. plugin-moderation-validate.js 校验插件是否存在
  3. 如果是作者主动下架,校验提交人是否为作者
  4. 维护者人工审核
  5. 维护者用 Close as completed 关闭
  6. plugin-moderation-close.js 把插件状态改成 delisted
  7. 自动生成 PR 更新 plugins.json 和 README

AI 审核

项目里还有一个 publish-plugin-ai-audit.js,它会对插件快照做一次 AI 静态审查。

这个脚本的思路是:

  • 下载同一个快照
  • 选择最多 24 个候选文件
  • 优先看 manifest.jsonpackage.json、入口文件、网络/文件/存储相关文件
  • 把内容发给 AI 接口
  • 要求 AI 返回固定 JSON
  • 把审查结果写回 Issue 评论

这里我觉得比较好的地方是:AI 审核没有被设计成“最终裁判”。它只是给维护者多一份参考。

这比“AI 说安全所以自动上架”靠谱得多。

为什么不用数据库或后台服务?

这个项目最有意思的地方,其实不是代码多复杂,而是它尽量不引入额外系统。

它把 GitHub 自带的东西用到了比较完整:

  • Issue Form 当申请表
  • Issue 评论当审查反馈和快照记录
  • Label 当自动校验状态
  • Close reason 当人工审核信号
  • Pull Request 当数据变更入口
  • plugins.json 当市场索引
  • README 当公开展示页
  • Git 历史当审计日志

所以它不需要一个后台,不需要数据库,也不需要单独做管理面板。对于一个开源音乐播放器的插件市场来说,这个复杂度刚刚好。

ps: GitHub Actions真的好用,包括我之前的 阿珏のBlog 的国际化之路

结尾

回头看这个项目,它并不是那种“架构很重”的插件平台。它更像一个长得很朴素、但每个步骤都能追溯的登记系统。

用户通过 Issue 提交,Action 自动检查,维护者人工确认,PR 合并生效。所有关键动作都留在 GitHub 上,所有市场数据都落在 plugins.json 里。出问题时能查,更新时有记录,下架时也不抹掉历史。

它没有试图一步到位做成一个完整后台,而是先把插件市场最核心的信任链路搭起来。

一个社区插件生态,真正需要的第一件事可能不是华丽的页面,而是一套大家都能看懂、能信任、能复盘、能继续改进的流程。

这个仓库 MoeKoeMusic-Plugins 就是这样来的。

插件市场网页版

当然以上这些都不是一步到位的,是一步一步更新完善到现在的结果的

  • avatar
    游客

    人尽皆知,第一个上架的插件是背景插件
    那第一个出现,甚至直到现在都没上架的插件是什么?
    ~~应该不可能是我的插件吧(~~

    • avatar
      博主

      @ 晚梦 明知故问痴汉笑

      • avatar
        游客

        @ 阿珏 我还以为在我之前就有人写了插件来着吧唧

发表评论
OωO表情

相关阅读

最新文章

恰饭