跳到正文

FluxDown 0.5.0 原生 GPUI 客户端正式发布——作者来信:为什么我把整个界面从头重写了一遍。去看看

FluxDown
下载 文档 定价 更新日志 赞助
插件开发 调试与排错

插件开发

调试与排错

插件日志在哪、怎么搜;每种改动之后该做什么;以及你会遇到的报错信息、原因与解决办法对照表。

编辑此页

这一页写给「出问题了」的时刻:去哪里看、插件的各种状态是什么意思、某个改动需要什么操作,以及最有用的——报错信息与它们的原因。

关于信息的语言。 FluxDown 插件引擎抛出的错误大多是中文,你在应用和日志里看到的正是这些原文。本页逐字引用它们,方便你直接搜索。SDK 命令行的信息是英文。

快速检查清单

插件「毫无反应」时,按顺序检查:

  1. 加载了吗? 在设置 → 扩展 → 插件里,这一行必须显示已加载。加载失败表示 FluxDown 读不了它;点开错误(「插件加载错误」,带复制按钮),见安装与校验报错。
  2. 启用了吗? 看名称旁边有没有已禁用、已自动禁用、已被市场撤回或需要授权,见插件状态。
  3. 重新加载了吗? manifest 和 main 的改动要点重新加载才生效,见开发循环。
  4. URL 匹配吗? resolver、hook 和拦截器的规则是对完整 URL 匹配的,见 resolver 问题和拦截器问题里的检查项。
  5. 日志怎么说? 搜索 [plugin:<你的 identity>],见日志。

日志

哪些内容会进日志

你写的记录为
flux.logger.info(...)、console.log、console.info、console.debug一行 INFO
flux.logger.warn(...)、console.warn一行 INFO——在日志文件里区分不出 warn 和 info
flux.logger.error(...)、console.error一行 ERROR(立即刷盘)

每一行都带前缀 [plugin:<identity>],后面是你的参数:字符串原样输出,其余值输出为 JSON,参数之间用一个空格连接。一行日志大致如下:

14:02:31.512 INFO … [plugin:me@mirror-demo] rewriting https://mirror-demo.invalid/files/1Mb.dat -> https://proof.ovh.net/files/1Mb.dat

(中间的部分是日志器附加的源码位置信息。)每条消息超过 4 KB 会被截断。

