import json import os from botoy import Botoy with open("botoy.json") as f: config = json.load(f) qq = config["qq"] os.environ["BOTQQ"] = str(qq) bot = Botoy(qq=qq, use_plugins=True) if __name__ == "__main__": bot.run()
def __init__(self, client_id: str, config: Dict[str, Any], channel): super().__init__(client_id, config) self.client_config = config[self.client_id] self.uin = self.client_config['qq'] self.host = self.client_config.get('host', 'http://127.0.0.1') self.port = self.client_config.get('port', 8888) IOTConfig.configs = self.client_config self.bot = Botoy(qq=self.uin, host=self.host, port=self.port) self.action = Action(qq=self.uin, host=self.host, port=self.port) IOTFactory.bot = self.bot IOTFactory.action = self.action self.channel = channel ChatMgr.slave_channel = channel self.iot_msg = IOTMsgProcessor(self.uin) @self.bot.when_connected def on_ws_connected(): self.logger.info("Connected to OPQBot!") @self.bot.when_disconnected def on_ws_disconnected(): self.logger.info("Disconnected from OPQBot!") @self.bot.on_friend_msg def on_friend_msg(ctx: FriendMsg): self.logger.debug(ctx) if int(ctx.FromUin) == int(self.uin) and not IOTConfig.configs.get( 'receive_self_msg', True): self.logger.info( "Received self message and flag set. Cancel delivering...") return remark_name = self.get_friend_remark(ctx.FromUin) if not remark_name: info = self.get_stranger_info(ctx.FromUin) if info: remark_name = info.get('nickname', '') else: remark_name = str(ctx.FromUin) if ctx.MsgType == 'TempSessionMsg': # Temporary chat chat_uid = f'private_{ctx.FromUin}_{ctx.TempUin}' elif ctx.MsgType == 'PhoneMsg': chat_uid = f'phone_{ctx.FromUin}' else: chat_uid = f'friend_{ctx.FromUin}' chat = ChatMgr.build_efb_chat_as_private( EFBPrivateChat( uid=chat_uid, name=remark_name, )) author = chat.other # Splitting messages messages: List[Message] = [] func = getattr(self.iot_msg, f'iot_{ctx.MsgType}_friend') messages.extend(func(ctx, chat)) # Sending messages one by one message_id = ctx.MsgSeq for idx, val in enumerate(messages): if not isinstance(val, Message): continue val.uid = f"friend_{ctx.FromUin}_{message_id}_{idx}" val.chat = chat val.author = author val.deliver_to = coordinator.master coordinator.send_message(val) if val.file: val.file.close() @self.bot.on_group_msg def on_group_msg(ctx: GroupMsg): # OPQbot has no indicator for anonymous user, so we have to test the uin nickname = ctx.FromNickName if int(ctx.FromUserId) == int( self.uin) and not IOTConfig.configs.get( 'receive_self_msg', True): self.logger.info( "Received self message and flag set. Cancel delivering...") return remark_name = self.get_friend_remark(ctx.FromUserId) if not remark_name: info = self.get_stranger_info(ctx.FromUserId) if info: remark_name = info.get('nickname', '') chat = ChatMgr.build_efb_chat_as_group( EFBGroupChat(uid=f"group_{ctx.FromGroupId}", name=ctx.FromGroupName)) author = ChatMgr.build_efb_chat_as_member( chat, EFBGroupMember(name=nickname, alias=remark_name, uid=str(ctx.FromUserId))) # Splitting messages messages: List[Message] = [] func = getattr(self.iot_msg, f'iot_{ctx.MsgType}_group') messages.extend(func(ctx, chat)) # Sending messages one by one message_id = ctx.MsgSeq for idx, val in enumerate(messages): if not isinstance(val, Message): continue val.uid = f"group_{ctx.FromGroupId}_{message_id}_{idx}" val.chat = chat val.author = author val.deliver_to = coordinator.master coordinator.send_message(val) if val.file: val.file.close() @self.bot.on_event def on_event(ctx: EventMsg): pass # fixme
from botoy import Action, Botoy, GroupMsg from botoy.collection import MsgTypes from botoy.decorators import ignore_botself, these_msgtypes from botoy.session import SessionController from botoy.sugar import Text host = None qq = None assert all([host, qq]) bot = Botoy(qq=qq, host=host, log=False) action = Action(qq, host=host) # 功能1, 查询 # 指令查询+关键字 def search(word): return f'已查询{word}' # 新建一个会话控制器,每个功能对应一个控制器(我是避免用这样听起来很高级的名词的,但这里我也不知道用什么描述比较好) # 这里的参数表示生成的session无任何操作该时长后被自动关闭 sc = SessionController(1 * 60) @bot.on_group_msg @ignore_botself @these_msgtypes(MsgTypes.TextMsg) def _(ctx: GroupMsg): if ctx.Content.startswith('查询'): # 取需要查询的内容,如果发送的消息直接包含了需要查询的关键字 # 则直接返回查询结果即可
from botoy import decorators as deco from botoy import Botoy, GroupMsg from botoy import Action from modules import bot_config action = Action(qq=bot_config.bot_qq, host=bot_config.host, port=bot_config.port) bot = Botoy(qq=bot_config.bot_qq, host=bot_config.host, port=bot_config.port, log=False, use_plugins=bot_config.use_plugins) @bot.on_group_msg @deco.from_these_users(364988395) @deco.queued_up(name="manage_plugin") def manage_plugin(ctx: GroupMsg): c = ctx.Content if c == "插件管理": action.sendGroupText( ctx.FromGroupId, ("插件列表 => 发送启用插件列表\n" "已停用插件 => 发送停用插件列表\n" "刷新所有插件 => 刷新所有插件,包括新建文件\n" "重载插件+插件名 => 重载指定插件\n" "停用插件+插件名 => 停用指定插件\n" "启用插件+插件名 => 启用指定插件\n"), )
class iot(BaseClient): client_name: str = "IOTbot Client" client_id: str = "iot" client_config: Dict[str, Any] bot: Botoy action: Action channel: SlaveChannel logger: logging.Logger = logging.getLogger(__name__) info_list = TTLCache(maxsize=2, ttl=600) info_dict = TTLCache(maxsize=2, ttl=600) group_member_list = TTLCache(maxsize=20, ttl=3600) stranger_cache = TTLCache(maxsize=100, ttl=3600) sio: socketio.Client = None event: threading.Event = None def __init__(self, client_id: str, config: Dict[str, Any], channel): super().__init__(client_id, config) self.client_config = config[self.client_id] self.uin = self.client_config['qq'] self.host = self.client_config.get('host', 'http://127.0.0.1') self.port = self.client_config.get('port', 8888) IOTConfig.configs = self.client_config self.bot = Botoy(qq=self.uin, host=self.host, port=self.port) self.action = Action(qq=self.uin, host=self.host, port=self.port) IOTFactory.bot = self.bot IOTFactory.action = self.action self.channel = channel ChatMgr.slave_channel = channel self.iot_msg = IOTMsgProcessor(self.uin) @self.bot.when_connected def on_ws_connected(): self.logger.info("Connected to OPQBot!") @self.bot.when_disconnected def on_ws_disconnected(): self.logger.info("Disconnected from OPQBot!") @self.bot.on_friend_msg def on_friend_msg(ctx: FriendMsg): self.logger.debug(ctx) if int(ctx.FromUin) == int(self.uin) and not IOTConfig.configs.get( 'receive_self_msg', True): self.logger.info( "Received self message and flag set. Cancel delivering...") return remark_name = self.get_friend_remark(ctx.FromUin) if not remark_name: info = self.get_stranger_info(ctx.FromUin) if info: remark_name = info.get('nickname', '') else: remark_name = str(ctx.FromUin) if ctx.MsgType == 'TempSessionMsg': # Temporary chat chat_uid = f'private_{ctx.FromUin}_{ctx.TempUin}' elif ctx.MsgType == 'PhoneMsg': chat_uid = f'phone_{ctx.FromUin}' else: chat_uid = f'friend_{ctx.FromUin}' chat = ChatMgr.build_efb_chat_as_private( EFBPrivateChat( uid=chat_uid, name=remark_name, )) author = chat.other # Splitting messages messages: List[Message] = [] func = getattr(self.iot_msg, f'iot_{ctx.MsgType}_friend') messages.extend(func(ctx, chat)) # Sending messages one by one message_id = ctx.MsgSeq for idx, val in enumerate(messages): if not isinstance(val, Message): continue val.uid = f"friend_{ctx.FromUin}_{message_id}_{idx}" val.chat = chat val.author = author val.deliver_to = coordinator.master coordinator.send_message(val) if val.file: val.file.close() @self.bot.on_group_msg def on_group_msg(ctx: GroupMsg): # OPQbot has no indicator for anonymous user, so we have to test the uin nickname = ctx.FromNickName if int(ctx.FromUserId) == int( self.uin) and not IOTConfig.configs.get( 'receive_self_msg', True): self.logger.info( "Received self message and flag set. Cancel delivering...") return remark_name = self.get_friend_remark(ctx.FromUserId) if not remark_name: info = self.get_stranger_info(ctx.FromUserId) if info: remark_name = info.get('nickname', '') chat = ChatMgr.build_efb_chat_as_group( EFBGroupChat(uid=f"group_{ctx.FromGroupId}", name=ctx.FromGroupName)) author = ChatMgr.build_efb_chat_as_member( chat, EFBGroupMember(name=nickname, alias=remark_name, uid=str(ctx.FromUserId))) # Splitting messages messages: List[Message] = [] func = getattr(self.iot_msg, f'iot_{ctx.MsgType}_group') messages.extend(func(ctx, chat)) # Sending messages one by one message_id = ctx.MsgSeq for idx, val in enumerate(messages): if not isinstance(val, Message): continue val.uid = f"group_{ctx.FromGroupId}_{message_id}_{idx}" val.chat = chat val.author = author val.deliver_to = coordinator.master coordinator.send_message(val) if val.file: val.file.close() @self.bot.on_event def on_event(ctx: EventMsg): pass # fixme def login(self): pass def logout(self): self.action.logout() def relogin(self): pass def send_message(self, msg: 'Message') -> 'Message': chat_info = msg.chat.uid.split('_') chat_type = chat_info[0] chat_uid = chat_info[1] if msg.edit: pass # todo Revoke message & resend if msg.type in [MsgType.Text, MsgType.Link]: if isinstance(msg.target, Message): # Reply to message max_length = 50 tgt_alias = iot_at_user(msg.target.author.uid) tgt_text = process_quote_text(msg.target.text, max_length) msg.text = "%s%s\n\n%s" % (tgt_alias, tgt_text, msg.text) self.iot_send_text_message(chat_type, chat_uid, msg.text) msg.uid = str(uuid.uuid4()) self.logger.debug('[%s] Sent as a text message. %s', msg.uid, msg.text) elif msg.type in (MsgType.Image, MsgType.Sticker, MsgType.Animation): self.logger.info("[%s] Image/Sticker/Animation %s", msg.uid, msg.type) self.iot_send_image_message(chat_type, chat_uid, msg.file, msg.text) msg.uid = str(uuid.uuid4()) elif msg.type is MsgType.Voice: self.logger.info(f"[{msg.uid}] Voice.") if not VOICE_SUPPORTED: self.iot_send_text_message(chat_type, chat_uid, "[语音消息]") else: pydub.AudioSegment.from_file(msg.file).export( msg.file, format='s16le', parameters=["-ac", "1", "-ar", "24000"]) output_file = tempfile.NamedTemporaryFile() if not Silkv3.encode(msg.file.name, output_file.name): self.iot_send_text_message(chat_type, chat_uid, "[语音消息]") else: self.iot_send_voice_message(chat_type, chat_uid, output_file) if msg.text: self.iot_send_text_message(chat_type, chat_uid, msg.text) msg.uid = str(uuid.uuid4()) return msg def send_status(self, status: 'Status'): raise NotImplementedError def receive_message(self): # replaced by on_* pass def get_friends(self) -> List['Chat']: if not self.info_list.get('friend', None): self.update_friend_list() friends = [] self.info_dict['friend'] = {} for friend in self.info_list.get('friend', []): friend_uin = friend['FriendUin'] friend_name = friend['NickName'] friend_remark = friend['Remark'] new_friend = EFBPrivateChat(uid=f"friend_{friend_uin}", name=friend_name, alias=friend_remark) self.info_dict['friend'][friend_uin] = friend friends.append(ChatMgr.build_efb_chat_as_private(new_friend)) return friends def get_groups(self) -> List['Chat']: if not self.info_list.get('group', None): self.update_group_list() groups = [] self.info_dict['group'] = {} for group in self.info_list.get('group', []): group_name = group['GroupName'] group_id = group['GroupId'] new_group = EFBGroupChat(uid=f"group_{group_id}", name=group_name) self.info_dict['group'][group_id] = IOTGroup(group) groups.append(ChatMgr.build_efb_chat_as_group(new_group)) return groups def get_login_info(self) -> Dict[Any, Any]: pass def get_stranger_info(self, user_id) -> Union[Dict, None]: if not self.stranger_cache.get(user_id, None): response = self.action.getUserInfo(user=user_id) if response.get('code', 1) != 0: # Failed to get info return None else: self.stranger_cache[user_id] = response.get('data', None) return self.stranger_cache.get(user_id) def get_group_info(self, group_id: int, no_cache=True) -> Union[None, IOTGroup]: if no_cache or not self.info_dict.get('group', None): self.update_group_list() return self.info_dict['group'].get(group_id, None) def get_chat_picture(self, chat: 'Chat') -> BinaryIO: chat_type = chat.uid.split('_') if chat_type[0] == 'private': private_uin = chat_type[1].split('_')[0] return download_user_avatar(private_uin) elif chat_type[0] == 'friend': return download_user_avatar(chat_type[1]) elif chat_type[0] == 'group': return download_group_avatar(chat_type[1]) def get_chat(self, chat_uid: ChatID) -> 'Chat': chat_info = chat_uid.split('_') chat_type = chat_info[0] chat_attr = chat_info[1] chat = None if chat_type == 'friend': chat_uin = int(chat_attr) remark_name = self.get_friend_remark(chat_uin) chat = ChatMgr.build_efb_chat_as_private( EFBPrivateChat( uid=chat_attr, name=remark_name if remark_name else "", )) elif chat_type == 'group': chat_uin = int(chat_attr) group_info = self.get_group_info(chat_uin, no_cache=False) group_members = self.get_group_member_list(chat_uin, no_cache=False) chat = ChatMgr.build_efb_chat_as_group( EFBGroupChat(uid=f"group_{chat_uin}", name=group_info.get('GroupName', "")), group_members) elif chat_type == 'private': pass # fixme elif chat_type == 'phone': pass # fixme return chat def get_chats(self) -> Collection['Chat']: return self.get_friends() + self.get_groups() def get_group_member_list(self, group_id, no_cache=True): if no_cache \ or not self.group_member_list.get(group_id, None): # Key expired or not exists # Update group member list group_members = self.action.getGroupMembers(group_id) efb_group_members: List[EFBGroupMember] = [] for qq_member in group_members: qq_member = IOTGroupMember(qq_member) efb_group_members.append( EFBGroupMember(name=qq_member['NickName'], alias=qq_member['GroupCard'], uid=qq_member['MemberUin'])) self.group_member_list[group_id] = efb_group_members return self.group_member_list[group_id] def poll(self): # threading.Thread(target=self.bot.run, daemon=True).start() # self.bot.run() self.sio = self.bot.run_no_wait() self.event = threading.Event() self.event.wait() self.logger.info("IOTBot quited.") def stop_polling(self): if self.sio: self.sio.disconnect() if self.bot.pool: self.bot.pool.shutdown(wait=False) if self.event: self.event.set() def update_friend_list(self): """ Update friend list from OPQBot """ self.info_list['friend'] = self.action.getUserList() def update_group_list(self): self.info_list['group'] = self.action.getGroupList() def get_friend_remark(self, uin: int) -> Union[None, str]: count = 0 while count <= 1: if not self.info_list.get('friend', None): self.update_friend_list() self.get_friends() count += 1 else: break if count > 1: # Failure or friend not found raise Exception("Failed to update friend list!" ) # todo Optimize error handling if not self.info_dict.get('friend', None) or uin not in self.info_dict['friend']: return None # When there is no mark available, the OPQBot API will fill the remark field with nickname # Thus no need to test whether isRemark is true or not return self.info_dict['friend'][uin].get('Remark', None) def iot_send_text_message(self, chat_type: str, chat_uin: str, content: str): if chat_type == 'phone': # Send text to self self.action.sendPhoneText(content) elif chat_type == 'group': chat_uin = int(chat_uin) self.action.sendGroupText(chat_uin, content) elif chat_type == 'friend': chat_uin = int(chat_uin) self.action.sendFriendText(chat_uin, content) elif chat_type == 'private': user_info = chat_uin.split('_') chat_uin = int(user_info[0]) chat_origin = int(user_info[1]) self.action.sendPrivateText(chat_uin, chat_origin, content) def iot_send_image_message(self, chat_type: str, chat_uin: str, file: IO, content: Union[str, None] = None): image_base64 = base64.b64encode(file.read()).decode("UTF-8") md5_sum = hashlib.md5(file.read()).hexdigest() content = content if content else "" if chat_type == 'private': user_info = chat_uin.split('_') chat_uin = int(user_info[0]) chat_origin = int(user_info[1]) self.action.sendPrivatePic(user=chat_uin, group=chat_origin, picBase64Buf=image_base64, content=content) elif chat_type == 'friend': chat_uin = int(chat_uin) self.action.sendFriendPic(user=chat_uin, picBase64Buf=image_base64, content=content) elif chat_type == 'group': chat_uin = int(chat_uin) self.action.sendGroupPic(group=chat_uin, picBase64Buf=image_base64, content=content) def iot_send_voice_message(self, chat_type: str, chat_uin: str, file: IO): voice_base64 = base64.b64encode(file.read()).decode("UTF-8") if chat_type == 'private': user_info = chat_uin.split('_') chat_uin = int(user_info[0]) chat_origin = int(user_info[1]) self.action.sendPrivateVoice(user=chat_uin, group=chat_origin, voiceBase64Buf=voice_base64) elif chat_type == 'friend': chat_uin = int(chat_uin) self.action.sendFriendVoice(user=chat_uin, voiceBase64Buf=voice_base64) elif chat_type == 'group': chat_uin = int(chat_uin) self.action.sendGroupVoice(group=chat_uin, voiceBase64Buf=voice_base64)
import telebot import urllib import demjson import requests import base64 # tgbot debug mode #import logging #logger = telebot.logger # telebot.logger.setLevel(logging.DEBUG) # Outputs debug messages to console. from botoy import Action, AsyncBotoy, Botoy, EventMsg, FriendMsg, GroupMsg, AsyncAction qq_num = 000000000 qqbot = Botoy(qq=qq_num) action = Action(qq_num) tg_token = "000000000:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" tgbot = telebot.TeleBot(tg_token) qq_group_id = 000000000 tg_chat_id = -000000000000 proxy_config = 'socks5://127.0.0.1:1080' telebot.apihelper.proxy = {'https': proxy_config} proxies = { 'http': proxy_config, 'https': proxy_config,
from botoy import Action, Botoy, GroupMsg from botoy import decorators as deco bot = Botoy(use_plugins=True) @bot.group_context_use def group_ctx_middleware(ctx): ctx.master = 333 # 主人qq return ctx @bot.on_group_msg @deco.queued_up(name="manage_plugin") def manage_plugin(ctx: GroupMsg): if ctx.FromUserId != ctx.master: return action = Action(ctx.CurrentQQ) c = ctx.Content if c == "插件管理": action.sendGroupText( ctx.FromGroupId, ( "py插件 => 发送启用插件列表\n" "已停用py插件 => 发送停用插件列表\n" "刷新py插件 => 刷新所有插件,包括新建文件\n" "重载py插件+插件名 => 重载指定插件\n" "停用py插件+插件名 => 停用指定插件\n" "启用py插件+插件名 => 启用指定插件\n" ), )
from botoy import Action, Botoy, GroupMsg, FriendMsg from botoy import decorators as deco from module import config, database import json bot = Botoy( qq=config.botqq, host=config.host, port=config.port, # log=True, log=False, use_plugins=True) action = Action(qq=config.botqq, host=config.host, port=config.port) @bot.group_context_use def group_ctx_middleware(ctx: GroupMsg): ctx.type = 'group' # 群聊 ctx.QQ = ctx.FromUserId # 这条消息的发送者 ctx.QQG = ctx.FromGroupId # 这条消息的QQ群 ctx.accessLevel = database.BasicOperation.auth(ctx.QQG, ctx.QQ) # 权限等级 if ctx.MsgType == 'AtMsg': # @消息 ctx.AtContentDict = json.loads(ctx.Content) ctx.AtUserID = ctx.AtContentDict['UserID'] ctx.AtTips = ctx.AtContentDict.get('Tips') # 回复消息时才有 ctx.Content = ctx.AtContentDict['Content'] return ctx @bot.friend_context_use
file_dir = pathlib.Path("./config.json").exists() if file_dir: logger.success('( ̄▽ ̄)ノ配置文件已创建,请填写配置文件') else: logger.error('_(:3 」∠ )_配置文件创建失败') sys.exit() file = pathlib.Path("./config.json").exists() if file: load_config() else: logger.info('未检测到配置文件_(┐「ε:)_') create_config() if config["BotQQ"] == 0 or config["superAdmin"] == 0: logger.error('_(┐「ε:)_配置文件未填写,请检查配置文件中"BotQQ"与"superAdmin"~') sys.exit() # ------------------数据库------------------ group_config = TinyDB('./db/group_config.json') friend_config = TinyDB('./db/friend_config.json') tag_db = TinyDB('./db/tag.json') status = TinyDB('./db/status.json') pixiv_db = TinyDB('./db/pixiv.json') rank = TinyDB('./db/rank.json') db_tmp = TinyDB(storage=MemoryStorage) Q = Query() # ------------------bot启动参数------------------ bot = Botoy(qq=config['BotQQ'], host=config['host'], port=config['port'], use_plugins=config['use_plugins'], log=config['log'], log_file=config['log_file']) action = Action(qq=config['BotQQ'])
from botoy import Botoy, GroupMsg from botoy.action import Action from botoy import FriendMsg from botoy import refine from botoy.refine import _group_msg from botoy import decorators as deco from rex import rex bot = Botoy() test = { "toUser": 1043190359, "sendToType": 2, "groupid": 0, "Content": "测试", "sendMsgType": "TextMsg", "atUser": 0 } ''' @deco.from_these_groups(684033496) ''' @bot.on_group_msg @deco.from_these_groups(1043190359, 684033496) def group_(ctx: GroupMsg): if ctx.FromUserId != ctx.CurrentQQ and ("元" in ctx.Content): Action(ctx.CurrentQQ).sendFriendText( 251031557, ctx.Content[:ctx.Content.find(")")] + ")/") @bot.on_group_msg