3个脚本解放90%笔记管理时间:Trilium自动化指南
作为知识工作者,你是否每天都在重复这些操作:手动分类新收集的资料、定期整理分散的笔记片段、在不同设备间同步重要内容?这些机械劳动不仅占用大量时间,还容易出错和遗漏。Trilium Notes(以下简称Trilium)的脚本编程功能就像一位不知疲倦的助手,能帮你将这些重复工作自动化,让你专注于真正有价值的思考和创作。
本文将通过三个实战案例,带你掌握Trilium脚本开发的核心技术,从痛点分析到实际应用,全方位提升你的笔记管理效率。无论你是Trilium新手还是有一定经验的用户,都能从中找到适合自己的自动化方案。
一、痛点分析:笔记管理中的效率陷阱
在知识管理过程中,我们常常面临以下效率瓶颈:
1.1 信息收集的碎片化困境
每天从网页、电子书、会议记录中收集大量信息,但这些内容往往分散在不同笔记中,缺乏统一的组织方式。据统计,知识工作者平均每天要花费20%的时间寻找和整理信息,相当于每周损失近一整天的有效工作时间。
💡 技术提示:信息碎片化 - 指知识内容分散存储在多个位置,缺乏关联性和结构化的状态
1.2 重复性操作的时间消耗
格式化笔记、添加标签、创建索引等重复性工作占用大量时间。以每周整理10篇技术文章为例,手动添加标签、分类和关联至少需要2小时,一年下来就是超过100小时的无效劳动。
1.3 跨设备同步的复杂性
在电脑、平板和手机间同步笔记时,往往需要手动选择和传输,不仅效率低下,还可能导致版本混乱和数据丢失。特别是包含大量图片或附件的笔记,同步过程更加繁琐。
二、核心功能:Trilium脚本API详解
Trilium提供了强大的前后端脚本API,就像为你配备了两个专业助手:后端API负责数据处理和系统操作,前端API专注于用户界面和交互体验。
2.1 前后端API对比表
| 特性 | 后端API | 前端API |
|---|---|---|
| 运行环境 | 服务器/本地应用 | 浏览器 |
| 主要功能 | 数据操作、文件处理、定时任务 | UI交互、用户输入、界面展示 |
| 权限级别 | 高(可访问所有笔记数据) | 中(主要访问当前用户数据) |
| 典型应用 | 批量处理、数据导入导出、定时任务 | 界面组件、快捷键操作、交互工具 |
| 入口文件 | src/services/backend_script_api.js | src/public/app/services/frontend_script_api.js |
💡 技术提示:API(应用程序编程接口) - 允许不同软件组件之间通信的规则和协议,就像餐厅菜单,定义了你可以点的菜品(功能)和如何下单(参数)
2.2 核心API功能介绍
后端核心功能
-
笔记操作:创建、读取、更新和删除笔记,是自动化的基础功能
// 创建文本笔记 const {note, branch} = api.createTextNote( parentNoteId, // 父笔记ID "新笔记标题", // 笔记标题 "笔记内容" // 笔记内容 ); -
搜索功能:使用Trilium强大的查询语法筛选笔记
// 搜索最近7天修改的未完成任务 const tasks = api.searchForNotes("#type:task AND #status:incomplete AND #dateModified:>now-7d"); -
事务处理:确保一系列操作要么全部成功,要么全部失败,保证数据一致性
api.transactional(() => { // 在此执行多个数据库操作 note1.save(); note2.save(); });
前端核心功能
-
界面交互:添加按钮、菜单和自定义组件
// 添加工具栏按钮 api.addButtonToToolbar({ id: "quick-note", title: "快速笔记", icon: "plus", action: () => createQuickNote() }); -
消息提示:向用户展示操作结果
// 显示成功消息 api.showMessage("笔记创建成功", "success"); // 显示错误消息 api.showMessage("保存失败,请重试", "error"); -
上下文感知:获取当前活动笔记和用户操作
// 获取当前正在编辑的笔记 const currentNote = await api.getActiveNote(); console.log("当前编辑笔记:", currentNote.title);
📚 参考文档:BackendScriptApi
📚 参考文档:FrontendScriptApi
三、实战应用:三个高效自动化脚本
3.1 构建:网页内容自动抓取与格式化
问题引入:每天阅读多篇技术文章,手动复制粘贴到笔记中并格式化需要大量时间。
解决方案:开发一个后端脚本,监控剪贴板内容,自动识别网页链接,抓取内容并格式化为统一笔记格式。
代码实现:
// == 网页内容自动抓取器 ==
// 每30秒检查一次剪贴板
api.setInterval(async () => {
try {
// ① 获取剪贴板内容
const clipboardContent = await api.getClipboardText();
// ② 检查是否为URL且未处理过
if (isValidUrl(clipboardContent) && !await isUrlProcessed(clipboardContent)) {
api.log(`发现新URL: ${clipboardContent}`);
// ③ 使用事务确保操作完整性
api.transactional(async () => {
// ④ 抓取网页内容
const {title, content, author, publishDate} = await fetchWebPage(clipboardContent);
// ⑤ 创建格式化笔记
const {note} = api.createTextNote(
"web-clippings", // 父笔记ID
title, // 网页标题
generateFormattedContent(title, content, author, publishDate, clipboardContent)
);
// ⑥ 添加标签和属性
note.setLabel("source", "web");
note.setLabel("author", author || "unknown");
note.setLabel("url", clipboardContent);
note.setLabel("processed", "true");
// ⑦ 保存笔记
await note.save();
// ⑧ 前端通知
api.showMessage(`已自动保存: ${title}`, "success");
});
}
} catch (e) {
api.log(`抓取失败: ${e.message}`, "error");
api.showMessage(`网页抓取失败: ${e.message}`, "error");
}
}, 30000); // 30秒检查一次
// 辅助函数:验证URL
function isValidUrl(url) {
try {
new URL(url);
return true;
} catch (e) {
return false;
}
}
// 辅助函数:检查URL是否已处理
async function isUrlProcessed(url) {
const existingNotes = await api.searchForNotes(`#url:"${url}"`);
return existingNotes.length > 0;
}
// 辅助函数:生成格式化内容
function generateFormattedContent(title, content, author, date, url) {
return `# ${title}\n\n` +
(author ? `**作者**: ${author}\n\n` : "") +
(date ? `**发布日期**: ${date}\n\n` : "") +
`**来源**: 原文链接\n\n` +
"## 内容摘要\n\n" +
content + "\n\n" +
"## 个人笔记\n\n" +
"- [ ] 需要深入研究的点\n" +
"- [ ] 相关联的已有笔记";
}
效果验证:
- 复制任意网页链接到剪贴板
- 等待30秒或手动触发脚本
- 检查"web-clippings"笔记下是否出现新创建的格式化笔记
- 验证笔记是否包含标题、作者、来源链接和内容摘要
应用场景扩展:
- 添加自动分类功能,根据内容主题自动分配到不同父笔记
- 实现摘要生成,使用API自动提取文章关键点
- 添加图片处理,自动下载并保存网页中的图片到笔记附件
3.2 构建:笔记自动关联与知识图谱
问题引入:随着笔记数量增加,手动建立笔记间的关联变得越来越困难,导致知识孤岛。
解决方案:开发一个前端小部件,分析当前笔记内容,自动推荐相关笔记并提供一键关联功能。
代码实现:
// == 智能笔记关联助手 ==
class NoteRelationAssistant extends api.NoteContextAwareWidget {
constructor() {
super();
this.relatedNotes = [];
this.currentNoteId = null;
}
// 当笔记上下文变化时调用
async onNoteContextChanged({noteId}) {
this.currentNoteId = noteId;
await this.updateRecommendations();
}
// 更新关联推荐
async updateRecommendations() {
if (!this.currentNoteId) return;
try {
// ① 获取当前笔记
const note = await api.getNote(this.currentNoteId);
if (!note) return;
// ② 提取关键词
const keywords = this.extractKeywords(note.content);
if (keywords.length === 0) {
this.relatedNotes = [];
this.refresh();
return;
}
// ③ 搜索相关笔记
const query = this.buildSearchQuery(keywords);
const results = await api.searchForNotes(query);
// ④ 排除当前笔记并排序
this.relatedNotes = results
.filter(n => n.noteId !== this.currentNoteId)
.sort((a, b) => (b.score || 0) - (a.score || 0))
.slice(0, 5); // 取前5个最相关的笔记
// ⑤ 刷新界面
this.refresh();
} catch (e) {
api.log(`关联推荐错误: ${e.message}`, "error");
this.relatedNotes = [];
this.refresh();
}
}
// 提取关键词
extractKeywords(content) {
// 简单实现:提取长度>4的独特单词
const words = content.toLowerCase()
.replace(/[^\w\s]/g, ' ')
.split(/\s+/)
.filter(word => word.length > 4);
// 去重并返回前10个关键词
return [...new Set(words)].slice(0, 10);
}
// 构建搜索查询
buildSearchQuery(keywords) {
// 构建OR查询,匹配任意关键词
return keywords.map(k => `text:${k}`).join(" OR ");
}
// 渲染小部件
render() {
if (this.relatedNotes.length === 0) {
return `
<div class="relation-assistant">
<h3>笔记关联助手</h3>
<p>没有找到相关笔记</p>
</div>
`;
}
return `
<div class="relation-assistant">
<h3>推荐关联笔记</h3>
<ul>
${this.relatedNotes.map(note => `
<li>
<div class="note-item">
<a href="#" onclick="api.activateNote('${note.noteId}')">${note.title}</a>
<button onclick="api.getWidget('relation-assistant').createRelation('${note.noteId}')">
关联
</button>
</div>
</li>
`).join('')}
</ul>
</div>
`;
}
// 创建笔记关联
async createRelation(targetNoteId) {
if (!this.currentNoteId || !targetNoteId) return;
try {
// ① 获取当前笔记和目标笔记
const currentNote = await api.getNote(this.currentNoteId);
const targetNote = await api.getNote(targetNoteId);
// ② 添加双向关联属性
currentNote.addAttribute("relation", targetNote.title, {
noteId: targetNoteId
});
targetNote.addAttribute("relation", currentNote.title, {
noteId: this.currentNoteId
});
// ③ 保存更改
await currentNote.save();
await targetNote.save();
// ④ 显示成功消息
api.showMessage(`已关联笔记: ${targetNote.title}`, "success");
// ⑤ 更新推荐列表
await this.updateRecommendations();
} catch (e) {
api.log(`创建关联失败: ${e.message}`, "error");
api.showMessage(`关联失败: ${e.message}`, "error");
}
}
}
// 注册小部件到右侧面板
api.addWidgetToRightPanel({
widget: NoteRelationAssistant,
title: "笔记关联助手",
id: "relation-assistant"
});
效果验证:
- 创建或打开任意笔记
- 在右侧面板找到"笔记关联助手"小部件
- 观察是否显示相关笔记推荐
- 点击"关联"按钮测试关联功能
- 检查相关笔记是否添加了relation属性
应用场景扩展:
- 基于笔记内容相似度自动创建关联,无需手动触发
- 添加关联强度评分,帮助识别最相关的笔记
- 实现关联可视化,以图形方式展示笔记间的关系网络
3.3 构建:基于标签的自动化工作流
问题引入:项目管理中需要跟踪任务进度,手动更新任务状态和截止日期提醒效率低下。
解决方案:开发一个状态机脚本,基于标签自动管理任务状态流转和截止日期提醒。
代码实现:
// == 任务状态自动化管理器 ==
// 每天9:00运行
api.scheduleDailyJob("0 9 * * *", async () => {
await processOverdueTasks();
await processInProgressTasks();
await processCompletedTasks();
});
// 处理逾期任务
async function processOverdueTasks() {
// ① 搜索所有逾期且未完成的任务
const overdueTasks = await api.searchForNotes(`
#type:task
AND #status:!completed
AND #dueDate:<today
`);
if (overdueTasks.length === 0) return;
api.log(`发现${overdueTasks.length}个逾期任务`);
// ② 处理每个逾期任务
api.transactional(async () => {
for (const task of overdueTasks) {
// 设置逾期标签
task.setLabel("status", "overdue");
// 添加逾期提醒评论
const dueDate = task.getLabelValue("dueDate");
task.addComment(`任务已逾期 (原截止日期: ${dueDate})`);
// 保存更改
await task.save();
// 发送通知
api.sendNotification({
title: "任务逾期提醒",
message: `任务 "${task.title}" 已逾期,请及时处理`,
noteId: task.noteId
});
}
});
}
// 处理进行中任务
async function processInProgressTasks() {
// ① 搜索进行中的任务
const inProgressTasks = await api.searchForNotes(`
#type:task
AND #status:in-progress
AND #dueDate:>today
AND #dueDate:<now+3d
`);
if (inProgressTasks.length === 0) return;
api.log(`发现${inProgressTasks.length}个即将到期的任务`);
// ② 发送即将到期提醒
for (const task of inProgressTasks) {
const dueDate = task.getLabelValue("dueDate");
api.sendNotification({
title: "任务即将到期",
message: `任务 "${task.title}" 将在${dueDate}到期`,
noteId: task.noteId
});
}
}
// 处理已完成任务
async function processCompletedTasks() {
// ① 搜索最近完成的任务
const completedTasks = await api.searchForNotes(`
#type:task
AND #status:completed
AND #dateModified:>now-1d
`);
if (completedTasks.length === 0) return;
api.log(`发现${completedTasks.length}个最近完成的任务`);
// ② 自动归档完成任务
api.transactional(async () => {
const archiveNoteId = await getOrCreateArchiveNote();
for (const task of completedTasks) {
// 创建到归档文件夹的分支
await api.createBranch(archiveNoteId, task.noteId, {
prefix: "[完成] "
});
// 添加完成日期标签
task.setLabel("completedDate", new Date().toISOString().split('T')[0]);
await task.save();
}
});
}
// 获取或创建归档笔记
async function getOrCreateArchiveNote() {
const archiveNotes = await api.searchForNotes("#archive AND #type:folder");
if (archiveNotes.length > 0) {
return archiveNotes[0].noteId;
}
// 创建归档笔记
const {note} = await api.createTextNote(
api.rootNoteId, // 根笔记下
"任务归档", // 标题
"自动归档已完成的任务" // 描述
);
note.setLabel("type", "folder");
note.setLabel("archive", "true");
await note.save();
return note.noteId;
}
// 手动触发处理函数(用于测试)
global.processTasks = async () => {
await processOverdueTasks();
await processInProgressTasks();
await processCompletedTasks();
api.showMessage("任务处理完成");
};
效果验证:
- 创建带有#type:task、#status:in-progress和#dueDate标签的测试任务
- 将dueDate设置为昨天(逾期任务)和明天(即将到期任务)
- 运行global.processTasks()手动触发处理
- 检查逾期任务是否被标记为overdue并收到通知
- 检查即将到期任务是否收到提醒
- 将任务状态改为completed,检查是否被自动归档
应用场景扩展:
- 添加任务优先级机制,高优先级任务提前提醒
- 实现任务依赖关系,前置任务完成后自动激活后续任务
- 生成任务完成情况报告,统计周期内任务完成率和延期率
四、常见问题排查:脚本开发与运行故障解决
在Trilium脚本开发过程中,你可能会遇到各种问题。以下是几个常见错误案例及解决方法:
4.1 问题:脚本执行时提示"api未定义"
错误表现:
ReferenceError: api is not defined
原因分析:
- 脚本未正确设置运行环境属性
- 脚本在不支持的环境中运行(如前端API在后端环境调用)
解决方法:
-
确保笔记已添加正确的运行环境属性:
- 后端脚本:添加
#run=backend属性 - 前端脚本:添加
#run=frontend属性
- 后端脚本:添加
-
验证API是否适用于当前环境:
- 后端API(如文件操作、数据库事务)只能在后端脚本中使用
- 前端API(如UI组件、用户交互)只能在前端脚本中使用
💡 技术提示:环境隔离 - Trilium严格分离前后端环境,以确保安全性和稳定性,就像餐厅的前厅和后厨,各有专门的工作区域和工具
4.2 问题:搜索结果与预期不符
错误表现:
// 预期返回多个结果,实际返回空数组
const results = api.searchForNotes("#tag:important");
console.log(results.length); // 输出 0
原因分析:
- 搜索语法错误
- 标签名称大小写不匹配
- 笔记权限设置导致无法访问
解决方法:
-
检查搜索语法是否正确:
- 使用
#tag:value而非#tag=value - 注意特殊字符需要转义,如空格使用
%20 - 日期格式需符合YYYY-MM-DD或相对格式(如now-7d)
- 使用
-
验证标签实际存在:
// 列出所有标签验证 const tags = await api.searchForNotes("attrs:text=tag"); console.log(tags.map(t => t.title)); -
检查笔记权限:
// 检查当前用户是否有权限访问 const note = await api.getNote(noteId); console.log(note.isProtected); // 如果为true,可能需要解锁
4.3 问题:脚本执行超时或内存溢出
错误表现:
Script execution timed out after 30 seconds
或
RangeError: Maximum call stack size exceeded
原因分析:
- 处理大量笔记时没有分页
- 递归调用没有终止条件
- 循环中执行了耗时操作
解决方法:
-
实现分页处理大量数据:
// 使用offset和limit分页处理 let offset = 0; const batchSize = 50; let hasMore = true; while (hasMore) { const notes = await api.searchForNotes("#type:note", { offset, limit: batchSize }); if (notes.length < batchSize) hasMore = false; // 处理当前批次 for (const note of notes) { // 处理逻辑 } offset += batchSize; // 每批处理后短暂休息,避免资源占用过高 await api.sleep(100); } -
优化递归逻辑:
- 添加明确的终止条件
- 考虑将递归改为迭代
- 增加递归深度检查
-
使用事务批量处理:
// 将多个操作合并为一个事务 api.transactional(() => { notes.forEach(note => { // 批量更新操作 note.setLabel("processed", "true"); note.save(); }); });
4.4 问题:前端小部件不显示或无法交互
错误表现:
- 自定义小部件未出现在右侧面板
- 小部件显示但按钮点击无反应
- 界面更新不及时
原因分析:
- 小部件注册代码有误
- 事件处理函数作用域问题
- 未调用刷新方法更新界面
解决方法:
-
检查小部件注册代码:
// 正确的注册方式 api.addWidgetToRightPanel({ widget: MyWidgetClass, // 类本身,不是实例 title: "我的小部件", id: "my-widget-unique-id" }); -
确保事件处理函数正确绑定:
// 错误方式 render() { return `<button onclick="handleClick()">点击</button>`; } // 正确方式 render() { return `<button onclick="api.getWidget('my-widget-unique-id').handleClick()">点击</button>`; } handleClick() { // 处理逻辑 } -
数据更新后刷新界面:
// 数据变化后调用refresh() this.data = newData; this.refresh(); // 触发重新渲染
4.5 问题:权限错误,无法执行操作
错误表现:
PermissionError: Not allowed to modify protected note
原因分析:
- 尝试修改受保护的系统笔记
- 当前用户权限不足
- 操作需要管理员权限
解决方法:
-
检查笔记是否受保护:
const note = await api.getNote(noteId); console.log(note.isProtected); // true表示受保护 -
确保操作的是用户自己的笔记:
- 避免修改系统内置笔记(如#root、#templates等)
- 创建自己的笔记进行操作和测试
-
必要时修改保护状态(谨慎操作):
// 仅在测试环境使用 note.setProtected(false); await note.save(); // 操作完成后恢复保护状态 note.setProtected(true); await note.save();
五、进阶技巧:提升脚本质量与性能
5.1 模块化开发与代码复用
将通用功能封装为模块,提高代码复用性和可维护性。
// 模块笔记: #module=note-utils
// 保存为"笔记工具库"笔记
/**
* 格式化日期为YYYY-MM-DD格式
* @param {Date} date - 日期对象
* @returns {string} 格式化后的日期字符串
*/
exports.formatDate = (date) => {
return date.toISOString().split('T')[0];
};
/**
* 获取笔记的所有标签
* @param {Note} note - 笔记对象
* @returns {Object} 标签键值对
*/
exports.getNoteTags = (note) => {
const tags = {};
note.getAttributes().forEach(attr => {
if (attr.type === 'label') {
tags[attr.name] = attr.value;
}
});
return tags;
};
// 在其他脚本中使用
const noteUtils = require("note-utils");
const formattedDate = noteUtils.formatDate(new Date());
const tags = noteUtils.getNoteTags(note);
💡 技术提示:模块化 - 将复杂系统分解为独立、可重用的组件,就像乐高积木,不同模块可以组合成各种复杂结构
5.2 性能优化策略
针对处理大量笔记的脚本,采用以下优化策略:
-
批量操作代替循环单个操作:
// 低效方式 for (const note of notes) { await note.save(); // 每次保存都触发数据库操作 } // 高效方式 api.transactional(() => { notes.forEach(note => { note.save(); // 事务内批量处理 }); }); -
使用缓存减少重复计算:
// 使用api.cache缓存计算结果 function getKeywordIndex() { if (!api.cache.keywordIndex) { // 耗时的计算过程 api.cache.keywordIndex = buildKeywordIndex(); // 设置缓存过期时间(1小时) api.setTimeout(() => { api.cache.keywordIndex = null; }, 3600000); } return api.cache.keywordIndex; } -
延迟加载非关键数据:
// 只加载必要数据,其他数据按需加载 async function getNotesSummary() { // 先获取基本信息 const notes = await api.searchForNotes("#type:article", { fields: ["noteId", "title", "dateModified"] // 只获取需要的字段 }); // 需要时才加载详细内容 for (const note of notes) { note.getContent = async () => { if (!note._content) { const fullNote = await api.getNote(note.noteId); note._content = fullNote.content; } return note._content; }; } return notes; }
5.3 错误处理与日志记录
完善的错误处理和日志记录是生产级脚本的必备要素:
/**
* 安全执行函数并记录错误
* @param {Function} func - 要执行的函数
* @param {string} operation - 操作名称,用于日志
* @param {boolean} showMessage - 是否向用户显示消息
* @returns {*} 函数执行结果
*/
async function safeExecute(func, operation, showMessage = true) {
try {
const result = await func();
api.log(`[成功] ${operation}`);
if (showMessage) {
api.showMessage(`${operation}成功`, "success");
}
return result;
} catch (e) {
// 详细日志记录
const errorMsg = `[失败] ${operation}: ${e.message}\n${e.stack}`;
api.log(errorMsg, "error");
// 向用户显示简化消息
if (showMessage) {
api.showMessage(`${operation}失败: ${e.message}`, "error");
}
// 重新抛出错误,允许上层处理
throw e;
}
}
// 使用示例
const result = await safeExecute(
() => api.createTextNote(parentId, title, content),
`创建笔记 "${title}"`
);
六、技术成长路径图
初级阶段:脚本使用与简单修改(1-2周)
目标:能够使用现有脚本并进行简单修改
学习内容:
- 理解Trilium脚本基本概念
- 学会创建和运行简单脚本
- 修改现有脚本参数适应个人需求
- 使用基础API(createTextNote, searchForNotes)
实践项目:
- 修改自动抓取脚本,调整笔记保存位置
- 自定义搜索条件,筛选特定类型笔记
中级阶段:独立开发实用脚本(1-2个月)
目标:能够独立开发解决实际问题的脚本
学习内容:
- 掌握前后端API主要功能
- 学习事务处理和错误处理
- 理解脚本调度和事件系统
- 开发简单的前端小部件
实践项目:
- 开发个人知识分类系统
- 创建项目管理工作流脚本
- 实现自定义数据导入工具
高级阶段:构建复杂自动化系统(3-6个月)
目标:能够构建跨功能的复杂自动化系统
学习内容:
- 深入理解Trilium内部架构
- 掌握模块化和代码组织
- 学习性能优化和安全最佳实践
- 开发高级UI组件和交互系统
实践项目:
- 构建个人知识图谱系统
- 开发与外部应用集成的接口
- 创建自定义编辑器扩展
七、脚本模板库
以下是几个常用的脚本模板,可作为你开发自己脚本的起点:
-
定时任务模板:
// #run=backend // 定时任务模板:每天执行一次 // 配置定时表达式 const cronExpression = "0 0 * * *"; // 每天午夜执行 // 注册定时任务 api.scheduleJob(cronExpression, async () => { try { api.log("定时任务开始执行"); // 任务逻辑 await performTask(); api.log("定时任务执行完成"); } catch (e) { api.log(`定时任务失败: ${e.message}`, "error"); } }); // 任务实现 async function performTask() { // TODO: 实现具体任务逻辑 } // 手动触发函数 global.runTask = performTask; -
前端小部件模板:
// #run=frontend // 前端小部件模板 class MyCustomWidget extends api.NoteContextAwareWidget { constructor() { super(); this.data = []; } // 当笔记上下文变化时调用 async onNoteContextChanged({noteId}) { this.data = await loadData(noteId); this.refresh(); } // 加载数据 async loadData(noteId) { // TODO: 实现数据加载逻辑 return []; } // 渲染界面 render() { return ` <div class="my-widget"> <h3>我的小部件</h3> <div class="widget-content"> <!-- TODO: 实现界面渲染 --> </div> </div> `; } } // 注册小部件 api.addWidgetToRightPanel({ widget: MyCustomWidget, title: "我的小部件", id: "my-custom-widget" }); -
批量处理模板:
// #run=backend // 批量处理模板 // 配置 const SEARCH_QUERY = "#type:note AND #needsProcessing:true"; const BATCH_SIZE = 50; // 主函数 async function batchProcess() { let offset = 0; let processedCount = 0; api.log(`开始批量处理,查询: ${SEARCH_QUERY}`); while (true) { // 获取一批笔记 const notes = await api.searchForNotes(SEARCH_QUERY, { offset, limit: BATCH_SIZE }); if (notes.length === 0) break; // 处理当前批次 await api.transactional(async () => { for (const note of notes) { await processNote(note); processedCount++; } }); api.log(`已处理 ${processedCount} 个笔记`); offset += BATCH_SIZE; } api.log(`批量处理完成,共处理 ${processedCount} 个笔记`); return processedCount; } // 处理单个笔记 async function processNote(note) { // TODO: 实现单个笔记处理逻辑 note.setLabel("needsProcessing", "false"); await note.save(); } // 执行批量处理 global.batchProcess = batchProcess; batchProcess().then(count => { api.showMessage(`批量处理完成,共处理 ${count} 个笔记`); });
八、结语
通过本文介绍的Trilium脚本编程技术,你已经掌握了自动化笔记管理的核心能力。从简单的网页抓取到复杂的工作流自动化,这些工具能帮你将知识管理效率提升数倍。
记住,最好的自动化方案是那些为你个人工作流程量身定制的方案。不要满足于使用别人的脚本,而是思考自己日常工作中最耗时的环节,尝试用脚本将其自动化。
你最想自动化的笔记场景是什么?是文献管理、项目跟踪还是内容创作?尝试用今天学到的API实现它,并在Trilium社区分享你的成果。自动化的旅程没有终点,每一个小的改进都会累积成显著的效率提升。
现在就打开Trilium,开始你的自动化之旅吧!
GLM-5智谱 AI 正式发布 GLM-5,旨在应对复杂系统工程和长时域智能体任务。Jinja00
LongCat-AudioDiT-1BLongCat-AudioDiT 是一款基于扩散模型的文本转语音(TTS)模型,代表了当前该领域的最高水平(SOTA),它直接在波形潜空间中进行操作。00
jiuwenclawJiuwenClaw 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。Python0245- QQwen3.5-397B-A17BQwen3.5 实现了重大飞跃,整合了多模态学习、架构效率、强化学习规模以及全球可访问性等方面的突破性进展,旨在为开发者和企业赋予前所未有的能力与效率。Jinja00
AtomGit城市坐标计划AtomGit 城市坐标计划开启!让开源有坐标,让城市有星火。致力于与城市合伙人共同构建并长期运营一个健康、活跃的本地开发者生态。01
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python05