博客,对我而言,像是一种记录生活或者点滴灵感的小小空间。随心所欲,想到什么写什么,然而灵感并不会在我坐在电脑面前看着打开的编辑器发呆的时候突然迸发出来。大部分时候,总是一闪而过的思绪,一股想要动笔的念头,出门在外,背着电脑写博客多少有点不现实,等我新建文章准备就绪,灵感早已飘至九霄云外,只剩我和电脑面面相觑,落得一地空虚...

需求

为了解决这个问题,首先得搞明白我的需求。我的要求不高,我只需要多端能够同步我的文章,就像那些日记软件一样,打开手机写上两笔,回到电脑上能够继续编辑,不用我每次在 手机/平板 上写完了文章之后还要复制粘贴到电脑上再推送到 Github 。

所以,为了能够实现文章实时同步,多端的编辑器得统一了。之前我的写作方案是

  • Windows:Typora/VS Code
  • iOS:备忘录/天悦日记
  • Android:天悦日记

我需要一个软件,它需要

  • 支持 MD 语法,最好支持 LaTeX
  • 三端适配(电脑/手机/平板)
  • 多端实时同步(Webdav/S3...)
  • 连接 Github 执行文章推送的操作
  • 最好能实时预览
  • 最好免费

基于此,能够实现上述功能的,我选 Obsidian !

旧的思路

My设想是在移动端(iOS/Android)编辑的时候,hexo 的命令需求就不考虑了,即在移动端只同步博客文章,不同步其他的配置项,要更新博客的话推送文章到 Github 仓库使用 Action 自动更新博客。

流程图如下,使用 Obsidian 的 Remotely Save 插件进行实时同步。

But!我忘了在移动端进行 git push 操作是很麻烦的。先不说怎么在手机上用 Git ,单就这边 push 完之后另外那边就得 pull,实时同步不会同步 .git 文件,所以多端的 git 提交信息是不一致的,这个时候你想 push 到 Github,那就嘿嘿嘿了。然后!Obsidian 的 Git 插件,基本上都不支持移动端,我总不能在手机上开 terminal 写命令行吧,噢,我的老天那实在是太抽象了!他们直接在 README 中标注了

Caution

Depending on your device and available free RAM, Obsidian may

  • crash on clone/pull
  • create buffer overflow errors
  • run indefinitely.

It's caused by the underlying git implementation on mobile, which is not efficient. I don't know how to fix this. If that's the case for you, I have to admit this plugin won't work for you. So commenting on any issue or creating a new one won't help. I am sorry.

新的思路

正当我一筹莫展思索如何在手机上完成 push 操作时,突然灵光一闪,既然本地 push 到仓库不行的话,那么让仓库自动 Download 我的同步文件如何?这样在本地就就不需要进行 git 操作,只需要发个通知让 github action 自动跑就行了,还能避免 git 和同步插件的冲突问题。

有搞头,我瞄见曙光了哈。新的思路如下

新的思路
新的思路

理论可行,实践开始!

准备

我用的同步方案是 Remotely Save + Cloudflare R2 ,为什么选 R2 ?

  • 存储费用:每月免费 10G 额度,超出每 GB 收 $0.015
  • A 类操作:每月一百万次免费额度,每秒 1000 次
  • B 类操作:每月一千万次免费额度,每秒 250 次
  • 流量费用:无!对的他没有流量费用!

我选它不是因为我的钱包比脸还干净哈,你们不要误会了,我只同步 MD 文件,免费的额度妥妥的够用哈,他要是挂了我都要夸他是慈善家。

玩笑就开到这里,你需要准备的东西有:

  • 一台 PC
  • Github 账号
  • Cloudflare 账号
  • 一个灵巧的脑袋

Cloudflare

首先登录 Cloudflare ,要开通 R2(怎么开网上教程很多,这里就不多赘述)。在 R2 中我们创建一个 bucket 储存桶,名称随意(我的名称是 obsidian-hexo ),好记即可,等会要用。

现在我们创建 API 令牌,使用 Obsidian 同步时需要令牌,点击右侧的管理 API 令牌。新建一个,名称随意,权限勾选管理员读或写,对象读或写我不知道行不行哈。其他不动,点击创建。

