diff --git a/.gitignore b/.gitignore index d86aec13..1dad476d 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ mcvrss.txt assets/usercard/*.png test.py assets/Favicon/**/*.png -assets/cache/* \ No newline at end of file +assets/cache/* +save.db +cache/* \ No newline at end of file diff --git a/CommandGen.py b/CommandGen.py deleted file mode 100644 index aa27944a..00000000 --- a/CommandGen.py +++ /dev/null @@ -1,100 +0,0 @@ -import re - -ignorelist = [] - -from commandlist import commandlist - -clist = commandlist() - - -async def findcommand(str1, group=0): - str1 = re.sub(r'^~', '~', str1) - q = re.match(r'^.*(:\n~)(.*)', str1) - if q: - return q.group(2) - q = re.match(r'^~(.*)', str1) - if q: - return q.group(1) - q = re.match(r'^!(.*\-.*)', str1) - if q: - q = str.upper(q.group(1)) - return 'bug ' + q - -async def command(text, group=0): - result = await findcommand(text, group) - c = result - if c != None: - try: - d = result.split(' ') - d = d[0] - except Exception: - d = c - if d in clist: - k = clist.get(d) - k1 = re.match(r'from (.*) import (.*)\|(.*)', k) - if k1: - cmd = eval( - f'__import__("modules.{k1.group(1)}", fromlist=["{k1.group(1)}"]).{k1.group(2)}().{k1.group(3)}') - if d == c: - return await cmd() - else: - c = re.sub(r'^'+d+' ','',c) - return await cmd(c) - else: - k2 = re.match(r'from (.*) import (.*)', k) - if k2: - cmd = eval(f'__import__("modules.{k2.group(1)}", fromlist=["{k2.group(1)}"]).{k2.group(2)}') - if d == c: - return await cmd() - else: - c = re.sub(r'^' + d + ' ', '', c) - return await cmd(c) - else: - a = __import__('modules.' + k, fromlist=[k]) - if d == c: - return await a.main() - else: - c = re.sub(r'^' + d + ' ', '', c) - return await a.main(c) - - -async def ttext(text, group=0): - if text.find('[Webhook]') != -1: - pass - else: - w = re.findall(r'\[\[(.*?)\]\]', text, re.I) - w2 = re.findall(r'\{\{(.*?)\}\}', text, re.I) - z = [] - c = '\n' - if w: - from modules.wiki import im - wi1 = [] - if str(w) != '['']' or str(w) != '[]': - for x in w: - if x == '' or x in wi1: - pass - else: - wi1.append(x) - if wi1 != []: - z.append(await im(wi1)) - if w2: - from modules.wiki import imt - wi2 = [] - if str(w2) != '['']' or str(w2) != '[]': - for x in w2: - if x == '' or x in wi2: - pass - else: - wi2.append(x) - if wi2 != []: - z.append(await imt(wi2)) - w3 = re.findall(r'(https://bugs.mojang.com/browse/.*?-\d*)', text) - for link in w3: - matchbug = re.match(r'https://bugs.mojang.com/browse/(.*?-\d*)',link) - if matchbug: - import modules.bug - z.append(await modules.bug.main(matchbug.group(1))) - if str(z): - v = c.join(z) - if v != '': - return v diff --git a/MessageGen.py b/MessageGen.py deleted file mode 100644 index 75a2b5c4..00000000 --- a/MessageGen.py +++ /dev/null @@ -1,154 +0,0 @@ -import asyncio -import os -import random -import re -import traceback -from os.path import abspath - -import graia.application.interrupt as inter -from graia.application.message.chain import MessageChain -from graia.application.message.elements.internal import Plain, Image, Source - -from modules.findimage import findimage - -try: - cachepath = abspath('./assets/cache/') - cachefile = os.listdir(cachepath) - for file in cachefile: - os.remove(f'{cachepath}/{file}') -except Exception: - pass - - -async def gen(bcc, app, message, target1, target2='0', msgtype='None', runfun='command'): - im = inter.InterruptControl(bcc) - command = __import__('CommandGen', fromlist=[runfun]) - command = getattr(command, runfun) - if msgtype == 'Group': - run = await command(message.asDisplay(), target1.id) - else: - run = await command(message.asDisplay()) - # print(run) - if run != None: - await msgproc(run, app, im, command, message, target1, target2, msgtype) - - -async def msgproc(resultmsgraw, app, im, command, message, target1, target2='0', msgtype='None'): - print(resultmsgraw) - msgchain = await makemsgchain(resultmsgraw) - send = await sendmessage(app, msgchain, target1, target2, msgtype, - message[Source][0] if msgtype == 'Group' else 0) - uimgcs = re.findall(r'\[\[uimgc:.*\]\]', resultmsgraw, re.I | re.M) - for uimgc in uimgcs: - uimgc = re.match(r'\[\[uimgc:(.*)\]\]', uimgc) - if uimgc: - await uimgsend(app, message, target1, target2, msgtype, uimgc.group(1)) - r = re.findall(r'(https?://.*?/File:.*?\.(?:png|gif|jpg|jpeg|webp|bmp|ico))', resultmsgraw, re.I) - for d in r: - d1 = await findimage(d) - if d1 is not None: - await linkimgsend(app, d1, target1, target2, msgtype) - await afterproc(resultmsgraw, app, im, command, send, message, target1, target2, msgtype) - - -async def makemsgchain(msg): - msg = re.sub('\[wait\]', '', msg) - msgbase = re.sub(r'\[\[uimgc:.*\]\]', '', msg) - msgchain = MessageChain.create([Plain(msgbase)]) - return msgchain - - -async def afterproc(resultmsgraw, app, im, command, send, message, target1, target2='0', msgtype='None'): - if resultmsgraw.find('[一分钟后撤回本消息]') != -1: - await asyncio.sleep(60) - await app.revokeMessage(send) - if resultmsgraw.find('[30秒后撤回本消息]') != -1: - await asyncio.sleep(30) - await app.revokeMessage(send) - if resultmsgraw.find('[wait]') != -1: - ranint = random.randint(1, 3) - if ranint == 2: - waitmsg = await makemsgchain('提示:你可以发送“是”字来将所有无效结果再次查询。(考虑到实现复杂性,恕不提供选择性查询)') - await sendmessage(app, waitmsg, target1, target2, msgtype) - MessageEventImport = __import__('graia.application', fromlist=[f'{msgtype}Message']) - MessageEvent = getattr(MessageEventImport, f'{msgtype}Message') - InterruptImport = __import__('graia.application.interrupt.interrupts', - fromlist=[f'{msgtype}MessageInterrupt']) - Interrupt = getattr(InterruptImport, f'{msgtype}MessageInterrupt') - if msgtype == 'Friend': - event: MessageEvent = await im.wait(Interrupt(target1.id)) - else: - event: MessageEvent = await im.wait(Interrupt(target1, target2)) - print(event) - if event.messageChain.asDisplay() == '是': - msg2 = await command(resultmsgraw) - await msgproc(msg2, app, im, command, message, target1, target2, msgtype) - else: - pass - - -async def uimgsend(app, message, target1, target2, msgtype, link): - exec('from graia.application.message.elements.internal import UploadMethods') - mth = eval(f'UploadMethods.{msgtype}') - try: - msgchain = MessageChain.create( - [Image.fromLocalFile(filepath=abspath(link), method=mth)]) - print('Sending Image...') - await sendmessage(app, msgchain, target1, target2, msgtype, - message[Source][0] if msgtype == 'Group' else 0) - except Exception: - traceback.print_exc() - msgchain = MessageChain.create( - [Plain('上传过程中遇到了问题,图片发送失败。')]) - await sendmessage(app, msgchain, target1, target2, msgtype, - message[Source][0] if msgtype == 'Group' else 0) - - -async def linkimgsend(app, sendlink, target1, target2, msgtype): - exec('from graia.application.message.elements.internal import UploadMethods') - mth = eval(f'UploadMethods.{msgtype}') - try: - msgchain = MessageChain.create([Image.fromNetworkAddress(url=sendlink, method=mth)]) - print('Sending Image...') - await sendmessage(app, msgchain, target1, target2, msgtype) - except Exception: - traceback.print_exc() - msgchain = MessageChain.create( - [Plain('上传过程中遇到了问题,图片发送失败。')]) - await sendmessage(app, msgchain, target1, target2, msgtype) - - -async def sendmessage(app, msgchain, target1, target2, msgtype, quoteid=0): - if msgtype == 'Friend': - friend = target1 - send = await app.sendFriendMessage(friend, msgchain.asSendable()) - if msgtype == 'Group': - group = target1 - send = await app.sendGroupMessage(group, msgchain.asSendable(), quote=quoteid if quoteid != 0 else None) - if msgtype == 'Temp': - group = target1 - member = target2 - send = await app.sendTempMessage(group=group, target=member, message=msgchain.asSendable()) - return send - - -""" -if msgtype == 'Group': - voice = re.findall(r'https?://.*?/File:.*?\.(?:ogg|m4a|mp3|flac|wav)', run, re.I) - for voicelink in voice: - try: - findvoicename = re.match(r'(https?://.*?/)File:(.*?\.(?:ogg|m4a|mp3|flac|wav))', voicelink, re.I) - downloadfile = await dfile(findvoicename.group(1), findvoicename.group(2)) - print(downloadfile) - conventamr = await camr(downloadfile) - print(conventamr) - readfile = open(conventamr, 'rb+') - uploadvoice = await app.uploadVoice(readfile.read()) - voicemsgchain = MessageChain.create([uploadvoice]) - await app.sendGroupMessage(target1, voicemsgchain) - readfile.close() - os.remove(downloadfile) - os.remove(conventamr) - except Exception: - traceback.print_exc() -""" diff --git a/assets/cache/296b3cef-8801-430e-afd1-fe5b16d7cdcb b/assets/cache/296b3cef-8801-430e-afd1-fe5b16d7cdcb deleted file mode 100644 index 5a6b1371..00000000 Binary files a/assets/cache/296b3cef-8801-430e-afd1-fe5b16d7cdcb and /dev/null differ diff --git a/assets/chromedriver.exe b/assets/chromedriver.exe new file mode 100644 index 00000000..805fd953 Binary files /dev/null and b/assets/chromedriver.exe differ diff --git a/assets/infoboxfix.css b/assets/infoboxfix.css new file mode 100644 index 00000000..633dbdec --- /dev/null +++ b/assets/infoboxfix.css @@ -0,0 +1,15 @@ +html body { + margin-top: 0px !important; +} + +div.infobox div.notaninfobox { + width: 100% !important; + float: none !important; + margin: 0 0 0 0 !important; +} + +table.infobox { + width: 100% !important; + float: unset !important; + margin: 0 0 0 0 !important; +} \ No newline at end of file diff --git a/assets/mcversion_jira.txt b/assets/mcversion_jira.txt new file mode 100644 index 00000000..53ccae96 --- /dev/null +++ b/assets/mcversion_jira.txt @@ -0,0 +1,4 @@ + +21w03a +1.16.5 +Future Version - 1.17+ \ No newline at end of file diff --git a/bot.py b/bot.py index 6ef0c2e0..1126bd8b 100644 --- a/bot.py +++ b/bot.py @@ -1,80 +1,43 @@ import asyncio -from graia.application import GraiaMiraiApplication, Session -from graia.application.event.mirai import NewFriendRequestEvent, BotInvitedJoinGroupRequestEvent +from graia.application import GraiaMiraiApplication from graia.application.friend import Friend from graia.application.group import Group, Member from graia.application.message.chain import MessageChain -from graia.broadcast import Broadcast -from MessageGen import gen +from core.broadcast import bcc, app +from core.loader import rss_loader +from core.parser import parser +import os -loop = asyncio.get_event_loop() +cache_path = os.path.abspath('./cache/') +if os.path.exists(cache_path): + for x in os.listdir(cache_path): + os.remove(cache_path + x) + os.removedirs(cache_path) + os.mkdir(cache_path) +else: + os.mkdir(cache_path) -bcc = Broadcast(loop=loop, debug_flag=True) -app = GraiaMiraiApplication( - broadcast=bcc, - enable_chat_log=False, - connect_info=Session( - host="http://localhost:11919", # 填入 httpapi 服务运行的地址 - authKey='1145141919810', # 填入 authKey - account=2926887640, # 你的机器人的 qq 号 - websocket=True # Graia 已经可以根据所配置的消息接收的方式来保证消息接收部分的正常运作. - ) -) +@bcc.receiver('GroupMessage') +async def group_message_handler(message: MessageChain, group: Group, member: Member): + kwargs = {MessageChain: message, Group: group, Member: member} + await parser(kwargs) -@bcc.receiver("GroupMessage") -async def group_message_handler(app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): - await gen(bcc, app, message, group, member, msgtype='Group') +@bcc.receiver('FriendMessage') +async def group_message_handler(message: MessageChain, friend: Friend): + kwargs = {MessageChain: message, Friend: friend} + await parser(kwargs) -@bcc.receiver("GroupMessage") -async def group_message_handler1(app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): - await gen(bcc, app, message, group, member, msgtype='Group', runfun='ttext') - - -@bcc.receiver("FriendMessage") -async def friend_message_handler(app: GraiaMiraiApplication, message: MessageChain, friend: Friend): - await gen(bcc, app, message, friend, msgtype='Friend') - - -@bcc.receiver("FriendMessage") -async def friend_message_handler1(app: GraiaMiraiApplication, message: MessageChain, friend: Friend): - await gen(bcc, app, message, friend, msgtype='Friend', runfun='ttext') - - -@bcc.receiver("TempMessage") -async def temp_message_handler(app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): - await gen(bcc, app, message, group, member, msgtype='Temp') - - -@bcc.receiver("TempMessage") -async def temp_message_handler1(app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): - await gen(bcc, app, message, group, member, msgtype='Temp', runfun='ttext') - - -@bcc.receiver("NewFriendRequestEvent") -async def NFriend(event: NewFriendRequestEvent): - await event.accept() - - -@bcc.receiver("BotInvitedJoinGroupRequestEvent") -async def NGroup(event: BotInvitedJoinGroupRequestEvent): - await event.accept() - - -import subbot - - -@bcc.receiver("ApplicationLaunched") -async def subbot1(app: GraiaMiraiApplication): - await subbot.ver(app) - - -@bcc.receiver("ApplicationLaunched") -async def subbot2(app: GraiaMiraiApplication): - await subbot.newbie(app) +@bcc.receiver('ApplicationLaunched') +async def message_handler(app: GraiaMiraiApplication): + rss_list = rss_loader() + gather_list = [] + for x in rss_list: + gather_list.append(asyncio.ensure_future(rss_list[x](app))) + await asyncio.gather(*gather_list) app.launch_blocking() diff --git a/commandlist.py b/commandlist.py deleted file mode 100644 index d4e6f6a3..00000000 --- a/commandlist.py +++ /dev/null @@ -1,37 +0,0 @@ -def commandlist(): - clist = {} - import os - path = os.path.abspath('./modules') - dirs = os.listdir(path) - - import re - - for file in dirs: - filename = os.path.abspath(f'./modules/{file}') - a1 = None - a2 = None - if os.path.isdir(filename): - if file == '__pycache__': - pass - else: - a1 = file - a2 = file - if os.path.isfile(filename): - b = re.match(r'(.*)(.py)', file) - if b: - a1 = b.group(1) - a2 = b.group(1) - try: - if a1 is not None: - a = __import__('modules.' + a1, fromlist=[a2]) - if isinstance(a.command, dict): - clist.update(a.command) - print(f'Successful loaded {a2} from {a1}! command = {a.command}') - elif isinstance(a.command, tuple): - for x in a.command: - if isinstance(x, dict): - clist.update(x) - print(f'Successful loaded {x.keys()}! command = {x}') - except Exception as e: - print(str(e) + ', skip!') - return clist diff --git a/config/__init__.py b/config/__init__.py index 66c97c64..43b1f3e9 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -1,9 +1,13 @@ from configparser import ConfigParser -from os.path import abspath -def config(q): +def config(path, q): cp = ConfigParser() - cp.read(abspath("./config/config.cfg")) + cp.read(path) section = cp.sections()[0] - return (cp.get(section, q)) + value = cp.get(section, q) + if value.upper() == 'TRUE': + return True + if value.upper() == 'FALSE': + return False + return value diff --git a/core/broadcast.py b/core/broadcast.py new file mode 100644 index 00000000..0c5e29b2 --- /dev/null +++ b/core/broadcast.py @@ -0,0 +1,28 @@ +import asyncio +from os.path import abspath + +from graia.application import GraiaMiraiApplication, Session +from graia.broadcast import Broadcast + +from config import config + +loop = asyncio.get_event_loop() +config_filename = 'config.cfg' +config_path = abspath('./config/' + config_filename) + + +def c(q): + return config(config_path, q) + + +bcc = Broadcast(loop=loop, debug_flag=c('debug_flag')) +app = GraiaMiraiApplication( + broadcast=bcc, + enable_chat_log=c('enable_chat_log'), + connect_info=Session( + host=c('host'), # 填入 httpapi 服务运行的地址 + authKey=c('authkey'), # 填入 authKey + account=c('account'), # 你的机器人的 qq 号 + websocket=c('websocket') # Graia 已经可以根据所配置的消息接收的方式来保证消息接收部分的正常运作. + ) +) diff --git a/modules/pbc.py b/core/dirty_check.py similarity index 89% rename from modules/pbc.py rename to core/dirty_check.py index b98110cf..aaf0868e 100644 --- a/modules/pbc.py +++ b/core/dirty_check.py @@ -3,6 +3,7 @@ import datetime import hashlib import hmac import json +import os.path import time from urllib.parse import urlencode @@ -22,11 +23,13 @@ def computeMD5hash(my_string): return m.hexdigest() -accessKeyId = config("accessKeyId") -accessKeySecret = config("accessKeySecret") - - -async def pbc(text): +async def check(text): + try: + config_path = os.path.abspath('config/config.cfg') + accessKeyId = config(config_path, "Check_accessKeyId") + accessKeySecret = config(config_path, "Check_accessKeySecret") + except Exception: + return '' print('hello') body = { "scenes": [ @@ -38,7 +41,7 @@ async def pbc(text): }, text)) } print(urlencode({ - 'test': 123 + 'we': 123 })) clientInfo = '{}' root = 'https://green.cn-shanghai.aliyuncs.com' @@ -81,6 +84,7 @@ async def pbc(text): async with session.post('{}{}'.format(root, url), data=json.dumps(body)) as resp: if resp.status == 200: result = await resp.json() + print(result) resultUsers = [] for item in result['data']: content = item['content'] @@ -93,13 +97,7 @@ async def pbc(text): else: content = "<全部吃掉了>" resultUsers.append(content) - return (resultUsers) + return ''.join(resultUsers) else: return (await resp.text()) - - -async def pbc1(newUsers): - Users = [] - Users.append(newUsers) - return await pbc(Users) diff --git a/core/loader.py b/core/loader.py new file mode 100644 index 00000000..fc95c506 --- /dev/null +++ b/core/loader.py @@ -0,0 +1,116 @@ +import importlib +import os +import re +import traceback + + +def command_loader(): + fun_file = None + admin_list = {} + essential_list = {} + command_list = {} + help_list = {} + regex_list = {} + self_options_list = [] + options_list = [] + load_dir_path = os.path.abspath('./modules/') + dir_list = os.listdir(load_dir_path) + for file_name in dir_list: + file_path = f'{load_dir_path}/{file_name}' + print(file_path) + if os.path.isdir(file_path): + if file_path != '__pycache__': + fun_file = file_name + if os.path.isfile(file_path): + b = re.match(r'(.*)(.py)', file_path) + if b: + fun_file = b.group(1) + print(fun_file) + try: + if fun_file is not None: + import_fun = importlib.__import__('modules.' + fun_file, fromlist=[fun_file]) + try: + admins = import_fun.admin + if isinstance(admins, dict): + admin_list.update(admins) + print(admins) + except: + traceback.print_exc() + try: + essentials = import_fun.essential + if isinstance(essentials, dict): + essential_list.update(essentials) + print(essentials) + except: + traceback.print_exc() + try: + fun_commands = import_fun.command + if isinstance(fun_commands, dict): + command_list.update(fun_commands) + print(fun_commands) + except: + traceback.print_exc() + try: + fun_help = import_fun.help + if isinstance(fun_help, dict): + help_list.update(fun_help) + print(fun_help) + except: + traceback.print_exc() + try: + fun_regex = import_fun.regex + if isinstance(fun_regex, dict): + regex_list.update(fun_regex) + print(fun_regex) + except: + traceback.print_exc() + try: + fun_self_options = import_fun.self_options + if isinstance(fun_self_options, list): + for x in fun_self_options: + self_options_list.append(x) + print(fun_self_options) + except: + traceback.print_exc() + try: + fun_options = import_fun.options + if isinstance(fun_options, list): + for x in fun_options: + self_options_list.append(x) + print(fun_options) + except: + traceback.print_exc() + except: + traceback.print_exc() + return admin_list, essential_list, command_list, help_list, regex_list, self_options_list, options_list + + +def rss_loader(): + fun_file = None + rss_list = {} + load_dir_path = os.path.abspath('./modules/') + dir_list = os.listdir(load_dir_path) + for file_name in dir_list: + file_path = f'{load_dir_path}/{file_name}' + print(file_path) + if os.path.isdir(file_path): + if file_path != '__pycache__': + fun_file = file_name + if os.path.isfile(file_path): + b = re.match(r'(.*)(.py)', file_path) + if b: + fun_file = b.group(1) + print(fun_file) + try: + if fun_file is not None: + import_fun = importlib.__import__('modules.' + fun_file, fromlist=[fun_file]) + try: + rss = import_fun.rss + if isinstance(rss, dict): + rss_list.update(rss) + print(rss) + except: + traceback.print_exc() + except: + traceback.print_exc() + return rss_list diff --git a/core/parser.py b/core/parser.py new file mode 100644 index 00000000..4d22f5c0 --- /dev/null +++ b/core/parser.py @@ -0,0 +1,79 @@ +import re + +from graia.application import Friend +from graia.application.group import Group, Member +from graia.application.message.chain import MessageChain + +import database +from core.loader import command_loader +from core.template import sendMessage + +admin_list, essential_list, command_list, help_list, regex_list, self_options_list, options_list = command_loader() +print(essential_list) +function_list = [] +for command in command_list: + function_list.append(command) +for reg in regex_list: + function_list.append(reg) +for options in self_options_list: + function_list.append(options) +for options in options_list: + function_list.append(options) +print(function_list) + + +async def parser(kwargs: dict): + display = kwargs[MessageChain].asDisplay() + command_prefix = ['~', '~'] + if Group in kwargs: + trigger = kwargs[Member].id + if Friend in kwargs: + trigger = kwargs[Friend].id + if database.check_black_list(trigger): + if not database.check_white_list(trigger): + return + if display[0] in command_prefix: + command = re.sub(r'^' + display[0], '', display) + command_first_word = command.split(' ')[0] + if command_first_word in command_list: + if Group in kwargs: + check_command_enable = database.check_enable_modules(kwargs[Group].id, command_first_word) + if check_command_enable: + check_command_enable_self = database.check_enable_modules_self(kwargs[Member].id, + command_first_word) + if check_command_enable_self: + kwargs['trigger_msg'] = command + await command_list[command_first_word](kwargs) + else: + await sendMessage(kwargs, f'此模块未启用,请管理员在群内发送~enable {command_first_word}启用本模块。') + else: + check_command_enable_self = database.check_enable_modules_self(kwargs[Friend].id, command_first_word) + if check_command_enable_self: + kwargs['trigger_msg'] = command + await command_list[command_first_word](kwargs) + elif command_first_word in essential_list: + kwargs['trigger_msg'] = command + kwargs['function_list'] = function_list + kwargs['help_list'] = help_list + await essential_list[command_first_word](kwargs) + elif command_first_word in admin_list: + if database.check_superuser(kwargs): + kwargs['trigger_msg'] = command + kwargs['function_list'] = function_list + await admin_list[command_first_word](kwargs) + else: + await sendMessage(kwargs, '权限不足') + # regex + if Group in kwargs: + for regex in regex_list: + check_command_enable = database.check_enable_modules(kwargs[Group].id, + regex) + if check_command_enable: + check_command_enable_self = database.check_enable_modules_self(kwargs[Member].id, regex) + if check_command_enable_self: + await regex_list[regex](kwargs) + if Friend in kwargs: + for regex in regex_list: + check_command_enable_self = database.check_enable_modules_self(kwargs[Friend].id, regex) + if check_command_enable_self: + await regex_list[regex](kwargs) diff --git a/core/template.py b/core/template.py new file mode 100644 index 00000000..06476a38 --- /dev/null +++ b/core/template.py @@ -0,0 +1,98 @@ +import eventlet +from graia.application import MessageChain, GroupMessage, FriendMessage +from graia.application.friend import Friend +from graia.application.group import Group, Member +from graia.application.message.elements.internal import Plain, Image, Source +from graia.broadcast.interrupt import InterruptControl +from graia.broadcast.interrupt.waiter import Waiter + +from core.broadcast import app, bcc +from database import check_superuser + + +async def sendMessage(kwargs: dict, msgchain): + if isinstance(msgchain, str): + msgchain = MessageChain.create([Plain(msgchain)]) + if Group in kwargs: + try: + eventlet.monkey_patch() + with eventlet.Timeout(15): + send = await app.sendGroupMessage(kwargs[Group], msgchain, quote=kwargs[MessageChain][Source][0].id) + return send + except eventlet.timeout.Timeout: + split_msg = msgchain.get(Plain) + sent_msgs = [] + for msgs in split_msg: + send = await app.sendGroupMessage(kwargs[Group], MessageChain.create([msgs]), quote=kwargs[MessageChain][Source][0].id) + sent_msgs.append(send) + split_img = msgchain.get(Image) + for imgs in split_img: + send = await app.sendGroupMessage(kwargs[Group], MessageChain.create([imgs]), quote=kwargs[MessageChain][Source][0].id) + sent_msgs.append(send) + return sent_msgs + if Friend in kwargs: + try: + eventlet.monkey_patch() + with eventlet.Timeout(15): + send = await app.sendFriendMessage(kwargs[Friend], msgchain) + return send + except eventlet.timeout.Timeout: + split_msg = msgchain.get(Plain) + sent_msgs = [] + for msgs in split_msg: + send = await app.sendFriendMessage(kwargs[Friend], MessageChain.create([msgs])) + sent_msgs.append(send) + split_img = msgchain.get(Image) + for imgs in split_img: + send = await app.sendFriendMessage(kwargs[Friend], MessageChain.create([imgs])) + sent_msgs.append(send) + return sent_msgs + + +async def wait_confirm(kwargs: dict): + inc = InterruptControl(bcc) + confirm_command = ["是", "对", 'yes', 'y'] + if Group in kwargs: + @Waiter.create_using_function([GroupMessage]) + def waiter(waiter_group: Group, + waiter_member: Member, waiter_message: MessageChain): + if all([ + waiter_group.id == kwargs[Group].id, + waiter_member.id == kwargs[Member].id, + ]): + print(111) + if waiter_message.asDisplay() in confirm_command: + return True + else: + return False + if Friend in kwargs: + @Waiter.create_using_function([FriendMessage]) + def waiter(waiter_friend: Friend, waiter_message: MessageChain): + if all([ + waiter_friend.id == kwargs[Friend].id, + ]): + if waiter_message.asDisplay() in confirm_command: + return True + else: + return False + + return await inc.wait(waiter) + + +async def revokeMessage(msgchain): + if isinstance(msgchain, list): + for msg in msgchain: + await app.revokeMessage(msg) + else: + await app.revokeMessage(msgchain) + + +def check_permission(kwargs): + if Group in kwargs: + if str(kwargs[Member].permission) in ['MemberPerm.Administrator', 'MemberPerm.Owner'] or check_superuser( + kwargs[Member].id): + return True + if Friend in kwargs: + if check_superuser(kwargs[Friend].id): + return True + return False \ No newline at end of file diff --git a/database/__init__.py b/database/__init__.py new file mode 100644 index 00000000..08288862 --- /dev/null +++ b/database/__init__.py @@ -0,0 +1,277 @@ +import os +import sqlite3 +import traceback + +from graia.application import Group, Friend, Member + +dbpath = os.path.abspath('./database/save.db') + + +def initialize(): + a = open(dbpath, 'w') + a.close() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + c.execute('''CREATE TABLE group_permission + (ID INT PRIMARY KEY NOT NULL, + ENABLE_MODULES TEXT);''') + c.execute('''CREATE TABLE self_permission + (ID INT PRIMARY KEY NOT NULL, + DISABLE_MODULES TEXT);''') + c.execute('''CREATE TABLE black_list + (ID INT PRIMARY KEY NOT NULL);''') + c.execute('''CREATE TABLE white_list + (ID INT PRIMARY KEY NOT NULL);''') + c.execute('''CREATE TABLE warn + (ID INT PRIMARY KEY NOT NULL, + WARN TEXT);''') + c.execute('''CREATE TABLE superuser + (ID INT PRIMARY KEY NOT NULL);''') + c.close() + + +def connect_db(path): + conn = sqlite3.connect(path) + c = conn.cursor() + return c + + +def update_modules(do, id, modules_name, table='group_permission', value='ENABLE_MODULES'): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID={id}").fetchone() + if do == 'add': + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + return '失败:模块已被启用:' + modules_name + else: + enabled_split.append(modules_name) + c.execute(f"UPDATE {table} SET {value}='{'|'.join(enabled_split)}' WHERE ID='{id}'") + conn.commit() + return '成功:启用模块:' + modules_name + else: + c.execute(f"INSERT INTO {table} (ID, {value}) VALUES (?, ?)", (id, modules_name)) + conn.commit() + return '成功:启用模块:' + modules_name + elif do == 'del': + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + enabled_split.remove(modules_name) + c.execute(f"UPDATE {table} SET {value}='{'|'.join(enabled_split)}' WHERE ID='{id}'") + conn.commit() + return '成功:禁用模块:' + modules_name + else: + return '失败:未启用过该模块:' + modules_name + else: + return '失败:未启用过该模块:' + modules_name + + +def update_modules_self(do, id, modules_name, table='self_permission', value='DISABLE_MODULES'): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID={id}").fetchone() + if do == 'del': + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + return '失败:模块已被禁用:' + modules_name + else: + enabled_split.append(modules_name) + c.execute(f"UPDATE {table} SET {value}='{'|'.join(enabled_split)}' WHERE ID='{id}'") + conn.commit() + return '成功:禁用模块:' + modules_name + else: + c.execute(f"INSERT INTO {table} (ID, {value}) VALUES (?, ?)", (id, modules_name)) + conn.commit() + return '成功:禁用模块:' + modules_name + elif do == 'add': + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + enabled_split.remove(modules_name) + c.execute(f"UPDATE {table} SET {value}='{'|'.join(enabled_split)}' WHERE ID='{id}'") + conn.commit() + return '成功:启用模块:' + modules_name + else: + return '失败:未禁用过该模块:' + modules_name + else: + return '失败:未禁用过该模块:' + modules_name + + +def check_enable_modules(kwargs, modules_name, table='group_permission'): + if not os.path.exists(dbpath): + initialize() + if isinstance(kwargs, int): + target = kwargs + else: + if Group in kwargs: + table == 'group_permission' + target = kwargs[Group].id + if Friend in kwargs: + table == 'self_permission' + target = kwargs[Friend].id + if table == 'group_permission': + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID='{target}'").fetchone() + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + return True + else: + return False + else: + return False + if table == 'self_permission': + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID='{target}'").fetchone() + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + return False + else: + return True + else: + return True + + +def check_enable_modules_self(id, modules_name, table='self_permission'): + if not os.path.exists(dbpath): + initialize() + if table == 'self_permission': + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID='{id}'").fetchone() + if a: + enabled_split = a[1].split('|') + if modules_name in enabled_split: + return False + else: + return True + else: + return True + + +def check_enable_modules_all(table, modules_name): + # 检查表中所有匹配的对象,返回一个list + if not os.path.exists(dbpath): + initialize() + enable_target = [] + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table}").fetchall() + for x in a: + enabled_split = x[1].split('|') + if modules_name in enabled_split: + enable_target.append(x[0]) + return enable_target + + +def add_black_list(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + c.execute(f"INSERT INTO black_list (ID) VALUES ('{id}')") + conn.commit() + c.close() + + +def add_white_list(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + c.execute(f"INSERT INTO white_list (ID) VALUES ('{id}')") + conn.commit() + c.close() + + +def check_black_list(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM black_list WHERE ID={id}").fetchone() + if a: + return True + else: + return False + + +def check_white_list(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM white_list WHERE ID={id}").fetchone() + if a: + return True + else: + return False + + +def check_superuser(kwargs: dict): + if not os.path.exists(dbpath): + initialize() + if Group in kwargs: + id = kwargs[Member].id + if Friend in kwargs: + id = kwargs[Friend].id + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM superuser WHERE ID={id}").fetchone() + if a: + return True + else: + return False + + +def add_superuser(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + try: + c.execute(f"INSERT INTO superuser (ID) VALUES ('{id}')") + except: + traceback.print_exc() + conn.commit() + c.close() + return '成功?我也不知道成没成,懒得写判断了(' + + +def del_superuser(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + try: + c.execute(f"DELETE FROM superuser WHERE ID='{id}'") + except: + traceback.print_exc() + conn.commit() + c.close() + return '成功?我也不知道成没成,懒得写判断了(' + + +def warn_someone(id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM warn WHERE ID={id}").fetchone() + if a: + c.execute(f"UPDATE warn SET WARN='{int(a[1]) + 1}' WHERE ID='{id}'") + else: + c.execute(f"INSERT INTO warn (ID, WARN) VALUES (?, ?)", (id, 0,)) + conn.commit() + if int(a[1]) > 5: + add_black_list(id) diff --git a/modules/__init__.py b/modules/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/ab/__init__.py b/modules/ab/__init__.py deleted file mode 100644 index 4dc755ff..00000000 --- a/modules/ab/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding:utf-8 -*- -import json - -import aiohttp - -from modules.UTC8 import UTC8 -from modules.pbc import pbc - - -async def main(): - url = 'https://minecraft-zh.gamepedia.com/api.php?action=query&list=abuselog&aflprop=user|title|action|result|filter|timestamp&format=json' - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as req: - if req.status != 200: - return f"请求时发生错误:{req.status}" - else: - text1 = await req.text() - file = json.loads(text1) - d = [] - for x in file['query']['abuselog'][:5]: - d.append('•' + x['title'] + ' - ' + x['user'] + '于' + UTC8(x['timestamp'], 'onlytimenoutc') + '\n过滤器名:' + x[ - 'filter'] + '\n处理结果:' + x['result']) - y = await pbc(d) - space = '\n' - f = space.join(y) - if f.find('<吃掉了>') != -1 or f.find('<全部吃掉了>') != -1: - return f + '\n...仅显示前5条内容\n检测到外来信息介入,请前往滥用日志查看所有消息。Special:滥用日志\n[一分钟后撤回本消息]' - else: - return f + '\n...仅显示前5条内容\n[一分钟后撤回本消息]' - - -command = {'ab': 'ab'} diff --git a/modules/bug/__init__.py b/modules/bug/__init__.py deleted file mode 100644 index d9ecb97c..00000000 --- a/modules/bug/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import re - -from .bugtracker import bug - - -async def main(name): - q = re.match(r'(.*)\-(.*)', name) - if q: - return (await bug(q.group(1) + '-' + q.group(2))) - - -command = {'bug': 'bug'} diff --git a/modules/bugtracker/__init__.py b/modules/bugtracker/__init__.py new file mode 100644 index 00000000..9dd6096f --- /dev/null +++ b/modules/bugtracker/__init__.py @@ -0,0 +1,41 @@ +import re + +from graia.application import MessageChain +from graia.application.message.elements.internal import Plain + +from core.template import sendMessage +from .bugtracker import bug + + +async def bugtracker(kwargs: dict): + msg = kwargs['trigger_msg'] + msg = re.sub('bug ', '', msg) + q = re.match(r'(.*)\-(.*)', msg) + if q: + result = await bug(q.group(1) + '-' + q.group(2)) + msgchain = MessageChain.create([Plain(result)]) + await sendMessage(kwargs, msgchain) + + +async def regex_bugtracker(kwargs: dict): + msg = kwargs[MessageChain].asDisplay() + if msg[0] == '!': + msg = re.sub('!', '', msg) + msg = re.sub('bug ', '', msg) + q = re.match(r'(.*)\-(.*)', msg) + if q: + result = await bug(q.group(1) + '-' + q.group(2)) + msgchain = MessageChain.create([Plain(result)]) + await sendMessage(kwargs, msgchain) + findlink = re.findall(r'(https://bugs.mojang.com/browse/.*?-\d*)', msg) + for link in findlink: + print(link) + matchbug = re.match(r'https://bugs.mojang.com/browse/(.*?-\d*)', link) + if matchbug: + await sendMessage(kwargs, await bug(matchbug.group(1))) + + +command = {'bug': bugtracker} +regex = {'bug_regex': regex_bugtracker} +help = {'bug': {'module': '查询Mojira上的漏洞编号。', 'help': '~bug 查询Mojira上的漏洞编号。'}, + 'bug_regex': {'module': '正则自动查询Mojira上的漏洞编号。', 'help': '提示:正则自动查询Mojira漏洞已开启,所有消息开头为!和来自Mojira的链接将会被自动查询并发送梗概内容。'}} diff --git a/modules/bug/bugtracker.py b/modules/bugtracker/bugtracker.py similarity index 100% rename from modules/bug/bugtracker.py rename to modules/bugtracker/bugtracker.py diff --git a/modules/camr.py b/modules/camr.py deleted file mode 100644 index e637a81b..00000000 --- a/modules/camr.py +++ /dev/null @@ -1,11 +0,0 @@ -from os.path import abspath - -import ffmpy - - -async def camr(filename): - ff = ffmpy.FFmpeg( - inputs={abspath(filename): None}, - outputs={abspath(filename + '.amr'): '-ar 8000 -ab 12.2k -filter_complex channelsplit=channel_layout=mono'}) - ff.run() - return filename + '.amr' diff --git a/modules/checkuser.py b/modules/checkuser.py deleted file mode 100644 index 1a1944db..00000000 --- a/modules/checkuser.py +++ /dev/null @@ -1,13 +0,0 @@ -import json - -import requests - - -def checkuser(path, username): - url = 'https://' + path + '.gamepedia.com/api.php?action=query&list=users&ususers=' + username + '&usprop=groups%7Cblockinfo%7Cregistration%7Ceditcount%7Cgender&format=json' - q = requests.get(url) - file = json.loads(q.text) - if ('missing' in file['query']['users'][0]): - return False - else: - return True diff --git a/modules/core/__init__.py b/modules/core/__init__.py new file mode 100644 index 00000000..ff118d75 --- /dev/null +++ b/modules/core/__init__.py @@ -0,0 +1,180 @@ +from graia.application import Group, MessageChain, Member, Friend +from graia.application.message.elements.internal import Plain + +import database +from core.template import sendMessage, check_permission + + +async def enable_modules(kwargs: dict): + """ +~enable [self] """ + command = kwargs['trigger_msg'].split(' ') + function_list = kwargs['function_list'] + if not len(command) > 1: + await sendMessage(kwargs, '命令格式错误。' + enable_modules.__doc__) + return + command_second_word = command[1] + if Group in kwargs: + if command_second_word == 'self': + if not len(command) > 2: + await sendMessage(kwargs, '命令格式错误。' + enable_modules.__doc__) + return + command_third_word = command[2] + if command_third_word in function_list: + msg = database.update_modules_self('add', kwargs[Member].id, command_third_word) + await sendMessage(kwargs, msg) + else: + await sendMessage(kwargs, '此模块不存在。') + elif command_second_word == 'all': + if check_permission(kwargs): + msglist = [] + for function in function_list: + msg = database.update_modules('add', kwargs[Group].id, function) + msglist.append(msg) + await sendMessage(kwargs, '\n'.join(msglist)) + else: + await sendMessage(kwargs, '你没有使用该命令的权限。') + elif command_second_word in function_list: + if check_permission(kwargs): + msg = database.update_modules('add', kwargs[Group].id, command_second_word) + await sendMessage(kwargs, msg) + else: + await sendMessage(kwargs, '你没有使用该命令的权限。') + else: + msgchain = MessageChain.create([Plain('此模块不存在。')]) + await sendMessage(kwargs, msgchain) + elif Friend in kwargs: + if command_second_word == 'self': + if not len(command) > 2: + await sendMessage(kwargs, '命令格式错误。' + enable_modules.__doc__) + return + command_second_word = command[2] + do = 'add' + if command_second_word == 'all': + msglist = [] + for function in function_list: + msg = database.update_modules_self(do, kwargs[Friend].id, function) + msglist.append(msg) + await sendMessage(kwargs, '\n'.join(msglist)) + elif command_second_word in function_list: + msg = database.update_modules_self(do, kwargs[Friend].id, command_second_word) + await sendMessage(kwargs, msg) + else: + await sendMessage(kwargs, '此模块不存在。') + + +async def disable_modules(kwargs: dict): + """ +~disable [self] """ + command = kwargs['trigger_msg'].split(' ') + if not len(command) > 1: + await sendMessage(kwargs, '命令格式错误。' + disable_modules.__doc__) + return + function_list = kwargs['function_list'] + command_second_word = command[1] + if Group in kwargs: + if command_second_word == 'self': + if not len(command) > 2: + await sendMessage(kwargs, '命令格式错误。' + disable_modules.__doc__) + return + command_third_word = command[2] + if command_third_word in function_list: + msg = database.update_modules_self('del', kwargs[Member].id, command_third_word) + await sendMessage(kwargs, msg) + else: + await sendMessage(kwargs, '此模块不存在。') + elif command_second_word == 'all': + if check_permission(kwargs): + msglist = [] + for function in function_list: + msg = database.update_modules('del', kwargs[Group].id, function) + msglist.append(msg) + await sendMessage(kwargs, '\n'.join(msglist)) + else: + await sendMessage(kwargs, '你没有使用该命令的权限。') + elif command_second_word in function_list: + if check_permission(kwargs): + msg = database.update_modules('del', kwargs[Group].id, command_second_word) + await sendMessage(kwargs, msg) + else: + await sendMessage(kwargs, '你没有使用该命令的权限。') + else: + await sendMessage(kwargs, '此模块不存在。') + elif Friend in kwargs: + if command_second_word == 'self': + if not len(command) > 2: + await sendMessage(kwargs, '命令格式错误。' + disable_modules.__doc__) + return + command_second_word = command[2] + do = 'del' + if command_second_word == 'all': + msglist = [] + for function in function_list: + msg = database.update_modules_self(do, kwargs[Friend].id, function) + msglist.append(msg) + await sendMessage(kwargs, '\n'.join(msglist)) + elif command_second_word in function_list: + msg = database.update_modules_self(do, kwargs[Friend].id, command_second_word) + await sendMessage(kwargs, msg) + else: + await sendMessage(kwargs, '此模块不存在。') + + +async def bot_help(kwargs: dict): + help_list = kwargs['help_list'] + print(help_list) + help_msg = [] + help_msg.append('基础命令:') + for x in help_list: + if 'essential' in help_list[x]: + help_msg.append(help_list[x]['help']) + help_msg.append('模块扩展命令:') + for x in help_list: + if Group in kwargs: + if database.check_enable_modules(kwargs, x): + if 'help' in help_list[x]: + help_msg.append(help_list[x]['help']) + if 'depend' in help_list[x]: + if database.check_enable_modules(kwargs, help_list[x]['depend']): + if help_list[x]['help'] not in help_msg: + help_msg.append(help_list[x]['help']) + elif Friend in kwargs: + if 'help' in help_list[x]: + help_msg.append(help_list[x]['help']) + if 'depend' in help_list[x]: + if help_list[x]['help'] not in help_msg: + help_msg.append(help_list[x]['help']) + await sendMessage(kwargs, '\n'.join(help_msg)) + + +async def modules_help(kwargs: dict): + help_list = kwargs['help_list'] + help_msg = [] + help_msg.append('当前可用的模块有:') + for x in help_list: + if 'module' in help_list[x]: + help_msg.append(x+ ':' + help_list[x]['module']) + await sendMessage(kwargs, '\n'.join(help_msg)) + + +async def add_su(kwargs: dict): + command = kwargs['trigger_msg'].split(' ') + if database.check_superuser(kwargs): + await sendMessage(kwargs, database.add_superuser(command[1])) + else: + await sendMessage(kwargs, '权限不足。') + + +async def del_su(kwargs: dict): + command = kwargs['trigger_msg'].split(' ') + if database.check_superuser(kwargs): + await sendMessage(kwargs, database.del_superuser(command[1])) + else: + await sendMessage(kwargs, '权限不足。') + + +essential = {'enable': enable_modules, 'disable': disable_modules, 'help': bot_help, 'modules': modules_help} +admin = {'add_su': add_su, 'del_su': del_su} +help = {'enable': {'module': '开启一个模块', 'help': '~enable <模块名> - 开启一个模块', 'essential': True}, + 'disable': {'module': '关闭一个模块', 'help': '~disable <模块名> - 关闭一个模块', 'essential': True}, + 'module': {'help': '~modules - 查询所有可用模块。'}} diff --git a/modules/credits.py b/modules/credits.py deleted file mode 100644 index 092c86f4..00000000 --- a/modules/credits.py +++ /dev/null @@ -1,15 +0,0 @@ -async def main(): - return '''=============== -主开发者 OasisAkari - - _LittleC_ -代码贡献 Dianliang233 - wyapx -资金支持 WDLJT -2020 Teahouse Studios -=============== -此机器人的源代码已于https://github.com/Teahouse-Studios/bot仓库与母项目Graia采用相同协议AGPL-3.0 License进行开源。 -[30秒后撤回本消息]''' - - -command = 'credits' diff --git a/modules/dfile.py b/modules/dfile.py deleted file mode 100644 index 78eb6a50..00000000 --- a/modules/dfile.py +++ /dev/null @@ -1,46 +0,0 @@ -import os -import re -import uuid -from os.path import abspath - -import aiohttp -from bs4 import BeautifulSoup as bs - - -async def dfile(link, filename): - suffix = re.match(r'.*(\..*)$', filename) - async with aiohttp.ClientSession() as session: - async with session.get(link + 'File:' + filename) as req: - if req.status != 200: - return f"请求时发生错误:{req.status}" - else: - q = await req.text() - soup = bs(q, 'html.parser') - aa = soup.find('div', id='mw-content-text') - aaa = aa.find('div', class_='fullImageLink', id='file') - aaaa = aaa.find('audio') - print(aaaa) - z = re.match('.*<.*src="(.*)".*><.*', str(aaa), re.S) - url = z.group(1) - print(url) - d = abspath('./assets/cache/') - if not os.path.exists(d): - os.makedirs(d) - print(suffix.group(1)) - path = d + '/' + str(uuid.uuid4()) + suffix.group(1) - print(path) - try: - if not os.path.exists(d): - os.mkdir(d) - if not os.path.exists(path): - async with aiohttp.ClientSession() as session: - async with session.get(url) as r: - with open(path, "wb") as fp: - chunk = await r.content.read() - fp.write(chunk) - return path - else: - print("已存在") - return path - except Exception as e: - print(str(e)) diff --git a/modules/findimage.py b/modules/findimage.py deleted file mode 100644 index 5914a0eb..00000000 --- a/modules/findimage.py +++ /dev/null @@ -1,25 +0,0 @@ -import re - -import traceback - -import aiohttp -from bs4 import BeautifulSoup as bs - - -async def findimage(url): - async with aiohttp.ClientSession() as session: - async with session.get(url) as req: - if req.status != 200: - return None - else: - q = await req.text() - try: - soup = bs(q, 'html.parser') - aa = soup.find('div', id='mw-content-text') - src = aa.find_all('div', class_='fullImageLink') - z = re.match('.*<.*', str(src), re.S) - find = re.sub(r'\?.*', '', z.group(1)) - return find - except Exception: - traceback.print_exc() - return None diff --git a/modules/help.py b/modules/help.py deleted file mode 100644 index 2cf5f3a8..00000000 --- a/modules/help.py +++ /dev/null @@ -1,35 +0,0 @@ -path = '~' - - -async def main(): - return f'''{path}ab - 查看Minecraft Wiki过滤器日志。 -{path}bug - 从Mojira中获取此Bug的信息。 -{path}credits - 展示制作人员列表。 -{path}mcv - 获取当前Minecraft Java版最新版本。 -{path}mcbv - 获取当前Minecraft基岩版最新版本。 -{path}mcdv - 获取当前Minecraft Dungeons最新版本。 -{path}rc - 查看Minecraft Wiki最近更改。 -{path}server -h -{path}user -h -{path}wiki -h -! - 用于快捷查bug,如!mc-4 -[[]] - 用于快捷查wiki,如[[海晶石]] -{{{{}}}} - 用于快捷查wiki模板,如{{{{v}}}} -[30秒后撤回本消息]''' - - -def wikihelp(): - return f'''{path}wiki ~ - 从指定Gamepedia站点中输出条目链接。 -{path}wiki :, {path}wiki- - 从指定语言中的Minecraft Wiki中输出条目链接。 -{path}wiki - 从Minecraft Wiki(英文)中输出条目链接。''' - - -def userhelp(): - return f'''{path}user ~ - 从指定Gamepedia站点中输出用户信息。 -{path}user :, {path}user- - 从指定语言中的Minecraft Wiki中输出用户信息。 -{path}user - 从Minecraft Wiki(英文)中输出用户信息。 -[-r] - 输出详细信息。 -[-p] - 输出一张用户信息的图片(不包含用户组)。''' - - -command = {'help': 'help'} diff --git a/modules/interwikilist/__init__.py b/modules/interwikilist/__init__.py deleted file mode 100644 index a87a219a..00000000 --- a/modules/interwikilist/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -from configparser import ConfigParser -from os.path import abspath - -path = abspath("./modules/interwikilist/") -print(path) - -def iwlist(): - cp = ConfigParser() - cp.read(path+"/list.cfg") - print(path) - section = cp.sections()[0] - return (cp.options(section)) - - -def iwlink(iw): - cp = ConfigParser() - cp.read(path+"/list.cfg") - section = cp.sections()[0] - return (cp.get(section, iw)) - - -def iwalllink(): - links = [] - for x in iwlist(): - links.append(iwlink(x)) - return links \ No newline at end of file diff --git a/modules/interwikilist/list.cfg b/modules/interwikilist/list.cfg deleted file mode 100644 index d5261a63..00000000 --- a/modules/interwikilist/list.cfg +++ /dev/null @@ -1,36 +0,0 @@ -[list] -aether = https://aether.gamepedia.com/ -ftb = https://ftb.gamepedia.com/ -gphelp = https://help.gamepedia.com/ -gphelpzh = https://help-zh.gamepedia.com/ -mw = https://www.mediawiki.org/w/ -mwphab = https://phabricator.wikimedia.org/ -wikimedia = https://commons.wikimedia.org/w/ -wikisource = http://wikisource.org/wiki/ -wiktionary = http://en.wiktionary.org/wiki/ -cs = https://minecraft-cs.gamepedia.com/ -de = https://minecraft-de.gamepedia.com/ -el = https://minecraft-el.gamepedia.com/ -en = https://minecraft.gamepedia.com/ -es = https://minecraft-es.gamepedia.com/ -fr = https://minecraft-fr.gamepedia.com/ -hu = https://minecraft-hu.gamepedia.com/ -it = https://minecraft-it.gamepedia.com/ -ja = https://minecraft-ja.gamepedia.com/ -ko = https://minecraft-ko.gamepedia.com/ -nl = https://minecraft-nl.gamepedia.com/ -pl = https://minecraft-pl.gamepedia.com/ -pt = https://minecraft-pt.gamepedia.com/ -ru = https://minecraft-ru.gamepedia.com/ -th = https://minecraft-th.gamepedia.com/ -tr = https://minecraft-tr.gamepedia.com/ -uk = https://minecraft-uk.gamepedia.com/ -zh = https://minecraft-zh.gamepedia.com/ -moegirl = https://zh.moegirl.org.cn/ -enmoe = https://en.moegirl.org.cn/ -jamoe = https://ja.moegirl.org.cn/ -moe = https://zh.moegirl.org.cn/ -arc = https://wiki.arcaea.cn/index.php/ -arcaea = https://wiki.arcaea.cn/index.php/ -lakeus = https://files.lakejason0.ml/ -adodoz = https://wiki.adodoz.cn/ \ No newline at end of file diff --git a/modules/mcbv.py b/modules/mcbv.py deleted file mode 100644 index a51a2e29..00000000 --- a/modules/mcbv.py +++ /dev/null @@ -1,34 +0,0 @@ -import re - -import aiohttp - - -async def get_data(url: str, fmt: str): - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: - if hasattr(req, fmt): - return await getattr(req, fmt)() - else: - raise ValueError(f"NoSuchMethod: {fmt}") - - -async def main(): - try: - data = await get_data('https://bugs.mojang.com/rest/api/2/project/10200/versions', "json") - except (ConnectionError, OSError): # Probably... - return "发生错误:土豆熟了" - beta = [] - release = [] - for v in data: - if not v['archived']: - match = re.match(r"(.*Beta)$", v["name"]) - if match: - beta.append(match.group(1)) - else: - release.append(v["name"]) - prefix = " | " - return f'Beta:{prefix.join(beta)},Release:{prefix.join(release)}\n' \ - f'(数据来源于MoJira,可能会比官方发布要早一段时间。信息仅供参考。)' - - -command = {'mcbv': 'mcbv'} diff --git a/modules/mcdv.py b/modules/mcdv.py deleted file mode 100644 index e78ad689..00000000 --- a/modules/mcdv.py +++ /dev/null @@ -1,24 +0,0 @@ -import aiohttp - - -async def get_data(url: str, fmt: str): - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: - if hasattr(req, fmt): - return await getattr(req, fmt)() - else: - raise ValueError(f"NoSuchMethod: {fmt}") - - -async def main(): - try: - data = await get_data('https://bugs.mojang.com/rest/api/2/project/11901/versions', "json") - except (ConnectionError, OSError): # Probably... - return "发生错误:土豆熟了" - for v in data: - if not v['archived']: - return f'最新版:{v.get("name")} \n(数据来源于MoJira,可能会比官方发布要早一段时间。信息仅供参考。)' - return "出了点问题,快去锤develop(" - - -command = {'mcdv': 'mcdv'} diff --git a/modules/mcv/__init__.py b/modules/mcv/__init__.py new file mode 100644 index 00000000..d1424538 --- /dev/null +++ b/modules/mcv/__init__.py @@ -0,0 +1,33 @@ +from graia.application import MessageChain +from graia.application.message.elements.internal import Plain + +from core.template import sendMessage +from .mcv import mcv, mcbv, mcdv + + +async def mcv_loader(kwargs: dict): + run = await mcv() + msgchain = MessageChain.create([Plain(run)]) + await sendMessage(kwargs, msgchain) + + +async def mcbv_loader(kwargs: dict): + run = await mcbv() + msgchain = MessageChain.create([Plain(run)]) + await sendMessage(kwargs, msgchain) + + +async def mcdv_loader(kwargs: dict): + run = await mcdv() + msgchain = MessageChain.create([Plain(run)]) + await sendMessage(kwargs, msgchain) + + +command = {'mcv': mcv_loader, 'mcbv': mcbv_loader, 'mcdv': mcdv_loader} +help = {'mcv': {'module': '查询当前Minecraft Java版启动器内最新版本。', + 'help': '~mcv - 查询当前Minecraft Java版启动器内最新版本。'}, + 'mcbv': {'module': '查询当前Minecraft基岩版Jira上记录的最新版本。', + 'help': '~mcbv - 查询当前Minecraft基岩版Jira上记录的最新版本。'}, + 'mcdv': {'module': '查询当前Minecraft Dungeons Jira上记录的最新版本。', + 'help': '~mcdv - 查询当前Minecraft Dungeons Jira上记录的最新版本。'} + } diff --git a/modules/mcv.py b/modules/mcv/mcv.py similarity index 50% rename from modules/mcv.py rename to modules/mcv/mcv.py index 5de98407..df00fcf8 100644 --- a/modules/mcv.py +++ b/modules/mcv/mcv.py @@ -1,3 +1,5 @@ +import re + import aiohttp @@ -10,7 +12,7 @@ async def get_data(url: str, fmt: str): raise ValueError(f"NoSuchMethod: {fmt}") -async def main(): +async def mcv(): try: data = await get_data('http://launchermeta.mojang.com/mc/game/version_manifest.json', "json") message1 = f"最新版:{data['latest']['release']},最新快照:{data['latest']['snapshot']}" @@ -33,4 +35,31 @@ Mojira上所记录最新版本为: (以启动器内最新版本为准,Mojira仅作版本号预览用)""" -command = {'mcv': 'mcv'} +async def mcbv(): + try: + data = await get_data('https://bugs.mojang.com/rest/api/2/project/10200/versions', "json") + except (ConnectionError, OSError): # Probably... + return "发生错误:土豆熟了" + beta = [] + release = [] + for v in data: + if not v['archived']: + match = re.match(r"(.*Beta)$", v["name"]) + if match: + beta.append(match.group(1)) + else: + release.append(v["name"]) + prefix = " | " + return f'Beta:{prefix.join(beta)},Release:{prefix.join(release)}\n' \ + f'(数据来源于MoJira,可能会比官方发布要早一段时间。信息仅供参考。)' + + +async def mcdv(): + try: + data = await get_data('https://bugs.mojang.com/rest/api/2/project/11901/versions', "json") + except (ConnectionError, OSError): # Probably... + return "发生错误:土豆熟了" + for v in data: + if not v['archived']: + return f'最新版:{v.get("name")} \n(数据来源于MoJira,可能会比官方发布要早一段时间。信息仅供参考。)' + return "出了点问题,快去锤develop(" diff --git a/modules/mcv_rss/__init__.py b/modules/mcv_rss/__init__.py new file mode 100644 index 00000000..ec054e4d --- /dev/null +++ b/modules/mcv_rss/__init__.py @@ -0,0 +1,99 @@ +import asyncio +import traceback +from os.path import abspath + +from graia.application import MessageChain +from graia.application.message.elements.internal import Plain + +from database import check_enable_modules_all +from modules.mcv.mcv import get_data + + +def mcversion(): + w = open(abspath('./assets/mcversion.txt'), 'r+') + s = w.read().split('\n') + w.close() + return s + + +def mcversion_jira(): + w = open(abspath('./assets/mcversion_jira.txt'), 'r+') + s = w.read().split('\n') + w.close() + return s + + +async def mcv_rss(app): + url = 'http://launchermeta.mojang.com/mc/game/version_manifest.json' + print('subbot ver launched') + while True: + try: + verlist = mcversion() + file = await get_data(url, 'json') + release = file['latest']['release'] + snapshot = file['latest']['snapshot'] + if release not in verlist: + print(release) + for qqgroup in check_enable_modules_all('group_permission', 'mcv_rss'): + try: + await app.sendGroupMessage(int(qqgroup), MessageChain.create( + [Plain('启动器已更新' + file['latest']['release'] + '正式版。')])) + await asyncio.sleep(0.5) + except Exception: + traceback.print_exc() + addversion = open('./assets/mcversion.txt', 'a') + addversion.write('\n' + release) + addversion.close() + verlist = mcversion() + if snapshot not in verlist: + print(snapshot) + for qqgroup in check_enable_modules_all('group_permission', 'mcv_rss'): + try: + await app.sendGroupMessage(int(qqgroup), MessageChain.create( + [Plain('启动器已更新' + file['latest']['snapshot'] + '快照。')])) + await asyncio.sleep(0.5) + except Exception: + traceback.print_exc() + addversion = open('./assets/mcversion.txt', 'a') + addversion.write('\n' + snapshot) + addversion.close() + await asyncio.sleep(10) + except Exception: + traceback.print_exc() + await asyncio.sleep(5) + + +async def mcv_jira_rss(app): + url = 'https://bugs.mojang.com/rest/api/2/project/10400/versions' + print('subbot jira launched') + while True: + try: + verlist = mcversion_jira() + file = await get_data(url, 'json') + release = [] + for v in file: + if not v['archived']: + release.append(v['name']) + for x in release: + if x not in verlist: + print(x) + for qqgroup in check_enable_modules_all('group_permission', 'mcv_jira_rss'): + try: + await app.sendGroupMessage(int(qqgroup), MessageChain.create( + [Plain(f'Jira已更新{x}。\n(Jira上的信息仅作版本号预览用,不代表启动器已更新此版本)')])) + await asyncio.sleep(0.5) + except Exception: + traceback.print_exc() + addversion = open('./assets/mcversion_jira.txt', 'a') + addversion.write('\n' + x) + addversion.close() + await asyncio.sleep(10) + except Exception: + traceback.print_exc() + await asyncio.sleep(5) + + +rss = {'mcv_rss': mcv_rss, 'mcv_jira_rss': mcv_jira_rss} +options = ['mcv_rss', 'mcv_jira_rss'] +help = {'mcv_rss': {'module': '订阅Minecraft Java版游戏版本检测。(仅群聊)'}, + 'mcv_jira_rss': {'module': '订阅Minecraft Java版游戏版本检测(Jira记录,仅作预览用)。(仅群聊)'}} diff --git a/modules/mcversion.py b/modules/mcversion.py deleted file mode 100644 index 8f8a8dad..00000000 --- a/modules/mcversion.py +++ /dev/null @@ -1,8 +0,0 @@ -from os.path import abspath - - -def mcversion(): - w = open(abspath('./assets/mcversion.txt'), 'r') - s = w.read().split('\n') - w.close() - return (s) diff --git a/modules/mcvrss.py b/modules/mcvrss.py deleted file mode 100644 index ea3d4858..00000000 --- a/modules/mcvrss.py +++ /dev/null @@ -1,42 +0,0 @@ -import os -import re -from os.path import abspath - - -def mcvrss(): - w = open(abspath('./mcvrss.txt'), 'r') - s = w.read().split('\n') - if '' in s: - s.remove('') - w.close() - return (s) - - -def mcvrssa(group): - q = mcvrss() - if group in q: - return ('该群已在订阅列表中。') - else: - wr = open('../mcvrss.txt', 'a+') - wr.write(re.sub(r'\n$', '', '\n' + group)) - wr.close() - return ('已订阅。') - - -def mcvrssr(group): - q = mcvrss() - if group in q: - q.remove(group) - os.remove('../mcvrss.txt') - wr = open('../mcvrss.txt', 'a') - y = [] - h = '' - for x in q: - y.append(x + '\n') - g = h.join(y) - k = re.sub(r'\n$', '', g) - wr.write(k) - wr.close() - return ('已移除订阅。') - else: - return ('此群不在订阅列表中。') diff --git a/modules/nintendoerr.py b/modules/nintendoerr.py deleted file mode 100644 index 62871e61..00000000 --- a/modules/nintendoerr.py +++ /dev/null @@ -1,529 +0,0 @@ -#Copied from kurisu(https://github.com/nh-server/Kurisu/blob/port/cogs/err.py) -import binascii -import re - -class Err(): - """ - Parses CTR error codes. - """ - - - # CTR Error Codes - summaries = { - 0: 'Success', - 1: 'Nothing happened', - 2: 'Would block', - 3: 'Out of resource', - 4: 'Not found', - 5: 'Invalid state', - 6: 'Not supported', - 7: 'Invalid argument', - 8: 'Wrong argument', - 9: 'Canceled', - 10: 'Status changed', - 11: 'Internal', - 63: 'Invalid result value' - } - - levels = { - 0: "Success", - 1: "Info", - - 25: "Status", - 26: "Temporary", - 27: "Permanent", - 28: "Usage", - 29: "Reinitialize", - 30: "Reset", - 31: "Fatal" - } - - modules = { - 0: 'Common', - 1: 'Kernel', - 2: 'Util', - 3: 'File server', - 4: 'Loader server', - 5: 'TCB', - 6: 'OS', - 7: 'DBG', - 8: 'DMNT', - 9: 'PDN', - 10: 'GSP', - 11: 'I2C', - 12: 'GPIO', - 13: 'DD', - 14: 'CODEC', - 15: 'SPI', - 16: 'PXI', - 17: 'FS', - 18: 'DI', - 19: 'HID', - 20: 'CAM', - 21: 'PI', - 22: 'PM', - 23: 'PM_LOW', - 24: 'FSI', - 25: 'SRV', - 26: 'NDM', - 27: 'NWM', - 28: 'SOC', - 29: 'LDR', - 30: 'ACC', - 31: 'RomFS', - 32: 'AM', - 33: 'HIO', - 34: 'Updater', - 35: 'MIC', - 36: 'FND', - 37: 'MP', - 38: 'MPWL', - 39: 'AC', - 40: 'HTTP', - 41: 'DSP', - 42: 'SND', - 43: 'DLP', - 44: 'HIO_LOW', - 45: 'CSND', - 46: 'SSL', - 47: 'AM_LOW', - 48: 'NEX', - 49: 'Friends', - 50: 'RDT', - 51: 'Applet', - 52: 'NIM', - 53: 'PTM', - 54: 'MIDI', - 55: 'MC', - 56: 'SWC', - 57: 'FatFS', - 58: 'NGC', - 59: 'CARD', - 60: 'CARDNOR', - 61: 'SDMC', - 62: 'BOSS', - 63: 'DBM', - 64: 'Config', - 65: 'PS', - 66: 'CEC', - 67: 'IR', - 68: 'UDS', - 69: 'PL', - 70: 'CUP', - 71: 'Gyroscope', - 72: 'MCU', - 73: 'NS', - 74: 'News', - 75: 'RO', - 76: 'GD', - 77: 'Card SPI', - 78: 'EC', - 79: 'Web Browser', - 80: 'Test', - 81: 'ENC', - 82: 'PIA', - 83: 'ACT', - 84: 'VCTL', - 85: 'OLV', - 86: 'NEIA', - 87: 'NPNS', - 90: 'AVD', - 91: 'L2B', - 92: 'MVD', - 93: 'NFC', - 94: 'UART', - 95: 'SPM', - 96: 'QTM', - 97: 'NFP (amiibo)', - 254: 'Application', - 255: 'Invalid result value' - } - - descriptions = { - 0: 'Success', - 2: 'Invalid memory permissions (kernel)', - 4: 'Invalid ticket version (AM)', - 5: 'Invalid string length. This error is returned when service name length is greater than 8 or zero. (srv)', - 6: 'Access denied. This error is returned when you request a service that you don\'t have access to. (srv)', - 7: 'String size does not match string contents. This error is returned when service name contains an unexpected null byte. (srv)', - 8: 'Camera already in use/busy (qtm).', - 10: 'Not enough memory (os)', - 26: 'Session closed by remote (os)', - 32: 'Empty CIA? (AM)', - 37: 'Invalid NCCH? (AM)', - 39: 'Invalid title version (AM)', - 43: 'Database doesn\'t exist/failed to open (AM)', - 44: 'Trying to uninstall system-app (AM)', - 47: 'Invalid command header (OS)', - 101: 'Archive not mounted/mount-point not found (fs)', - 105: 'Request timed out (http)', - 106: 'Invalid signature/CIA? (AM)', - 120: 'Title/object not found? (fs)', - 141: 'Gamecard not inserted? (fs)', - 190: 'Object does already exist/failed to create object.', - 230: 'Invalid open-flags / permissions? (fs)', - 250: 'FAT operation denied (fs?)', - 271: 'Invalid configuration (mvd).', - 335: '(No permission? Seemed to appear when JKSM was being used without its XML.)', - 391: 'NCCH hash-check failed? (fs)', - 392: 'RSA/AES-MAC verification failed? (fs)', - 393: 'Invalid database? (AM)', - 395: 'RomFS/Savedata hash-check failed? (fs)', - 630: 'Command not allowed / missing permissions? (fs)', - 702: 'Invalid path? (fs)', - 740: '(Occurred when NDS card was inserted and attempting to use AM_GetTitleCount on MEDIATYPE_GAME_CARD.) (fs)', - 761: 'Incorrect read-size for ExeFS? (fs)', - 1000: 'Invalid selection', - 1001: 'Too large', - 1002: 'Not authorized', - 1003: 'Already done', - 1004: 'Invalid size', - 1005: 'Invalid enum value', - 1006: 'Invalid combination', - 1007: 'No data', - 1008: 'Busy', - 1009: 'Misaligned address', - 1010: 'Misaligned size', - 1011: 'Out of memory', - 1012: 'Not implemented', - 1013: 'Invalid address', - 1014: 'Invalid pointer', - 1015: 'Invalid handle', - 1016: 'Not initialized', - 1017: 'Already initialized', - 1018: 'Not found', - 1019: 'Cancel requested', - 1020: 'Already exists', - 1021: 'Out of range', - 1022: 'Timeout', - 1023: 'Invalid result value' - } - - # Nintendo Error Codes - errcodes = { - # Nintendo 3DS - '001-0502': 'Some sort of network error related to friend presence. "Allow Friends to see your online status" might fix this.', - '001-0803': 'Could not communicate with authentication server.', - '002-0102': 'System is permanently banned by Nintendo. You cannot ask how to fix this issue here.', - '002-0107': 'System is temporarily(?) banned by Nintendo. You cannot ask how to fix this issue here.', - '002-0119': 'System update required (outdated friends-module)', - '002-0120': 'Title update required (outdated title version)', - '002-0121': 'Local friend code SEED has invalid signature.\n\nThis should not happen unless it is modified. The only use case for modifying this file is for system unbanning, so you cannot ask how to fix this issue here.', - '002-0123': 'System is generally banned by Nintendo. You cannot ask how to fix this issue here.', - '022-2502': 'Region settings between the console and Nintendo Network ID do not match. The console region must be fixed to use the NNID. If you want to use a different region, the NNID must be unlinked from the system or deleted.', - '022-2932': 'Unable to agree to the Nintendo Network Services Agreement. Usually found on region-changed devices.', - '003-1099': 'Access point could not be found with the given SSID.', - '003-2001': 'DNS error. If using a custom DNS server, make sure the settings are correct.', - '005-7000': 'Base error code for most other error codes. No error occured.', - '005-2008': 'This error is caused by installing a game or game update from an unofficial source, as it contains a bad ticket.\nThe only solution is to delete the unofficial game or update as well as its ticket\nin FBI, and install the game or update legitimately. If the title was uninstalled\nalready, remove the ticket in FBI.', - '005-4800': 'HTTP Status 500 (Internal Error), unknown cause(?). eShop servers might have issues.', - '005-5602': 'Unable to connect to the eShop. This error is most likely the result of an incorrect region setting.\nMake sure your region is correctly set in System Settings. If you encounter this error after region-changing your system, make sure you followed all the steps properly.', - '005-5958': 'Unknown eShop error. Usually seen on region-changed devices.', - '005-5964': 'Your Nintendo Network ID has been banned from accessing the eShop.\nIf you think this was unwarranted, you will have to contact Nintendo Support to have it reversed.', - '005-7550': 'Replace SD card(?). Occurs on Nintendo eShop.', - '006-0102': 'Unexpected error. Could probably happen trying to play an out-of-region title online?', - '006-0332': 'Disconnected from the game server.', - '006-0502': 'Could not connect to the server.\n\n• Check the [network status page](http://support.nintendo.com/networkstatus)\n• Move closer to your wireless router\n• Verify DNS settings. If "Auto-Obtain" doesn\'t work, try Google\'s Public DNS (8.8.8.8, 8.8.4.4) and try again.', - '006-0612': 'Failed to join the session.', - '007-0200': 'Could not access SD card.', - '007-2001': 'Usually the result after region-changing the system. New 3DS cannot fix this issue right now.', - '007-2100': 'The connection to the Nintendo eShop timed out.\nThis may be due to an ongoing server maintenance, check to make sure the servers are operating normally. You may also encounter this error if you have a weak internet connection.', - '007-2404': 'An error occurred while attempting to connect to the Nintendo eShop.\nMake sure you are running the latest firmware, since this error will appear if you are trying to access the eShop on older versions.', - '007-2670': 'Generic connection error.', - '007-2720': 'SSL error?', - '007-2916': 'HTTP error, server is probably down. Try again later?', - '007-2920': 'This error is caused by installing a game or game update from an unofficial source, as it contains a bad ticket.\nThe only solution is to delete the unofficial game or update as well as its ticket\nin FBI, and install the game or update legitimately. If the title was uninstalled\nalready, remove the ticket in FBI.', - '007-2913': 'HTTP error, server is probably down. Try again later?', - '007-2923': 'The Nintendo Servers are currently down for maintenance. Please try again later.', - '007-3102': 'Cannot find title on Nintendo eShop. Probably pulled.', - '007-6054': 'Occurs when ticket database is full (8192 tickets).', - '009-1000': 'System update required. (friends module?)', - '009-2916': 'NIM HTTP error, server is probably down. Try again later?', - '009-2913': 'NIM HTTP error, server is probably down. Try again later?', - '009-2920': 'This error is caused by installing a game or game update from an unofficial source, as it contains a bad ticket.\nThe only solution is to delete the unofficial game or update as well as its ticket\nin FBI, and install the game or update legitimately. If the title was uninstalled\nalready, remove the ticket in FBI.', - '009-4079': 'Could not access SD card. General purpose error.', - '009-4998': '"Local content is newer."\nThe actual cause of this error is unknown.', - '009-6106': '"AM error in NIM."\nProbably a bad ticket.', - '009-8401': 'Update data corrupted. Delete and re-install.', - '011-3021': 'Cannot find title on Nintendo eShop. Probably incorrect region, or never existed.', - '011-3136': 'Nintendo eShop is currently unavailable. Try again later.', - '011-6901': 'System is banned by Nintendo, this error code description is oddly Japanese, generic error code. You cannot ask how to fix this issue here.', - '012-1511': 'Certificate warning.', - '014-0016': 'Both systems have the same movable.sed key. Format the target and try system transfer again.', - '014-0062': 'Error during System Transfer. Move closer to the wireless router and keep trying.', - '022-2452': 'Occurs when trying to use Nintendo eShop with UNITINFO patches enabled.', - '022-2501': 'Attempting to use a Nintendo Network ID on one system when it is linked on another. This can be the result of using System Transfer, then restoring the source system\'s NAND and attempting to use services that require a Nintendo Network ID.\n\nIn a System Transfer, all Nintendo Network ID accounts associated with the system are transferred over, whether they are currently linked or not.', - '022-2511': 'System update required (what causes this? noticed while opening Miiverse, probably not friends module)', - '022-2613': 'Incorrect e-mail or password when trying to link an existing Nintendo Network ID. Make sure there are no typos, and the given e-mail is the correct one for the given ID.\nIf you forgot the password, reset it at ', - '022-2631': 'Nintendo Network ID deleted, or not usable on the current system. If you used System Transfer, the Nintendo Network ID will only work on the target system.', - '022-2633': 'Nintendo Network ID temporarily locked due to too many incorrect password attempts. Try again later.', - '022-2634': 'Nintendo Network ID is not correctly linked on the system. This can be a result of formatting the SysNAND using System Settings to unlink it from the EmuNAND.\nTo fix, boot GodMode9 and [follow these steps.](https://3ds.hacks.guide/godmode9-usage#removing-an-nnid-without-formatting-your-device)\nAfterwards, reboot and sign into your NNID again.', - '022-2812': 'System is permanently banned by Nintendo for illegally playing the Pokemon Sun & Moon ROM leak online before release. You cannot ask how to fix this issue here.', - '022-2815': 'System is banned by Nintendo from Miiverse access.', - '022-5515': 'Network timeout.', - '032-1820': 'Browser error that asks whether you want to go on to a potentially dangerous website. Can be bypassed by touching "yes".', - '090-0212': 'Game is permanently banned from Pokémon Global Link. This is most likely as a result of using altered or illegal save data.', - # Wii U - # these all mean different things technically and maybe i should list them - '102-2802': 'NNID is permanently banned by Nintendo. You cannot ask how to fix this issue here.', - '102-2805': 'System is banned from accessing Nintendo eShop. You cannot ask how to fix this issue here.', - '102-2812': 'System + linked NNID and access to online services are permanently banned by Nintendo. You cannot ask how to fix this issue here.', - '102-2813': 'System is banned by Nintendo. You cannot ask how to fix this issue here.', - '102-2814': 'System is permanently banned from online multiplayer in a/multiple game(s) (preferably Splatoon). You cannot ask how to fix this issue here.', - '102-2815': 'System is banned from accessing the Nintendo eShop. You cannot ask how to fix this issue here.', - '102-2816': 'System is banned for a/multiple game(s) (preferably Splatoon) for an unknown duration, by attempting to use modified static.pack/+ game files online. You cannot ask how to fix this issue here.', - '106-0306': 'NNID is temporarily banned from a/multiple games (preferably Splatoon) online multiplayer. You cannot ask how to fix this issue here.', - '106-0346': 'NNID is permanently banned from a/multiple games (preferably Splatoon) online multiplayer. You cannot ask how to fix this issue here.', - '112-1037': 'Incorrect permissions for the default index.html file which prevents the Internet Browser from reading it. This can be fixed by following [this guide](https://wiiu.hacks.guide/#/fix-errcode-112-1037).', - '115-1009': 'System is permanently banned from Miiverse.', - '121-0902': 'Permissions missing for the action you are trying to perfrom (Miiverse error).', - '126-9622': 'Error when attempting to add funds. Maybe try again after a while, or make sure there is no issue with the payment method.', - '150-1031': 'Disc could not be read. Either the disc is dirty, the lens is dirty, or the disc is unsupported (i.e. not a Wii or Wii U game).', - '150-2031': 'Disc could not be read. Either the disc is dirty, the lens is dirty, or the disc is unsupported (i.e. not a Wii or Wii U game).', - '160-0101': '"Generic error". Can happen when formatting a system with CBHC.', - '160-0102': 'Error in SLC/MLC or USB.', - '160-0103': '"The system memory is corrupted (MLC)."', - '160-0104': '"The system memory is corrupted (SLC)."', - '160-0105': 'USB storage corrupted?', - '199-9999': 'Usually occurs when trying to run an unsigned title without signature patches, or something unknown(?) is corrupted.', - } - - switch_errcodes = { - # Switch - '007-1037': ['Could not detect an SD card.', None], - '2001-0125': ['Executed svcCloseHandle on main-thread handle (No known support page)', None], - '2002-6063': ['Attempted to read eMMC CID from browser? (No known support page)', None], - '2005-0003': ['You are unable to download software.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/22393/kw/2005-0003'], - '2016-2101': ['Inserted Tencent-Nintendo (Chinese model) cartridge into regular Switch, which is region locked.', 'https://nintendoswitch.com.cn/support/'], - '2110-3400': ['This error code indicates the Internet connection you are attempting to use likely requires some type of authentication through a web browser (such as agreeing to terms of service or entering a username and password).', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/22569/kw/2110-3400'], - '2124-4007': ['System + Nintendo Account are permanently banned by Nintendo. You cannot ask how to fix this issue here.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/28046/kw/2124-4007'], - '2124-4025': ['Game Card is banned, this "COULD" happen to legal users if so contact Nintendo to allow them to whitelist the Game Card. Otherwise, You cannot ask how to fix this issue here.', None], - '2124-4027': ['System + Nintendo Account are banned from a game (preferably Splatoon 2) online multiplayer services for a set duration which can be found after checking your email on the account recieving the ban. You cannot ask how to fix this issue here.', None], - '2162-0002': ['General userland crash', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/22596/kw/2162-0002'], - '2164-0020': ['Error starting software.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/22539/kw/2164-0020'], - '2168-0000': ['Illegal opcode. (No known support page)', None], - '2168-0001': ['Resource/Handle not available.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/29104/kw/2168-0001'], - '2168-0002': ['Segmentation Fault.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/22518/kw/2168-0002'], - '2168-0003': ['Memory access must be 4 bytes aligned. (No known support page)', None], - '2181-4008': ['System is permanently banned by Nintendo. You cannot ask how to fix this issue here.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/42061/kw/2181-4008'], - '2811-5001': ['General connection error.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/22392/kw/2811-5001'], - '2124-4517': ['Console banned due a breach of the user agreements. You cannot ask how to fix this issue here.', 'https://en-americas-support.nintendo.com/app/answers/detail/a_id/43652/kw/2124-4517'], - '2124-4621': ['Online features in foreign games are not available on Tencent-Nintendo Switch (Chinese model).', 'https://nintendoswitch.com.cn/support/'] - } - - messages = [] - - def get_name(self, d, k, show_unknown=False): - if k in d: - return f'{d[k]} ({k})' - else: - if show_unknown: - return f'_Unknown {show_unknown}_ ({k})' # crappy method - else: - return f'{k}' - - async def aaaa(self, rc): - # i know this is shit that's the point - if rc == 3735928559: - self.messages.append(binascii.unhexlify(hex(3273891394255502812531345138727304541163813328167758675079724534358388)[2:]).decode('utf-8')) - elif rc == 3735927486: - self.messages.append(binascii.unhexlify(hex(271463605137058211622646033881424078611212374995688473904058753630453734836388633396349994515442859649191631764050721993573)[2:]).decode('utf-8')) - elif rc == 2343432205: - self.messages.append(binascii.unhexlify(hex(43563598107828907579305977861310806718428700278286708)[2:]).decode('utf-8')) - - async def convert_zerox(self, rc): - if not rc & 0x80000000: - self.messages.append('This is likely not a CTR error code.') - await self.aaaa(rc) - desc = rc & 0x3FF - mod = (rc >> 10) & 0xFF - summ = (rc >> 21) & 0x3F - level = (rc >> 27) & 0x1F - return desc, mod, summ, level, rc - - def nim_3ds_errors(self, err: str): - """ - Parses 3ds nim error codes between the range of 005-2000 to 005-3023, 005-4200 to 005-4399, 005-4400 to 005-4999, 005-5000 to 005-6999 and 005-7000 to 005-9999. - - 005-2000 to 005-3023: - - NIM got a result of its own. Took description and added by 52000. - - 005-4200 to 005-4399: - - NIM got an HTTP result. Took description and added by 54200, cutting out at 54399 if it was beyond that. - - 005-4400 to 005-4999: - - Range of HTTP codes, however, can suffer collision. - - 005-5000 to 005-6999: - - SOAP Error Code range, when is not 0 on the SOAP responses. - - 005-7000 to 005-9999: - - Non specific expected results are formatted to an error code in nim by taking result module and shifting right by 5, and taking the result description and masked with 0x1F, then added both together along with 57000. - """ - - if len(err) != 8: - return False - - try: - err_hi = int(err[:3], 10) - err_lo = int(err[-4:], 10) - except ValueError: - return False - - if err_hi != 5: - return False - - if 2000 <= err_lo < 3024: - err_lo -= 2000 - - self.messages.append("Module") - self.messages.append(self.get_name(self.modules, 52)) - self.messages.append("Description") - self.messages.append(self.get_name(self.descriptions, err_lo)) - return True - - # this range is still a little mystified by another section in nim - # but this covers one section of it - elif 4200 <= err_lo < 4400: - embed_extra = None - if err_lo == 4399: - embed_extra = "Or NIM's HTTP result description maximum." - err_lo -= 4200 - - self.messages.append("Module") - self.messages.append(self.get_name(self.modules, 40)) - self.messages.append("Description") - self.messages.append(self.get_name(self.descriptions, err_lo)) - if embed_extra: - self.messages.append("Extra Note") - self.messages.append(embed_extra) - return True - - elif 4400 <= err_lo < 5000: - err_lo -= 4400 - embed_extra = None - if err_lo < 100: - desc = f"{err_lo + 100}" - elif 100 <= err_lo < 500: - desc = f"{err_lo + 100} or {err_lo}" - embed_extra = "Likely due to a programming mistake in NIM, this error code range suffers collision.\n" - embed_extra += "Real HTTP code will vary with what operation it came from." - else: - desc = f"{err_lo}" - - self.messages.append("HTTP error code") - self.messages.append("Code") - self.messages.append(desc) - if embed_extra: - self.messages.append("Extra Note") - self.messages.append(embed_extra) - return True - - elif 5000 <= err_lo < 7000: - err_lo -= 5000 - - desc = f"SOAP Message returned ErrorCode {err_lo} on a NIM operation." - if err_lo == 1999: - desc += "\nOr beyond 1999. It's maxed out at 005-6999." - self.messages.append(desc) - return True - - elif err_lo >= 7000: - embed_extra = None - if err_lo == 9999: - embed_extra = "Also NIM's maximum compacted result to error code." - elif err_lo == 7000: - embed_extra = "Also NIM's minimum compacted result to error code." - err_lo -= 7000 - - module = err_lo >> 5 - short_desc = err_lo & 0x1F - - known_desc = [] - unknown_desc = [] - - for i in range(0+short_desc, 0x400+short_desc, 0x20): - if i not in self.descriptions: - unknown_desc += [str(i)] - continue - known_desc += [self.get_name(self.descriptions, i)] - - known_desc = "\n".join(known_desc) - unknown_desc = ", ".join(unknown_desc) - - self.messages.append("Module") - self.messages.append(self.get_name(self.modules, module)) - if known_desc: - self.messages.append("Possible known descriptions") - self.messages.append(known_desc) - if unknown_desc: - self.messages.append("Possible unknown descriptions") - self.messages.append(unknown_desc) - if embed_extra: - self.messages.append("Extra Note") - self.messages.append(embed_extra) - return True - - return False - - async def err(self, err: str): - """ - Parses Nintendo and CTR error codes, with a fancy embed. 0x prefix is not required. - - Example: - .err 0xD960D02B - .err 022-2634 - """ - if re.match('[0-1][0-9][0-9]\-[0-9][0-9][0-9][0-9]', err): - self.messages.append(err + (": Nintendo 3DS" if err[0] == "0" else ": Wii U")) - self.messages.append(f"https://en-americas-support.nintendo.com/app/answers/list/kw/{err}") - if err in self.errcodes: - self.messages.append(self.errcodes[err]) - else: - self.messages.append("I don't know this one! Click the error code for details on Nintendo Support.") - - # 0xE60012 - # Switch Error Codes (w/ website) - # Switch Error Codes (w/o website) - elif re.match('[0-9][0-9][0-9][0-9]\-[0-9][0-9][0-9][0-9]', err): - self.messages.append(err + ": Nintendo Switch") - self.messages.append("http://en-americas-support.nintendo.com/app/answers/landing/p/897") - if re.match('2110\-1[0-9][0-9][0-9]', err): - self.messages.append("http://en-americas-support.nintendo.com/app/answers/detail/a_id/22594") - self.messages.append("General connection error.") - elif re.match('2110\-29[0-9][0-9]', err): - self.messages.append("http://en-americas-support.nintendo.com/app/answers/detail/a_id/22277/p/897") - self.messages.append("General connection error.") - elif re.match('2110\-2[0-8][0-9][0-9]', err): - self.messages.append("http://en-americas-support.nintendo.com/app/answers/detail/a_id/22263/p/897") - self.messages.append("General connection error.") - else: - if err in self.switch_errcodes: - self.messages.append(self.switch_errcodes[err][1]) - self.messages.append(self.switch_errcodes[err][0]) - else: - self.messages.append("I don't know this one! Click the error code for details on Nintendo Support.\n\nIf you keep getting this issue and Nintendo Support does not help, and know how to fix it, you should report relevant details to [the Kurisu repository](https://github.com/nh-server/Kurisu/issues) so it can be added to the bot.") - else: - try: - err_num = int(err, 16) - except ValueError: - return f"Invalid error code {err}." - - desc, mod, summ, level, rc = await self.convert_zerox(err_num) - - # garbage - self.messages.append(f"0x{rc:X}") - self.messages.append("Module") - self.messages.append(self.get_name(self.modules, mod)) - self.messages.append("Description") - self.messages.append(self.get_name(self.descriptions, desc)) - self.messages.append("Summary") - self.messages.append(self.get_name(self.summaries, summ)) - self.messages.append("Level") - self.messages.append(self.get_name(self.levels, level)) - a = '\n' - b = a.join(self.messages) - self.messages.clear() - return b - -command = {'err': 'from nintendoerr import Err|err'} \ No newline at end of file diff --git a/modules/pathexist.py b/modules/pathexist.py deleted file mode 100644 index 9103337a..00000000 --- a/modules/pathexist.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import re -from os.path import abspath - - -def pathexist(ss): - ss = re.sub('_', '', ss) - d = abspath('./assets/Favicon/' + ss + '/') - if not os.path.exists(d): - os.mkdir(d) - else: - pass - ddd = abspath('./assets/Favicon/' + ss + '/Wiki.png') - if not os.path.exists(ddd): - return False - else: - return True - - -def pathexist2(ss): - ddd = abspath('./home/wdljt/oasisakari/bot/assets/usercard/' + ss + '.png') - if not os.path.exists(ddd): - return False - else: - return True diff --git a/modules/ping.py b/modules/ping.py deleted file mode 100644 index 4fd2cb3c..00000000 --- a/modules/ping.py +++ /dev/null @@ -1,21 +0,0 @@ -import time - -import psutil - - -async def main(): - Boot_Start = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(psutil.boot_time())) - time.sleep(0.5) - Cpu_usage = psutil.cpu_percent() - RAM = int(psutil.virtual_memory().total / (1027 * 1024)) - RAM_percent = psutil.virtual_memory().percent - Swap = int(psutil.swap_memory().total / (1027 * 1024)) - Swap_percent = psutil.swap_memory().percent - BFH = r'%' - return ("Pong!\n" + "系统运行时间:%s" % Boot_Start \ - + "\n当前CPU使用率:%s%s" % (Cpu_usage, BFH) \ - + "\n物理内存:%dM 使用率:%s%s" % (RAM, RAM_percent, BFH) \ - + "\nSwap内存:%dM 使用率:%s%s" % (Swap, Swap_percent, BFH)) - - -command = {'ping': 'ping'} diff --git a/modules/rc/__init__.py b/modules/rc/__init__.py deleted file mode 100644 index 8b3d9266..00000000 --- a/modules/rc/__init__.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding:utf-8 -*- -import json - -import aiohttp - -from modules.UTC8 import UTC8 -from modules.pbc import pbc - - -async def main(): - url = 'https://minecraft-zh.gamepedia.com/api.php?action=query&list=recentchanges&rcprop=title|user|timestamp&rctype=edit|new&format=json' - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: - if req.status != 200: - return f"请求时发生错误:{req.status}" - else: - text1 = await req.text() - file = json.loads(text1) - d = [] - for x in file['query']['recentchanges'][:5]: - d.append(x['title'] + ' - ' + x['user'] + ' ' + UTC8(x['timestamp'], 'onlytime')) - y = await pbc(d) - print(y) - space = '\n' - f = space.join(y) - if f.find('<吃掉了>') != -1 or f.find('<全部吃掉了>') != -1: - return (f + '\n...仅显示前5条内容\n检测到外来信息介入,请前往最近更改查看所有消息。Special:最近更改') - else: - return (f + '\n...仅显示前5条内容') - - -command = {'rc': 'rc'} diff --git a/modules/server/__init__.py b/modules/server/__init__.py index a2135079..09fcbd93 100644 --- a/modules/server/__init__.py +++ b/modules/server/__init__.py @@ -1,20 +1,24 @@ +import asyncio import re +from core.template import sendMessage, revokeMessage from .server import server -from .serverraw import serverraw -async def main(message): - if message == '-h': - return ('''~server
- 从指定地址服务器的25565端口中获取Motd。 -~server
: - 从指定地址服务器的端口中获取Motd。 -[-r] - 获取Motd的源代码。''') +async def main(kwargs: dict): + message = kwargs['trigger_msg'] + message = re.sub('^server ', '', message) msgsplit = message.split(' ') if '-r' in msgsplit: message = re.sub(' -r|-r ', '', message) - return await serverraw(message) + sendmsg = await server(message, raw=True) else: - return await server(message) + sendmsg = await server(message) + send = await sendMessage(kwargs, sendmsg) + await asyncio.sleep(30) + await revokeMessage(send) -command = {'server': 'server'} +command = {'server': main} +help = {'server': {'module': '获取Minecraft Java/基岩版服务器motd。', + 'help': '~server <服务器地址>:<服务器端口> - 获取Minecraft Java/基岩版服务器motd。'}} diff --git a/modules/server/be.py b/modules/server/be.py deleted file mode 100644 index f07dc0b4..00000000 --- a/modules/server/be.py +++ /dev/null @@ -1,48 +0,0 @@ -import asyncio - - -class EchoClientProtocol: - def __init__(self, on_con_lost): - self.on_con_lost = on_con_lost - self.transport = None - - def connection_made(self, transport): - self.transport = transport - self.transport.sendto(b'\x01' + int.to_bytes(1, 8, 'little') + bytearray.fromhex( - '00ffff00fefefefefdfdfdfd12345678') + bytearray.fromhex('a1b6ac63b81ca9d3')) - - def datagram_received(self, data, addr): - result = data[35:].decode() - self.transport.close() - self.on_con_lost.set_result(result) - - def error_received(self, exc): - print('Error received:', exc) - - def connection_lost(self, exc): - pass - - -async def main(addr, port): - loop = asyncio.get_running_loop() - - on_con_lost = loop.create_future() - - transport, protocol = await loop.create_datagram_endpoint( - lambda: EchoClientProtocol(on_con_lost), - remote_addr=(addr, port)) - - try: - data = await asyncio.wait_for(on_con_lost, timeout=5) - # https://wiki.vg/Raknet_Protocol - # Server ID string format - - # Edition (MCPE or MCEE for Education Edition) - edition, motd_1, protocol, version_name, player_count, max_players, unique_id, motd_2, \ - game_mode, game_mode_num, port_v4, port_v6, nothing_here = data.split(';') - return ( - '[BE]\n' + motd_1 + ' - ' + motd_2 + '\n在线玩家:' + player_count + '/' + max_players + '\n游戏版本:' + edition + version_name + '\n游戏模式:' + game_mode) - except Exception: - pass - finally: - transport.close() diff --git a/modules/server/server.py b/modules/server/server.py index e936217d..182f3316 100644 --- a/modules/server/server.py +++ b/modules/server/server.py @@ -4,7 +4,8 @@ import traceback import aiohttp -async def server(address): + +async def server(address, raw=False): matchObj = re.match(r'(.*):(.*)', address, re.M | re.I) servers = [] @@ -34,16 +35,16 @@ async def server(address): if 'description' in jejson: description = jejson['description'] if 'text' in description: - servers.append(description['text']) + servers.append(str(description['text'])) elif 'extra' in description: extra = description['extra'] text = [] qwq = '' for item in extra[:]: - text.append(item['text']) + text.append(str(item['text'])) servers.append(qwq.join(text)) else: - servers.append(description) + servers.append(str(description)) if 'players' in jejson: onlinesplayer = f"在线玩家:{str(jejson['players']['online'])} / {str(jejson['players']['max'])}" @@ -73,11 +74,11 @@ async def server(address): bejson = json.loads(bemotd) edition, motd_1, protocol, version_name, player_count, max_players, unique_id, motd_2, \ game_mode, game_mode_num, port_v4, port_v6, nothing_here = bejson['motd'].split(';') - bemsg = '[BE]\n' +\ - motd_1 + ' - ' + motd_2 +\ - '\n在线玩家:' + player_count + '/' + max_players +\ - '\n游戏版本:' + edition + version_name +\ - '\n游戏模式:' + game_mode + bemsg = '[BE]\n' + \ + motd_1 + ' - ' + motd_2 + \ + '\n在线玩家:' + player_count + '/' + max_players + \ + '\n游戏版本:' + edition + version_name + \ + '\n游戏模式:' + game_mode servers.append(bemsg) except Exception: @@ -88,4 +89,7 @@ async def server(address): else: awa = '\n' servers.append("[30秒后撤回本消息]") + print(servers) + if raw: + return awa.join(servers) return re.sub(r'§\w', "", awa.join(servers)) diff --git a/modules/server/serverraw.py b/modules/server/serverraw.py deleted file mode 100644 index 39499600..00000000 --- a/modules/server/serverraw.py +++ /dev/null @@ -1,92 +0,0 @@ -import json -import re -import traceback - -import aiohttp - - -async def serverraw(address): - matchObj = re.match(r'(.*):(.*)', address, re.M | re.I) - servers = [] - - try: - if matchObj: - serip = matchObj.group(1) - port1 = matchObj.group(2) - port2 = matchObj.group(2) - else: - serip = address - port1 = '25565' - port2 = '19132' - - try: - url = 'http://motd.wd-api.com/java?ip=' + serip + '&port=' + port1 + '&mode=info' - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: - if req.status != 200: - print(f"请求时发生错误:{req.status}") - else: - motd = await req.text() - file = json.loads(motd) - try: - if file['code'] == 200: - servers.append('[JE]') - jejson = file['data'] - if 'description' in jejson: - description = jejson['description'] - if 'text' in description: - servers.append(description['text']) - elif 'extra' in description: - extra = description['extra'] - text = [] - qwq = '' - for item in extra[:]: - text.append(item['text']) - servers.append(qwq.join(text)) - else: - servers.append(description) - - if 'players' in jejson: - onlinesplayer = f"在线玩家:{str(jejson['players']['online'])} / {str(jejson['players']['max'])}" - servers.append(onlinesplayer) - if 'version' in jejson: - versions = "游戏版本:" + file['data']['version']['name'] - servers.append(versions) - servers.append(serip + ':' + port1) - else: - print('获取JE服务器信息失败。') - except Exception: - traceback.print_exc() - servers.append("[JE]\n发生错误:调用API时发生错误。") - except Exception: - print('获取JE服务器信息失败。') - traceback.print_exc() - try: - beurl = 'http://motd.wd-api.com/bedrock?ip=' + serip + '&port=' + port2 + '&mode=info' - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: - if req.status != 200: - print(f"请求时发生错误:{req.status}") - else: - bemotd = await req.text() - bejson = json.loads(bemotd) - edition, motd_1, protocol, version_name, player_count, max_players, unique_id, motd_2, \ - game_mode, game_mode_num, port_v4, port_v6, nothing_here = bejson['motd'].split(';') - bemsg = '[BE]\n' +\ - motd_1 + ' - ' + motd_2 +\ - '\n在线玩家:' + player_count + '/' + max_players +\ - '\n游戏版本:' + edition + version_name +\ - '\n游戏模式:' + game_mode - servers.append(bemsg) - - except Exception: - print('获取BE服务器信息失败。') - traceback.print_exc() - if str(servers) == '[]': - return ('连接失败,没有检测到任何服务器。') - else: - awa = '\n' - servers.append("[30秒后撤回本消息]") - return awa.join(servers) - except Exception as e: - return ("发生错误:" + str(e) + ".") diff --git a/modules/user/__init__.py b/modules/user/__init__.py index db61e8c5..873d62b1 100644 --- a/modules/user/__init__.py +++ b/modules/user/__init__.py @@ -1,64 +1,101 @@ import re -from modules.help import userhelp -from modules.interwikilist import iwlink, iwlist +from graia.application import Group, Friend, MessageChain +from graia.application.message.elements.internal import Image, UploadMethods, Plain + +from core.template import sendMessage +from modules.wiki.database import get_start_wiki, get_custom_interwiki from .userlib import User -async def main(command): - try: - commandsplit = command.split(' ') - except Exception: - commandsplit = [] - if '-h' in commandsplit: - return userhelp() - else: - s = re.match(r'~(.*?) (.*)', command) - if s: - metaurl = 'https://' + s.group(1) + '.gamepedia.com/' - if '-r' in commandsplit: - rmargv = re.sub(' -r|-r ', '', s.group(2)) - return await User(metaurl, rmargv, '-r') - elif '-p' in commandsplit: - rmargv = re.sub(' -p|-p ', '', s.group(2)) - return await User(metaurl, rmargv, '-p') - else: - return await User(metaurl, s.group(2)) - i = re.match(r'(.*?):(.*)', command) - if i: - w = i.group(1) - rmargv = i.group(2) - if w in iwlist(): - metaurl = iwlink(w) - if '-r' in commandsplit: - rmargv = re.sub(' -r|-r ', '', rmargv) - return await User(metaurl, rmargv, '-r') - elif '-p' in commandsplit: - rmargv = re.sub(' -p|-p ', '', rmargv) - return await User(metaurl,rmargv, '-p') - else: - return await User(metaurl, rmargv) - else: - metaurl = 'https://minecraft.gamepedia.com/' - if '-r' in commandsplit: - rmargv = re.sub(' -r|-r ', '', rmargv) - return await User(metaurl, rmargv,'-r') - elif '-p' in commandsplit: - rmargv = re.sub(' -p|-p ', '', rmargv) - return await User(metaurl,rmargv, '-p') - else: - return await User(metaurl, rmargv) +# 使用次数过少,故简单移植处理( +async def main(kwargs: dict): + command = re.sub('^user ', '', kwargs['trigger_msg']) + commandsplit = command.split(' ') + s = re.match(r'~(.*?) (.*)', command) + if s: + metaurl = 'https://' + s.group(1) + '.gamepedia.com/api.php' + if '-r' in commandsplit: + rmargv = re.sub(' -r|-r ', '', s.group(2)) + result = await User(metaurl, rmargv, '-r') + elif '-p' in commandsplit: + rmargv = re.sub(' -p|-p ', '', s.group(2)) + result = await User(metaurl, rmargv, '-p') else: - metaurl = 'https://minecraft.gamepedia.com/' + result = await User(metaurl, s.group(2)) + i = re.match(r'(.*?):(.*)', command) + if i: + w = i.group(1) + rmargv = i.group(2) + if Group in kwargs: + table = 'custom_interwiki_group' + id = kwargs[Group].id + if Friend in kwargs: + table = 'custon_interwiki_self' + id = kwargs[Friend].id + get_iw = get_custom_interwiki(table, id, w) + if get_iw: + metaurl = get_iw + if '-r' in commandsplit: + rmargv = re.sub(' -r|-r ', '', rmargv) + result = await User(metaurl, rmargv, '-r') + elif '-p' in commandsplit: + rmargv = re.sub(' -p|-p ', '', rmargv) + result = await User(metaurl, rmargv, '-p') + else: + result = await User(metaurl, rmargv) + else: + if Group in kwargs: + table = 'start_wiki_link_group' + if Friend in kwargs: + table = 'start_wiki_link_self' + get_url = get_start_wiki(table, id) + if get_url: + metaurl = get_url + if '-r' in commandsplit: + rmargv = re.sub(' -r|-r ', '', rmargv) + result = await User(metaurl, rmargv, '-r') + elif '-p' in commandsplit: + rmargv = re.sub(' -p|-p ', '', rmargv) + result = await User(metaurl, rmargv, '-p') + else: + result = await User(metaurl, rmargv) + else: + if Group in kwargs: + table = 'start_wiki_link_group' + id = kwargs[Group].id + if Friend in kwargs: + table = 'start_wiki_link_self' + id = kwargs[Friend].id + get_url = get_start_wiki(table, id) + if get_url: + metaurl = get_url if '-r' in commandsplit: rmargv = re.sub(' -r|-r ', '', command) - return await User(metaurl, rmargv, '-r') + result = await User(metaurl, rmargv, '-r') elif '-p' in commandsplit: rmargv = re.sub(' -p|-p ', '', command) - return await User(metaurl, rmargv, '-p') + result = await User(metaurl, rmargv, '-p') else: - return await User(metaurl, command) + result = await User(metaurl, command) + if result: + matchimg = re.match('.*\[\[uimgc:(.*)]]', result) + if matchimg: + if Group in kwargs: + mth = UploadMethods.Group + if Friend in kwargs: + mth = UploadMethods.Friend + imgchain = MessageChain.create([Image.fromLocalFile(matchimg.group(1), method=mth)]) + result = re.sub('\[\[uimgc:.*]]', '', result) + msgchain = MessageChain.create([Plain(result)]) + msgchain = msgchain.plusWith(imgchain) + else: + msgchain = MessageChain.create([Plain(result)]) + await sendMessage(kwargs, msgchain) - -command = {'user': 'user'} +command = {'user': main} +help = {'user':{'module':'获取一个Gamepedia用户的信息。', + 'help':'~user [~(wiki_name)] - 获取一个Gamepedia用户的信息。' + + '\n[-r] - 获取详细信息' + + '\n[-p] - 生成一张图片'}} diff --git a/modules/user/tpg.py b/modules/user/tpg.py index 80f86a97..673a6c1d 100644 --- a/modules/user/tpg.py +++ b/modules/user/tpg.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- +import uuid from os.path import abspath from PIL import Image from PIL import ImageDraw from PIL import ImageFont -import uuid def tpg(favicon, wikiname, username, gender, registertime, contributionwikis, createcount, editcount, deletecount, patrolcount, sitetop, globaltop, wikipoint, blockbyuser='0', blocktimestamp1='0', blocktimestamp2='0', @@ -103,6 +103,6 @@ def tpg(favicon, wikiname, username, gender, registertime, contributionwikis, cr draw.text((200, 1539), '到' + str(blocktimestamp2), '#ffffff', font=font) if bantype == 'Y': draw.text((200, 1589), str(blockreason), '#ffffff', font=font) - filepath = abspath('./assets/cache/' + str(uuid.uuid4()) + '.png') + filepath = abspath('./cache/' + str(uuid.uuid4()) + '.png') img3.save(filepath) return filepath diff --git a/modules/user/userlib.py b/modules/user/userlib.py index f4ae2f4b..6b88a86c 100644 --- a/modules/user/userlib.py +++ b/modules/user/userlib.py @@ -3,7 +3,7 @@ import urllib import aiohttp -from modules.UTC8 import UTC8 +from modules.utils.UTC8 import UTC8 from .tool import yhz, gender @@ -18,7 +18,7 @@ async def get_data(url: str, fmt: str): async def getwikiname(wikiurl): try: - wikinameurl = wikiurl + 'api.php?action=query&meta=allmessages&ammessages=mainpage&format=json' + wikinameurl = wikiurl + '?action=query&meta=allmessages&ammessages=mainpage&format=json' wikiname = await get_data(wikinameurl, 'json') Wikiname = wikiname['query']['allmessages'][0]['*'] except Exception: @@ -32,7 +32,7 @@ def d(str1): async def User(wikiurl, username, argv=None): - UserJsonURL = wikiurl + 'api.php?action=query&list=users&ususers=' + username + '&usprop=groups%7Cblockinfo%7Cregistration%7Ceditcount%7Cgender&format=json' + UserJsonURL = wikiurl + '?action=query&list=users&ususers=' + username + '&usprop=groups%7Cblockinfo%7Cregistration%7Ceditcount%7Cgender&format=json' GetUserJson = await get_data(UserJsonURL, 'json') Wikiname = await getwikiname(wikiurl) try: @@ -48,8 +48,8 @@ async def User(wikiurl, username, argv=None): if BlockedBy: Blockedtimestamp = UTC8(GetUserJson['query']['users'][0]['blockedtimestamp'], 'full') Blockexpiry = UTC8(str(GetUserJson['query']['users'][0]['blockexpiry']), 'full') - Blockmessage = f'\n{User}正在被封禁!' +\ - f'\n被{BlockedBy}封禁,时间从{Blockedtimestamp}到{Blockexpiry}' + Blockmessage = f'\n{User}正在被封禁!' + \ + f'\n被{BlockedBy}封禁,时间从{Blockedtimestamp}到{Blockexpiry}' try: Blockreason = GetUserJson['query']['users'][0]['blockreason'] if Blockreason: @@ -60,6 +60,7 @@ async def User(wikiurl, username, argv=None): pass if argv == '-r' or argv == '-p': from bs4 import BeautifulSoup as bs + wikiurl = re.sub('api.php', '', wikiurl) clawerurl = wikiurl + 'UserProfile:' + username clawer = await get_data(clawerurl, 'text') soup = bs(clawer, 'html.parser') @@ -79,6 +80,9 @@ async def User(wikiurl, username, argv=None): matchlink = re.match(r'https?://(.*)/', wikiurl) filepath = os.path.abspath('./assets/Favicon/' + matchlink.group(1) + '/') if not os.path.exists(filepath): + favicon_path = os.path.abspath('./assets/Favicon/') + if not os.path.exists(favicon_path): + os.mkdir(favicon_path) os.mkdir(filepath) wikipng = os.path.abspath('./assets/Favicon/' + matchlink.group(1) + '/Wiki.png') if not os.path.exists(wikipng): @@ -100,55 +104,55 @@ async def User(wikiurl, username, argv=None): pass if Brs == 1: imagepath = tpg(favicon=wikipng, - wikiname=Wikiname, - username=User, - gender=Gender, - registertime=Registration, - contributionwikis=d(str(dd[0])), - createcount=d(str(dd[1])), - editcount=d(str(dd[2])), - deletecount=d(str(dd[3])), - patrolcount=d(str(dd[4])), - sitetop=d(str(dd[5])), - globaltop=d(str(dd[6])), - wikipoint=point, - blockbyuser=BlockedBy, - blocktimestamp1=Blockedtimestamp, - blocktimestamp2=Blockexpiry, - bantype='YN') + wikiname=Wikiname, + username=User, + gender=Gender, + registertime=Registration, + contributionwikis=d(str(dd[0])), + createcount=d(str(dd[1])), + editcount=d(str(dd[2])), + deletecount=d(str(dd[3])), + patrolcount=d(str(dd[4])), + sitetop=d(str(dd[5])), + globaltop=d(str(dd[6])), + wikipoint=point, + blockbyuser=BlockedBy, + blocktimestamp1=Blockedtimestamp, + blocktimestamp2=Blockexpiry, + bantype='YN') elif Brs == 2: imagepath = tpg(favicon=wikipng, - wikiname=Wikiname, - username=User, - gender=Gender, - registertime=Registration, - contributionwikis=d(str(dd[0])), - createcount=d(str(dd[1])), - editcount=d(str(dd[2])), - deletecount=d(str(dd[3])), - patrolcount=d(str(dd[4])), - sitetop=d(str(dd[5])), - globaltop=d(str(dd[6])), - wikipoint=point, - blockbyuser=BlockedBy, - blocktimestamp1=Blockedtimestamp, - blocktimestamp2=Blockexpiry, - blockreason=Blockreason, - bantype='Y') + wikiname=Wikiname, + username=User, + gender=Gender, + registertime=Registration, + contributionwikis=d(str(dd[0])), + createcount=d(str(dd[1])), + editcount=d(str(dd[2])), + deletecount=d(str(dd[3])), + patrolcount=d(str(dd[4])), + sitetop=d(str(dd[5])), + globaltop=d(str(dd[6])), + wikipoint=point, + blockbyuser=BlockedBy, + blocktimestamp1=Blockedtimestamp, + blocktimestamp2=Blockexpiry, + blockreason=Blockreason, + bantype='Y') except KeyError: imagepath = tpg(favicon=wikipng, - wikiname=Wikiname, - username=User, - gender=Gender, - registertime=Registration, - contributionwikis=d(str(dd[0])), - createcount=d(str(dd[1])), - editcount=d(str(dd[2])), - deletecount=d(str(dd[3])), - patrolcount=d(str(dd[4])), - sitetop=d(str(dd[5])), - globaltop=d(str(dd[6])), - wikipoint=point) + wikiname=Wikiname, + username=User, + gender=Gender, + registertime=Registration, + contributionwikis=d(str(dd[0])), + createcount=d(str(dd[1])), + editcount=d(str(dd[2])), + deletecount=d(str(dd[3])), + patrolcount=d(str(dd[4])), + sitetop=d(str(dd[5])), + globaltop=d(str(dd[6])), + wikipoint=point) if argv == '-p': return f'{wikiurl}UserProfile:{urllib.parse.quote(rmuser.encode("UTF-8"))}[[uimgc:{imagepath}]]' return (wikiurl + 'UserProfile:' + urllib.parse.quote(rmuser.encode('UTF-8')) + '\n' + @@ -162,4 +166,4 @@ async def User(wikiurl, username, argv=None): return '没有找到此用户。' else: import traceback - traceback.print_exc() \ No newline at end of file + traceback.print_exc() diff --git a/modules/UTC8.py b/modules/utils/UTC8.py similarity index 100% rename from modules/UTC8.py rename to modules/utils/UTC8.py diff --git a/modules/utils/__init__.py b/modules/utils/__init__.py new file mode 100644 index 00000000..6558e40a --- /dev/null +++ b/modules/utils/__init__.py @@ -0,0 +1,68 @@ +import asyncio +import time + +import psutil +from graia.application import Group, Friend + +from core.template import sendMessage, revokeMessage +from modules.utils.ab import ab +from modules.utils.newbie import newbie +from modules.utils.rc import rc + + +async def rc_loader(kwargs: dict): + if Group in kwargs: + table = 'start_wiki_link_group' + id = kwargs[Group].id + if Friend in kwargs: + table = 'start_wiki_link_self' + id = kwargs[Friend].id + msg = await rc(table, id) + await sendMessage(kwargs, msg) + + +async def ab_loader(kwargs: dict): + if Group in kwargs: + table = 'start_wiki_link_group' + id = kwargs[Group].id + if Friend in kwargs: + table = 'start_wiki_link_self' + id = kwargs[Friend].id + msg = await ab(table, id) + send = await sendMessage(kwargs, msg) + await asyncio.sleep(60) + await revokeMessage(send) + + +async def newbie_loader(kwargs: dict): + if Group in kwargs: + table = 'start_wiki_link_group' + id = kwargs[Group].id + if Friend in kwargs: + table = 'start_wiki_link_self' + id = kwargs[Friend].id + msg = await newbie(table, id) + await sendMessage(kwargs, msg) + + +async def ping(kwargs: dict): + Boot_Start = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(psutil.boot_time())) + time.sleep(0.5) + Cpu_usage = psutil.cpu_percent() + RAM = int(psutil.virtual_memory().total / (1027 * 1024)) + RAM_percent = psutil.virtual_memory().percent + Swap = int(psutil.swap_memory().total / (1027 * 1024)) + Swap_percent = psutil.swap_memory().percent + BFH = r'%' + result = ("Pong!\n" + "系统运行时间:%s" % Boot_Start \ + + "\n当前CPU使用率:%s%s" % (Cpu_usage, BFH) \ + + "\n物理内存:%dM 使用率:%s%s" % (RAM, RAM_percent, BFH) \ + + "\nSwap内存:%dM 使用率:%s%s" % (Swap, Swap_percent, BFH)) + await sendMessage(kwargs, result) + +command = {'rc': rc_loader, 'ab': ab_loader, 'newbie': newbie_loader} +essential = {'ping': ping} +help = {'rc': {'module': '查询Wiki最近更改。', 'help': '~rc - 查询Wiki最近更改。'}, + 'ab': {'module': '查询Wiki滥用过滤器日志。', 'help': '~ab - 查询Wiki滥用过滤器日志。'}, + 'newbie': {'module': '查询Wiki用户注册日志。', 'help': '~newbie - 查询Wiki用户注册日志。'}, + 'ping': {'module': 'Pong', 'help': '~ping - PongPongPong', 'essential': True}} \ No newline at end of file diff --git a/modules/utils/ab.py b/modules/utils/ab.py new file mode 100644 index 00000000..ec050365 --- /dev/null +++ b/modules/utils/ab.py @@ -0,0 +1,31 @@ +import json + +import aiohttp + +from core.dirty_check import check +from modules.utils.UTC8 import UTC8 +from modules.wiki.database import get_start_wiki + + +async def ab(table, id): + get_wiki_url = get_start_wiki(table, id) + if get_wiki_url: + url = get_wiki_url + '?action=query&list=abuselog&aflprop=user|title|action|result|filter|timestamp&format=json' + async with aiohttp.ClientSession() as session: + async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: + if req.status != 200: + return f"请求时发生错误:{req.status}" + else: + text1 = await req.text() + file = json.loads(text1) + d = [] + for x in file['query']['abuselog'][:5]: + d.append('•' + x['title'] + ' - ' + x['user'] + '于' + UTC8(x['timestamp'], 'onlytimenoutc') + '\n过滤器名:' + x[ + 'filter'] + '\n处理结果:' + x['result']) + y = await check(d) + if y.find('<吃掉了>') != -1 or y.find('<全部吃掉了>') != -1: + return y + '\n...仅显示前5条内容\n检测到外来信息介入,请前往滥用日志查看所有消息。Special:滥用日志\n[一分钟后撤回本消息]' + else: + return y + '\n...仅显示前5条内容\n[一分钟后撤回本消息]' + else: + return '未设定起始Wiki。' diff --git a/modules/newbie/__init__.py b/modules/utils/newbie.py similarity index 68% rename from modules/newbie/__init__.py rename to modules/utils/newbie.py index b81eb6e8..e423689b 100644 --- a/modules/newbie/__init__.py +++ b/modules/utils/newbie.py @@ -1,14 +1,16 @@ -# -*- coding:utf-8 -*- import json import re import aiohttp -from modules.pbc import pbc +from core.dirty_check import check +from modules.wiki.database import get_start_wiki -async def main(): - url = 'https://minecraft-zh.gamepedia.com/api.php?action=query&list=logevents&letype=newusers&format=json' +async def newbie(table, id): + get_wiki_url = get_start_wiki(table, id) + if get_wiki_url: + url = get_wiki_url + '?action=query&list=logevents&letype=newusers&format=json' async with aiohttp.ClientSession() as session: async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: if req.status != 200: @@ -20,16 +22,12 @@ async def main(): for x in file['query']['logevents']: d.append(x['title']) print(str(d)) - y = await pbc(d) - space = '\n' + m = '\n'.join(d) + y = await check([m]) print(str(y)) - j = space.join(y) - f = re.findall(r'.*\n.*\n.*\n.*\n.*', j) + f = re.findall(r'.*\n.*\n.*\n.*\n.*', str(y)) g = '这是当前的新人列表:\n' + f[0] + '\n...仅显示前5条内容' if g.find('<吃掉了>') != -1 or g.find('<全部吃掉了>') != -1: return (g + '\n检测到外来信息介入,请前往日志查看所有消息。Special:日志?type=newusers') else: return (g) - - -command = {'新人': 'newbie'} diff --git a/modules/utils/rc.py b/modules/utils/rc.py new file mode 100644 index 00000000..e3d6f46a --- /dev/null +++ b/modules/utils/rc.py @@ -0,0 +1,34 @@ +import json + +import aiohttp + +from core.dirty_check import check +from modules.utils.UTC8 import UTC8 +from modules.wiki.database import get_start_wiki + + +async def rc(table, id): + get_wiki_url = get_start_wiki(table, id) + if get_wiki_url: + url = get_wiki_url + '?action=query&list=recentchanges&rcprop=title|user|timestamp&rctype=edit|new&format=json' + async with aiohttp.ClientSession() as session: + async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: + if req.status != 200: + return f"请求时发生错误:{req.status}" + else: + text1 = await req.text() + file = json.loads(text1) + d = [] + for x in file['query']['recentchanges'][:5]: + d.append(x['title'] + ' - ' + x['user'] + ' ' + UTC8(x['timestamp'], 'onlytime')) + m = '\n'.join(d) + print(m) + y = await check([m]) + print(y) + if y.find('<吃掉了>') != -1 or y.find('<全部吃掉了>') != -1: + msg = y + '\n...仅显示前5条内容\n检测到外来信息介入,请前往最近更改查看所有消息。Special:最近更改' + else: + msg = y + '\n...仅显示前5条内容' + return msg + else: + return '未设定起始Wiki。' diff --git a/modules/wiki/__init__.py b/modules/wiki/__init__.py index 0052998f..06358a8f 100644 --- a/modules/wiki/__init__.py +++ b/modules/wiki/__init__.py @@ -1,9 +1,17 @@ import re -import traceback -from modules.help import wikihelp -from modules.interwikilist import iwlist, iwlink -from .wikilib import wiki +from graia.application import MessageChain +from graia.application.friend import Friend +from graia.application.group import Group, Member +from graia.application.message.elements.internal import Image, UploadMethods +from graia.application.message.elements.internal import Plain + +import modules.wiki.database as database +import modules.wiki.wikilib +from core.template import sendMessage, check_permission, wait_confirm, revokeMessage +from database import warn_someone, check_enable_modules_self, check_enable_modules +from modules.wiki.helper import check_wiki_available +from .getinfobox import get_infobox_pic langcode = ['ab', 'aa', 'af', 'sq', 'am', 'ar', 'hy', 'as', 'ay', 'az', 'ba', 'eu', 'bn', 'dz', 'bh', 'bi', 'br', 'bg', 'my', 'be', 'km', 'ca', 'zh', 'co', 'hr', 'cs', 'da', 'nl', 'en', 'eo', 'et', 'fo', 'fa', 'fj', 'fi', 'fr', @@ -14,131 +22,320 @@ langcode = ['ab', 'aa', 'af', 'sq', 'am', 'ar', 'hy', 'as', 'ay', 'az', 'ba', 'e 'si', 'ss', 'sk', 'sl', 'so', 'es', 'su', 'sw', 'sv', 'tl', 'tg', 'ta', 'tt', 'te', 'th', 'to', 'ts', 'tr', 'tk', 'tw', 'ug', 'uk', 'ur', 'uz', 'vi', 'vo', 'cy', 'wo', 'xh', 'yi', 'yo', 'zu'] -wiki = wiki().main -async def main(message, group=0): - if message == '-h': - return wikihelp() +async def wiki_loader(kwargs: dict): + command = kwargs['trigger_msg'] + command = re.sub(r'^wiki ', '', command) + if Group in kwargs: + start_table = 'start_wiki_link_group' + if Friend in kwargs: + start_table = 'start_wiki_link_self' + get_link = database.get_start_wiki(start_table, kwargs[Group].id) + if not get_link: + if Group in kwargs: + prompt = '没有指定起始Wiki,请管理员在群内发送~wiki_start_site <域名>来设定起始Wiki。\n例子:~wiki_start_site https://minecraft-zh.gamepedia.com/' + if Friend in kwargs: + prompt = '没有指定起始Wiki,请发送~wiki_start_site <域名>来设定起始Wiki。\n例子:~wiki_start_site https://minecraft-zh.gamepedia.com/' + await sendMessage(kwargs, MessageChain.create([Plain(prompt)])) else: - matchsite = re.match(r'~(.*?) (.*)', message) - if matchsite: - wikiurl = 'https://' + matchsite.group(1) + '.gamepedia.com/' - return await wiki(wikiurl, matchsite.group(2), 'gp:' + matchsite.group(1)) - return await choosemethod(message, group) + iw = None + co = False + if Group in kwargs: + check_gamepedia_addon_enable = check_enable_modules(kwargs[Group].id, + 'wiki_gamepedia_addon') + if check_gamepedia_addon_enable: + matchsite = re.match(r'~(.*?) (.*)', command) + if matchsite: + get_link = 'https://' + matchsite.group(1) + '.gamepedia.com/api.php' + iw = 'gp:' + matchsite.group(1) + co = True + command = matchsite.group(2) + matchgp = re.match(r'^gp:(.*?):(.*)', command) + if matchgp: + get_link = 'https://' + matchgp.group(1) + '.gamepedia.com/api.php' + iw = 'gp:' + matchgp.group(1) + co = True + command = matchsite.group(2) + print(co) + matchinterwiki = re.match(r'(.*?):(.*)', command) + if matchinterwiki and not co: + if Group in kwargs: + get_custom_iw = database.get_custom_interwiki('custom_interwiki_group', kwargs[Group].id, + matchinterwiki.group(1)) + if Friend in kwargs: + get_custom_iw = database.get_custom_interwiki('custom_interwiki_self', kwargs[Friend].id, + matchinterwiki.group(1)) + if get_custom_iw: + iw = matchinterwiki.group(1) + get_link = get_custom_iw + command = re.sub(matchinterwiki.group(1) + ':', '', command) + msg = await wikilib.wikilib().main(get_link, command, interwiki=iw) + if msg['status'] == 'done': + msgchain = MessageChain.create([Plain((msg['url'] + '\n' if 'url' in msg else '') + msg['text'])]) + if 'net_image' in msg: + try: + if Group in kwargs: + mth = UploadMethods.Group + elif Friend in kwargs: + mth = UploadMethods.Friend + imgchain = MessageChain.create([Image.fromNetworkAddress(msg['net_image'], method=mth)]) + msgchain = msgchain.plusWith(imgchain) + except: + pass + await sendMessage(kwargs, msgchain) + if 'url' in msg: + check_options = check_enable_modules_self(kwargs[Member].id if Group in kwargs else kwargs[Friend].id, + 'wiki_infobox') + print(check_options) + if check_options: + pic = await get_infobox_pic(get_link, msg['url']) + if Group in kwargs: + mth = UploadMethods.Group + elif Friend in kwargs: + mth = UploadMethods.Friend + imgchain = MessageChain.create([Image.fromLocalFile(pic, method=mth)]) + await sendMessage(kwargs, imgchain) + + elif msg['status'] == 'wait': + await sendMessage(kwargs, MessageChain.create([Plain(msg['text'])])) + wait = await wait_confirm(kwargs) + if wait: + msg = await wikilib.wikilib().main(get_link, msg['title']) + await sendMessage(kwargs, MessageChain.create([Plain(msg['title'])])) + elif msg['status'] == 'warn': + if Group in kwargs: + trigger = kwargs[Member].id + if Friend in kwargs: + trigger = kwargs[Friend].id + warn_someone(trigger) + await sendMessage(kwargs, MessageChain.create([Plain(msg['text'])])) -async def choosemethod(matchmsg, group=0, basewiki='en'): - try: - pagename = matchmsg - if group == 250500369 or group == 676942198: - wikiurl = 'https://wiki.arcaea.cn/' - return await wiki(wikiurl, pagename, 'arc') +async def set_start_wiki(kwargs: dict): + if Group in kwargs: + if check_permission(kwargs): + command = kwargs['trigger_msg'] + command = re.sub(r'^wiki_start_site ', '', command) + check = await check_wiki_available(command) + if check: + result = database.add_start_wiki('start_wiki_link_group', kwargs[Group].id, check[0]) + await sendMessage(kwargs, MessageChain.create([Plain(result + check[1])])) + else: + result = '错误:此Wiki不是一个有效的MediaWiki/尝试建立连接超时。' + await sendMessage(kwargs, MessageChain.create([Plain(result)])) else: - matchinterwiki = re.match(r'(.*?):(.*)', matchmsg) - if matchinterwiki: - pagename = matchinterwiki.group(2) - interwiki = str.lower(matchinterwiki.group(1)) - if interwiki == 'gp': - matchsitename = re.match(r'(.*?):(.*)', pagename) - wikiurl = 'https://' + matchsitename.group(1) + '.gamepedia.com/' - return await wiki(wikiurl, matchsitename.group(2), 'gp:' + matchsitename.group(1)) - if interwiki == 'fd': - matchsitename = re.match(r'(.*?):(.*)', pagename) - wikiurl = f'https://{matchsitename.group(1)}.fandom.com/' - pagename = matchsitename.group(2) - interwiki = 'fd:' + matchsitename.group(1) - matchlangcode = re.match(r'(.*?):(.*)', matchsitename.group(2)) - if matchlangcode: - if matchlangcode.group(1) in langcode: - wikiurl = f'https://{matchsitename.group(1)}.fandom.com/{matchlangcode.group(1)}/' - pagename = matchlangcode.group(2) - interwiki = 'fd:' + matchsitename.group(1) + ':' + matchlangcode.group(1) - return await wiki(wikiurl, pagename, interwiki) - if interwiki == 'w': - matchsitename = re.match(r'(.*?):(.*)', pagename) - if matchsitename.group(1) == 'c': - matchsitename = re.match(r'(.*?):(.*)', matchsitename.group(2)) - wikiurl = f'https://{matchsitename.group(1)}.fandom.com/' - pagename = matchsitename.group(2) - interwiki = 'w:c:' + matchsitename.group(1) - matchlangcode = re.match(r'(.*?):(.*)', matchsitename.group(2)) - if matchlangcode: - if matchlangcode.group(1) in langcode: - wikiurl = f'https://{matchsitename.group(1)}.fandom.com/{matchlangcode.group(1)}/' - pagename = matchlangcode.group(2) - interwiki = 'w:c:' + matchsitename.group(1) + ':' + matchlangcode.group(1) - return await wiki(wikiurl, pagename, interwiki) - if interwiki in iwlist(): - wikiurl = iwlink(interwiki) - return await wiki(wikiurl, pagename, interwiki) - elif interwiki in ['Wikipedia', 'wikipedia', 'WP', 'wp']: - return '暂不支持Wikipedia查询。' + result = '你没有使用该命令的权限。' + await sendMessage(kwargs, MessageChain.create([Plain(result)])) + if Friend in kwargs: + command = kwargs['trigger_msg'] + command = re.sub(r'^wiki_start_site ', '', command) + check = await check_wiki_available(command) + if check: + result = database.add_start_wiki('start_wiki_link_self', kwargs[Friend].id, check[0]) + await sendMessage(kwargs, MessageChain.create([Plain(result + check[1])])) + else: + result = '错误:此Wiki不是一个有效的MediaWiki/尝试建立连接超时。' + await sendMessage(kwargs, MessageChain.create([Plain(result)])) + + +async def interwiki(kwargs: dict): + command = kwargs['trigger_msg'] + command = re.sub(r'^interwiki ', '', command) + command = command.split(' ') + if Group in kwargs: + check = check_permission(kwargs) + if check: + if command[0] == 'add': + iw = command[1].split('>') + check = await check_wiki_available(iw[1]) + if check: + result = database.config_custom_interwiki('add', 'custom_interwiki_group', kwargs[Group].id, iw[0], + check[0]) + await sendMessage(kwargs, MessageChain.create([Plain(result + check[1])])) else: - wikiurl = iwlink(basewiki) - return await wiki(wikiurl, matchmsg, '') + result = '错误:此Wiki不是一个有效的MediaWiki/尝试建立连接超时。' + await sendMessage(kwargs, MessageChain.create([Plain(result)])) + elif command[0] == 'del': + result = database.config_custom_interwiki('del', 'custom_interwiki_group', kwargs[Group].id, command[1]) + await sendMessage(kwargs, MessageChain.create([Plain(result)])) else: - wikiurl = iwlink(basewiki) - return await wiki(wikiurl, matchmsg, '') - except Exception as e: - traceback.print_exc() - return f'发生错误:{str(e)}' - - -async def im(message): - z = [] - a = '\n' - for x in message: - pipe = re.match(r'(.*?)\|.*', x) - if pipe: - x = pipe.group(1) - x = re.sub(r'^:', '', x) - url = iwlink('zh') - pagename = x - interwiki = '' - matchinterwiki = re.match(r'(.*?):(.*)', x, re.I) - if matchinterwiki: - z.append(await choosemethod(x, basewiki='zh')) + await sendMessage(kwargs, '命令不合法。') else: - z.append(await wiki(url, pagename, interwiki)) - return a.join(z) - - -async def imarc(message): - z = [] - a = '\n' - for x in message: - pipe = re.match(r'(.*?)\|.*', x, re.I) - x = pipe.group(1) - x = re.sub(r'^:', '', x) - url = 'https://wiki.arcaea.cn/' - interwiki = '' - z.append(await wiki(url, x, interwiki, igmessage=True)) - return a.join(z) - - -async def imt(message): - z = [] - a = '\n' - for x in message: - pipe = re.match(r'(.*?)\|.*', x, re.I) - if pipe: - x = pipe.group(1) - x = re.sub(r'^:', '', x) - url = iwlink('zh') - pagename = 'Template:' + x - matchinterwiki = re.match(r'(.*?):(.*)', x) - interwiki = '' - if matchinterwiki: - interwiki = matchinterwiki.group(1) - interwiki = str.lower(interwiki) - if interwiki in iwlist(): - url = iwlink(interwiki) - pagename = 'Template:' + matchinterwiki.group(2) + result = '你没有使用该命令的权限。' + await sendMessage(kwargs, MessageChain.create([Plain(result)])) + if Friend in kwargs: + if command[0] == 'add': + iw = command[1].split('>') + check = await check_wiki_available(iw[1]) + if check: + result = database.config_custom_interwiki('add', 'custom_interwiki_self', kwargs[Friend].id, iw[0], + check[0]) + await sendMessage(kwargs, MessageChain.create([Plain(result + check[1])])) else: - interwiki = '' - pagename = 'Template:' + x - z.append(await wiki(url, pagename, interwiki, igmessage=False, template=True)) - return a.join(z) + result = '错误:此Wiki不是一个有效的MediaWiki/尝试建立连接超时。' + await sendMessage(kwargs, MessageChain.create([Plain(result)])) + elif command[0] == 'del': + result = database.config_custom_interwiki('del', 'custom_interwiki_self', kwargs[Friend].id, command[1]) + await sendMessage(kwargs, MessageChain.create([Plain(result)])) + else: + await sendMessage(kwargs, '命令不合法。') -command = {'wiki': 'wiki'} +async def regex_wiki(kwargs: dict): + display = kwargs[MessageChain].asDisplay() + + async def regex_proc(kwargs: dict, display): + mains = re.findall(r'\[\[(.*?)\]\]', display, re.I) + templates = re.findall(r'\{\{(.*?)\}\}', display, re.I) + find_dict = {} + global_status = 'done' + for main in mains: + if main == '' or main in find_dict: + pass + else: + find_dict.update({main: 'main'}) + for template in templates: + if template == '' or template in find_dict: + pass + else: + find_dict.update({template: 'template'}) + if find_dict != {}: + waitlist = [] + imglist = [] + urllist = {} + msglist = MessageChain.create([]) + waitmsglist = MessageChain.create([]) + if Group in kwargs: + table = 'start_wiki_link_group' + target = kwargs[Group].id + mth = UploadMethods.Group + if Friend in kwargs: + table = 'start_wiki_link_self' + target = kwargs[Friend].id + mth = UploadMethods.Friend + for find in find_dict: + if find_dict[find] == 'template': + template = True + else: + template = False + get_link = database.get_start_wiki(table, target) + if not get_link: + if Group in kwargs: + prompt = '没有指定起始Wiki,请管理员在群内发送~wiki_start_site <域名>来设定起始Wiki。\n例子:~wiki_start_site https://minecraft-zh.gamepedia.com/' + if Friend in kwargs: + prompt = '没有指定起始Wiki,请发送~wiki_start_site <域名>来设定起始Wiki。\n例子:~wiki_start_site https://minecraft-zh.gamepedia.com/' + prompt = Plain(prompt) + if prompt not in msglist: + msglist.plusWith(MessageChain.create([prompt])) + else: + iw = None + matchinterwiki = re.match(r'(.*?):(.*)', find) + if matchinterwiki: + if Group in kwargs: + iw_table = 'custom_interwiki_group' + if Friend in kwargs: + iw_table = 'custom_interwiki_self' + get_custom_iw = modules.wiki.database.get_custom_interwiki(iw_table, + target, + matchinterwiki.group(1)) + if get_custom_iw: + get_link = get_custom_iw + find = re.sub(matchinterwiki.group(1) + ':', '', find) + iw = matchinterwiki.group(1) + # fandom addon + if matchinterwiki.group(1) == 'w': + matchinterwiki = re.match(r'(.*?):(.*)', matchinterwiki.group(2)) + if matchinterwiki: + if matchinterwiki.group(1) == 'c': + check_fandom_addon_enable = check_enable_modules(kwargs[Group].id, + 'wiki_fandom_addon') + if check_fandom_addon_enable: + matchinterwiki = re.match(r'(.*?):(.*)', matchinterwiki.group(2)) + if matchinterwiki: + matchlangcode = re.match(r'(.*?):(.*)', matchinterwiki.group(2)) + if matchlangcode: + if matchlangcode.group(1) in langcode: + get_link = f'https://{matchinterwiki.group(1)}.fandom.com/{matchlangcode.group(1)}/api.php' + find = matchlangcode.group(2) + iw = matchinterwiki.group(1) + ':' + matchlangcode.group(1) + else: + get_link = f'https://{matchinterwiki.group(1)}.fandom.com/api.php' + find = matchinterwiki.group(2) + iw = matchinterwiki.group(1) + else: + get_link = f'https://{matchinterwiki.group(1)}.fandom.com/api.php' + find = matchinterwiki.group(2) + iw = matchinterwiki.group(1) + msg = await modules.wiki.wikilib.wikilib().main(get_link, find, interwiki=iw, template=template) + status = msg['status'] + if status == 'wait': + global_status = 'wait' + waitlist.append(msg['title']) + waitmsglist = waitmsglist.plusWith(MessageChain.create( + [Plain(('\n' if msglist != MessageChain.create([]) else '') + msg['text'])])) + if status == 'warn': + global_status = 'warn' + msglist = msglist.plusWith(MessageChain.create( + [Plain(('\n' if msglist != MessageChain.create([]) else '') + msg['text'])])) + if status == 'done': + msglist = msglist.plusWith(MessageChain.create([Plain( + ('\n' if msglist != MessageChain.create([]) else '') + ( + msg['url'] + '\n' if 'url' in msg else '') + msg['text'])])) + if 'net_image' in msg: + imglist.append(msg['net_image']) + if 'url' in msg: + urllist.update({msg['url']: get_link}) + if msglist != MessageChain.create([]): + await sendMessage(kwargs, msglist) + if imglist != []: + imgchain = MessageChain.create([]) + for img in imglist: + imgchain = imgchain.plusWith(MessageChain.create([Image.fromNetworkAddress(img, method=mth)])) + await sendMessage(kwargs, imgchain) + if urllist != {}: + print(urllist) + check_options = check_enable_modules_self( + kwargs[Member].id if Group in kwargs else kwargs[Friend].id, 'wiki_infobox') + if check_options: + infoboxchain = MessageChain.create([]) + for url in urllist: + get_infobox = await get_infobox_pic(urllist[url], url) + if get_infobox: + infoboxchain = infoboxchain.plusWith( + MessageChain.create([Image.fromLocalFile(get_infobox, method=mth)])) + if infoboxchain != MessageChain.create([]): + await sendMessage(kwargs, infoboxchain) + if global_status == 'warn': + if Group in kwargs: + trigger = kwargs[Member].id + if Friend in kwargs: + trigger = kwargs[Friend].id + warn_someone(trigger) + if waitmsglist != MessageChain.create([]): + send = await sendMessage(kwargs, waitmsglist) + wait = await wait_confirm(kwargs) + if wait: + nwaitlist = [] + for waits in waitlist: + waits1 = f'[[{waits}]]' + nwaitlist.append(waits1) + await regex_proc(kwargs, '\n'.join(nwaitlist)) + else: + await revokeMessage(send) + + await regex_proc(kwargs, display) + + +command = {'wiki': wiki_loader, 'wiki_start_site': set_start_wiki, 'interwiki': interwiki} +regex = {'wiki_regex': regex_wiki} +self_options = ['wiki_infobox'] +options = ['wiki_fandom_addon', 'wiki_gamepedia_addon'] +help = {'wiki': {'module': '查询Wiki内容。', 'help': '~wiki [interwiki:] - 查询Wiki内容。'}, + 'wiki_start_site': {'module': '设置起始查询Wiki。', 'help': '~wiki_start_site - 设置起始查询Wiki。'}, + 'interwiki': {'module': '设置自定义Interwiki。', 'help': '~interwiki - 设置自定义Interwiki。'}, + 'wiki_regex': {'module':'启用正则Wikitext查询。', 'help': '[[]]|{{}} - 当聊天中出现此种Wikitext时进行自动查询。'}, + 'wiki_infobox': {'module': '当被查询的页面包含Infobox时自动提取并渲染为图片发送。', + 'help': 'Infobox渲染已开启:当被查询的页面包含Infobox时自动提取并渲染为图片发送。(群聊默认开启且不可全局关闭,个人可使用~disable self wiki_infobox关闭)', 'depend': 'wiki'}, + 'wiki_fandom_addon': {'module': '启用为Fandom定制的Wiki查询功能。(仅群聊)', + 'help': '提示:为Fandom定制的Wiki查询功能已开启,现在包含有[[w:c::[langcode:]]]的消息会自动定向查询至Fandom的Wiki。'}, + 'wiki_gamepedia_addom':{'module': '启用为Gamepedia定制的Wiki查询功能。(仅群聊)', 'help': '提示:为Gamepedia定制的查询功能已开启,现在输入~wiki ~ 会自动定向查询至Gamepedia的Wiki。'}} \ No newline at end of file diff --git a/modules/wiki/database.py b/modules/wiki/database.py new file mode 100644 index 00000000..13cefdbc --- /dev/null +++ b/modules/wiki/database.py @@ -0,0 +1,121 @@ +import os +import sqlite3 + +dbpath = os.path.abspath('./modules/wiki/save.db') + + +def initialize(): + a = open(dbpath, 'w') + a.close() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + c.execute('''CREATE TABLE start_wiki_link_group + (ID INT PRIMARY KEY NOT NULL, + LINK TEXT);''') + c.execute('''CREATE TABLE custom_interwiki_group + (ID INT PRIMARY KEY NOT NULL, + INTERWIKIS TEXT);''') + c.execute('''CREATE TABLE start_wiki_link_self + (ID INT PRIMARY KEY NOT NULL, + LINK TEXT);''') + c.execute('''CREATE TABLE custom_interwiki_self + (ID INT PRIMARY KEY NOT NULL, + INTERWIKIS TEXT);''') + c.close() + + +def add_start_wiki(table, id, value): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID={id}").fetchone() + if a: + c.execute(f"UPDATE {table} SET LINK='{value}' WHERE ID='{id}'") + conn.commit() + return '成功设置起始Wiki:' + else: + c.execute(f"INSERT INTO {table} (ID, Link) VALUES (?, ?)", (id, value)) + conn.commit() + return '成功设置起始Wiki:' + + +def get_start_wiki(table, id): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID={id}").fetchone() + if a: + return a[1] + else: + return False + + +def config_custom_interwiki(do, table, id, iw, link=None): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID={id}").fetchone() + if do == 'add': + if a: + split_iws = a[1].split('|') + iwlist = [] + for iws in split_iws: + split_iw = iws.split('>') + iwlist.append(split_iw[0]) + if iw in iwlist: + for iws in split_iws: + if iws.find(iw + '>') != -1: + split_iws.remove(iws) + split_iws.append(f'{iw}>{link}') + c.execute( + f"UPDATE {table} SET INTERWIKIS='{'|'.join(split_iws)}' WHERE ID='{id}'") + conn.commit() + return '成功:更新自定义Interwiki:' + else: + split_iws.append(f'{iw}>{link}') + c.execute( + f"UPDATE {table} SET INTERWIKIS='{'|'.join(split_iws)}' WHERE ID='{id}'") + conn.commit() + return '成功:添加自定义Interwiki:' + else: + c.execute(f"INSERT INTO {table} (ID, INTERWIKIS) VALUES (?, ?)", (id, f'{iw}>{link}')) + conn.commit() + return '成功:添加自定义Interwiki:' + elif do == 'del': + if a: + split_iws = a[1].split('|') + iwlist = [] + for iws in split_iws: + split_iw = iws.split('>') + iwlist.append(split_iw[0]) + if iw in iwlist: + for iws in split_iws: + if iws.find(iw + '>') != -1: + split_iws.remove(iws) + c.execute( + f"UPDATE {table} SET INTERWIKIS='{'|'.join(split_iws)}' WHERE ID='{id}'") + conn.commit() + return '成功:删除自定义Interwiki:' + else: + return '失败:添加过此Interwiki:' + else: + return '失败:未添加过任何Interwiki。' + + +def get_custom_interwiki(table, id, iw): + if not os.path.exists(dbpath): + initialize() + conn = sqlite3.connect(dbpath) + c = conn.cursor() + a = c.execute(f"SELECT * FROM {table} WHERE ID={id}").fetchone() + if a: + interwikis = a[1].split('|') + for iws in interwikis: + if iws.find(iw + '>') != -1: + iws = iws.split('>') + return iws[1] + else: + return False diff --git a/modules/wiki/getinfobox.py b/modules/wiki/getinfobox.py new file mode 100644 index 00000000..2aa09d49 --- /dev/null +++ b/modules/wiki/getinfobox.py @@ -0,0 +1,115 @@ +import asyncio +import json +import os +import re +import traceback +import uuid + +import aiohttp +from bs4 import BeautifulSoup +from selenium import webdriver +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities + +from config import config +from .helper import get_url + +config_path = os.path.abspath('./config/config.cfg') + +try: + if config_path: + infobox_render = config(config_path, 'infobox_render') +except: + infobox_render = None + + +async def get_infobox_pic(link, pagelink): + try: + print('hello') + link = re.sub('api.php', '', link) + try: + html = await get_url(pagelink, 'text') + except: + return False + print(111) + soup = BeautifulSoup(html, 'html.parser') + pagename = uuid.uuid4() + url = os.path.abspath(f'./cache/{pagename}.html') + if os.path.exists(url): + os.remove(url) + print(222) + find_infobox = soup.find(class_='notaninfobox') + if find_infobox is None: + find_infobox = soup.find(class_='infobox') + if find_infobox is None: + return False + + if infobox_render is None: + open_file = open(url, 'a', encoding='utf-8') + else: + html_list = [] + + for x in soup.find_all(rel='stylesheet'): + y = str(x.get('href')) + z = re.sub('^/load.php', f'{link}load.php', y) + if infobox_render is None: + open_file.write(f'\n') + else: + html_list.append(f'\n') + + replace_link = re.sub(r'href=\"/(.*)\"', 'href=\"' + link + '\\1\"', str(find_infobox), re.M) + replace_link = re.sub(r'\(/(media/)', '(' + link + '\\1', replace_link, re.M) + + if infobox_render is None: + open_file.write(str(replace_link)) + open_file.close() + else: + html_list.append(str(replace_link)) + html = {'content': '\n'.join(html_list)} + print(333) + + path2 = os.path.abspath('./assets/chromedriver.exe') + picname = os.path.abspath(f'./cache/{pagename}.jpg') + if os.path.exists(picname): + os.remove(picname) + if infobox_render is not None: + async with aiohttp.ClientSession() as session: + async with session.post(infobox_render, headers={ + 'Content-Type': 'application/json', + }, data=json.dumps(html)) as resp: + with open(picname, 'wb+') as jpg: + jpg.write(await resp.read()) + return picname + desired_capabilities = DesiredCapabilities.CHROME + desired_capabilities["pageLoadStrategy"] = "none" + options = webdriver.ChromeOptions() + options.add_argument('--headless') + options.add_argument('--disable-gpu') + driver = webdriver.Chrome(path2, options=options) + driver.set_window_size(500, 400) + js_height = "return document.body.clientHeight" + + link = url + print(link) + driver.get(link) + await asyncio.sleep(1) + k = 1 + height = driver.execute_script(js_height) + while True: + if k * 500 < height: + js_move = "window.scrollTo(0,{})".format(k * 500) + print(js_move) + driver.execute_script(js_move) + await asyncio.sleep(1) + height = driver.execute_script(js_height) + k += 1 + else: + break + scroll_width = driver.execute_script('return document.body.parentNode.scrollWidth') + scroll_height = driver.execute_script('return document.body.parentNode.scrollHeight') + driver.set_window_size(scroll_width, scroll_height) + driver.get_screenshot_as_file(picname) + driver.close() + return picname + except Exception: + traceback.print_exc() + return False diff --git a/modules/wiki/helper.py b/modules/wiki/helper.py new file mode 100644 index 00000000..e43a0f69 --- /dev/null +++ b/modules/wiki/helper.py @@ -0,0 +1,38 @@ +import re + +import aiohttp + + +async def get_url(url, fmt): + async with aiohttp.ClientSession() as session: + async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: + if hasattr(req, fmt): + return await getattr(req, fmt)() + else: + raise ValueError(f"NoSuchMethod: {fmt}") + + +async def check_wiki_available(link): + try: + api = re.match(r'(https?://.*?/api.php$)', link) + json1 = await get_url(api.group(1), 'json') + wikiname = json1['query']['general']['sitename'] + return api.group(1), wikiname + except: + pass + if link[-1] not in ['/', '\\']: + link = link + '/' + test1 = link + 'api.php?action=query&meta=siteinfo&format=json' + try: + json1 = await get_url(test1, 'json') + wikiname = json1['query']['general']['sitename'] + return link + 'api.php', wikiname + except: + pass + try: + test2 = link + 'w/api.php?action=query&meta=siteinfo&format=json' + json2 = await get_url(test2, 'json') + wikiname = json2['query']['general']['sitename'] + return link + 'w/api.php', wikiname + except: + return False diff --git a/modules/wiki/wikilib.py b/modules/wiki/wikilib.py index b78cb4d0..c5f07306 100644 --- a/modules/wiki/wikilib.py +++ b/modules/wiki/wikilib.py @@ -4,10 +4,11 @@ import urllib import aiohttp -from modules.interwikilist import iwlist, iwlink +import core.dirty_check +from .helper import check_wiki_available -class wiki: +class wikilib: async def get_data(self, url: str, fmt: str): async with aiohttp.ClientSession() as session: try: @@ -18,9 +19,44 @@ class wiki: raise ValueError(f"NoSuchMethod: {fmt}") except Exception: traceback.print_exc() + return False + + def danger_wiki_check(self): + if self.wikilink.upper().find('WIKIPEDIA') != -1: + return True + return False + + async def danger_text_check(self, text): + if not self.danger_wiki_check(): + return False + check = await core.dirty_check.check([text]) + print(check) + if check.find('<吃掉了>') != -1 or check.find('<全部吃掉了>') != -1: + return True + return False + + async def get_interwiki(self, url): + interwiki_list = url + '?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local&format=json' + json = await self.get_data(interwiki_list, 'json') + interwikimap = json['query']['interwikimap'] + interwiki_dict = {} + for interwiki in interwikimap: + interwiki_dict[interwiki['prefix']] = re.sub('\$1', '', interwiki['url']) + return interwiki_dict + + async def get_image(self, pagename): + try: + url = self.wikilink + f'?action=query&titles={pagename}&prop=imageinfo&iiprop=url&format=json' + json = await self.get_data(url, 'json') + parsepageid = self.parsepageid(json) + imagelink = json['query']['pages'][parsepageid]['imageinfo'][0]['url'] + return imagelink + except: + traceback.print_exc() + return False async def getpage(self): - getlinkurl = self.wikilink + 'api.php?action=query&format=json&prop=info&inprop=url&redirects&titles=' + self.pagename + getlinkurl = self.wikilink + '?action=query&format=json&prop=info&inprop=url&redirects&titles=' + self.pagename getpage = await self.get_data(getlinkurl, "json") return getpage @@ -32,7 +68,7 @@ class wiki: async def researchpage(self): try: - searchurl = self.wikilink + 'api.php?action=query&generator=search&gsrsearch=' + self.pagename + '&gsrsort=just_match&gsrenablerewrites&prop=info&gsrlimit=1&format=json' + searchurl = self.wikilink + '?action=query&generator=search&gsrsearch=' + self.pagename + '&gsrsort=just_match&gsrenablerewrites&prop=info&gsrlimit=1&format=json' getsecjson = await self.get_data(searchurl, "json") secpageid = self.parsepageid(getsecjson) sectitle = getsecjson['query']['pages'][secpageid]['title'] @@ -40,19 +76,30 @@ class wiki: target = '' else: target = f'{self.interwiki}:' - return f'[wait]找不到条目,您是否要找的是:[[{target}{sectitle}]]?' + prompt = f'找不到{target}{self.pagename},您是否要找的是:[[{target}{sectitle}]]?' + if self.templateprompt: + prompt = self.templateprompt + prompt + if await self.danger_text_check(prompt): + return {'status': 'done', 'text': '发生错误:拒绝访问。'} + return {'status': 'wait', 'title': f'{target}{sectitle}', 'text': prompt} except Exception: try: - searchurl = self.wikilink + 'api.php?action=query&list=search&srsearch=' + self.pagename + '&srwhat=text&srlimit=1&srenablerewrites=&format=json' + searchurl = self.wikilink + '?action=query&list=search&srsearch=' + self.pagename + '&srwhat=text&srlimit=1&srenablerewrites=&format=json' getsecjson = await self.get_data(searchurl, "json") sectitle = getsecjson['query']['search'][0]['title'] if self.interwiki == '': target = '' else: target = f'{self.interwiki}:' - return f'[wait]找不到条目,您是否要找的是:[[{target}{sectitle}]]?' + prompt = f'找不到{target}{self.pagename},您是否要找的是:[[{target}{sectitle}]]?' + if self.templateprompt: + prompt = self.templateprompt + prompt + if await self.danger_text_check(prompt): + return {'status': 'done', 'text': '发生错误:拒绝访问。'} + return {'status': 'wait', 'title': f'{target}{sectitle}', 'text': prompt} except Exception: - return '找不到条目。' + traceback.print_exc() + return {'status': 'done', 'text': '找不到条目。'} async def nullpage(self): if 'invalid' in self.psepgraw: @@ -60,18 +107,21 @@ class wiki: self.psepgraw['invalidreason']) rs = '发生错误:“' + rs1 + '”。' rs = re.sub('".”', '"”', rs) - return rs + return {'status': 'done', 'text': rs} if 'missing' in self.psepgraw: self.rspt = await self.researchpage() - self.interference() return self.rspt - - return self.orginwikilink + urllib.parse.quote(self.pagename.encode('UTF-8')) + self.orginwikilink = re.sub('api.php', '', self.orginwikilink) + if not self.sentyouprompt: + msg = self.orginwikilink + urllib.parse.quote(self.pagename.encode('UTF-8')) + else: + msg = '您要的' + self.pagename + ':' + self.orginwikilink + urllib.parse.quote(self.pagename.encode('UTF-8')) + return {'status': 'done', 'text': msg} async def getdesc(self): try: - descurl = self.wikilink + 'api.php?action=query&prop=extracts&exsentences=1&&explaintext&exsectionformat=wiki' \ - '&format=json&titles=' + self.pagename + descurl = self.wikilink + '?action=query&prop=extracts&exsentences=1&&explaintext&exsectionformat=wiki' \ + '&format=json&titles=' + self.pagename loadtext = await self.get_data(descurl, "json") pageid = self.parsepageid(loadtext) desc = loadtext['query']['pages'][pageid]['extract'] @@ -82,17 +132,22 @@ class wiki: async def getfirstline(self): try: - descurl = self.wikilink + f'api.php?action=parse&page={self.gflpagename}&prop=wikitext§ion=1&format=json' + descurl = self.wikilink + f'?action=parse&page={self.gflpagename}&prop=wikitext§ion=1&format=json' loaddesc = await self.get_data(descurl, 'json') descraw = loaddesc['parse']['wikitext']['*'] cutdesc = re.findall(r'(.*(?:!|\?|\.|;|!|?|。|;))', descraw, re.S | re.M) desc = cutdesc[0] except Exception: + traceback.print_exc() desc = '' return desc async def step1(self): + if self.template: + self.pagename = 'Template:' + self.pagename self.pageraw = await self.getpage() + if not self.pageraw: + return {'status': 'done', 'text': '发生错误:无法获取到页面。'} if 'redirects' in self.pageraw['query']: self.pagename = self.pageraw['query']['redirects'][0]['to'] self.pageid = self.parsepageid(self.pageraw) @@ -103,8 +158,8 @@ class wiki: if self.template == True: self.pagename = self.orginpagename = re.sub(r'^Template:', '', self.pagename) self.template = False - self.interference() - return f'提示:[Template:{self.pagename}]不存在,已自动回滚搜索页面。\n' + await self.step1() + self.templateprompt = f'提示:[Template:{self.pagename}]不存在,已自动回滚搜索页面。\n' + return await self.step1() return await self.nullpage() else: return await self.step2() @@ -116,6 +171,7 @@ class wiki: if desc == '': self.gflpagename = geturlpagename.group(2) desc = await self.getfirstline() + print(desc) try: section = re.match(r'.*(\#.*)', self.pagename) finpgname = geturlpagename.group(2) + urllib.parse.quote(section.group(1).encode('UTF-8')) @@ -125,10 +181,10 @@ class wiki: finpgname = urllib.parse.unquote(finpgname) finpgname = re.sub('_', ' ', finpgname) if finpgname == self.orginpagename: - rmlstlb = re.sub('\n$', '', fullurl + '\n' + desc) + rmlstlb = re.sub('\n$', '', desc) else: rmlstlb = re.sub('\n$', '', - f'\n(重定向[{self.orginpagename}] -> [{finpgname}])\n{fullurl}\n{desc}') + f'(重定向[{self.orginpagename}] -> [{finpgname}]){desc}') rmlstlb = re.sub('\n\n', '\n', rmlstlb) rmlstlb = re.sub('\n\n', '\n', rmlstlb) try: @@ -136,47 +192,58 @@ class wiki: result = rm5lline[0] + '...行数过多已截断。' except Exception: result = rmlstlb - if self.interwiki != '': - pagename = self.interwiki + ':' + self.pagename - return f'您要的{self.pagename}:{result}' + msgs = {'status': 'done', 'url': fullurl, 'text': result} + matchimg = re.match(r'File:.*?\.(?:png|gif|jpg|jpeg|webp|bmp|ico)', self.pagename, re.I) + if matchimg: + getimg = await self.get_image(self.pagename) + if getimg: + msgs['net_image'] = getimg + if await self.danger_text_check(result): + return {'status': 'done', 'text': '发生错误:拒绝访问。'} + return msgs - - def interference(self): - if self.pagename.find('色图来') != -1:#ftynmsl - self.pagename = '你妈' - if self.pagename == '你妈': - self.rspt = '[wait] 提示:找不到[你妈],请问你是否想找一个[[新妈]]?' - if self.pagename == '新妈': - self.rspt = '你没有妈。' - - async def main(self, wikilink, pagename, interwiki='', igmessage=False, template=False): + async def main(self, wikilink, pagename, interwiki=None, igmessage=False, template=False, tryiw=0): print(wikilink) print(pagename) print(interwiki) + pagename = re.sub('_', ' ', pagename) + pagename = pagename.split('|')[0] self.orginwikilink = wikilink - self.wikilink = re.sub('index.php/', '', self.orginwikilink)#fxxk + self.wikilink = re.sub('index.php/', '', self.orginwikilink) # fxxk + danger_check = self.danger_wiki_check() + if danger_check: + if await self.danger_text_check(pagename): + return {'status': 'done', 'text': '发生错误:拒绝访问。'} self.orginpagename = pagename self.pagename = pagename - self.interwiki = interwiki + if interwiki == None: + self.interwiki = '' + else: + self.interwiki = interwiki self.igmessage = igmessage self.template = template + self.templateprompt = None try: matchinterwiki = re.match(r'(.*?):(.*)', self.pagename) if matchinterwiki: - if matchinterwiki.group(1) in iwlist(): - return await self.main(iwlink(matchinterwiki.group(1)), matchinterwiki.group(2), - matchinterwiki.group(1), - self.igmessage, self.template) + iwlist = await self.get_interwiki(self.wikilink) + print(iwlist) + if matchinterwiki.group(1) in iwlist: + if tryiw <= 5: + interwiki_link = iwlist[matchinterwiki.group(1)] + check = await check_wiki_available(interwiki_link) + if check: + return await self.main(check[0], matchinterwiki.group(2), + matchinterwiki.group(1), + self.igmessage, self.template, self.sentyouprompt, tryiw + 1) + else: + return {'status': 'done', + 'text': f'发生错误:指向的interwiki不是一个有效的MediaWiki。{interwiki_link}{matchinterwiki.group(2)}'} + else: + return {'status': 'warn', 'text': '警告:尝试重定向已超过5次,继续尝试将有可能导致你被机器人加入黑名单。'} return await self.step1() except Exception as e: traceback.print_exc() if igmessage == False: - return f'发生错误:{str(e)}' - - -if __name__ == '__main__': - import asyncio - - a = asyncio.run(wiki().main('https://minecraft-zh.gamepedia.com/', '海晶石','zh')) - print(a) + return f'发生错误:{str(e)}' + '\n' diff --git a/subbot.py b/subbot.py deleted file mode 100644 index d10d4bce..00000000 --- a/subbot.py +++ /dev/null @@ -1,97 +0,0 @@ -import asyncio -import traceback - -import aiohttp -from graia.application import MessageChain -from graia.application.message.elements.internal import Plain - -from modules.UTC8 import UTC8 -from modules.pbc import pbc1 - - -async def get_data(url: str, fmt: str): - async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=aiohttp.ClientTimeout(total=20)) as req: - if hasattr(req, fmt): - return await getattr(req, fmt)() - else: - raise ValueError(f"NoSuchMethod: {fmt}") - - -async def newbie(app): - print('subbot newbie launched') - url = 'https://minecraft-zh.gamepedia.com/api.php?action=query&list=logevents&letype=newusers&format=json' - while True: - try: - file = await get_data(url, 'json') - qq = [] - for x in file['query']['logevents'][:]: - qq.append(x['title']) - print('!' + x['title']) - while True: - c = 'f' - try: - qqqq = await get_data(url, 'json') - for xz in qqqq['query']['logevents'][:]: - if xz['title'] in qq: - pass - else: - s = await pbc1(UTC8(xz['timestamp'], 'onlytime') + '新增新人:' + xz['title']) - print(s) - if s[0].find("<吃掉了>") != -1 or s[0].find("<全部吃掉了>") != -1: - await app.sendGroupMessage(731397727, MessageChain.create([Plain(s[ - 0] + '\n检测到外来信息介入,请前往日志查看所有消息。Special:日志?type=newusers')]).asSendable()) - else: - await app.sendGroupMessage(731397727, - MessageChain.create([Plain(s[0])]).asSendable()) - c = 't' - except Exception: - pass - if c == 't': - break - else: - await asyncio.sleep(10) - await asyncio.sleep(5) - except Exception: - traceback.print_exc() - - -async def ver(app): - from modules.mcvrss import mcvrss - from modules.mcversion import mcversion - url = 'http://launchermeta.mojang.com/mc/game/version_manifest.json' - print('subbot ver launched') - while True: - try: - verlist = mcversion() - file = await get_data(url, 'json') - release = file['latest']['release'] - snapshot = file['latest']['snapshot'] - if release in verlist: - pass - else: - for qqgroup in mcvrss(): - try: - await app.sendGroupMessage(int(qqgroup), MessageChain.create( - [Plain('启动器已更新' + file['latest']['release'] + '正式版。')]).asSendable()) - except Exception: - traceback.print_exc() - addversion = open('./assets/mcversion.txt', 'a') - addversion.write('\n' + release) - addversion.close() - if snapshot in verlist: - pass - else: - for qqgroup in mcvrss(): - try: - await app.sendGroupMessage(int(qqgroup), MessageChain.create( - [Plain('启动器已更新' + file['latest']['snapshot'] + '快照。')]).asSendable()) - except Exception: - traceback.print_exc() - addversion = open('./assets/mcversion.txt', 'a') - addversion.write('\n' + snapshot) - addversion.close() - await asyncio.sleep(10) - except Exception: - traceback.print_exc() - await asyncio.sleep(5) \ No newline at end of file diff --git a/test.py b/test.py index 0db901b5..7401623f 100644 --- a/test.py +++ b/test.py @@ -1,6 +1,3 @@ -from wikim import wikim -import asyncio -loop = asyncio.get_event_loop() -result = loop.run_until_complete(wikim('wiki Netherite')) -print(result) -loop.close() \ No newline at end of file +from database import check_enable_modules_all + +print(check_enable_modules_all('group_permission', 'wiki'))