# 将Joplin动态接入到网页端博客
**Joplin**(<https://github.com/laurent22/joplin>) 是一个开源免费、支持各种云同步方式、支持Win、Mac、Android、iOS、Linux甚至是命令行的全平台笔记式Markdown编辑器。有了它,**其他一切用于整理笔记的Markdown编辑器都可以抛弃掉**了(当然单独打开一个md文件是需要其他编辑器的,Joplin基于笔记本结构,不是单个文件的查看器)。

但是美中不足之处是它没有网页客户端,而且即使有网页客户端,也不是那种可以当做个人博客网站来给其他人做展示的网页,都是面向个人的。
在这个情况下,我的Markdown出现在了两个不同的地方(Joplin,和我的博客),出于程序员不把冗余度降到最低就不舒服的特质,我决定「**把我的博客内核中目录结构、文章、Markdown等部分数据换成Joplin的数据**」,剩下的Joplin不支持的诸如评论、点赞等功能,再由我重新包装处理。
会产生以下两种解决方案:
1. Joplin中打包导出md,再传到博客数据中去。如果博客是静态的(没后端),那必须用这种。这种实现数据流是单向的,博客端不可能产生任何能影响Joplin数据的操作。
2. 在博客服务器上安装Joplin命令行版,然后在编写博客后端时使用HTTP请求呼叫Joplin的一个监听端口,实现动态的增删改查功能。这种数据流是双向的,相当于套壳代理实现了全功能Joplin。还可以实现阅读权限之类的(见下)
由于[我的博客](https://rickonono3.top)本身已经是第五个版本了,本身就是增删改查全在后台,后端服务器也是自己写的,因此选择使用第二种方案。如果你使用了现成的博客框架,可能只能用第一种了。
# 步骤〇 - 熟悉Joplin云同步和日常使用
Joplin云同步其实就是把一套数据实时备份到云盘上去,不同客户端进行合并和冲突处理。同步可以基于WebDAV(还单独适配了NextCloud)、OneDrive、AWS S3、Google Drive等,还有它自己的一个开源自托管专用服务器Joplin Server,还有基于Joplin Server的一个Joplin Cloud(当然花钱),这两个太专用了,我没打算用这两个。
我目前使用的是OneDrive,如果以后要搭NextCloud,可能就换成自��的NextCloud了。由于一会儿要考虑Joplin命令行版本,使用WebDAV、NextCloud和AWS是命令行客户端支持比较好的,但是因为我目前没有直接的私有WebDAV方案(也有但是太拉),国外的网盘又彻底地不好访问,所以只能硬着头皮上OneDrive。在命令行里登录OneDrive是需要一些操作的,一会儿会有步骤。
选好了网盘,剩下的事情就是先自己多用用,了解一下Joplin的整个使用流程。Joplin支持树形笔记本结构(但是只有Windows和Mac和API目前有正规实现,其他端都是只能查看不能改),支持TODO记录和普通记录,TODO记录就是整个记录被视为一个待办项。另外为了和通用Markdown格式相匹配,建议在Markdown格式选项里打开Soft break增强(就是换行必须换两个才能生成`<p></p>`,跟两个空格再换一个行会使用`<br/>`,不跟空格只换一个行不视为换行的那个),打开这个会和大部分Markdown渲染引擎兼容。
注:坚果云WebDAV使用的传输优化算法与Joplin不兼容。我差点掉坑里,幸好网上有老哥指出来了。
# 步骤一 - 安装和配置Joplin命令行端
遇事不决,[官方文档](https://joplinapp.org/terminal/)!
除官方文档外,这里有些事情需要注意:
- 命令行端能实现大部分的基础工作,但是依然有些功能没有完全实现,部分情况下我们需要打开`~/.config/joplin/settings.json`文件,去里面手动改配置项(一会儿详细介绍)
- 命令行端笔记标题和笔记内容是混在一个文本文件里的,第一行是笔记标题,第二行是空行,第三行开始是笔记内容,这和其他所有客户端都是分离开的不太一样。
- 命令行端的同步。如果使用的是只需要明文用户名、密码或密钥的同步方案,当然是最好的,就直接按官方文档加入配置里就行了;如果像我一样使用的是OneDrive,设置完`config sync.target 3`之后,首次执行`sync`,Joplin会给你弹出一个地址,让你从**浏览器**里访问这个地址,这需要下面的方法来解决。
## 通过浏览器在微软网站上登录OneDrive
**怎样在服务器的终端上打开一个支持JS的浏览器,在微软网站上登录OneDrive?**
两个方案:
- SSH连接中,有一个X11 Forwarding技术,可以在具有X Server环境的系统的SSH客户端上打开没有图形界面但是开启了X11转发的SSH服务器上的GUI应用程序,包括浏览器。
- 截止2022年最好的终端浏览器——[browsh](https://github.com/browsh-org/browsh),这是一个基于无头Firefox的开源终端快照式浏览器,可以在没有GUI的终端里通过捕捉并模拟一些色块来显示Firefox渲染出的页面,然后对文字有一些专门的优化(然而中���支持不佳,稍有遗憾)。
## 将`joplin sync`加入cron任务中
Joplin只有在客户端打开的情况下才能定时同步(默认5mins),甚至只挂着`joplin server start`都是不行的。为了保证同步自动化,建议将`joplin sync`加入cron任务中。
那么这样,我们就实现了一个可以正常使用的Joplin命令行客户端——然而我们并不是真的打算在命令行用它干什么。
# 步骤二 - 命令行的真正用处——暴露API
Joplin是一个庞大且有野心的项目,它提供了一套完整的插件体系,和基于RESTful API的通用编程接口,称作[Joplin Data API](https://joplinapp.org/api/references/rest_api/)。原本这套接口主要是用来和网页剪裁插件配合使用的,在桌面端,把网页上的内容快速保存到Joplin里——然而这只是它的一种用法,其实它暴露出的接口功能足以实现一个真正的套壳客户端,可以被任意的程序接入和封装,达到数据全部打通的目的。
开启API服务器只需如下步骤:
1. `config api.port 端口号`
2. `server start` (这句建议在shell里执行`joplin server start`,别在joplin程序里执行,因为会阻塞)
它只监听本地环路,所以无法直接通过外网访问哦!
然后,如文档所述,如果我们想使用这套API,必须要有一个token。文档中提供了两种token获取方式,一种是全局token,一种是程序申请的token。但是经过实际测试,命令行端无法同意程序申请的token,所以只剩一种全局token方式了。根据[这篇主题](https://discourse.joplinapp.org/t/retrieval-of-api-key-on-linux/18593/3)中Joplin作者给出的方案,我们在`~/.config/joplin/settings.json`文件中可以看到一个叫`api.token`的字段,它就是我们需要的全局token。
最终构造出的请求应该类似这样:
```sh
curl 'http://localhost:端口/notes?token=xxx'
```
# 步骤三 - 编程实现博客后端
这一步就是看文档啦,结合自己的软件需求,列出以下几个功能可以参考:
- 文章获取
- 文章渲染
- 文章操作(可选)
- 目录结构(可选)
- 目录操作(可选)
- 标签功能(可选)
- 搜索功能(可选)
我是选择了包含以上全部功能的,因为原有的博客系统就是目录式的,也有自己开发的markdown编辑器,正好可以都用上,标签和搜索也是比较有用的功能。
最后附上我自己设计的Joplin笔记本架构(+为博客中可见,-为博客中不可见):
```text
- 一些不在博客中的笔记本
+ _BLOG
+ 一些公开笔记本
+ 一些加密笔记本*|PASSWORD
+ 一些公开笔记本
+ 一些加密笔记本*|PASSWORD_2
- 一些隐藏笔记本*
- 一些隐藏笔记本*
```
- 只有 \_BLOG 笔记本下的东西才会被放在博客里,其他是个人自己的笔记。
- 笔记本和笔记都可以通过在标题末尾加`*`来标记为隐藏(不能在博客上看),在临时隐藏一些文章时很有用。
- 笔记本和笔记都可以通过在标题末尾加`*|密码`来标记为加密(需要输入密码才能看),如果嵌套了多层加密,则用户在博客上必须把所有密码输对才能看。
- 任何嵌套在隐藏笔记本中的内容都不会被博客渲染,不论它是公开、隐藏还是加密,只能在Joplin中查看。