点击确认创建之后会出现下面三个值,只会出现一次! 复制保留等下要用。

  • Access Key ID
  • Secret Access Key
  • Endpoint

然后记下你的 bucket-name ,就是你刚刚创建储存桶时取的名称,不是 API 令牌的名称哈,不要搞混了。Cloudflare 配置完成,可以把他关掉了。

Github

登录 Github 账号,创建一个新的空仓库 MyBlogCode 并设为 private ,进入 仓库设置secrets and variables -> Action 项中,新建四个 secret ,注意是 secret 不是 variable !填入你刚刚从 Cloudflare 获取的四个参数。

R2_Endpoint: https://xxxxxxxxxxx.r2.cloudflarestorage.com 
R2_Access_Key_ID: xxxxx
R2_Secret_Access_Key: xxxxxxxxxxxx
R2_Bucket_Name: obsidian-hexo # 替换成你自己的

如果你有推送到 github pages (xxx.github.io) 的需求,你还需要新建一个 secret 名称为 HEXO_DEPLOY_PRI 作为仓库的私钥,在 github pages 仓库中设置公钥。如何操作可以参考

设置好一对密钥之后不用看他的 action ,使用我的 action 。

Hexo

在你的本地 Hexo 博客根目录下执行 git init 将 Hexo 初始化为 git 仓库,然后编辑 .gitignore (没有的话新建一个),填入以下内容,这是执行 git 操作时会忽略的文件。

.gitignore
.DS_Store
Thumbs.db
db.json
*.log
node_modules/
public/
.deploy*/
_multiconfig.yml
themes/
source/
scaffolds/
yarn.lock

本地新建 .github 文件夹及其文件,文件结构如下

hexo 根目录
└─ .github
├─ dependabot.yml
└─ workflows
└─ auto_deploy.yml

文件内容如下

dependabot.yml

功能是检测你使用的 npm 包是否有更新,如果有更新则提交 PR 到你的仓库,你不加这个文件也没问题。

/.github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 20
auto_deploy.yml

在 github action 上完成 hexo g & d 操作,其中有参数需要自定义!请仔细阅读并配置注释处!

其中 Instanll Pandoc 是可选项,因为我使用的渲染器是 hexo-renderer-pandoc 需要有本地 pandoc 环境。

/.github/workflows/auto_deploy.yml
name: CI

on:
push:
branches:
- main
repository_dispatch:
types: publish

env:
GIT_USER: your-name # github用户名
GIT_EMAIL: your-email # 你的邮箱
THEME_REPO: xaoxuu/hexo-theme-stellar # 如果你有自己fork的主题仓库可选你自己的仓库,没有默认使用最新版进行构建
THEME_BRANCH: main # 使用主题分支
DEPLOY_REPO: your-name/your-name.github.io # hexo-deploy-git推送的目标仓库
DEPLOY_BRANCH: main # 推送到目标分支

jobs:
build:
name: Build on node ${{ matrix.node_version }} and ${{ matrix.os }}
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest]
node_version: [20.x]

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Checkout theme repo
uses: actions/checkout@v2
with:
repository: ${{ env.THEME_REPO }}
ref: ${{ env.THEME_BRANCH }}
path: themes/stellar

- name: Sync R2
uses: luxl/download-s3-with-endpoint@v0.2.2
with:
aws_access_key_id: ${{ secrets.R2_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.R2_SECRET_ACCESS_KEY }}
aws_region: us-east-1
aws_bucket: ${{ secrets.R2_BUCKET_NAME }}
endpoint: '${{ secrets.R2_ENDPOINT }}'
source: ''
target: './source'

- name: Checkout deploy repo
uses: actions/checkout@v2
with:
repository: ${{ env.DEPLOY_REPO }}
ref: ${{ env.DEPLOY_BRANCH }}
path: .deploy_git

- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node_version }}

- name: Install pandoc # 可选
run: |
sudo apt-get update
sudo apt-get install -y pandoc

