[Obcsapi v2] 微信到 Obsidian 2.0
微信到 Obsidian 2.0,以前出过一个1.0版本。最近发现了一个 Obsidian 的 Memos 插件,跟 flomo 界面非常像,或者说一样。不过数据来源用的是 Obsidian 。我使用了多端同步插件 remotely save插件,选择腾讯云COS同步。我想,如果能够在微信测试号中,信息发送过去,然后存储到COS中。在 Obsidian 中一刷新就能看到了。
1.0 版本 微信使用 Remotely Save S3 兼容 发送到 Obsidian 1.0版本。不太好用
!!! 注意 新项目已发布 Obsidian 从本地到云端 obcsapi v3.0
下面文章属于 2.0 版本,新项目是 3.0 版本。请读者根据自身实际情况酌情选择!!!
2.0 说明
因此我写下了2.0版本。实现了以下功能:
- 支持图片和文字
- 图片下载到存储本地,而非链接(微信发送的图片,会给咱们的服务器返回图片URL)
- 对用户的判断,仅限特定用户存储笔记。(根据 OpenID 判断)
- 检索文字中含有 “todo” ,则生成勾选框。如
- [ ] 13:11 somethingtodo
- 正常生成
- 13:11 something
- 内容能在 Memos 中正常显示
- 支持收藏链接(部分支持),位置,语音(转文字存储)。(2.1 新增)
- 返回可点击的链接,可以在微信内置浏览器中使用 Memos (2.1 新增,需要kkbt/obweb支持,参考页面,支持查看三天,修改一天)
BUG:
- 不推荐批量传图片,推荐显示已保存后依次上传。
- 不推荐一秒内上传多个文件,图片命名精确到1S。1S内多图片会覆盖。
- 不要使用微信自带的表情符号,请使用输入法表情。
- 如果微信输入框换行或分段,只会在这一条消息最开始有
- 13:11
。也就是说,第二行、第二段不会在 Memos 中显示。
说明: 不推荐批量传图片,程序对图片处理非常粗糙。。例如1M带宽服务器,连续传五个图片时。造成费时间会超过五秒,触发微信重传机制。这个机制带来的问题有很多。比如会多上传几份重复的文件,并且在微信测试号显示服务故障。(其实解决方案有很多,如使用任务队列或者是异步的方式。先返回success,另外开线程上传文件。留着以后有机会解决吧)。
程序
开源地址: https://gitee.com/kkbt/obsidian-csapi
微信发送到 Obsidian 是该项目的最初的功能,后进一步拓展出更多功能。
依赖
- werobot
- cos-python-sdk-v5
程序思路
程序思路运行一个测试号服务器,使用werobot。根据message的公共属性source,即微信用户的唯一openid,判断用户。是自己的ID,如果是文字消息,判断消息字符串是否包含todo,包含则在消息字符串增加勾选框markdown语法,否则使用无序列表。然后根据当日时间,判断当日日志是否存在。若存在,下载本日日志并添加处理好的字符串,然后上传。不存在则直接上传处理好的字符串。
如果是图片消息,从消息中获取图片url并下载。下载完成之后上传至COS中,图片命名为当前的时间精确到秒。图片名包装成md图片链接。处理好的字符串按照文字消息的处理方法保存。
注意:以下代码仅为参考,最新代码请带 https://gitee.com/kkbt/obsidian-csapi 获取。
主文件 wechat.py 和 get_add.py 需要放到同一级目录下。运行 python wechat.py
# -*- coding=utf-8
# README
# 需要安装的依赖
# werobot cos-python-sdk-v5
# 可用 Alist 或其他可挂载 S3 的开源网盘 实现web编辑.md
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import werobot
import time
import get_add as cosga
# 相关信息
token = "token" # 自定义
APP_ID = "wxxxxxxxxxxxxxxxxx" # 微信公众号测试号APP_ID
APP_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 微信公众号测试号APP_SECRET
# werobot 配置
robot = werobot.WeRoBot(token=token)
robot.config["APP_ID"] = APP_ID
robot.config["APP_SECRET"] = APP_SECRET
rob_client = robot.client
rob_client.delete_menu()
#
# rob_client.create_menu({
# "button":[{
# "type": "click",
# "name": "今日",
# "key": "info"
# }]
# })
# message.source 为 OpenID 。获取->测试号二维码->用户列表(最多100个)->微信号
@robot.key_click("info")
def menu_click(message):
if (message.source != "o6_bmjrPTlm6_2sgVt7hMZOPfL2M"):
return '你不是恐咖兵糖'
return cosga.get_daily_today()
# 关注回复
@robot.subscribe
def subscribe(message):
return "这是恐咖兵糖的测试公众号"
# 文字消息回复 put_object append_object
@robot.text
def text_reply(message):
if (message.source != "o6_bmjrPTlm6_2sgVt7hMZOPfL2M"):
return '你不是恐咖兵糖'
str = cosga.add_memos_in_daily(message.content) # ETag
return "📩 已保存"
# 图片消息
@robot.image
def image_reply(message):
if (message.source != "o6_bmjrPTlm6_2sgVt7hMZOPfL2M"):
return '你不是恐咖兵糖'
now_key = cosga.save_asset(message.img)
str = cosga.add_memos_in_daily("") # ETag
return "📩 已保存"
@robot.error_page
def make_error_page(url):
return "404"
@robot.handler
def error_message(message):
return "不支持的消息类型"
robot.config["HOST"] = "0.0.0.0"
robot.config["PORT"] = "8008"
robot.run()
get_add.py
# -*- coding=utf-8
# 需要安装的依赖
# werobot cos-python-sdk-v5
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import time
import requests
# 相关信息
secret_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 腾讯云 secret_i
secret_key = "xxxxxxxxxxxxxxxxxxxxxxxxx" # 腾讯云 secret_key
region = "ap-nanjing" # 腾讯云 COS
cos_token = None # 腾讯云 COS token
scheme = "https" # 腾讯云 COS 访问模式
bucket = "test-0123456789" # 腾讯云 Bucket
config = CosConfig(
Region=region,
SecretId=secret_id,
SecretKey=secret_key,
Token=cos_token,
Scheme=scheme,
)
client = CosS3Client(config)
# name = time.strftime("%Y%m%d%H%M%S", time.localtime())
def add_memos_in_daily(text):
# 生成ObjectKey => 日志/2022-08-08.md
daily_note_dir_path = "日志/"
today_daily_file_key = daily_note_dir_path + time.strftime("%Y-%m-%d", time.localtime()) + ".md"
todo = "todo"
if todo in text:
message = time.strftime("\n- [ ] %H:%M ", time.localtime()) + text
else:
message = time.strftime("\n- %H:%M ", time.localtime()) + text
response3 = client.object_exists(
Bucket=bucket,
Key=today_daily_file_key
)
# 判断本日日志是否存在
if(response3==True):
# 存在 读取文件
response2 = client.get_object(
Bucket=bucket,
Key=today_daily_file_key
)
str1=response2['Body'].get_raw_stream().read().decode('utf-8')
btyes = bytes(str1+ message, encoding="utf8")
else:
btyes = bytes(message, encoding="utf8")
#btyes = bytes(str1+"- 20:01 somgthing", encoding="utf8")
# name = time.strftime("%Y%m%d%H%M%S", time.localtime())
response_sum = client.put_object(
Bucket=bucket,
Body=btyes,
Key=today_daily_file_key
)
return response_sum["ETag"]
def save_asset(file):
# 生成ObjectKey => 日志/附件/202208/20220808131104.jpg
file = requests.get(file).content # wechat file is url 为了防止过期,下载下来。
# file = bytes("", encoding = "utf8") # 直接使用腾讯微信链接显示图片
daily_asset_dir_path = "日志/附件/" + time.strftime("%Y%m",time.localtime()) + "/"
today_daily_asset_file_key = daily_asset_dir_path + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".jpg"
now_key = today_daily_asset_file_key
response_file = client.put_object(
Bucket=bucket,
Body=file,
Key=now_key
)
print(response_file["ETag"])
return now_key
# 已弃用 原因: 超过一定长度后微信显示服务错误
def get_daily_today():
# 生成ObjectKey => 日志/2022-08-08.md
daily_note_dir_path = "日志/"
today_daily_file_key = daily_note_dir_path + time.strftime("%Y-%m-%d", time.localtime()) + ".md"
response3 = client.object_exists(
Bucket=bucket,
Key=today_daily_file_key
)
if(response3==True):
# 存在 读取文件
response2 = client.get_object(
Bucket=bucket,
Key=today_daily_file_key
)
str1=response2['Body'].get_raw_stream().read().decode('utf-8')
return str1
else:
return '今日无日志'
效果图
微信测试号建议直接放在桌面




以上效果图为早期版本效果图,新的版本已经返回已保存,和可点击的链接文字。即可在微信内置浏览器使用 Memeos
希望以后会有优秀的类似转发服务提供商,而且按量付费不太贵那种。能用很简单,好用很困难。Knuth 大佬(发明 KMP 算法的那位),说二分
Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky…
这软件也是如此,思路很简单,细节是魔鬼