实际使用中要记住:

  • 按 identity 过滤,而不是按级别: 搜索 [plugin:me@mirror-demo]。搜「warn」或「error」会漏掉你自己写的警告。
  • Error 对象会被记成 {}(它没有可枚举属性)。请改记 String(error) 或 error.message。
  • 引擎自己会写以 [plugin](冒号后面没有 identity)开头的行,记录加载、启停和熔断事件,例如 [plugin] 跳过 …(有插件加载不了)、[plugin] <identity> 连续超时,已自动熔断禁用。搜索 [plugin 两种都能看到。
  • main 里的 console.log 和其他所有插件输出一样进 daemon 日志,不会出现在浏览器控制台里——即使视图是在 Web 端显示的。

文件在哪

插件代码运行在 FluxDown 的后台服务(daemon)里,所以插件输出进的是 daemon 的日志目录:daemon 数据目录下的 logs/。文件名形如 fluxdown_YYYY-MM-DD.log(滚动后为 fluxdown_YYYY-MM-DD.N.log);单个文件到 2 MB 就滚动,超过 7 天的日志会被删除,目录总大小默认上限 10 MB(可在设置 → 关于 → 日志占用上限修改)。

系统daemon 日志目录
Linux$XDG_DATA_HOME/fluxdown/logs/(默认 ~/.local/share/fluxdown/logs/)
macOS~/Library/Application Support/fluxdown/logs/
Windows 安装版%LOCALAPPDATA%\FluxDown\logs\
Windows 便携版(exe 旁有 portable 标记文件)<程序目录>\portable_data\logs\
设置了 FLUXDOWN_DATA_DIR 的任何系统——无头服务器、Docker$FLUXDOWN_DATA_DIR/logs/(Docker 镜像里是 /data/logs/)

桌面应用和 agent 会把它们自己的诊断日志(desktop.log、agent.log)写进应用数据根目录下另一个 agent/logs/ 文件夹。插件输出不在那里。

在应用内打开与导出日志

位置作用
设置 → 关于 → 导出日志(桌面端和 Web 端)保存一个 zip,包含 agent 日志和 daemon 日志(在 daemon/logs/ 里),令牌、Cookie 等敏感信息已被遮盖。这是在任何部署(包括远程主机)下拿到插件输出最可靠的办法。
设置 → 关于 → 打开目录(桌面端)和打开日志目录菜单 / 命令面板项打开桌面应用的 agent 日志目录(desktop.log、agent.log)——适合排查应用自身的崩溃,但里面没有你插件的日志行。请改去打开上表中的 daemon 目录。

Web 端没有可打开的文件夹,请用导出日志。(旧版服务端的 /api/v1/logs REST 接口已经不存在。)

想要更详细的日志

日志级别默认是 INFO,而你的 flux.logger 输出本来就是 INFO,所以通常不需要调整。要提高 daemon 自身的详细程度,请在启动 daemon 的进程环境里设置 FLUXDOWN_LOG_LEVEL(error、warn、info、debug、trace)或 RUST_LOG,然后重启。

开发循环

用从目录安装(开发模式)安装插件,才能获得最快的循环。开发模式插件记录你的文件夹路径并直接读取它。它所在行上的重新加载按钮(提示文字:「重新加载(重读 manifest 与脚本)」)会重读 manifest 和全部脚本,并重新执行安装时的检查。如果失败,会显示错误,并且开发模式登记会保留,你可以改好文件再次重新加载。

你改了什么该怎么做
resolver、hooks、interceptors、auth 或订阅脚本什么都不用做——开发模式插件每次调用都会读这些文件。SDK 项目要重建(npm run dev 会在保存时自动重建)。
main 脚本重新加载。 main 是一个长期存活的上下文,只在启动时读取;打开着的视图会话会结束(显示「视图会话已结束」和重新打开按钮),重新打开后运行的是新代码。
manifest.json(任何内容:匹配规则、入口、设置项、视图、命令、权限、版本)重新加载。 manifest 只在加载插件时解析。
新增了权限或网络主机的 manifest 改动重新加载,然后在对话框里批准(见插件状态)。
桌面脚本(desktop.entry)关掉视图再重新打开;如果同时改了 manifest,还要重新加载。
某个插件设置项的值什么都不用做——下次调用时就会传入(并会推送给运行中的 main)。
SDK 的配置文件(fluxdown-plugin.config.json)重启 npm run dev,然后重新加载。
由 .fxplug 或市场安装的插件重新安装:非开发模式插件在加载时只读入内存一次。

请记住:npm run build、npm run pack 和 npm run dev 会先删除 dist/。如果 dist/ 就是你装的开发模式文件夹,请等构建结束再测试;之后若显示加载失败,点重新加载。

把启用开关关掉再打开,附带效果也会重新加载所有插件,但只有重新加载按钮会把错误反馈给你。

开发模式登记优先于同一 identity 的普通安装副本。要测试打好的 .fxplug,请先卸载开发模式那一份。

插件状态

行上显示含义怎么办
已加载manifest 解析成功,插件已在内存里。—
加载失败manifest 或某个必需文件有问题,或者应用版本太旧。点开可看「插件加载错误」,复制错误可复制。修好后重新加载(开发模式)或重新安装。
需要授权manifest 请求了你还没批准的权限或网络主机。插件处于禁用状态,启用开关被锁住,并显示授权按钮。用其他方式启用会失败,信息里含 consent required。点授权并批准。新版本请求更多权限时需要再次批准;请求更少则不用。
已禁用你手动关掉了它。重新打开。
已自动禁用触发了熔断,见下文。修好脚本,再把它打开(安装更新也会自动重新启用)。
已被市场撤回插件市场撤回了这个版本。启用时报 该插件版本已被插件市场撤回,请升级后再启用。更新插件。
「开发模式」徽标通过目录安装。—

熔断器

resolver、拦截器、订阅 provider 或 main 调用中,连续 3 次超时或内存超限,会让插件被自动禁用(出现其他结果即清零;hooks 和 authenticate 不计入)。你会收到提示(「插件「…」已因连续失败被自动禁用,可在「设置 → 扩展 → 插件」中重新启用」),日志里有 [plugin] <identity> 连续超时,已自动熔断禁用,需要这个插件的任务会失败,报 插件 <identity> 已被熔断自动禁用;重新启用插件,或选择「忽略插件重试」按原始链接下载。常见原因:flux.fetch 在等一个永远不回应的主机、死循环、把巨大的响应读进内存。可以在 manifest 里调低 timeoutMs 来比默认值(resolver 10 秒,拦截器 5 秒)更快失败,给 flux.fetch 加上错误处理,然后重新启用。

安装与校验报错

这些错误出现在安装、重新加载或运行 npm run validate 的时候。安装对话框会显示 安装失败:… / 插件安装失败:…,后面跟着信息;同样的文字也会写进日志。

引擎报错(与 npm run validate)

引擎报告这些错误时会带前缀 manifest 非法: 。npm run validate 和 SDK 校验器使用同一套规则、几乎相同的措辞,但没有这个前缀,并且会一次列出全部问题,而不是遇到第一个就停。措辞不同的地方,下表给出的是引擎的原文。

信息原因解决
JSON 解析失败: …manifest.json 不是合法 JSON、某个值的类型不对,或含有引擎不认识的字段(此时详情里是 unknown field …)。修正语法;删掉未知字段——拼写和嵌套层级都会被检查,见 Manifest 参考。用 SDK 校验时得到的是 manifest: 未知字段 <key>。
identity '…' 非法:须匹配 ^[a-z0-9_-]+@[a-z0-9_-]+$identity 不是由小写字母、数字、_、- 组成的 作者@名称。改名,例如 me@my-plugin。不能有点,不能有大写。
name 不可为空name 为空。填上。
version '…' 非法:须为 MAJOR.MINOR.PATCH不是用点分隔的三个数字。用 1.0.0。SDK 和插件索引更严格:不能有 v 前缀和后缀。
v1 每插件至多一个 resolver / v1 每插件至多一个 subscription providerresolvers / subscriptions 里有多个条目。只保留一个。
resolver entry 路径 '…' 非法(hooks entry、auth entry、subscription entry、main entry、icon、sniffRules 同理)绝对路径、盘符、..、空段或控制字符。使用包内的相对路径,例如 resolve.js。
resolver match.urls 不可为空 / hooks match.urls 不可为空规则列表为空。添加一条规则,或者干脆不写 hooks.match。
interceptors entry 路径 '…' 非法路径规则与其他入口相同。使用包内的相对路径,例如 intercept.js。
interceptors.stages 不可为空interceptors.stages 是空列表。至少列出一个阶段。
未知拦截阶段 '…',合法:[…]阶段名不存在。使用信息里列出的名称之一(prepare、refresh、probed 等)。
interceptors.stages 重复:'…'同一个阶段列了两次。删掉重复项。
interceptors match.urls 不可为空规则列表为空。至少添加一条规则;interceptors.match 必填。
interceptors timeoutMs 不可为 0timeoutMs 为 0。用正整数,实际生效最多 30000。
声明 interceptors 时 permissions 必须包含 intercept声明了 interceptors 却没有 intercept 权限。把 "intercept" 加进 permissions。
resolver timeoutMs 不可为 0timeoutMs 为 0(auth 与 subscription 同样会检查)。用正整数,实际生效最多 30000。
hooks.events 不可为空hooks 没有事件。至少列出一个事件。
未知事件 '…',合法:[…]不是 onStart、onError、onDone、onMetaProbed、onCancel 之一。改正名称(main.events 同样适用,其信息为 main.events 未知事件 '…',合法:[…])。
未知权限 '…',合法:[…]权限名不存在。使用 ffmpeg、ytdlp、auth、tasks、browserRules、desktop、background、intercept 之一。
声明 auth.entry 时 permissions 必须包含 auth声明了 auth 却没有 auth 权限。把 "auth" 加进 permissions。
声明 sniffRules 时 permissions 必须包含 browserRules有嗅探规则却没有对应权限。加上 "browserRules"。
main.background 为 true 时 permissions 必须包含 backgroundmain.background 为 true 却没有 background 权限。加上 "background"。
view '<id>' 有可移植实现,必须声明 main没有 desktop(或带 portable: true)的视图需要 main 脚本。声明 main。
声明 commands 时必须声明 main命令需要 main。声明 main。
view id '…' 非法:… / command id '…' 非法:须匹配 ^[a-z][a-z0-9-]{0,31}$id 不是以小写字母开头、由 a-z0-9- 组成、至多 32 个字符。改名。
view id '…' 重复 / command id '…' 重复 / setting key '…' 重复id 或 key 重复。改成唯一的。
contributes.views 至多 16 项 / contributes.commands 至多 32 项贡献项太多。减少。
view '<id>' title 须为 1–40 个字符 / command '<id>' title 须为 1–40 个字符标题为空或超过 40 个字符。缩短。
view '…' networkHosts '…' 非法 / …重复网络主机不是小写 DNS 名或 IP 字面量(不能带协议、端口、路径或通配符),或者重复。写成 api.example.com。
setting key 不可为空设置项的 key 为空。填上。
setting '<key>': …某个设置项有问题——widget 与类型不匹配、select 没有 options、default 不在选项里、min > max、数字或布尔的默认值不对。见 Manifest 参考。
setting '<key>': pattern 非法(JS RegExp 编译失败)pattern 不是合法的 JavaScript 正则表达式。修正正则。
包内缺少文件 '…'manifest 声明的某个文件不在文件夹或 zip 里:main、resolvers、hooks、interceptors、auth 或 subscriptions 的入口,某个 desktop 入口,或 sniffRules。信息里的路径与 manifest.json 中的写法一致。dist/ 被清空或从未构建的开发模式插件,在安装和重新加载时就会这样报错(该行显示加载失败),而不是等到任务调用 resolver 时才发现。SDK 校验还会检查 icon。创建该文件,或改对路径。SDK 项目要检查:脚本是否列在 fluxdown-plugin.config.json 的 entries 里,输出名是否一致。重新构建后点重新加载。
读取入口文件 '…' 失败: …入口文件存在但读不出来(没有权限、路径是个目录,或文件不是合法的 UTF-8);冒号之后是系统错误。出现的场合同上。修好权限或文件(UTF-8 文本),然后重新加载。
main entry '…' 扩展名须为 .jsmain 不是 .js 文件。改名。
sniffRules '…' 扩展名须为 .json / sniffRules format 须为 fluxdown-sniff-pack / sniffRules 至多 500 条规则 / sniffRules 文件超过 262144 字节嗅探规则包有问题。见 Manifest 参考。
需要 App ≥ X,当前 YminAppVersion 比你的应用新。升级 FluxDown,或降低 minAppVersion。
脚本编译失败: …resolver、hooks、interceptors、auth 或订阅脚本有语法错误——或者在顶层就抛了异常。检查时会在一个没有 flux 和 console 的空白上下文里把脚本求值一次。修正语法;把所有 flux.* / console.* 调用挪进入口函数。TypeScript 项目请运行 npm run typecheck,并确认产物已重新构建。
安装后未能加载插件(校验失败或版本门槛不满足)上面这些检查在安装过程中失败了;如果有旧版本,已经被恢复。看日志里更早的几行,找到真正的原因。
读取 manifest 失败: … / 读取 manifest.json 失败: …你选的文件夹里没有 manifest.json。选直接包含 manifest.json 的那个文件夹——SDK 项目是 dist/,不是项目根目录。
zip 内未找到根 manifest.jsonzip 根目录(或它唯一的顶层文件夹)里没有 manifest.json。压缩 dist/ 的内容;npm run pack 会正确处理。
zip 条目数 N 超过上限 200 / 解压总量超过 … 字节上限(疑压缩炸弹)文件超过 200 个,或解压后超过 50 MB。精简插件包。
zip 含非法路径(zip-slip)压缩包含有 .. 或绝对路径。用正常的压缩工具重新打包。
插件加载失败: …对开发模式插件重新加载时发现了加载失败;冒号后面是原因(上面某一条信息)。修好后再重新加载。
不是开发模式插件: …对已安装(非开发模式)的插件请求了重新加载。改为重新安装。

SDK 命令行的报错

信息原因
dist/ not found; run `fluxdown-plugin build` first没有先构建就运行了 validate。
dist/manifest.json missing构建产物不完整。
package has N files; the limit is 200、package is N bytes; the limit is 52428800包的大小限制。
fluxdown-plugin.config.json: unknown key '…' / …: entries must be an object of string → string / …: entries key '…' is not a safe relative path配置文件写错了。
<path> is not empty往非空文件夹里执行了 create。
<flag> needs a value--选项 后面没有值。
带 文件:行:列 的 esbuild 错误块某个被打包的文件里有 TypeScript/JSX 错误;到该位置修正。

resolver 问题

resolver 失败时,任务会进入下载失败,信息以 [插件] <identity>: 开头,后面是错误文本。FluxDown 绝不会自己退回去使用原始页面 URL(fail-closed),因为那可能把一个 HTML 页面存成视频。

忽略插件重试

在失败的任务上右键,选择忽略插件重试(有一个确认对话框说明含义)。FluxDown 会清除这个任务的插件绑定,并用原始链接重试——插件坏了、被卸载或被禁用,而你想要普通下载时就用它。卸载插件时,会对它的所有任务应用同样的逃生机制。

任务运行时的信息

这些信息都以 [插件] <identity>: <信息> 的形式出现。来自宿主的信息会被包装成 插件运行时错误: …、插件输出非法: … 等。

信息原因解决
插件运行时错误: <你的错误信息>你的脚本抛了异常(或者某个被拒绝的 await 没有捕获)。<你的错误信息> 就是 error.message。看它前面的日志行;想自己处理失败,就给 flux.fetch 包上 try/catch。
插件运行时错误: 入口 resolve 未定义脚本跑了,但没有在 globalThis.resolve 上放函数——漏了 defineResolver(...)、函数名写错,或者用了 ES 的 export 而不是全局函数。定义 resolve。hook 的名字是 onStart/onError/onDone/onMetaProbed/onCancel;auth 是 authenticate;订阅是 subscribe。
脚本编译失败: …脚本有语法错误。修正。
脚本执行超时调用没有在预算内完成(默认 10 秒,最多 30 秒)。计入熔断。提速或减少请求数;确实有慢站点时把 timeoutMs 调到最多 30000。
脚本超出内存上限使用超过 64 MB。计入熔断。不要持有大响应;谨慎对待被 truncated 截断的响应体。
插件运行时过载(并发已满)同时的解析太多;等待空闲名额超过 3 秒。重试任务。
插件输出非法: resolve 返回值非法: …返回的对象字段类型不对,比如 totalBytes 不是数字。按 API 参考返回正确的结构。
插件输出非法: url scheme 不允许: …、url 超过 8KB、file_name 非法: …、variants 过多: N > 50、manifest 与 url/variants/audioUrl 互斥返回结果违反了某条规则:不支持的 URL 协议、URL 过长、不安全的文件名、变体太多,或同时返回 manifest 和 url。修正返回字段。
缺少必填设置项: 插件 <identity> 需先配置「<标题>」某个 required: true 的设置项既没有值也没有默认值。脚本根本不会被调用。在插件设置(齿轮按钮)里填上,或给它一个 default。
插件运行时错误: 插件 <identity> 已卸载或加载失败;可在任务菜单选择「忽略插件重试」按原始链接下载任务绑定的插件已被卸载或加载失败。重装或修好插件,或者忽略插件重试。
插件运行时错误: 插件 <identity> 已被禁用;重新启用插件,或选择「忽略插件重试」按原始链接下载插件被禁用了(熔断后这句话里是 已被熔断自动禁用,被撤回则是 已被插件市场撤回)。启用它,或者忽略插件重试。
插件运行时错误: 插件 <identity> 当前版本未提供 resolver(或源码读取失败)…已安装的版本没有声明 resolver,或者 resolver 文件在插件加载之后消失了(例如插件运行期间 dist/ 被清空)。加载插件时就已经缺失的 resolver 文件,会更早作为加载失败报出:包内缺少文件 '…'(见上)。检查 entry 文件是否存在;重新构建并重新加载。

完全没有反应(原始 URL 被原样下载)?说明 resolver 根本没被选中:

  • 规则没有匹配。规则是对完整 URL 不区分大小写地匹配;* 是唯一的通配符;第一个 * 之前的文字必须是 URL 的前缀,最后一个 * 之后的文字必须是后缀。example.com/* 匹配不了 https://example.com/x——应写 *://example.com/*。
  • 插件被禁用、仍处于需要授权,或者没有加载。
  • 选中了别的插件。有多个插件匹配时,FluxDown 会问一次并可能记住选择;请检查插件 → 站点默认插件。无人值守的下载使用站点默认插件,或 identity 最小的插件。
  • 添加 URL 的方式绕过了插件——用常规的新建下载对话框添加链接来对照检查。

另见 resolver 教程。

flux.fetch 与被拦截的地址

flux.fetch 只能访问公网的 HTTP(S) 主机。回环、局域网私有地址、链路本地、云元数据以及其他不可路由的地址都被有意拦截,包括经由域名解析和重定向到达的情况。

信息(出现在 插件输出非法: / 插件运行时错误: 之后)原因
URL 非法: …url 无法解析。
flux.fetch 仅支持 http/https用了 file:、ftp: 等 URL。
blocked: non-routable IPURL 是字面量 IP,如 127.0.0.1、192.168.x.x、169.254.x.x。
blocked: non-routable redirect target服务器重定向到了这类地址。
fetch 失败: … 加详情连接错误、TLS 错误、超时(每个请求 10 秒),或域名只解析到非公网地址。
插件未声明 auth 权限,不能使用认证凭据没有 auth 权限却传了 authRef。

开发时怎样对着自己的服务器测试:flux.fetch 访问不了 localhost 或你的局域网。可选做法:把测试环境放在公网主机上(HTTPS,端口不限)、使用公共的 mock 服务,或者在一个设置项后面放一份写死的数据,让插件跳过请求直接返回。对于只改写 URL 的 resolver,根本不需要服务器——resolver 可以直接返回固定的 url(见 TypeScript 项目里 .invalid 主机的做法)。响应体只支持文本(超过 8 MB 时 truncated: true)。

hook 问题

hook 没法让任务失败,所以它们的错误只出现在日志里,形如带 [plugin:<identity>] 的行:

日志文本含义
hook onDone 执行失败(已忽略): <错误>hook 抛了异常、超时,或入口缺失(入口 onDone 未定义)。hook 名就是对应的事件处理函数名。
钩子并发已满,本次钩子被丢弃同时运行的 hook 太多,这次通知被丢弃,而不是排队。
外部工具钩子排队已满,本次钩子被丢弃使用 ffmpeg / yt-dlp 的 hook 的同类情况。

请记住:同一个插件里的 resolver 与 onMetaProbed 不能共存——带 resolver 的任务会跳过元数据探测,加载日志会警告 同时声明 resolver 与 onMetaProbed;带 resolver 的任务跳过探测,该钩子不会触发。另外,hook 只对已启用、且 hooks.match(如果有)匹配任务 URL 的插件运行。ffmpeg 与重试见事件钩子指南。

拦截器问题

拦截器能改动任务,所以它的影响体现在三个地方:任务的活动日志、任务的错误信息和审计日志。

活动记录

打开任务详情的日志页:类型为插件的条目由拦截器写入。条目只写字段名、阶段和文件名——绝不写请求头的值、Cookie 或请求体。

条目含义
插件 <identity> 改写了请求:<字段>应用了 prepare(或 resolver request)补丁;列出被改的字段,例如 请求头、Cookie、线程数。
插件 <identity> 的文件名改写已忽略(任务已开始下载)fileName 只在任务首次运行时生效;恢复和重试会忽略它。
插件 <identity> 调整了并发:…probed 的结果改变了 segments 或 maxConnections。
插件 <identity> 刷新了凭据(HTTP <状态码>):<字段>refresh 在请求被 401 / 403 / 410 拒绝后换发了新凭据。
插件 <identity> 选择了第 N 个画质 / …个PeriodselectVariant / selectPeriod 选中了某一项(从 1 开始计数)。
插件 <identity> 过滤了 N 个视频分片 / …音频分片segments 或 liveSegments 丢弃了分片。
插件 <identity> 改写了 N 个…分片地址segments 的 rewrite 替换了分片 URI。
插件 <identity> 请求在 N 毫秒后重试failed 调用请求了重试。
插件 <identity> 的 <阶段> 阶段出错,已忽略:<信息>调用抛异常、超时、返回了非法内容或非法补丁,且 onFailure 为 continue。任务不带这项改动继续进行。
正在执行插件下载后处理 / 插件后处理已跳过:找不到下载文件 / 插件后处理已跳过:读取任务信息失败finalize 正在执行,或因读不到文件或任务记录而被跳过。
插件后处理已取消,任务按原文件完成finalize 期间任务被暂停或取消。
插件 <identity> 将下载文件替换为 <文件名>finalize 返回了 replaceWith。

失败信息

onFailure 为 fail,或某个阶段本身就是无条件中止(probed 与 finalize 的 fail、被拒绝的 resolver 补丁)时,任务进入下载失败,信息为

[插件] <identity>(<stage>):<message>

resolver 补丁被拒绝时则是 [插件] <identity>: <message>。<message> 是插件自己的 fail 文本,或引擎给出的原因,例如 请求头 '<name>' 由引擎管理,不可设置、仅 HTTP 任务可声明 ephemeral、url 只能在同一主机内改写(跨站改写请使用 resolver)、url 不能改变下载协议类别。补丁是全有或全无的:只要有一个字段不合法,整个补丁都不会生效。

审计事件

每次调用都会写一条审计记录 intercept.<stage>(如 intercept.prepare),目标为任务 id,结果为 ok 或 error,详情里是错误文本。见权限。

常见误区

  • 根本没有被调用。 插件没有已批准的 intercept 权限(该行显示需要授权)、被禁用,或者 interceptors.match.urls 既没匹配任务的原始 URL,也没匹配 resolver 产出的 URL。规则写法见 resolver 问题:用 *://example.com/*,而不是 example.com/*。BitTorrent 与 eD2K 任务从不被拦截。
  • 阶段没列出来。 只有 interceptors.stages 里列出的阶段才会被调用。
  • fileName 没有效果。 它只在任务首次运行时生效;找一找 文件名改写已忽略 这条记录。
  • ephemeral 被拒绝。 只有 HTTP 任务能跳过探测;totalBytes 与 rangeSupported 只能和 ephemeral: true 一起使用。
  • 某个请求头被拒绝。 引擎自己管理的请求头(如 Range)不可设置,错误信息会指出是哪一个。
  • 重启后改动消失。 补丁从不落库,每次运行都会重新应用,所以插件每次都必须重新返回它们。

视图、命令与 main

main 和视图代码运行在 daemon 里的常驻上下文中;它们的错误会写进日志,视图错误还会显示在视图里。

现象原因与解决
视图没有出现在活动栏 / Web 端插件没加载或没启用;或者视图只有 desktop 实现——Web 端只显示可移植的视图(没有 desktop 入口,或带 "portable": true)。移动端不渲染插件视图。
视图顶部出现错误条,上一次的内容仍可见render 或 event 抛了异常,或返回了非法的树。错误条显示信息;下一次成功渲染后它会消失。来自 main 的信息有:render() returned no node(render 没有返回节点)、view not registered: <id>(flux.ui.view 里的 id 与 contributes.views[].id 不一致)、command not registered: <id>(manifest 里的命令没有对应的 flux.commands.register)、unknown session: …。
invalid view node root/…: …节点树违反了某条规则;路径就是节点 id。典型情况:a node must be an object {k, p, c}(字符串子节点——把文字包进 <text text="…"/>)、<kind> unknown prop "…"; allowed props: …、<kind> prop "…": expected string, got a number(数字要用 String() 转换)、<kind> missing required prop "…"、duplicate sibling id: …(两个同级节点的 key 相同)、the tree has more than 5000 nodes、nesting is deeper than the limit of 64 levels。见视图。
第一次打开就失败,视图显示加载失败和重新打开第一次渲染就非法或抛了异常。修好,重新加载,点重新打开。
「视图会话已结束」和重新打开插件被禁用、被重新加载,或者它的 main 在失败(超时或内存超限)后被回收。重新打开即可。
flux.tasks / flux.auth / flux.ffmpeg / flux.ytdlp 上出现 TypeError这些对象只有在声明了对应权限并且已被批准时才存在。声明权限、重新加载、授权。
tasks.create rate limitedflux.tasks.create 每个插件每分钟最多调用 20 次。
点按钮没反应ev.node 里的节点 id 写错了——它是 root/<key>/…;先把 ev.node 打到日志里看一次真实的 id。
在输入框里打字会跳动或丢失输入框必须是受控的:把文字存进状态,再作为 value 传回去。见可移植界面指南。
命令没有出现它需要 palette: true(命令面板)或 taskMenu: true(任务右键菜单)、一个 main 脚本,以及与之对应的 flux.commands.register。
Web 端提示仅桌面可用,或什么都没显示原生 desktop 视图只在桌面应用里存在。

main 的调用是逐个串行的,每次调用的预算是墙钟 30 秒、CPU 2 秒、内存 64 MB;超出预算会结束该插件所有视图会话,并计入熔断。

无头服务器与 Docker

  • 插件逻辑和它的日志都在服务器上。插件输出在 $FLUXDOWN_DATA_DIR/logs/fluxdown_YYYY-MM-DD.log(Docker 镜像里是 /data/logs/,所以挂载的目录或命名卷能把它保留下来)。在 Web 端用设置 → 关于 → 导出日志下载它们。
  • Web 端的从目录安装填的是服务器 / 容器内的路径。把你的构建产物挂载进去,例如 -v "$PWD/dist:/plugins-dev/mirror-demo:ro",然后填 /plugins-dev/mirror-demo。从浏览器上传 .fxplug 则不需要挂载。
  • 开发循环是一样的:在 Web 端也可以点重新加载。
  • 没有桌面会话时,desktop 视图无处显示;Web 端只显示可移植视图。
  • flux.fetch 在服务器上执行,所以它用的是服务器的网络、代理设置和 DNS——而不是你浏览器的。

常见问题

我改了 resolver.js,没有任何效果。 是开发模式插件还是已安装的副本?已安装(zip / 市场)的插件在加载时就被缓存了:请重新安装。如果是指向 dist/ 的开发模式插件,构建完成了吗?dist/resolve.js 里有你的改动吗?

我改了 manifest.json,什么都没发生。 点重新加载。用 SDK 时还要确认 npm run dev 或 npm run build 已经把它复制进了 dist/。

重新加载后提示「重新加载失败:…」。 后面的文字就是加载失败的原因(见安装与校验报错)。开发模式登记仍然保留,改好后再次重新加载。

重新加载后插件行显示需要授权。 manifest 现在请求了你尚未批准的权限或主机。批准它们;在此之前什么都不会运行。

我的 console.log 在浏览器里看不到。 插件代码运行在 daemon 里,不是在浏览器里。请看 daemon 日志或导出日志,见日志。

flux.settings.x 是 undefined。 这个 key 没有在 manifest.settings 里声明,或者该设置项既没有值也没有 default(只有 required 的设置项才会阻止调用)。

提示 setTimeout / URL / TextEncoder 未定义。 插件环境是没有浏览器 API 的 QuickJS。额外可用的只有 atob、btoa、queueMicrotask 和 performance.now();在 main 里要用 flux.timers。TypeScript 项目能拦下大部分这类问题,因为 lib 不含 DOM。

去哪里看插件做过什么? 审计日志(设置 → 扩展 → 插件 → 审计日志,或在某个插件上点审计记录)列出授权、安装、请求、任务操作等——见权限。

还是解决不了? 导出日志(设置 → 关于 → 导出日志),反馈问题时附上插件的 identity 与版本、上表中的原始错误文本,以及它前后的 [plugin:…] 日志行。

这页文档有问题?

页面
操作
↑↓选择打开