最近决定正式弃用 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()
效果图:
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"
用 Alfred 给它设置快捷键,愉快地使用。
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 即可。