前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mastodon 同步到 Memos

Mastodon 同步到 Memos

作者头像
eallion
发布2024-03-10 09:22:43
1310
发布2024-03-10 09:22:43
举报
文章被收录于专栏:大大的小蜗牛大大的小蜗牛

最新脚本:https://gist.github.com/eallion/bf8861eb3292c2351c1067fba3198c26

Update:添加宝塔面板的示例。

TL;DR

直接跳转到本页 脚本内容 查看脚本代码。

前言

不知道是我运气好还是不好,在我准备把 Memos 当成主力工具加入到我的工作流中的时候,遇上了 v0.19.0 的版本更新,这次版本更新带来了一系列大坑。除了 Memos 新版本的鲁棒性备受质疑,甚至连搭载它的服务器本身也被影响,我在 64G 内存的物理机上都跑不动它。就像网友所说,Memos 只像是一个练手的项目。果断弃之。Google Keep、Obsidian 这些工具哪里不好了吗?不把所有事务约束在一个工具里确实是麻烦了一点,但是 All in one 基本上也等于是 All in boom。 现在我对 Memos 的定位是用来备份我的 Mastodon(方式之一)。

我一直喜欢 Webhook 这种主动式 Push 的方案,比 RSS、Cron 计划任务这些被动式 Pull 的方案简洁低碳环保,更具有即时性。主要是掌握主动的感觉让人觉得很爽。

下面开始介绍一下 Mastodon 利用 Webhook 同步嘟文到 Memos 的方法。我用的是 Shell Script 脚本,是一个很简单的脚本,只作了一些常识性的逻辑判断,可能不完美。用 Node.js、Python 等都可以实现。

已测试版本

Mastodon 需要自己的实例,或者具有管理员权限能创建 Webhook 的账号才能使用此方法。

安装工具

请在服务器上安装工具,若有报错,请根据错误日志安装其他对应工具

  • sudo apt install jq
  • sudo apt install lynx

Webhook 工具

Mastodon 前往 https://{INSTANCE}/admin/webhooks 创建一个 Webhook。 事件可以只选 status:created,回复和转嘟也都算此事件喔。 目的地 URL 就填自己部署的 Webhook 的链接,如:https://webhook.example.com/hooks/mastodon-sync-to-memos 宝塔的是:https://webhook.mybtserver.com:8888/hook?access_key=ACCESSKEY Mastodon 的 Webhook 目的地 URL 建议绑定域名,不然 Sidekiq 可能处理不了。

/assets/images/posts/2024/03/mastodon-webhook.png
/assets/images/posts/2024/03/mastodon-webhook.png

脚本内容

把下方的脚本内容保存到服务器上的一个 .sh 文件中,如当前用户的 Home 目录(~)的 ~/mastodon_sync_to_memos.sh 文件中,并配置以下内容,请注意替换:

  • MEMOS_HOST=""
  • MEMOS_ACCESS_TOKEN=""
  • MEMOS_VISIBILITY=""
  • MASTODON_INSTANCE=""
  • MASTODON_ID=""
  • SKIP_MASTODON_REPLY=
  • SKIP_MASTODON_REBLOG=
  • HOME_DIR=~
  • FILE_PATH=$HOME_DIR/.mastodon_memos_id.json

查找 Mastodon ID: https://INSTANCE/api/v1/accounts/lookup?acct=USERNAME

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

