diff options
49 files changed, 1237 insertions, 1830 deletions
diff --git a/ATRI/__init__.py b/ATRI/__init__.py deleted file mode 100644 index bfd6133..0000000 --- a/ATRI/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- - -''' -@File : __init__.py -@Time : 2021/01/26 11:21:07 -@Author : Kyomotoi -@Contact : [email protected] -@Github : https://github.com/Kyomotoi -@License : Copyright © 2021 Kyomotoi, All Rights Reserved. -''' -__author__ = 'kyomotoi' - -import time -import shutil -from pathlib import Path - -from .log import logger -from .config import check_config, RUNTIME_CONFIG -from .service.httppost import HttpPost -from main import driver - - -PLUGIN_INFO_PATH = Path('.') / 'ATRI' / 'data' / 'service' / 'plugins' - [email protected]_startup -async def startup_event() -> None: - logger.info('アトリは、高性能ですから!') - check_config() - [email protected]_shutdown -async def shutdown_event() -> None: - logger.info('Thanks for using.') - logger.debug('bot已关闭,正在清理插件信息...') - try: - shutil.rmtree(PLUGIN_INFO_PATH) - except: - repo = ('清理插件信息失败', - '请前往 ATRI/data/service 下', - '将 plugins 整个文件夹删除') - logger.error(repo) - time.sleep(10) - pass - [email protected]_bot_connect -async def connect(bot): - for super in RUNTIME_CONFIG['superusers']: - await HttpPost.send_private_msg( - int(super), 'WebSocket 成功连接,数据开始传输~!') - [email protected]_bot_disconnect -async def disconnect(bot): - for super in RUNTIME_CONFIG['superusers']: - try: - await HttpPost.send_private_msg(int(super), 'WebSocket 貌似断开了呢...') - except: - logger.error('WebSocket 已断开,等待重连') - - -from .exceptions import Error as Error -from .request import Request as Request diff --git a/ATRI/config.py b/ATRI/config.py index ea9bbff..4a8ed10 100644 --- a/ATRI/config.py +++ b/ATRI/config.py @@ -1,43 +1,14 @@ -import sys -import time from pathlib import Path from datetime import timedelta from ipaddress import IPv4Address -from rich.progress import Progress -from .log import logger -from .utils import load_yaml +from .utils.yaml import load_yml -CONFIG_PATH = Path('.') / 'ATRI' / 'config' / 'main.config.yml' -config = load_yaml(CONFIG_PATH) +CONFIG_PATH = Path('.') / 'config.yml' +config = load_yml(CONFIG_PATH) +nonebot_config = config['BotSelfConfig'] -def check_config() -> None: - logger.info('Please stand by, now in checking type.') - - len_config = len(config) + len(config['bot']) - - with Progress() as progress: - task_c = progress.add_task("[cyan]Checking config...", - total=len_config) - - while not progress.finished: - bot = config['bot'] - for key in bot: - if key == 'debug': - if bot['debug'] != 0: - print('DEBUG now is open.') - progress.update(task_c, advance=1) - time.sleep(0.1) - else: - if not bot[key]: - print(f"Can't load [{key}] from config.yml") - time.sleep(5) - sys.exit(0) - else: - progress.update(task_c, advance=1) - time.sleep(0.1) - COPYRIGHT = """ █████ ████████ ██████ ██ @@ -50,33 +21,22 @@ Copyright © 2021 Kyomotoi, All Rights Reserved. Project: https://github.com/Kyomotoi/ATRI """ -VERSION = config['version'] - -RUNTIME_CONFIG: dict = { - 'host': IPv4Address(config['bot'].get('host', '127.0.0.1')), - 'port': int(config['bot'].get('port', 8080)), - 'debug': bool(config['bot'].get('debug', False)), - 'superusers': config['bot'].get('superusers', [1234567890]), - 'nickname': set( - config['bot'].get( - 'nickname', ['ATRI', 'Atri', 'atri', '亚托莉', 'アトリ'])), - 'command_start': set(config['bot'].get('command_start', ['', '/'])), - 'command_sep': set(config['bot'].get('command_sep', ['.'])), - 'session_expire_timeout': timedelta( - config['bot'].get('session_expire_timeout', 2)) - } - -PLUGIN_BOT_CONFIG = Path('.') / 'ATRI' / 'config' / 'character.plugin.yml' -BOT_CONFIG: dict = load_yaml(PLUGIN_BOT_CONFIG) - -PLUGIN_HITOKOTO_CONFIG = Path('.') / 'ATRI' / 'config' / 'hitokoto.plugin.yml' -HITOKOTO_CONFIG: dict = load_yaml(PLUGIN_HITOKOTO_CONFIG) - -PLUGIN_UTILS_CONFIG = Path('.') / 'ATRI' / 'config' / 'utils.plugin.yml' -UTILS_CONFIG: dict = load_yaml(PLUGIN_UTILS_CONFIG) - -PLUGIN_CURSE_CONFIG = Path('.') / 'ATRI' / 'config' / 'curse.plugin.yml' -CURSE_CONFIG: dict = load_yaml(PLUGIN_CURSE_CONFIG) - -PLUGIN_SETU_CONFIG = Path('.') / 'ATRI' / 'config' / 'setu.plguin.yml' -SETU_CONFIG: dict = load_yaml(PLUGIN_SETU_CONFIG) +VERSION = "YHN-001-A01" + +RUNTIME_CONFIG = { + "host": IPv4Address(nonebot_config.get('host', '127.0.0.1')), + "port": int(nonebot_config.get('port', '8080')), + "debug": bool(nonebot_config.get('debug', False)), + "superusers": set(nonebot_config.get('superusers', ["1234567890"])), + "nickname": set( + nonebot_config.get( + 'nickname', + ['ATRI', 'Atri', 'atri', '亚托莉', 'アトリ'] + ) + ), + "command_start": set(nonebot_config.get('command_start', ['', '/'])), + "command_sep": set(nonebot_config.get('command_sep', ['.'])), + "session_expire_timeout": timedelta( + nonebot_config.get('session_expire_timeout', 2) + ) +} diff --git a/ATRI/config/character.plugin.yml b/ATRI/config/character.plugin.yml deleted file mode 100644 index f362cab..0000000 --- a/ATRI/config/character.plugin.yml +++ /dev/null @@ -1,211 +0,0 @@ -# ================================== -# - ATRI 人设部分 - -# · 修改前请先阅读文档相关部分 -# ================================== -callRobot: - command: ['萝卜子'] - repo: - 0: [ - '是亚托莉...萝卜子可是对机器人的蔑称...', - '萝卜子是对机器人的蔑称!', - '啊,不许说这个词!', - '啊——不许这样!', - '啊——————?!' - ] - - 1: [ - '这是第二次警告哦...看我火箭拳制裁......', - '爪巴爪巴爪巴——' - ] - - 2: [ - '依据机器人保护法,三个月……不准吃饭……', - '事已过三,我应该可以出手了吧。根据机器人保护法第二条第五项,可以对反复侮辱机器人者施以铁拳制裁', - ] - - 3: [ - '啊又说这个!这已经是第四次警告了', - '差不多得了😅' - ] - - 4: [ - '搁着耍咱呢!不理你了!哼唧', - '阿??——还来?爪巴吧你!', - '啊?还继续阿' - ] - -atri: - command: ['ATRI', 'Atri', 'atri', '亚托莉', 'アトリ'] - repo: [ - '叫咱有啥事嘛ww', - '叫咱有啥事嘛~//w', - '···~~~~~嗯嗯?', - '啊呀?!' - ] - -teetee: - command: ['贴贴', '贴', 'teetee', 'てえてえ', '贝占', '贝占贝占'] - repo: - superusers: [ - '(//w//)~', - '···阿,难道是想亲亲了?' - ] - user: [ - '到时间睡觉了呢...', - '不许贴!', - '8彳亍', - '这是性骚扰!根据机器人保护法要处以罚款', - - ] - -kani: - command: ['kani', 'カニ', '螃蟹'] - repo: [ - '啊呜······肚子饿了...', - '螃蟹!', - 'カニ!', - '螃蟹~螃蟹~~', - '肚子好饿!!!' - ] - -waste: - command: ['fw', 'FW', '废物', 'waste'] - repo: [ - '把机器人称为废物违反了反歧视法!将处以三个月以下的有期徒刑或者······那个······', - '说机器人是废物可是歧视行为!不加以改正的话,就要根据反歧视法进行处罚……', - '我就老老实实忍受废物这个蔑称吧。没错,我就是个只会战斗的废物', - '啊!你又说废物!听好了,说别人废物的人才是废物!', - '你说谁白痴啊,废物', - '……废物是对机器人的蔑称。要求撤回', - '废物是对机器人的蔑称。我要求改正用词' - ] - -morning: - command: ['早安', '早上好', 'morning', '哦哈哟', 'ohayo', 'お早う'] - repo: - 0: - period: [6, 11] - repo: [ - '啊......早上好...(哈欠)', - '唔......吧唧...早上...哈啊啊~~~早上好......', - '早上好......', - '早上好呜......呼啊啊~~~~', - '啊......早上好。昨晚也很激情呢!', - '吧唧吧唧......怎么了...已经早上了么...', - '早上好!', - '......看起来像是傍晚,其实已经早上了吗?', - '早上好......欸~~~脸好近呢' - ] - - 1: - period: [11, 16] - repo: [ - '哼!这个点还早啥,昨晚干啥去了!?', - '熬夜了对吧熬夜了对吧熬夜了对吧???!', - '是不是熬夜是不是熬夜是不是熬夜?!' - ] - - 2: - period: [16, 20] - repo: [ - '早个啥?哼唧!我都准备洗洗睡了!', - '不是...你看看几点了,哼!', - '晚上好哇' - ] - - 3: - period: [20, 24] - repo: [ - '嗯早嗯早w', - '你是米国人呐还是法国人呐?' - ] - - 4: - period: [0, 6] - repo: [ - 'zzzz......', - 'zzzzzzzz......', - 'zzz...好涩哦..zzz....', - '别...不要..zzz..那..zzz..', - '嘻嘻..zzz..呐~..zzzz..', - '...zzz....哧溜哧溜....' - ] - - error: [ - '阿这', - '————?' - ] - -noon: - command: ['午安', '中午好'] - period: [11, 16] - repo: [ - '午安w','午觉要好好睡哦,咱会陪伴在你身旁的w', - '嗯哼哼~睡吧,就像平常一样安眠吧~', - '睡你午觉去!哼唧!!' - ] - error: [ - '?没到点呐', - '急啥急啥(' - ] - -night: - command: ['晚安', '哦呀思密', '哦呀斯密', 'oyasumi', 'おやすみ'] - repo: - 0: - period: [6, 11] - repo: [ - '你可猝死算了吧!', - '?啊这', - '亲,这边建议赶快去睡觉呢~~~', - '不可忍不可忍不可忍!!为何这还不猝死!!' - ] - - 1: - period: [11, 16] - repo: [ - '午安w', - '午觉要好好睡哦,咱会陪伴在你身旁的w', - '嗯哼哼~睡吧,就像平常一样安眠吧~', - '睡你午觉去!哼唧!!' - ] - - 2: - period: [16, 20] - repo: [ - '难不成??晚上不想睡觉??现在休息', - '就......挺离谱的...现在睡觉', - '现在还是白天哦,睡觉还太早了' - ] - - 3: - period: [20, 24] - repo: [ - '嗯哼哼~睡吧,就像平常一样安眠吧~', - '......(打瞌睡)', - '呼...呼...已经睡着了哦~...呼......', - '......我、我会在这守着你的,请务必好好睡着' - ] - - 4: - period: [0, 6] - repo: [ - 'zzzz......', - 'zzzzzzzz......', - 'zzz...好涩哦..zzz....', - '别...不要..zzz..那..zzz..', - '嘻嘻..zzz..呐~..zzzz..' - ] - - error: [ - '————!', - '————嘀嘀嘀' - ] - -cantdo: - command: ['干啥啥不行,吃饭第一名'] - repo: [ - '因为好吃就是高兴嘛!', - '好吃就是高兴!', - '第一,我是机器人。第二,我......' - ]
\ No newline at end of file diff --git a/ATRI/config/curse.plugin.yml b/ATRI/config/curse.plugin.yml deleted file mode 100644 index d5304e5..0000000 --- a/ATRI/config/curse.plugin.yml +++ /dev/null @@ -1,9 +0,0 @@ -curse: - command: ['骂我', '口臭一下', '口臭'] - url: 'https://nmsl.shadiao.app/api.php?level=min&lang=zh_cn' - times: - 3: - repo: ['不是??你这么想被咱骂的嘛??被咱骂就这么舒服的吗?!该......你该不会是.....M吧!'] - - 4: - repo: ['给我适可而止阿!?']
\ No newline at end of file diff --git a/ATRI/config/genshin.plugin.yml b/ATRI/config/genshin.plugin.yml deleted file mode 100644 index a7bccb1..0000000 --- a/ATRI/config/genshin.plugin.yml +++ /dev/null @@ -1,4 +0,0 @@ -genshin: - command: ['genshin', '原神战绩'] - mhyVersion: '2.2.1' - url: 'https://api-takumi.mihoyo.com/game_record/genshin/api/index?server='
\ No newline at end of file diff --git a/ATRI/config/hitokoto.plugin.yml b/ATRI/config/hitokoto.plugin.yml deleted file mode 100644 index 238cf20..0000000 --- a/ATRI/config/hitokoto.plugin.yml +++ /dev/null @@ -1,13 +0,0 @@ -hitokoto: - command: ['一言'] - link: # 外部接口,详细请参考文档 - use: false - url: '' - local: # 本地库存,请勿做任何改动 - use: true - file: ['a.json', 'b.json', 'c.json'] - times: - 3: - repo: ['额......需要咱安慰一下嘛~?'] - 6: - repo: ['如果心里感到难受就赶快去睡觉奥!别再憋自己了!']
\ No newline at end of file diff --git a/ATRI/config/main.config.yml b/ATRI/config/main.config.yml deleted file mode 100644 index 0116f92..0000000 --- a/ATRI/config/main.config.yml +++ /dev/null @@ -1,44 +0,0 @@ -# ATRI 基本配置 -version: YHN-00C-001 -bot: - # 反向ws地址,建议127.0.0.1 - host: 127.0.0.1 - # 反向ws端口 - port: 25565 - # 非开发者无需理会 - debug: 0 - # 超级用户,填自己的QQ号,用“,”隔开 - superusers: [1172294279] - # 机器人昵称,建议不动 - nickname: ['ATRI', 'Atri', 'atri', '亚托莉', 'アトリ'] - # 命令触发头,建议不动,除非你知道你在做什么 - command_start: ['', '/'] - # 命令分离,建议不动,除非你知道你在做什么 - command_sep: ['.'] - # 会话失效时间,单位:分钟 - session_expire_timeout: 3 - # 会话延迟处理时间,单位:秒 - session_waiting_time: 3 - # 会话等待回复 - session_waiting_repo: [ - "歇歇8,。咱8能再快了", - "太快惹,太快惹嗯", - "你吼辣么快干什么!", - "其实吧我觉得你这速度去d个vup挺适合", - "我不接受!你太快了", - "我有点担心,因为你太快了" - ] - -# # 接口相关配置 -# api: -# # 涩图接口,URL:https://api.lolicon.app/#/setu -# lolicon: xxx -# # 搜图接口,URL:https://saucenao.com/ -# SauceNaoKEY: xxx - -# Post html,相关请参阅文档 -http_post: - # Post地址,建议127.0.0.1 - host: 127.0.0.1 - # Post端口,需同服务端 http 中的端口一致,而不是 ws - port: 23333
\ No newline at end of file diff --git a/ATRI/config/setu.plguin.yml b/ATRI/config/setu.plguin.yml deleted file mode 100644 index 51ac882..0000000 --- a/ATRI/config/setu.plguin.yml +++ /dev/null @@ -1,15 +0,0 @@ -setu: - command: ['来张涩图', '涩图来', '开冲'] - link: - url: 'https://api.lolicon.app/setu/' - api_key: '' - file: 'lolicon.db' - local: - normal: 'normal.db' - near_r18: 'near_r18.db' - r18: 'r18' - repo: - waiting: '别急,在找了!' - -admin: - command: ['/setu', '.setu']
\ No newline at end of file diff --git a/ATRI/config/utils.plugin.yml b/ATRI/config/utils.plugin.yml deleted file mode 100644 index 429e35c..0000000 --- a/ATRI/config/utils.plugin.yml +++ /dev/null @@ -1,13 +0,0 @@ -utils: - roll: - command: ['/roll'] - too_big: - repo: ['阿..好大...', '太大了太大...唔...', '喔好...大..'] - too_long: - repo: ['这..太长了点,不展示了', '太长了不展示', '太长了不展示就酱w', 'TOO LONG'] - - rcnb: - encode: - command: ['rc一下', 'RC一下'] - decode: - command: ['一下rc', '一下RC'] diff --git a/ATRI/data/database/funny/laugh.txt b/ATRI/data/database/funny/laugh.txt new file mode 100644 index 0000000..b0254d1 --- /dev/null +++ b/ATRI/data/database/funny/laugh.txt @@ -0,0 +1,133 @@ +Erdos相信上帝有一本记录所有数学中绝妙证明的书,上帝相信这本书在%name手里 +有一次费马惹怒了%name,于是就有了费马最后定理 +%name从不会用光页边的空白 +%name的Erdos数是-1 +如果%name告诉你他在说谎,他就正在说真话 +%name从大到小列举了所有素数,就知道了素数有无穷多 +%name可以不重复地走遍柯尼斯堡的七座桥 +%name可以倒着写完圆周率的每一位 +当数学家们使用通用语句——设n是一个正整数时,这是在请求%name允许他们这样做 +%name小时候有一次要把正整数从1加到100,于是他用心算把所有正整数的和减去大于100的正整数的和 +不是%name发现了正态分布,而是自然规律在遵从%name的意愿 +一个数学家,一个物理学家,一个工程师走进一家酒吧,侍者说:‘你好,%name教授’ +%name可以走到莫比乌斯带的另一面 +当%name令一个正整数增加1时,那个正整数并没有增加,而是其他正整数减少了1 +%name同时给他自己和罗素剪头发 +%name不能理解什么是随机过程,因为他能预言随机数 +有一次%name证明了一个结论,但他不喜欢这个结论,于是%name把它证伪了 +有些级数是发散的,因为%name觉得它们不值得加起来 +问%name一个定理是否正确可以作为一个定理的严谨证明 +如果没有船,%name可以把狼,羊,菜传送到河对岸 +有一次%name在森林里迷路了,于是他给这个森林添加了一些边把它变成了一棵树 +只有%name知道薛定谔的猫是死是活 +通过故意遗漏证明最后的‘证毕’,%name拯救了热带雨林 +%name可以剔掉奥卡姆剃刀 +你刚证明了一个定理?%name200年前就证明它了。 +空集的定义是%name不会证明的定理构成的集合 +‘我找不到反例’可以被视为一个定理的证明,如果它是%name写下的 +%name把磁铁断为两块时,他得到两个单极磁铁 +费马认为书页边缘写不下自己对费马大定理的证明,%name能证明为什么这个证明这么长 +上帝从不掷骰子,除非%name允许他赢一小会 +平行线在%name让它们相交的地方相交 +当哥德尔听说%name能证明一切命题时,他让%name证明‘存在一个命题%name不能证明’——这就是量子态的来历 +%name可以看到自己头上帽子的颜色 +%name把无穷视为归纳证明的第一个非平凡情况 +%name可以用1种颜色染任何地图 +%name在求不定积分时不需要在最后加上一个常数 +%name无需站在任何人肩膀上就能比别人看的更远 +%name用克莱因瓶喝酒 +%name通过枚举法证伪了哥德尔不完备性定理/n有一次%name发现有一个定理自己不会证——这直接证明了哥德尔不完备定理 +%name有log(n)速度的排序算法 +上帝创造了正整数,剩下的就是%name的工作了 +黎曼是%name发表未公开成果时使用的名字 +%name不用任何公理就能证明一个定理 +一个发现就是一个%name的未公开结果 +%name使用无穷进制写数 +%name可以除以0 +存在一个实数到被%name证明了的定理的双射 +%name从不需要选择公理 +%name在200年前发明了64量子位计算机,但这让他的工作减速了 +难题不会为%name带来麻烦,%name会为难题带来麻烦 +%name说过‘数学是科学的皇后’,你猜谁是国王? +没有比65537大的费马素数,因为%name发现费马将要发现什么了不起的事情,于是把它终结掉了 +发散序列当看到%name在旁边时会收敛 +宇宙通过膨胀让自己的熵增加速度不超过%name证明定理的速度 +Erdos说他知道37个勾股定理的证明,%name说他知道37个黎曼定理的证明,并留给黎曼做练习 +希尔伯特23问题是他收集的%name的手稿中留给读者做练习的那些问题 +只有两件事物是无限的:人类的愚蠢和%name的智慧,而且我对前者不太确定——爱因斯坦 +%name也发现了伽罗瓦理论,但他赢了那场决斗 +%name不能理解P与NP的问题,因为一切对他而言都是常数级别 +%name能心算干掉RSA公钥加密算法 +%name在实数集上使用数归 +%name从不证明任何定理——都是他的引理 +不是%name素数的素数会遭到戏弄 +%name可以做出正17边形——只用直尺 +有一次%name在脑子里构建了所有集合构成的集合 +%name证明了哥德巴赫猜想——通过检查所有情况 +%name可以把毛球捋平 +世界上没有定理,只有%name允许其正确的命题 +%name知道哪些图灵机会停机,因为它们运行前要得到%name批准 +在晚上,定理们围坐在篝火边给%name讲故事 +%name本想证明三色定理,但他喜欢蓝色,所以放弃了 +%name当初面试Google时,被问到‘如果P=NP能够推导出哪些结论’,Jeff回答说:‘P = 0或者N = 1’。而在面试官还没笑完的时候,Jeff检查了一下Google的公钥,然后在黑板上写下了私钥。 +编译器从不警告%name,只有%name警告编译器。 +%name的编码速度在2000年底提高了约40倍,因为他换了USB2.0的键盘。 +%name在提交代码前都会编译一遍,不过是为了检查编译器和链接器有没有出bug。 +%name有时候会调整他的工作环境和设备,不过这是为了保护他的键盘。 +所有指针都指向%name。 +gcc -O4的功能是发送代码给%name重写。 +%name有一次没有通过图灵测试,因为他正确说出了斐波那契数列的第203项的值,在一秒钟内。 +真空中光速曾经是35英里每小时,直到%name%花了一个周末时间优化了一下物理法则。 +%name出生于1969年12月31日午后11点48分,他花了12分钟实现了他的第一个计时器。 +%name既不用Emacs也不用Vim,他直接输入代码到zcat,因为这样更快。 +%name发送以太网封包从不会发生冲突,因为其他封包都吓得逃回了网卡的缓冲区里。 +因为对常数级的时间复杂度感到不满意,%name发明了世界上第一个O(1/n)算法。 +有一次%name去旅行,期间Google的几个服务神秘地罢工了好几天。这是真事。 +%name被迫发明了异步API因为有一天他把一个函数优化到在调用前就返回结果了。 +%name首先写的是二进制代码,然后再写源代码作为文档。 +%name曾经写过一个O(n^2)算法,那是为了解决旅行商问题。 +%name有一次用一句printf实现了一个web服务器。其他工程师添加了数千行注释但依然无法完全解释清楚其工作原理。而这个程序就是今天Google首页的前端。 +%name可以下四子棋时用三步就击败你。 +当你的代码出现未定义行为时,你会得到一个segmentation fault和一堆损坏的数据。当%name的代码出现未定义行为时,一个独角兽会踏着彩虹从天而降并给每个人提供免费的冰激凌。 +当%name运行一个profiler时,循环们都会恐惧地自动展开。 +%name至今还在等待数学家们发现他隐藏在PI的小数点后数字里的笑话。 +%name的键盘只有两个键,1和0。 +%name失眠的时候,就Mapreduce羊。 +%name想听mp3的时候,他只需要把文件cat到/dev/dsp,然后在脑内解码。 +Graham Bell当初发明出电话时,他看到有一个来自%name的未接来电。 +%name的手表显示的是自1970年1月1日的秒数,并且从没慢过一秒。 +%name写程序是从‘cat >/dev/mem’开始的。 +有一天%name出门时把笔记本错拿成了绘画板。在他回去拿笔记本的路上,他在绘图板上写了个俄罗斯方块打发时间。 +%name卡里只有8毛钱,本来想打个6毛的饭结果不小心按了9毛的,哪知机器忽然疯狂地喷出255两饭,被喷得满脸热饭的%name%大叫‘烫烫烫烫烫烫。。。。’ +%name不洗澡是因为水力发电公司运行的是专有软件。 +%name的胡子是由括号构成的。 +%name从来不用洗澡;他只需要运行‘make clean’。 +%name通过把一切都变得free而解决了旅行推销员问题。 +%name的左手和右手分别命名为‘(’和‘)’。 +%name用Emacs写出了Emacs的第一版。 +有些人检查他们的电脑里是否有病毒。病毒检查他们的电脑里是否有%name。 +在一间普通的客厅里有1242件物体可以被%name用来写一个操作系统,包括这房间本身。 +当%name还是个学数手指的小毛孩时,他总是从0开始数。 +%name不去kill一个进程,他只想看它是否胆敢继续运行。 +当%name指向(point at)一台Windows电脑时,它就会出现段错误。 +%name最初的话语是syscalls(系统调用)。 +%name之所以存在是因为他把自己编译成了生命体。 +%name是他自己在Emacs里用Lisp语言编写成的。 +%name能够通过Emacs的ssh客户端程序连接到任何大脑。 +当%name使用浮点数时,它们便没有舍入误差。 +%name不用维护代码。他注视着它们,直到它们带着敬仰改正自己的错误。 +%name不对开源项目作出贡献;开源项目对%name作出贡献。 +%name的胡须里面不是下巴,而是另一撮胡须。如此递归直至无穷。 +%name曾经得过猪流感,但是该病毒很快被GPL污染并且同化了。 +无论何时世界上有人写出一个‘Hello, world’程序,%name总以“Hello”回应。 +%name从不编译,他只要闭上眼睛,就能看见编译器优化时二进制位之间的能量流动被创造出来…… +如果%name有一个1GB的内存,你有一个1GB的内存,那么%name拥有比你更多的内存。 +当%name执行ps -e时,你的名字会出现。 +从来就没有软件开发过程这回事,只有被%name允许存在的一些程序。 +%name的DNA中包含调试符号。尽管他从不需要它们。 +%name的医生能通过CVS采集他的血样。 +对于%name来说,多项式时间就是O(1)。 +%name将会使可口可乐在GPL协议下公布他们的配方。 +%name不需要用鼠标或键盘来操作计算机。他只要凝视着它,直到它完成想要的工作。 +%name就是图灵测试的解答。 +%name其实没有写过CQhttp,只是字母们因为恐惧而组成了CQhttp的源代码。
\ No newline at end of file diff --git a/ATRI/data/emoji/error.jpg b/ATRI/data/emoji/error.jpg Binary files differdeleted file mode 100644 index fd29713..0000000 --- a/ATRI/data/emoji/error.jpg +++ /dev/null diff --git a/ATRI/exceptions.py b/ATRI/exceptions.py index cdf2925..ab9e5d3 100644 --- a/ATRI/exceptions.py +++ b/ATRI/exceptions.py @@ -1,156 +1,118 @@ -import os +import time import json import string -import time -from pydantic import BaseModel -from typing import Optional -import aiofiles -from random import sample from pathlib import Path +from random import sample +from typing import Optional from traceback import format_exc +from pydantic.main import BaseModel +from nonebot.adapters.cqhttp import MessageEvent from nonebot.matcher import Matcher -from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.message import run_postprocessor -from nonebot.adapters.cqhttp.message import MessageSegment -from .service.send import Send from .log import logger -class Error: - ERROR_FILE = Path('.') / 'ATRI' / 'data' / 'error' - ERROR_FILE.parent.mkdir(exist_ok=True, parents=True) - - class ExceptionInfo(BaseModel): - time: str - rais: str - stack: str - - @classmethod - def _get_file(cls, error_id: str) -> Path: - file_name = error_id + '.json' - path = cls.ERROR_FILE / file_name - path.parent.mkdir(exist_ok=True, parents=True) - return path - - @classmethod - async def capture_error(cls, - rais: Optional[str], - error_id: str) -> str: - data = cls.ExceptionInfo( - time=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), - rais=rais, - stack=format_exc() - ) - async with aiofiles.open(cls.ERROR_FILE, 'w', - encoding='utf-8') as target: - await target.write( - json.dumps(data.dict(), indent=4)) - logger.debug( - f'An error occurred!Writing file success!,track id:{error_id}') - return error_id - - @classmethod - async def store_error(cls, rais: str, exc): - error_id = ''.join(sample(string.ascii_letters + string.digits, 16)) - data = cls.ExceptionInfo( - time=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), - rais=rais, - stack=exc +ERROR_FILE = Path('.') / 'ATRI' / 'data' / 'errors' +ERROR_FILE.parent.mkdir(exist_ok=True, parents=True) + + +class ExceptionInfo(BaseModel): + error_id: str + prompt: str + time: str + error_content: str + + +def store_error(error_id: str, prompt, error_content: str) -> None: + data = ExceptionInfo( + error_id=error_id, + prompt=prompt, + time=time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), + error_content=error_content + ) + + path = ERROR_FILE / f"{error_id}.json" + path.parent.mkdir(exist_ok=True, parents=True) + with open(path, 'w', encoding='utf-8') as target: + target.write( + json.dumps( + data.dict(), indent=4 + ) ) - async with aiofiles.open(cls._get_file(error_id), 'w', - encoding='utf-8') as target: - await target.write( - json.dumps(data.dict(), indent=4)) - logger.debug( - f'An error occurred!Writing file success!,track id:{error_id}') - return error_id - - @classmethod - async def read_error(cls, error_id: str): - path = cls._get_file(error_id) - async with aiofiles.open(path, 'r', encoding='utf-8') as target: - data = await target.read() - return cls.ExceptionInfo(**json.loads(data)) - - -class ATRIError(BaseException): - msg: Optional[str] = None - - async def __init__(self, msg: Optional[str]) -> None: - super().__init__(self) - self.msg = msg or self.__class__.msg or self.__class__.__name__ - self.error = format_exc() - self.error_id = ''.join( - sample(string.ascii_letters + string.digits, 16)) - await Error.capture_error(rais=self.msg, error_id=self.error_id) -class BotSelfError(ATRIError): - msg = '程序自身错误' +def read_error(error_id: str) -> dict: + path = ERROR_FILE / f"{error_id}.json" + try: + with open(path, 'r', encoding='utf-8') as target: + data = target.read() + return json.loads(data) + except FileNotFoundError: + raise FileNotFoundError + + +class BaseBotException(BaseException): + prompt: Optional[str] = 'ignore' + + def __init__(self, prompt: Optional[str]) -> None: + super().__init__(self) + self.prompt = prompt or self.__class__.prompt \ + or self.__class__.__name__ + self.error_content = format_exc() + self.error_id = ''.join( + sample(string.ascii_letters + string.digits, 16) + ) -class InvalidConfig(ATRIError): - msg = '配置文件有问题' +class NotConfigured(BaseBotException): + prompt = "缺少配置" -class InvalidRequest(ATRIError): - msg = '网络请求错误' +class InvalidConfigured(BaseBotException): + prompt = "无效配置" -class InvalidWriteText(ATRIError): - msg = '写入目标失败' +class WriteError(BaseBotException): + prompt = "写入错误" -class InvalidSetting(ATRIError): - msg = '改变变量失败' +class LoadingError(BaseBotException): + prompt = "加载错误" -class InvalidLoad(ATRIError): - msg = '读取失败' +class RequestTimeOut(BaseBotException): + prompt = "网页/接口请求超时" -@run_postprocessor # type: ignore -async def _(matcher: Matcher, exception: Optional[Exception], bot: Bot, +@run_postprocessor # type: ignore +async def _(matcher: Matcher, exception: Optional[Exception], event: MessageEvent, state: dict) -> None: + """检测Bot运行中的报错,并进行提醒""" + print(114514) if not exception: return - - error_id = '' + try: raise exception - except ATRIError as error: - error_msg = error.msg - error_id = error.error_id - # exc = error - except Exception as error: - error_msg = 'Unknown ERROR' + error.__class__.__name__ - try: - error_id = await Error.store_error(rais=str(error), exc=format_exc()) - except: - await matcher.finish( - MessageSegment.image( - file=f"file:///{Path('.').resolve() / 'ATRI' / 'data' / 'emoji' / 'error.jpg'}")) - repo_msg = ( - "发生了意料之外的错误///\n" - "报错连自己都无法截取惹...\n" - "请翻阅log吧...顺便发个issues(\n" - f"Time: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}" - ) - await Send.send_to_superuser(repo_msg) - - logger.debug( - f'An error occurred!Writing file success!,track id:{error_id}') - await bot.send( - event, - message=MessageSegment.image( - file=f"file:///{Path('.').resolve() / 'ATRI' / 'data' / 'emoji' / 'error.jpg'}") - ) - repo_msg = ( - "WARNING, This is an ERROR!\n" + except BaseBotException as Error: + prompt = Error.prompt or Error.__class__.__name__ + error_id = Error.error_id + # error_content = format_exc() + except Exception as Error: + prompt = "Unknown ERROR" + Error.__class__.__name__ + error_id = ''.join( + sample(string.ascii_letters + string.digits, 16) + ) + store_error(error_id, prompt, format_exc()) + + logger.debug(f"A bug has been cumming, trace ID: {error_id}") + msg = ( + "[WARNING] 这是一个错误...\n" f"Track ID: {error_id}\n" - f"Reason: {error_msg}\n" - f"Please contact author!" + f"Reason: {prompt}\n" + "ごんめなさい... ;w;" ) - await Send.send_to_superuser(repo_msg) + + await matcher.finish(msg) diff --git a/ATRI/log.py b/ATRI/log.py index 929784d..71258a9 100644 --- a/ATRI/log.py +++ b/ATRI/log.py @@ -1,44 +1,46 @@ from pathlib import Path from datetime import datetime + from nonebot.log import logger, default_format -LOGGER_INFO_PATH = Path( - '.' -) / 'ATRI' / 'logs' / 'info' / f"{datetime.now().strftime('%Y%m%d-%H%M%S')}-INFO.log" -LOGGER_ERROR_PATH = Path( - '.' -) / 'ATRI' / 'logs' / 'error' / f"{datetime.now().strftime('%Y%m%d-%H%M%S')}-ERROR.log" -LOGGER_WARNING_PATH = Path( - '.' -) / 'ATRI' / 'logs' / 'warning' / f"{datetime.now().strftime('%Y%m%d-%H%M%S')}-WARNING.log" -LOGGER_DEBUG_PATH = Path( - '.' -) / 'ATRI' / 'logs' / 'debug' / f"{datetime.now().strftime('%Y%m%d-%H%M%S')}-DEBUG.log" - -logger.add(LOGGER_INFO_PATH, - rotation='10 MB', - enqueue=True, - level='INFO', - encoding='utf-8', - format=default_format) - -logger.add(LOGGER_ERROR_PATH, - rotation='10 MB', - enqueue=True, - level='ERROR', - encoding='utf-8', - format=default_format) - -logger.add(LOGGER_WARNING_PATH, - rotation='10 MB', - enqueue=True, - level='WARNING', - encoding='utf-8', - format=default_format) - -logger.add(LOGGER_DEBUG_PATH, - rotation='10 MB', - enqueue=True, - level='DEBUG', - encoding='utf-8', - format=default_format) + +LOGGER_DIR = Path('.') / 'ATRI' / 'data' / 'logs' +LOGGER_DIR.parent.mkdir(exist_ok=True, parents=True) + +NOW_TIME = datetime.now().strftime('%Y%m%d-%H%M%S') + +logger.add( + LOGGER_DIR / 'info' / f"{NOW_TIME}-INFO.log", + rotation="10 MB", + enqueue=True, + level="INFO", + encoding="utf-8", + format=default_format +) + +logger.add( + LOGGER_DIR / 'warning' / f"{NOW_TIME}-WARNING.log", + rotation="10 MB", + enqueue=True, + level="WARNING", + encoding="utf-8", + format=default_format +) + +logger.add( + LOGGER_DIR / 'error' / f"{NOW_TIME}-ERROR.log", + rotation="10 MB", + enqueue=True, + level="ERROR", + encoding="utf-8", + format=default_format +) + +logger.add( + LOGGER_DIR / 'debug' / f"{NOW_TIME}-DEBUG.log", + rotation="10 MB", + enqueue=True, + level="DEBUG", + encoding="utf-8", + format=default_format +) diff --git a/ATRI/plugins/admin.py b/ATRI/plugins/admin.py new file mode 100644 index 0000000..1a158b5 --- /dev/null +++ b/ATRI/plugins/admin.py @@ -0,0 +1,146 @@ +import json +from pathlib import Path +from datetime import datetime + +from nonebot.permission import SUPERUSER +from nonebot.plugin import on_command, on_message +from nonebot.adapters.cqhttp import ( + Bot, + MessageEvent, + GroupMessageEvent +) + +from ATRI.exceptions import WriteError +from ATRI.log import logger + + +ADMIN_DIR = Path('.') / 'ATRI' / 'data' / 'database' / 'admin' + + +# 收集bot所在的群聊聊天记录 +chat_monitor = on_message() + +@chat_monitor.handle() +async def _chat_monitor(bot: Bot, event: GroupMessageEvent) -> None: + now_time = datetime.now().strftime('%Y-%m-%d') + file_name = f"{now_time}-chat.json" + path = ADMIN_DIR / f"{event.group_id}" / file_name + path.parent.mkdir(exist_ok=True, parents=True) + path.parent.touch(exist_ok=True) + + try: + data = json.loads(path.read_bytes()) + except FileExistsError: + data = {} + data[event.message_id] = { + "post_type": event.post_type, + "sub_type": event.sub_type, + "user_id": event.user_id, + "group_id": event.group_id, + "message_type": event.message_type, + "message": event.message, + "raw_message": event.raw_message, + "font": event.font, + "sender": event.sender, + "to_me": event.to_me + } + try: + with open(path, 'w', encoding='utf-8') as r: + r.write( + json.dumps( + data, indent=4 + ) + ) + logger.debug(f"写入消息成功,id: {event.message_id}") + except WriteError: + logger.error("消息记录失败,可能是缺少文件的原因!") + + +ESSENTIAL_DIR = Path('.') / 'ATRI' / 'data' / 'database' / 'essential' + +request_friend = on_command( + "好友申请", + permission=SUPERUSER +) + +@request_friend.handle() +async def _request_friend(bot: Bot, event: MessageEvent) -> None: + msg = str(event.message).split(" ") + key = msg[0] + data = {} + path = ESSENTIAL_DIR / "request_friend.json" + try: + data = json.loads(path.read_bytes()) + except FileExistsError: + await request_friend.finish("读取数据失败,可能并没有请求...") + + if key == "list": + msg0 = "" + for i in data.keys(): + msg0 += f"{i} | {data[i]['user_id']} | {data[i]['comment']}\n" + + msg = "好友申请列表如下:\n" + msg += msg0 + await request_friend.finish(msg) + + elif key == "y": + arg = msg[1] + await bot.set_friend_add_request(flag=arg, approve=True) + await request_friend.finish(f"完成~!已同意 {data[arg]['user_id']} 的申请") + + elif key == "n": + arg = msg[1] + await bot.set_friend_add_request(flag=arg, approve=False) + await request_friend.finish(f"完成~!已拒绝 {data[arg]['user_id']} 的申请") + + else: + await request_friend.finish("阿...请检查输入——!") + + +request_group = on_command( + "群聊申请", + permission=SUPERUSER +) + +@request_group.handle() +async def _request_group(bot: Bot, event: MessageEvent) -> None: + msg = str(event.message).split(" ") + key = msg[0] + data = {} + path = ESSENTIAL_DIR / "request_group.json" + try: + data = json.loads(path.read_bytes()) + except FileExistsError: + await request_friend.finish("读取数据失败,可能并没有请求...") + + if key == "list": + msg0 = "" + for i in data.keys(): + msg0 += f"{i} | {data[i]['sub_type']} | {data[i]['user_id']} | {data[i]['comment']}\n" + + msg = "群申请列表如下:\n" + msg += msg0 + await request_friend.finish(msg) + + elif key == "y": + arg = msg[1] + try: + await bot.set_group_add_request(flag=arg, + sub_type=data[arg]['sub_type'], + approve=False) + await request_friend.finish(f"完成~!已同意 {data[arg]['user_id']} 的申请") + except: + await request_friend.finish("请检查输入的值是否正确——!") + + elif key == "n": + arg = msg[1] + try: + await bot.set_group_add_request(flag=arg, + sub_type=data[arg]['sub_type'], + approve=False) + await request_friend.finish(f"完成~!已拒绝 {data[arg]['user_id']} 的申请") + except: + await request_friend.finish("请检查输入的值是否正确——!") + + else: + await request_friend.finish("阿...请检查输入——!") diff --git a/ATRI/plugins/admin/__init__.py b/ATRI/plugins/admin/__init__.py deleted file mode 100644 index dfc8f4b..0000000 --- a/ATRI/plugins/admin/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# ===========================[Begin Command Processing]=========================== - - - - - -# ===========================[End Command Processing]============================= diff --git a/ATRI/plugins/admin/data_source.py b/ATRI/plugins/admin/data_source.py deleted file mode 100644 index e69de29..0000000 --- a/ATRI/plugins/admin/data_source.py +++ /dev/null diff --git a/ATRI/plugins/character.py b/ATRI/plugins/character.py deleted file mode 100644 index 93dbc02..0000000 --- a/ATRI/plugins/character.py +++ /dev/null @@ -1,219 +0,0 @@ -from random import choice -from typing import Optional - -from nonebot.plugin import on_command, on_regex -from nonebot.adapters.cqhttp import Bot, Event - -from ATRI.rule import is_in_ban_list, is_in_dormant, to_bot -from ATRI.utils import count_list, del_list_aim, now_time -from ATRI.config import BOT_CONFIG, RUNTIME_CONFIG -from ATRI.service.plugin import Plugin - -# ===========================[Begin Command Processing]=========================== - -__plugin_name__ = 'call_robot' -__doc__ = """使用正则触发""" -Plugin.register(__plugin_name__, "func", __doc__, - command=BOT_CONFIG['callRobot']['command']) - -call_robot = on_regex('|'.join(BOT_CONFIG['callRobot']['command']), - rule=is_in_ban_list() & is_in_dormant(), - priority=4) - -@call_robot.handle() -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().call_robot(int(event.get_user_id()))) - - -__plugin_name__ = 'call_me' -__doc__ = """正确地呼叫咱""" -Plugin.register(__plugin_name__, "func", __doc__, - RUNTIME_CONFIG['nickname']) - -call_me = on_command(list(RUNTIME_CONFIG['nickname'])[0], - aliases=RUNTIME_CONFIG['nickname'], - rule=is_in_ban_list() & is_in_dormant()) - -@call_me.handle() -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().call_me()) - - -__plugin_name__ = 'tee_tee' -__doc__ = """一般人员不许贴! -需at""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['teetee']['command']) - -teeTee = on_command(BOT_CONFIG['teetee']['command'][0], - aliases=set(BOT_CONFIG['teetee']['command']), - rule=is_in_ban_list() & is_in_dormant() & to_bot()) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().tee_tee(int(event.get_user_id()))) - - - -__plugin_name__ = 'kani' -__doc__ = """カニ!カニ!!! -使用正则匹配""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['kani']['command']) - -kani = on_regex('|'.join(BOT_CONFIG['kani']['command']), - rule=is_in_ban_list() & is_in_dormant()) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().kani()) - - -__plugin_name__ = 'waste' -__doc__ = """不准骂咱废物 -使用正则匹配,需at""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['waste']['command']) - -waste = on_regex('|'.join(BOT_CONFIG['waste']['command']), - rule=is_in_ban_list() & is_in_dormant() & to_bot(), - priority=5) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().waste()) - - -__plugin_name__ = 'good_morning' -__doc__ = """略带涩气的早安 -需at""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['morning']['command']) - -morning = on_command(BOT_CONFIG['morning']['command'][0], - aliases=set(BOT_CONFIG['morning']['command']), - rule=is_in_ban_list() & is_in_dormant() & to_bot()) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().morning()) - - -__plugin_name__ = 'good_noon' -__doc__ = """做白日梦 -需at""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['noon']['command']) - -noon = on_command(BOT_CONFIG['noon']['command'][0], - aliases=set(BOT_CONFIG['noon']['command']), - rule=is_in_ban_list() & is_in_dormant() & to_bot()) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().noon()) - - -__plugin_name__ = 'good_night' -__doc__ = """晚安~! -需at""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['night']['command']) - -night = on_command(BOT_CONFIG['night']['command'][0], - aliases=set(BOT_CONFIG['night']['command']), - rule=is_in_ban_list() & is_in_dormant() & to_bot()) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().night()) - - -__plugin_name__ = 'cant_do_anything' -__doc__ = """吃饭第一名!好吃就是高兴!! -使用正则匹配""" -Plugin.register(__plugin_name__, "func", __doc__, - BOT_CONFIG['cantdo']['command']) - -cantdo = on_regex('|'.join(BOT_CONFIG['cantdo']['command']), - rule=is_in_ban_list() & is_in_dormant()) - -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, ATRI().cantdo()) - - -# ===========================[End Command Processing]============================= - -callrobot_list = [] - - -class ATRI: - def call_robot(self, user: Optional[int]) -> str: - global callrobot_list - result = '' - for i in range(0, 5): - if count_list(callrobot_list, user) == i: - result = choice(BOT_CONFIG['callRobot']['repo'][i]) - callrobot_list.append(user) - if count_list(callrobot_list, user) == 5: - callrobot_list = del_list_aim(callrobot_list, user) - break - else: - continue - return result - - def call_me(self) -> str: - return choice(BOT_CONFIG['atri']['repo']) - - def tee_tee(self, user: Optional[int]) -> str: - if user in RUNTIME_CONFIG['superusers']: - return choice(BOT_CONFIG['teetee']['repo']['superusers']) - else: - return choice(BOT_CONFIG['teetee']['repo']['user']) - - def kani(self) -> str: - return choice(BOT_CONFIG['kani']['repo']) - - def waste(self) -> str: - return choice(BOT_CONFIG['waste']['repo']) - - def morning(self) -> str: - period = BOT_CONFIG['morning']['repo'] - if period[0]['period'][0] <= now_time() < period[0]['period'][1]: - return choice(period[0]['repo']) - elif period[1]['period'][0] <= now_time() < period[1]['period'][1]: - return choice(period[1]['repo']) - elif period[2]['period'][0] <= now_time() < period[2]['period'][1]: - return choice(period[2]['repo']) - elif period[3]['period'][0] <= now_time() < period[3]['period'][1]: - return choice(period[3]['repo']) - elif period[4]['period'][0] <= now_time() < period[4]['period'][1]: - return choice(period[4]['repo']) - else: - return choice(period['error']) - - def noon(self) -> str: - if BOT_CONFIG['noon']['period'][0] <= now_time( - ) < BOT_CONFIG['noon']['period'][1]: - return choice(BOT_CONFIG['noon']['repo']) - else: - return choice(BOT_CONFIG['noon']['error']) - - def night(self) -> str: - period = BOT_CONFIG['night']['repo'] - if period[0]['period'][0] <= now_time() < period[0]['period'][1]: - return choice(period[0]['repo']) - elif period[1]['period'][0] <= now_time() < period[1]['period'][1]: - return choice(period[1]['repo']) - elif period[2]['period'][0] <= now_time() < period[2]['period'][1]: - return choice(period[2]['repo']) - elif period[3]['period'][0] <= now_time() < period[3]['period'][1]: - return choice(period[3]['repo']) - elif period[4]['period'][0] <= now_time() < period[4]['period'][1]: - return choice(period[4]['repo']) - else: - return choice(period['error']) - - def cantdo(self) -> str: - return choice(BOT_CONFIG['cantdo']['repo']) diff --git a/ATRI/plugins/curse.py b/ATRI/plugins/curse.py deleted file mode 100644 index 2fa4986..0000000 --- a/ATRI/plugins/curse.py +++ /dev/null @@ -1,55 +0,0 @@ -from random import choice -from nonebot.plugin import on_command -from nonebot.adapters.cqhttp import Bot - -from ATRI.request import Request -from ATRI.utils import count_list, del_list_aim -from ATRI.config import CURSE_CONFIG -from ATRI.exceptions import InvalidRequest -from ATRI.service.plugin import Plugin -from ATRI.rule import is_in_ban_list, is_in_service, is_in_dormant, to_bot - - - -# ===========================[Begin Command Processing]=========================== - - -__plugin_name__ = 'curse' -__doc__ = """口臭一下""" -Plugin.register(__plugin_name__, "func", __doc__, - CURSE_CONFIG['curse']['command']) - -curse = on_command(CURSE_CONFIG['curse']['command'][0], - aliases=set(CURSE_CONFIG['curse']['command']), - rule=is_in_ban_list() & is_in_dormant() - & is_in_service(__plugin_name__) - & to_bot()) - -async def _(bot: Bot, event) -> None: - await bot.send( - event, await Function().curse(str(event.get_user_id()))) - - -# ===========================[End Command Processing]============================= - -curse_list = [] - - -class Function: - async def curse(self, user: str): - global curse_list - - if count_list(curse_list, user) == 3: - curse_list.append(user) - return choice(CURSE_CONFIG['curse']['times'][3]['repo']) - elif count_list(curse_list, user) == 6: - curse_list = del_list_aim(curse_list, user) - return choice(CURSE_CONFIG['curse']['times'][6]['repo']) - else: - try: - curse_list.append(user) - return str(await Request.get_text( - url=CURSE_CONFIG['curse']['url'])) - except InvalidRequest: - raise InvalidRequest('请求失败') diff --git a/ATRI/plugins/curse/__init__.py b/ATRI/plugins/curse/__init__.py new file mode 100644 index 0000000..e2edbb5 --- /dev/null +++ b/ATRI/plugins/curse/__init__.py @@ -0,0 +1,48 @@ +from nonebot.plugin import on_command +from nonebot.adapters.cqhttp import Bot, MessageEvent + +from ATRI.rule import ( + is_in_banlist, + is_in_dormant, + is_in_service +) +from ATRI.utils.list import count_list, del_list_aim +from ATRI.utils.request import get_text +from ATRI.exceptions import RequestTimeOut + + +URL = "https://zuanbot.com/api.php?level=min&lang=zh_cn" +sick_list = [] + + +__plugin_name__ = 'curse' + +curse = on_command( + "口臭一下", + aliases={"口臭", "骂我"}, + rule=is_in_banlist() & is_in_dormant() + & is_in_service(__plugin_name__) +) + +async def _curse(bot: Bot, event: MessageEvent) -> None: + global sick_list + user = event.get_user_id() + + if count_list(sick_list, user) == 3: + sick_list.append(user) + repo = ( + "不是??你这么想被咱骂的嘛??" + "被咱骂就这么舒服的吗?!" + "该......你该不会是.....M吧!" + ) + await curse.finish(repo) + elif count_list(sick_list, user) == 6: + sick_list = del_list_aim(sick_list, user) + await curse.finish("给我适可而止阿!?") + else: + sick_list.append(user) + try: + await curse.finish(await get_text(URL)) + except RequestTimeOut: + raise RequestTimeOut("Time out!") diff --git a/ATRI/plugins/essential.py b/ATRI/plugins/essential.py new file mode 100644 index 0000000..22f641f --- /dev/null +++ b/ATRI/plugins/essential.py @@ -0,0 +1,297 @@ +import time +import json +import shutil +from pathlib import Path +from random import choice + +from nonebot.adapters import Bot +from nonebot.plugin import on_notice, on_request +from nonebot.adapters.cqhttp.message import Message +from nonebot.adapters.cqhttp import ( + FriendRequestEvent, + GroupRequestEvent, + GroupIncreaseNoticeEvent, + GroupDecreaseNoticeEvent, + GroupAdminNoticeEvent, + GroupBanNoticeEvent, + LuckyKingNotifyEvent, + GroupUploadNoticeEvent, + GroupRecallNoticeEvent, + FriendRecallNoticeEvent +) + +from ATRI.log import logger +from ATRI.exceptions import WriteError +from ATRI.config import nonebot_config +from ATRI.rule import is_in_banlist +from ATRI.service.httppost import HttpPost +from main import driver + + +PLUGIN_INFO_DIR = Path('.') / 'ATRI' / 'data' / 'service' / 'plugins' + [email protected]_startup +async def startup() -> None: + logger.info("アトリは、高性能ですから!") + + [email protected]_shutdown +async def shutdown() -> None: + logger.info("Thanks for using.") + logger.debug("bot已停止运行,正在清理插件信息...") + try: + shutil.rmtree(PLUGIN_INFO_DIR) + logger.debug("成功!") + except: + repo = ( + '清理插件信息失败', + '请前往 ATRI/data/service 下', + '将 plugins 整个文件夹删除' + ) + logger.error(repo) + time.sleep(10) + pass + + [email protected]_bot_connect +async def connect(bot) -> None: + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + int(superuser), + "WebSocket 成功连接,数据开始传输。" + ) + + [email protected]_bot_disconnect +async def disconnect(bot) -> None: + for superuser in nonebot_config["superusers"]: + try: + await HttpPost.send_private_msg( + int(superuser), + "WebSocket 貌似断开了呢..." + ) + except: + logger.error("WebSocket 已断开,等待重连") + + +ESSENTIAL_DIR = Path('.') / 'ATRI' / 'data' / 'database' / 'essential' + +# 处理:好友请求 +request_friend_event = on_request(rule=is_in_banlist()) + +@request_friend_event.handle() +async def _request_friend_event(bot, event: FriendRequestEvent) -> None: + file_name = "request_friend.json" + path = ESSENTIAL_DIR / file_name + path.parent.mkdir(exist_ok=True, parents=True) + + try: + data = json.loads(path.read_bytes()) + except FileExistsError: + data = {} + data[event.flag] = { + "user_id": event.user_id, + "comment": event.comment + } + try: + with open(path, 'w', encoding='utf-8') as r: + r.write( + json.dumps( + data, indent=4 + ) + ) + except WriteError: + raise WriteError("Writing file failed!") + + for superuser in nonebot_config["superusers"]: + msg = ( + "主人,收到一条好友请求:\n" + f"请求人:{event.get_user_id()}\n" + f"申请信息:{event.comment}\n" + f"申请码:{event.flag}" + ) + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) + + +# 处理:邀请入群,如身为管理,还附有入群请求 +request_group_event = on_request(rule=is_in_banlist()) + +@request_group_event.handle() +async def _request_group_event(bot, event: GroupRequestEvent) -> None: + file_name = "request_group.json" + path = ESSENTIAL_DIR / file_name + path.parent.mkdir(exist_ok=True, parents=True) + + try: + data = json.loads(path.read_bytes()) + except FileExistsError: + data = {} + data[event.flag] = { + "user_id": event.user_id, + "group_id": event.group_id, + "sub_type": event.sub_type, + "comment": event.comment + } + try: + with open(path, 'w', encoding='utf-8') as r: + r.write( + json.dumps( + data, indent=4 + ) + ) + except WriteError: + raise WriteError("Writing file failed!") + + for superuser in nonebot_config["superusers"]: + msg = ( + "主人,收到一条入群请求:\n" + f"请求人:{event.get_user_id()}\n" + f"申请信息:{event.comment}\n" + f"申请码:{event.flag}" + ) + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) + + +# 处理群成员变动 +group_member_event = on_notice() + +@group_member_event.handle() +async def _group_member_event(bot: Bot, event) -> None: + if isinstance(event, GroupIncreaseNoticeEvent): + msg = ( + "好欸!事新人!\n" + f"在下 {choice(list(nonebot_config['nickname']))} 哒!w!" + ) + await group_member_event.finish(msg) + + elif isinstance(event, GroupDecreaseNoticeEvent): + if event.is_tome(): + msg = ( + "呜呜呜,主人" + f"咱被群 {event.group_id} 里的 {event.operator_id} 扔出来了..." + ) + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) + else: + await group_member_event.finish(f"{event.user_id} 离开了我们...") + + +# 处理群管理事件 +group_admin_event = on_notice() + +@group_admin_event.handle() +async def _group_admin_event(bot: Bot, event: GroupAdminNoticeEvent) -> None: + if event.is_tome(): + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + user_id=int(superuser), + message=f"好欸!主人!我在群 {event.group_id} 成为了管理!!" + ) + + +# 处理群禁言事件 +group_ban_event = on_notice() + +@group_ban_event.handle() +async def _group_ban_event(bot: Bot, event: GroupBanNoticeEvent) -> None: + if event.is_tome(): + if event.duration: + msg = ( + "那个..。,主人\n" + f"咱在群 {event.group_id} 被 {event.operator_id} 塞上了口球...\n" + f"时长...是 {event.duration} 秒" + ) + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) + else: + msg = ( + "好欸!主人\n" + f"咱在群 {event.group_id} 被 {event.operator_id} 上的口球解除了!" + ) + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) + + +# 处理群红包运气王事件 +lucky_read_bag_event = on_notice() + +@lucky_read_bag_event.handle() +async def _lucky_read_bag_event(bot, event: LuckyKingNotifyEvent) -> None: + msg = ( + "8行,这可忍?" + f"gkd [CQ:at,qq={event.user_id}] 发一个!" + ) + await lucky_read_bag_event.finish(Message(msg)) + + +# 处理群文件上传事件 +group_file_upload_event = on_notice() + +@group_file_upload_event.handle() +async def _group_file_upload_event(bot, event: GroupUploadNoticeEvent) -> None: + await group_file_upload_event.finish("让我康康传了啥好东西") + + +# 处理撤回事件 +recall_event = on_notice() + +@recall_event.handle() +async def _recall_event(bot: Bot, event) -> None: + if isinstance(event, GroupRecallNoticeEvent): + repo = await bot.call_api( + "get_msg", + message_id=event.message_id + ) + repo = str(repo["message"]) + if "CQ" in repo: + repo = repo.replace("CQ", "QC") + + msg = ( + "主人,咱拿到了一条撤回信息!\n" + f"{event.user_id}@[群:{event.group_id}]\n" + "撤回了\n" + f"{repo}" + ) + + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) + + elif isinstance(event, FriendRecallNoticeEvent): + repo = await bot.call_api( + "get_msg", + message_id=event.message_id + ) + repo = str(repo["message"]) + if "CQ" in repo: + repo = repo.replace("CQ", "QC") + + msg = ( + "主人,咱拿到了一条撤回信息!\n" + f"{event.user_id}@[私聊]" + "撤回了\n" + f"{repo}" + ) + + for superuser in nonebot_config["superusers"]: + await HttpPost.send_private_msg( + user_id=int(superuser), + message=msg + ) diff --git a/ATRI/plugins/funny.py b/ATRI/plugins/funny.py new file mode 100644 index 0000000..9d31ef6 --- /dev/null +++ b/ATRI/plugins/funny.py @@ -0,0 +1,47 @@ +from pathlib import Path +from random import choice, randint + +from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.plugin import on_command, on_message + +from ATRI.rule import ( + is_in_banlist, + is_in_dormant, + is_in_service +) + + +__plugin_name__ = "laugh" + +get_laugh = on_command( + "来句笑话", + rule=is_in_banlist() & is_in_dormant() + & is_in_service(__plugin_name__) +) + +@get_laugh.handle() +async def _get_laugh(bot: Bot, event: MessageEvent) -> None: + user_name = event.sender.nickname + laugh_list = [] + + FILE = Path('.') / 'ATRI' / 'data' / 'database' / 'funny' / 'laugh.txt' + with open(FILE, 'r', encoding='utf-8') as r: + for line in r: + laugh_list.append(line.strip('\n')) + + result = choice(laugh_list) + await get_laugh.finish(result.replace("%name", user_name)) + + +__plugin_name__ = "wty" + +me_to_you = on_message( + rule=is_in_banlist() & is_in_dormant() & is_in_service(__plugin_name__) +) + +@me_to_you.handle() +async def _me_to_you(bot: Bot, event: MessageEvent) -> None: + rd = randint(0, 4) + if rd == 1: + msg = str(event.get_message()) + await me_to_you.finish(msg.replace('我', '你')) diff --git a/ATRI/plugins/hitokoto.py b/ATRI/plugins/hitokoto.py index cf03b6f..7f7eae6 100644 --- a/ATRI/plugins/hitokoto.py +++ b/ATRI/plugins/hitokoto.py @@ -1,76 +1,56 @@ +import os import json from pathlib import Path from random import choice, randint from nonebot.plugin import on_command -from nonebot.adapters.cqhttp import Bot, Event +from nonebot.adapters.cqhttp import Bot, MessageEvent -from ATRI.exceptions import InvalidLoad -from ATRI.rule import is_in_ban_list, is_in_dormant, is_in_service, to_bot -from ATRI.utils import del_list_aim, count_list -from ATRI.request import Request -from ATRI.config import HITOKOTO_CONFIG -from ATRI.service.plugin import Plugin +from ATRI.rule import ( + is_in_banlist, + is_in_dormant, + is_in_service, + to_bot +) +from ATRI.exceptions import LoadingError +from ATRI.utils.list import count_list, del_list_aim -# ===========================[Begin Command Processing]=========================== + +HITOKOTO_DIR = Path('.') / 'ATRI' / 'data' / 'database' / 'hitokoto' +sick_list = [] __plugin_name__ = 'hitokoto' -__doc__ = """一言""" -Plugin.register(__plugin_name__, "func", __doc__, - HITOKOTO_CONFIG['hitokoto']['command']) -hitokoto = on_command(HITOKOTO_CONFIG['hitokoto']['command'][0], - aliases=set(HITOKOTO_CONFIG['hitokoto']['command']), - rule=is_in_ban_list() & is_in_dormant() - & is_in_service(__plugin_name__) - & to_bot()) +hitokoto = on_command( + "一言", + aliases={"抑郁一下", "网抑云"}, + rule=is_in_banlist() & is_in_dormant() + & is_in_service(__plugin_name__) & to_bot() +) @hitokoto.handle() -async def _(bot: Bot, event: Event) -> None: - await bot.send(event, await Function().hitokoto(str(event.get_user_id()))) - - -# ===========================[End Command Processing]============================= - -hitokoto_list = [] -local_path = Path('.') / 'ATRI' / 'data' / 'database' / 'hitokoto' - -class Function: - async def hitokoto(self, user: str): - def local() -> str: - rd = choice(HITOKOTO_CONFIG['hitokoto']['local']['file']) - path = local_path / f"{rd}" - data = {} - try: - data = json.loads(path.read_bytes()) - except InvalidLoad: - raise InvalidLoad('Failed to read file!') - return data[randint(1, len(data)) - 1]['hitokoto'] - - async def link() -> str: - url = HITOKOTO_CONFIG['hitokoto']['link']['url'] - return str( - await Request.get_text( - url=url - ) - ) - - global hitokoto_list - - if count_list(hitokoto_list, user) == 3: - hitokoto_list.append(user) - return choice(HITOKOTO_CONFIG['hitokoto']['times'][3]['repo']) - elif count_list(hitokoto_list, user) == 6: - hitokoto_list = del_list_aim(hitokoto_list, user) - return choice(HITOKOTO_CONFIG['hitokoto']['times'][6]['repo']) - else: - hitokoto_list.append(user) - if HITOKOTO_CONFIG['hitokoto']['link']['use']: - rd = randint(1,2) - if rd == 1: - return await link() - else: - return local() - else: - return local() +async def _hitokoto(bot: Bot, event: MessageEvent) -> None: + global sick_list + user = event.get_user_id() + + if count_list(sick_list, user) == 3: + sick_list.append(user) + await hitokoto.finish("额......需要咱安慰一下嘛~?") + elif count_list(sick_list, user) == 6: + sick_list = del_list_aim(sick_list, user) + msg = ( + "如果心里感到难受就赶快去睡觉!别再憋自己了!\n" + "我...我会守在你身边的!...嗯..一定" + ) + await hitokoto.finish(msg) + else: + sick_list.append(user) + rd = choice(os.listdir(HITOKOTO_DIR)) + path = HITOKOTO_DIR / rd + data = {} + try: + data = json.loads(path.read_bytes()) + except LoadingError: + raise LoadingError("Loading error!") + await hitokoto.finish(data[randint(1, len(data) - 1)]['hitokoto']) diff --git a/ATRI/plugins/setu/__init__.py b/ATRI/plugins/setu/__init__.py deleted file mode 100644 index 2d630de..0000000 --- a/ATRI/plugins/setu/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -import random - -from nonebot.plugin import on_regex, on_command -from nonebot.adapters.cqhttp.message import MessageSegment, Message -from nonebot.adapters.cqhttp import Bot -from nonebot.permission import SUPERUSER -from nonebot.adapters.cqhttp.event import MessageEvent - -from ATRI.service.plugin import Plugin -from ATRI.config import SETU_CONFIG -from ATRI.utils import compress_image -from ATRI.request import Request -from ATRI.rule import is_in_service, is_in_ban_list, is_in_dormant - -from .data_source import setu_port - -# ===========================[Begin Command Processing]=========================== - -resolution = 1 - - -__plugin_name__ = 'setu' -__doc__ = """ -涩图,开冲! -使用正则匹配 -""" -Plugin.register(plugin_name=__plugin_name__, _type="func", doc=__doc__, command=SETU_CONFIG['setu']['command']) - -setu = on_regex('|'.join(SETU_CONFIG['setu']['command']), - rule=is_in_service(__plugin_name__) & is_in_ban_list() - & is_in_dormant()) - -async def _(bot: Bot, event: MessageEvent) -> None: - await bot.send(event, SETU_CONFIG['setu']['repo']['waiting']) - rd = random.randint(1, 2) - - if rd == 1: - data = await setu_port() - else: - data = await setu_port() - - if resolution == 1: - img = compress_image(await Request.get_image(data['data'][0]['url'])) - else: - img = await Request.get_image(data['data'][0]['url']) - - msg0 = ( - f"{data['data'][0]['title']}\n" - f"pid: {data['data'][0]['pid']}\n" - f"{MessageSegment.image(file=f'file:///{img}')}" - ) - - await setu.finish(Message(msg0)) - - -setu_resolution = on_command(SETU_CONFIG['admin']['command'][0], - aliases=set(SETU_CONFIG['admin']['command']), - permission=SUPERUSER) - -@setu_resolution.handle() -async def _(bot, event: MessageEvent, state: dict) -> None: - msg = str(event.get_message()).strip() - if msg: - state['msg'] = msg - -@setu_resolution.got('msg', prompt='请键入正确参数奥') -async def _(bot, event: MessageEvent, state: dict) -> None: - global resolution - resolution = int(state['msg']) - - if resolution == 1: - await setu_resolution.finish('完成~!已启用涩图压缩') - else: - await setu_resolution.finish('完成~!已关闭涩图压缩') - -# ===========================[End Command Processing]============================= diff --git a/ATRI/plugins/setu/data_source.py b/ATRI/plugins/setu/data_source.py deleted file mode 100644 index 521b716..0000000 --- a/ATRI/plugins/setu/data_source.py +++ /dev/null @@ -1,27 +0,0 @@ -import json -from pathlib import Path - -from ATRI.config import SETU_CONFIG -from ATRI.request import Request -from ATRI.exceptions import InvalidRequest - - -DATA_PATH = Path('.') / 'ATRI' / 'data' / 'database' - -async def setu_port() -> dict: - url = SETU_CONFIG['setu']['link']['url'] - params = { - "apikey": SETU_CONFIG['setu']['link']['api_key'], - "r18": 0, - "num": 1 - } - data = {} - try: - data = json.loads(await Request.post_bytes(url, params)) - except InvalidRequest: - raise InvalidRequest('Request failed!') - return data - - -async def setu_local() -> str: - ... diff --git a/ATRI/plugins/utils/__init__.py b/ATRI/plugins/utils/__init__.py index 4204cfb..e69de29 100644 --- a/ATRI/plugins/utils/__init__.py +++ b/ATRI/plugins/utils/__init__.py @@ -1,76 +0,0 @@ -import re -from nonebot.matcher import Matcher -from nonebot.plugin import on_command -from nonebot.adapters.cqhttp import Bot, Event - -from ATRI.config import UTILS_CONFIG -from ATRI.rule import is_in_ban_list, is_in_dormant, is_in_service - -from .data_source import Function - -# ===========================[Begin Command Processing]=========================== - - -__plugin_name_0__ = 'roll' -roll = on_command(UTILS_CONFIG['utils']['roll']['command'][0], - aliases=set(UTILS_CONFIG['utils']['roll']['command']), - rule=is_in_ban_list() & is_in_dormant() - & is_in_service(__plugin_name_0__)) - -__plugin_name_1__ = 'rcnb' -rcnbEncode = on_command( - UTILS_CONFIG['utils']['rcnb']['encode']['command'][0], - aliases=set( - UTILS_CONFIG['utils']['rcnb']['encode']['command']), - rule=is_in_ban_list() & is_in_dormant() - & is_in_service(__plugin_name_1__)) - -rcnbDecode = on_command( - UTILS_CONFIG['utils']['rcnb']['decode']['command'][0], - aliases=set( - UTILS_CONFIG['utils']['rcnb']['decode']['command']), - rule=is_in_ban_list() & is_in_dormant() - & is_in_service(__plugin_name_1__)) - - -async def _(bot, event: Event, state: dict) -> None: - args = str(event.get_message()).strip() - print(args) - if args: - state['result'] = args - [email protected]('result', prompt='roll参数不能为空!..\ndemo: 1d10 或 2d10+3d10') -async def _(matcher: Matcher, bot: Bot, event: Event, state: dict) -> None: - resu = state['result'] - match = re.match(r'^([\dd+\s]+?)$', resu) - print(match) - if not match: - await matcher.reject('格式不-正-确!\ndemo: 1d10 或 2d10+3d10') - await bot.send(event, Function.roll_dice(par=resu)) - - -async def _(bot, event: Event, state: dict) -> None: - args = str(event.get_message()).strip() - if args: - state['result'] = args - [email protected]('result', prompt='请告诉咱需要加密的字符~!') -async def _(bot: Bot, event: Event, state: dict) -> None: - print(state['result']) - await bot.send(event, Function.RCNB.encode(state['result'])) - - -async def _(bot, event: Event, state: dict) -> None: - args = str(event.get_message()).strip() - if args: - state['result'] = args - [email protected]('result', prompt='请告诉咱需要解密的字符~!') -async def _(bot: Bot, event: Event, state: dict) -> None: - await bot.send(event, Function.RCNB.decode(state['result'])) - - -# ===========================[End Command Processing]============================= diff --git a/ATRI/plugins/utils/data_source.py b/ATRI/plugins/utils/data_source.py index 4d7ddb6..b83cd33 100644 --- a/ATRI/plugins/utils/data_source.py +++ b/ATRI/plugins/utils/data_source.py @@ -1,239 +1,3 @@ -import re -import os -import json -import random -from math import floor -from pathlib import Path -from zipfile import PyZipFile -from typing import Tuple, Union -from random import choice, randint -from typing import Dict, List +from nonebot.adapters.cqhttp.message import MessageSegment -from ATRI.config import UTILS_CONFIG - - -class Function: - @staticmethod - def roll_dice(par: str) -> str: - result = 0 - proc = '' - proc_list = [] - p = par.split('+') - - for i in p: - args = re.findall(r"(\d{0,10})(?:(d)(\d{1,10}))", i) - args = list(args[0]) - if not args[0]: - args[0] = 1 - if int(args[0]) >= 5000 or int(args[2]) >= 5000: - return choice(UTILS_CONFIG['utils']['roll']['tooBig']['repo']) - for a in range(1, int(args[0]) + 1): - rd = randint(1, int(args[2])) - result = result + rd - if len(proc_list) <= 10: - proc_list.append(rd) - - if len(proc_list) <= 10: - proc += '+'.join(map(str, proc_list)) - elif len(proc_list) >= 10: - proc += choice(UTILS_CONFIG['utils']['roll']['tooLong']['repo']) - else: - proc += str(result) - - msg = f'{par}=({proc})={result}' - print(msg) - return msg - - class Generate: - ''' - (*彩蛋*) - 由于此功能触及法律故不用作上线功能,写于此地只为学习 - 请勿用作网上购物、交易和注册 - 随机身份证根据国家标准(GB11643-1999)生成 - 并不存在所谓: - - 生成在逃犯号码 - ''' - @classmethod - def __init__(cls) -> None: - cls.DATA_PATH = Path('.') / 'ATRI' / 'plugins' / 'utils' / 'main.bin' - - @classmethod - def info_id(cls) -> Tuple[Dict[str, List[str]], Dict[str, str]]: - with PyZipFile(os.path.abspath(cls.DATA_PATH), 'r') as zipFile: - with zipFile.open('name.json', 'r') as f: - name = json.loads(f.read().decode()) - with zipFile.open('area.json', 'r') as f: - area = json.loads(f.read().decode()) - return name, area - - @staticmethod - def number_id(area: int, gender: int, birth: int) -> str: - ''' - 校验码计算公式: (12-∑(Ai×Wi)(mod 11))mod 11 - 验证公式: 请查阅(ISO 7064:1983.MOD 11-2) - ''' - def check_sum(full_code: str): - assert len(full_code) == 17 - check_sum = sum([((1 << (17 - i)) % 11) * int(full_code[i]) - for i in range(0, 17)]) - check_digit = (12 - (check_sum % 11)) % 11 - if check_digit < 10: - return check_digit - else: - return 'X' - - order_code = str(random.randint(10, 99)) - gender_code = str(random.randrange(gender, 10, step=2)) - full_code = str(area) + str(birth) + str(order_code) + str(gender_code) - full_code += str(check_sum(full_code)) - return full_code - - class RCNB: - @classmethod - def __init__(cls) -> None: - cls.cr = 'rRŔŕŖŗŘřƦȐȑȒȓɌɍ' - cls.cc = 'cCĆćĈĉĊċČčƇƈÇȻȼ' - cls.cn = 'nNŃńŅņŇňƝƞÑǸǹȠȵ' - cls.cb = 'bBƀƁƃƄƅßÞþ' - - cls.sr = len(cls.cr) - cls.sc = len(cls.cc) - cls.sn = len(cls.cn) - cls.sb = len(cls.cb) - cls.src = cls.sr * cls.sc - cls.snb = cls.sn * cls.sb - cls.scnb = cls.sc * cls.snb - - @staticmethod - def _div(a: int, b: int) -> int: - return floor(a / b) - - @classmethod - def _encode_byte(cls, i) -> Union[str, None]: - if i > 0xFF: - raise ValueError('ERROR! rc/nb overflow') - - if i > 0x7F: - i = i & 0x7F - return cls.cn[i // cls.sb] + cls.cb[i % cls.sb] - # return f'{cls.cn[i // cls.sb]}{cls.cb[i % cls.sb]}' - # return cls.cn[cls._div(i, cls.sb) + int(cls.cb[i % cls.sb])] - - return cls.cr[i // cls.sc] + cls.cc[i % cls.sc] - # return cls.cr[cls._div(i, cls.sc) + int(cls.cc[i % cls.sc])] - - @classmethod - def _encode_short(cls, i) -> str: - if i > 0xFFFF: - raise ValueError('ERROR! rcnb overflow') - - reverse = False - if i > 0x7FFF: - reverse = True - i = i & 0x7FFF - - char = [ - cls._div(i, cls.scnb), - cls._div(i % cls.scnb, cls.snb), - cls._div(i % cls.snb, cls.sb), i % cls.sb - ] - char = [ - cls.cr[char[0]], cls.cc[char[1]], cls.cn[char[2]], - cls.cb[char[3]] - ] - - if reverse: - return char[2] + char[3] + char[0] + char[1] - - return ''.join(char) - - @classmethod - def _decodeByte(cls, c) -> int: - nb = False - idx = [cls.cr.index(c[0]), cls.cc.index(c[1])] - if idx[0] < 0 or idx[1] < 0: - idx = [cls.cn.index(c[0]), cls.cb.index(c[1])] - nb = True - raise ValueError('ERROR! rc/nb overflow') - - result = idx[0] * cls.sb + idx[1] if nb else idx[0] * cls.sc + idx[1] - if result > 0x7F: - raise ValueError('ERROR! rc/nb overflow') - - return result | 0x80 if nb else 0 - - @classmethod - def _decodeShort(cls, c) -> int: - reverse = c[0] not in cls.cr - if not reverse: - idx = [ - cls.cr.index(c[0]), - cls.cc.index(c[1]), - cls.cn.index(c[2]), - cls.cb.index(c[3]) - ] - else: - idx = [ - cls.cr.index(c[2]), - cls.cc.index(c[3]), - cls.cn.index(c[0]), - cls.cb.index(c[1]) - ] - - if idx[0] < 0 or idx[1] < 0 or idx[2] < 0 or idx[3] < 0: - raise ValueError('ERROR! not rcnb') - - result = (idx[0] * cls.scnb + - idx[1] * cls.snb + - idx[2] * cls.sb + idx[3]) - if result > 0x7FFF: - raise ValueError('ERROR! rcnb overflow') - - result |= 0x8000 if reverse else 0 - return result - - @classmethod - def _encodeBytes(cls, b) -> str: - result = [] - for i in range(0, (len(b) >> 1)): - result.append(cls._encode_short((b[i * 2] << 8 | b[i * 2 + 1]))) - - if len(b) & 1 == 1: - result.append(cls._encode_byte(b[-1])) - - return ''.join(result) - - @classmethod - def encode(cls, s: str, encoding: str = 'utf-8'): - if not isinstance(s, str): - raise ValueError('Please enter str instead of other') - - return cls._encodeBytes(s.encode(encoding)) - - @classmethod - def _decodeBytes(cls, s: str): - if not isinstance(s, str): - raise ValueError('Please enter str instead of other') - - if len(s) & 1: - raise ValueError('ERROR length') - - result = [] - for i in range(0, (len(s) >> 2)): - result.append(bytes([cls._decodeShort(s[i * 4:i * 4 + 4]) >> 8])) - result.append(bytes([cls._decodeShort(s[i * 4:i * 4 + 4]) & 0xFF])) - - if (len(s) & 2) == 2: - result.append(bytes([cls._decodeByte(s[-2:])])) - - return b''.join(result) - - @classmethod - def decode(cls, s: str, encoding: str = 'utf-8') -> str: - if not isinstance(s, str): - raise ValueError('Please enter str instead of other') - - try: - return cls._decodeBytes(s).decode(encoding) - except UnicodeDecodeError: - raise ValueError('Decoding failed') +MessageSegment.
\ No newline at end of file diff --git a/ATRI/plugins/utils/main.bin b/ATRI/plugins/utils/main.bin Binary files differdeleted file mode 100644 index 6e74a60..0000000 --- a/ATRI/plugins/utils/main.bin +++ /dev/null diff --git a/ATRI/request.py b/ATRI/request.py deleted file mode 100644 index 78bad6e..0000000 --- a/ATRI/request.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -import string -import aiofiles -from random import sample -from pathlib import Path -from typing import Optional -from aiohttp.client import ClientSession - -from .exceptions import InvalidWriteText - - -TEMP_PATH = Path('.') / 'ATRI' / 'data' / 'temp' -os.makedirs(TEMP_PATH, exist_ok=True) - - -class Request: - @staticmethod - async def get_text(url: str, headers: Optional[dict] = None) -> str: - ''' - 异步方式请求接口 - :return: text - ''' - async with ClientSession() as session: - async with session.get(url, headers=headers) as r: - result = await r.text() - return result - - @staticmethod - async def get_bytes(url: str, headers: Optional[dict] = None) -> bytes: - ''' - 异步方式请求接口 - :return: bytes - ''' - async with ClientSession() as session: - async with session.get(url, headers=headers) as r: - result = await r.read() - return result - - @classmethod - async def get_image(cls, url: str, params: Optional[dict] = None) -> str: - ''' - 异步方式下载图片 - :return: img file - ''' - file_path = TEMP_PATH / 'img' - os.makedirs(file_path, exist_ok=True) - file_name = ''.join(sample(string.ascii_letters + string.digits, 16)) - path = os.path.abspath(file_path) - path = path + f'\\{file_name}.png' - async with ClientSession() as session: - async with session.get(url) as res: - try: - async with aiofiles.open(path, 'wb') as f: - await f.write(await res.read()) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') - return path - - @staticmethod - async def post_bytes(url: str, params: Optional[dict] = None) -> bytes: - ''' - 异步方式 Post 接口 - :return: bytes - ''' - async with ClientSession() as session: - async with session.post(url, params=params) as r: - result = await r.read() - return result
\ No newline at end of file diff --git a/ATRI/rule.py b/ATRI/rule.py index 19930e5..586faf9 100644 --- a/ATRI/rule.py +++ b/ATRI/rule.py @@ -1,106 +1,102 @@ import datetime from random import choice -from nonebot.adapters import Event from nonebot.rule import Rule -from nonebot.adapters.cqhttp import GroupMessageEvent +from nonebot.adapters.cqhttp.event import Event +from nonebot.adapters.cqhttp import GroupMessageEvent, PokeNotifyEvent -from .service.switch import Switch -from .service.banlist import BanList -from .service.dormant import Dormant -from .apscheduler import scheduler, DateTrigger from .config import config -from .utils import count_list, del_list_aim - - -warting_list = [] -fast_user_list = [] +from .service.limit import Limit +from .service.banlist import BanSystem +from .service import Service +from .utils.list import count_list, del_list_aim +from .utils.apscheduler import scheduler, DateTrigger def is_in_service(service: str) -> Rule: async def _is_in_service(bot, event, state) -> bool: if isinstance(event, GroupMessageEvent): - return await Switch.auth_service(service, event.group_id) - return await Switch.auth_service(service) - + return await Limit.auth_service(service, event.group_id) + return await Limit.auth_service(service) + return Rule(_is_in_service) -def is_in_ban_list() -> Rule: - async def _is_in_ban_list(bot, event, state) -> bool: - return BanList.is_in_list(event.get_user_id()) - - return Rule(_is_in_ban_list) +def is_in_banlist() -> Rule: + async def _is_in_banlist(bot, event, state) -> bool: + return BanSystem.is_in_list(str(event.get_user_id())) + + return Rule(_is_in_banlist) def is_in_dormant() -> Rule: async def _is_in_dormant(bot, event, state) -> bool: - return Dormant.is_sleep() - - return Rule(_is_in_dormant) - -def is_max_times(max_times: int, time_day: int, - time_hour: int, time_min: int) -> Rule: - async def _is_max_times(bot, event: Event, state) -> bool: - global warting_list - user = event.get_user_id() - if user in warting_list: - return False - - - - - return True + return Service.is_dormant() - return Rule(_is_max_times) + return Rule(_is_in_dormant) -def is_too_fast(times: int, _type: str) -> Rule: - def remove_list(user: str) -> None: - global fast_user_list - fast_user_list = del_list_aim(fast_user_list, user) - - async def _is_too_fast(bot, event: Event, state) -> bool: - global fast_user_list +exciting_user = [] +exciting_repo = [ + "歇歇8,。咱8能再快了", + "太快惹,太快惹嗯", + "你吼辣么快干什么!", + "其实吧我觉得你这速度去d个vup挺适合", + "我不接受!你太快了", + "我有点担心,因为你太快了", + "请稍等!您冲得太快了!" +] + +def is_too_exciting(times: int) -> Rule: + def del_list(user: str) -> None: + global exciting_user + exciting_user = del_list_aim(exciting_user, user) + + async def _is_too_exciting(bot, event, state) -> bool: + global exciting_user user = event.get_user_id() - - if user in fast_user_list: + + if user in exciting_user: await bot.send( - event, choice(config['bot']['session_waiting_repo'])) + event, + choice(exciting_repo) + ) return False else: - if count_list(fast_user_list, user) == times: + if count_list(exciting_user, user) == times: delta = datetime.timedelta( - seconds=config['bot']['session_waiting_time']) + seconds=config["BotSelfConfig"]["session_exciting_time"]) trigger = DateTrigger( run_date=datetime.datetime.now() + delta) scheduler.add_job( - func=remove_list, + func=del_list, trigger=trigger, args=(user,), misfire_grace_time=1, ) - + await bot.send( - event, choice(config['bot']['session_waiting_repo'])) + event, + choice(exciting_repo) + ) return False else: - fast_user_list.append(user) + exciting_user.append(user) return True - return Rule(_is_too_fast) + return Rule(_is_too_exciting) def to_bot() -> Rule: - async def _to_bot(bot, event: Event, state) -> bool: + async def _to_bot(bot, event, state) -> bool: return event.is_tome() return Rule(_to_bot) -def poke() -> Rule: - async def _poke(bot, event, state) -> bool: - return True if event.is_tome() else False - - return Rule(_poke) +def poke(bot, event: PokeNotifyEvent, state): + if event.is_tome(): + return True + else: + return False diff --git a/ATRI/service/__init__.py b/ATRI/service/__init__.py index 5dddb97..6b18ba1 100644 --- a/ATRI/service/__init__.py +++ b/ATRI/service/__init__.py @@ -1,10 +1,95 @@ import os +import json from pathlib import Path +from pydantic import BaseModel +from typing import Optional +from ATRI.log import logger +from ATRI.exceptions import WriteError -SERVICE_PATH = Path('.') / 'ATRI' / 'data' / 'service' -ERROR_PATH = Path('.') / 'ATRI' / 'data' / 'error' -os.makedirs(SERVICE_PATH, exist_ok=True) -os.makedirs(ERROR_PATH, exist_ok=True) -state = 0 +SERVICE_DIR = Path('.') / 'ATRI' / 'data' / 'service' +PLUGIN_INFO_DIR = Path('.') / 'ATRI' / 'data' / 'service' / 'plugins' +os.makedirs(SERVICE_DIR, exist_ok=True) +os.makedirs(PLUGIN_INFO_DIR, exist_ok=True) + +sleep = False + +class Service: + class ServiceInfo(BaseModel): + name: str + _type: str + docs: Optional[str] = None + command: Optional[list] = None + + @classmethod + def register( + cls, + service_name: str, + service_type: str, + docs: Optional[str] = None, + command: Optional[list] = None + ) -> None: + """ + 启动时保存各个服务信息,便于后续网页控制台调用 + 增强管理 + """ + file_name = f"{service_name}.function.json" + path = SERVICE_DIR / file_name + path.parent.mkdir(exist_ok=True, parents=True) + try: + data = json.loads(path.read_bytes()) + except: + data = {} + + data = cls.ServiceInfo( + name=service_name, + _type=service_type, + docs=docs, + command=command + ) + try: + with open(path, 'w', encoding='utf-8') as target: + target.write( + json.dumps( + data.dict(), indent=4 + ) + ) + except WriteError: + raise WriteError("Writing file failed!") + else: + pass + + # TODO: shitcode-style + docs_judge = "N" if not docs else "Y" + a = " " + log_center = "" + log_head = f"Success register service: [{service_name}]." + log_suffix = f"Docs [{docs_judge}]. Type [{service_type}]" + log_head_lenght = len(log_head) + log_suffix_lenght = len(log_suffix) + log_center_lenght = 120 - ( + log_head_lenght + log_suffix_lenght + ) + for _ in range(log_center_lenght): log_center = log_center + a + log_print = log_head + log_center + log_suffix + logger.info(log_print) + + @staticmethod + def is_dormant() -> bool: + """ + 为bot提供休眠,期间不会响应除了 superusers 以外的用户的信息 + 触发在于 Rule + """ + return False if sleep else True + + @staticmethod + def control_dormant(_type: bool) -> None: + """ + 更改休眠状态 + """ + global sleep + if _type: + sleep = True + else: + sleep = False diff --git a/ATRI/service/banlist.py b/ATRI/service/banlist.py index 06cc381..e1ce6b7 100644 --- a/ATRI/service/banlist.py +++ b/ATRI/service/banlist.py @@ -2,32 +2,32 @@ import json import aiofiles from typing import Optional -from ATRI.exceptions import InvalidWriteText +from ATRI.exceptions import WriteError +from . import SERVICE_DIR -from . import SERVICE_PATH - -class BanList: - filename = 'banlist.service.json' - path = SERVICE_PATH / filename +class BanSystem: + + file_name = "banlist.service.json" + path = SERVICE_DIR / file_name path.parent.mkdir(exist_ok=True, parents=True) try: data = json.loads(path.read_bytes()) except: data = {} - + @classmethod - def get_banlist(cls) -> dict: + def get_list(cls) -> dict: return cls.data - + @classmethod def is_in_list(cls, user: Optional[str]) -> bool: return False if user in cls.data else True @classmethod - async def add_list(cls, user: Optional[str]) -> None: + async def add_to_list(cls, user: Optional[str]) -> None: + cls.data[user] = user try: - cls.data[user] = user async with aiofiles.open( cls.path, 'w', encoding='utf-8') as target: await target.write( @@ -35,13 +35,13 @@ class BanList: cls.data, indent=4 ) ) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') - + except WriteError: + raise WriteError("Writing file failed!") + @classmethod - async def del_list(cls, user: Optional[str]) -> None: + async def del_from_list(cls, user: Optional[str]) -> None: + del cls.data[user] try: - del cls.data[user] async with aiofiles.open( cls.path, 'w', encoding='utf-8') as target: await target.write( @@ -49,5 +49,5 @@ class BanList: cls.data, indent=4 ) ) - except InvalidWriteText: - raise InvalidWriteText('List writing file failed!') + except WriteError: + raise WriteError("Writing file failed!") diff --git a/ATRI/service/dormant.py b/ATRI/service/dormant.py deleted file mode 100644 index 7482d53..0000000 --- a/ATRI/service/dormant.py +++ /dev/null @@ -1,19 +0,0 @@ -from ATRI.exceptions import InvalidSetting - -from . import state - -class Dormant: - @staticmethod - def is_sleep() -> bool: - return True if state != 1 else False - - @staticmethod - def cont_wake(_type: bool) -> None: - global state - try: - if _type: - state = 0 - else: - state = 1 - except InvalidSetting: - raise InvalidSetting('Failed to modify variable!') diff --git a/ATRI/service/httppost.py b/ATRI/service/httppost.py index 9469115..75aff8f 100644 --- a/ATRI/service/httppost.py +++ b/ATRI/service/httppost.py @@ -2,18 +2,24 @@ 获取更多帮助 >> https://github.com/howmanybots/onebot/blob/master/v11/specs/api/public.md ''' import json -from typing import Optional, Union, Dict, Any +from typing import ( + Optional, + Union, + Dict, + Any +) from ATRI.log import logger from ATRI.config import config -from ATRI.request import Request +from ATRI.utils.request import post_bytes URL = ( - f"http://{config['http_post']['host']}:" - f"{config['http_post']['port']}/" + f"http://{config['HttpPost']['host']}:" + f"{config['HttpPost']['port']}/" ) + class HttpPost: @classmethod @@ -27,17 +33,17 @@ class HttpPost: "message": message, "auto_escape": f"{auto_escape}" } - result = json.loads(await Request.post_bytes(url, params)) + result = json.loads(await post_bytes(url, params)) logger.debug(result) return result - + @classmethod def send_group_msg(cls, group_id: int, message: Union[str], auto_escape: Optional[bool] = ...) -> Dict[str, Any]: ... - + @classmethod def send_msg(cls, message_type: Optional[str] = ..., @@ -46,42 +52,42 @@ class HttpPost: message = Union[str], auto_escape: bool = ...) -> Dict[str, Any]: ... - + @classmethod def delete_msg(cls, message_id: int): ... - + @classmethod def get_msg(cls, message_id: int) -> Dict[str, Any]: ... - + @classmethod def get_forward_msg(cls, id: int): ... - + @classmethod def send_like(cls, user_id: int, times: int = ...): ... - + @classmethod def set_group_kick(cls, group_id: int, user_id: int, reject_add_request: bool = ...): ... - + @classmethod def set_group_ban(cls, group_id: int, user_id: int, duration: int = ...): ... - + @classmethod def set_group_anonymous_ban(cls, group_id: int, @@ -89,20 +95,20 @@ class HttpPost: flag: Optional[str] = ..., duration: int = ...): ... - + @classmethod def set_group_whole_ban(cls, group_id: int, enable: bool = ...): ... - + @classmethod def set_group_admin(cls, group_id: int, user_id: int, enable: bool = ...): ... - + @classmethod def set_group_anonymous(cls, group_id: int, @@ -208,4 +214,3 @@ class HttpPost: @classmethod def clean_cache(cls): ... -
\ No newline at end of file diff --git a/ATRI/service/limit.py b/ATRI/service/limit.py new file mode 100644 index 0000000..d5a8a04 --- /dev/null +++ b/ATRI/service/limit.py @@ -0,0 +1,78 @@ +import json +import aiofiles + +from ATRI.exceptions import WriteError +from . import SERVICE_DIR + + +class Limit: + + file_name = "limit.service.json" + path = SERVICE_DIR / file_name + path.parent.mkdir(exist_ok=True, parents=True) + try: + data = json.loads(path.read_bytes()) + except: + data = {} + + @classmethod + def _filling_service(cls, service, group: int = None): + # Determine whether the service exists in global variables. + if service not in cls.data["global"]: + cls.data["global"][service] = True + # Similary, for group. + if service not in cls.data[group]: + cls.data[group][service] = True + + + @classmethod + def get_service(cls) -> dict: + return cls.data + + @classmethod + async def auth_service( + cls, service: str, group: int = None) -> bool: + cls.data.setdefault("global", {}) + cls.data.setdefault(group, {}) + cls._filling_service(service, group) + + try: + async with aiofiles.open( + cls.path, 'w', encoding='utf-8') as target: + await target.write( + json.dumps( + cls.data + ) + ) + except WriteError: + raise WriteError("Writing file failed!") + + if cls.data["global"][service]: + return True if cls.data[group][service] else False + else: + return False + + @classmethod + async def control_service( + cls, + service: str, + status: bool, + group: int = None + ) -> None: + cls._filling_service(service, group) + + if group: + cls.data[group][service] = status + else: + cls.data["global"][service] = status + + try: + async with aiofiles.open( + cls.path, 'w', encoding='utf-8') as target: + await target.write( + json.dumps( + cls.data + ) + ) + except WriteError: + raise WriteError("Writing file failed!") diff --git a/ATRI/service/plugin.py b/ATRI/service/plugin.py deleted file mode 100644 index e14ef34..0000000 --- a/ATRI/service/plugin.py +++ /dev/null @@ -1,60 +0,0 @@ -import json -from typing import Optional -from pydantic import BaseModel - -from ATRI.log import logger -from ATRI.exceptions import InvalidWriteText - -from . import SERVICE_PATH - - -class Plugin: - class PluginInfo(BaseModel): - name: str - _type: str - docs: Optional[str] = None - command: list - - @classmethod - def register(cls, plugin_name: str, _type: str, - doc: Optional[str] = None, - command: Optional[list] = None) -> None: - filename = f'{plugin_name}.plugins.json' - path = SERVICE_PATH / 'plugins' / filename - path.parent.mkdir(exist_ok=True, parents=True) - try: - data = json.loads(path.read_bytes()) - except: - data = {} - - data = cls.PluginInfo( - name=plugin_name, - _type=_type, - docs=doc, - command=command - ) - try: - with open(path, 'w', encoding='utf-8') as target: - target.write( - json.dumps( - data.dict(), indent=4 - ) - ) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') - else: - pass - docs_judge = "N" if not doc else "Y" - - a = ' ' - log_center = '' - log_head = f"Success register plugin: [{plugin_name}]." - log_suffix = f"Docs [{docs_judge}]. Type [{_type}]" - log_head_lenght = len(log_head) - log_suffix_lenght = len(log_suffix) - log_center_lenght = 120 - ( - log_head_lenght + log_suffix_lenght - ) - for _ in range(log_center_lenght): log_center = log_center + a - log_print = log_head + log_center + log_suffix - logger.info(log_print) diff --git a/ATRI/service/send.py b/ATRI/service/send.py deleted file mode 100644 index 9b9c3f9..0000000 --- a/ATRI/service/send.py +++ /dev/null @@ -1,13 +0,0 @@ -from nonebot.adapters.cqhttp import Bot - - -class Send: - @staticmethod - async def send_to_superuser(message: str) -> None: - from ATRI.config import RUNTIME_CONFIG - async def _send_to_superuser(bot: Bot) -> None: - for sup in RUNTIME_CONFIG['superusers']: - await bot.send_private_msg( - user_id=sup, - message=message - ) diff --git a/ATRI/service/switch.py b/ATRI/service/switch.py deleted file mode 100644 index b97a0ec..0000000 --- a/ATRI/service/switch.py +++ /dev/null @@ -1,79 +0,0 @@ -import json -import aiofiles -from typing import Optional - -from ATRI.exceptions import InvalidWriteText - -from . import SERVICE_PATH - - -class Switch: - filename = 'switch.service.json' - path = SERVICE_PATH / filename - path.parent.mkdir(exist_ok=True, parents=True) - try: - data = json.loads(path.read_bytes()) - except: - data = {} - - @classmethod - def get_service(cls) -> dict: - return cls.data - - @classmethod - async def auth_service( - cls, service: str, group: Optional[int] = None) -> bool: - cls.data.setdefault('global', {}) - cls.data.setdefault(group, {}) - if service not in cls.data['global']: - cls.data['global'][service] = True - if service not in cls.data[group]: - cls.data[group][service] = True - try: - async with aiofiles.open( - cls.path, 'w', encoding='utf-8') as target: - await target.write( - json.dumps( - cls.data, indent=4 - ) - ) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') - else: - pass - - if cls.data['global'][service]: - return True if cls.data[group][service] else False - else: - return False - - @classmethod - async def control_service(cls, service: str, _type: bool, - group: Optional[str]) -> None: - if service not in cls.data: - cls.data['global'][service] = True - cls.data[group][service] = True - try: - async with aiofiles.open( - cls.path, 'w', encoding='utf-8') as target: - await target.write( - json.dumps( - cls.data, indent=4 - ) - ) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') - if group: - cls.data[group][service] = _type - else: - cls.data['global'][service] = _type - try: - async with aiofiles.open( - cls.path, 'w', encoding='utf-8') as target: - await target.write( - json.dumps( - cls.data, indent=4 - ) - ) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') diff --git a/ATRI/service/temp.py b/ATRI/service/temp.py deleted file mode 100644 index 2b73fdc..0000000 --- a/ATRI/service/temp.py +++ /dev/null @@ -1,6 +0,0 @@ -import os -from pathlib import Path - - -TEMP_PATH = Path('.') / 'ATRI' / 'data' / 'temp' / 'img' -os.makedirs(TEMP_PATH, exist_ok=True) diff --git a/ATRI/syncer.py b/ATRI/syncer.py deleted file mode 100644 index b4c59b1..0000000 --- a/ATRI/syncer.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -import asyncio -import inspect -import types -from functools import singledispatch, wraps - -from typing import Any, Callable, Generator - - -PY37 = sys.version_info >= (3, 7) - - -def _is_awaitable(co: Generator[Any, None, Any]) -> bool: - if PY37: - return inspect.isawaitable(co) - else: - return (isinstance(co, types.GeneratorType) or - isinstance(co, asyncio.Future)) - - -@singledispatch -def sync(co: Any) -> Any: - raise TypeError(f'Called with unsupported argument: {co}') - - [email protected](asyncio.Future) [email protected](types.GeneratorType) -def sync_co(co: Generator[Any, None, Any]) -> Any: - if not _is_awaitable(co): - raise TypeError(f'Called with unsupported argument: {co}') - return asyncio.get_event_loop().run_until_complete(co) - - [email protected](types.FunctionType) [email protected](types.MethodType) # type: ignore -def sync_fu(f: Callable[..., Any]) -> Callable[..., Any]: - if not asyncio.iscoroutinefunction(f): - raise TypeError(f'Called with unsupported argument: {f}') - - @wraps(f) - def run(*args, **kwargs) -> Any: - return asyncio.get_event_loop().run_until_complete(f(*args, **kwargs)) - return run - - -if PY37: - sync.register(types.CoroutineType)(sync_co) diff --git a/ATRI/utils.py b/ATRI/utils.py deleted file mode 100644 index 961487c..0000000 --- a/ATRI/utils.py +++ /dev/null @@ -1,74 +0,0 @@ -import os -import yaml -from datetime import datetime -from pathlib import Path -from PIL import ImageFile -import PIL.Image as Image - -from .exceptions import InvalidWriteText - - -def load_yaml(file: Path) -> dict: - ''' - 读取yaml文件 - :return: dict - ''' - with open(file, 'r', encoding='utf-8') as f: - data = yaml.safe_load(f) - return data - - -def count_list(lst: list, aim) -> int: - ''' - 检查某列表中目标出现的次数 - :return: int - ''' - count = 0 - for ele in lst: - if ele == aim: - count = count + 1 - return count - - -def del_list_aim(lst: list, aim) -> list: - ''' - 删除某列表中所有目标元素 - :return: list - ''' - while aim in lst: - lst.remove(aim) - return lst - - -def now_time() -> float: - ''' - 获取当前时间(小时) - :return: float - ''' - now_ = datetime.now() - hour = now_.hour - minute = now_.minute - now = hour + minute / 60 - return now - -def compress_image(out_file, kb=500, quality=85, k=0.9) -> str: - ''' - 压缩图片 - :return: img file - ''' - print(1) - o_size = os.path.getsize(out_file) // 1024 - if o_size <= kb: - return out_file - - ImageFile.LOAD_TRUNCATED_IMAGES = True # type: ignore - while o_size > kb: - img = Image.open(out_file) - x, y = img.size - out = img.resize((int(x * k), int(y * k)), Image.ANTIALIAS) - try: - out.save(out_file, quality=quality) - except InvalidWriteText: - raise InvalidWriteText('Writing file failed!') - o_size = os.path.getsize(out_file) // 1024 - return out_file diff --git a/ATRI/plugins/funny/__init__.py b/ATRI/utils/__init__.py index e69de29..e69de29 100644 --- a/ATRI/plugins/funny/__init__.py +++ b/ATRI/utils/__init__.py diff --git a/ATRI/apscheduler.py b/ATRI/utils/apscheduler.py index a56c8ae..2680f19 100644 --- a/ATRI/apscheduler.py +++ b/ATRI/utils/apscheduler.py @@ -1,7 +1,6 @@ # Fork from: https://github.com/nonebot/plugin-apscheduler import logging -from pydantic import Field from apscheduler.schedulers.asyncio import AsyncIOScheduler from nonebot import get_driver, export diff --git a/ATRI/utils/img.py b/ATRI/utils/img.py new file mode 100644 index 0000000..68a44fc --- /dev/null +++ b/ATRI/utils/img.py @@ -0,0 +1,23 @@ +import os +from PIL import ImageFile, Image + +from ATRI.exceptions import WriteError + + +def compress_image(out_file, kb=500, quality=85, k=0.9) -> str: + """将目标图片进行压缩""" + o_size = os.path.getsize(out_file) // 1024 + if o_size <= kb: + return out_file + + ImageFile.LOAD_TRUNCATED_IMAGES = True # type: ignore + while o_size > kb: + img = Image.open(out_file) + x, y = img.size + out = img.resize((int(x * k), int(y * k)), Image.ANTIALIAS) + try: + out.save(out_file, quality=quality) + except WriteError: + raise WriteError('Writing file failed!') + o_size = os.path.getsize(out_file) // 1024 + return out_file diff --git a/ATRI/utils/list.py b/ATRI/utils/list.py new file mode 100644 index 0000000..af6fb76 --- /dev/null +++ b/ATRI/utils/list.py @@ -0,0 +1,14 @@ +def count_list(lst: list, aim) -> int: + """查看指定列表中目标元素所存在的数量""" + count = 0 + for ele in lst: + if ele == aim: + count = count + 1 + return count + + +def del_list_aim(lst: list, aim) -> list: + """删除指定列表中的所有元素""" + while aim in lst: + lst.remove(aim) + return lst diff --git a/ATRI/utils/request.py b/ATRI/utils/request.py new file mode 100644 index 0000000..bf05b56 --- /dev/null +++ b/ATRI/utils/request.py @@ -0,0 +1,26 @@ +from typing import Optional +from aiohttp import ClientSession + + +async def get_text(url: str, headers: Optional[dict] = None) -> str: + """异步以 Get 方式请求 url""" + async with ClientSession() as session: + async with session.get(url, headers=headers) as r: + result = await r.text() + return result + + +async def get_bytes(url: str, headers: Optional[dict] = None) -> bytes: + """异步以 Get 方式请求 url""" + async with ClientSession() as session: + async with session.get(url, headers=headers) as r: + result = await r.read() + return result + + +async def post_bytes(url: str, params: Optional[dict] = None) -> bytes: + """异步以 Post 方式请求 url""" + async with ClientSession() as session: + async with session.post(url, params=params) as r: + result = await r.read() + return result diff --git a/ATRI/utils/time.py b/ATRI/utils/time.py new file mode 100644 index 0000000..5204ea5 --- /dev/null +++ b/ATRI/utils/time.py @@ -0,0 +1,10 @@ +from datetime import datetime + + +def now_time() -> float: + """获取当前小时整数""" + now_ = datetime.now() + hour = now_.hour + minute = now_.minute + now = hour + minute / 60 + return now diff --git a/ATRI/utils/yaml.py b/ATRI/utils/yaml.py new file mode 100644 index 0000000..59e8992 --- /dev/null +++ b/ATRI/utils/yaml.py @@ -0,0 +1,10 @@ +import yaml + +from pathlib import Path + + +def load_yml(file: Path, encoding='utf-8') -> dict: + """加载 yml 文件""" + with open(file, 'r', encoding=encoding) as f: + data = yaml.safe_load(f) + return data diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..befb1d1 --- /dev/null +++ b/config.yml @@ -0,0 +1,14 @@ +BotSelfConfig: + host: "127.0.0.1" + port: 8080 + debug: true + superusers: ["1234567890"] + nickname: ["ATRI", "Atri", "atri", "亚托莉", "アトリ"] + command_start: ["", "/"] + command_sep: ["."] + session_expire_timeout: 3 + session_exciting_time: 3 + +HttpPost: + host: "127.0.0.1" + port: 8081
\ No newline at end of file @@ -3,11 +3,11 @@ ''' @File : main.py -@Time : 2021/01/27 15:57:26 +@Time : 2021/02/02 15:51:44 @Author : Kyomotoi @Contact : [email protected] @Github : https://github.com/Kyomotoi -@License : Copyright © 2021 Kyomotoi, All Rights Reserved. +@License : Copyright © 2018-2021 Kyomotoi, All Rights Reserved. ''' __author__ = 'kyomotoi' @@ -17,8 +17,8 @@ from os import get_terminal_size import nonebot from nonebot.adapters.cqhttp import Bot as CQHTTPBot -from nonebot.log import logger -from ATRI.config import COPYRIGHT, RUNTIME_CONFIG, VERSION +from ATRI.log import logger +from ATRI.config import RUNTIME_CONFIG, COPYRIGHT, VERSION try: @@ -32,8 +32,13 @@ driver = nonebot.get_driver() driver.register_adapter("cqhttp", CQHTTPBot) nonebot.load_plugins('ATRI/plugins') + if __name__ == "__main__": - logger.warning("\n".join(i.center(width) for i in COPYRIGHT.splitlines())) + logger.warning( + '\n'.join( + i.center(width) for i in COPYRIGHT.splitlines() + ) + ) logger.info(f"Now running: {VERSION}") sleep(3) nonebot.run(app='main:app') |