Huaiyao Jin

Huaiyao Jin

关于 Memos

最近决定正式弃用 flomo 和心光 app,总是有些介意数据在别人的服务器上。

也正是这个原因,之前在这两个 app 上记录并不多,并且记录的也只是一些自我提醒和日常事件,不涉及特别隐私的内容。

用来替换它们的是 Memos,很早就从“i小声读书”公众号看到过,一直没有下决心试用。

Memos 开源可自托管,所有数据存放在本地,用起来像是一个迷你微博。使用之后最近这几天记录得更多了,也会上传小朋友的照片。

安装与配置

docker 安装

在 Mac mini 上安装 Docker Desktop,后来感觉有些笨重,改成 Orbstack。

安装 Memos,参考 https://www.usememos.com/docs/install/self-hosting

docker run -d \
  --init \
  --name memos \
  --publish 5230:5230 \
  --restart always \
  --volume ~/.memos/:/var/opt/memos \
  ghcr.io/usememos/memos:latest

自定义样式

自定义霞鹜文楷字体,参考 https://ysicing.me/tools/memos-diy-style/

自定义样式:

body{font-family: "LXGW WenKai Screen", sans-serif !important;}

自定义脚本:

function changeFont() {
  const link = document.createElement("link");
  link.rel = "stylesheet";
  link.type = "text/css";
  link.href = "https://cdn.staticfile.org/lxgw-wenkai-screen-webfont/1.7.0/lxgwwenkaiscreen.css";
  document.head.append(link);
};
changeFont()

效果图:

image.png

MacOS 客户端

MacOS 没有专门的 app,也不太习惯 Moe Memos,搜索了一下,最后用 nativefier 把网页打包成 app。

参考:
https://sspai.com/post/57865
https://github.com/nativefier/nativefier

sudo npm install nativefier -g

nativefier "http://10.0.0.100:5230"

image.png

用 Alfred 给它设置快捷键,愉快地使用。

image.png

iOS 客户端

直接用网页版,Safari 里添加网页到主屏幕。

但是 Memos 服务是运行在内网,在外面如何访问 memos 是个问题。

折腾了好一会儿,还是没有把握将 Mac mini 暴露在公网上,搜索了一阵,最后在 Mac mini、Macbook、iPhone 上安装 Tailscale,把这些设备组成一个虚拟局域网,安全易用。

运行 Tailscale 后手机网页访问 Mac mini IP 加端口即可:

导入旧数据

把之前在心光、Noto、Pendo 里零散的记录清洗一下,然后导入 Memos。

使用 https://github.com/JakeLaoyu/memos-import-from-flomo 会丢失记录的原始时间。

研究了一番,最后使用直接导入 sqlite 数据库的方法。

jinhuaiyao@huaiyaos-mac-mini .memos % sqlite3 memos_prod.db
sqlite> .schema
...
CREATE TABLE memo (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  creator_id INTEGER NOT NULL,
  created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
  updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
  row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
  content TEXT NOT NULL DEFAULT '',
  visibility TEXT NOT NULL CHECK (visibility IN ('PUBLIC', 'PROTECTED', 'PRIVATE')) DEFAULT 'PRIVATE'
);
...

jinhuaiyao@huaiyaos-mac-mini .memos % cat a
2023-11-24 07:59:42 | 这是一个测试1。
2023-11-23 17:53:15 | 这是一个测试2。

jinhuaiyao@huaiyaos-mac-mini .memos % n=10
cat a | while read line
do
time=`echo $line |awk -F'|' '{print $1}'`
content=`echo $line |awk -F'|' '{print $2}'`
time_n=`sqlite3 memos_prod.db "select strftime('%s','$time') - 28800;"`
echo "INSERT INTO memo VALUES($n,1,$time_n,$time_n,'NORMAL','$content','PRIVATE');"
n=$((n+1))
done>aaa.sql

jinhuaiyao@huaiyaos-mac-mini .memos % cat aaa.sql
INSERT INTO memo VALUES(10,1,1700783982,1700783982,'NORMAL',' 这是一个测试1。','PRIVATE');
INSERT INTO memo VALUES(11,1,1700733195,1700733195,'NORMAL',' 这是一个测试2。','PRIVATE');

jinhuaiyao@huaiyaos-mac-mini .memos % sqlite3 memos_prod.db < aaa.sql

重启 memos docker 后刷新网页就可以看到导入的数据了。

数据备份

Mac mini 增加一个 cronjob。

# backup memos
10 5,10,15,20 * * * /bin/bash /Users/jinhuaiyao/Library/CloudStorage/OneDrive-Personal/Config/Mac_Script/backup_memos.sh >/Users/jinhuaiyao/Log/backup_memos.txt 2>&1

