前言

之前在做微信机器人的时候(见:制作一个微信机器人 ),突然想到能不能在微信上发送一条消息就可以将笔记记录到trilium中,毕竟手机浏览web端的体验实在是有些别扭。

摸索一番后发现trilium有相应的API可供调用而且还支持自定义API,于是打算在微信机器人中增加与trilium的联动。

目前实现的功能

  1. 记录灵感 - 记录突然想到的事情
  2. 记录日记 - 记录今日的想法
  3. 在日程表上记录重要事件
  4. 查看重要事件倒数日
  5. 查看待办任务
  6. 新建待办任务

准备工作

导入python包 trilium-py,这个库中封装了部分trilium的常用方法。使用前需要初始化自己的笔记地址和token。

def __init__(self) -> None:
server_url = 'https://domain:8080'
token = 'mytoken'
self.ea = ETAPI(server_url, token)

记录灵感

我的习惯是在今日日记下方建立子笔记方便日后回溯,首先建立一个方法,用于处理事件。

def sendInspiration(self,title="新灵感",content=""):
pass

所以首先需要做的是获取今日日记笔记的id。

today = str(datetime.today().date())
todayNoteId = self.ea.get_day_note_id(today)

在笔记下方建立子笔记,传入标题和内容,并且设置前缀【灵感】。

res = self.ea.create_note(parentNoteId=todayNoteId,type="text",title=title,content=content,prefix="灵感")

此外,我还习惯在【灵感】笔记上打标签,一个是【#灵感】方便查找,另一个是【#createdDate=<创建日期>】,方便使用 Trilium-collection-views.进行布局。

self.ea.create_attribute(attributeId="",noteId=res["note"]["noteId"],name="灵感",type="label",value="",isInheritable=False)
self.ea.create_attribute(attributeId="",noteId=res["note"]["noteId"],name="createdDate",type="label",value=today,isInheritable=False)

至此微信机器人可以通过调用sendInspiration方法记录灵感,在微信机器人的监听方法中加入判断:

记录重要事件elif "灵感" == newMsg[1][0:2]:
content = newMsg[1][3:]
title = loopTips("请输入标题")
res = triliumtools.sendInspiration(title,content)
wechat.SendMsg(res)

效果如下图:

记录日记也是同理,在此不做赘述。

记录重要日程

这里需要一个trilium插件: trilium-scripts.,这是一个更好的日历视图,可以直观的显示某天的日程安排和重要事项,效果如下图所示:

这个插件通过在日记笔记中增加设定的标签,可以在视图中显示相应的事件,比如在1月10日的日记笔记中增加标签:#Event=理发,就会在日历的相应位置显示事件。

所以我们需要做的就是接受相应的参数,在指定的日记笔记中添加标签即可。

创建方法:

def setEvent(self,type,date,name):
dateId = self.ea.get_day_note_id(date)
self.ea.create_attribute(attributeId="",noteId=dateId,name=type,type="label",value=name,isInheritable=False)
return "记录成功!"

在微信机器人的监听方法中增加新的判断:

elif "Event" in newMsg[1] or "Holiday" in newMsg[1] or "Birthday" in newMsg[1]:
res = newMsg[1].split(" ")
if re.search(r'\d{1,2}-\d{1,2}-\d{1,2}',res[1]) == None:
wechat.SendMsg("日期有误!")
else:
anser = triliumtools.setEvent(res[0],res[1],res[2])
wechat.SendMsg(anser)

这里我只设定了EventHolidayBirthday三个事件,之后只需要在与机器人对话的时候传入相应的关键词、日期和事件即可记录到trilium中,效果如下图:

获取倒数日

倒数日是我在上一步中的插件上进行的魔改,在日历下方增加了倒数日功能,效果图如下:

它会根据我们设立的事件标签,动态生成事件并且自动算出距离事件的日期。

现在我需要实现的是向微信机器人发送【倒数日】三个字,然后微信机器人将倒数日推送给我。

显然trilium-py无法实现我的需求,这时候需要自己定义一个API接口,说到这里我又不得不感叹trilium真是一个神级软件,可拓展性也太强了。

新建一个后端js代码笔记,添加一个标签#customRequestHandler=daysMatter ,代码如下:

const {req,res} = api;
api.log('获取倒数日api调用');

function putHTML (type,eventName,date) {
var nowDate = new Date();
var lastDate = new Date(date);
if ((type == "Birthday" || type == "Holiday") && (nowDate > lastDate)) {
return
}
if (nowDate >= lastDate){
var days = parseInt((nowDate - lastDate)/(1000*3600*24))
var infoText = "⋆ "+eventName+"已经:"+days+"天"
}else {
var days = parseInt((lastDate - nowDate)/(1000*3600*24))+1
var infoText = "⋆ "+eventName+"还有:"+days+"天"
}
return infoText
}

if (req.method == 'GET' ) {
var types=["Event","Birthday","Holiday"]
var newArr =[]
for (const type of types) {
var attrs = api.sql.getColumn(`SELECT DISTINCT value FROM attributes WHERE name='`+type+`' AND isDeleted =0`)
for (attr of attrs) {
notes = api.getNotesWithLabel(type,attr)

targetNote = notes[[notes.length-1]]
noteTitle = targetNote.title.substring(0,11)


templist = [type,attr,noteTitle]
newArr.push(templist)
}
}
var msgs = []
for (const note of newArr) {
msgs.push(putHTML(note[0],note[1],note[2]))
}
res.status(201).json(msgs);
}
else {
api.log("请求参数错误, 返回400");
res.send(400);
}

之后即可通过https://域名/custom/daysMatter进行访问,如此一来即可使用requests获取返回值,代码如下:

def daysMatter():
wechat = WeChat()
wechat.ChatWith("东东")
msgs = []
url = "https://domain:8080/custom/countdown"
headers = {
'Accept': "application/json, text/plain, */*",
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
'Connection':'close'
}
requests.DEFAULT_RETRIES = 5 # 增加重试连接次数
s = requests.session()
s.keep_alive = False # 关闭多余连接
try:
res = requests.get(url,headers=headers)
for event in res.json():
if event !=None:
msgs.append(event)
wechat.SendWrapMsg(msgs)
except:
wechat.SendMsg("trilium连接失败...")

最终实现的效果如下图:

任务管理

之前在这篇文章中介绍过trilium的任务管理功能:改进 trilium 的任务管理功能

因为平时不方便使用电脑的时候有查看当前待办事项的需求,所以使用微信机器人快速查看任务是个不错的方法,调用trilium-py可以很方便的实现这一功能,代码如下:

def findTask(self,type):
msgs = []
boxNoteId = "HDjVNjIYU3iI"
doingNoteId = "WgDRTZpY7StM"
serchId = (type == "盒子") and boxNoteId or doingNoteId
try:
childsNoteId = self.ea.get_note(serchId)["childNoteIds"]
for childNoteId in childsNoteId:
title = self.ea.get_note(childNoteId)["title"]
msgs.append(title)
except:
msgs.append("连接失败...")
return msgs

新建任务的方法与上文类似,不过多赘述, 但是有一点需要注意的是,我的任务是由模板创建的,类似下图:

所以在建立任务笔记的时候需要增加一个关系标签,将template指向任务模板:

create_attribute(attributeId="",noteId=res["note"]["noteId"],name="template",type="relation",value="任务模板",isInheritable=False)

结语

经过这么一番折腾之后,我可以在微信中实现与云端笔记的交互。