├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── bot.py ├── botoy.json ├── database.sql ├── mysql.json ├── plugins ├── bot_anti_revoke.py ├── bot_baidu_ocr.py ├── bot_flash_pic.py ├── bot_generate_qrcode.py ├── bot_good_morning.py ├── bot_ph_logo.py ├── bot_record_msg.py └── bot_sysinfo.py ├── requirements.txt ├── resources ├── good-morning │ └── Config │ │ ├── GoodMorning.json │ │ └── GoodNight.json └── ph-logo │ └── font │ └── ArialEnUnicodeBold.ttf ├── run.sh └── util └── db ├── config.py ├── create_db_pool.py ├── operate_data.py └── sql.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | logs/ 23 | .idea/ 24 | wheels/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | cover/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | .pybuilder/ 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # IPython 84 | profile_default/ 85 | ipython_config.py 86 | 87 | # pyenv 88 | # For a library or package, you might want to ignore these files since the code is 89 | # intended to run in multiple environments; otherwise, check them in: 90 | # .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 100 | __pypackages__/ 101 | 102 | # Celery stuff 103 | celerybeat-schedule 104 | celerybeat.pid 105 | 106 | # SageMath parsed files 107 | *.sage.py 108 | 109 | # Environments 110 | .env 111 | .venv 112 | env/ 113 | venv/ 114 | ENV/ 115 | env.bak/ 116 | venv.bak/ 117 | 118 | # Spyder project settings 119 | .spyderproject 120 | .spyproject 121 | 122 | # Rope project settings 123 | .ropeproject 124 | 125 | # mkdocs documentation 126 | /site 127 | 128 | # mypy 129 | .mypy_cache/ 130 | .dmypy.json 131 | dmypy.json 132 | 133 | # Pyre type checker 134 | .pyre/ 135 | 136 | # pytype static type analyzer 137 | .pytype/ 138 | 139 | # Cython debug symbols 140 | cython_debug/ 141 | 142 | REMOVED_PLUGINS 143 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Time Brand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BBB_Bot(棒棒冰) - based on OPQBot 2 | 3 | ## 最近撤回(Anti Revoke)🔥 4 | 5 | 不错过其他人发送的撤回消息。 6 | 7 | ## OCR文字识别(Baidu OCR)🔥 8 | 9 | 一键识别图片中的文字,生产效率高。 10 | 11 | ## 闪照现(Flash Pic)🔥 12 | 13 | 不错过其他人发送的闪照。 14 | 15 | ## 生成二维码(Generate Qrcode)🔥 16 | 17 | 自动生成二维码。 18 | 19 | ## 关注早晚安(Good Morning)🚀 20 | 关注睡眠时间,灵活调整生物钟 21 | 22 | ## PH-Logo🔥 23 | 24 | 新颖的自制ph-Logo工具,Logo图生产效率高。 25 | 26 | ## 消息本地存储(Record Msg)🔥 27 | 28 | 接收的消息实时存到本地数据库。 29 | 30 | ### 鸣谢 31 | [opqqq-plugin](https://github.com/fz6m/opqqq-plugin) 32 | 33 | ### 编辑文件❗ 34 | 注:编辑任何文件请保证在 UTF-8 编码下,若为 ANSI,使用 NotePad++ 编码 -> 转为 UTF-8 编码。 -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from botoy import Action, Botoy, GroupMsg 4 | from botoy import decorators as deco 5 | 6 | bot_qq = 123456 # 机器人qq 7 | os.environ['BOTQQ'] = str(bot_qq) 8 | bot = Botoy(use_plugins=True) 9 | 10 | 11 | @bot.group_context_use 12 | def group_ctx_middleware(ctx): 13 | ctx.master = 10001 # 主人qq 14 | return ctx 15 | 16 | 17 | @bot.on_group_msg 18 | @deco.queued_up(name="manage_plugin") 19 | def manage_plugin(ctx: GroupMsg): 20 | if ctx.FromUserId != ctx.master: 21 | return 22 | action = Action(ctx.CurrentQQ) 23 | c = ctx.Content 24 | if c == "插件管理": 25 | action.sendGroupText( 26 | ctx.FromGroupId, 27 | ( 28 | "py插件 => 发送启用插件列表\n" 29 | "已停用py插件 => 发送停用插件列表\n" 30 | "刷新py插件 => 刷新所有插件,包括新建文件\n" 31 | "重载py插件+插件名 => 重载指定插件\n" 32 | "停用py插件+插件名 => 停用指定插件\n" 33 | "启用py插件+插件名 => 启用指定插件\n" 34 | ), 35 | ) 36 | return 37 | # 发送启用插件列表 38 | if c == "py插件": 39 | action.sendGroupText(ctx.FromGroupId, "\n".join(bot.plugins)) 40 | return 41 | # 发送停用插件列表 42 | if c == "已停用py插件": 43 | action.sendGroupText(ctx.FromGroupId, "\n".join(bot.removed_plugins)) 44 | return 45 | try: 46 | if c == "刷新py插件": 47 | bot.reload_plugins() 48 | # 重载指定插件 重载py插件+[插件名] 49 | elif c.startswith("重载py插件"): 50 | plugin_name = c[6:] 51 | bot.reload_plugin(plugin_name) 52 | # 停用指定插件 停用py插件+[插件名] 53 | elif c.startswith("停用py插件"): 54 | plugin_name = c[6:] 55 | bot.remove_plugin(plugin_name) 56 | # 启用指定插件 启用py插件+[插件名] 57 | elif c.startswith("启用py插件"): 58 | plugin_name = c[6:] 59 | bot.recover_plugin(plugin_name) 60 | except Exception as e: 61 | action.sendGroupText(ctx.FromGroupId, "操作失败: %s" % e) 62 | 63 | 64 | if __name__ == "__main__": 65 | bot.run() 66 | -------------------------------------------------------------------------------- /botoy.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "http://127.0.0.1", 3 | "port": 8888, 4 | "group_blacklist": [], 5 | "friend_blacklist": [], 6 | "blocked_users": [], 7 | "webhook": false, 8 | "webhook_post_url": "http://127.0.0.1:5000", 9 | "webhook_timeout": 20 10 | } 11 | -------------------------------------------------------------------------------- /database.sql: -------------------------------------------------------------------------------- 1 | SET NAMES utf8mb4; 2 | SET FOREIGN_KEY_CHECKS = 0; 3 | 4 | -- ---------------------------- 5 | -- Table structure for tb_bot_config 6 | -- ---------------------------- 7 | DROP TABLE IF EXISTS `tb_bot_config`; 8 | CREATE TABLE `tb_bot_config` ( 9 | `current_qq` bigint(20) NOT NULL COMMENT '机器人QQ', 10 | `master_qq` bigint(20) NULL DEFAULT NULL COMMENT '主人QQ', 11 | PRIMARY KEY (`current_qq`) USING BTREE 12 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC; 13 | 14 | -- ---------------------------- 15 | -- Records of tb_bot_config 16 | -- ---------------------------- 17 | INSERT INTO `tb_bot_config` VALUES (123456, 10001); 18 | -- ---------------------------- 19 | -- Table structure for tb_friendlist 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `tb_friendlist`; 22 | CREATE TABLE `tb_friendlist` ( 23 | `FriendUin` bigint(20) NOT NULL, 24 | `IsRemark` tinyint(1) NULL DEFAULT NULL, 25 | `NickName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 26 | `OnlineStr` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 27 | `Remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 28 | `Status` int(11) NULL DEFAULT NULL, 29 | PRIMARY KEY (`FriendUin`) USING BTREE 30 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC; 31 | 32 | -- ---------------------------- 33 | -- Table structure for tb_good_morning 34 | -- ---------------------------- 35 | DROP TABLE IF EXISTS `tb_good_morning`; 36 | CREATE TABLE `tb_good_morning` ( 37 | `uin` bigint(20) NOT NULL, 38 | `nick_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 39 | `group_id` bigint(20) NULL DEFAULT NULL, 40 | `group_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 41 | `model` int(11) NULL DEFAULT NULL, 42 | `time` timestamp NULL DEFAULT NULL, 43 | PRIMARY KEY (`uin`) USING BTREE, 44 | INDEX `tb_good_morning_Idx_Time`(`time`) USING BTREE 45 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC; 46 | 47 | -- ---------------------------- 48 | -- Table structure for tb_group_member 49 | -- ---------------------------- 50 | DROP TABLE IF EXISTS `tb_group_member`; 51 | CREATE TABLE `tb_group_member` ( 52 | `GroupUin` bigint(20) NOT NULL, 53 | `MemberUin` bigint(20) NOT NULL, 54 | `Age` int(11) NULL DEFAULT NULL, 55 | `AutoRemark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 56 | `CreditLevel` int(11) NULL DEFAULT NULL, 57 | `Email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 58 | `FaceId` int(11) NULL DEFAULT NULL, 59 | `Gender` int(11) NULL DEFAULT NULL, 60 | `GroupAdmin` int(11) NULL DEFAULT NULL, 61 | `GroupCard` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 62 | `JoinTime` int(11) NULL DEFAULT NULL, 63 | `LastSpeakTime` int(11) NULL DEFAULT NULL, 64 | `MemberLevel` int(11) NULL DEFAULT NULL, 65 | `Memo` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 66 | `NickName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 67 | `ShowName` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 68 | `SpecialTitle` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 69 | `Status` int(11) NULL DEFAULT NULL, 70 | PRIMARY KEY (`GroupUin`, `MemberUin`) USING BTREE 71 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC; 72 | 73 | -- ---------------------------- 74 | -- Table structure for tb_trooplist 75 | -- ---------------------------- 76 | DROP TABLE IF EXISTS `tb_trooplist`; 77 | CREATE TABLE `tb_trooplist` ( 78 | `GroupId` bigint(20) NOT NULL, 79 | `GroupMemberCount` int(11) NULL DEFAULT NULL, 80 | `GroupName` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 81 | `GroupNotice` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 82 | `GroupOwner` bigint(20) NULL DEFAULT NULL, 83 | `GroupTotalCount` int(11) NULL DEFAULT NULL, 84 | PRIMARY KEY (`GroupId`) USING BTREE 85 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC; 86 | 87 | SET FOREIGN_KEY_CHECKS = 1; 88 | -------------------------------------------------------------------------------- /mysql.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "127.0.0.1", 3 | "port": 3306, 4 | "user": "填你自己的", 5 | "password": "填你自己的", 6 | "database": "填你自己的" 7 | } 8 | -------------------------------------------------------------------------------- /plugins/bot_anti_revoke.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import re 4 | import time 5 | 6 | from botoy import GroupMsg, EventMsg 7 | from botoy import decorators as deco 8 | from botoy.sugar import Text, Picture, Voice 9 | 10 | import util.db.sql as op 11 | 12 | 13 | @deco.ignore_botself 14 | def receive_group_msg(ctx: GroupMsg): 15 | at_user_id = None 16 | if ctx.MsgType == 'AtMsg': 17 | content = json.loads(ctx.Content) 18 | msg = content['Content'] 19 | at_user_id = content['UserID'][0] if "UserID" in content else None 20 | elif ctx.MsgType == 'TextMsg': 21 | msg = ctx.Content 22 | else: 23 | return 24 | 25 | info_ret = re.findall(r'最近撤回\s*(\d.*)', msg) 26 | info_1 = re.findall(r'最近撤回', msg) 27 | if info_1: 28 | page_no = info_ret[0] if info_ret else 1 29 | group = ctx.FromGroupId 30 | uin = ctx.FromUserId 31 | try: 32 | if op.is_group_owner(group, uin) is True or op.is_group_admin(group, uin) is True or op.is_bot_master( 33 | ctx.CurrentQQ, uin) is True: 34 | msg_revoke = op.find_group_msg_recent_revoke(group, page_no, at_user_id) 35 | if len(msg_revoke) == 0: 36 | Text('\n[呃,没有更多记录了]', True) 37 | else: 38 | t = '' 39 | m = msg_revoke[0] 40 | t += f'''{m['nick_name']} {time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(m["msg_time"]))}\n''' 41 | 42 | if m["msg_type"] == 'TextMsg': 43 | t += m["content"] 44 | Text(t, True) 45 | elif m["msg_type"] == 'VoiceMsg': 46 | m_c_json = json.loads(m["content"]) 47 | Text(t, True) 48 | Voice(voice_url=m_c_json['Url']) 49 | elif m["msg_type"] == 'AtMsg': 50 | m_c_json = json.loads(m["content"]) 51 | t += m_c_json["Content"] 52 | Text(t, True) 53 | elif m["msg_type"] == 'PicMsg': 54 | m_c_json = json.loads(m["content"]) 55 | t += m_c_json["Content"] if "Content" in m_c_json else "" 56 | if m_c_json["Tips"] == '[群消息-QQ闪照]': 57 | Picture(pic_url=m_c_json['Url'], text=f'[ATUSER({uin})]{t}[PICFLAG]') 58 | elif m_c_json["Tips"] == '[群图片]': 59 | for pic in m_c_json["GroupPic"]: 60 | Picture(pic_url=pic['Url'], text=f'[ATUSER({uin})]{t}[PICFLAG]') 61 | time.sleep(0.5) 62 | elif m_c_json["Tips"] == '[好友图片]': 63 | for pic in m_c_json["FriendPic"]: 64 | Picture(pic_url=pic['Url'], text=f'[ATUSER({uin})]{t}[PICFLAG]') 65 | time.sleep(0.5) 66 | else: 67 | Text('\n只有群主和管理员可以使用“最近撤回”指令', True) 68 | except Exception as e: 69 | print('anti_revoke -> db.find returns null result') 70 | print(e) 71 | return 72 | 73 | 74 | def receive_events(ctx: EventMsg): 75 | if ctx.EventName == 'ON_EVENT_GROUP_ADMINSYSNOTIFY': 76 | 77 | msg_group_id = ctx.EventData['GroupId'] 78 | # 管理员变更,强制刷新成员列表 79 | op.check_group_member_list(msg_group_id, 0) 80 | 81 | elif ctx.EventName == 'ON_EVENT_GROUP_REVOKE' and ctx.EventData['UserID'] != int(os.getenv('BOTQQ')): 82 | msg_seq = ctx.EventData['MsgSeq'] 83 | msg_group_id = ctx.EventData['GroupID'] 84 | admin_user_id = ctx.EventData['AdminUserID'] 85 | user_id = ctx.EventData['UserID'] 86 | 87 | try: 88 | # 置群消息为撤回状态 89 | op.update_group_msg_is_revoked_by_msg_seq(msg_seq, msg_group_id, admin_user_id, user_id) 90 | except Exception as e: 91 | print('anti_revoke -> db.find returns null result') 92 | return 93 | -------------------------------------------------------------------------------- /plugins/bot_baidu_ocr.py: -------------------------------------------------------------------------------- 1 | """百度ai的OCR接口 2 | 填写应用信息 3 | 4 | 使用: 发送ocr文字加图片 5 | """ 6 | import time 7 | 8 | import requests 9 | from aip import AipOcr 10 | from botoy import GroupMsg 11 | from botoy.collection import MsgTypes 12 | from botoy.decorators import ignore_botself, in_content, these_msgtypes 13 | from botoy.refine import refine_pic_group_msg 14 | from botoy.sugar import Text 15 | 16 | APP_ID = "" 17 | API_KEY = "" 18 | SECRET_KEY = "" 19 | assert all([APP_ID, API_KEY, SECRET_KEY]), "请填写" 20 | 21 | client = AipOcr(APP_ID, API_KEY, SECRET_KEY) 22 | 23 | 24 | def ocr(image_url: str) -> str: 25 | try: 26 | image = requests.get(image_url, timeout=10).content 27 | except Exception: 28 | return "识别出错" 29 | try: 30 | resp = client.basicAccurate(image) 31 | except Exception: 32 | return "识别出错" 33 | if "error_code" not in resp: 34 | words = [word["words"] for word in resp["words_result"]] 35 | msg = "\n".join(words) 36 | return msg 37 | return "识别出错" 38 | 39 | 40 | @ignore_botself 41 | @these_msgtypes(MsgTypes.PicMsg) 42 | @in_content("ocr", raw=False) 43 | def receive_group_msg(ctx: GroupMsg): 44 | pic_ctx = refine_pic_group_msg(ctx) 45 | for pic in pic_ctx.GroupPic: 46 | Text(ocr(pic.Url)) 47 | time.sleep(0.5) 48 | -------------------------------------------------------------------------------- /plugins/bot_flash_pic.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re 3 | import time 4 | 5 | from botoy import GroupMsg 6 | from botoy import decorators as deco 7 | from botoy.sugar import Text, Picture 8 | 9 | import util.db.sql as op 10 | 11 | 12 | @deco.ignore_botself 13 | def receive_group_msg(ctx: GroupMsg): 14 | at_user_id = None 15 | if ctx.MsgType == 'AtMsg': 16 | content = json.loads(ctx.Content) 17 | msg = content['Content'] 18 | at_user_id = content['UserID'][0] if "UserID" in content else None 19 | elif ctx.MsgType == 'TextMsg': 20 | msg = ctx.Content 21 | else: 22 | return 23 | 24 | info_ret = re.findall(r'闪照现\s*(\d.*)', msg) 25 | info_1 = re.findall(r'闪照现', msg) 26 | if info_1: 27 | page_no = info_ret[0] if info_ret else 1 28 | group = ctx.FromGroupId 29 | uin = ctx.FromUserId 30 | try: 31 | if op.is_group_owner(group, uin) is True or op.is_group_admin(group, uin) is True or op.is_bot_master( 32 | ctx.CurrentQQ, uin) is True: 33 | msg_flash_pic = op.find_group_msg_recent_flash_pic(group, page_no, at_user_id) 34 | if len(msg_flash_pic) == 0: 35 | Text('\n[呃,没有更多记录了]', True) 36 | else: 37 | m = msg_flash_pic[0] 38 | msg = f'''\n{m['nick_name']} {time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(m["msg_time"]))}''' 39 | m_c_json = json.loads(m["content"]) 40 | Picture(pic_url=m_c_json['Url'], text=f'[ATUSER({uin})]{msg}[PICFLAG]') 41 | else: 42 | Text('\n只有群主和管理员可以使用“闪照现”指令', True) 43 | except Exception as e: 44 | print('flash_pic -> db.find returns null result') 45 | print(e) 46 | return 47 | -------------------------------------------------------------------------------- /plugins/bot_generate_qrcode.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import io 3 | 4 | from botoy import GroupMsg 5 | from botoy.decorators import ignore_botself, startswith, these_msgtypes 6 | from botoy.sugar import Picture 7 | 8 | try: 9 | import qrcode 10 | except ImportError as e: 11 | raise ImportError("请先安装依赖库: pip install qrcode") from e 12 | 13 | 14 | def gen_qrcode(text: str) -> str: 15 | img = qrcode.make(text, error_correction=qrcode.constants.ERROR_CORRECT_H, box_size=10, border=1) 16 | img_buffer = io.BytesIO() 17 | img.save(img_buffer) 18 | return base64.b64encode(img_buffer.getvalue()).decode() 19 | 20 | 21 | @ignore_botself 22 | @these_msgtypes("TextMsg") 23 | @startswith("生成二维码") 24 | def receive_group_msg(ctx: GroupMsg): 25 | Picture(pic_base64=gen_qrcode(ctx.Content[5:])) 26 | -------------------------------------------------------------------------------- /plugins/bot_good_morning.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | RESOURCES_BASE_PATH = './resources/good-morning' 4 | 5 | # ========================================== 6 | 7 | # 屏蔽群 例:[12345678, 87654321] 8 | blockGroupNumber = [] 9 | # 早安指令 10 | goodMorningInstructionSet = ['早', '早安', '哦哈哟', 'ohayo', 'ohayou', '早安啊', '早啊', '早上好', '早w', '早呀'] 11 | # 晚安指令 12 | goodNightInstructionSet = ['晚', '晚安', '哦呀斯密', 'oyasumi', 'oyasimi', '睡了', '睡觉了', '睡觉'] 13 | 14 | # ========================================== 15 | 16 | import datetime 17 | import json 18 | import os 19 | import random 20 | from enum import Enum 21 | 22 | from botoy import Action, GroupMsg 23 | from dateutil.parser import parse 24 | 25 | import util.db.sql as op 26 | 27 | 28 | # ========================================== 29 | 30 | def receive_group_msg(ctx: GroupMsg): 31 | if ctx.FromUserId == ctx.CurrentQQ: 32 | return 33 | 34 | userGroup = ctx.FromGroupId 35 | userQQ = ctx.FromUserId 36 | msg = ctx.Content 37 | nickname = ctx.FromNickName 38 | group_name = ctx.FromGroupName 39 | 40 | if Tools.commandMatch(userGroup, blockGroupNumber): 41 | return 42 | 43 | if not Tools.textOnly(ctx.MsgType): 44 | return 45 | 46 | bot = Action( 47 | qq=ctx.CurrentQQ 48 | ) 49 | 50 | mainProgram(bot, userQQ, userGroup, msg, nickname, group_name) 51 | 52 | 53 | class Model(Enum): 54 | ALL = '_all' 55 | 56 | BLURRY = '_blurry' 57 | 58 | SEND_AT = '_send_at' 59 | 60 | SEND_DEFAULT = '_send_default' 61 | 62 | 63 | class Status: 64 | SUCCESS = '_success' 65 | 66 | FAILURE = '_failure' 67 | 68 | 69 | class Tools(): 70 | 71 | @staticmethod 72 | def textOnly(msgType): 73 | return True if msgType == 'TextMsg' else False 74 | 75 | @staticmethod 76 | def readJsonFile(p): 77 | if not os.path.exists(p): 78 | return Status.FAILURE 79 | with open(p, 'r', encoding='utf-8') as f: 80 | return json.loads(f.read()) 81 | 82 | @staticmethod 83 | def commandMatch(msg, commandList, model=Model.ALL): 84 | if model == Model.ALL: 85 | for c in commandList: 86 | if c == msg: 87 | return True 88 | if model == Model.BLURRY: 89 | for c in commandList: 90 | if msg.find(c) != -1: 91 | return True 92 | return False 93 | 94 | 95 | class Utils: 96 | 97 | @staticmethod 98 | def get_user_info(userQQ): 99 | return op.get_user_greeting_data(userQQ) 100 | 101 | @staticmethod 102 | def read_conf(model): 103 | content = '' 104 | if model == GoodMorningModel.MORNING_MODEL.value: 105 | content = Tools.readJsonFile(f'{RESOURCES_BASE_PATH}/Config/GoodMorning.json') 106 | if model == GoodMorningModel.NIGHT_MODEL.value: 107 | content = Tools.readJsonFile(f'{RESOURCES_BASE_PATH}/Config/GoodNight.json') 108 | if content == Status.FAILURE: 109 | raise Exception('缺少早晚安配置文件!') 110 | return content 111 | 112 | @classmethod 113 | def get_a_words(cls, model, nickname): 114 | return random.choice((cls.read_conf(model))['statement'])['content'].replace(r'{name}', nickname) 115 | 116 | @classmethod 117 | def get_conf_by_para(cls, parameter, model): 118 | return (cls.read_conf(model))[parameter] 119 | 120 | 121 | class TimeUtils: 122 | 123 | @staticmethod 124 | def convert_time_Y_m_d(t): 125 | nowDate = str(datetime.datetime.strftime(t, '%Y-%m-%d')) 126 | return nowDate 127 | 128 | @staticmethod 129 | def get_now_time_Y_m_d(): 130 | nowDate = str(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')) 131 | return nowDate 132 | 133 | @staticmethod 134 | def get_last_time_for_goodnight_check_Y_m_d(): 135 | today = datetime.datetime.today() 136 | today_time_start = datetime.datetime(today.year, today.month, today.day, 0, 0, 0) 137 | last_time = datetime.datetime.now() + datetime.timedelta(hours=-12) 138 | if today_time_start < last_time: 139 | check_time = today_time_start 140 | else: 141 | check_time = last_time 142 | return str(datetime.datetime.strftime(check_time, '%Y-%m-%d %H:%M:%S')) 143 | 144 | @staticmethod 145 | def get_now_time(): 146 | nowDate = str(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S')) 147 | return nowDate 148 | 149 | @classmethod 150 | def calc_time_hour_lag(cls, lastTime): 151 | timeNow = cls.get_now_time() 152 | a = parse(datetime.datetime.strftime(lastTime, '%Y-%m-%d %H:%M:%S')) 153 | b = parse(timeNow) 154 | return int((b - a).total_seconds() / 3600) 155 | 156 | @staticmethod 157 | def get_now_hour(): 158 | return int(str(datetime.datetime.strftime(datetime.datetime.now(), '%H'))) 159 | 160 | @classmethod 161 | def calc_duration(cls, lastTime): 162 | timeNow = cls.get_now_time() 163 | a = parse(datetime.datetime.strftime(lastTime, '%Y-%m-%d %H:%M:%S')) 164 | b = parse(timeNow) 165 | seconds = int((b - a).total_seconds()) 166 | return [int(seconds / 3600), int((seconds % 3600) / 60), int(seconds % 60)] 167 | 168 | @staticmethod 169 | def format_time_para(parameterList, msg): 170 | return (msg.replace(r'{hour}', str(parameterList[0])) 171 | .replace(r'{minute}', str(parameterList[1])) 172 | .replace(r'{second}', str(parameterList[2]))) 173 | 174 | 175 | def mainProgram(bot, userQQ, userGroup, msg, nickname, group_name): 176 | # Good morning match 177 | if Tools.commandMatch(msg, goodMorningInstructionSet): 178 | sendMsg = good_morning_information(userQQ, userGroup, nickname, group_name) 179 | bot.sendGroupText(userGroup, sendMsg, atUser=userQQ) 180 | return 181 | 182 | # Good night detection 183 | if Tools.commandMatch(msg, goodNightInstructionSet): 184 | sendMsg = good_night_information(userQQ, userGroup, nickname, group_name) 185 | bot.sendGroupText(userGroup, sendMsg, atUser=userQQ) 186 | return 187 | 188 | 189 | class GoodMorningModel(Enum): 190 | MORNING_MODEL = 100 191 | NIGHT_MODEL = 200 192 | 193 | 194 | def userRegistration(uin, group_id, nick_name, group_name, model): 195 | data = dict( 196 | uin=uin, 197 | nick_name=nick_name, 198 | group_id=group_id, 199 | group_name=group_name, 200 | model=model, 201 | time=TimeUtils.get_now_time(), 202 | ) 203 | op.insert_user_greeting_data(data) 204 | return Status.SUCCESS 205 | 206 | 207 | def getRanking(from_group_id, model): 208 | if model == GoodMorningModel.MORNING_MODEL.value: 209 | return op.get_user_good_morning_rank(from_group_id, model, TimeUtils.get_now_time_Y_m_d()) 210 | 211 | if model == GoodMorningModel.NIGHT_MODEL.value: 212 | return op.get_user_good_night_rank(from_group_id, model, TimeUtils.get_last_time_for_goodnight_check_Y_m_d()) 213 | 214 | 215 | def greeting_handle(userQQ, userGroup, nickname, group_name, model): 216 | # registered and get replay words 217 | userRegistration(userQQ, userGroup, nickname, group_name, model) 218 | rank = getRanking(userGroup, model) 219 | send = Utils.get_a_words(model, nickname) + '\n' + (Utils.get_conf_by_para('suffix', model)).replace(r'{number}', 220 | str(rank)) 221 | return send 222 | 223 | 224 | def good_morning_information(userQQ, userGroup, nickname, group_name): 225 | # Check if registered 226 | registered = Utils.get_user_info(userQQ) 227 | send = '' 228 | if registered is False: 229 | # registered 230 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.MORNING_MODEL.value) 231 | return send 232 | # Already registered 233 | if registered['model'] == GoodMorningModel.MORNING_MODEL.value: 234 | # too little time 235 | if TimeUtils.calc_time_hour_lag(registered['time']) <= 4: 236 | send += Utils.get_conf_by_para('triggered', GoodMorningModel.MORNING_MODEL.value) 237 | return send 238 | # Good morning no twice a day 239 | if TimeUtils.convert_time_Y_m_d(registered['time']) != TimeUtils.get_now_time_Y_m_d(): 240 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.MORNING_MODEL.value) 241 | return send 242 | else: 243 | send += '您今天已经早安过啦!\n发送 晚安 试试吧~' 244 | return send 245 | if registered['model'] == GoodMorningModel.NIGHT_MODEL.value: 246 | sleeping_time = TimeUtils.calc_time_hour_lag(registered['time']) 247 | # too little time 248 | if sleeping_time <= 4: 249 | send += Utils.get_conf_by_para('unable_to_trigger', GoodMorningModel.MORNING_MODEL.value) 250 | return send 251 | # Sleep time cannot exceed 24 hours 252 | if sleeping_time < 24: 253 | send += greeting_handle(userQQ, userGroup, nickname, group_name, 254 | GoodMorningModel.MORNING_MODEL.value) + '\n' 255 | # Calculate precise sleep time 256 | sleepPreciseTime = TimeUtils.calc_duration(registered['time']) 257 | if sleepPreciseTime[0] >= 9: 258 | send += TimeUtils.format_time_para(sleepPreciseTime, 259 | (Utils.read_conf(GoodMorningModel.MORNING_MODEL.value))[ 260 | 'sleeping_time'][1]['content']) 261 | elif sleepPreciseTime[0] >= 7: 262 | send += TimeUtils.format_time_para(sleepPreciseTime, 263 | (Utils.read_conf(GoodMorningModel.MORNING_MODEL.value))[ 264 | 'sleeping_time'][0]['content']) 265 | else: 266 | send += TimeUtils.format_time_para(sleepPreciseTime, 267 | (Utils.read_conf(GoodMorningModel.MORNING_MODEL.value))[ 268 | 'too_little_sleep']) 269 | else: 270 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.MORNING_MODEL.value) 271 | return send 272 | return Status.FAILURE 273 | 274 | 275 | def good_night_information(userQQ, userGroup, nickname, group_name): 276 | # Check if registered 277 | registered = Utils.get_user_info(userQQ) 278 | send = '' 279 | if registered is False: 280 | # registered 281 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.NIGHT_MODEL.value) 282 | return send 283 | # Already registered 284 | if registered['model'] == GoodMorningModel.NIGHT_MODEL.value: 285 | # too little time 286 | if TimeUtils.calc_time_hour_lag(registered['time']) <= 4: 287 | send += Utils.get_conf_by_para('triggered', GoodMorningModel.NIGHT_MODEL.value) 288 | return send 289 | # Two good nights can not be less than 12 hours 290 | if TimeUtils.calc_time_hour_lag(registered['time']) >= 12: 291 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.NIGHT_MODEL.value) 292 | return send 293 | else: 294 | send += '您今天已经晚安过啦!\n发送 早安 试试吧~' 295 | return send 296 | if registered['model'] == GoodMorningModel.MORNING_MODEL.value: 297 | soberTime = TimeUtils.calc_time_hour_lag(registered['time']) 298 | # too little time 299 | if soberTime <= 4: 300 | send += Utils.get_conf_by_para('unable_to_trigger', GoodMorningModel.NIGHT_MODEL.value) 301 | return send 302 | # sober time cannot exceed 24 hours 303 | if soberTime < 24: 304 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.NIGHT_MODEL.value) + '\n' 305 | soberAccurateTime = TimeUtils.calc_duration(registered['time']) 306 | if soberAccurateTime[0] >= 12: 307 | send += TimeUtils.format_time_para(soberAccurateTime, 308 | (Utils.read_conf(GoodMorningModel.NIGHT_MODEL.value))[ 309 | 'working_hours'][2]['content']) 310 | else: 311 | send += TimeUtils.format_time_para(soberAccurateTime, random.choice( 312 | (Utils.read_conf(GoodMorningModel.NIGHT_MODEL.value))['working_hours'])['content']) 313 | else: 314 | send += greeting_handle(userQQ, userGroup, nickname, group_name, GoodMorningModel.NIGHT_MODEL.value) 315 | return send 316 | return Status.FAILURE 317 | -------------------------------------------------------------------------------- /plugins/bot_ph_logo.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import base64 4 | import io 5 | 6 | from PIL import Image 7 | from PIL import ImageDraw 8 | from PIL import ImageFont 9 | from botoy import GroupMsg, FriendMsg 10 | from botoy.sugar import Picture 11 | 12 | LEFT_PART_VERTICAL_BLANK_MULTIPLY_FONT_HEIGHT = 2 13 | LEFT_PART_HORIZONTAL_BLANK_MULTIPLY_FONT_WIDTH = 1 / 4 14 | RIGHT_PART_VERTICAL_BLANK_MULTIPLY_FONT_HEIGHT = 1 15 | RIGHT_PART_HORIZONTAL_BLANK_MULTIPLY_FONT_WIDTH = 1 / 4 16 | RIGHT_PART_RADII = 10 17 | BG_COLOR = '#000000' 18 | BOX_COLOR = '#F7971D' 19 | LEFT_TEXT_COLOR = '#FFFFFF' 20 | RIGHT_TEXT_COLOR = '#000000' 21 | FONT_SIZE = 50 22 | 23 | RESOURCES_BASE_PATH = './resources/ph-logo' 24 | FONT_PATH = f'{RESOURCES_BASE_PATH}/font/ArialEnUnicodeBold.ttf' 25 | 26 | 27 | def receive_friend_msg(ctx: FriendMsg): 28 | if ctx.Content.startswith('ph '): 29 | args = [i.strip() for i in ctx.Content.split(' ') if i.strip()] 30 | if len(args) >= 3: 31 | left = args[1] 32 | right = args[2] 33 | f = combine_img_horizontal 34 | if len(args) >= 4: 35 | if args[3] == '1': 36 | f = combine_img_vertical 37 | Picture(pic_base64=f(left, right)) 38 | 39 | 40 | def receive_group_msg(ctx: GroupMsg): 41 | if ctx.Content.startswith('ph '): 42 | args = [i.strip() for i in ctx.Content.split(' ') if i.strip()] 43 | if len(args) >= 3: 44 | left = args[1] 45 | right = args[2] 46 | f = combine_img_horizontal 47 | if len(args) >= 4: 48 | if args[3] == '1': 49 | f = combine_img_vertical 50 | Picture(pic_base64=f(left, right)) 51 | 52 | 53 | def create_left_part_img(text: str, font_size: int, type_='h'): 54 | font = ImageFont.truetype(FONT_PATH, font_size) 55 | font_width, font_height = font.getsize(text) 56 | offset_y = font.font.getsize(text)[1][1] 57 | if type_ == 'h': 58 | blank_height = font_height * 2 59 | else: 60 | blank_height = font_height 61 | right_blank = int(font_width / len(text) * LEFT_PART_HORIZONTAL_BLANK_MULTIPLY_FONT_WIDTH) 62 | img_height = font_height + offset_y + blank_height * 2 63 | if type_ == 'h': 64 | image_width = font_width + right_blank 65 | else: 66 | image_width = font_width + 2 * right_blank 67 | image_size = image_width, img_height 68 | image = Image.new('RGBA', image_size, BG_COLOR) 69 | draw = ImageDraw.Draw(image) 70 | if type_ == 'h': 71 | draw.text((0, blank_height), text, fill=LEFT_TEXT_COLOR, font=font) 72 | else: 73 | draw.text((right_blank, blank_height), text, fill=LEFT_TEXT_COLOR, font=font) 74 | return image 75 | 76 | 77 | def create_right_part_img(text: str, font_size: int): 78 | radii = RIGHT_PART_RADII 79 | font = ImageFont.truetype(FONT_PATH, font_size) 80 | font_width, font_height = font.getsize(text) 81 | offset_y = font.font.getsize(text)[1][1] 82 | blank_height = font_height * RIGHT_PART_VERTICAL_BLANK_MULTIPLY_FONT_HEIGHT 83 | left_blank = int(font_width / len(text) * RIGHT_PART_HORIZONTAL_BLANK_MULTIPLY_FONT_WIDTH) 84 | image_width = font_width + 2 * left_blank 85 | image_height = font_height + offset_y + blank_height * 2 86 | image = Image.new('RGBA', (image_width, image_height), BOX_COLOR) 87 | draw = ImageDraw.Draw(image) 88 | draw.text((left_blank, blank_height), text, fill=RIGHT_TEXT_COLOR, font=font) 89 | 90 | # 圆 91 | magnify_time = 10 92 | magnified_radii = radii * magnify_time 93 | circle = Image.new('L', (magnified_radii * 2, magnified_radii * 2), 0) # 创建一个黑色背景的画布 94 | draw = ImageDraw.Draw(circle) 95 | draw.ellipse((0, 0, magnified_radii * 2, magnified_radii * 2), fill=255) # 画白色圆形 96 | 97 | # 画4个角(将整圆分离为4个部分) 98 | magnified_alpha_width = image_width * magnify_time 99 | magnified_alpha_height = image_height * magnify_time 100 | alpha = Image.new('L', (magnified_alpha_width, magnified_alpha_height), 255) 101 | alpha.paste(circle.crop((0, 0, magnified_radii, magnified_radii)), (0, 0)) # 左上角 102 | alpha.paste(circle.crop((magnified_radii, 0, magnified_radii * 2, magnified_radii)), 103 | (magnified_alpha_width - magnified_radii, 0)) # 右上角 104 | alpha.paste(circle.crop((magnified_radii, magnified_radii, magnified_radii * 2, magnified_radii * 2)), 105 | (magnified_alpha_width - magnified_radii, magnified_alpha_height - magnified_radii)) # 右下角 106 | alpha.paste(circle.crop((0, magnified_radii, magnified_radii, magnified_radii * 2)), 107 | (0, magnified_alpha_height - magnified_radii)) # 左下角 108 | alpha = alpha.resize((image_width, image_height), Image.ANTIALIAS) 109 | image.putalpha(alpha) 110 | return image 111 | 112 | 113 | def combine_img_horizontal(left_text: str, right_text, font_size: int = FONT_SIZE) -> str: 114 | left_img = create_left_part_img(left_text, font_size) 115 | right_img = create_right_part_img(right_text, font_size) 116 | blank = 30 117 | bg_img_width = left_img.width + right_img.width + blank * 2 118 | bg_img_height = left_img.height 119 | bg_img = Image.new('RGBA', (bg_img_width, bg_img_height), BG_COLOR) 120 | bg_img.paste(left_img, (blank, 0)) 121 | bg_img.paste(right_img, (blank + left_img.width, int((bg_img_height - right_img.height) / 2)), mask=right_img) 122 | buffer = io.BytesIO() 123 | bg_img.save(buffer, format='png') 124 | return base64.b64encode(buffer.getvalue()).decode() 125 | 126 | 127 | def combine_img_vertical(left_text: str, right_text, font_size: int = FONT_SIZE) -> str: 128 | left_img = create_left_part_img(left_text, font_size, type_='v') 129 | right_img = create_right_part_img(right_text, font_size) 130 | blank = 15 131 | bg_img_width = max(left_img.width, right_img.width) + blank * 2 132 | bg_img_height = left_img.height + right_img.height + blank * 2 133 | bg_img = Image.new('RGBA', (bg_img_width, bg_img_height), BG_COLOR) 134 | bg_img.paste(left_img, (int((bg_img_width - left_img.width) / 2), blank)) 135 | bg_img.paste(right_img, (int((bg_img_width - right_img.width) / 2), blank + left_img.height), mask=right_img) 136 | buffer = io.BytesIO() 137 | bg_img.save(buffer, format='png') 138 | return base64.b64encode(buffer.getvalue()).decode() 139 | -------------------------------------------------------------------------------- /plugins/bot_record_msg.py: -------------------------------------------------------------------------------- 1 | from botoy import GroupMsg, FriendMsg 2 | 3 | import util.db.sql as op 4 | 5 | 6 | def receive_group_msg(ctx: GroupMsg): 7 | # 检查群列表及群成员数据是否存在, 不存在就建立 8 | op.check_group_list(ctx.FromGroupId) 9 | op.check_group_member_list(ctx.FromGroupId, ctx.FromUserId) 10 | # 群消息存入数据库 11 | op.insert_group_msg(ctx) 12 | 13 | 14 | def receive_friend_msg(ctx: FriendMsg): 15 | # 检查好友数据是否存在, 不存在就建立 16 | op.check_friend_list(ctx.FromUin) 17 | # 好友消息存入数据库 18 | op.insert_friend_msg(ctx) 19 | pass 20 | -------------------------------------------------------------------------------- /plugins/bot_sysinfo.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import time 3 | 4 | import cpuinfo 5 | import psutil 6 | from botoy import decorators as deco 7 | from botoy.sugar import Text 8 | 9 | 10 | def get_cpu_info(): 11 | info = cpuinfo.get_cpu_info() # 获取CPU型号等 12 | cpu_count = psutil.cpu_count(logical=False) # 1代表单核CPU,2代表双核CPU 13 | xc_count = psutil.cpu_count() # 线程数,如双核四线程 14 | cpu_percent = round((psutil.cpu_percent()), 2) # cpu使用率 15 | try: 16 | model = info["hardware_raw"] # cpu型号 17 | except Exception: 18 | model = info["brand_raw"] # cpu型号 19 | try: # 频率 20 | freq = info["hz_actual_friendly"] 21 | except Exception: 22 | freq = "null" 23 | cpu_info = (model, freq, info["arch"], cpu_count, xc_count, cpu_percent) 24 | return cpu_info 25 | 26 | 27 | def get_memory_info(): 28 | memory = psutil.virtual_memory() 29 | swap = psutil.swap_memory() 30 | total_nc = round((float(memory.total) / 1024 / 1024 / 1024), 3) # 总内存 31 | used_nc = round((float(memory.used) / 1024 / 1024 / 1024), 3) # 已用内存 32 | available_nc = round((float(memory.available) / 1024 / 1024 / 1024), 3) # 空闲内存 33 | percent_nc = memory.percent # 内存使用率 34 | swap_total = round((float(swap.total) / 1024 / 1024 / 1024), 3) # 总swap 35 | swap_used = round((float(swap.used) / 1024 / 1024 / 1024), 3) # 已用swap 36 | swap_free = round((float(swap.free) / 1024 / 1024 / 1024), 3) # 空闲swap 37 | swap_percent = swap.percent # swap使用率 38 | men_info = ( 39 | total_nc, 40 | used_nc, 41 | available_nc, 42 | percent_nc, 43 | swap_total, 44 | swap_used, 45 | swap_free, 46 | swap_percent, 47 | ) 48 | return men_info 49 | 50 | 51 | def uptime(): 52 | now = time.time() 53 | boot = psutil.boot_time() 54 | boottime = datetime.datetime.fromtimestamp(boot).strftime("%Y-%m-%d %H:%M:%S") 55 | nowtime = datetime.datetime.fromtimestamp(now).strftime("%Y-%m-%d %H:%M:%S") 56 | up_time = str( 57 | datetime.datetime.utcfromtimestamp(now).replace(microsecond=0) 58 | - datetime.datetime.utcfromtimestamp(boot).replace(microsecond=0) 59 | ) 60 | alltime = (boottime, nowtime, up_time) 61 | return alltime 62 | 63 | 64 | def sysinfo(): 65 | cpu_info = get_cpu_info() 66 | mem_info = get_memory_info() 67 | up_time = uptime() 68 | msg = ( 69 | "CPU型号:{0}\r\n频率:{1}\r\n架构:{2}\r\n核心数:{3}\r\n线程数:{4}\r\n负载:{5}%\r\n{6}\r\n" 70 | "总内存:{7}G\r\n已用内存:{8}G\r\n空闲内存:{9}G\r\n内存使用率:{10}%\r\n{6}\r\n" 71 | "swap:{11}G\r\n已用swap:{12}G\r\n空闲swap:{13}G\r\nswap使用率:{14}%\r\n{6}\r\n" 72 | "开机时间:{15}\r\n当前时间:{16}\r\n已运行时间:{17}" 73 | ) 74 | full_meg = msg.format( 75 | cpu_info[0], 76 | cpu_info[1], 77 | cpu_info[2], 78 | cpu_info[3], 79 | cpu_info[4], 80 | cpu_info[5], 81 | "*" * 20, 82 | mem_info[0], 83 | mem_info[1], 84 | mem_info[2], 85 | mem_info[3], 86 | mem_info[4], 87 | mem_info[5], 88 | mem_info[6], 89 | mem_info[7], 90 | up_time[0], 91 | up_time[1], 92 | up_time[2], 93 | ) 94 | return full_meg 95 | 96 | 97 | @deco.ignore_botself 98 | @deco.equal_content("sysinfo") 99 | def receive_group_msg(_): 100 | Text(sysinfo()) 101 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | qrcode==6.1 2 | baidu_aip==2.2.18.0 3 | py_cpuinfo==7.0.0 4 | psutil==5.8.0 5 | requests==2.25.1 6 | botoy 7 | mysql-connector-python 8 | Pillow==8.1.2 9 | python_dateutil==2.8.1 10 | -------------------------------------------------------------------------------- /resources/good-morning/Config/GoodMorning.json: -------------------------------------------------------------------------------- 1 | { 2 | "statement": [ 3 | { 4 | "id": 1, 5 | "content": "{name} 早安~今天也是元气满满的一天呢!" 6 | }, 7 | { 8 | "id": 2, 9 | "content": "{name} 早安喵呜~" 10 | }, 11 | { 12 | "id": 3, 13 | "content": "早上好呀 {name}!" 14 | } 15 | ], 16 | "unable_to_trigger": "睡眠时间太短,不能早安。", 17 | "triggered": "已经早安过啦!", 18 | "suffix": "今天是第 {number} 个起床的哟~", 19 | "sleeping_time": [ 20 | { 21 | "id": 1, 22 | "content": "主人昨晚睡了 {hour} 小时 {minute} 分钟 {second} 秒" 23 | }, 24 | { 25 | "id": 2, 26 | "content": "主人昨晚足足睡了 {hour} 小时 {minute} 分钟 {second} 秒。看起来充分休息了嘛~" 27 | } 28 | ], 29 | "too_little_sleep": "主人昨晚竟然只睡了 {hour} 小时 {minute} 分钟 {second} 秒。要早些休息哟~" 30 | } -------------------------------------------------------------------------------- /resources/good-morning/Config/GoodNight.json: -------------------------------------------------------------------------------- 1 | { 2 | "statement": [ 3 | { 4 | "id": 1, 5 | "content": "{name} 晚安,记得做个美梦哟~" 6 | }, 7 | { 8 | "id": 2, 9 | "content": "{name} 晚安,那么我们明天再见啦~" 10 | }, 11 | { 12 | "id": 3, 13 | "content": "晚安 {name}~" 14 | } 15 | ], 16 | "unable_to_trigger": "清醒时间太短,不能晚安。", 17 | "triggered": "已经晚安过啦!快去睡觉!", 18 | "suffix": "今天是第 {number} 个睡觉的哟~", 19 | "working_hours": [ 20 | { 21 | "id": 1, 22 | "content": "今天工作学习了 {hour} 小时 {minute} 分钟 {second} 秒。快去睡觉吧~" 23 | }, 24 | { 25 | "id": 2, 26 | "content": "今天清醒了 {hour} 小时 {minute} 分钟 {second} 秒呢。" 27 | }, 28 | { 29 | "id": 3, 30 | "content": "今天工作学习了 {hour} 小时 {minute} 分钟 {second} 秒。辛苦啦辛苦啦~" 31 | }, 32 | { 33 | "id": 4, 34 | "content": "今天工作学习了 {hour} 小时 {minute} 分钟 {second} 秒。今天过得开心吗?" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /resources/ph-logo/font/ArialEnUnicodeBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opq-osc/bbb_bot/2089da8497da2f9379ca14ea815cefddba942e58/resources/ph-logo/font/ArialEnUnicodeBold.ttf -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | nohup python3 -u bot.py > o.log 2>&1 & -------------------------------------------------------------------------------- /util/db/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import json 4 | 5 | 6 | class _config: 7 | friend_list_updating = set() 8 | troop_list_updating = set() 9 | member_list_updating = set() 10 | table_creating = set() 11 | 12 | def add_friend_list_updating(self, flag): 13 | self.friend_list_updating.add(flag) 14 | 15 | def add_troop_list_updating(self, flag): 16 | self.troop_list_updating.add(flag) 17 | 18 | def add_member_list_updating(self, flag): 19 | self.member_list_updating.add(flag) 20 | 21 | def add_table_creating(self, flag): 22 | self.table_creating.add(flag) 23 | 24 | def remove_friend_list_updating(self, flag): 25 | self.friend_list_updating.discard(flag) 26 | 27 | def remove_troop_list_updating(self, flag): 28 | self.troop_list_updating.discard(flag) 29 | 30 | def remove_member_list_updating(self, flag): 31 | self.member_list_updating.discard(flag) 32 | 33 | def remove_table_creating(self, flag): 34 | self.table_creating.discard(flag) 35 | 36 | def friend_list_is_updating(self, flag): 37 | return flag in self.friend_list_updating 38 | 39 | def troop_list_is_updating(self, flag): 40 | return flag in self.troop_list_updating 41 | 42 | def member_list_is_updating(self, flag): 43 | return flag in self.member_list_updating 44 | 45 | def table_is_creating(self, flag): 46 | return flag in self.table_creating 47 | 48 | 49 | config_dict = {} 50 | try: 51 | with open('./mysql.json', encoding='utf-8') as f: 52 | config_dict = json.load(f) 53 | except FileNotFoundError: 54 | pass 55 | except json.JSONDecodeError as e: 56 | print('Mysql 数据库配置文件不规范') 57 | 58 | config = _config() 59 | -------------------------------------------------------------------------------- /util/db/create_db_pool.py: -------------------------------------------------------------------------------- 1 | import mysql.connector.pooling 2 | 3 | from util.db.config import config_dict 4 | 5 | db_pool = mysql.connector.pooling.MySQLConnectionPool(**config_dict, charset="utf8mb4", pool_name="pool", pool_size=32) 6 | -------------------------------------------------------------------------------- /util/db/operate_data.py: -------------------------------------------------------------------------------- 1 | from util.db.create_db_pool import db_pool 2 | 3 | 4 | def execute(sql): 5 | conn = db_pool.get_connection() 6 | conn.start_transaction() 7 | cursor = conn.cursor(dictionary=True) 8 | cursor.execute(sql) 9 | conn.commit() 10 | conn.close() 11 | return 12 | 13 | 14 | def query(sql): 15 | conn = db_pool.get_connection() 16 | conn.start_transaction() 17 | cursor = conn.cursor(dictionary=True) 18 | cursor.execute(sql) 19 | result = cursor.fetchall() 20 | conn.close() 21 | return result 22 | 23 | 24 | def insert(tb, dt): 25 | conn = db_pool.get_connection() 26 | conn.start_transaction() 27 | cursor = conn.cursor(dictionary=True) 28 | ls = [(k, dt[k]) for k in dt if dt[k] is not None] 29 | sql = 'INSERT INTO `%s` (' % tb + ','.join(i[0] for i in ls) + \ 30 | ') VALUES (' + ','.join('%r' % i[1] for i in ls) + ');' 31 | try: 32 | cursor.execute(sql) 33 | except Exception as e: 34 | print(sql) 35 | print('DBErr:' + str(e)) 36 | conn.commit() 37 | conn.close() 38 | return 39 | 40 | 41 | def insert_many(tb, _field, _list): 42 | conn = db_pool.get_connection() 43 | conn.start_transaction() 44 | cursor = conn.cursor(dictionary=True) 45 | ls = [k for k in _field] 46 | sql = 'INSERT INTO `%s` (' % tb + ','.join(i for i in ls) + \ 47 | ') VALUES (' + ','.join('%s' for i in ls) + ');' 48 | try: 49 | cursor.executemany(sql, _list) 50 | except Exception as e: 51 | print(sql) 52 | print('DBErr:' + str(e)) 53 | conn.commit() 54 | conn.close() 55 | return 56 | 57 | 58 | def update(table, dt_update, dt_condition): 59 | conn = db_pool.get_connection() 60 | conn.start_transaction() 61 | cursor = conn.cursor(dictionary=True) 62 | sql = 'UPDATE %s SET ' % table + ','.join('%s=%r' % (k, dt_update[k]) for k in dt_update) \ 63 | + ' WHERE ' + ' AND '.join('%s=%r' % (k, dt_condition[k]) for k in dt_condition) + ';' 64 | try: 65 | cursor.execute(sql) 66 | except Exception as e: 67 | print(sql) 68 | print(str(e)) 69 | conn.commit() 70 | conn.close() 71 | return 72 | -------------------------------------------------------------------------------- /util/db/sql.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import json 4 | import os 5 | import time 6 | 7 | from botoy import Action, GroupMsg, FriendMsg 8 | 9 | import util.db.operate_data as db 10 | from util.db.config import config 11 | 12 | action = Action( 13 | qq=int(os.getenv('BOTQQ')) 14 | ) 15 | 16 | friend_msg_table__pre = 'tb_c2cmsg_' 17 | group_msg_table__pre = 'tb_troopmsg_' 18 | 19 | 20 | def is_table_exist(table_name): 21 | res = db.query(f'''SHOW TABLES LIKE '{table_name}';''') 22 | return len(res) != 0 23 | 24 | 25 | def find_group_list_by_group_owner(g, m): 26 | r = db.query(f'''SELECT GroupId FROM `tb_trooplist` WHERE GroupId={g} AND GroupOwner={m};''') 27 | return r 28 | 29 | 30 | def find_group_list_by_group_admin(g, m): 31 | r = db.query(f'''SELECT MemberUin FROM `tb_group_member` WHERE GroupUin={g} AND MemberUin={m} AND GroupAdmin=1;''') 32 | return r 33 | 34 | 35 | def find_qq_bot_master(current_qq, master_qq): 36 | res = db.query(f'''SELECT * FROM `tb_bot_config` WHERE current_qq={current_qq} AND master_qq={master_qq};''') 37 | return res 38 | 39 | 40 | def check_friend_list(from_uin): 41 | try: 42 | r = find_friend_by_friend_uin(from_uin) 43 | if len(r) == 0 and config.friend_list_is_updating(0) is False: 44 | config.add_friend_list_updating(0) 45 | print(str(from_uin) + ' -> 检测到新的好友,刷新[好友列表]中...') 46 | delete_friend_list() # 删除好友列表 47 | 48 | _field = dict( 49 | FriendUin=None, 50 | IsRemark=None, 51 | NickName=None, 52 | OnlineStr=None, 53 | Remark=None, 54 | Status=None, 55 | ) 56 | _list = [] 57 | ls = [k for k in _field] 58 | for friend_list in action.getUserList(): 59 | _tup = [] 60 | for i in ls: 61 | _tup.append(friend_list[i]) 62 | _list.append(_tup) 63 | insert_friend_list_many(_field, _list) 64 | config.remove_friend_list_updating(0) 65 | print(str(from_uin) + ' -> [好友列表]刷新完毕.') 66 | 67 | except Exception as e: 68 | print('Err -> check_group_list: ' + str(e)) 69 | return 70 | 71 | 72 | def check_group_list(from_group_id): 73 | try: 74 | r = find_group_by_group_id(from_group_id) 75 | if len(r) == 0 and config.troop_list_is_updating(0) is False: 76 | config.add_troop_list_updating(0) 77 | print(str(from_group_id) + ' -> 检测到新的群组,刷新[群组列表]中...') 78 | delete_troop_list() # 删除群组列表 79 | 80 | _field = dict( 81 | GroupId=None, 82 | GroupMemberCount=None, 83 | GroupName=None, 84 | GroupNotice=None, 85 | GroupOwner=None, 86 | GroupTotalCount=None, 87 | ) 88 | _list = [] 89 | ls = [k for k in _field] 90 | for troop_list in action.getGroupList(): 91 | _tup = [] 92 | for i in ls: 93 | _tup.append(troop_list[i]) 94 | _list.append(_tup) 95 | insert_group_list_many(_field, _list) 96 | config.remove_troop_list_updating(0) 97 | print(str(from_group_id) + ' -> [群组列表]刷新完毕.') 98 | 99 | except Exception as e: 100 | print('Err -> check_group_list: ' + str(e)) 101 | return 102 | 103 | 104 | def check_group_member_list(msg_group_id, from_user_id): 105 | try: 106 | r = find_member_by_uin(msg_group_id, from_user_id) 107 | if len(r) == 0 and config.member_list_is_updating(0) is False: 108 | config.add_member_list_updating(0) 109 | if from_user_id == 0: 110 | print(str(msg_group_id) + ' -> 检测到[管理员变更],刷新[群成员列表]中...') 111 | else: 112 | print(str(msg_group_id) + ' -> 检测到[新的群成员],刷新[群成员列表]中...') 113 | delete_member_list(msg_group_id) # 删除群成员列表 114 | 115 | _field = dict( 116 | GroupUin=None, 117 | MemberUin=None, 118 | Age=None, 119 | AutoRemark=None, 120 | CreditLevel=None, 121 | Email=None, 122 | FaceId=None, 123 | Gender=None, 124 | GroupAdmin=None, 125 | GroupCard=None, 126 | JoinTime=None, 127 | LastSpeakTime=None, 128 | MemberLevel=None, 129 | Memo=None, 130 | NickName=None, 131 | ShowName=None, 132 | SpecialTitle=None, 133 | Status=None, 134 | ) 135 | _list = [] 136 | ls = [k for k in _field] 137 | for group_user_list in action.getGroupMembers(msg_group_id): 138 | group_user_list['GroupUin'] = msg_group_id 139 | _tup = [] 140 | for i in ls: 141 | _tup.append(group_user_list[i]) 142 | _list.append(_tup) 143 | insert_member_list_many(_field, _list) 144 | config.remove_member_list_updating(0) 145 | print(str(msg_group_id) + ' -> [群成员列表]刷新完毕.') 146 | except Exception as e: 147 | print('Err -> check_group_member_list: ' + str(e)) 148 | return 149 | 150 | 151 | def is_group_owner(msg_group_id, member_id): 152 | try: 153 | r = find_group_list_by_group_owner(msg_group_id, member_id) 154 | if len(r) == 0: 155 | return False 156 | else: 157 | return True 158 | except Exception as e: 159 | print('Err -> is_group_owner: ' + str(e)) 160 | return False 161 | 162 | 163 | def is_group_admin(msg_group_id, member_id): 164 | try: 165 | r = find_group_list_by_group_admin(msg_group_id, member_id) 166 | if len(r) == 0: 167 | return False 168 | else: 169 | return True 170 | except Exception as e: 171 | print('Err -> is_group_admin: ' + str(e)) 172 | return False 173 | 174 | 175 | def is_bot_master(current_qq, master_qq): 176 | try: 177 | r = find_qq_bot_master(current_qq, master_qq) 178 | if len(r) == 0: 179 | return False 180 | else: 181 | return True 182 | except Exception as e: 183 | print('Err -> is_bot_master: ' + str(e)) 184 | return False 185 | 186 | 187 | def find_friend_by_friend_uin(friend_uin): 188 | res = db.query(f'''SELECT FriendUin FROM `tb_friendlist` WHERE FriendUin={friend_uin};''') 189 | return res 190 | 191 | 192 | def find_group_by_group_id(group_id): 193 | res = db.query(f'''SELECT GroupId FROM `tb_trooplist` WHERE GroupId={group_id};''') 194 | return res 195 | 196 | 197 | def insert_friend_list_many(_field, _list): 198 | db.insert_many('tb_friendlist', _field, _list) 199 | 200 | 201 | def insert_group_list_many(_field, _list): 202 | db.insert_many('tb_trooplist', _field, _list) 203 | 204 | 205 | def find_member_by_uin(group_id, user_id): 206 | res = db.query(f'''SELECT GroupUin FROM `tb_group_member` WHERE GroupUin={group_id} AND MemberUin={user_id};''') 207 | return res 208 | 209 | 210 | def delete_friend_list(): 211 | db.execute(f'''DELETE FROM `tb_friendlist` WHERE 1;''') 212 | 213 | 214 | def delete_troop_list(): 215 | db.execute(f'''DELETE FROM `tb_trooplist` WHERE 1;''') 216 | 217 | 218 | def delete_member_list(group_uin): 219 | db.execute(f'''DELETE FROM `tb_group_member` WHERE `GroupUin` = {group_uin};''') 220 | 221 | 222 | def insert_member_list_many(_field, _list): 223 | db.insert_many('tb_group_member', _field, _list) 224 | 225 | 226 | def update_group_msg_is_revoked_by_msg_seq(msg_seq, group_id, admin_user_id, user_id): 227 | if is_table_exist(f'{group_msg_table__pre}{group_id}'): 228 | db.update(f'{group_msg_table__pre}{group_id}', dict( 229 | revoke_flag=1, 230 | revoke_AdminUserID=admin_user_id, 231 | revoke_UserID=user_id, 232 | revoke_time=int(time.time()), 233 | ), dict( 234 | msg_seq=msg_seq, 235 | )) 236 | 237 | 238 | def find_group_msg_recent_flash_pic(gid, pno, uin=None): 239 | if uin is None: 240 | res = db.query( 241 | f'''SELECT * FROM `{group_msg_table__pre}{gid}` WHERE tips='[群消息-QQ闪照]' ORDER BY msg_time DESC LIMIT {int(pno) - 1},1;''') 242 | else: 243 | res = db.query( 244 | f'''SELECT * FROM `{group_msg_table__pre}{gid}` WHERE uin={uin} AND tips='[群消息-QQ闪照]' ORDER BY msg_time DESC LIMIT {int(pno) - 1},1;''') 245 | return res 246 | 247 | 248 | def find_group_msg_recent_revoke(gid, pno, uin=None): 249 | if uin is None: 250 | res = db.query( 251 | f'''SELECT * FROM `{group_msg_table__pre}{gid}` WHERE revoke_flag=1 ORDER BY msg_time DESC LIMIT {int(pno) - 1},1;''') 252 | else: 253 | res = db.query( 254 | f'''SELECT * FROM `{group_msg_table__pre}{gid}` WHERE uin={uin} AND revoke_flag=1 ORDER BY msg_time DESC LIMIT {int(pno) - 1},1;''') 255 | return res 256 | 257 | 258 | def create_table_friendmsg(from_uin): 259 | db.execute(f'''CREATE TABLE `{friend_msg_table__pre}{from_uin}` ( 260 | `msgId` bigint(20) NOT NULL AUTO_INCREMENT, 261 | `uin` bigint(20) NOT NULL, 262 | `TempUin` bigint(20) NULL, 263 | `flag` tinyint(1) NULL, 264 | `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, 265 | `tips` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 266 | `msg_time` int(11) NULL DEFAULT NULL, 267 | `msg_type` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 268 | `msg_seq` int(11) NULL DEFAULT NULL, 269 | `redbag_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, 270 | PRIMARY KEY (`msgId`) USING BTREE, 271 | INDEX `{friend_msg_table__pre}{from_uin}_Idx_MsgTime`(`msg_time`) USING BTREE 272 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;''') 273 | 274 | 275 | def create_table_troopmsg(group_id): 276 | db.execute(f'''CREATE TABLE `{group_msg_table__pre}{group_id}` ( 277 | `msgId` bigint(20) NOT NULL AUTO_INCREMENT, 278 | `uin` bigint(20) NOT NULL, 279 | `nick_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 280 | `cluster_id` bigint(20) NULL DEFAULT NULL, 281 | `flag` tinyint(1) NULL, 282 | `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, 283 | `tips` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 284 | `msg_time` int(11) NULL DEFAULT NULL, 285 | `msg_type` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, 286 | `msg_seq` int(11) NULL DEFAULT NULL, 287 | `msg_random` bigint(20) NULL DEFAULT NULL, 288 | `redbag_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL, 289 | `revoke_flag` tinyint(4) NULL DEFAULT NULL, 290 | `revoke_AdminUserID` bigint(20) NULL DEFAULT NULL, 291 | `revoke_UserID` bigint(20) NULL DEFAULT NULL, 292 | `revoke_time` int(11) NULL DEFAULT NULL, 293 | PRIMARY KEY (`msgId`) USING BTREE, 294 | INDEX `{group_msg_table__pre}{group_id}_Idx_MsgSeq`(`msg_seq`) USING BTREE, 295 | INDEX `{group_msg_table__pre}{group_id}_Idx_MsgTime`(`msg_time`) USING BTREE 296 | ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC;''') 297 | 298 | 299 | # friend_msg 300 | def insert_friend_msg(ctx: FriendMsg): 301 | flag = 1 # 自己消息标志 302 | from_uin = ctx.FromUin 303 | if from_uin == ctx.CurrentQQ: 304 | from_uin = ctx.ToUin 305 | flag = 0 306 | 307 | table_name = f'{friend_msg_table__pre}{from_uin}' 308 | if is_table_exist(table_name): 309 | content_json = {} 310 | try: 311 | content_json = json.loads(ctx.Content) 312 | except Exception as e: 313 | pass 314 | 315 | tips = None 316 | try: 317 | if "Tips" in content_json: 318 | tips = content_json["Tips"] 319 | except Exception as e: 320 | pass 321 | 322 | db.insert(table_name, dict( 323 | uin=from_uin, 324 | TempUin=ctx.TempUin, 325 | flag=flag, 326 | content=ctx.Content, 327 | tips=tips, 328 | msg_time=int(time.time()), 329 | msg_type=ctx.MsgType, 330 | msg_seq=ctx.MsgSeq, 331 | redbag_info=json.dumps(ctx.RedBaginfo) if ctx.RedBaginfo is not None else None, 332 | )) 333 | else: 334 | if config.table_is_creating(table_name) is False: 335 | config.add_table_creating(table_name) 336 | create_table_friendmsg(from_uin) 337 | print(f'{table_name} -> 创建[好友消息]表') 338 | config.remove_table_creating(table_name) 339 | 340 | 341 | def insert_group_msg(ctx: GroupMsg): 342 | flag = 1 # 自己消息标志 343 | from_uin = ctx.FromUserId 344 | if from_uin == ctx.CurrentQQ: 345 | flag = 0 346 | 347 | table_name = f'{group_msg_table__pre}{ctx.FromGroupId}' 348 | if is_table_exist(table_name): 349 | content_json = {} 350 | try: 351 | content_json = json.loads(ctx.Content) 352 | except Exception as e: 353 | pass 354 | 355 | tips = None 356 | try: 357 | if "Tips" in content_json: 358 | tips = content_json["Tips"] 359 | except Exception as e: 360 | pass 361 | 362 | db.insert(table_name, dict( 363 | uin=from_uin, 364 | nick_name=ctx.FromNickName, 365 | cluster_id=ctx.FromGroupId, 366 | flag=flag, 367 | content=ctx.Content, 368 | tips=tips, 369 | msg_time=ctx.MsgTime, 370 | msg_type=ctx.MsgType, 371 | msg_seq=ctx.MsgSeq, 372 | msg_random=ctx.MsgRandom, 373 | redbag_info=json.dumps(ctx.RedBaginfo) if ctx.RedBaginfo is not None else None, 374 | )) 375 | else: 376 | if config.table_is_creating(table_name) is False: 377 | config.add_table_creating(table_name) 378 | create_table_troopmsg(ctx.FromGroupId) 379 | print(f'{table_name} -> 创建[群组]消息表') 380 | config.remove_table_creating(table_name) 381 | 382 | 383 | def get_user_greeting_data(uin): 384 | res = db.query(f'''SELECT model,time FROM `tb_good_morning` WHERE uin={uin};''') 385 | if len(res) == 0: 386 | return False 387 | return res[0] 388 | 389 | 390 | def insert_user_greeting_data(data): 391 | res = db.query(f'''SELECT uin FROM `tb_good_morning` WHERE uin={data['uin']};''') 392 | if len(res) == 0: 393 | db.insert('tb_good_morning', data) 394 | else: 395 | db.update('tb_good_morning', dict(data), dict(uin=data['uin'])) 396 | 397 | 398 | def get_user_good_morning_rank(group_id, model, cur_time): 399 | r = db.query( 400 | f'''SELECT COUNT(*) FROM `tb_good_morning` WHERE group_id={group_id} AND time>=\'{cur_time}\' AND model={model};''') 401 | if len(r) == 0: 402 | return 1 403 | return r[0]['COUNT(*)'] 404 | 405 | 406 | def get_user_good_night_rank(group_id, model, last_time): 407 | r = db.query( 408 | f'''SELECT COUNT(*) FROM `tb_good_morning` WHERE group_id={group_id} AND time>=\'{last_time} 12:00:00\' AND model={model};''') 409 | if len(r) == 0: 410 | return 1 411 | return r[0]['COUNT(*)'] 412 | --------------------------------------------------------------------------------