Skip to content

自定义脚本总览

自定义脚本让你用一段 JavaScript 直接操作 dYm 的数据、下载任务和抖音接口, 做界面上没有做成按钮的批量操作——批量改用户设置、按自己的规则清理文件、 把收藏夹整个拉下来,都属于这一类。

打开入口

「自定义脚本」页默认是隐藏的,需要先开开发者模式:

设置 → 系统 → 开发者模式 打开后,左侧导航会多出「自定义脚本」。

关掉开发者模式时,如果正停在该页面会被送回首页,但已经在跑的脚本不会停

两类脚本

内置脚本我的脚本
来源随应用发布,编译在包里用户数据目录下的 scripts/*.js
能否编辑只读可以,编辑器里直接改
升级影响随版本更新不受升级影响

两类脚本跑的是同一套运行时——内置脚本也是以 CommonJS 源码的形式存在, 和你自己写的没有区别。所以内置脚本可以当范例读,点「以此为模板新建」 就能得到一份逐字相同、可编辑的副本。

脚本长什么样

一个脚本就是一个 CommonJS 模块,导出 metarun 两样东西:

js
exports.meta = {
  name: '脚本名称', // 必填,列表里显示的名字
  description: '一句话说明', // 可选
  timeout: 0 // 可选,超时毫秒数;不填或 0 = 不限时长
}

exports.run = async (api) => {
  api.log('开始')
  // 逻辑写在这里,能做什么见 API 参考
  return { done: true } // 返回值会显示在运行结果里(需 JSON 可序列化)
}

run 的入参 api 就是脚本的全部能力来源,详见 API 参考

沙箱限制

脚本在 Node 的 vm 沙箱里求值,有两条必须知道的约束:

没有 require,也没有 import 不能引第三方库,也不能直接用 fspath 这些 Node 内置模块。所有能力都从 run(api) 的入参走——文件操作用 api.fs, 网络请求用 api.net.fetch

沙箱挡的是手滑,不是恶意

这些限制的目的是让写错的脚本不至于毁掉无关文件,不是用来安全地运行别人的代码。 api.db.exec 能跑任意 SQL、api.net.fetch 能连任意地址;开启 api.shell 之后更是能执行任意本地命令。 运行来路不明的脚本前先把代码读一遍。

沙箱里能直接用的全局只有:consolesetTimeoutclearTimeoutURLURLSearchParamsTextEncoderTextDecoder,以及 JS 自带的 MathJSONDateMapSet 等标准对象。

顶层代码会在「列出脚本」时执行。 应用扫描脚本列表时会把每个文件求值一遍, 好读出 meta。所以顶层只放常量和函数声明,别在顶层写有副作用的逻辑—— 写了的话,光是打开「自定义脚本」页就会触发它。

js
// 顶层:可以
const DELAY_MS = 3000

// 顶层:不要这么写,打开页面就会执行
// deleteEverything()

exports.run = async (api) => {
  // 有副作用的事情写在这里
}

顶层求值有 5 秒超时,写死循环会让脚本在列表里显示为加载失败。

脚本放在哪

我的脚本存在用户数据目录的 scripts/ 下,一个 .js 文件就是一个脚本。 点页面右上角「打开脚本目录」可以直接跳过去。同一个目录里还有一份 README.md,是随版本更新的 API 速查,内容与本站的 API 参考 对应。

只有 .js 结尾的文件会被当成脚本,所以往里放笔记、数据文件都不影响。

下一步

基于 GPL-3.0 许可发布