Rum 的底层和 app 的代码仓库都已经开源了。前不久得知有工程师随手实现了 rum bot,可以直接调用 api 往本地已经启动的 rum 上推送内容。内容可以是纯文本,纯图片或文本与图片的混合。 我非常兴奋,有幸拿到了两份不同的代码实现;其中有位工程师本来是用 rust 实现的,为了让我能看懂,特意帮我重写了一份 python 实现,真是感谢。 基础:RumPost 类我用 Python 把建立连接(session)、调用 api 推送(post)的基础逻辑封装为一个简单的 RumPost 类。 """rum bot""" import base64 import json import uuid from datetime import datetime from typing import List, Dict import requests
class RumPost: """调用 api 往本地已经启动的 Rum 发布内容"""
def __init__(self,PORT:int,HOST:str,CACERT:str): """ :param PORT: int,本地已经启动的 Rum 的端口号 :param HOST: str,本地已经启动的 Rum 的 host :param CACERT: str,本地 Rum 的 server.crt 文件的绝对路径 """ self.BASEURL = f'https://{HOST}:{PORT}' self.session = requests.Session() self.session.verify = CACERT self.session.headers.update({ 'USER-AGENT': 'asiagirls-py-bot', 'Content-Type': 'application/json', })
def get_nodeinfo(self): url = f'{self.BASEURL}/api/v1/node' resp = self.session.get(url) return resp.json()
def send_post(self, group_id: str, msg: str, images: List[str]) -> Dict[str, str]: """ :param group_id: str :param msg: message content :param images: list of str, list of image file path or url :return: dict, return rest api response """ url = f'{self.BASEURL}/api/v1/group/content' payload = { "type": "Add", "object": { "type": "Note", "content": msg, "name": "", }, "target": { "id": group_id, "type": "Group" } }
images = images or [] for x in images: with open(x, 'rb') as f: data = f.read() if 'image' not in payload['object']: payload['object']['image'] = [] payload['object']['image'].append({ "mediaType": x.split(".")[-1], "content": base64.b64encode(data).decode('utf-8'), "name": f'{uuid.uuid4()}-{datetime.now().isoformat()}', }) resp = self.session.post(url, json=payload) return resp.json()
这之后,基于该类生成实例,建立连接并推送内容,就变得非常简单: b = RumPost(PORT,HOST,CACERT) b.send_post(group_id, msg, images)
接下来可以基于此,实现更多丰富功能、满足不同场景了。 场景一,脚本自动执行。不用设定闹钟手动执行;到了指定的时间,电脑自动运行代码,无需人工操作或记忆。 说起来很难,但实现起来特别容易。在 Windows 操作系统中,直接用“任务计划程序”这个功能,设定参数时选择启动 Python 程序并运行事先编写好的 Python 脚本即可。这是操作系统自带的现成工具,特别强大。 它还能支持更复杂的场合。比如,无需电脑 24H 开机,到点自动开机,执行完任务再自动关机。 场景二、内容分类推送。希望对内容分类,不同的内容推送到不同的群组。同时最好标记下哪些内容已经推送过,哪些还没有;当内容不足时,可以提醒我去补充内容。 不管是图片、文本还是图片和文本的集合,都可视为 bot 的数据源 source,于是自定义本地存储的数据格式,并从中随机抽取内容推送。 def common(b,picdirs,textfile,groups=GROUPS): """通用的图、文随机选择工具,推送到指定组"""
pics = [] for idir in picdirs: ipics = Dir(idir).search_files_by_types((".png",".jpg",".jpeg")) pics.extend(ipics)
texts = JsonFile(textfile).read_file_by_json()
for g in groups: fresh = [i for i in texts if texts[i] == 0] if len(fresh) == 0: print("该新增文案了",textfile) break itext = random.choice(fresh) try: ipic = [random.choice(pics)] except: ipic = []
b.send_post(groups[g], itext, ipic) print(g,itext) texts[itext] = 1 sleep(1)
JsonFile(textfile).write_file_by_json(texts)
注:JsonFile 类是我的一个常用的自定义类,封装了下 json 文件的读与写。你也可以直接改写,比如调用 json 的相关方法。Dir 类的 search_files_by_types() 也如此,是我简单封装的一个常用方法。 比如我收集了一些早安问候、笑话等内容,于是它们可以被分别封装为: def morning(b): """早安问候文本和图片""" picdirs = [r'D:\rum_bot_source\pixabay_morning'] textfile = r"D:\MY-OBSIDIAN-DATA\my_auto_task\rum_bot_source\text_for_morning.json" groups = { "测试bot":"fcbd859d-aa16-4dba-8156-69afb03b3eb3", "刘娟娟的朋友圈":"4e784292-6a65-471e-9f80-e91202e3358c", } common(b,picdirs,textfile,groups)
def joke(b): """笑话文本和图片""" picdirs = [r'D:\rum_bot_source\joke'] textfile = r"D:\MY-OBSIDIAN-DATA\my_auto_task\rum_bot_source\text_for_joke.json" groups = { "测试bot":"fcbd859d-aa16-4dba-8156-69afb03b3eb3", "刘娟娟的朋友圈":"4e784292-6a65-471e-9f80-e91202e3358c", } common(b,picdirs,textfile,groups)
往后,rum 的种子网络将越来越多,不同的种子网络具有不同的主题或氛围。这样的内容分组推送,就很有必要。 场景三、分时选内容。希望做到根据当前几点钟,“智能”判断该推送什么内容。说起来是“智能”,其实代码逻辑非常简单,python 的新手也能轻松掌握。 from datetime import datetime
h = datetime.now().hour
if h>=6 and h<=9: morning(b) elif h>=18 and h<=21: joke(b)
可拓展空间也非常多,比如存一份节假日表格,提前准备好适合不同节日的内容,然后执行时根据日期来判断是否触发特别的即日祝福内容。 零基础,从哪里开始那么,一个能全天候自动执行,具备一点智能的 rum bot 这就封装好、并可以运行了。随后你可以专注于挑选内容和文本,在本地构建和充实内容 source,剩下的就交给 rum bot 去自动发布。 这个 bot 确实简单,自学 Python 的新手也完全可以掌握:能读懂代码,会修订一些参数,更进一步可以调整逻辑,定制更符合自己需要的 rum bot。 也许你暂时看不懂 rum 已经开源的 Go 语言代码,但 rum bot 确实是一个低门槛的参与方式。如果你感兴趣但零基础,不妨来 xue.cn 上通过《自学是门手艺》或《进入编程世界的第一课》先掌握一点 Python 吧。 如果你已经掌握了一点 Python,那就直接试试看吧~
|