去年闲着没事写了个下载器 FluxDown ,Rust 做引擎,Flutter 做壳,多线程分段、断点续传这些常规操作都有。本来到这就该收工了,但用久了老觉得少点什么——下载这活儿,真正烦的从来不是搬字节,是搬之前得先把分享页抠出直链,搬完了想顺手转个码、归个档。这些需求太杂,我不可能全预判,也不想把设置页堆成一百个勾选框。
所以最近给它加了个插件系统,想拿来给 V 友们拍拍砖。
一个插件就是一个文件夹:一个 `manifest.json` + 一两个 `.js`。没有构建、没有 npm 、没有框架。插件只能干两件事:
- resolver:下载前改写 URL ,把分享页换成真直链(导出 `resolve(ctx)`)
- hooks:任务开始 / 完成 / 出错时收通知(`onStart` / `onDone` / `onError` …)
四十行不到就能教它认识一个新站点,大概长这样:
```js
async function resolve(ctx) {
const id = ctx.url.split("/share/")[1];
if (!id) return null; // 不归我管,按原样下
const res = await flux.fetch({ url: "https://xxx/api/" + id });
const data = JSON.parse(res.body);
return { url: data.directUrl, fileName: data.name, rangeSupported: true };
}
```
我在安全上花的心思比功能本身还多,因为让第三方 JS 跑在别人机器上,一个不小心就是给人埋雷:
- 每次调用开一个全新的 QuickJS 上下文,跑完即弃,没有全局残留
- resolve 给 10s / 64MB ,钩子 5s / 32MB ,连续三次超时或爆内存直接熔断禁用
- `flux.fetch` 只放行公网 http/https ,环回 / 局域网 / 云元数据 IP 全拦,连每一跳重定向都查(防 SSRF )
- 失败 fail-closed ,绝不偷偷回退去下原始页面 URL——不然你会得到一个把 HTML 存成 .mp4 的坏文件还不知道为啥
然后把 ffmpeg 和 yt-dlp 也塞进来了,应用里一键托管安装,插件声明权限后能调,但同样关在笼子里:ffmpeg 只在下完那一刻可用、工作目录就是产物目录、参数审查( URL / 绝对路径 / `..` 全拒,够不到网络也出不了目录); yt-dlp 放行网络但那些能执行外部程序、读浏览器凭据的危险开关全黑名单,还强制前置 `--ignore-config`。于是一条流水线成立了:插件抠直链 → 多线程拉下来 → 下完自动转码,你只点了一下"下载"。
市场我特意没做成一个服务,就是一份数据格式:索引是 GitHub 上 Git 版本化的 JSON ,谁都能 fork ;插件包 `.fxplug` 内容寻址( sha256 整包),多镜像轮着下,没有单点、没人能一键下架你的东西。
关于承诺我想说清楚:项目免费、开源( AGPL )。以后功能会继续加,也会有账号体系,但免费、不放广告、界面保持简洁这三条不会变。别的都能商量,这三条是底线。
官网 fluxdown.zerx.dev ,代码和文档都在 GitHub 。目前主要是 Windows ,macOS/Linux 在路上。插件系统刚落地,肯定有没考虑到的地方,欢迎来提意见 / 骂两句 / 顺手写个插件。
所以最近给它加了个插件系统,想拿来给 V 友们拍拍砖。
一个插件就是一个文件夹:一个 `manifest.json` + 一两个 `.js`。没有构建、没有 npm 、没有框架。插件只能干两件事:
- resolver:下载前改写 URL ,把分享页换成真直链(导出 `resolve(ctx)`)
- hooks:任务开始 / 完成 / 出错时收通知(`onStart` / `onDone` / `onError` …)
四十行不到就能教它认识一个新站点,大概长这样:
```js
async function resolve(ctx) {
const id = ctx.url.split("/share/")[1];
if (!id) return null; // 不归我管,按原样下
const res = await flux.fetch({ url: "https://xxx/api/" + id });
const data = JSON.parse(res.body);
return { url: data.directUrl, fileName: data.name, rangeSupported: true };
}
```
我在安全上花的心思比功能本身还多,因为让第三方 JS 跑在别人机器上,一个不小心就是给人埋雷:
- 每次调用开一个全新的 QuickJS 上下文,跑完即弃,没有全局残留
- resolve 给 10s / 64MB ,钩子 5s / 32MB ,连续三次超时或爆内存直接熔断禁用
- `flux.fetch` 只放行公网 http/https ,环回 / 局域网 / 云元数据 IP 全拦,连每一跳重定向都查(防 SSRF )
- 失败 fail-closed ,绝不偷偷回退去下原始页面 URL——不然你会得到一个把 HTML 存成 .mp4 的坏文件还不知道为啥
然后把 ffmpeg 和 yt-dlp 也塞进来了,应用里一键托管安装,插件声明权限后能调,但同样关在笼子里:ffmpeg 只在下完那一刻可用、工作目录就是产物目录、参数审查( URL / 绝对路径 / `..` 全拒,够不到网络也出不了目录); yt-dlp 放行网络但那些能执行外部程序、读浏览器凭据的危险开关全黑名单,还强制前置 `--ignore-config`。于是一条流水线成立了:插件抠直链 → 多线程拉下来 → 下完自动转码,你只点了一下"下载"。
市场我特意没做成一个服务,就是一份数据格式:索引是 GitHub 上 Git 版本化的 JSON ,谁都能 fork ;插件包 `.fxplug` 内容寻址( sha256 整包),多镜像轮着下,没有单点、没人能一键下架你的东西。
关于承诺我想说清楚:项目免费、开源( AGPL )。以后功能会继续加,也会有账号体系,但免费、不放广告、界面保持简洁这三条不会变。别的都能商量,这三条是底线。
官网 fluxdown.zerx.dev ,代码和文档都在 GitHub 。目前主要是 Windows ,macOS/Linux 在路上。插件系统刚落地,肯定有没考虑到的地方,欢迎来提意见 / 骂两句 / 顺手写个插件。