Trilium附件上传云存储插件

-
2026-09-03

Trilium 附件上传插件(nas_upload.js)功能说明与配置指南

适用版本:TriliumNext 0.105.0(桌面版 Electron 验证通过,浏览器/服务器模式亦兼容) 用途:把笔记中拖入/粘贴的文件改存到第三方存储(飞牛 NAS、OpenList/AList、群晖 WebDAV 等),笔记内只保留可点击链接,避免大附件撑爆 Trilium 的 SQLite 数据库。


image

一、功能概览

能力 说明
双后端可切换 OpenList API 模式 / 通用 WebDAV 模式,改一个配置即可
三种拦截模式 全转存 / 按大小分流 / 仅手动按钮,按需选择
拖拽 & 粘贴拦截 文件拖进笔记、或粘贴文件时自动转存,不进数据库
浮动按钮手动上传 右下角圆形按钮,可多选文件,不拦截任何输入
自动插入链接 上传成功后光标处自动插入下载链接(CKEditor 官方 API,不破坏编辑器)
自动复制剪贴板 上传完成自动复制链接,桌面版走 Electron 原生通道(不受手势限制)
年月子目录 自动按 YYYY-MM 分目录,避免单目录文件堆积
防覆盖命名 文件名加时间戳前缀
429 限流自愈 服务端限流时自动退避重试 + 会话内目录缓存,减少重复请求
链接与协议分离 上传走 WebDAV 协议地址,返回给用户的是可点击的「文件页/直链」地址(自动去 /dav

二、安装方法

  1. 在 Trilium 新建一条 Code 笔记,语言设为 application/javascript(mime = application/javascript)。
  2. nas_upload.js 的全部内容粘贴进该笔记。
  3. 给这条笔记添加标签:#run=frontendStartup
  4. 重启 Trilium(菜单 → 重启),或按 Ctrl+Shift+R 刷新。
  5. 控制台(F12)出现 [NAS上传] 开头的日志即代表启动成功;右下角出现蓝色 按钮即代表脚本生效。

⚠️ 修改 CONFIG 配置区后,必须重启 Trilium 才能生效(该脚本在 frontend 启动时加载一次)。


三、配置项详解(CONFIG)

所有配置集中在文件顶部的 CONFIG 对象,按模块说明如下。

1. 全局开关

backend: 'openlist'      // 'openlist' | 'webdav',决定走哪套上传后端
mode: 'size'             // 'all' | 'size' | 'manual',拦截策略(见下方表)
sizeThresholdKB: 1024    // mode='size' 时的大小阈值,单位 KB
mode 值 行为
'all' 所有文件都转存到 NAS,Trilium 里只留链接
'size'(默认) 按大小分流:单批中任一文件 ≥ 阈值则整批转存,否则走 Trilium 原生内联附件
'manual' 不拦截拖拽/粘贴,只提供右下角按钮手动上传

2. OpenList 后端配置(backend: 'openlist' 时生效)

openlist: {
   baseUrl: 'http://192.168.1.100:5244',  // OpenList 地址(不要带 /dav)
   token: '',                              // 方式一:直接填令牌(后台→设置→其他→令牌)
   username: 'admin',                      // 方式二:token 留空时填账密自动登录
   password: '',                           // OpenList 登录密码
   remotePath: '/trilium-attachments'      // 上传目标目录(会自动创建)
}
  • 鉴权二选一:填 token 则优先用 token;token 留空则脚本用 username/password/api/auth/login 换 token 并缓存到会话内。
  • remotePath 注意:OpenList 根目录是虚拟的,目录名须以已挂载存储名开头,例如 /本地存储/trilium-attachments(登录首页看到的文件夹名即存储名)。直接写 /trilium-attachments 在根下建目录会 403。
  • 上传成功后默认返回直链:{baseUrl}/d{remotePath}/文件名(需目标目录对 guest 可读,否则 403)。

3. WebDAV 后端配置(backend: 'webdav' 时生效)

webdav: {
   baseUrl: 'http://192.168.1.100:5244/dav',  // WebDAV 地址(OpenList 为 :5244/dav,飞牛/群晖为各自的 /dav)
   username: 'admin',
   password: '',
   remotePath: '/trilium-attachments',
   linkStyle: 'plain',        // 'plain' | 'openlistDirect' | 'dav'
   linkBaseUrl: ''            // 可选,链接用的对外域名
}

linkStyle 三选一(返回给用户的链接长相):

链接形式 说明
'plain'(默认) http://ip:5244/trilium-attachments/... 自动去掉 /dav,打开 OpenList 文件页,最常用
'openlistDirect' http://ip:5244/d/trilium-attachments/... OpenList /d 直链,浏览器直接下载/内联
'dav' http://ip:5244/dav/trilium-attachments/... 保留原始协议地址,浏览器打开会弹认证框,一般不用
linkBaseUrl:不填则自动用 baseUrl 去掉末尾 /dav;若用域名访问(如 https://openlist.nsoft.vip),在此显式填写域名,让返回的链接走公网域名而非局域网 IP。

4. 命名与目录

filenameWithTime: true,   // 文件名加时间戳前缀防覆盖,如 20260903_143251_报告.docx
monthlyDirs: true,        // 按年月自动分子目录:/trilium-attachments/2026-09/xxx.png
linkAsFilename: true      // 插入链接的文字:true=显示文件名,false=显示裸 URL

四、使用方式

自动转存(mode ≠ manual)

  • 拖拽:把文件拖进任意 text/code/render 笔记正文,被脚本拦截后自动上传、插入链接。
  • 粘贴:复制文件后 Ctrl+V 粘贴进笔记,同样自动转存。

手动上传(任何 mode 都可用)

  • 点击右下角蓝色 按钮 → 选文件(可多选)→ 自动上传并插入/复制链接。

上传后行为

  1. 右下角 Toast 提示「上传中 → 已上传 N 个文件,链接已插入并复制」。
  2. 链接自动插入到当前光标处(多个文件之间补空格)。
  3. 链接文本自动复制到剪贴板(桌面版必成功)。

五、链接插入机制(四级降级,跨版本兼容)

CKEditor 5 是 Model-View-DOM 三层架构,外部脚本绝不能直接操作 DOM(会导致 view 树与实际 DOM 失同步,鼠标悬停链接时 Link 插件查不到节点 → 报 hasClass of undefined 崩溃)。脚本因此做了运行时探测 + 多重降级:

  1. editor.addLinkToEditor(href, title) —— 官方 API(v0.105/0.98 均存在)
  2. editor.addLink(href, title, true) —— externalLink=true 必须传,否则 href 会被加 # 变成内部笔记链接
  3. 从返回对象里挖出 CKEditor 实例 → 走 model.change(writer.insertText(...)) 官方 model API
  4. 从 DOM + React fiber 反查 CKEditor 实例(__reactFiber$ → 沿 fiber.return 向上 60 层找 stateNode)→ 仍走 model API

四层全部失败时降级为「复制到剪贴板 + 提示 Ctrl+V 手动粘贴」,并在控制台输出一次诊断(编辑器类型、可用方法名),方便定位版本差异。


六、剪贴板机制(三级通道)

浏览器 navigator.clipboard.writeText()document.execCommand('copy') 都需要用户手势,而上传是异步的,await 之后手势已过期 → 自动复制会静默失败。脚本的三级通道:

  1. Electron 原生 clipboard(桌面版最优):require('electron').clipboard.writeText()不受手势限制typeof require !== 'function' 保护浏览器模式自动跳过。
  2. Clipboard API → execCommand 依次兜底(浏览器模式,仅在仍有手势时生效)。
  3. 全失败 → 弹「手动复制」面板(用户点击按钮本身即手势,必成功),1.2 秒后自动消失。

七、429 限流处理与 OpenList 限流配置

脚本侧自愈:

  • createdDirs 会话级目录缓存:同一目录建过一次不再重复发 MKCOL/mkdir 建目录请求。
  • getRetryDelay():优先读 Retry-After 头,否则线性退避 1s→2s→3s→4s→5s(上限 8s),最多重试 5 次
  • 多文件上传之间强制间隔 500ms,避免突发请求。 OpenList 服务端限流调高(若仍频繁 429):
  • 管理后台 → 设置 → 流量:4 个限速项设为 -1(不限速)。
  • max_concurrency 默认 64,按需调高。
  • data/config.json 里的 rate_limit(可能默认 20 req/min)改大或注释掉。
  • 临时建议:把 backend 切回 'openlist' API 模式,请求量约少一半,且可能走不同的限流计数器。

八、WebDAV 权限 / 路径报错速查

上传失败时脚本会按 HTTP 状态码给出中文提示并附服务端返回正文:

状态码 常见原因 排查
401 账号或密码错误 核对 username/password
403 无写权限 ①OpenList 用户未开「WebDAV 管理」权限(CanWebdavManage)②飞牛账号对共享目录无写权限 ③存储驱动只读 ④remotePath 不在已挂载存储下
404 路径不存在 检查 baseUrlremotePath
405 方法不允许 目录已存在但服务不允许覆盖(MKCOL 405 已按正常处理,非错误)
409 父目录不存在 建目录被拒,检查上层路径
413 文件超过大小限制 服务端单文件上限
429 服务端限流 见第七节,已自动重试 5 次仍失败则稍后重试
507 磁盘空间不足 清 NAS 空间

调试技巧:backend: 'webdav' 时启动会自动跑 PROPFIND 自检,结果打在控制台,可快速区分「路径错」还是「权限错」。


九、常见问题(FAQ)

Q:上传成功但笔记里链接点不动 / 鼠标划过报错?
A:说明走了错误的插入通道。确保脚本是最新版(四级降级 + model API),不要用 execCommand 直接插 DOM。

Q:提示「已复制」但 Ctrl+V 粘出旧内容?
A:浏览器模式异步复制无解,请用 Trilium 桌面版(走 Electron 原生 clipboard);或点弹出的「手动复制」按钮。

Q:OpenList 链接打开 403?
A:直链需目标目录对 guest 可读。若不想公开,把 linkStyle 设为 'plain'(文件页)或 'dav',或给目录开访客可读。

Q:改了配置没生效?
A:改 CONFIG 后必须重启 Trilium(#run=frontendStartup 只在启动时加载一次)。

Q:远程访问时浏览器报 CORS?
A:桌面版 Electron 一般不受 CORS 限制;浏览器/服务器模式访问需给 OpenList 开 CORS(或在同域下反代)。

Q:中文密码 / 中文目录怎么处理?
A:脚本用 btoa(unescape(encodeURIComponent(...))) 做 UTF-8 安全 base64;路径逐段 encodeURIComponent,中文目录/密码均支持。


十、卸载

删除那条带 #run=frontendStartup 标签的 Code 笔记并重启 Trilium 即可;右下角按钮会随脚本卸载而消失。


目录