summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ATRI/__init__.py61
-rw-r--r--ATRI/config.py86
-rw-r--r--ATRI/config/character.plugin.yml211
-rw-r--r--ATRI/config/curse.plugin.yml9
-rw-r--r--ATRI/config/genshin.plugin.yml4
-rw-r--r--ATRI/config/hitokoto.plugin.yml13
-rw-r--r--ATRI/config/main.config.yml44
-rw-r--r--ATRI/config/setu.plguin.yml15
-rw-r--r--ATRI/config/utils.plugin.yml13
-rw-r--r--ATRI/data/database/funny/laugh.txt133
-rw-r--r--ATRI/data/emoji/error.jpgbin28209 -> 0 bytes
-rw-r--r--ATRI/exceptions.py208
-rw-r--r--ATRI/log.py82
-rw-r--r--ATRI/plugins/admin.py146
-rw-r--r--ATRI/plugins/admin/__init__.py7
-rw-r--r--ATRI/plugins/admin/data_source.py0
-rw-r--r--ATRI/plugins/character.py219
-rw-r--r--ATRI/plugins/curse.py55
-rw-r--r--ATRI/plugins/curse/__init__.py48
-rw-r--r--ATRI/plugins/essential.py297
-rw-r--r--ATRI/plugins/funny.py47
-rw-r--r--ATRI/plugins/hitokoto.py106
-rw-r--r--ATRI/plugins/setu/__init__.py77
-rw-r--r--ATRI/plugins/setu/data_source.py27
-rw-r--r--ATRI/plugins/utils/__init__.py76
-rw-r--r--ATRI/plugins/utils/data_source.py240
-rw-r--r--ATRI/plugins/utils/main.binbin3992353 -> 0 bytes
-rw-r--r--ATRI/request.py68
-rw-r--r--ATRI/rule.py114
-rw-r--r--ATRI/service/__init__.py95
-rw-r--r--ATRI/service/banlist.py36
-rw-r--r--ATRI/service/dormant.py19
-rw-r--r--ATRI/service/httppost.py41
-rw-r--r--ATRI/service/limit.py78
-rw-r--r--ATRI/service/plugin.py60
-rw-r--r--ATRI/service/send.py13
-rw-r--r--ATRI/service/switch.py79
-rw-r--r--ATRI/service/temp.py6
-rw-r--r--ATRI/syncer.py47
-rw-r--r--ATRI/utils.py74
-rw-r--r--ATRI/utils/__init__.py (renamed from ATRI/plugins/funny/__init__.py)0
-rw-r--r--ATRI/utils/apscheduler.py (renamed from ATRI/apscheduler.py)1
-rw-r--r--ATRI/utils/img.py23
-rw-r--r--ATRI/utils/list.py14
-rw-r--r--ATRI/utils/request.py26
-rw-r--r--ATRI/utils/time.py10
-rw-r--r--ATRI/utils/yaml.py10
-rw-r--r--config.yml14
-rw-r--r--main.py15
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'
-
-async def startup_event() -> None:
- logger.info('アトリは、高性能ですから!')
- check_config()
-
-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
deleted file mode 100644
index fd29713..0000000
--- a/ATRI/data/emoji/error.jpg
+++ /dev/null
Binary files differ
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'
+
+async def startup() -> None:
+ logger.info("アトリは、高性能ですから!")
+
+
+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
deleted file mode 100644
index 6e74a60..0000000
--- a/ATRI/plugins/utils/main.bin
+++ /dev/null
Binary files differ
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
diff --git a/main.py b/main.py
index 4819a20..1d3afbe 100644
--- a/main.py
+++ b/main.py
@@ -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')