jinhuaiyao@huaiyaos-mac-mini .memos % cat /Users/jinhuaiyao/Library/CloudStorage/OneDrive-Personal/Config/Mac_Script/backup_memos.sh
DATE=`date +%Y%m%d-%H%M%d`
/usr/bin/tar -cvzf "/Users/jinhuaiyao/Library/Mobile Documents/com~apple~CloudDocs/Me/backup_memos/memos_prod.db.${DATE}.tar.gz" /Users/jinhuaiyao/.memos/memos_prod.db

记录回顾

随机记录推送到 iOS,使用 Memos api + python + bark 实现。

有些记录还是需要时不时地去回顾,比如一些重要的事,一些生活和工作中的提醒。

Memos 提供 api 去获取数据,最不济还可以直接查询数据库,所以数据获取没有问题。

推送消息到 iOS

很久之前在少数派看到一篇讲 bark 这个消息推送服务的文章,当时还下载了 iOS app,不过那会儿不知道如何利用,这次就用上了。

在买的 VPS 上先安装 docker,再安装 bark 服务端,参考 https://bark.day.app/

root@hostdare-1:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.6 LTS
Release:	20.04
Codename:	focal

sudo apt update

sudo apt install apt-transport-https ca-certificates curl software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update

sudo apt install docker-ce

sudo systemctl status docker

docker run -dt --name bark -p 10086:8080 -v `pwd`/bark-data:/data finab/bark-server

测试一下:

curl -X "POST" "http://xx.xx.xx.xx:10086/3dVxxxxxxxxxxxeM" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{
  "body": "这是一个测试",
  "title": "Test Title",
  "badge": 1,
  "category": "myNotificationCategory",
  "icon": "https://www.usememos.com/logo-rounded.png",
  "group": "test"
}'

iPhone 上收到推送。

Memos api 获取数据

参考 https://github.com/usememos/memos/blob/main/docs/api/v1.md

curl "http://10.0.0.100:5230/api/v1/memo?creatorId=1&tag=important&limit=1&offset=0" \
   -H "Accept: application/json" \
   -H "Authorization: Bearer Your-Access-Tokens"

[
  {
    "id": 2369,
    "rowStatus": "NORMAL",
    "creatorId": 1,
    "createdTs": 1705132608,
    "updatedTs": 1705132628,
    "displayTs": 1705132608,
    "content": "#important CCCCCCCCCC",
    "visibility": "PRIVATE",
    "pinned": false,
    "creatorName": "huaiyao",
    "creatorUsername": "jinhuaiyao",
    "resourceList": [],
    "relationList": []
  }
]

curl "http://10.0.0.100:5230/api/v1/tag?creatorId=1" \
   -H "Accept: application/json" \
   -H "Authorization: Bearer Your-Access-Tokens"

[
  "important",
  "折腾",
  "提醒",
  "等等"
]
import json, datetime, subprocess, random

curl_command = """
curl -s "http://10.0.0.100:5230/api/v1/memo?creatorId=1&tag=important" \
   -H "Accept: application/json" \
   -H "Authorization: Bearer Your-Access-Tokens"
"""

result = subprocess.run(curl_command, shell=True, stdout=subprocess.PIPE)
json_data = result.stdout.decode('utf-8')
parsed_json = json.loads(json_data)

total_rows = len(parsed_json)

#print(total_rows)

random_number = random.randint(0, total_rows - 1)
content = parsed_json[random_number]['content'] if parsed_json else None
createdTs = parsed_json[random_number]['createdTs'] if parsed_json else None

dt_object = datetime.datetime.fromtimestamp(createdTs)
formatted_time = dt_object.strftime('%Y-%m-%d %H:%M:%S')

print(formatted_time + ' - ' + content)

combined_content = f"{formatted_time} - {content}"

curl_command_1 = f"""
curl -s -X "POST" "http://xx.xx.xx.xx:10086/3dVxxxxxxxxxxxeM" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{{
  "body": "{combined_content}",
  "title": "Memos records",
  "badge": 1,
  "category": "memos",
  "icon": "https://www.usememos.com/logo-rounded.png",
  "group": "test"
}}'
"""

subprocess.run(curl_command_1, shell=True, stdout=subprocess.PIPE)
jinhuaiyao@huaiyaos-mac-mini ~ % python3 test.py
2024-01-13 15:56:31 - #important 这是一个测试A。
jinhuaiyao@huaiyaos-mac-mini ~ % python3 test.py
2024-01-13 15:56:48 - #important 这是一个测试C。
jinhuaiyao@huaiyaos-mac-mini ~ % python3 test.py
2024-01-13 15:56:48 - #important 这是一个测试C。
jinhuaiyao@huaiyaos-mac-mini ~ % python3 test.py
2024-01-13 15:56:31 - #important 这是一个测试A。

Mac mini 上添加一个 cronjob 即可。