- name: Configuration environment
env:
HEXO_DEPLOY_PRI: ${{secrets.HEXO_DEPLOY_PRI}}
run: |
sudo timedatectl set-timezone "Asia/Shanghai"
mkdir -p ~/.ssh/
echo "$HEXO_DEPLOY_PRI" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
git config --global user.name $GIT_USER
git config --global user.email $GIT_EMAIL
# 若没有使用hexo-deploy-git插件推送到其他github page仓库,可以把上面的操作都注释掉
npm install hexo-cli -g
npm install

- name: Deploy hexo
run: |
hexo cl
hexo g
hexo d

这个 action 跑起来的大概要四到五分钟,挺慢的说实话(其实是我插件比较多它deploy的时候耗时太久了),不过我不需要实时给出结果,它不报错就行了,至于速度,Who Cares?

连接Hexo与Github

上述步骤完成之后可以连接你的 github 空仓库到你的本地 hexo 仓库了,在 hexo 根目录下依次执行以下命令,将 your-name/your-repo 替换为你的仓库地址。

git add .
git commit -m "init"
git remote add origin https://github.com/your-name/your-repo
git push -u origin main

上传完成之后你的 github 空仓库现在应该有如下内容

github仓库
├─ .github
│ ├─ dependabot.yml
│ └─ workflows
│ └─ auto_deploy.yml
├─ _config.stellar.yml
├─ _config.yml
├─ .gitignore
└─ package.json

Obsidian

PC 下载安装 Obsidian ,移动端先不要急,PC 配置好之后再配置移动端。

知识库

首先将我们的博客 source 目录作为一个 Obsidian 知识库(vault)打开,然后设置语言为中文🫠

插件

打开第三方插件市场,关闭安全模式,搜索并安装下面两个插件(要挂🪜或者去 Github 下载)

Remotely Save

设置打开插件的配置选项,选择远程服务为 S3或兼容S3的服务,分别填入刚刚从 Cloudflare 获取到的几个参数

Endpoint: https://xxxxxxxxxxx.com
Access Key ID: xxxxx
Secret Access Key: xxxxxxxxxxxx
Region: us-east-1
Bucket Name: obsidian-hexo # 替换成你自己的

完成之后点击下面检查是否可连接,右上角提示能够访问到对应储存桶即可。

先别急着关,滑到下面,在进阶设置中,打开同步以 "_" 开头的文件夹。处理空文件夹选删除本地和服务器上的文件夹。

其他同步参数可以自己看情况配置,我设置的是默认启动后 1s 同步一次,每 5 分钟同步一次。不要打开同步配置文件夹!不要打开同步配置文件夹!开启的话多端的配置文件容易混淆!你也不想好不容易填好的配置文件突然就空了叭。

APIRequest

要使用 API 调用 github action,你需要生成一个 access token ,链接直达

名字随便填,时间选永不过期,权限选 Workflow 即可。生成 token 并复制(只会出现一次)。

回到 Obsidian ,设置中打开该插件的配置选项,对应填入如下内容,你需要将 Authorization 中的 access_token 替换为你刚刚复制的 tokenyour-name/your-repo 替换为你的仓库路径。

name: hexo
URL: https://api.github.com/repos/your-name/your-repo/dispatches
Response format: JSON
Request method: POST
Data to Send: {"event_type": "publish"}
Headers: {"Content-Type": "application/json", "Authorization": "Bearer access_token"}

填完之后点击 ADD THIS APIR ,该插件配置完成。

如何使用?在 Obsidian 中呼出命令面板,搜索 API ,找到 APIRequest: Show Response in Modal 点击即可,会提示报错 Error ,不用鸟他,github action 已经在跑了。

移动端

PC 端配置完成之后,在移动端安装 Obsidian ,初始我们创建一个 vault ,名称为 source (不能取其他名字,否则无法同步),进入该知识库,安装 Remotely Save 插件。

这个时候我们回到电脑端,打开 Remotely Save 的设置界面,滑到下方有个导出,我们选择导出非 Oauth2 部分,会出现一个二维码。使用移动端的浏览器扫描该二维码会得到一长串 obsidian://... 字符配置,复制下来填入插件设置的导入部分,退出设置我们手动同步一次,就能够看到你的文章出现咯!