#!/bin/bash # 已测试版本: # Memos: v0.18.2 # Mastodon: v4.2.8 # ====================================================== # 配置开始 # Memos Host MEMOS_HOST="" # Memos Access Token MEMOS_ACCESS_TOKEN="" # 发布 Memos 的可见性 ('PUBLIC', 'PROTECTED', 'PRIVATE') 三选一 MEMOS_VISIBILITY=PUBLIC # Mastodon Instance MASTODON_INSTANCE="" # Mastodon ID, Find ID: https://INSTANCE/api/v1/accounts/lookup?acct=USERNAME MASTODON_ID="" # 跳过回复和转嘟 SKIP_MASTODON_REPLY=true SKIP_MASTODON_REBLOG=true # 获取当前用户的 Home 目录路径及保存 ID 的文件,保持默认,不用更改 HOME_DIR=~ FILE_PATH=$HOME_DIR/.mastodon_memos_id.json # 配置结束 # ====================================================== # 以下内容不用更改 # 检查 ID 文件是否存在 if [ ! -f "$FILE_PATH" ]; then # 如果文件不存在,则创建文件并写入 JSON 数据 echo ' { "latest_memos_id": "0", "latest_mastodon_id": "0", "bind": [] } ' > "$FILE_PATH" echo "Data file created: $FILE_PATH" else # 如果文件存在,则跳过并进行后续步骤 echo "Local data exist, skipping..." fi # 拼接 API 和 Token if [[ "$MEMOS_HOST" != */ ]]; then MEMOS_HOST="$MEMOS_HOST/" fi MEMOS_API_HOST="${MEMOS_HOST}api/v1/memo" AUTHORIZATION="Bearer ${MEMOS_ACCESS_TOKEN}" # Memos 获取最新的 Memos ID MEMOS_URL="${MEMOS_API_HOST}?creatorId=101&rowStatus=NORMAL&limit=1" LATEST_MEMOS_ID=$(curl --connect-timeout 60 -s $MEMOS_URL | jq -r '.[0].id') # Mastodon 的 API if [[ "$MASTODON_INSTANCE" != */ ]]; then MASTODON_INSTANCE="$MASTODON_INSTANCE/" fi CONTENT_URL="${MASTODON_INSTANCE}api/v1/accounts/${MASTODON_ID}/statuses?limit=1&exclude_replies=${SKIP_MASTODON_REPLY}&exclude_reblogs=${SKIP_MASTODON_REBLOG}" # Mastodon 最新 Status 的 ID LATEST_MASTODON_ID=$(curl --connect-timeout 60 -s $CONTENT_URL | jq -r '.[0].id') # 定义 LOCAL_MEMOS_ID 变量 LOCAL_MEMOS_ID=$(cat "$FILE_PATH" | jq -r '.latest_memos_id') LOCAL_MASTODON_ID=$(cat "$FILE_PATH" | jq -r '.latest_mastodon_id') # Webhook 触发时,判断 Mastodon 最新 ID 是否为暂存 ID,防止重复同步 if [ "$LATEST_MASTODON_ID" == "$LOCAL_MASTODON_ID" ]; then echo "Mastodon no updated, skipping..." echo "Skipped: $(TZ=UTC-8 date +"%Y-%m-%d"" ""%T")" echo "=============================" exit 0 fi CONTENT=$(curl --connect-timeout 60 -s $CONTENT_URL | jq -r '.[0]') MEDIA=$(echo $CONTENT | jq -r '.media_attachments') # 判断 Media 的内容 if [ "$MEDIA" != "null" ]; then MEDIAS=$(echo $CONTENT | jq -r '.media_attachments[] | select(.type=="image") | .url') # 拼接图片 images="" for url in $MEDIAS; do images="$images![image]($url)\n" done TEXT=$(echo "$CONTENT" | jq -r '.content' | lynx -dump -stdin -nonumbers -nolist | tr -d '\n' | sed '/^$/N;s/\n\n/\n/g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed -E 's/ {2,}/ /g') TEXT="$TEXT\n$images" else # 普通内容 TEXT=$(echo "$CONTENT" | jq -r '.content' | lynx -dump -stdin -nonumbers -nolist | tr -d '\n' | sed '/^$/N;s/\n\n/\n/g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed -E 's/ {2,}/ /g') fi # 判断内容是否为空 if [ -z "$TEXT" ] || [ "$TEXT" == "\\n" ]; then echo "Content is empty, skipping..." echo "Skipped: $(TZ=UTC-8 date +"%Y-%m-%d"" ""%T")" echo "=============================" exit 0 fi # 双引号转义 TEXT=$(echo "$TEXT" | sed 's/"/\\"/g') # Webhook 触发时,判断 Memos 最新 ID 是否为暂存 ID # 当 Memos 单方面有更新后,验证 Mastodon 和 Memos 的 ID 绑定关系(Todo) #if [ "$LATEST_MEMOS_ID" == "$LOCAL_MEMOS_ID" ]; then # echo "Memos no updated, skipping..." # echo "Skipped: $(TZ=UTC-8 date +"%Y-%m-%d"" ""%T")" # echo "=============================" # exit 0 #fi # 对比 Matodon 和 Memos 的 Content 内容的 MD5 值(不一定精确) # 后期尝试引入 GPT 对比内容 CONTENT_MEMOS=$(curl --connect-timeout 60 -s $MEMOS_URL | jq '.[0].content') CONTENT_MASTODON=$TEXT # 获取最新 Memos 的 MD5 LATEST_MEMOS_MD5=$(echo $CONTENT_MEMOS | tr -d '"' | md5sum | cut -d' ' -f1) # 获取最新 Mastodon 的 MD5 LATEST_TEXT_MD5=$(echo $TEXT | tr -d '"' | md5sum | cut -d' ' -f1) # 通过 MD5 判断内容是否重复 if [ "$LATEST_TEXT_MD5" == "$LATEST_MEMOS_MD5" ]; then echo "Content is duplicate, skipping..." echo "Skipped: $(TZ=UTC-8 date +"%Y-%m-%d"" ""%T")" echo "=============================" exit 0 fi # 替换 NeoDB 的评分 Emoji TEXT=$(echo "$TEXT" | sed "s/:star_empty:/🌑/g; s/:star_half:/🌗/g; s/:star_solid:/🌕/g") # 去掉最末尾的空行 TEXT=$(echo "$TEXT" | sed 's/\\n$//') # 发布 Memos 并获取返回的 JSON 数据 RESPONSE=$(curl -s -X POST \ -H "Accept: application/json" \ -H "Authorization: $AUTHORIZATION" \ -d "{ \"content\": \"$TEXT\", \"visibility\": \"$MEMOS_VISIBILITY\"}" \ $MEMOS_API_HOST) # 从返回的 JSON 数据中提取 Memos 的 id 值 NEW_MEMOS_ID=$(echo "$RESPONSE" | jq -r '.id') # 更新 JSON 文件中的 latest_memos_id 的值 jq ".latest_memos_id = \"$NEW_MEMOS_ID\"" "$FILE_PATH" > "${FILE_PATH}.tmp" && mv "${FILE_PATH}.tmp" "$FILE_PATH" # 更新 JSON 文件中的 latest_mastodon_id 的值 jq ".latest_mastodon_id = \"$LATEST_MASTODON_ID\"" "$FILE_PATH" > "${FILE_PATH}.tmp" && mv "${FILE_PATH}.tmp" "$FILE_PATH" # 更新 Mastodon 和 Memos 的 ID 的绑定关系,并确保 "bind" 中的数组保留唯一键,键也只有唯一值 jq ".bind += [{\"$LATEST_MASTODON_ID\": \"$NEW_MEMOS_ID\"}] | .bind = (.bind | unique)" "$FILE_PATH" > "${FILE_PATH}.tmp" && mv "${FILE_PATH}.tmp" "$FILE_PATH" echo "Sync Mastodon to Memos Successful!" echo "Done: $(TZ=UTC-8 date +"%Y-%m-%d"" ""%T")" echo "============================="

宝塔面板

宝塔面板如果用 Webhook 插件,可以直接把上面的脚本内容复制到 Webhook 插件的脚本中。不用另外在服务器中手动创建 .sh 文件。

/assets/images/posts/2024/03/bt-webhook.png
/assets/images/posts/2024/03/bt-webhook.png

JSON 数据文件内容

初次运行脚本,它会在当前用户的 Home 目录 ~ 新建一个文件 ~/.mastodon_memos_id.json 并初始化,后续此文件会记录 Mastodon ID 和 Memos ID 的绑定关系。如果不想在 Home 目录创建,就需要修改 HOME_DIR=FILE_PATH= 这两个参数。

1 2 3 4 5

{ "latest_memos_id": "", "latest_mastodon_id": "", "bind": [] }

生产环境产生数据后,示例:

1 2 3 4 5 6 7 8 9 10 11 12

{ "latest_memos_id": "6231", "latest_mastodon_id": "112061852482921394", "bind": [ { "112059053750743781": "6230" }, { "112061852482921394": "6231" } ] }

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-03-092,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TL;DR
  • 前言
  • 已测试版本
  • 安装工具
  • Webhook 工具
  • 脚本内容
    • 宝塔面板
    • JSON 数据文件内容
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档