安装 APIRequest 插件,参数就按照电脑端的配置填,保存一致,用法相同。

同步以及博客构建部分到这里就结束了,下面是优化 Obsidian 的使用部分


博客文章管理

插入Front-matter模板

Obsidian有一个模板功能,允许我们预先写好一些内容模板,写文章时可以随时快捷插入,设置文章模板为 _draft 目录。

由于我是用的 source 文件夹,所以无法读取到它的上级目录 scaffolds 中的模板文件,所以我们曲线救国,在 _drafts 文件夹下新建 post.md ,把原来的 scaffolds 中模版的 front-matter 复制过来,若你和我一样使用的是 stellar 主题,那你可以抄我的配置。

source/_drafts/post.md
---
title: {{title}}
date: {{date}}
updated: {{date}}
published: false
tags: []
categories: []
description:
cover:
banner:
poster: # 海报(可选,全图封面卡片)
topic: 标题上方的小字 # 可选
headline: 大标题 # 必选
caption: 标题下方的小字 # 可选
color: 标题颜色 # 可选
sticky: # 数字越大越靠前
mermaid:
mathjax:
topic: # 专栏 id
references:
---

新建文章时我们使用模板即可。这个模板图标位置可能和我的不太一样,可以自己拖动排序。

还需要你在 设置 -> 编辑器 -> 显示 中将文档属性那一条改为 源码 ,因为有时候 Obsidian 识别的 front-matter 不好修改。

新建文章

可以设置新建 Markdown 文件生成的位置,将其改为 _posts 目录下。同时把使用 Wiki 链接关掉,Obsidian 的链接格式并不是 MD 语法。

发布文章

将文章 front-matter 中的 published 参数改为 true 即可。

Todo

现在已经可以在移动端丝滑的写一篇文章并发布到博客上了,不需要电脑操作干预。但是还有一个非常影响体验的问题就是图片上传的问题,我在电脑端使用的是 Piclist,能够自动将图片转化为 webp 格式并上传,然而在移动端上没有插件能够上传到我使用的图床,终究是做不到像电脑上那样拖拽上传,使用其他图床管理起来又十分不便。

或许可以把 Piclist 部署到服务器可能解决这个问题?但是这样一来我就需要一台服务器了…看来我得把去不图床的网页放后台开着了…

有些思路了,在本地编辑的时候上传图片的话直接让他上传到 R2 里面去,在 action 上让他装 piclist 去批量上传图片替换掉文章中的本地图片引用链接,最后删掉 R2 中的图片并同步回去,感觉比较麻烦,不知道是否可行。潜在的问题有

  • 同步回去 Remotely Save 能否检测到 R2 上的更新并同步下来,检测不到的话会不会用本地的文件覆盖掉 R2
  • 如果写正则匹配式的话需要避开在线图片的引用,不能匹配 ![...](https://...)
  • 匹配之后返回的替换回来的格式是 {% image %} 还是 MD 标准语法?考虑到使用 Swiper 需要是 MD 标准语法,所以排除 image 标签,意味着无法控制图片的大小和其他参数
  • 每次 action 都是重头跑的,要是 R2 有图片没有被删除的话下次又会被重复上传,浪费图床空间

研究了一下写了脚本放 action 上面跑,结果上传本地图片到去不图床的时候被宝塔拦下来了😭

结语

最后发现还是在电脑上写博文最舒服,图片的制作,上传,各种样式杂七杂八的东西放到移动端上面实现多少有些别扭和不合理,想要让博客创作完全脱离电脑目前来说还是很难的(对我而言),不过我的需求没那么高,能同步文章,在我离开电脑之后能够再写上几笔,留下我的一点点思绪,我就大致满足了。

我的hexo工作流
我的hexo工作流

实际上我的创作 belike

偷群u的图
偷群u的图

PS. 这篇文章的文字部分基本都是在我的 Android Pad 上撰写


陕ICP备2022011813 | 由又拍云提供CDN加速
| 基于 Stellar 主题
十年之约