mirror of
https://github.com/KimigaiiWuyi/GenshinUID.git
synced 2025-07-04 05:53:29 +00:00
Compare commits
140 Commits
Author | SHA1 | Date | |
---|---|---|---|
42e8693463 | |||
92e032077c | |||
00b1ebd71e | |||
de71e83be8 | |||
a398fcc0f3 | |||
11840e0f75 | |||
77a597cfca | |||
b128fd38b8 | |||
447b24dde9 | |||
72c36be0a9 | |||
2c07c490bb | |||
914ff0e83b | |||
a9eacfbe0c | |||
91f0ee82b9 | |||
8727fb0bc1 | |||
6cb7bd7ab8 | |||
efa924c1a8 | |||
01b9d48b38 | |||
b84764d907 | |||
236fbebd3b | |||
a9600d85b7 | |||
b087dd7f24 | |||
083f55d852 | |||
5aec15e9f4 | |||
d952e1bf78 | |||
2e4120bf89 | |||
a325bfe4f2 | |||
f9e84e5fdf | |||
c8588a2848 | |||
79d1e86200 | |||
40217dba09 | |||
2cb0ccd452 | |||
52b1c06125 | |||
1f54160e2b | |||
15fc075878 | |||
2a03b056da | |||
6bf9cef4f4 | |||
c3562ae49e | |||
de312d2314 | |||
db96d23876 | |||
ecb286b33f | |||
a93787bfea | |||
f93eb116f1 | |||
3265e2cf0d | |||
2c4c3589fc | |||
77ea5118a2 | |||
a7e0477f72 | |||
fe59404ee9 | |||
402184496f | |||
6a3504026b | |||
59184adea7 | |||
83fd57ec54 | |||
e6979b75be | |||
7878f0e278 | |||
e318984801 | |||
d62ab6e341 | |||
d5a379d0ef | |||
02375b1284 | |||
2aaf5aa1c6 | |||
54701a448b | |||
d74959b751 | |||
d087e75e4e | |||
79a4faf5c4 | |||
38f08262d4 | |||
13c5fe2eb0 | |||
92844b1897 | |||
2984f4e578 | |||
8407d556ee | |||
d68cbc24fa | |||
8032841408 | |||
9eaf184f19 | |||
a215bc16cb | |||
ed412e890c | |||
99ea01d9e4 | |||
ad385bd77c | |||
18fd5e2cd0 | |||
cd2303d37d | |||
6ba82d4d1b | |||
96227fe4be | |||
fa35be809f | |||
9f7db4e5b2 | |||
5c6008381b | |||
461911e186 | |||
ef1d7eb997 | |||
8f2d3ae8e5 | |||
21c40bcfe5 | |||
fbb1cec548 | |||
0371014fd6 | |||
d367197838 | |||
4cfd3537f0 | |||
a221356da4 | |||
5bc15948fe | |||
a8040c7321 | |||
5cb62671fc | |||
9b959b0f2c | |||
bb2b19ec22 | |||
c5e1d9e88a | |||
82842b25fc | |||
56700bf420 | |||
c3e8aaa6fc | |||
8c53148488 | |||
96b40242e8 | |||
7df0a67f8d | |||
bf17cc3caf | |||
a1002d91ec | |||
9ae5605af0 | |||
f79dbd03b4 | |||
8c08e1c2d6 | |||
6e76e909d3 | |||
a39e3c7365 | |||
46444af78c | |||
166d530f35 | |||
571b9bd97a | |||
18e5c968ad | |||
142995766e | |||
9db963ea18 | |||
996a4e8c29 | |||
4a7f822b94 | |||
f04e8ccc48 | |||
98907c5671 | |||
f6e4f8c129 | |||
f20c0b7e1f | |||
9f9106d788 | |||
cdab68347c | |||
87885db01e | |||
90ce5b77fe | |||
dc4ba1811f | |||
32f391e629 | |||
46a176283d | |||
7b15e44f9d | |||
1204b5a5e7 | |||
b0b09cdc70 | |||
eb17cebc28 | |||
d9eeca0ba8 | |||
7c30452e15 | |||
9c7a51e749 | |||
bc9af2b8d6 | |||
2a92081968 | |||
1f4322b769 | |||
bbb301d72a |
16
.dockerignore
Normal file
16
.dockerignore
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# .git
|
||||||
|
.vscode
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env
|
||||||
|
venv
|
||||||
|
.pytest_cache
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
tests
|
||||||
|
GenshinUID.egg-info
|
||||||
|
build
|
||||||
|
__pycache__
|
||||||
|
.pytest_cache
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -210,7 +210,7 @@ celerybeat.pid
|
|||||||
*.sage.py
|
*.sage.py
|
||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
.env/
|
||||||
.venv
|
.venv
|
||||||
env/
|
env/
|
||||||
venv/
|
venv/
|
||||||
@ -668,5 +668,6 @@ result.txt
|
|||||||
### GenshinUID ###
|
### GenshinUID ###
|
||||||
GenshinUID/genshinuid_help/help.png
|
GenshinUID/genshinuid_help/help.png
|
||||||
GenshinUID/genshinuid_map/map_data
|
GenshinUID/genshinuid_map/map_data
|
||||||
.vscode/settings.json
|
|
||||||
.vscode/settings.json
|
### Debug ###
|
||||||
|
testnb2/
|
||||||
|
@ -5,11 +5,6 @@ ci:
|
|||||||
autoupdate_schedule: monthly
|
autoupdate_schedule: monthly
|
||||||
autoupdate_commit_msg: ":arrow_up: auto update by pre-commit-ci"
|
autoupdate_commit_msg: ":arrow_up: auto update by pre-commit-ci"
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/hadialqattan/pycln
|
|
||||||
rev: v2.1.2
|
|
||||||
hooks:
|
|
||||||
- id: pycln
|
|
||||||
|
|
||||||
- repo: https://github.com/pycqa/isort
|
- repo: https://github.com/pycqa/isort
|
||||||
rev: 5.11.5
|
rev: 5.11.5
|
||||||
hooks:
|
hooks:
|
||||||
@ -25,17 +20,16 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
|
|
||||||
|
- repo: https://github.com/hadialqattan/pycln
|
||||||
|
rev: v2.1.2
|
||||||
|
hooks:
|
||||||
|
- id: pycln
|
||||||
|
|
||||||
- repo: https://github.com/python-poetry/poetry
|
- repo: https://github.com/python-poetry/poetry
|
||||||
rev: 1.3.1
|
rev: 1.3.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: poetry-check
|
- id: poetry-check
|
||||||
|
- id: poetry-lock
|
||||||
- id: poetry-export
|
- id: poetry-export
|
||||||
args:
|
args: ["-f", "requirements.txt", "--without-hashes", "-o", "requirements.txt"]
|
||||||
[
|
|
||||||
"-f",
|
|
||||||
"requirements.txt",
|
|
||||||
"--without-hashes",
|
|
||||||
"-o",
|
|
||||||
"requirements.txt",
|
|
||||||
]
|
|
||||||
verbose: true
|
verbose: true
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"python.languageServer": "Pylance",
|
"python.languageServer": "Pylance",
|
||||||
"python.analysis.typeCheckingMode": "off",
|
"python.analysis.typeCheckingMode": "basic",
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"audioid",
|
"audioid",
|
||||||
"enka",
|
"enka",
|
||||||
|
43
Dockerfile
Normal file
43
Dockerfile
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
FROM python:3.9
|
||||||
|
|
||||||
|
# 1. 环境设置
|
||||||
|
|
||||||
|
# 使用镜像源
|
||||||
|
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y tzdata
|
||||||
|
|
||||||
|
ENV TZ Asia/Shanghai
|
||||||
|
|
||||||
|
# 2. 安装 GenshinUID
|
||||||
|
WORKDIR /plugin
|
||||||
|
|
||||||
|
COPY ./pyproject.toml ./LICENSE ./README.md /plugin/
|
||||||
|
|
||||||
|
COPY ./GenshinUID /plugin/GenshinUID/
|
||||||
|
|
||||||
|
RUN pip install --editable "."
|
||||||
|
|
||||||
|
COPY ./.git /plugin/.git
|
||||||
|
|
||||||
|
# 3. 生成 nb2 项目
|
||||||
|
WORKDIR /nb2
|
||||||
|
|
||||||
|
RUN pip install tomlkit "cookiecutter>=2.1.1"
|
||||||
|
|
||||||
|
COPY ./deploy/cookiecutter.yml ./deploy/update_pyproject.py /nb2/
|
||||||
|
|
||||||
|
# RUN cookiecutter --config-file ./cookiecutter.yml https://github.com/nonebot/nb-cli.git --directory="nb_cli/project" --no-input
|
||||||
|
# 使用镜像源
|
||||||
|
RUN cookiecutter --config-file ./cookiecutter.yml https://ghproxy.com/https://github.com/nonebot/nb-cli.git --directory="nb_cli/project" --no-input
|
||||||
|
|
||||||
|
RUN python update_pyproject.py
|
||||||
|
|
||||||
|
COPY ./deploy/.env.dev /nb2/nb2/
|
||||||
|
|
||||||
|
WORKDIR /nb2/nb2
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
|
||||||
|
CMD python bot.py
|
@ -0,0 +1,39 @@
|
|||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot import require, load_all_plugins, get_plugin_by_module_name
|
||||||
|
|
||||||
|
require('nonebot_plugin_apscheduler')
|
||||||
|
|
||||||
|
if get_plugin_by_module_name("GenshinUID"):
|
||||||
|
logger.info("推荐直接加载 GenshinUID 仓库文件夹")
|
||||||
|
load_all_plugins(
|
||||||
|
[
|
||||||
|
'GenshinUID.genshinuid_abyss',
|
||||||
|
'GenshinUID.genshinuid_adv',
|
||||||
|
'GenshinUID.genshinuid_ann',
|
||||||
|
'GenshinUID.genshinuid_gcg',
|
||||||
|
'GenshinUID.genshinuid_xkdata',
|
||||||
|
'GenshinUID.genshinuid_check',
|
||||||
|
'GenshinUID.genshinuid_collection',
|
||||||
|
'GenshinUID.genshinuid_config',
|
||||||
|
'GenshinUID.genshinuid_enka',
|
||||||
|
'GenshinUID.genshinuid_etcimg',
|
||||||
|
'GenshinUID.genshinuid_eventlist',
|
||||||
|
'GenshinUID.genshinuid_gachalog',
|
||||||
|
'GenshinUID.genshinuid_guide',
|
||||||
|
'GenshinUID.genshinuid_help',
|
||||||
|
'GenshinUID.genshinuid_map',
|
||||||
|
'GenshinUID.genshinuid_meta',
|
||||||
|
'GenshinUID.genshinuid_mhybbscoin',
|
||||||
|
'GenshinUID.genshinuid_mys',
|
||||||
|
'GenshinUID.genshinuid_note',
|
||||||
|
'GenshinUID.genshinuid_resin',
|
||||||
|
'GenshinUID.genshinuid_resource',
|
||||||
|
'GenshinUID.genshinuid_roleinfo',
|
||||||
|
'GenshinUID.genshinuid_signin',
|
||||||
|
'GenshinUID.genshinuid_user',
|
||||||
|
'GenshinUID.genshinuid_wikitext',
|
||||||
|
'GenshinUID.genshinuid_webconsole',
|
||||||
|
'GenshinUID.genshinuid_update',
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import hoshino
|
|
||||||
from hoshino import Service
|
|
||||||
|
|
||||||
sv = Service('genshinuid', bundle='genshin', help_='发送"原神帮助"查看详情')
|
|
||||||
hoshino_bot = hoshino.get_bot()
|
|
||||||
logger = sv.logger
|
|
5
GenshinUID/config.py
Normal file
5
GenshinUID/config.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from nonebot import get_driver
|
||||||
|
|
||||||
|
config = get_driver().config
|
||||||
|
SUPERUSERS = {x for x in config.superusers}
|
||||||
|
priority = 2
|
@ -1,59 +1,85 @@
|
|||||||
import re
|
from typing import Any, Tuple
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_regex
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import RegexGroup
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..genshinuid_meta import register_menu
|
||||||
from .draw_abyss_card import draw_abyss_img
|
from .draw_abyss_card import draw_abyss_img
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.mhy_api.convert_mysid_to_uid import convert_mysid
|
from ..utils.mhy_api.convert_mysid_to_uid import convert_mysid
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.draw_image_tools.send_image_tool import convert_img
|
||||||
|
|
||||||
|
get_abyss_info = on_regex(
|
||||||
@sv.on_rex(
|
|
||||||
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
||||||
r'(uid|查询|mys)?([0-9]+)?(上期)?(深渊|sy)'
|
r'(uid|查询|mys)?([0-9]+)?(上期)?(深渊|sy)'
|
||||||
r'(9|10|11|12|九|十|十一|十二)?(层)?'
|
r'(9|10|11|12|九|十|十一|十二)?(层)?'
|
||||||
r'(\[CQ:at,qq=[0-9]+\])?( )?$',
|
r'(\[CQ:at,qq=[0-9]+\])?( )?$',
|
||||||
|
block=True,
|
||||||
)
|
)
|
||||||
async def send_abyss_info(bot: HoshinoBot, ev: CQEvent):
|
# 恢复了查询二字,和其他的查询打架下次解决
|
||||||
args = ev['match'].groups()
|
|
||||||
|
|
||||||
|
@get_abyss_info.handle()
|
||||||
|
@handle_exception('查询深渊信息')
|
||||||
|
@register_menu(
|
||||||
|
'查询深渊信息',
|
||||||
|
'查询(@某人)(上期)深渊(xx层)',
|
||||||
|
'查询你的或者指定人的深渊战绩',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'可以用来查看你的或者指定人的深渊战绩,可以指定层数,默认为最高层数\n'
|
||||||
|
'可以在命令文本后带一张图以自定义背景图\n'
|
||||||
|
' \n' # 如果想要空行,请在换行符前面打个空格,不然会忽略换行符
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>{查询</ft>'
|
||||||
|
'<ft color=(125,125,125)>(@某人)</ft>'
|
||||||
|
'<ft color=(238,120,0)>|uid</ft><ft color=(0,148,200)>xx</ft>'
|
||||||
|
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>xx</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
'<ft color=(125,125,125)>(上期)</ft>'
|
||||||
|
'<ft color=(238,120,0)>深渊</ft>'
|
||||||
|
'<ft color=(125,125,125)>(xx层)</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>查询深渊</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>uid123456789上期深渊</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi</ft> '
|
||||||
|
'<ft color=(238,120,0)>上期深渊12层</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_abyss_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Tuple[Any, ...] = RegexGroup(),
|
||||||
|
):
|
||||||
logger.info('开始执行[查询深渊信息]')
|
logger.info('开始执行[查询深渊信息]')
|
||||||
logger.info('[查询深渊信息]参数: {}'.format(args))
|
logger.info(f'[查询深渊信息]参数: {args}')
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
|
|
||||||
if at:
|
if args[2] == 'mys':
|
||||||
qid = int(at.group(1))
|
|
||||||
else:
|
|
||||||
if ev.sender:
|
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
# 判断uid
|
|
||||||
if args[2] != 'mys':
|
|
||||||
if args[3] is None:
|
|
||||||
uid = await select_db(qid, mode='uid')
|
|
||||||
uid = str(uid)
|
|
||||||
elif len(args[3]) != 9:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
uid = args[3]
|
|
||||||
else:
|
|
||||||
uid = await convert_mysid(args[3])
|
uid = await convert_mysid(args[3])
|
||||||
|
elif args[3] is None:
|
||||||
logger.info('[查询深渊信息]uid: {}'.format(uid))
|
uid = await select_db(qid, mode='uid')
|
||||||
|
uid = str(uid)
|
||||||
if '未找到绑定的UID' in uid:
|
elif len(args[3]) != 9:
|
||||||
await bot.send(ev, UID_HINT)
|
return
|
||||||
|
|
||||||
# 判断深渊期数
|
|
||||||
if args[4] is None:
|
|
||||||
schedule_type = '1'
|
|
||||||
else:
|
else:
|
||||||
schedule_type = '2'
|
uid = args[3]
|
||||||
logger.info('[查询深渊信息]深渊期数: {}'.format(schedule_type))
|
logger.info(f'[查询深渊信息]uid: {uid}')
|
||||||
|
if '未找到绑定的UID' in uid:
|
||||||
|
await matcher.finish(UID_HINT)
|
||||||
|
schedule_type = '1' if args[4] is None else '2'
|
||||||
|
logger.info(f'[查询深渊信息]深渊期数: {schedule_type}')
|
||||||
if args[6] in ['九', '十', '十一', '十二']:
|
if args[6] in ['九', '十', '十一', '十二']:
|
||||||
floor = (
|
floor = (
|
||||||
args[6]
|
args[6]
|
||||||
@ -62,17 +88,17 @@ async def send_abyss_info(bot: HoshinoBot, ev: CQEvent):
|
|||||||
.replace('十二', '12')
|
.replace('十二', '12')
|
||||||
.replace('十', '10')
|
.replace('十', '10')
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
floor = args[6]
|
floor = args[6]
|
||||||
if floor is not None:
|
if floor is not None:
|
||||||
floor = int(floor)
|
floor = int(floor)
|
||||||
logger.info('[查询深渊信息]深渊层数: {}'.format(floor))
|
logger.info(f'[查询深渊信息]深渊层数: {floor}')
|
||||||
|
|
||||||
im = await draw_abyss_img(uid, floor, schedule_type)
|
im = await draw_abyss_img(uid, floor, schedule_type)
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
im = await convert_img(im)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -1,36 +1,34 @@
|
|||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot.adapters.ntchat import Message
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..config import priority
|
||||||
from .get_achi_desc import get_achi, get_daily_achi
|
from .get_achi_desc import get_achi, get_daily_achi
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_task_info = on_command('查委托', aliases={'委托'}, priority=priority)
|
||||||
|
get_achi_info = on_command('查成就', aliases={'成就'}, priority=priority)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('查委托')
|
@get_task_info.handle()
|
||||||
async def send_task_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('查委托')
|
||||||
if ev.message:
|
async def send_task_info(matcher: Matcher, args: Message = CommandArg()):
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
if not args:
|
||||||
else:
|
|
||||||
return
|
return
|
||||||
|
name = str(args[0])
|
||||||
if message == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
name = str(message)
|
|
||||||
logger.info(f'[查委托] 参数:{name}')
|
logger.info(f'[查委托] 参数:{name}')
|
||||||
im = await get_daily_achi(name)
|
im = await get_daily_achi(name)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('查成就')
|
@get_achi_info.handle()
|
||||||
async def send_achi_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('查成就')
|
||||||
if ev.message:
|
async def send_achi_info(matcher: Matcher, args: Message = CommandArg()):
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
if not args:
|
||||||
else:
|
|
||||||
return
|
return
|
||||||
|
name = str(args[0])
|
||||||
if message == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
name = str(message)
|
|
||||||
logger.info(f'[查成就] 参数:{name}')
|
logger.info(f'[查成就] 参数:{name}')
|
||||||
im = await get_achi(name)
|
im = await get_achi(name)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
@ -1,19 +1,72 @@
|
|||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from typing import Any, Tuple
|
||||||
|
|
||||||
from ..base import sv
|
from nonebot import on_regex
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import RegexGroup
|
||||||
|
|
||||||
|
from ..config import priority
|
||||||
from .get_adv import char_adv, weapon_adv
|
from .get_adv import char_adv, weapon_adv
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
from ..utils.alias.alias_to_char_name import alias_to_char_name
|
from ..utils.alias.alias_to_char_name import alias_to_char_name
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_char_adv = on_regex('([\u4e00-\u9fa5]+)(用什么|能用啥|怎么养)', priority=priority)
|
||||||
|
get_weapon_adv = on_regex(
|
||||||
|
'([\u4e00-\u9fa5]+)(能给谁|给谁用|要给谁|谁能用)', priority=priority
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'([\u4e00-\u9fa5]+)(用什么|能用啥|怎么养)')
|
@get_char_adv.handle()
|
||||||
async def send_char_adv(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('建议')
|
||||||
name = await alias_to_char_name(str(ev['match'].group(1)))
|
@register_menu(
|
||||||
|
'角色配置推荐',
|
||||||
|
'xx用什么',
|
||||||
|
'查询角色武器/圣遗物推荐配置',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'可以查询某角色的武器/圣遗物推荐配置\n'
|
||||||
|
'支持部分角色别名\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(0,148,200)>[角色名]</ft>'
|
||||||
|
'<ft color=(238,120,0)>{用什么|能用啥|怎么养}</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>钟离用什么</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>公子怎么养</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_char_adv(
|
||||||
|
matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
|
||||||
|
):
|
||||||
|
name = await alias_to_char_name(str(args[0]))
|
||||||
im = await char_adv(name)
|
im = await char_adv(name)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'([\u4e00-\u9fa5]+)(能给谁|给谁用|要给谁|谁能用)')
|
@get_weapon_adv.handle()
|
||||||
async def send_weapon_adv(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('建议')
|
||||||
name = await alias_to_char_name(str(ev['match'].group(1)))
|
@register_menu(
|
||||||
|
'装备适用角色',
|
||||||
|
'xx能给谁',
|
||||||
|
'查询某武器/圣遗物能给谁用',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'可以通过武器/圣遗物名反查适用的角色\n'
|
||||||
|
'支持部分别名\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(0,148,200)>[武器名]</ft>'
|
||||||
|
'<ft color=(238,120,0)>{能给谁|给谁用|要给谁|谁能用}</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>四风原典能给谁</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>千岩给谁用</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_weapon_adv(
|
||||||
|
matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
|
||||||
|
):
|
||||||
|
name = await alias_to_char_name(str(args[0]))
|
||||||
im = await weapon_adv(name)
|
im = await weapon_adv(name)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
@ -1,90 +1,97 @@
|
|||||||
|
import base64
|
||||||
import random
|
import random
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from nonebot import get_bot
|
from nonebot.log import logger
|
||||||
from hoshino import Service, priv
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot import get_bot, on_command
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
from nonebot.adapters.ntchat import (
|
||||||
|
MessageEvent,
|
||||||
|
MessageSegment,
|
||||||
|
TextMessageEvent,
|
||||||
|
)
|
||||||
|
|
||||||
from ..base import logger
|
|
||||||
from .util import black_ids
|
from .util import black_ids
|
||||||
|
from ..config import priority
|
||||||
from .main import ann, consume_remind
|
from .main import ann, consume_remind
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..genshinuid_config.default_config import string_config
|
from ..genshinuid_config.default_config import string_config
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from .ann_card import sub_ann, unsub_ann, ann_list_card, ann_detail_card
|
from .ann_card import sub_ann, unsub_ann, ann_list_card, ann_detail_card
|
||||||
|
|
||||||
sv_help = '''
|
update_ann_scheduler = scheduler
|
||||||
原神公告
|
get_ann_info = on_command('原神公告', priority=priority)
|
||||||
原神公告#ID
|
reg_ann = on_command(
|
||||||
'''.strip()
|
'订阅原神公告', priority=priority, rule=FullCommand(), permission=SUPERUSER
|
||||||
|
|
||||||
sv = Service(
|
|
||||||
name='原神公告', # 功能名
|
|
||||||
use_priv=priv.NORMAL, # 使用权限
|
|
||||||
manage_priv=priv.ADMIN, # 管理权限
|
|
||||||
visible=True, # 可见性
|
|
||||||
enable_on_default=True, # 默认启用
|
|
||||||
# bundle = '娱乐', #分组归类
|
|
||||||
help_=sv_help, # 帮助说明
|
|
||||||
)
|
)
|
||||||
|
unreg_ann = on_command(
|
||||||
prefix = '原神'
|
'取消订阅原神公告',
|
||||||
|
aliases={'取消原神公告', '退订原神公告'},
|
||||||
|
priority=priority,
|
||||||
|
rule=FullCommand(),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
)
|
||||||
|
consume_ann = on_command('清除原神公告红点', priority=priority, rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix((f'{prefix}公告#', f'{prefix}公告'))
|
@get_ann_info.handle()
|
||||||
async def ann_(bot, ev):
|
@handle_exception('原神公告', '获取/发送原神公告失败')
|
||||||
ann_id = ev.message.extract_plain_text().strip()
|
async def send_ann_pic(
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
ann_id = str(args).replace(' ', '').replace('#', '')
|
||||||
|
|
||||||
if not ann_id:
|
if not ann_id:
|
||||||
img = await ann_list_card()
|
img = await ann_list_card()
|
||||||
img = await convert_img(img)
|
await matcher.finish(MessageSegment.image(img))
|
||||||
await bot.send(ev, img, at_sender=True)
|
|
||||||
return
|
|
||||||
|
|
||||||
if not ann_id.isdigit():
|
if not ann_id.isdigit():
|
||||||
raise Exception("公告ID不正确")
|
raise Exception("公告ID不正确")
|
||||||
try:
|
|
||||||
img = await ann_detail_card(int(ann_id))
|
img = await ann_detail_card(int(ann_id))
|
||||||
img = await convert_img(img)
|
await matcher.finish(MessageSegment.image(img))
|
||||||
await bot.send(ev, img, at_sender=True)
|
|
||||||
except Exception as e:
|
|
||||||
await bot.finish(ev, str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(f'订阅{prefix}公告')
|
@reg_ann.handle()
|
||||||
async def sub_ann_(bot, ev):
|
@handle_exception('设置原神公告', '设置原神公告失败')
|
||||||
if not priv.check_priv(ev, priv.ADMIN):
|
async def send_reg_ann(
|
||||||
raise Exception("你没有权限开启原神公告推送")
|
event: TextMessageEvent,
|
||||||
try:
|
matcher: Matcher,
|
||||||
await bot.send(ev, sub_ann(ev.group_id))
|
):
|
||||||
except Exception as e:
|
await matcher.finish(sub_ann(event.room_wxid))
|
||||||
await bot.finish(ev, str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch((f'取消订阅{prefix}公告', f'取消{prefix}公告', f'退订{prefix}公告'))
|
@unreg_ann.handle()
|
||||||
async def unsub_ann_(bot, ev):
|
@handle_exception('取消原神公告', '取消设置原神公告失败')
|
||||||
if not priv.check_priv(ev, priv.ADMIN):
|
async def send_unreg_ann(
|
||||||
raise Exception("你没有权限取消原神公告推送")
|
event: TextMessageEvent,
|
||||||
try:
|
matcher: Matcher,
|
||||||
await bot.send(ev, unsub_ann(ev.group_id))
|
):
|
||||||
except Exception as e:
|
await matcher.finish(unsub_ann(event.room_wxid))
|
||||||
await bot.finish(ev, str(e))
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(f'取消{prefix}公告红点')
|
@consume_ann.handle()
|
||||||
async def consume_remind_(bot, ev):
|
@handle_exception('取消原神公告红点', '取消红点失败')
|
||||||
try:
|
async def send_consume_ann(
|
||||||
qid = int(ev.sender['user_id'])
|
event: MessageEvent,
|
||||||
uid = await select_db(qid, mode='uid')
|
matcher: Matcher,
|
||||||
uid = str(uid)
|
):
|
||||||
if '未找到绑定的UID' in uid:
|
qid = event.from_wxid
|
||||||
await bot.send(ev, UID_HINT)
|
uid = await select_db(qid, mode='uid')
|
||||||
return
|
uid = str(uid)
|
||||||
await bot.send(ev, await consume_remind(uid), at_sender=True)
|
if '未找到绑定的UID' in uid:
|
||||||
except Exception as e:
|
await matcher.finish(UID_HINT)
|
||||||
await bot.finish(ev, str(e))
|
await matcher.finish(await consume_remind(uid))
|
||||||
|
|
||||||
|
|
||||||
@sv.scheduled_job('cron', minute=10)
|
@update_ann_scheduler.scheduled_job('cron', minute=10)
|
||||||
async def check_ann():
|
async def check_ann():
|
||||||
await check_ann_state()
|
await check_ann_state()
|
||||||
|
|
||||||
@ -93,11 +100,9 @@ async def check_ann_state():
|
|||||||
logger.info('[原神公告] 定时任务: 原神公告查询..')
|
logger.info('[原神公告] 定时任务: 原神公告查询..')
|
||||||
ids = string_config.get_config('Ann_Ids')
|
ids = string_config.get_config('Ann_Ids')
|
||||||
sub_list = string_config.get_config('Ann_Groups')
|
sub_list = string_config.get_config('Ann_Groups')
|
||||||
|
|
||||||
if not sub_list:
|
if not sub_list:
|
||||||
logger.info('没有群订阅, 取消获取数据')
|
logger.info('没有群订阅, 取消获取数据')
|
||||||
return
|
return
|
||||||
|
|
||||||
if not ids:
|
if not ids:
|
||||||
ids = await ann().get_ann_ids()
|
ids = await ann().get_ann_ids()
|
||||||
if not ids:
|
if not ids:
|
||||||
@ -105,10 +110,9 @@ async def check_ann_state():
|
|||||||
string_config.set_config('Ann_Ids', ids)
|
string_config.set_config('Ann_Ids', ids)
|
||||||
logger.info('初始成功, 将在下个轮询中更新.')
|
logger.info('初始成功, 将在下个轮询中更新.')
|
||||||
return
|
return
|
||||||
|
|
||||||
new_ids = await ann().get_ann_ids()
|
new_ids = await ann().get_ann_ids()
|
||||||
new_ann = set(ids) ^ set(new_ids)
|
|
||||||
|
|
||||||
|
new_ann = set(ids) ^ set(new_ids)
|
||||||
if not new_ann:
|
if not new_ann:
|
||||||
logger.info('[原神公告] 没有最新公告')
|
logger.info('[原神公告] 没有最新公告')
|
||||||
return
|
return
|
||||||
@ -117,17 +121,22 @@ async def check_ann_state():
|
|||||||
if ann_id in black_ids:
|
if ann_id in black_ids:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
img = await ann_detail_card(ann_id)
|
img = await ann_detail_card(ann_id) # 防止抛出异常报错
|
||||||
img = await convert_img(img)
|
|
||||||
bot = get_bot()
|
bot = get_bot()
|
||||||
|
b64img = base64.b64encode(img)
|
||||||
|
|
||||||
for group in sub_list:
|
for group in sub_list:
|
||||||
try:
|
try:
|
||||||
await bot.send_group_msg(group_id=group, message=img)
|
await bot.call_api(
|
||||||
|
api='send_image',
|
||||||
|
to_wxid=str(group),
|
||||||
|
file_path="base64://" + b64img.decode(),
|
||||||
|
)
|
||||||
await asyncio.sleep(random.uniform(1, 3))
|
await asyncio.sleep(random.uniform(1, 3))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(str(e))
|
logger.exception(e)
|
||||||
|
|
||||||
logger.info('[原神公告] 推送完毕, 更新数据库')
|
logger.info('[原神公告] 推送完毕, 更新数据库')
|
||||||
string_config.set_config('Ann_Ids', new_ids)
|
string_config.set_config('Ann_Ids', new_ids)
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
import random
|
import random
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat import Bot, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..config import priority
|
||||||
from .backup_data import data_backup
|
from .backup_data import data_backup
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.db_operation.db_cache_and_check import check_db, check_stoken_db
|
from ..utils.db_operation.db_cache_and_check import check_db, check_stoken_db
|
||||||
from ..utils.db_operation.db_operation import delete_cookies, get_all_push_list
|
from ..utils.db_operation.db_operation import delete_cookies, get_all_push_list
|
||||||
from ..utils.message.get_cqhttp_data import (
|
from ..utils.message.get_cqhttp_data import (
|
||||||
@ -12,35 +20,75 @@ from ..utils.message.get_cqhttp_data import (
|
|||||||
get_group_member_list,
|
get_group_member_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
backup = on_command(
|
||||||
|
'gs清除缓存', rule=FullCommand(), priority=priority, permission=SUPERUSER
|
||||||
|
)
|
||||||
|
check = on_command(
|
||||||
|
'校验全部Cookies', rule=FullCommand(), priority=priority, permission=SUPERUSER
|
||||||
|
)
|
||||||
|
check_stoken = on_command(
|
||||||
|
'校验全部Stoken', rule=FullCommand(), priority=priority, permission=SUPERUSER
|
||||||
|
)
|
||||||
|
remove_invalid_user = on_command(
|
||||||
|
'清除无效用户', rule=FullCommand(), priority=priority, permission=SUPERUSER
|
||||||
|
)
|
||||||
|
|
||||||
@sv.scheduled_job('cron', hour=0)
|
backup_scheduler = scheduler
|
||||||
|
|
||||||
|
|
||||||
|
@backup_scheduler.scheduled_job('cron', hour=0)
|
||||||
async def daily_refresh_charData():
|
async def daily_refresh_charData():
|
||||||
await data_backup()
|
await data_backup()
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('gs清除缓存')
|
@backup.handle()
|
||||||
|
@handle_exception('清除缓存', '清除缓存错误')
|
||||||
|
@register_menu(
|
||||||
|
'清除缓存',
|
||||||
|
'清除缓存',
|
||||||
|
'清除插件产生的缓存数据',
|
||||||
|
trigger_method='超级用户指令',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'备份一份插件数据库后清除插件产生的文件与数据库缓存\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>清除缓存</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
async def send_backup_msg(
|
async def send_backup_msg(
|
||||||
bot: HoshinoBot,
|
bot: Bot,
|
||||||
ev: CQEvent,
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
):
|
):
|
||||||
if ev.sender:
|
if not await SUPERUSER(bot, event):
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
return
|
||||||
if qid not in bot.config.SUPERUSERS:
|
|
||||||
return
|
|
||||||
|
|
||||||
await data_backup()
|
await data_backup()
|
||||||
await bot.send(ev, '操作成功完成!')
|
await matcher.finish('操作成功完成!')
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('清除无效用户')
|
@remove_invalid_user.handle()
|
||||||
async def send_remove_invalid_user_msg(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('清除无效用户', '清除无效用户错误')
|
||||||
if ev.sender:
|
@register_menu(
|
||||||
qid = int(ev.sender['user_id'])
|
'清除无效用户',
|
||||||
else:
|
'清除无效用户',
|
||||||
return
|
'清除非好友或非推送群成员的数据',
|
||||||
if qid not in bot.config.SUPERUSERS:
|
trigger_method='超级用户指令',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'从数据库中删除掉 开启了私聊推送但不是Bot好友的用户 '
|
||||||
|
'以及 开启了群聊推送但不在推送目标群的用户 的数据\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>清除无效用户</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_remove_invalid_user_msg(
|
||||||
|
bot: Bot,
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
im_list = []
|
im_list = []
|
||||||
invalid_user = {}
|
invalid_user = {}
|
||||||
@ -62,40 +110,78 @@ async def send_remove_invalid_user_msg(bot: HoshinoBot, ev: CQEvent):
|
|||||||
for uid in invalid_uid_list:
|
for uid in invalid_uid_list:
|
||||||
im_list.append(await delete_cookies(str(uid)))
|
im_list.append(await delete_cookies(str(uid)))
|
||||||
logger.warning(f'无效UID已被删除: {uid}')
|
logger.warning(f'无效UID已被删除: {uid}')
|
||||||
await bot.send(ev, f'已清理失效用户{len(im_list)}个!')
|
await matcher.finish(f'已清理失效用户{len(im_list)}个!')
|
||||||
|
|
||||||
|
|
||||||
# 群聊内 校验Cookies 是否正常的功能,不正常自动删掉
|
# 群聊内 校验Cookies 是否正常的功能,不正常自动删掉
|
||||||
@sv.on_fullmatch('校验全部Cookies')
|
@check.handle()
|
||||||
async def send_check_cookies(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('Cookie校验', 'Cookie校验错误')
|
||||||
|
@register_menu(
|
||||||
|
'校验全部Cookies',
|
||||||
|
'校验全部Cookies',
|
||||||
|
'校验数据库内所有Cookies是否正常',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'校验数据库内所有Cookies是否正常,不正常的会自动删除\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>校验全部Cookies</ft>\n'
|
||||||
|
'注意<ft color=(238,120,0)>Cookies</ft>的'
|
||||||
|
'<ft color=(238,120,0)>C</ft>为大写'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_check_cookie(bot: Bot, matcher: Matcher):
|
||||||
raw_mes = await check_db()
|
raw_mes = await check_db()
|
||||||
im = raw_mes[0]
|
im = raw_mes[0]
|
||||||
await bot.send(ev, im)
|
await matcher.send(im)
|
||||||
for i in raw_mes[1]:
|
for i in raw_mes[1]:
|
||||||
await bot.send_private_msg(
|
await bot.call_api(
|
||||||
user_id=i[0],
|
api='send_private_msg',
|
||||||
message=(
|
**{
|
||||||
'您绑定的Cookies(uid{})已失效,以下功能将会受到影响:\n'
|
'user_id': i[0],
|
||||||
'查看完整信息列表\n查看深渊配队\n自动签到/当前状态/每月统计\n'
|
'message': (
|
||||||
'请及时重新绑定Cookies并重新开关相应功能。'
|
'您绑定的Cookies(uid{})已失效,以下功能将会受到影响:\n'
|
||||||
).format(i[1]),
|
'查看完整信息列表\n查看深渊配队\n自动签到/当前状态/每月统计\n'
|
||||||
|
'请及时重新绑定Cookies并重新开关相应功能。'
|
||||||
|
).format(i[1]),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
await asyncio.sleep(3 + random.randint(1, 3))
|
await asyncio.sleep(3 + random.randint(1, 3))
|
||||||
|
await matcher.finish()
|
||||||
|
|
||||||
|
|
||||||
# 群聊内 校验Stoken 是否正常的功能,不正常自动删掉
|
# 群聊内 校验Stoken 是否正常的功能,不正常自动删掉
|
||||||
@sv.on_fullmatch('校验全部Stoken')
|
@check_stoken.handle()
|
||||||
async def send_check_stoken(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('Stoken校验', 'Stoken校验错误')
|
||||||
|
@register_menu(
|
||||||
|
'校验全部Stoken',
|
||||||
|
'校验全部Stoken',
|
||||||
|
'校验数据库内所有Stoken是否正常',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'校验数据库内所有Stoken是否正常,不正常的会自动删除\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>校验全部Stoken</ft>\n'
|
||||||
|
'注意<ft color=(238,120,0)>Stoken</ft>的<ft color=(238,120,0)>S</ft>为大写'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_check_stoken(bot: Bot, matcher: Matcher):
|
||||||
raw_mes = await check_stoken_db()
|
raw_mes = await check_stoken_db()
|
||||||
im = raw_mes[0]
|
im = raw_mes[0]
|
||||||
await bot.send(ev, im)
|
await matcher.send(im)
|
||||||
for i in raw_mes[1]:
|
for i in raw_mes[1]:
|
||||||
await bot.send_private_msg(
|
await bot.call_api(
|
||||||
user_id=i[0],
|
api='send_private_msg',
|
||||||
message=(
|
**{
|
||||||
'您绑定的Stoken(uid{})已失效,以下功能将会受到影响:\n'
|
'user_id': i[0],
|
||||||
'gs开启自动米游币,开始获取米游币。\n'
|
'message': (
|
||||||
'重新添加后需要重新开启自动米游币。'
|
'您绑定的Stoken(uid{})已失效,以下功能将会受到影响:\n'
|
||||||
).format(i[1]),
|
'gs开启自动米游币,开始获取米游币。\n'
|
||||||
|
'重新添加后需要重新开启自动米游币。'
|
||||||
|
).format(i[1]),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
await asyncio.sleep(3 + random.randint(1, 3))
|
await asyncio.sleep(3 + random.randint(1, 3))
|
||||||
|
|
||||||
|
await matcher.finish()
|
||||||
|
@ -1,70 +1,99 @@
|
|||||||
import re
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from ..genshinuid_meta import register_menu
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from ..utils.data_convert.get_uid import get_uid
|
from ..utils.data_convert.get_uid import get_uid
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.message.error_reply import * # noqa: F403,F401
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
|
||||||
from .draw_collection_card import draw_explora_img, draw_collection_img
|
from .draw_collection_card import draw_explora_img, draw_collection_img
|
||||||
|
|
||||||
|
get_collection_info = on_command('查询收集', aliases={'收集', 'sj'}, block=True)
|
||||||
|
get_explora_info = on_command('查询探索', aliases={'探索', 'ts'}, block=True)
|
||||||
|
|
||||||
@sv.on_prefix(('查询收集', '收集', 'sj'))
|
|
||||||
async def send_collection_info(bot: HoshinoBot, ev: CQEvent):
|
@get_collection_info.handle()
|
||||||
raw_mes = ev.message.extract_plain_text().replace(' ', '')
|
@handle_exception('查询收集信息')
|
||||||
|
@register_menu(
|
||||||
|
'查询收集信息',
|
||||||
|
'查询(@某人)收集',
|
||||||
|
'查询你的或者指定人的宝箱收集度',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'可以用来查看你的或者指定人的宝箱收集度\n'
|
||||||
|
'可以在命令文本后带一张图以自定义背景图\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>{查询</ft>'
|
||||||
|
'<ft color=(125,125,125)>(@某人)</ft>'
|
||||||
|
'<ft color=(238,120,0)>|uid</ft><ft color=(0,148,200)>xx</ft>'
|
||||||
|
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>xx</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
'<ft color=(238,120,0)>{收集|宝箱|sj|bx}</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>查询收集</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>uid123456789宝箱</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi'
|
||||||
|
'</ft> <ft color=(238,120,0)>bx</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_collection_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
logger.info('开始执行[查询收集信息]')
|
logger.info('开始执行[查询收集信息]')
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', raw_mes)
|
logger.info('[查询收集信息]参数: {}'.format(args))
|
||||||
|
raw_mes = args.extract_plain_text().strip()
|
||||||
if at:
|
if event.at_user_list:
|
||||||
qid = int(at.group(1))
|
qid = event.at_user_list[0]
|
||||||
else:
|
else:
|
||||||
if ev.sender:
|
qid = event.from_wxid
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
uid = await get_uid(qid, raw_mes)
|
uid = await get_uid(qid, raw_mes)
|
||||||
logger.info('[查询收集信息]uid: {}'.format(uid))
|
logger.info('[查询收集信息]uid: {}'.format(uid))
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
if '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
im = await draw_collection_img(qid, uid)
|
im = await draw_collection_img(qid, uid)
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix(('查询探索', '探索', 'ts'))
|
@get_explora_info.handle()
|
||||||
async def send_explora_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('查询探索信息')
|
||||||
raw_mes = ev.message.extract_plain_text().replace(' ', '')
|
async def send_explora_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
logger.info('开始执行[查询探索信息]')
|
logger.info('开始执行[查询探索信息]')
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', raw_mes)
|
logger.info('[查询探索信息]参数: {}'.format(args))
|
||||||
|
raw_mes = args.extract_plain_text().strip()
|
||||||
if at:
|
if event.at_user_list:
|
||||||
qid = int(at.group(1))
|
qid = event.at_user_list[0]
|
||||||
else:
|
else:
|
||||||
if ev.sender:
|
qid = event.from_wxid
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
uid = await get_uid(qid, raw_mes)
|
uid = await get_uid(qid, raw_mes)
|
||||||
logger.info('[查询探索信息]uid: {}'.format(uid))
|
logger.info('[查询探索信息]uid: {}'.format(uid))
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
if '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
im = await draw_explora_img(qid, uid)
|
im = await draw_explora_img(qid, uid)
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -1,133 +1,211 @@
|
|||||||
import re
|
from typing import Any, Tuple
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import RegexGroup
|
||||||
|
from nonebot import on_regex, on_command
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.adapters.ntchat import Bot, MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from .draw_config_card import draw_config_img
|
from .draw_config_card import draw_config_img
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from .set_config import set_push_value, set_config_func
|
from .set_config import set_push_value, set_config_func
|
||||||
from ..utils.message.error_reply import * # noqa: F403,F401
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
|
||||||
|
|
||||||
|
open_and_close_switch = on_regex(
|
||||||
|
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
||||||
|
r'(gs)(开启|关闭)(.*)'
|
||||||
|
r'(\[CQ:at,qq=[0-9]+\])?( )?$'
|
||||||
|
)
|
||||||
|
|
||||||
@sv.on_fullmatch('gs配置')
|
push_config = on_regex(
|
||||||
async def send_config_card(bot: HoshinoBot, ev: CQEvent):
|
|
||||||
logger.info('开始执行[gs配置]')
|
|
||||||
im = await draw_config_img()
|
|
||||||
if isinstance(im, str):
|
|
||||||
await bot.send(ev, im)
|
|
||||||
elif isinstance(im, bytes):
|
|
||||||
im = await convert_img(im)
|
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(
|
|
||||||
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
||||||
r'(gs)(设置)([\u4e00-\u9fffa-zA-Z]*)([0-9]*)'
|
r'(gs)(设置)([\u4e00-\u9fffa-zA-Z]*)([0-9]*)'
|
||||||
r'(\[CQ:at,qq=[0-9]+\])?( )?$'
|
r'(\[CQ:at,qq=[0-9]+\])?( )?$'
|
||||||
)
|
)
|
||||||
async def send_config_msg(bot: HoshinoBot, ev: CQEvent):
|
|
||||||
args = ev['match'].groups()
|
config_card = on_command('gs配置', rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
|
@config_card.handle()
|
||||||
|
@handle_exception('发送配置表')
|
||||||
|
@register_menu(
|
||||||
|
'发送配置表',
|
||||||
|
'gs配置',
|
||||||
|
'查看插件当前配置项开关情况',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查看插件当前配置项开关情况\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>gs配置</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_config_card(matcher: Matcher):
|
||||||
|
logger.info('开始执行[gs配置]')
|
||||||
|
im = await draw_config_img()
|
||||||
|
if isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
elif isinstance(im, bytes):
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
else:
|
||||||
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
|
@push_config.handle()
|
||||||
|
@handle_exception('设置推送服务')
|
||||||
|
@register_menu(
|
||||||
|
'设置推送阈值',
|
||||||
|
'gs设置xx(@某人)',
|
||||||
|
'设置自己或指定人的推送服务阈值',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'设置某人的推送服务阈值\n'
|
||||||
|
'超级用户可以设置他人的推送服务阈值\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>gs设置</ft>'
|
||||||
|
'<ft color=(0,148,200)>[服务名称][阈值]</ft>'
|
||||||
|
'<ft color=(125,125,125)>(@某人)</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>gs设置推送140</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_config_msg(
|
||||||
|
bot: Bot,
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Tuple[Any, ...] = RegexGroup(),
|
||||||
|
):
|
||||||
logger.info('开始执行[设置阈值信息]')
|
logger.info('开始执行[设置阈值信息]')
|
||||||
logger.info('[设置阈值信息]参数: {}'.format(args))
|
logger.info('[设置阈值信息]参数: {}'.format(args))
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(event.from_wxid)
|
||||||
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "" and await SUPERUSER(bot, event):
|
||||||
|
qid = user
|
||||||
|
else:
|
||||||
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(
|
||||||
|
content="{$@}你没有权限操作别人的状态噢~", at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
|
||||||
|
|
||||||
if at:
|
|
||||||
qid = int(at.group(1))
|
|
||||||
else:
|
|
||||||
if ev.sender:
|
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
if qid in bot.config.SUPERUSERS:
|
|
||||||
is_admin = True
|
|
||||||
else:
|
|
||||||
is_admin = False
|
|
||||||
|
|
||||||
if at and is_admin:
|
|
||||||
qid = at
|
|
||||||
elif at and at != qid:
|
|
||||||
await bot.send(ev, '你没有权限操作别人的状态噢~', at_sender=True)
|
|
||||||
logger.info('[设置阈值信息]qid: {}'.format(qid))
|
logger.info('[设置阈值信息]qid: {}'.format(qid))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
except TypeError:
|
except TypeError:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(
|
||||||
return
|
MessageSegment.room_at_msg(
|
||||||
|
content='{$@}' + UID_HINT, at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
func = args[4].replace('阈值', '')
|
func = args[4].replace('阈值', '')
|
||||||
if args[5]:
|
if args[5]:
|
||||||
try:
|
try:
|
||||||
value = int(args[5])
|
value = int(args[5])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
await bot.send(ev, '请输入数字哦~', at_sender=True)
|
await matcher.finish(
|
||||||
return
|
MessageSegment.room_at_msg(
|
||||||
|
content="{$@}请输入数字哦~", at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '请输入正确的阈值数字!', at_sender=True)
|
await matcher.finish(
|
||||||
return
|
MessageSegment.room_at_msg(
|
||||||
|
content="{$@}请输入正确的阈值数字!", at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
logger.info('[设置阈值信息]func: {}, value: {}'.format(func, value))
|
logger.info('[设置阈值信息]func: {}, value: {}'.format(func, value))
|
||||||
im = await set_push_value(func, str(uid), value)
|
im = await set_push_value(func, str(uid), value)
|
||||||
await bot.send(ev, im, at_sender=True)
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(content="{$@}" + f"{im}", at_list=wxid_list)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# 开启 自动签到 和 推送树脂提醒 功能
|
# 开启 自动签到 和 推送树脂提醒 功能
|
||||||
@sv.on_rex(
|
@open_and_close_switch.handle()
|
||||||
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
@register_menu(
|
||||||
r'(gs)(开启|关闭)(.*)'
|
'开关推送服务',
|
||||||
r'(\[CQ:at,qq=[0-9]+\])?( )?$'
|
'gs{开启|关闭}xx(@某人)',
|
||||||
|
'开关自己或指定人的推送服务状态',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'设置某人的推送服务开关状态\n'
|
||||||
|
'超级用户可以设置他人的推送服务状态\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>gs{开启|关闭}</ft>'
|
||||||
|
'<ft color=(0,148,200)>[服务名称]</ft>'
|
||||||
|
'<ft color=(125,125,125)>(@某人)</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>gs开启推送</ft>'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
async def open_switch_func(bot: HoshinoBot, ev: CQEvent):
|
async def open_switch_func(
|
||||||
args = ev['match'].groups()
|
bot: Bot,
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
if at:
|
args: Tuple[Any, ...] = RegexGroup(),
|
||||||
qid = int(at.group(1))
|
):
|
||||||
else:
|
wxid_list = []
|
||||||
if ev.sender:
|
wxid_list.append(event.from_wxid)
|
||||||
qid = int(ev.sender['user_id'])
|
qid = event.from_wxid
|
||||||
else:
|
if event.at_user_list:
|
||||||
return
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "" and await SUPERUSER(bot, event):
|
||||||
|
qid = user
|
||||||
|
else:
|
||||||
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(
|
||||||
|
content="{$@}你没有权限操作别人的状态噢~", at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
config_name = args[4]
|
config_name = args[4]
|
||||||
|
|
||||||
logger.info(f'[{qid}]尝试[{args[3]}]了[{config_name}]功能')
|
logger.info(f'[{qid}]尝试[{args[3]}]了[{config_name}]功能')
|
||||||
|
|
||||||
|
fake_seession = f'group_{event.room_wxid}_{event.from_wxid}'
|
||||||
|
|
||||||
if args[3] == '开启':
|
if args[3] == '开启':
|
||||||
query = 'OPEN'
|
query = 'OPEN'
|
||||||
gid = str(ev.group_id) if ev.group_id else 'on'
|
gid = (
|
||||||
|
fake_seession.split('_')[1]
|
||||||
|
if len(fake_seession.split('_')) == 3
|
||||||
|
else 'on'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
query = 'CLOSED'
|
query = 'CLOSED'
|
||||||
gid = 'off'
|
gid = 'off'
|
||||||
|
|
||||||
if qid in bot.config.SUPERUSERS:
|
uid = await select_db(qid, mode='uid')
|
||||||
is_admin = True
|
if uid is None or not isinstance(uid, str) or not uid.isdecimal():
|
||||||
else:
|
await matcher.finish(
|
||||||
is_admin = False
|
MessageSegment.room_at_msg(
|
||||||
|
content='{$@}' + UID_HINT, at_list=wxid_list
|
||||||
if at and is_admin:
|
)
|
||||||
qid = at
|
)
|
||||||
elif at and at != qid:
|
|
||||||
bot.send(ev, '你没有权限操作别人的状态噢~', at_sender=True)
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
uid = await select_db(qid, mode='uid')
|
|
||||||
except TypeError:
|
|
||||||
await bot.send(ev, UID_HINT)
|
|
||||||
return
|
|
||||||
|
|
||||||
im = await set_config_func(
|
im = await set_config_func(
|
||||||
config_name=config_name,
|
config_name=config_name,
|
||||||
uid=uid, # type: ignore
|
uid=uid,
|
||||||
qid=qid, # type: ignore
|
qid=str(qid),
|
||||||
option=gid,
|
option=gid,
|
||||||
query=query,
|
query=query,
|
||||||
is_admin=is_admin,
|
is_admin=await SUPERUSER(bot, event),
|
||||||
|
)
|
||||||
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(content="{$@}" + f"{im}", at_list=wxid_list)
|
||||||
)
|
)
|
||||||
await bot.send(ev, im, at_sender=True)
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
|
||||||
from ..base import sv
|
|
||||||
from .export_data import export_v3
|
from .export_data import export_v3
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
|
|
||||||
|
export_v3_data = on_command('导出v3数据', permission=SUPERUSER, rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix(('导出v3数据'))
|
@export_v3_data.handle()
|
||||||
async def send_export_msg(bot: HoshinoBot, ev: CQEvent):
|
async def send_export_msg(matcher: Matcher):
|
||||||
if ev.sender:
|
await matcher.send('开始导出数据..可能需要一定时间!')
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
if qid not in bot.config.SUPERUSERS:
|
|
||||||
return
|
|
||||||
await bot.send(ev, '开始导出数据..可能需要一定时间!')
|
|
||||||
await export_v3()
|
await export_v3()
|
||||||
await bot.send(ev, '导出数据成功!')
|
await matcher.send('导出数据成功!')
|
||||||
|
@ -5,7 +5,7 @@ from ..utils.download_resource.RESOURCE_PATH import MAIN_PATH
|
|||||||
from ..utils.db_operation.db_operation import get_all_bind, get_user_bind_data
|
from ..utils.db_operation.db_operation import get_all_bind, get_user_bind_data
|
||||||
|
|
||||||
DATA_PATH = MAIN_PATH / 'v3_data.json'
|
DATA_PATH = MAIN_PATH / 'v3_data.json'
|
||||||
BOT_ID = 'onebot'
|
BOT_ID = 'ntchat'
|
||||||
RECOGNIZE_SERVER = {
|
RECOGNIZE_SERVER = {
|
||||||
'1': 'cn_gf01',
|
'1': 'cn_gf01',
|
||||||
'2': 'cn_gf01',
|
'2': 'cn_gf01',
|
||||||
|
@ -3,104 +3,197 @@ import random
|
|||||||
import asyncio
|
import asyncio
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
from nonebot.adapters.ntchat import (
|
||||||
|
Bot,
|
||||||
|
MessageEvent,
|
||||||
|
MessageSegment,
|
||||||
|
TextMessageEvent,
|
||||||
|
QuoteMessageEvent,
|
||||||
|
)
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..config import priority
|
||||||
from .get_enka_img import draw_enka_img
|
from .get_enka_img import draw_enka_img
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from .draw_char_rank import draw_cahrcard_list
|
from .draw_char_rank import draw_cahrcard_list
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.enka_api.get_enka_data import switch_api
|
from ..utils.enka_api.get_enka_data import switch_api
|
||||||
from ..utils.enka_api.enka_to_card import enka_to_card
|
from ..utils.enka_api.enka_to_card import enka_to_card
|
||||||
from ..utils.enka_api.enka_to_data import enka_to_data
|
from ..utils.enka_api.enka_to_data import enka_to_data
|
||||||
from ..utils.download_resource.RESOURCE_PATH import TEMP_PATH
|
from ..utils.download_resource.RESOURCE_PATH import TEMP_PATH
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.db_operation.db_operation import select_db, get_all_uid
|
from ..utils.db_operation.db_operation import select_db, get_all_uid
|
||||||
|
|
||||||
|
refresh = on_command('强制刷新')
|
||||||
|
original_pic = on_command('原图', rule=FullCommand())
|
||||||
|
change_api = on_command('切换api', rule=FullCommand())
|
||||||
|
get_charcard_list = on_command('毕业度统计')
|
||||||
|
get_char_info = on_command(
|
||||||
|
'查询',
|
||||||
|
priority=priority,
|
||||||
|
)
|
||||||
|
|
||||||
AUTO_REFRESH = False
|
AUTO_REFRESH = False
|
||||||
|
refresh_scheduler = scheduler
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('切换api')
|
@change_api.handle()
|
||||||
async def send_change_api_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('切换api')
|
||||||
print(ev)
|
@register_menu(
|
||||||
if ev.sender:
|
'切换API',
|
||||||
qid = int(ev.sender['user_id'])
|
'切换api',
|
||||||
else:
|
'切换获取角色面板时使用的API',
|
||||||
return
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
if qid not in bot.config.SUPERUSERS:
|
'切换获取角色面板时使用的Enka Network API\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>切换api</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_change_api_info(
|
||||||
|
bot: Bot,
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
|
|
||||||
im = await switch_api()
|
im = await switch_api()
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'^(\[CQ:reply,id=[0-9]+\])?( )?(\[CQ:at,qq=[0-9]+\])?( )?原图')
|
@original_pic.handle()
|
||||||
async def send_original_pic(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('原图')
|
||||||
for msg in ev.message:
|
@register_menu(
|
||||||
if msg['type'] == 'reply':
|
'查看面板原图',
|
||||||
msg_id = msg['data']['id']
|
'原图',
|
||||||
path = TEMP_PATH / f'{msg_id}.jpg'
|
'查看角色面板中原随机图',
|
||||||
if path.exists():
|
trigger_method='回复+指令',
|
||||||
logger.info('[原图]访问图片: {}'.format(path))
|
detail_des=(
|
||||||
with open(path, 'rb') as f:
|
'介绍:\n'
|
||||||
im = await convert_img(f.read())
|
'查看开启随机图功能时角色面板中角色位置的原图,需要回复要查看原图的面板图片消息\n'
|
||||||
await bot.send(ev, im)
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>原图</ft>'
|
||||||
@sv.on_rex(
|
),
|
||||||
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
|
||||||
r'(uid|查询|mys)([0-9]+)?'
|
|
||||||
r'([\u4e00-\u9fa5]+)'
|
|
||||||
r'(\[CQ:at,qq=[0-9]+\])?( )?',
|
|
||||||
)
|
)
|
||||||
async def send_char_info(bot: HoshinoBot, ev: CQEvent):
|
async def send_original_pic(
|
||||||
args = ev['match'].groups()
|
event: QuoteMessageEvent,
|
||||||
if args[4] is None:
|
matcher: Matcher,
|
||||||
return
|
):
|
||||||
# 获取角色名
|
msg_id = event.quote_message_id
|
||||||
msg = ''.join(re.findall('[\u4e00-\u9fa5]', args[4]))
|
path = TEMP_PATH / f'{msg_id}.jpg'
|
||||||
logger.info('开始执行[查询角色面板]')
|
if path.exists():
|
||||||
logger.info('[查询角色面板]参数: {}'.format(args))
|
logger.info('[原图]访问图片: {}'.format(path))
|
||||||
# 获取角色名
|
with open(path, 'rb') as f:
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
await matcher.finish(MessageSegment.image(f.read()))
|
||||||
image = re.search(r'\[CQ:image,file=(.*),url=(.*)]', str(ev.message))
|
|
||||||
|
|
||||||
img = None
|
|
||||||
if image:
|
@get_char_info.handle()
|
||||||
img = image.group(2)
|
@handle_exception('查询角色面板')
|
||||||
if at:
|
@register_menu(
|
||||||
qid = int(at.group(1))
|
'查询角色面板',
|
||||||
else:
|
'查询(@某人)角色名',
|
||||||
if ev.sender:
|
'查询你的或者指定人的已缓存展柜角色的面板',
|
||||||
qid = int(ev.sender['user_id'])
|
detail_des=(
|
||||||
else:
|
'介绍:\n'
|
||||||
|
'可以用来查看你的或者指定人的已缓存展柜角色的面板\n'
|
||||||
|
'支持部分角色别名\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>{查询</ft>'
|
||||||
|
'<ft color=(125,125,125)>(@某人)</ft>'
|
||||||
|
'<ft color=(238,120,0)>|uid</ft><ft color=(0,148,200)>xx</ft>'
|
||||||
|
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>xx</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
'<ft color=(0,148,200)>[角色名]</ft>\n'
|
||||||
|
'后面可以跟 '
|
||||||
|
'<ft color=(238,120,0)>换</ft>'
|
||||||
|
'<ft color=(125,125,125)>(精{一|二|三|四|五})</ft>'
|
||||||
|
'<ft color=(0,148,200)>[武器名]</ft> '
|
||||||
|
'来更换展示的武器\n'
|
||||||
|
'可以跟 '
|
||||||
|
'<ft color=(125,125,125)>(成长)</ft><ft color=(238,120,0)>曲线</ft> '
|
||||||
|
'来查询该角色成长曲线\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>查询宵宫</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>查询绫华换精五雾切</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>查询一斗成长曲线</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi</ft>'
|
||||||
|
' <ft color=(238,120,0)>公子</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@register_menu(
|
||||||
|
'查询展柜角色',
|
||||||
|
'查询展柜角色',
|
||||||
|
'查询插件已缓存的展柜角色列表',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询插件当前已缓存的展柜角色列表\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>查询展柜角色</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_char_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
raw_mes = args.extract_plain_text().strip()
|
||||||
|
name = ''.join(re.findall('[\u4e00-\u9fa5]', raw_mes))
|
||||||
|
# 如果输入中(查询之后的内容)没有其他字符串(如角色名等)则忽略。
|
||||||
|
if not name:
|
||||||
|
return
|
||||||
|
# 若查询中有@则排除@后内容,排除后若@前没有 其他内容则不继续运行下方代码 防止与roleinfo查询打架
|
||||||
|
# 修改后@人应该在命令末尾 如:查询万叶@XXXX
|
||||||
|
if "@" in raw_mes:
|
||||||
|
raw_mes = raw_mes.split("@")[0]
|
||||||
|
if not raw_mes:
|
||||||
return
|
return
|
||||||
logger.info('[查询角色面板]QQ: {}'.format(qid))
|
logger.info('开始执行[查询角色面板]')
|
||||||
|
# 获取被@的Wxid,排除""
|
||||||
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
|
logger.info('[查询角色面板]WXID: {}'.format(qid))
|
||||||
|
|
||||||
# 获取uid
|
# 获取uid
|
||||||
if args[3] is None:
|
uid = re.findall(r'\d+', raw_mes.split("@")[0])
|
||||||
|
if uid:
|
||||||
|
uid = uid[0]
|
||||||
|
else:
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
uid = str(uid)
|
uid = str(uid)
|
||||||
else:
|
|
||||||
uid = args[3]
|
|
||||||
logger.info('[查询角色面板]uid: {}'.format(uid))
|
logger.info('[查询角色面板]uid: {}'.format(uid))
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
if '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
im = await draw_enka_img(msg, uid, img)
|
im = await draw_enka_img(raw_mes, uid, None)
|
||||||
|
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, Tuple):
|
elif isinstance(im, Tuple):
|
||||||
img = await convert_img(im[0])
|
await matcher.send(MessageSegment.image(im[0]))
|
||||||
req = await bot.send(ev, img)
|
# msg_id = req['message_id']
|
||||||
msg_id = req['message_id']
|
|
||||||
if im[1]:
|
if im[1]:
|
||||||
with open(TEMP_PATH / f'{msg_id}.jpg', 'wb') as f:
|
with open(TEMP_PATH / f'{uid}.jpg', 'wb') as f:
|
||||||
f.write(im[1])
|
f.write(im[1])
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
async def refresh_char_data():
|
async def refresh_char_data():
|
||||||
@ -125,92 +218,119 @@ async def refresh_char_data():
|
|||||||
return f'执行成功!共刷新{str(t)}个角色!'
|
return f'执行成功!共刷新{str(t)}个角色!'
|
||||||
|
|
||||||
|
|
||||||
@sv.scheduled_job('cron', hour='4')
|
@refresh_scheduler.scheduled_job('cron', hour='4')
|
||||||
async def daily_refresh_charData():
|
async def daily_refresh_charData():
|
||||||
global AUTO_REFRESH
|
global AUTO_REFRESH
|
||||||
if AUTO_REFRESH:
|
if AUTO_REFRESH:
|
||||||
await refresh_char_data()
|
await refresh_char_data()
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('强制刷新')
|
@refresh.handle()
|
||||||
async def send_card_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('强制刷新')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'刷新展柜缓存',
|
||||||
else:
|
'强制刷新',
|
||||||
return
|
'强制刷新你的或者指定人缓存的角色展柜数据',
|
||||||
|
detail_des=(
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
'指令:'
|
||||||
|
'<ft color=(238,120,0)>强制刷新</ft>'
|
||||||
if at:
|
'<ft color=(125,125,125)>(uid/全部数据)</ft>\n'
|
||||||
qid = int(at.group(1))
|
' \n'
|
||||||
message = message.replace(str(at), '')
|
'用于强制刷新你的或者指定人缓存的角色展柜数据\n'
|
||||||
else:
|
'当刷新全部数据时需要机器人管理员权限\n'
|
||||||
if ev.sender:
|
' \n'
|
||||||
qid = int(ev.sender['user_id'])
|
'示例:\n'
|
||||||
else:
|
'<ft color=(238,120,0)>强制刷新</ft>;\n'
|
||||||
return
|
'<ft color=(238,120,0)>强制刷新123456789</ft>;\n'
|
||||||
|
'<ft color=(238,120,0)>强制刷新全部数据</ft>'
|
||||||
uid = re.findall(r'\d+', message) # str
|
),
|
||||||
|
)
|
||||||
|
async def send_card_info(
|
||||||
|
bot: Bot,
|
||||||
|
matcher: Matcher,
|
||||||
|
event: TextMessageEvent,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
|
uid = re.findall(r'\d+', message.split("@")[0]) # str
|
||||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||||
|
# 获取被@的Wxid,排除""
|
||||||
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
|
|
||||||
if len(uid) >= 1:
|
if len(uid) >= 1:
|
||||||
uid = uid[0]
|
uid = uid[0]
|
||||||
else:
|
else:
|
||||||
if m == '全部数据':
|
if m == '全部数据':
|
||||||
if qid in bot.config.SUPERUSERS:
|
if await SUPERUSER(bot, event):
|
||||||
await bot.send(ev, '开始刷新全部数据,这可能需要相当长的一段时间!!')
|
await matcher.send('开始刷新全部数据,这可能需要相当长的一段时间!!')
|
||||||
im = await refresh_char_data()
|
im = await refresh_char_data()
|
||||||
await bot.send(ev, str(im))
|
await matcher.finish(str(im))
|
||||||
return
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
uid = str(uid)
|
uid = str(uid)
|
||||||
if '未找到绑定的UID' in uid:
|
if not uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
return
|
|
||||||
im = await enka_to_card(uid)
|
im = await enka_to_card(uid)
|
||||||
|
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('毕业度统计')
|
@get_charcard_list.handle()
|
||||||
async def send_charcard_list(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('毕业度统计')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'毕业度统计',
|
||||||
else:
|
'毕业度统计',
|
||||||
return
|
'查看你或指定人已缓存的展柜角色毕业度',
|
||||||
|
detail_des=(
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
'指令:'
|
||||||
|
'<ft color=(238,120,0)>毕业度统计</ft>'
|
||||||
if at:
|
'<ft color=(125,125,125)>(@某人)</ft>\n'
|
||||||
qid = int(at.group(1))
|
' \n'
|
||||||
message = message.replace(str(at), '')
|
'可以查看你或指定人已缓存的所有展柜角色毕业度\n'
|
||||||
else:
|
' \n'
|
||||||
if ev.sender:
|
'示例:\n'
|
||||||
qid = int(ev.sender['user_id'])
|
'<ft color=(238,120,0)>毕业度统计</ft>;\n'
|
||||||
else:
|
'<ft color=(238,120,0)>毕业度统计</ft><ft color=(0,148,200)>@无疑Wuyi</ft>'
|
||||||
return
|
),
|
||||||
|
)
|
||||||
|
async def send_charcard_list(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
raw_mes = args.extract_plain_text().strip()
|
||||||
|
# 获取被@的Wxid,排除""
|
||||||
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
|
|
||||||
# 获取uid
|
# 获取uid
|
||||||
uid = re.findall(r'\d+', message)
|
uid = re.findall(r'\d+', raw_mes.split("@")[0])
|
||||||
if uid:
|
if uid:
|
||||||
uid = uid[0]
|
uid = uid[0]
|
||||||
else:
|
else:
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
|
uid = str(uid)
|
||||||
|
|
||||||
im = await draw_cahrcard_list(str(uid), qid)
|
im = await draw_cahrcard_list(str(uid), qid)
|
||||||
|
|
||||||
logger.info(f'UID{uid}获取角色数据成功!')
|
logger.info(f'UID{uid}获取角色数据成功!')
|
||||||
if isinstance(im, bytes):
|
if isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, str(im))
|
await matcher.finish(str(im))
|
||||||
|
@ -501,7 +501,7 @@ class Character:
|
|||||||
|
|
||||||
# 重新计算加成值
|
# 重新计算加成值
|
||||||
# base_effect_list = [
|
# base_effect_list = [
|
||||||
# [limit_list, effect_attr, effect_value,effect_base]
|
# [limit_list, effect_attr, effect_value, effect_base]
|
||||||
# ]
|
# ]
|
||||||
for effect in base_effect_list:
|
for effect in base_effect_list:
|
||||||
prop = await self.get_buff_value(prop, *effect)
|
prop = await self.get_buff_value(prop, *effect)
|
||||||
@ -614,8 +614,12 @@ class Character:
|
|||||||
'type': '攻击力',
|
'type': '攻击力',
|
||||||
'plus': 1,
|
'plus': 1,
|
||||||
'value': [
|
'value': [
|
||||||
f'''{int(i[:-1]) +
|
f'''{
|
||||||
int(self.power_list["A霜华矢·霜华绽发伤害"]["value"][index][:-1])
|
int(i[:-1]) + int(
|
||||||
|
self.power_list[
|
||||||
|
"A霜华矢·霜华绽发伤害"
|
||||||
|
]["value"][index][:-1]
|
||||||
|
)
|
||||||
}%'''
|
}%'''
|
||||||
for index, i in enumerate(
|
for index, i in enumerate(
|
||||||
self.power_list['A霜华矢命中伤害']['value']
|
self.power_list['A霜华矢命中伤害']['value']
|
||||||
|
@ -216,8 +216,8 @@ class Fight:
|
|||||||
if '前台' in char.power_list[char.power_name]['name']:
|
if '前台' in char.power_list[char.power_name]['name']:
|
||||||
if char.char_name == '纳西妲':
|
if char.char_name == '纳西妲':
|
||||||
em = char.fight_prop[f'{char.attack_type}_elementalMastery']
|
em = char.fight_prop[f'{char.attack_type}_elementalMastery']
|
||||||
effect = f'''elementalMastery+
|
effect = f'''
|
||||||
{0.25 * em if 0.25 * em <= 250 else 250}
|
elementalMastery+{0.25 * em if 0.25 * em <= 250 else 250}
|
||||||
'''.strip()
|
'''.strip()
|
||||||
effect_list.append(effect)
|
effect_list.append(effect)
|
||||||
|
|
||||||
|
@ -1,42 +1,119 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, Tuple
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import on_regex, on_command
|
||||||
|
from nonebot.params import CommandArg, RegexGroup
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from ..version import Genshin_version
|
from ..version import Genshin_version
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_primogems_data = on_command('版本规划', aliases={'原石预估'})
|
||||||
|
get_img_data = on_regex(r'^(查询)?(伤害乘区|血量表|抗性表|血量排行)$')
|
||||||
|
|
||||||
PRIMOGEMS_DATA_PATH = Path(__file__).parent / 'primogems_data'
|
PRIMOGEMS_DATA_PATH = Path(__file__).parent / 'primogems_data'
|
||||||
IMG_PATH = Path(__file__).parent / 'img_data'
|
IMG_PATH = Path(__file__).parent / 'img_data'
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'^(版本规划|原石预估)(\S+)?$')
|
@get_primogems_data.handle()
|
||||||
async def send_primogems_data(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('版本规划')
|
||||||
args = ev['match'].groups()
|
@register_menu(
|
||||||
|
'版本原石规划',
|
||||||
|
'版本规划(版本号)',
|
||||||
|
'发送一张指定版本的原石规划图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张指定版本的原石规划图\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>版本规划</ft><ft color=(125,125,125)>(版本号)</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>原石预估</ft><ft color=(125,125,125)>(版本号)</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>版本规划</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>版本规划3.0</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_primogems_data(matcher: Matcher, args: Message = CommandArg()):
|
||||||
logger.info('开始执行[图片][版本规划]')
|
logger.info('开始执行[图片][版本规划]')
|
||||||
logger.info('[图片][版本规划]参数: {}'.format(args))
|
logger.info('[图片][版本规划]参数: {}'.format(args))
|
||||||
if args[1]:
|
if args:
|
||||||
path = PRIMOGEMS_DATA_PATH / f'{str(args[1])}.png'
|
path = PRIMOGEMS_DATA_PATH / f'{str(args)}.png'
|
||||||
if path.exists():
|
if path.exists():
|
||||||
img = f'{str(args[1])}.png'
|
img = f'{str(args)}.png'
|
||||||
else:
|
else:
|
||||||
return
|
await matcher.finish()
|
||||||
else:
|
else:
|
||||||
img = f'{Genshin_version[:3]}.png'
|
img = f'{Genshin_version[:3]}.png'
|
||||||
primogems_img = PRIMOGEMS_DATA_PATH / img
|
primogems_img = PRIMOGEMS_DATA_PATH / img
|
||||||
logger.info('[图片][版本规划]访问图片: {}'.format(img))
|
if primogems_img.exists():
|
||||||
primogems_img = await convert_img(primogems_img)
|
logger.info('[图片][版本规划]访问图片: {}'.format(img))
|
||||||
await bot.send(ev, primogems_img)
|
with open(primogems_img, 'rb') as f:
|
||||||
|
await matcher.finish(MessageSegment.image(f.read()))
|
||||||
|
else:
|
||||||
|
await matcher.finish()
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'^(查询)?(伤害乘区|血量表|抗性表|血量排行)$')
|
@get_img_data.handle()
|
||||||
async def send_img_data(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('杂图')
|
||||||
args = ev['match'].groups()
|
@register_menu(
|
||||||
|
'伤害乘区图',
|
||||||
|
'(查询)伤害乘区',
|
||||||
|
'发送一张理论伤害计算公式图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张理论伤害计算公式图\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(125,125,125)>(查询)</ft><ft color=(238,120,0)>伤害乘区</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@register_menu(
|
||||||
|
'怪物血量表',
|
||||||
|
'(查询)血量表',
|
||||||
|
'发送一张原神怪物血量表图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张原神怪物血量表图\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(125,125,125)>(查询)</ft><ft color=(238,120,0)>血量表</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@register_menu(
|
||||||
|
'怪物抗性表',
|
||||||
|
'(查询)抗性表',
|
||||||
|
'发送一张原神怪物抗性表图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张原神怪物抗性表图\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(125,125,125)>(查询)</ft><ft color=(238,120,0)>抗性表</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@register_menu(
|
||||||
|
'怪物血量排行',
|
||||||
|
'(查询)血量排行',
|
||||||
|
'发送一张原神怪物血量排行图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张原神怪物血量排行图\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(125,125,125)>(查询)</ft><ft color=(238,120,0)>血量排行</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_img_data(
|
||||||
|
matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
|
||||||
|
):
|
||||||
logger.info('开始执行[图片][杂图]')
|
logger.info('开始执行[图片][杂图]')
|
||||||
logger.info('[图片][杂图]参数: {}'.format(args))
|
logger.info('[图片][杂图]参数: {}'.format(args))
|
||||||
img = IMG_PATH / f'{args[1]}.jpg'
|
img = IMG_PATH / f'{args[1]}.jpg'
|
||||||
if img.exists():
|
if img.exists():
|
||||||
img = await convert_img(img)
|
with open(img, 'rb') as f:
|
||||||
await bot.send(ev, img)
|
await matcher.finish(MessageSegment.image(f.read()))
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
@ -1,24 +1,56 @@
|
|||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
|
||||||
from ..base import sv
|
from ..config import priority
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from .draw_event_img import get_event_img, get_all_event_img
|
from .draw_event_img import get_event_img, get_all_event_img
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_event = on_command('活动列表', priority=priority, rule=FullCommand())
|
||||||
|
get_gacha = on_command('卡池列表', priority=priority, rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
@sv.scheduled_job('cron', hour='2')
|
@scheduler.scheduled_job('cron', hour='2')
|
||||||
async def draw_event():
|
async def draw_event():
|
||||||
await get_all_event_img()
|
await get_all_event_img()
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('活动列表')
|
@get_event.handle()
|
||||||
async def send_events(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('活动')
|
||||||
|
@register_menu(
|
||||||
|
'活动列表',
|
||||||
|
'活动列表',
|
||||||
|
'查询当前版本活动日程表',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询当前版本活动日程表\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>活动列表</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_events(matcher: Matcher):
|
||||||
img = await get_event_img('EVENT')
|
img = await get_event_img('EVENT')
|
||||||
im = await convert_img(img)
|
await matcher.finish(MessageSegment.image(img))
|
||||||
await bot.send(ev, im)
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('卡池列表')
|
@get_gacha.handle()
|
||||||
async def send_gachas(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('活动')
|
||||||
|
@register_menu(
|
||||||
|
'卡池列表',
|
||||||
|
'卡池列表',
|
||||||
|
'查询当前版本卡池列表',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询当前版本卡池列表\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>卡池列表</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_gachas(matcher: Matcher):
|
||||||
img = await get_event_img('GACHA')
|
img = await get_event_img('GACHA')
|
||||||
im = await convert_img(img)
|
await matcher.finish(MessageSegment.image(img))
|
||||||
await bot.send(ev, im)
|
|
||||||
|
BIN
GenshinUID/genshinuid_eventlist/event.jpg
Normal file
BIN
GenshinUID/genshinuid_eventlist/event.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 307 KiB |
BIN
GenshinUID/genshinuid_eventlist/gacha.jpg
Normal file
BIN
GenshinUID/genshinuid_eventlist/gacha.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 411 KiB |
@ -1,93 +1,169 @@
|
|||||||
from nonebot import get_bot
|
import os
|
||||||
from hoshino.typing import CQEvent, HoshinoBot, NoticeSession
|
import asyncio
|
||||||
|
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.rule import is_type
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import get_bot, on_command, on_message
|
||||||
|
from nonebot.adapters.ntchat.permission import GROUP
|
||||||
|
from nonebot.adapters.ntchat import (
|
||||||
|
MessageSegment,
|
||||||
|
FileMessageEvent,
|
||||||
|
TextMessageEvent,
|
||||||
|
)
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from .get_gachalogs import save_gachalogs
|
from .get_gachalogs import save_gachalogs
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from .draw_gachalogs import draw_gachalogs_img
|
from .draw_gachalogs import draw_gachalogs_img
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from .export_and_import import export_gachalogs, import_gachalogs
|
from .export_and_import import export_gachalogs, import_gachalogs
|
||||||
|
|
||||||
|
get_gacha_log = on_command('刷新抽卡记录', aliases={'强制刷新抽卡记录'}, rule=FullCommand())
|
||||||
@sv.on_notice()
|
get_gacha_log_card = on_command('抽卡记录', rule=FullCommand())
|
||||||
async def import_gacha_log_info(session: NoticeSession):
|
import_gacha_log = on_message(block=False, rule=(is_type(FileMessageEvent)))
|
||||||
ev = session.event
|
export_gacha_log = on_command('导出抽卡记录', rule=FullCommand(), permission=GROUP)
|
||||||
if ev['notice_type'] != 'offline_file':
|
|
||||||
return
|
|
||||||
url = ev['file']['url']
|
|
||||||
name: str = ev['file']['name']
|
|
||||||
if not name.endswith('.json'):
|
|
||||||
return
|
|
||||||
qid = ev['user_id']
|
|
||||||
uid = await select_db(qid, mode='uid')
|
|
||||||
if not isinstance(uid, str) or '未找到绑定的UID' in uid:
|
|
||||||
await session.send(UID_HINT)
|
|
||||||
return
|
|
||||||
logger.info('开始执行[导入抽卡记录]')
|
|
||||||
im = await import_gachalogs(url, uid)
|
|
||||||
await session.send(im, at_sender=True)
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('导出抽卡记录')
|
@export_gacha_log.handle()
|
||||||
async def export_gacha_log_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('导出抽卡记录')
|
||||||
|
@register_menu(
|
||||||
|
'导出抽卡记录',
|
||||||
|
'导出抽卡记录',
|
||||||
|
'导出符合UIGF规范的抽卡记录',
|
||||||
|
trigger_method='群聊指令',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'导出UIGF格式规范的json格式抽卡记录上传到群文件\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>导出抽卡记录</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def export_gacha_log_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
logger.info('开始执行[导出抽卡记录]')
|
logger.info('开始执行[导出抽卡记录]')
|
||||||
qid = int(ev.sender['user_id'])
|
qid = event.from_wxid
|
||||||
gid = int(ev.group_id)
|
gid = event.room_wxid
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
bot = get_bot()
|
bot = get_bot()
|
||||||
if not isinstance(uid, str) or '未找到绑定的UID' in uid:
|
if not isinstance(uid, str) or '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
return
|
|
||||||
raw_data = await export_gachalogs(uid)
|
raw_data = await export_gachalogs(uid)
|
||||||
if raw_data['retcode'] == 'ok':
|
if raw_data['retcode'] == 'ok':
|
||||||
await bot.call_action(
|
await bot.call_api(
|
||||||
action='upload_group_file',
|
'send_file',
|
||||||
group_id=gid,
|
to_wxid=gid,
|
||||||
name=raw_data['name'],
|
file_path=raw_data['url'],
|
||||||
file=raw_data['url'],
|
|
||||||
)
|
)
|
||||||
logger.info(f'[导出抽卡记录] UID{uid}成功!')
|
logger.info(f'[导出抽卡记录] UID{uid}成功!')
|
||||||
await bot.send(ev, '上传成功!')
|
await matcher.finish('上传成功!')
|
||||||
else:
|
else:
|
||||||
logger.warning(f'[导出抽卡记录] UID{uid}失败!')
|
logger.warning(f'[导出抽卡记录] UID{uid}失败!')
|
||||||
await bot.send(ev, '导出抽卡记录失败!')
|
await matcher.finish('导出抽卡记录失败!')
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('抽卡记录')
|
@import_gacha_log.handle()
|
||||||
async def send_gacha_log_card_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('导入抽卡记录')
|
||||||
|
@register_menu(
|
||||||
|
'导入抽卡记录',
|
||||||
|
'json格式文件',
|
||||||
|
'导入符合UIGF规范的抽卡记录',
|
||||||
|
trigger_method='私聊离线文件',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'导入UIGF格式规范的json格式抽卡记录到插件本地缓存\n'
|
||||||
|
' \n'
|
||||||
|
'触发方式:\n'
|
||||||
|
'- <ft color=(238,120,0)>私聊发送json格式的离线文件</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def import_gacha_log_info(event: FileMessageEvent, matcher: Matcher):
|
||||||
|
await asyncio.sleep(2) # 等待下载文件,避免占用
|
||||||
|
# 检测文件是否存在并小于8MB
|
||||||
|
if (
|
||||||
|
os.path.exists(event.file)
|
||||||
|
and os.path.getsize(event.file) <= 8 * 1024 * 1024
|
||||||
|
and event.file_name.endswith(".json")
|
||||||
|
):
|
||||||
|
uid = await select_db(event.from_wxid, mode='uid')
|
||||||
|
if not isinstance(uid, str) or '未找到绑定的UID' in uid:
|
||||||
|
await matcher.finish(UID_HINT)
|
||||||
|
logger.info('开始执行[导入抽卡记录]')
|
||||||
|
im = await import_gachalogs(event.file, uid)
|
||||||
|
await matcher.finish(im)
|
||||||
|
else:
|
||||||
|
await matcher.finish()
|
||||||
|
|
||||||
|
|
||||||
|
@get_gacha_log_card.handle()
|
||||||
|
@handle_exception('抽卡记录')
|
||||||
|
@register_menu(
|
||||||
|
'查询抽卡记录',
|
||||||
|
'抽卡记录',
|
||||||
|
'查询你的原神抽卡记录',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询你的原神抽卡记录\n'
|
||||||
|
'需要<ft color=(238,120,0)>绑定Stoken</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'<ft color=(238,120,0)>抽卡记录</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_gacha_log_card_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
logger.info('开始执行[抽卡记录]')
|
logger.info('开始执行[抽卡记录]')
|
||||||
if ev.sender:
|
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
uid = await select_db(qid, mode='uid')
|
|
||||||
|
|
||||||
|
uid = await select_db(event.from_wxid, mode='uid')
|
||||||
if isinstance(uid, str):
|
if isinstance(uid, str):
|
||||||
im = await draw_gachalogs_img(uid, qid)
|
im = await draw_gachalogs_img(uid, event.from_wxid) # type: ignore
|
||||||
if isinstance(im, bytes):
|
if isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('刷新抽卡记录', '强制刷新抽卡记录'))
|
@get_gacha_log.handle()
|
||||||
async def send_daily_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('刷新抽卡记录')
|
||||||
|
@register_menu(
|
||||||
|
'刷新抽卡记录',
|
||||||
|
'刷新抽卡记录',
|
||||||
|
'刷新你的原神抽卡记录本地缓存',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'刷新你的原神抽卡记录本地缓存\n'
|
||||||
|
'需要<ft color=(238,120,0)>绑定Stoken</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>刷新抽卡记录</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_daily_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
logger.info('开始执行[刷新抽卡记录]')
|
logger.info('开始执行[刷新抽卡记录]')
|
||||||
if ev.sender:
|
wxid_list = []
|
||||||
qid = int(ev.sender['user_id'])
|
wxid_list.append(event.from_wxid)
|
||||||
else:
|
uid = await select_db(event.from_wxid, mode='uid')
|
||||||
return
|
|
||||||
uid = await select_db(qid, mode='uid')
|
|
||||||
if isinstance(uid, str):
|
if isinstance(uid, str):
|
||||||
is_force = False
|
is_force = False
|
||||||
if ev.raw_message and str(ev.raw_message).startswith('强制'):
|
if event.msg.startswith('强制'):
|
||||||
logger.info('[WARNING]本次为强制刷新')
|
|
||||||
is_force = True
|
is_force = True
|
||||||
|
tip = '正在刷新抽卡记录,请耐心等待,不要重复发送命令。'
|
||||||
|
await matcher.send(
|
||||||
|
MessageSegment.room_at_msg(content=tip, at_list=wxid_list)
|
||||||
|
)
|
||||||
im = await save_gachalogs(uid, None, is_force)
|
im = await save_gachalogs(uid, None, is_force)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
@ -16,22 +16,30 @@ INT_TO_TYPE = {
|
|||||||
|
|
||||||
|
|
||||||
async def import_gachalogs(history_url: str, uid: str) -> str:
|
async def import_gachalogs(history_url: str, uid: str) -> str:
|
||||||
history_data: dict = json.loads(get(history_url).text)
|
# 是否Json文件检测
|
||||||
data_uid = history_data['info']['uid']
|
try:
|
||||||
if data_uid != uid:
|
if not history_url.startswith(('http', 'https')):
|
||||||
return f'该抽卡记录UID{data_uid}与你绑定UID{uid}不符合!'
|
with open(history_url, 'r', encoding='utf-8') as history_url_files:
|
||||||
raw_data = history_data['list']
|
history_data = json.load(history_url_files)
|
||||||
result = {'新手祈愿': [], '常驻祈愿': [], '角色祈愿': [], '武器祈愿': []}
|
else:
|
||||||
for item in raw_data:
|
history_data: dict = get(history_url).json()
|
||||||
item['uid'] = uid
|
data_uid = history_data['info']['uid']
|
||||||
item['item_id'] = ''
|
if data_uid != uid:
|
||||||
item['count'] = '1'
|
return f'该抽卡记录UID{data_uid}与你绑定UID{uid}不符合!'
|
||||||
item['lang'] = 'zh-cn'
|
raw_data = history_data['list']
|
||||||
item['id'] = str(item['id'])
|
result = {'新手祈愿': [], '常驻祈愿': [], '角色祈愿': [], '武器祈愿': []}
|
||||||
del item['uigf_gacha_type']
|
for item in raw_data:
|
||||||
result[INT_TO_TYPE[item['gacha_type']]].append(item)
|
item['uid'] = uid
|
||||||
im = await save_gachalogs(uid, result)
|
item['item_id'] = ''
|
||||||
return im
|
item['count'] = '1'
|
||||||
|
item['lang'] = 'zh-cn'
|
||||||
|
item['id'] = str(item['id'])
|
||||||
|
del item['uigf_gacha_type']
|
||||||
|
result[INT_TO_TYPE[item['gacha_type']]].append(item)
|
||||||
|
im = await save_gachalogs(uid, result)
|
||||||
|
return im
|
||||||
|
except Exception:
|
||||||
|
return '导入失败,请检查你的Json文件!'
|
||||||
|
|
||||||
|
|
||||||
async def export_gachalogs(uid: str) -> dict:
|
async def export_gachalogs(uid: str) -> dict:
|
||||||
|
@ -1,49 +1,64 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..config import priority
|
||||||
from .draw_gcginfo import draw_gcg_info
|
from .draw_gcginfo import draw_gcg_info
|
||||||
from ..utils.message.error_reply import UID_HINT
|
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.message.error_reply import CK_HINT, UID_HINT
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_gcg_info = on_command('七圣召唤', aliases={'七圣', '召唤'}, priority=priority)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix(('七圣召唤', '七圣', '召唤'))
|
# 群聊内 每月统计 功能
|
||||||
async def send_gcg_pic(bot: HoshinoBot, ev: CQEvent):
|
@get_gcg_info.handle()
|
||||||
if ev.message:
|
@handle_exception('七圣召唤', '获取/发送七圣召唤失败', '@未找到绑定信息\n' + CK_HINT)
|
||||||
raw_mes = ev.message.extract_plain_text().replace(' ', '')
|
async def send_gcg_pic(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
raw_mes = args.extract_plain_text().strip().replace(' ', '')
|
||||||
|
if "@" in raw_mes:
|
||||||
|
name = ''.join(re.findall('^[\u4e00-\u9fa5]+', raw_mes.split("@")[0]))
|
||||||
|
if name:
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
return
|
name = ''.join(re.findall('^[\u4e00-\u9fa5]+', raw_mes))
|
||||||
|
if name:
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
return
|
||||||
logger.info('开始执行[七圣召唤]')
|
logger.info('开始执行[七圣召唤]')
|
||||||
|
qid = event.from_wxid
|
||||||
if at:
|
if event.at_user_list:
|
||||||
qid = int(at.group(1))
|
for user in event.at_user_list:
|
||||||
else:
|
user = user.strip()
|
||||||
qid = int(ev.sender['user_id'])
|
if user != "":
|
||||||
logger.info('[七圣召唤]QQ: {}'.format(qid))
|
qid = user
|
||||||
|
logger.info('[七圣召唤]WXID: {}'.format(qid))
|
||||||
|
|
||||||
# 获取uid
|
# 获取uid
|
||||||
uid = re.findall(r'\d+', raw_mes)
|
uid = re.findall(r'\d+', raw_mes.split("@")[0])
|
||||||
if uid:
|
if uid:
|
||||||
uid = uid[0]
|
uid = uid[0]
|
||||||
else:
|
else:
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
uid = str(uid)
|
uid = str(uid)
|
||||||
|
|
||||||
logger.info('[七圣召唤]uid: {}'.format(uid))
|
logger.info('[七圣召唤]uid: {}'.format(uid))
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
if '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
im = await draw_gcg_info(uid)
|
im = await draw_gcg_info(uid)
|
||||||
|
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -1,117 +1,134 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import threading
|
import threading
|
||||||
from typing import List
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any, List, Tuple
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import on_regex, on_command
|
||||||
|
from nonebot.params import CommandArg, RegexGroup
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from .get_card import get_gs_card
|
from .get_card import get_gs_card
|
||||||
from .get_guide import get_gs_guide
|
from .get_guide import get_gs_guide
|
||||||
from ..version import Genshin_version
|
from ..version import Genshin_version
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
from .get_abyss_data import get_review, generate_data
|
from .get_abyss_data import get_review, generate_data
|
||||||
from ..utils.alias.alias_to_char_name import alias_to_char_name
|
from ..utils.alias.alias_to_char_name import alias_to_char_name
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_guide_pic = on_regex('([\u4e00-\u9fa5]+)(推荐|攻略)')
|
||||||
|
get_bluekun_pic = on_command('参考面板')
|
||||||
|
get_card = on_command('原牌')
|
||||||
|
get_abyss = on_command('版本深渊')
|
||||||
|
|
||||||
IMG_PATH = Path(__file__).parent / 'img'
|
IMG_PATH = Path(__file__).parent / 'img'
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex('([\u4e00-\u9fa5]+)(推荐|攻略)')
|
@get_guide_pic.handle()
|
||||||
async def send_guide_pic(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('建议')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
name = name = str(ev['match'].group(1))
|
'角色攻略',
|
||||||
else:
|
'xx攻略',
|
||||||
|
'发送一张对应角色的西风驿站攻略图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张对应角色的米游社西风驿站攻略图\n'
|
||||||
|
'支持部分角色别名\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(0,148,200)>[角色名]</ft>'
|
||||||
|
'<ft color=(238,120,0)>{推荐|攻略}</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>钟离推荐</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>公子攻略</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_guide_pic(
|
||||||
|
matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
|
||||||
|
):
|
||||||
|
if not args:
|
||||||
return
|
return
|
||||||
|
name = str(args[0])
|
||||||
if name == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
im = await get_gs_guide(name)
|
im = await get_gs_guide(name)
|
||||||
|
|
||||||
if im:
|
if im:
|
||||||
logger.info('获得{}攻略成功!'.format(name))
|
logger.info('获得{}攻略成功!'.format(name))
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
logger.warning('未找到{}攻略图片'.format(name))
|
logger.warning('未找到{}攻略图片'.format(name))
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('参考面板')
|
@get_bluekun_pic.handle()
|
||||||
async def send_bluekun_pic(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('参考面板')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'参考面板',
|
||||||
|
'参考面板[角色名/元素名]',
|
||||||
|
'发送一张对应角色/元素的参考面板图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'发送一张对应角色/元素的参考面板图\n'
|
||||||
|
'支持部分角色别名\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>参考面板</ft>'
|
||||||
|
'<ft color=(0,148,200)>[角色名/元素名]</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>参考面板火</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>参考面板公子</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_bluekun_pic(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
if str(args[0]) in ['冰', '水', '火', '草', '雷', '风', '岩']:
|
||||||
|
name = str(args[0])
|
||||||
else:
|
else:
|
||||||
return
|
name = await alias_to_char_name(str(args[0]))
|
||||||
|
|
||||||
if message == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
if str(message) in ['冰', '水', '火', '草', '雷', '风', '岩']:
|
|
||||||
name = str(message)
|
|
||||||
else:
|
|
||||||
name = await alias_to_char_name(str(message))
|
|
||||||
img = IMG_PATH / '{}.jpg'.format(name)
|
img = IMG_PATH / '{}.jpg'.format(name)
|
||||||
if img.exists():
|
if img.exists():
|
||||||
img = await convert_img(img)
|
with open(img, 'rb') as f:
|
||||||
|
im = MessageSegment.image(f.read())
|
||||||
logger.info('获得{}参考面板图片成功!'.format(name))
|
logger.info('获得{}参考面板图片成功!'.format(name))
|
||||||
await bot.send(ev, img)
|
await matcher.finish(im)
|
||||||
else:
|
else:
|
||||||
logger.warning('未找到{}参考面板图片'.format(name))
|
logger.warning('未找到{}参考面板图片'.format(name))
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('原牌')
|
@get_card.handle()
|
||||||
async def send_gscard_pic(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('原牌')
|
||||||
if ev.message:
|
async def send_gscard_pic(matcher: Matcher, args: Message = CommandArg()):
|
||||||
name = ev.message.extract_plain_text().replace(' ', '')
|
if not args:
|
||||||
else:
|
|
||||||
return
|
return
|
||||||
|
name = str(args[0])
|
||||||
if name == '':
|
|
||||||
return
|
|
||||||
|
|
||||||
im = await get_gs_card(name)
|
im = await get_gs_card(name)
|
||||||
|
|
||||||
if im:
|
if im:
|
||||||
logger.info('获得{}原牌成功!'.format(name))
|
logger.info('获得{}原牌成功!'.format(name))
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
logger.warning('未找到{}原牌图片'.format(name))
|
logger.warning('未找到{}原牌图片'.format(name))
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('版本深渊')
|
@get_abyss.handle()
|
||||||
async def send_abyss_review(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('版本深渊')
|
||||||
if ev.message:
|
async def send_abyss_review(
|
||||||
version = ev.message.extract_plain_text().replace(' ', '')
|
matcher: Matcher,
|
||||||
else:
|
args: Message = CommandArg(),
|
||||||
return
|
):
|
||||||
|
if not args:
|
||||||
if version == '':
|
|
||||||
version = Genshin_version[:-2]
|
version = Genshin_version[:-2]
|
||||||
|
|
||||||
im = await get_review(version)
|
|
||||||
|
|
||||||
if isinstance(im, List):
|
|
||||||
mes = []
|
|
||||||
for msg in im:
|
|
||||||
mes.append(
|
|
||||||
{
|
|
||||||
'type': 'node',
|
|
||||||
'data': {
|
|
||||||
'name': '小仙',
|
|
||||||
'uin': '3399214199',
|
|
||||||
'content': msg,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
await bot.send_group_forward_msg(group_id=ev.group_id, messages=mes)
|
|
||||||
elif isinstance(im, str):
|
|
||||||
await bot.send(ev, im)
|
|
||||||
elif isinstance(im, bytes):
|
|
||||||
im = await convert_img(im)
|
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
version = str(args[0])
|
||||||
|
im = await get_review(version)
|
||||||
|
if isinstance(im, List):
|
||||||
|
im = '\n'.join(im)
|
||||||
|
await matcher.finish(im)
|
||||||
|
elif isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
elif isinstance(im, bytes):
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
else:
|
||||||
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
|
@ -2,18 +2,37 @@ import asyncio
|
|||||||
import threading
|
import threading
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from ..base import sv, logger
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
|
||||||
from .draw_help_card import draw_help_img
|
from .draw_help_card import draw_help_img
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_help = on_command('gs帮助')
|
||||||
|
|
||||||
HELP_IMG = Path(__file__).parent / 'help.png'
|
HELP_IMG = Path(__file__).parent / 'help.png'
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('gs帮助', 'genshin帮助', 'ys帮助', '原神帮助'))
|
@get_help.handle()
|
||||||
async def send_guide_pic(bot, ev):
|
@handle_exception('建议')
|
||||||
img = await convert_img(HELP_IMG)
|
@register_menu(
|
||||||
|
'插件帮助',
|
||||||
|
'gs帮助',
|
||||||
|
'查看插件功能帮助图',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n' '查看插件功能帮助图\n' ' \n' '指令:\n' '- <ft color=(238,120,0)>gs帮助</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_guide_pic(matcher: Matcher):
|
||||||
logger.info('获得gs帮助图片成功!')
|
logger.info('获得gs帮助图片成功!')
|
||||||
await bot.send(ev, img)
|
if HELP_IMG.exists():
|
||||||
|
with open(HELP_IMG, 'rb') as f:
|
||||||
|
await matcher.finish(MessageSegment.image(f.read()))
|
||||||
|
else:
|
||||||
|
await matcher.finish('帮助图不存在!')
|
||||||
|
|
||||||
|
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
|
@ -1,8 +1,24 @@
|
|||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from typing import Any, Dict
|
||||||
|
|
||||||
from ..base import sv, logger
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import RegexDict
|
||||||
|
from nonebot import on_regex, on_command
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.adapters.ntchat import Bot, MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
|
from ..config import priority
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from .draw_genshinmap_card import MAP_DATA, draw_genshin_map
|
from .draw_genshinmap_card import MAP_DATA, draw_genshin_map
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
change_map = on_command('切换地图', block=True, rule=FullCommand())
|
||||||
|
find_map = on_regex(
|
||||||
|
r'^(?P<name>.*)(在哪里|在哪|哪里有|哪儿有|哪有|在哪儿)$', priority=priority
|
||||||
|
)
|
||||||
|
find_map2 = on_regex(r'^(哪里有|哪儿有|哪有)(?P<name>.*)$', priority=priority)
|
||||||
|
|
||||||
|
|
||||||
MAP_ID_LIST = [
|
MAP_ID_LIST = [
|
||||||
'2', # 提瓦特
|
'2', # 提瓦特
|
||||||
@ -18,13 +34,31 @@ MAP_CHN_NAME = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('切换地图')
|
@change_map.handle()
|
||||||
async def send_change_map_msg(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('切换地图')
|
||||||
if ev.sender:
|
@register_menu(
|
||||||
qid = int(ev.sender['user_id'])
|
'切换地图',
|
||||||
else:
|
'切换地图',
|
||||||
return
|
'切换查找资源点功能所使用的地图',
|
||||||
if qid not in bot.config.SUPERUSERS:
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'切换查找资源点功能所使用的地图\n'
|
||||||
|
'指令按列表顺序轮流切换地图\n'
|
||||||
|
'目前可用地图:'
|
||||||
|
+ ";".join(
|
||||||
|
[f"<ft color=(238,120,0)>{x}</ft>" for x in MAP_CHN_NAME.values()]
|
||||||
|
)
|
||||||
|
+ ' \n\n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>切换地图</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_change_map_msg(
|
||||||
|
bot: Bot,
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
logger.info('[切换地图]正在执行...')
|
logger.info('[切换地图]正在执行...')
|
||||||
MAP_ID_LIST.append(MAP_ID_LIST[0])
|
MAP_ID_LIST.append(MAP_ID_LIST[0])
|
||||||
@ -32,44 +66,66 @@ async def send_change_map_msg(bot: HoshinoBot, ev: CQEvent):
|
|||||||
current = MAP_ID_LIST[0]
|
current = MAP_ID_LIST[0]
|
||||||
chn = MAP_CHN_NAME.get(current)
|
chn = MAP_CHN_NAME.get(current)
|
||||||
logger.info(f'[切换地图]当前地图为{chn}')
|
logger.info(f'[切换地图]当前地图为{chn}')
|
||||||
await bot.send(ev, f'切换到{chn}地图')
|
await matcher.finish(f'切换到{chn}地图')
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'^(?P<name>.*)(在哪里|在哪|哪里有|哪儿有|哪有|在哪儿)$')
|
@find_map.handle()
|
||||||
@sv.on_rex(r'^(哪里有|哪儿有|哪有)(?P<name>.*)$')
|
@find_map2.handle()
|
||||||
async def send_find_map_msg(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('查找资源点')
|
||||||
|
@register_menu(
|
||||||
|
'查找资源点',
|
||||||
|
'xx在哪',
|
||||||
|
'查找指定资源在地图上的位置',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'在米游社大地图上查询某资源的位置\n'
|
||||||
|
'使用 <ft color=(238,120,0)>切换地图</ft> 指令来切换目标地图'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(0,148,200)>[资源名称]</ft>'
|
||||||
|
'<ft color=(238,120,0)>{在哪里|在哪|哪里有|哪儿有|哪有|在哪儿}</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>{哪里有|哪儿有|哪有}</ft>'
|
||||||
|
'<ft color=(0,148,200)>[资源名称]</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>甜甜花在哪</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>哪有清心</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_find_map_msg(
|
||||||
|
matcher: Matcher, args: Dict[str, Any] = RegexDict()
|
||||||
|
):
|
||||||
map_id = MAP_ID_LIST[0]
|
map_id = MAP_ID_LIST[0]
|
||||||
map_name = MAP_CHN_NAME[map_id]
|
map_name = MAP_CHN_NAME[map_id]
|
||||||
args = ev['match'].groupdict().get('name')
|
|
||||||
logger.info(f'[查找资源点]正在执行...当前地图为{map_name}')
|
logger.info(f'[查找资源点]正在执行...当前地图为{map_name}')
|
||||||
logger.info('[查找资源点]参数: {}'.format(args))
|
logger.info('[查找资源点]参数: {}'.format(args))
|
||||||
|
|
||||||
if not args:
|
if not (args and (name := args.get('name'))):
|
||||||
return
|
return
|
||||||
|
|
||||||
im = ''
|
|
||||||
|
|
||||||
if not MAP_DATA.exists():
|
if not MAP_DATA.exists():
|
||||||
MAP_DATA.mkdir()
|
MAP_DATA.mkdir()
|
||||||
|
|
||||||
resource_temp_path = MAP_DATA / f'{map_name}_{args}.jpg'
|
resource_temp_path = MAP_DATA / f'{map_name}_{name}.jpg'
|
||||||
if resource_temp_path.exists():
|
if resource_temp_path.exists():
|
||||||
logger.info(f'本地已有{map_name}_{args}的资源点,直接发送...')
|
logger.info(f'本地已有{map_name}_{name}的资源点,直接发送...')
|
||||||
resource_temp = await convert_img(resource_temp_path)
|
with open(resource_temp_path, 'rb') as f:
|
||||||
await bot.send(ev, resource_temp)
|
await matcher.finish(MessageSegment.image(f.read()))
|
||||||
else:
|
else:
|
||||||
# 放弃安慰剂回复
|
# 放弃安慰剂回复
|
||||||
'''
|
'''
|
||||||
await bot.send(
|
await matcher.send(
|
||||||
ev,
|
(
|
||||||
f'正在查找{args},可能需要比较久的时间...\n当前地图:{map_name}',
|
f'正在查找{name},可能需要比较久的时间...\n'
|
||||||
|
f'当前地图:{MAP_CHN_NAME.get(MAP_ID_LIST[0])}'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
'''
|
'''
|
||||||
logger.info('本地未缓存,正在渲染...')
|
logger.info('本地未缓存,正在渲染...')
|
||||||
im = await draw_genshin_map(args, map_id, map_name)
|
im = await draw_genshin_map(name, map_id, map_name)
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
return
|
await matcher.finish()
|
||||||
# await bot.send(ev, im)
|
elif isinstance(im, bytes):
|
||||||
elif isinstance(im, bytes):
|
await matcher.finish(MessageSegment.image(im))
|
||||||
im = await convert_img(im)
|
else:
|
||||||
await bot.send(ev, im)
|
await matcher.finish('查找失败!')
|
||||||
|
54
GenshinUID/genshinuid_meta/__init__.py
Normal file
54
GenshinUID/genshinuid_meta/__init__.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from nonebot.plugin import PluginMetadata
|
||||||
|
|
||||||
|
sub_menus = []
|
||||||
|
__plugin_meta__ = PluginMetadata(
|
||||||
|
name='GenshinUID',
|
||||||
|
description='基于NoneBot2的原神Uid查询/原神Wiki/米游社签到/树脂提醒插件',
|
||||||
|
usage=(
|
||||||
|
'发送 <ft color=(238,120,0)>gs帮助</ft> 可以获取帮助列表,也可以参考下面的表格\n'
|
||||||
|
'可以使用 <ft color=(238,120,0)>菜单 gsuid </ft>'
|
||||||
|
'<ft color=(0,148,200)>[序号]</ft> '
|
||||||
|
'指令获取某功能详细介绍\n'
|
||||||
|
' \n'
|
||||||
|
'菜单描述中的指令:\n'
|
||||||
|
'<ft color=(0,148,200)>[中括号及其中的内容]</ft>,'
|
||||||
|
'或<ft color=(0,148,200)>用“xx”代表的内容</ft> '
|
||||||
|
'为<ft color=(238,120,0)>必选</ft>的参数,'
|
||||||
|
'请将它们替换为适当的值;\n'
|
||||||
|
'<ft color=(125,125,125)>(小括号及其中的内容)</ft> '
|
||||||
|
'为<ft color=(238,120,0)>可选</ft>参数,'
|
||||||
|
'可以省略;\n'
|
||||||
|
'<ft color=(238,120,0)>{大括号及其中的内容}</ft> '
|
||||||
|
'为<ft color=(238,120,0)>选择其一</ft>参数,'
|
||||||
|
'请将它们替换为用 <ft color=(238,120,0)>|</ft> 分割后括号中内容的其中一个值'
|
||||||
|
),
|
||||||
|
extra={'menu_data': sub_menus, 'menu_template': 'default'},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def register_menu_func(
|
||||||
|
func: str,
|
||||||
|
trigger_condition: str,
|
||||||
|
brief_des: str,
|
||||||
|
trigger_method: str = '指令',
|
||||||
|
detail_des: Optional[str] = None,
|
||||||
|
):
|
||||||
|
sub_menus.append(
|
||||||
|
{
|
||||||
|
'func': func,
|
||||||
|
'trigger_method': trigger_method,
|
||||||
|
'trigger_condition': trigger_condition,
|
||||||
|
'brief_des': brief_des,
|
||||||
|
'detail_des': detail_des or brief_des,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def register_menu(*args, **kwargs):
|
||||||
|
def decorator(f):
|
||||||
|
register_menu_func(*args, **kwargs)
|
||||||
|
return f
|
||||||
|
|
||||||
|
return decorator
|
@ -1,35 +1,81 @@
|
|||||||
import random
|
import random
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from nonebot import get_bot
|
from nonebot.log import logger
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import get_bot, on_command
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat import Bot, MessageEvent, MessageSegment
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..config import SUPERUSERS, priority
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from ..utils.db_operation.db_operation import config_check
|
from ..utils.db_operation.db_operation import config_check
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from .daily_mihoyo_bbs_coin import mihoyo_coin, all_daily_mihoyo_bbs_coin
|
from .daily_mihoyo_bbs_coin import mihoyo_coin, all_daily_mihoyo_bbs_coin
|
||||||
|
|
||||||
|
bbscoin_scheduler = scheduler
|
||||||
|
|
||||||
|
get_mihoyo_coin = on_command('开始获取米游币', priority=priority, rule=FullCommand())
|
||||||
|
all_bbscoin_recheck = on_command(
|
||||||
|
'全部重获取', priority=priority, rule=FullCommand()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# 获取米游币
|
# 获取米游币
|
||||||
@sv.on_fullmatch('开始获取米游币')
|
@get_mihoyo_coin.handle()
|
||||||
async def send_mihoyo_coin(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('获取米游币')
|
||||||
await bot.send(ev, '开始操作……', at_sender=True)
|
@register_menu(
|
||||||
qid = int(ev.sender['user_id']) # type: ignore
|
'手动获取米游币',
|
||||||
|
'开始获取米游币',
|
||||||
|
'手动触发米游社米游币任务',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'手动触发米游社获取米游币的任务\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>开始获取米游币</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_mihoyo_coin(event: MessageEvent, matcher: Matcher):
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(event.from_wxid)
|
||||||
|
await matcher.send(
|
||||||
|
MessageSegment.room_at_msg(content='{$@}开始操作……', at_list=wxid_list)
|
||||||
|
)
|
||||||
|
qid = event.from_wxid
|
||||||
im = await mihoyo_coin(qid)
|
im = await mihoyo_coin(qid)
|
||||||
await bot.send(ev, im, at_sender=True)
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(content="{$@}" + f'{im}', at_list=wxid_list)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('全部重获取')
|
@all_bbscoin_recheck.handle()
|
||||||
async def bbs_recheck(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('米游币全部重获取')
|
||||||
qid = int(ev.sender['user_id']) # type: ignore
|
@register_menu(
|
||||||
if qid not in bot.config.SUPERUSERS:
|
'重新获取米游币',
|
||||||
|
'全部重获取',
|
||||||
|
'重新运行所有自动获取米游币的任务',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'重新运行所有自动获取米游币的任务\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>全部重获取</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def bbs_recheck(bot: Bot, event: MessageEvent, matcher: Matcher):
|
||||||
|
if await SUPERUSER(bot, event):
|
||||||
|
await matcher.send('已开始执行!可能需要较久时间!')
|
||||||
|
await send_daily_mihoyo_bbs_sign()
|
||||||
|
await matcher.finish('执行完成!')
|
||||||
|
else:
|
||||||
return
|
return
|
||||||
await bot.send(ev, '已开始执行!可能需要较久时间!')
|
|
||||||
await send_daily_mihoyo_bbs_sign()
|
|
||||||
await bot.send(ev, '执行完成!')
|
|
||||||
|
|
||||||
|
|
||||||
# 每日一点十六分进行米游币获取
|
# 每日一点十六分进行米游币获取
|
||||||
@sv.scheduled_job('cron', hour='1', minute='16')
|
@bbscoin_scheduler.scheduled_job('cron', hour='1', minute='16')
|
||||||
async def sign_at_night():
|
async def sign_at_night():
|
||||||
if await config_check('SchedMhyBBSCoin'):
|
if await config_check('SchedMhyBBSCoin'):
|
||||||
await send_daily_mihoyo_bbs_sign()
|
await send_daily_mihoyo_bbs_sign()
|
||||||
@ -40,12 +86,12 @@ async def send_daily_mihoyo_bbs_sign():
|
|||||||
im, im_private = await all_daily_mihoyo_bbs_coin()
|
im, im_private = await all_daily_mihoyo_bbs_coin()
|
||||||
if im_private:
|
if im_private:
|
||||||
for user_id in im_private:
|
for user_id in im_private:
|
||||||
await bot.send_private_msg(
|
await bot.call_api(
|
||||||
user_id=user_id, message=im_private[user_id]
|
'send_text', to_wxid=user_id, content=im_private[user_id]
|
||||||
)
|
)
|
||||||
await asyncio.sleep(5 + random.randint(1, 3))
|
await asyncio.sleep(5 + random.randint(1, 3))
|
||||||
if await config_check('PrivateReport'):
|
if await config_check('PrivateReport'):
|
||||||
for qid in bot.config.SUPERUSERS:
|
for qid in SUPERUSERS:
|
||||||
await bot.send_private_msg(user_id=qid, message=im)
|
await bot.call_api(api='send_text', to_wxid=qid, content=im)
|
||||||
await asyncio.sleep(5 + random.randint(1, 3))
|
await asyncio.sleep(5 + random.randint(1, 3))
|
||||||
logger.info('米游币获取已结束。')
|
logger.info('米游币获取已结束。')
|
||||||
|
@ -1,39 +1,105 @@
|
|||||||
import asyncio
|
from typing import Any, Tuple
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import RegexGroup
|
||||||
|
from nonebot import on_regex, on_command
|
||||||
|
from nonebot.adapters.ntchat import (
|
||||||
|
Bot,
|
||||||
|
MessageEvent,
|
||||||
|
MessageSegment,
|
||||||
|
TextMessageEvent,
|
||||||
|
)
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..config import priority
|
||||||
from .get_lots_data import get_lots_msg
|
from .get_lots_data import get_lots_msg
|
||||||
from .get_meme_card import get_meme_img
|
from .get_meme_card import get_meme_img
|
||||||
from .get_mys_data import get_region_task, get_task_detail
|
from .get_mys_data import get_task_detail
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
get_task_adv = on_regex(
|
||||||
|
r'^(原神任务|任务|任务详情|任务攻略)( )?([\u4e00-\u9fa5]+)( )?$', priority=priority
|
||||||
|
)
|
||||||
|
get_meme = on_command('抽表情', priority=priority, rule=FullCommand())
|
||||||
|
get_lots = on_command('御神签', priority=priority, rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'^(原神任务|任务|任务详情|任务攻略)( )?([\u4e00-\u9fa5]+)( )?$')
|
@get_task_adv.handle()
|
||||||
async def send_task_adv(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('任务攻略')
|
||||||
args = ev['match'].groups()
|
@register_menu(
|
||||||
|
'任务攻略',
|
||||||
|
'任务xx',
|
||||||
|
'查询某任务的攻略',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询指定任务或指定地区的攻略\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>{原神任务|任务|任务详情|任务攻略}</ft>'
|
||||||
|
'<ft color=(238,120,0)>{</ft>'
|
||||||
|
'<ft color=(0,148,200)>[任务名]</ft>'
|
||||||
|
'<ft color=(238,120,0)>|须弥|层岩|海岛}</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>任务神樱大祓</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>任务须弥</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_task_adv(
|
||||||
|
bot: Bot,
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Tuple[Any, ...] = RegexGroup(),
|
||||||
|
):
|
||||||
|
'''
|
||||||
if str(args[2]) in ['须弥', '层岩', '海岛']:
|
if str(args[2]) in ['须弥', '层岩', '海岛']:
|
||||||
im = await get_region_task(str(args[2]))
|
im = await get_region_task(str(args[2]))
|
||||||
for i in im:
|
for i in im:
|
||||||
await bot.send_group_forward_msg(group_id=ev.group_id, messages=i)
|
await bot.call_api(
|
||||||
|
'send_group_forward_msg', group_id=event.group_id, messages=i
|
||||||
|
)
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
return
|
await matcher.finish()
|
||||||
else:
|
else:
|
||||||
im = await get_task_detail(str(args[2]))
|
'''
|
||||||
await bot.send(ev, im)
|
im = await get_task_detail(str(args[2]))
|
||||||
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('抽表情')
|
@get_meme.handle()
|
||||||
async def send_meme_card(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('抽表情')
|
||||||
|
@register_menu(
|
||||||
|
'抽表情',
|
||||||
|
'抽表情',
|
||||||
|
'随机发送一张札记角色表情',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'随机发送一张札记角色表情\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>抽表情</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_meme_card(matcher: Matcher):
|
||||||
logger.info('开始执行[抽表情]')
|
logger.info('开始执行[抽表情]')
|
||||||
img = await get_meme_img()
|
img = await get_meme_img()
|
||||||
img = await convert_img(img)
|
await matcher.finish(MessageSegment.image(img))
|
||||||
await bot.send(ev, img)
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('御神签')
|
@get_lots.handle()
|
||||||
async def send_lots_data(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('御神签')
|
||||||
qid = int(ev.sender['user_id'])
|
@register_menu(
|
||||||
|
'御神签',
|
||||||
|
'御神签',
|
||||||
|
'鸣神大社御神签',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n' '抽一签鸣神大社御神签\n' ' \n' '指令:\n' '- <ft color=(238,120,0)>御神签</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_lots_data(matcher: Matcher, event: MessageEvent):
|
||||||
|
qid = event.from_wxid
|
||||||
logger.info('开始执行[御神签]')
|
logger.info('开始执行[御神签]')
|
||||||
im = await get_lots_msg(qid)
|
im = await get_lots_msg(qid)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
@ -1,48 +1,96 @@
|
|||||||
import re
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.adapters.ntchat import MessageEvent, MessageSegment
|
||||||
|
|
||||||
from .note_text import award
|
from .note_text import award
|
||||||
from ..base import sv, logger
|
from ..config import priority
|
||||||
from .draw_note_card import draw_note_img
|
from .draw_note_card import draw_note_img
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.message.error_reply import CK_HINT, UID_HINT
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
monthly_data = on_command('每月统计', priority=priority, rule=FullCommand())
|
||||||
|
get_genshin_info = on_command(
|
||||||
|
'当前信息', aliases={'zj', '札记', '原石札记'}, priority=priority, rule=FullCommand()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# 群聊内 每月统计 功能
|
# 群聊内 每月统计 功能
|
||||||
@sv.on_fullmatch('每月统计')
|
@monthly_data.handle()
|
||||||
async def send_monthly_data(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('每月统计', '获取/发送每月统计失败', '@未找到绑定信息\n' + CK_HINT)
|
||||||
qid = int(ev.sender['user_id']) # type: ignore
|
@register_menu(
|
||||||
|
'文字札记',
|
||||||
|
'每月统计',
|
||||||
|
'文字形式米游社札记',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n' '文字形式米游社札记\n' ' \n' '指令:\n' '- <ft color=(238,120,0)>每月统计</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_monthly_data(
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
qid = event.from_wxid
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(event.from_wxid)
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
if isinstance(uid, str):
|
if isinstance(uid, str):
|
||||||
if '未找到绑定的UID' in uid:
|
if '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(
|
||||||
|
content='{$@}' + UID_HINT, at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生未知错误...')
|
await matcher.finish('发生未知错误...')
|
||||||
im = await award(uid)
|
im = await award(uid)
|
||||||
await bot.send(ev, im, at_sender=True)
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(content="{$@}" + f'{im}', at_list=wxid_list)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('当前信息', 'zj', '原石札记', '札记'))
|
# 群聊内 每月统计 功能
|
||||||
async def send_monthly_pic(bot: HoshinoBot, ev: CQEvent):
|
@get_genshin_info.handle()
|
||||||
logger.info('开始执行[每日信息]')
|
@handle_exception('每月统计', '获取/发送每月统计失败', '@未找到绑定信息\n' + CK_HINT)
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
@register_menu(
|
||||||
if at:
|
'图片札记',
|
||||||
qid = int(at.group(1))
|
'当前信息',
|
||||||
else:
|
'图片形式米游社札记',
|
||||||
if ev.sender:
|
detail_des=(
|
||||||
qid = int(ev.sender['user_id'])
|
'介绍:\n'
|
||||||
else:
|
'图片形式米游社札记\n'
|
||||||
return
|
' \n'
|
||||||
logger.info('[每日信息]QQ号: {}'.format(qid))
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>当前信息</ft>\n'
|
||||||
|
'- <ft color=(125,125,125)>(原石)</ft><ft color=(238,120,0)>札记</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>zj</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_monthly_pic(
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
qid = event.from_wxid
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(event.from_wxid)
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
logger.info('[每日信息]UID: {}'.format(uid))
|
if isinstance(uid, str):
|
||||||
im = await draw_note_img(str(uid))
|
if '未找到绑定的UID' in uid:
|
||||||
if isinstance(im, str):
|
await matcher.finish(
|
||||||
await bot.send(ev, im)
|
MessageSegment.room_at_msg(
|
||||||
elif isinstance(im, bytes):
|
content='{$@}' + UID_HINT, at_list=wxid_list
|
||||||
im = await convert_img(im)
|
)
|
||||||
await bot.send(ev, im)
|
)
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生未知错误...')
|
||||||
|
logger.info(f'[原石札记] 开始绘制,UID: {uid}')
|
||||||
|
im = await draw_note_img(uid)
|
||||||
|
if isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
elif isinstance(im, bytes):
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
else:
|
||||||
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -1,118 +1,134 @@
|
|||||||
import re
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from nonebot import get_bot
|
from nonebot.log import logger
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import get_bot, on_command
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from .notice import get_notice_list
|
from .notice import get_notice_list
|
||||||
from .resin_text import get_resin_text
|
from .resin_text import get_resin_text
|
||||||
from .draw_resin_card import get_resin_img
|
from .draw_resin_card import get_resin_img
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
notice_scheduler = scheduler
|
||||||
|
get_resin_info = on_command(
|
||||||
|
'每日',
|
||||||
|
aliases={'mr', '状态', '实时便笺', '便笺', '便签'},
|
||||||
|
block=True,
|
||||||
|
rule=FullCommand(),
|
||||||
|
)
|
||||||
|
get_daily_info = on_command('当前状态', rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('当前状态')
|
@get_daily_info.handle()
|
||||||
async def send_daily_info(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('每日信息文字版')
|
||||||
|
@register_menu(
|
||||||
|
'文字实时便笺',
|
||||||
|
'当前信息',
|
||||||
|
'米游社实时便笺文字版',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'米游社实时便笺文字版\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>当前状态</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_daily_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
logger.info('开始执行[每日信息文字版]')
|
logger.info('开始执行[每日信息文字版]')
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
|
||||||
if ev.sender:
|
|
||||||
qid = ev.sender['user_id']
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
if at:
|
|
||||||
qid = at.group(1)
|
|
||||||
|
|
||||||
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
logger.info('[每日信息文字版]QQ号: {}'.format(qid))
|
logger.info('[每日信息文字版]QQ号: {}'.format(qid))
|
||||||
|
|
||||||
uid: str = await select_db(qid, mode='uid') # type: ignore
|
uid: str = await select_db(qid, mode='uid') # type: ignore
|
||||||
logger.info('[每日信息文字版]UID: {}'.format(uid))
|
logger.info('[每日信息文字版]UID: {}'.format(uid))
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
if not uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
im = await get_resin_text(uid)
|
im = await get_resin_text(uid)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.scheduled_job('cron', minute='*/30')
|
@notice_scheduler.scheduled_job('cron', minute='*/30')
|
||||||
async def notice_job():
|
async def notice_job():
|
||||||
bot = get_bot()
|
bot = get_bot()
|
||||||
result = await get_notice_list()
|
result = await get_notice_list()
|
||||||
logger.info('[推送检查]完成!等待消息推送中...')
|
logger.info('[推送检查]完成!等待消息推送中...')
|
||||||
# 执行私聊推送
|
# 执行私聊推送
|
||||||
bot_ids = bot._wsr_api_clients.keys()
|
|
||||||
for qid in result[0]:
|
for qid in result[0]:
|
||||||
send_success = False
|
try:
|
||||||
for sid in bot_ids:
|
await bot.call_api(
|
||||||
try:
|
api='send_private_msg',
|
||||||
await bot.send_private_msg(
|
user_id=qid,
|
||||||
self_id=sid,
|
message=result[0][qid],
|
||||||
user_id=qid,
|
)
|
||||||
message=result[0][qid],
|
except Exception:
|
||||||
)
|
|
||||||
send_success = True
|
|
||||||
break
|
|
||||||
except Exception:
|
|
||||||
logger.info(f'[推送检查(轮推)] BOT {sid} 没有 {qid} 好友,已跳过')
|
|
||||||
if not send_success:
|
|
||||||
logger.warning(f'[推送检查] QQ {qid} 私聊推送失败!')
|
logger.warning(f'[推送检查] QQ {qid} 私聊推送失败!')
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
logger.info('[推送检查] 私聊推送完成')
|
logger.info('[推送检查]私聊推送完成')
|
||||||
# 执行群聊推送
|
# 执行群聊推送
|
||||||
for group_id in result[1]:
|
for group_id in result[1]:
|
||||||
send_success = False
|
try:
|
||||||
for sid in bot_ids:
|
await bot.call_api(
|
||||||
try:
|
api='send_group_msg',
|
||||||
await bot.send_group_msg(
|
group_id=group_id,
|
||||||
self_id=sid,
|
message=result[1][group_id],
|
||||||
group_id=group_id,
|
)
|
||||||
message=result[1][group_id],
|
except Exception:
|
||||||
)
|
logger.warning(f'[推送检查] 群 {group_id} 群聊推送失败!')
|
||||||
send_success = True
|
|
||||||
break
|
|
||||||
except Exception:
|
|
||||||
logger.info(f'[推送检查(轮推)] BOT {sid} 没有 {group_id} 群,已跳过')
|
|
||||||
if not send_success:
|
|
||||||
logger.warning(f'[推送检查] 群 {group_id} 推送失败!')
|
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
logger.info('[推送检查] 群聊推送完成')
|
logger.info('[推送检查]群聊推送完成')
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('执行推送检查任务'))
|
@get_resin_info.handle()
|
||||||
async def manual_notice_job(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('每日信息')
|
||||||
if ev.sender:
|
@register_menu(
|
||||||
qid = int(ev.sender['user_id'])
|
'图片实时便笺',
|
||||||
else:
|
'每日',
|
||||||
return
|
'图片形式米游社实时便笺',
|
||||||
if qid not in bot.config.SUPERUSERS:
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
await notice_job()
|
'图片形式米游社实时便笺\n'
|
||||||
await bot.send(ev, '推送检查任务已执行')
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>每日</ft>\n'
|
||||||
@sv.on_fullmatch(('每日', 'mr', '实时便笺', '便笺', '便签'))
|
'- <ft color=(238,120,0)>mr</ft>\n'
|
||||||
async def send_daily_info_pic(bot: HoshinoBot, ev: CQEvent):
|
'- <ft color=(238,120,0)>状态</ft>\n'
|
||||||
|
'- <ft color=(125,125,125)>(实时)</ft><ft color=(238,120,0)>便笺</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>便签</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_uid_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
logger.info('开始执行[每日信息]')
|
logger.info('开始执行[每日信息]')
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
qid = event.from_wxid
|
||||||
|
if event.at_user_list:
|
||||||
if at:
|
for user in event.at_user_list:
|
||||||
qid = int(at.group(1))
|
user = user.strip()
|
||||||
else:
|
if user != "":
|
||||||
if ev.sender:
|
qid = user
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info('[每日信息]QQ号: {}'.format(qid))
|
logger.info('[每日信息]QQ号: {}'.format(qid))
|
||||||
|
|
||||||
im = await get_resin_img(qid)
|
im = await get_resin_img(qid) # type:ignore
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -1,25 +1,47 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.adapters.ntchat import Bot, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.download_resource.download_all_resource import (
|
from ..utils.download_resource.download_all_resource import (
|
||||||
download_all_resource,
|
download_all_resource,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
download_resource = on_command('下载全部资源', rule=FullCommand())
|
||||||
|
|
||||||
@sv.on_fullmatch('下载全部资源')
|
|
||||||
async def send_download_resource_msg(bot: HoshinoBot, ev: CQEvent):
|
@download_resource.handle()
|
||||||
if ev.sender:
|
@handle_exception('下载全部资源', '资源下载错误')
|
||||||
qid = ev.sender['user_id']
|
@register_menu(
|
||||||
else:
|
'下载全部资源',
|
||||||
|
'下载全部资源',
|
||||||
|
'手动下载插件运行所需的资源',
|
||||||
|
trigger_method='管理员指令',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'手动下载插件正常运行所需的资源(一般每次启动会自动检查并下载)\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>下载全部资源</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_download_resource_msg(
|
||||||
|
bot: Bot,
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
if qid not in bot.config.SUPERUSERS:
|
await matcher.send('正在开始下载~可能需要较久的时间!')
|
||||||
return
|
|
||||||
await bot.send(ev, '正在开始下载~可能需要较久的时间!')
|
|
||||||
im = await download_all_resource()
|
im = await download_all_resource()
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
async def startup():
|
async def startup():
|
||||||
|
@ -1,27 +1,112 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment, TextMessageEvent
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from .get_regtime import calc_reg_time
|
from .get_regtime import calc_reg_time
|
||||||
from .draw_roleinfo_card import draw_pic
|
from .draw_roleinfo_card import draw_pic
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from ..utils.message.error_reply import UID_HINT
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.mhy_api.convert_mysid_to_uid import convert_mysid
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
|
||||||
|
get_role_info = on_command('uid', aliases={'查询'})
|
||||||
|
get_reg_time = on_command(
|
||||||
|
'原神注册时间', aliases={'注册时间', '查询注册时间'}, rule=FullCommand()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix(('原神注册时间', '注册时间'))
|
@get_role_info.handle()
|
||||||
async def regtime(bot, ev):
|
@handle_exception('查询角色信息')
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
@register_menu(
|
||||||
|
'查询帐号信息',
|
||||||
if at:
|
'查询',
|
||||||
qid = int(at.group(1))
|
'帐号基础数据与角色信息总览',
|
||||||
else:
|
detail_des=(
|
||||||
if ev.sender:
|
'介绍:\n'
|
||||||
qid = int(ev.sender['user_id'])
|
'查询帐号探索度、声望、宝箱收集、角色总览等等基础数据\n'
|
||||||
else:
|
'未绑定CK时最多只能查询8个角色信息\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>{查询|uid}</ft>'
|
||||||
|
'<ft color=(125,125,125)>({@某人|[UID]})</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>mys</ft>'
|
||||||
|
'<ft color=(125,125,125)>({@某人|[米游社ID]})</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>直接发送九位数UID</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>查询</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>查询</ft><ft color=(0,123,67)>@无疑Wuyi</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>uid123456789</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>123456789</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_role_info(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
raw_mes = args.extract_plain_text().strip().replace(' ', '')
|
||||||
|
# 若@在文本中 先无视@后面内容 如果@前面有内容则无视并停止执行下方命令 避免与enka查询打架
|
||||||
|
if "@" in raw_mes:
|
||||||
|
name = ''.join(re.findall('^[\u4e00-\u9fa5]+', raw_mes.split("@")[0]))
|
||||||
|
if name:
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
name = ''.join(re.findall('^[\u4e00-\u9fa5]+', raw_mes))
|
||||||
|
if name:
|
||||||
|
return
|
||||||
|
|
||||||
|
qid = event.from_wxid
|
||||||
|
# 识别@的人 排除空
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
|
|
||||||
|
# 获取uid
|
||||||
|
uid = re.findall(r'\d+', raw_mes.split("@")[0])
|
||||||
|
if uid:
|
||||||
|
uid = uid[0]
|
||||||
|
else:
|
||||||
|
uid = await select_db(qid, mode='uid')
|
||||||
|
uid = str(uid)
|
||||||
|
|
||||||
|
logger.info('开始执行[查询角色信息]')
|
||||||
|
logger.info('[查询角色信息]参数: {}'.format(args))
|
||||||
|
logger.info('[查询角色信息]uid: {}'.format(uid))
|
||||||
|
|
||||||
|
if '未找到绑定的UID' in uid:
|
||||||
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
|
im = await draw_pic(uid)
|
||||||
|
|
||||||
|
if isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
elif isinstance(im, bytes):
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
else:
|
||||||
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
|
@get_reg_time.handle()
|
||||||
|
async def regtime(
|
||||||
|
event: TextMessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
qid = event.from_wxid
|
||||||
|
# 识别@的人 排除空
|
||||||
|
if event.at_user_list:
|
||||||
|
for user in event.at_user_list:
|
||||||
|
user = user.strip()
|
||||||
|
if user != "":
|
||||||
|
qid = user
|
||||||
|
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
uid = str(uid)
|
uid = str(uid)
|
||||||
@ -30,57 +115,11 @@ async def regtime(bot, ev):
|
|||||||
logger.info('[查询注册时间]uid: {}'.format(uid))
|
logger.info('[查询注册时间]uid: {}'.format(uid))
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
if '未找到绑定的UID' in uid:
|
||||||
await bot.send(ev, UID_HINT)
|
await matcher.finish(UID_HINT)
|
||||||
|
|
||||||
im = await calc_reg_time(uid)
|
im = await calc_reg_time(uid)
|
||||||
await bot.send(ev, im)
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_rex(r'^()?()?()?([1256][0-9]{8})()?()?$')
|
|
||||||
@sv.on_rex(
|
|
||||||
r'^(\[CQ:at,qq=[0-9]+\])?( )?'
|
|
||||||
r'(uid|查询|mys)([0-9]+)?'
|
|
||||||
r'(\[CQ:at,qq=[0-9]+\])?( )?$',
|
|
||||||
)
|
|
||||||
async def send_role_info(bot: HoshinoBot, ev: CQEvent):
|
|
||||||
args = ev['match'].groups()
|
|
||||||
at = re.search(r'\[CQ:at,qq=(\d*)]', str(ev.message))
|
|
||||||
|
|
||||||
if at:
|
|
||||||
qid = int(at.group(1))
|
|
||||||
else:
|
|
||||||
if ev.sender:
|
|
||||||
qid = int(ev.sender['user_id'])
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
# 判断uid
|
|
||||||
if args[2] != 'mys':
|
|
||||||
if args[3] is None:
|
|
||||||
if args[2] is None:
|
|
||||||
return
|
|
||||||
uid = await select_db(qid, mode='uid')
|
|
||||||
uid = str(uid)
|
|
||||||
elif len(args[3]) != 9:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
uid = args[3]
|
|
||||||
else:
|
|
||||||
uid = await convert_mysid(args[3])
|
|
||||||
|
|
||||||
logger.info('开始执行[查询角色信息]')
|
|
||||||
logger.info('[查询角色信息]参数: {}'.format(args))
|
|
||||||
logger.info('[查询角色信息]uid: {}'.format(uid))
|
|
||||||
|
|
||||||
if '未找到绑定的UID' in uid:
|
|
||||||
await bot.send(ev, UID_HINT)
|
|
||||||
|
|
||||||
im = await draw_pic(uid)
|
|
||||||
|
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
|
||||||
im = await convert_img(im)
|
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -1,51 +1,91 @@
|
|||||||
import random
|
import random
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import get_bot, on_command
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat import Bot, MessageEvent, MessageSegment
|
||||||
|
|
||||||
|
from ..config import priority
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from sign import sign_in, daily_sign
|
from sign import sign_in, daily_sign
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from .sign import sign_in, daily_sign
|
from .sign import sign_in, daily_sign
|
||||||
|
|
||||||
import asyncio
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from nonebot import get_bot
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
|
||||||
|
|
||||||
from ..base import sv, logger
|
|
||||||
from ..utils.db_operation.db_operation import select_db, config_check
|
from ..utils.db_operation.db_operation import select_db, config_check
|
||||||
|
|
||||||
|
sign_scheduler = scheduler
|
||||||
|
|
||||||
|
get_sign = on_command('签到', priority=priority, rule=FullCommand())
|
||||||
|
all_recheck = on_command('全部重签', priority=priority, rule=FullCommand())
|
||||||
|
|
||||||
|
|
||||||
# 每日零点半执行米游社原神签到
|
# 每日零点半执行米游社原神签到
|
||||||
@sv.scheduled_job('cron', hour='0', minute='30')
|
@sign_scheduler.scheduled_job('cron', hour='0', minute='30')
|
||||||
async def sign_at_night():
|
async def sign_at_night():
|
||||||
if await config_check('SchedSignin'):
|
if await config_check('SchedSignin'):
|
||||||
await send_daily_sign()
|
await send_daily_sign()
|
||||||
|
|
||||||
|
|
||||||
# 群聊内 签到 功能
|
# 群聊内 签到 功能
|
||||||
@sv.on_rex(r'^(gs|米游社)(签到)$')
|
@get_sign.handle()
|
||||||
async def get_sign_func(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('签到')
|
||||||
|
@register_menu(
|
||||||
|
'手动米游社原神签到',
|
||||||
|
'签到',
|
||||||
|
'手动触发米游社原神签到任务',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'手动触发米游社原神签到任务\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>签到</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def get_sign_func(
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
logger.info('开始执行[签到]')
|
logger.info('开始执行[签到]')
|
||||||
qid = int(ev.sender['user_id']) # type: ignore
|
qid = event.from_wxid
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(event.from_wxid)
|
||||||
logger.info('[签到]QQ号: {}'.format(qid))
|
logger.info('[签到]QQ号: {}'.format(qid))
|
||||||
uid = await select_db(qid, mode='uid')
|
uid = await select_db(qid, mode='uid')
|
||||||
logger.info('[签到]UID: {}'.format(uid))
|
logger.info('[签到]UID: {}'.format(uid))
|
||||||
im = await sign_in(uid)
|
im = await sign_in(uid)
|
||||||
await bot.send(ev, im, at_sender=True)
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(content="{$@}" + f'{im}', at_list=wxid_list)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('全部重签')
|
@all_recheck.handle()
|
||||||
async def recheck(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('全部重签')
|
||||||
if ev.sender:
|
@register_menu(
|
||||||
qid = int(ev.sender['user_id'])
|
'米游社原神重签到',
|
||||||
else:
|
'全部重签',
|
||||||
|
'重新运行所有自动米游社原神签到任务',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'重新运行所有自动米游社原神签到任务\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>全部重签</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def recheck(bot: Bot, event: MessageEvent, matcher: Matcher):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
if qid not in bot.config.SUPERUSERS:
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.info('开始执行[全部重签]')
|
logger.info('开始执行[全部重签]')
|
||||||
await bot.send(ev, '已开始执行')
|
await matcher.send('已开始执行')
|
||||||
await send_daily_sign()
|
await send_daily_sign()
|
||||||
await bot.send(ev, '执行完成')
|
await matcher.finish('执行完成')
|
||||||
|
|
||||||
|
|
||||||
async def send_daily_sign():
|
async def send_daily_sign():
|
||||||
@ -60,9 +100,10 @@ async def send_daily_sign():
|
|||||||
# 执行私聊推送
|
# 执行私聊推送
|
||||||
for qid in private_msg_list:
|
for qid in private_msg_list:
|
||||||
try:
|
try:
|
||||||
await bot.send_private_msg(
|
await bot.call_api(
|
||||||
user_id=qid,
|
api='send_text',
|
||||||
message=private_msg_list[qid],
|
to_wxid=qid,
|
||||||
|
content=private_msg_list[qid],
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(f'[每日全部签到] QQ {qid} 私聊推送失败!')
|
logger.warning(f'[每日全部签到] QQ {qid} 私聊推送失败!')
|
||||||
@ -84,12 +125,16 @@ async def send_daily_sign():
|
|||||||
report,
|
report,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
msg_title = group_msg_list[gid]['push_message']
|
msg_title = group_msg_list[gid]['push_message'].rstrip()
|
||||||
# 发送群消息
|
# 发送群消息
|
||||||
|
at_wxid = []
|
||||||
|
at_wxid.append(group_msg_list[gid]['wxid'])
|
||||||
try:
|
try:
|
||||||
await bot.send_group_msg(
|
await bot.call_api(
|
||||||
group_id=gid,
|
api='send_room_at_msg',
|
||||||
message=msg_title,
|
to_wxid=gid,
|
||||||
|
at_list=at_wxid,
|
||||||
|
content=msg_title,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(f'[每日全部签到]群 {gid} 推送失败!')
|
logger.warning(f'[每日全部签到]群 {gid} 推送失败!')
|
||||||
|
@ -139,16 +139,18 @@ async def single_daily_sign(uid: str, gid: str, qid: str):
|
|||||||
# 如果失败, 则添加到推送列表
|
# 如果失败, 则添加到推送列表
|
||||||
if im.startswith('签到失败') or im.startswith('网络有点忙'):
|
if im.startswith('签到失败') or im.startswith('网络有点忙'):
|
||||||
# 不用MessageSegment.at(row[2]),因为不方便移植
|
# 不用MessageSegment.at(row[2]),因为不方便移植
|
||||||
message = f'[CQ:at,qq={qid}] {im}'
|
message = f'UID:{uid} | {im}'
|
||||||
group_msg_list[gid]['failed'] += 1
|
group_msg_list[gid]['failed'] += 1
|
||||||
group_msg_list[gid]['push_message'] += '\n' + message
|
group_msg_list[gid]['push_message'] += message + '\n'
|
||||||
else:
|
else:
|
||||||
group_msg_list[gid]['success'] += 1
|
group_msg_list[gid]['success'] += 1
|
||||||
# 没有开启简洁签到, 则每条消息都要携带@信息
|
# 没有开启简洁签到, 则每条消息都要携带@信息
|
||||||
else:
|
else:
|
||||||
# 不用MessageSegment.at(row[2]),因为不方便移植
|
# 不用MessageSegment.at(row[2]),因为不方便移植
|
||||||
message = f'[CQ:at,qq={qid}] {im}'
|
# message = '{$@}' + f'UID:{uid} | {im}'
|
||||||
group_msg_list[gid]['push_message'] += '\n' + message
|
message = f'UID:{uid} | {im}'
|
||||||
|
group_msg_list[gid]['wxid'] = qid
|
||||||
|
group_msg_list[gid]['push_message'] += message + '\n'
|
||||||
group_msg_list[gid]['success'] -= 1
|
group_msg_list[gid]['success'] -= 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,78 +1,131 @@
|
|||||||
from nonebot import get_bot, on_startup
|
from typing import Any, Tuple
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
|
||||||
|
|
||||||
from ..base import sv, logger
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import RegexGroup
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot import get_bot, on_regex, get_driver, on_command
|
||||||
|
from nonebot.adapters.ntchat import Bot, MessageEvent, MessageSegment
|
||||||
|
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
from .draw_update_log import draw_update_log_img
|
from .draw_update_log import draw_update_log_img
|
||||||
from .restart import restart_message, restart_genshinuid
|
from .restart import restart_message, restart_genshinuid
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
|
||||||
|
gs_restart = on_command('gs重启', rule=FullCommand())
|
||||||
|
get_update_log = on_command('更新记录', rule=FullCommand())
|
||||||
|
gs_update = on_regex(
|
||||||
|
r'^(gs)(强行)?(强制)?(更新)$',
|
||||||
|
block=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@on_startup
|
driver = get_driver()
|
||||||
async def check_msg():
|
|
||||||
try:
|
|
||||||
logger.info('检查遗留信息...')
|
|
||||||
update_log = await restart_message()
|
|
||||||
if update_log == {}:
|
|
||||||
return
|
|
||||||
bot = get_bot()
|
|
||||||
if update_log['send_type'] == 'group':
|
|
||||||
await bot.send_group_msg(
|
|
||||||
group_id=update_log['send_to'],
|
|
||||||
message=update_log['msg'],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await bot.send_private_msg(
|
|
||||||
user_id=update_log['send_to'],
|
|
||||||
message=update_log['msg'],
|
|
||||||
)
|
|
||||||
logger.info('遗留信息检查完毕!')
|
|
||||||
except Exception:
|
|
||||||
logger.warning('遗留信息检查失败!')
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('gs重启')
|
@driver.on_bot_connect
|
||||||
async def send_restart_msg(bot: HoshinoBot, ev: CQEvent):
|
async def _():
|
||||||
if ev.sender:
|
logger.info('检查遗留信息...')
|
||||||
qid = int(ev.sender['user_id'])
|
bot = get_bot()
|
||||||
else:
|
update_log = await restart_message()
|
||||||
|
if update_log == {}:
|
||||||
return
|
return
|
||||||
if qid not in bot.config.SUPERUSERS:
|
if update_log['send_type'] == 'group':
|
||||||
|
await bot.call_api(
|
||||||
|
api='send_room_at_msg',
|
||||||
|
to_wxid=update_log['send_to'],
|
||||||
|
content=update_log['msg'],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await bot.call_api(
|
||||||
|
api='send_text',
|
||||||
|
to_wxid=update_log['send_to'],
|
||||||
|
content=update_log['msg'],
|
||||||
|
)
|
||||||
|
logger.info('遗留信息检查完毕!')
|
||||||
|
|
||||||
|
|
||||||
|
@get_update_log.handle()
|
||||||
|
@register_menu(
|
||||||
|
'更新记录',
|
||||||
|
'更新记录',
|
||||||
|
'查看插件最近的更新记录',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查看插件最近的有效Git更新记录\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>更新记录</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_updatelog_msg(
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
im = await draw_update_log_img(is_update=False)
|
||||||
|
logger.info('正在执行[更新记录]...')
|
||||||
|
if isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
elif isinstance(im, bytes):
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
else:
|
||||||
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
|
||||||
|
|
||||||
|
@gs_restart.handle()
|
||||||
|
@register_menu(
|
||||||
|
'重启Bot',
|
||||||
|
'gs重启',
|
||||||
|
'重启Bot框架',
|
||||||
|
trigger_method='超级用户指令',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n' '重启Bot框架\n' ' \n' '指令:\n' '- <ft color=(238,120,0)>gs重启</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_restart_msg(
|
||||||
|
bot: Bot,
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
logger.warning('开始执行[重启]')
|
logger.warning('开始执行[重启]')
|
||||||
|
qid = event.from_wxid
|
||||||
if ev.group_id:
|
if len(event.get_session_id().split('_')) == 3:
|
||||||
send_id = str(ev.group_id)
|
send_id = event.get_session_id().split('_')[1]
|
||||||
send_type = 'group'
|
send_type = 'group'
|
||||||
else:
|
else:
|
||||||
send_id = qid
|
send_id = qid
|
||||||
send_type = 'private'
|
send_type = 'private'
|
||||||
await bot.send(ev, '正在执行[gs重启]...')
|
await matcher.send('正在执行[gs重启]...')
|
||||||
await restart_genshinuid(send_type, str(send_id))
|
await restart_genshinuid(send_type, str(send_id))
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch('更新记录')
|
@gs_update.handle()
|
||||||
async def send_updatelog_msg(bot: HoshinoBot, ev: CQEvent):
|
@register_menu(
|
||||||
im = await draw_update_log_img(is_update=False)
|
'更新插件',
|
||||||
logger.info('正在执行[更新记录]...')
|
'gs更新',
|
||||||
if isinstance(im, str):
|
'手动更新插件',
|
||||||
await bot.send(ev, im)
|
detail_des=(
|
||||||
elif isinstance(im, bytes):
|
'介绍:\n'
|
||||||
im = await convert_img(im)
|
'手动更新插件(执行 git pull)\n'
|
||||||
await bot.send(ev, im)
|
'每加上一个可选参数,执行等级加1\n'
|
||||||
else:
|
'当执行等级≥1时会还原上次更改,等级≥2时会清空暂存\n'
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>gs</ft>'
|
||||||
@sv.on_rex(r'^(gs)(强行)?(强制)?(更新)$')
|
'<ft color=(125,125,125)>(强行)(强制)</ft>'
|
||||||
async def send_update_msg(bot: HoshinoBot, ev: CQEvent):
|
'<ft color=(238,120,0)>更新</ft>'
|
||||||
if ev.sender:
|
),
|
||||||
qid = int(ev.sender['user_id'])
|
)
|
||||||
else:
|
async def send_update_msg(
|
||||||
return
|
bot: Bot,
|
||||||
if qid not in bot.config.SUPERUSERS:
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Tuple[Any, ...] = RegexGroup(),
|
||||||
|
):
|
||||||
|
if not await SUPERUSER(bot, event):
|
||||||
return
|
return
|
||||||
|
|
||||||
args = ev['match'].groups()
|
|
||||||
logger.info('[gs更新] 正在执行 ...')
|
logger.info('[gs更新] 正在执行 ...')
|
||||||
level = 2
|
level = 2
|
||||||
if args[1] is None:
|
if args[1] is None:
|
||||||
@ -80,12 +133,11 @@ async def send_update_msg(bot: HoshinoBot, ev: CQEvent):
|
|||||||
if args[2] is None:
|
if args[2] is None:
|
||||||
level -= 1
|
level -= 1
|
||||||
logger.info(f'[gs更新] 更新等级为{level}')
|
logger.info(f'[gs更新] 更新等级为{level}')
|
||||||
await bot.send(ev, f'开始执行[gs更新], 执行等级为{level}')
|
await matcher.send(f'开始执行[gs更新], 执行等级为{level}')
|
||||||
im = await draw_update_log_img(level)
|
im = await draw_update_log_img(level)
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
elif isinstance(im, bytes):
|
elif isinstance(im, bytes):
|
||||||
im = await convert_img(im)
|
await matcher.finish(MessageSegment.image(im))
|
||||||
await bot.send(ev, im)
|
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, '发生了未知错误,请联系管理员检查后台输出!')
|
await matcher.finish('发生了未知错误,请联系管理员检查后台输出!')
|
||||||
|
@ -8,7 +8,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
from ..utils.db_operation.db_operation import config_check
|
from ..utils.db_operation.db_operation import config_check
|
||||||
|
|
||||||
bot_start = Path().cwd() / 'run.py'
|
bot_start = Path().cwd() / 'bot.py'
|
||||||
restart_sh_path = Path().cwd() / 'gs_restart.sh'
|
restart_sh_path = Path().cwd() / 'gs_restart.sh'
|
||||||
update_log_path = Path(__file__).parent / 'update_log.json'
|
update_log_path = Path(__file__).parent / 'update_log.json'
|
||||||
|
|
||||||
@ -23,17 +23,17 @@ async def get_restart_sh(extra: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
async def restart_genshinuid(send_type: str, send_id: str) -> None:
|
async def restart_genshinuid(send_type: str, send_id: str) -> None:
|
||||||
pid = os.getpid()
|
|
||||||
extra = ''
|
extra = ''
|
||||||
if await config_check('UsePoetry'):
|
if await config_check('UsePoetry'):
|
||||||
extra = 'poetry run '
|
extra = 'poetry run '
|
||||||
extra += sys.executable
|
extra += sys.executable
|
||||||
restart_sh = await get_restart_sh(extra)
|
restart_sh = await get_restart_sh(extra)
|
||||||
with open(restart_sh_path, "w", encoding="utf8") as f:
|
if not restart_sh_path.exists():
|
||||||
f.write(restart_sh)
|
with open(restart_sh_path, "w", encoding="utf8") as f:
|
||||||
if platform.system() == 'Linux':
|
f.write(restart_sh)
|
||||||
os.system(f'chmod +x {str(restart_sh_path)}')
|
if platform.system() == 'Linux':
|
||||||
os.system(f'chmod +x {str(bot_start)}')
|
os.system(f'chmod +x {str(restart_sh_path)}')
|
||||||
|
os.system(f'chmod +x {str(bot_start)}')
|
||||||
now_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
|
now_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
|
||||||
update_log = {
|
update_log = {
|
||||||
'type': 'restart',
|
'type': 'restart',
|
||||||
@ -45,11 +45,9 @@ async def restart_genshinuid(send_type: str, send_id: str) -> None:
|
|||||||
with open(str(update_log_path), 'w', encoding='utf-8') as f:
|
with open(str(update_log_path), 'w', encoding='utf-8') as f:
|
||||||
json.dump(update_log, f)
|
json.dump(update_log, f)
|
||||||
if platform.system() == 'Linux':
|
if platform.system() == 'Linux':
|
||||||
subprocess.Popen(
|
os.execl(str(restart_sh_path), ' ')
|
||||||
f'kill -9 {pid} & {extra} {bot_start}',
|
|
||||||
shell=True,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
|
pid = os.getpid()
|
||||||
subprocess.Popen(
|
subprocess.Popen(
|
||||||
f'taskkill /F /PID {pid} & {extra} {bot_start}',
|
f'taskkill /F /PID {pid} & {extra} {bot_start}',
|
||||||
shell=True,
|
shell=True,
|
||||||
|
@ -1,103 +1,258 @@
|
|||||||
import hoshino
|
import asyncio
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from typing import Any, Tuple
|
||||||
|
|
||||||
from .topup import topup_
|
from nonebot.log import logger
|
||||||
from ..base import sv, logger
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot import on_regex, on_command
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot.params import CommandArg, RegexGroup
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
from nonebot.adapters.ntchat.permission import PRIVATE
|
||||||
|
from nonebot.adapters.ntchat import (
|
||||||
|
Bot,
|
||||||
|
MessageEvent,
|
||||||
|
MessageSegment,
|
||||||
|
TextMessageEvent,
|
||||||
|
)
|
||||||
|
|
||||||
|
from ..config import priority
|
||||||
|
from .topup import GOODS, topup_
|
||||||
from .qrlogin import qrcode_login
|
from .qrlogin import qrcode_login
|
||||||
from .get_ck_help_msg import get_ck_help
|
|
||||||
from .draw_user_card import get_user_card
|
from .draw_user_card import get_user_card
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.nonebot2.rule import FullCommand
|
||||||
|
from .get_ck_help_msg import get_ck_help, get_qr_help
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from .add_ck import deal_ck, get_ck_by_stoken, get_ck_by_all_stoken
|
from .add_ck import deal_ck, get_ck_by_stoken, get_ck_by_all_stoken
|
||||||
from ..utils.db_operation.db_operation import bind_db, delete_db, switch_db
|
from ..utils.db_operation.db_operation import bind_db, delete_db, switch_db
|
||||||
|
|
||||||
hoshino_bot = hoshino.get_bot()
|
add_cookie = on_command('添加', permission=PRIVATE)
|
||||||
|
get_ck_msg = on_command(
|
||||||
|
'绑定ck说明',
|
||||||
|
aliases={'ck帮助', '绑定ck'},
|
||||||
|
block=True,
|
||||||
|
rule=FullCommand(),
|
||||||
|
)
|
||||||
|
get_qr_msg = on_command(
|
||||||
|
'扫码登录说明',
|
||||||
|
aliases={'扫码帮助', '登录帮助', '登陆帮助'},
|
||||||
|
block=True,
|
||||||
|
rule=FullCommand(),
|
||||||
|
)
|
||||||
|
bind_info = on_command(
|
||||||
|
'绑定信息', priority=priority, block=True, rule=FullCommand()
|
||||||
|
)
|
||||||
|
refresh_ck = on_command(
|
||||||
|
'刷新CK',
|
||||||
|
aliases={'刷新ck', '刷新Ck', '刷新Cookies'},
|
||||||
|
priority=priority,
|
||||||
|
block=True,
|
||||||
|
rule=FullCommand(),
|
||||||
|
)
|
||||||
|
refresh_all_ck = on_command(
|
||||||
|
'刷新全部CK',
|
||||||
|
aliases={'刷新全部ck', '刷新全部Ck', '刷新全部Cookies'},
|
||||||
|
priority=priority,
|
||||||
|
block=True,
|
||||||
|
rule=FullCommand(),
|
||||||
|
permission=SUPERUSER,
|
||||||
|
)
|
||||||
|
bind = on_regex(
|
||||||
|
r'^(绑定|切换|解绑|删除)(uid|UID|mys|MYS)([0-9]+)?$', priority=priority
|
||||||
|
)
|
||||||
|
get_qrcode_login = on_command(
|
||||||
|
'扫码登录',
|
||||||
|
aliases={'扫码登陆', '扫码登入'},
|
||||||
|
rule=FullCommand(),
|
||||||
|
)
|
||||||
|
get_topup = on_command(
|
||||||
|
'gsrc', priority=priority, block=True, aliases={'原神充值', 'pay'}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('刷新全部CK', '刷新全部ck', '刷新全部Ck', '刷新全部Cookies'))
|
@get_topup.handle()
|
||||||
async def send_refresh_allck_msg(bot: HoshinoBot, ev: CQEvent):
|
async def send_topup(
|
||||||
if ev.sender:
|
matcher: Matcher, event: TextMessageEvent, args: Message = CommandArg()
|
||||||
qid = int(ev.sender['user_id'])
|
):
|
||||||
else:
|
# 获取被@的Wxid,排除""
|
||||||
return
|
qid = event.from_wxid
|
||||||
if qid not in bot.config.SUPERUSERS:
|
if event.at_user_list:
|
||||||
return
|
for user in event.at_user_list:
|
||||||
logger.info('开始执行[刷新全部ck]')
|
user = user.strip()
|
||||||
im = await get_ck_by_all_stoken()
|
if user != "":
|
||||||
if isinstance(im, bytes):
|
qid = user
|
||||||
im = await convert_img(im)
|
|
||||||
await bot.send(ev, im)
|
|
||||||
|
|
||||||
|
goods_id, method = 0, "alipay"
|
||||||
@sv.on_fullmatch(('刷新CK', '刷新ck', '刷新Ck', '刷新Cookies'))
|
for s in str(args).split():
|
||||||
async def send_refresh_ck_msg(bot: HoshinoBot, ev: CQEvent):
|
# 支持指定支付方式
|
||||||
logger.info('开始执行[刷新ck]')
|
if "微信" in s or "wx" in s:
|
||||||
if ev.sender:
|
method = "weixin"
|
||||||
qid = ev.sender['user_id']
|
continue
|
||||||
else:
|
if "支付宝" in s or "zfb" in s:
|
||||||
return
|
method = "alipay"
|
||||||
im = await get_ck_by_stoken(qid)
|
# 输入物品别名识别
|
||||||
if isinstance(im, bytes):
|
for gId, gData in GOODS.items():
|
||||||
im = await convert_img(im)
|
if (s == gId) or (s in gData["aliases"]):
|
||||||
await bot.send(ev, im)
|
goods_id = gId
|
||||||
|
break
|
||||||
|
group_id = event.room_wxid
|
||||||
@sv.on_fullmatch('绑定信息')
|
await matcher.finish(
|
||||||
async def send_bind_card(bot: HoshinoBot, ev: CQEvent):
|
await topup_(matcher, qid, group_id, goods_id, method)
|
||||||
logger.info('开始执行[查询用户绑定状态]')
|
|
||||||
if ev.sender:
|
|
||||||
qid = ev.sender['user_id']
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
im = await get_user_card(qid)
|
|
||||||
im = await convert_img(im)
|
|
||||||
logger.info('[查询用户绑定状态]完成!等待图片发送中...')
|
|
||||||
await bot.send(ev, im)
|
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('扫码登陆', '扫码登录', '扫码登入'))
|
|
||||||
async def send_qr_card(bot: HoshinoBot, ev: CQEvent):
|
|
||||||
im = await qrcode_login(hoshino_bot, ev.group_id, ev.user_id)
|
|
||||||
if not im:
|
|
||||||
return
|
|
||||||
im = await deal_ck(im, ev.user_id) # type: ignore
|
|
||||||
if isinstance(im, bytes):
|
|
||||||
im = await convert_img(im)
|
|
||||||
await bot.send(ev, im)
|
|
||||||
|
|
||||||
|
|
||||||
@hoshino_bot.on_message('private') # type: ignore
|
|
||||||
async def send_add_ck_msg(ctx):
|
|
||||||
message = ctx['raw_message']
|
|
||||||
sid = int(ctx['self_id'])
|
|
||||||
userid = int(ctx['sender']['user_id'])
|
|
||||||
gid = 0
|
|
||||||
if message.startswith('添加'):
|
|
||||||
message = message.replace('添加', '').replace(' ', '')
|
|
||||||
im = await deal_ck(message, userid) # type: ignore
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
if isinstance(im, bytes):
|
|
||||||
im = await convert_img(im)
|
|
||||||
await hoshino_bot.send_msg(
|
|
||||||
self_id=sid, user_id=userid, group_id=gid, message=im
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# 群聊内 绑定uid或者mysid 的命令,会绑定至当前qq号上
|
@refresh_all_ck.handle()
|
||||||
@sv.on_rex(r'^(绑定|切换|解绑|删除)(uid|UID|mys|MYS)([0-9]+)?$')
|
async def send_refresh_all_ck_msg(
|
||||||
async def send_link_uid_msg(bot: HoshinoBot, ev: CQEvent):
|
matcher: Matcher,
|
||||||
args = ev['match'].groups()
|
):
|
||||||
logger.info('开始执行[绑定/解绑用户信息]')
|
logger.info('开始执行[刷新全部CK]')
|
||||||
logger.info('[绑定/解绑]参数: {}'.format(str(args)))
|
im = await get_ck_by_all_stoken()
|
||||||
if ev.sender:
|
if isinstance(im, str):
|
||||||
qid = ev.sender['user_id']
|
await matcher.finish(im)
|
||||||
else:
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
|
||||||
|
|
||||||
|
@refresh_ck.handle()
|
||||||
|
async def send_refresh_ck_msg(
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
logger.info('开始执行[刷新CK]')
|
||||||
|
qid = event.from_wxid
|
||||||
|
im = await get_ck_by_stoken(qid)
|
||||||
|
if isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
|
||||||
|
|
||||||
|
@get_qrcode_login.handle()
|
||||||
|
async def send_qrcode_login(
|
||||||
|
bot: Bot,
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
logger.info('开始执行[扫码登陆]')
|
||||||
|
qid = event.from_wxid
|
||||||
|
im = await qrcode_login(matcher, qid)
|
||||||
|
if not im:
|
||||||
return
|
return
|
||||||
|
im = await deal_ck(im, qid)
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
|
||||||
|
|
||||||
|
@bind_info.handle()
|
||||||
|
@register_menu(
|
||||||
|
'绑定状态',
|
||||||
|
'绑定信息',
|
||||||
|
'查询你绑定UID的绑定和推送状态',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询你绑定的UID列表以及它们的CK、SK绑定状态和推送设置\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>绑定信息</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_bind_card(
|
||||||
|
event: MessageEvent,
|
||||||
|
matcher: Matcher,
|
||||||
|
):
|
||||||
|
logger.info('开始执行[查询用户绑定状态]')
|
||||||
|
qid = event.from_wxid
|
||||||
|
im = await get_user_card(qid)
|
||||||
|
logger.info('[查询用户绑定状态]完成!等待图片发送中...')
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
|
||||||
|
|
||||||
|
@add_cookie.handle()
|
||||||
|
@handle_exception('Cookie', '校验失败!请输入正确的Cookies!')
|
||||||
|
@register_menu(
|
||||||
|
'绑定CK、SK',
|
||||||
|
'添加[CK或SK]',
|
||||||
|
'绑定你的Cookies以及Stoken',
|
||||||
|
trigger_method='好友私聊指令',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'绑定你的Cookies以及Stoken\n'
|
||||||
|
'Cookies (CK):米游社Cookies;Stoken (SK):米哈游通行证Cookies\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>添加</ft><ft color=(0,148,200)>[CK或SK]</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_add_ck_msg(
|
||||||
|
event: MessageEvent, matcher: Matcher, args: Message = CommandArg()
|
||||||
|
):
|
||||||
|
mes = args.extract_plain_text().strip().replace(' ', '')
|
||||||
|
qid = event.from_wxid
|
||||||
|
im = await deal_ck(mes, qid)
|
||||||
|
if isinstance(im, str):
|
||||||
|
await matcher.finish(im)
|
||||||
|
await matcher.finish(MessageSegment.image(im))
|
||||||
|
|
||||||
|
|
||||||
|
# 群聊内 绑定uid或者mysid 的命令,会绑定至当前qq号上
|
||||||
|
@bind.handle()
|
||||||
|
@handle_exception('绑定ID', '绑定ID异常')
|
||||||
|
@register_menu(
|
||||||
|
'绑定UID',
|
||||||
|
'绑定xx',
|
||||||
|
'绑定原神UID或米游社UID',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'绑定原神UID或米游社UID\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>绑定'
|
||||||
|
'{uid</ft><ft color=(0,148,200)>[原神UID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>[米游社UID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@register_menu(
|
||||||
|
'解绑UID',
|
||||||
|
'解绑xx',
|
||||||
|
'解绑原神UID或米游社UID',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'解绑原神UID或米游社UID\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>{解绑|删除}'
|
||||||
|
'{uid</ft><ft color=(0,148,200)>[原神UID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>[米游社UID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@register_menu(
|
||||||
|
'切换UID',
|
||||||
|
'切换xx',
|
||||||
|
'切换当前原神UID或米游社UID',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'切换当前原神UID或米游社UID\n'
|
||||||
|
'绑定一个UID的情况下无法切换\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>切换'
|
||||||
|
'{uid</ft><ft color=(0,148,200)>[原神UID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>|mys</ft><ft color=(0,148,200)>[米游社UID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_link_uid_msg(
|
||||||
|
event: MessageEvent, matcher: Matcher, args: Tuple[Any, ...] = RegexGroup()
|
||||||
|
):
|
||||||
|
logger.info('开始执行[绑定/解绑用户信息]')
|
||||||
|
logger.info('[绑定/解绑]参数: {}'.format(args))
|
||||||
|
qid = event.from_wxid
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(event.from_wxid)
|
||||||
logger.info('[绑定/解绑]UserID: {}'.format(qid))
|
logger.info('[绑定/解绑]UserID: {}'.format(qid))
|
||||||
|
|
||||||
if args[0] in ('绑定'):
|
if args[0] in ('绑定'):
|
||||||
if args[2] is None:
|
if args[2] is None:
|
||||||
await bot.send(ev, '请输入正确的uid或者mysid!')
|
await matcher.finish('请输入正确的uid或者mysid!')
|
||||||
|
|
||||||
if args[1] in ('uid', 'UID'):
|
if args[1] in ('uid', 'UID'):
|
||||||
im = await bind_db(qid, args[2])
|
im = await bind_db(qid, args[2])
|
||||||
@ -110,32 +265,23 @@ async def send_link_uid_msg(bot: HoshinoBot, ev: CQEvent):
|
|||||||
im = await delete_db(qid, {'UID': args[2]})
|
im = await delete_db(qid, {'UID': args[2]})
|
||||||
else:
|
else:
|
||||||
im = await delete_db(qid, {'MYSID': args[2]})
|
im = await delete_db(qid, {'MYSID': args[2]})
|
||||||
await bot.send(ev, im, at_sender=True)
|
await matcher.finish(
|
||||||
|
MessageSegment.room_at_msg(content="{$@}" + f'{im}', at_list=wxid_list)
|
||||||
|
|
||||||
@sv.on_fullmatch(('绑定ck说明', 'ck帮助', '绑定ck'))
|
|
||||||
async def send_ck_msg(bot: HoshinoBot, ev: CQEvent):
|
|
||||||
msg_list = await get_ck_help()
|
|
||||||
forward_msg = []
|
|
||||||
for msg in msg_list:
|
|
||||||
forward_msg.append(
|
|
||||||
{
|
|
||||||
"type": "node",
|
|
||||||
"data": {"name": "小冰", "uin": "2854196306", "content": msg},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
await bot.send_group_forward_msg(
|
|
||||||
group_id=ev.group_id, messages=forward_msg
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix(("gsrc", "原神充值"))
|
@get_ck_msg.handle()
|
||||||
async def topup(bot: HoshinoBot, ev: CQEvent):
|
async def send_ck_help(matcher: Matcher):
|
||||||
qid = ev.user_id
|
msg_list = await get_ck_help()
|
||||||
goods_id = ev.message.extract_plain_text()
|
for msg in msg_list:
|
||||||
if goods_id == "":
|
await matcher.send(msg)
|
||||||
goods_id = 0
|
await asyncio.sleep(0.5)
|
||||||
else:
|
|
||||||
goods_id = int(goods_id)
|
|
||||||
group_id = ev.group_id
|
@get_qr_msg.handle()
|
||||||
await topup_(bot, qid, group_id, goods_id)
|
async def send_qr_help(matcher: Matcher):
|
||||||
|
msg_list = await get_qr_help()
|
||||||
|
for msg in msg_list:
|
||||||
|
await matcher.send(msg)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
@ -55,7 +55,7 @@ async def get_ck_by_all_stoken():
|
|||||||
return im
|
return im
|
||||||
|
|
||||||
|
|
||||||
async def get_ck_by_stoken(qid: int):
|
async def get_ck_by_stoken(qid: str):
|
||||||
uid_list: List = await select_db(qid, mode='list') # type: ignore
|
uid_list: List = await select_db(qid, mode='list') # type: ignore
|
||||||
uid_dict = {uid: qid for uid in uid_list}
|
uid_dict = {uid: qid for uid in uid_list}
|
||||||
im = await refresh_ck_by_uid_list(uid_dict)
|
im = await refresh_ck_by_uid_list(uid_dict)
|
||||||
|
241
GenshinUID/genshinuid_user/draw_topup_img.py
Normal file
241
GenshinUID/genshinuid_user/draw_topup_img.py
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
from time import strftime, localtime
|
||||||
|
|
||||||
|
from httpx import AsyncClient
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
from ..utils.genshin_fonts.genshin_fonts import FONT_ORIGIN_PATH
|
||||||
|
|
||||||
|
|
||||||
|
def font(size: int) -> ImageFont.FreeTypeFont:
|
||||||
|
"""Pillow 绘制字体设置"""
|
||||||
|
return ImageFont.truetype(str(FONT_ORIGIN_PATH), size=size)
|
||||||
|
|
||||||
|
|
||||||
|
# 支付宝充值图片绘制
|
||||||
|
async def draw_ali(
|
||||||
|
uid,
|
||||||
|
item_info: str,
|
||||||
|
item_price: str,
|
||||||
|
item_order_no: str,
|
||||||
|
qrcode,
|
||||||
|
item_icon: str,
|
||||||
|
item_create_time: int,
|
||||||
|
item_id: str,
|
||||||
|
) -> bytes:
|
||||||
|
"""充值图片绘制"""
|
||||||
|
async with AsyncClient() as client:
|
||||||
|
_img = await client.get(item_icon, timeout=10.0)
|
||||||
|
itemImg = Image.open(BytesIO(_img.content)).convert("RGBA")
|
||||||
|
|
||||||
|
themeColor = "#1678ff"
|
||||||
|
warning = 20 if item_id == 'ys_chn_blessofmoon_tier5' else 0
|
||||||
|
res = Image.new("RGBA", (450, 530), themeColor)
|
||||||
|
drawer = ImageDraw.Draw(res)
|
||||||
|
resample = getattr(Image, "Resampling", Image).LANCZOS
|
||||||
|
|
||||||
|
# 头部矩形背景
|
||||||
|
drawer.rectangle(
|
||||||
|
(75, 50 - warning, 375 - 1, 150 - warning), fill="#E5F9FF", width=0
|
||||||
|
)
|
||||||
|
# 商品图片
|
||||||
|
item = itemImg.resize((90, 90), resample=resample)
|
||||||
|
res.paste(item, (80, 55 - warning), item)
|
||||||
|
# 二维码图片
|
||||||
|
qrcode = Image.open(qrcode)
|
||||||
|
qrcode = qrcode.resize((300, 300), resample=resample)
|
||||||
|
res.paste(qrcode, (75, 150 + warning), qrcode)
|
||||||
|
# 商品名称
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int(175 + (195 - font(25).getlength(item_info)) / 2),
|
||||||
|
int(70 - warning + (30 - font(25).getbbox(item_info)[-1]) / 2),
|
||||||
|
),
|
||||||
|
item_info,
|
||||||
|
fill="#000000",
|
||||||
|
font=font(25),
|
||||||
|
)
|
||||||
|
# 价格
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int(175 + (195 - font(25).getlength(item_price)) / 2),
|
||||||
|
int(105 - warning + (30 - font(25).getbbox(item_price)[-1]) / 2),
|
||||||
|
),
|
||||||
|
item_price,
|
||||||
|
fill="#000000",
|
||||||
|
font=font(25),
|
||||||
|
)
|
||||||
|
# 商品充值 UID
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int((460 - font(15).getlength(f"充值到 UID{uid}")) / 2),
|
||||||
|
int(
|
||||||
|
155
|
||||||
|
+ warning
|
||||||
|
+ (20 - font(15).getbbox(f"充值到 UID{uid}")[-1]) / 2
|
||||||
|
),
|
||||||
|
),
|
||||||
|
f"充值到 UID{uid}",
|
||||||
|
fill="#333333",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
# 月卡相关商品警告
|
||||||
|
if warning:
|
||||||
|
# 首部矩形背景
|
||||||
|
drawer.rectangle((75, 130, 375 - 1, 170), fill="#eeeeee", width=0)
|
||||||
|
# 转换警告文字
|
||||||
|
warning_text = "特殊情况将直接返还 330 创世结晶"
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int((450 - font(15).getlength(warning_text)) / 2),
|
||||||
|
int(130 + (40 - font(15).getbbox(warning_text)[-1]) / 2),
|
||||||
|
),
|
||||||
|
warning_text,
|
||||||
|
fill="#ff5652",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
# 图片生成时间
|
||||||
|
timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime(int(item_create_time)))
|
||||||
|
drawer.text(
|
||||||
|
(int((460 - font(15).getlength(timestamp)) / 2), 425 + warning),
|
||||||
|
timestamp,
|
||||||
|
fill="#1678ff",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
# 账单信息
|
||||||
|
ticket = f"支付宝账单编号 {item_order_no}"
|
||||||
|
drawer.text(
|
||||||
|
(int((450 - font(15).getlength(ticket)) / 2), 460 + warning),
|
||||||
|
ticket,
|
||||||
|
fill="#ffffff",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
# 免责声明
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int(
|
||||||
|
(
|
||||||
|
410
|
||||||
|
- font(15).getlength(
|
||||||
|
"免责声明:该充值接口由米游社提供,不对充值结果负责。\n请在充值前仔细阅读米哈游的充值条款。"
|
||||||
|
)
|
||||||
|
/ 2
|
||||||
|
)
|
||||||
|
),
|
||||||
|
490 + warning,
|
||||||
|
),
|
||||||
|
"免责声明:该充值接口由米游社提供,不对充值结果负责。\n 请在充值前仔细阅读米哈游的充值条款。",
|
||||||
|
fill="#FFA500",
|
||||||
|
font=font(12),
|
||||||
|
)
|
||||||
|
buf = BytesIO()
|
||||||
|
res.convert("RGB").save(buf, format="PNG")
|
||||||
|
return buf.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
# 微信充值图片绘制
|
||||||
|
async def draw_wx(
|
||||||
|
uid,
|
||||||
|
item_info: str,
|
||||||
|
item_price: str,
|
||||||
|
item_order_no: str,
|
||||||
|
item_icon: str,
|
||||||
|
item_create_time: int,
|
||||||
|
item_id: str,
|
||||||
|
) -> bytes:
|
||||||
|
"""充值图片绘制"""
|
||||||
|
async with AsyncClient() as client:
|
||||||
|
_img = await client.get(item_icon, timeout=10.0)
|
||||||
|
itemImg = Image.open(BytesIO(_img.content)).convert("RGBA")
|
||||||
|
|
||||||
|
themeColor = "#29ac66"
|
||||||
|
warning = 20 if item_id == 'ys_chn_blessofmoon_tier5' else 0
|
||||||
|
res = Image.new("RGBA", (450, 200), themeColor)
|
||||||
|
drawer = ImageDraw.Draw(res)
|
||||||
|
resample = getattr(Image, "Resampling", Image).LANCZOS
|
||||||
|
left = (450 - 370) / 2 # (图片宽度 - 矩形宽度) / 2
|
||||||
|
top = (200 - 130) / 2 # (图片高度 - 矩形高度) / 2
|
||||||
|
# 头部矩形背景
|
||||||
|
drawer.rectangle(
|
||||||
|
(
|
||||||
|
left,
|
||||||
|
top - warning,
|
||||||
|
left + 370,
|
||||||
|
top + 130 - warning,
|
||||||
|
), # 使用新的左上角和右下角的坐标
|
||||||
|
fill="#E5F9FF", # 保留原有的填充色
|
||||||
|
width=0, # 保留原有的边框宽度
|
||||||
|
)
|
||||||
|
|
||||||
|
# 商品图片
|
||||||
|
item = itemImg.resize((110, 110), resample=resample)
|
||||||
|
res.paste(item, (55, 50 - warning), item)
|
||||||
|
# 商品名称
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int(175 + (215 - font(25).getlength(item_info)) / 2),
|
||||||
|
int(50 - warning + (30 - font(25).getbbox(item_info)[-1]) / 2),
|
||||||
|
),
|
||||||
|
item_info,
|
||||||
|
fill="#000000",
|
||||||
|
font=font(25),
|
||||||
|
)
|
||||||
|
# 价格
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int(180 + (195 - font(25).getlength(item_price)) / 2),
|
||||||
|
int(80 - warning + (30 - font(25).getbbox(item_price)[-1]) / 2),
|
||||||
|
),
|
||||||
|
item_price,
|
||||||
|
fill="#000000",
|
||||||
|
font=font(25),
|
||||||
|
)
|
||||||
|
# 商品充值 UID
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int(185 + (195 - font(15).getlength(f"充值到 UID{uid}")) / 2),
|
||||||
|
int(
|
||||||
|
120
|
||||||
|
- warning
|
||||||
|
+ (20 - font(15).getbbox(f"充值到 UID{uid}")[-1]) / 2
|
||||||
|
),
|
||||||
|
),
|
||||||
|
f"充值到 UID{uid}",
|
||||||
|
fill="#000000",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
# 图片生成时间
|
||||||
|
timestamp = strftime("%Y-%m-%d %H:%M:%S", localtime(int(item_create_time)))
|
||||||
|
drawer.text(
|
||||||
|
(int(185 + (195 - font(15).getlength(timestamp)) / 2), 140 - warning),
|
||||||
|
timestamp,
|
||||||
|
fill="#29ac66",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
if warning:
|
||||||
|
# 首部矩形背景
|
||||||
|
drawer.rectangle(
|
||||||
|
(left, top + 110, left + 370, top + 130), fill="#eeeeee", width=0
|
||||||
|
)
|
||||||
|
# 转换警告文字
|
||||||
|
warning_text = "特殊情况将直接返还 330 创世结晶"
|
||||||
|
drawer.text(
|
||||||
|
(
|
||||||
|
int((450 - font(15).getlength(warning_text)) / 2),
|
||||||
|
int(135 + (40 - font(15).getbbox(warning_text)[-1]) / 2),
|
||||||
|
),
|
||||||
|
warning_text,
|
||||||
|
fill="#ff5652",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
# 账单信息
|
||||||
|
ticket = f"微信支付账单编号 {item_order_no}"
|
||||||
|
drawer.text(
|
||||||
|
(int((450 - font(15).getlength(ticket)) / 2), 170),
|
||||||
|
ticket,
|
||||||
|
fill="#ffffff",
|
||||||
|
font=font(15),
|
||||||
|
)
|
||||||
|
buf = BytesIO()
|
||||||
|
res.convert("RGB").save(buf, format="PNG")
|
||||||
|
return buf.getvalue()
|
@ -29,7 +29,7 @@ gs_font_15 = genshin_font_origin(15)
|
|||||||
gs_font_26 = genshin_font_origin(26)
|
gs_font_26 = genshin_font_origin(26)
|
||||||
|
|
||||||
|
|
||||||
async def get_user_card(qid: int) -> bytes:
|
async def get_user_card(qid: str) -> bytes:
|
||||||
uid_list: List = await select_db(qid, 'list') # type: ignore
|
uid_list: List = await select_db(qid, 'list') # type: ignore
|
||||||
w, h = 500, len(uid_list) * 210 + 330
|
w, h = 500, len(uid_list) * 210 + 330
|
||||||
img = await get_simple_bg(w, h)
|
img = await get_simple_bg(w, h)
|
||||||
|
@ -26,6 +26,10 @@ http://user.mihoyo.com/(国服)
|
|||||||
然后在和机器人的私聊窗口,粘贴发送即可
|
然后在和机器人的私聊窗口,粘贴发送即可
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
QRL = '''请在群里发送【扫码登录】并用米游社/原神进行扫码绑定
|
||||||
|
如果使用该功能,请先绑定UID后再进行登录
|
||||||
|
注意不要乱扫他人二维码'''
|
||||||
|
|
||||||
|
|
||||||
async def get_ck_help() -> List:
|
async def get_ck_help() -> List:
|
||||||
msg_list = []
|
msg_list = []
|
||||||
@ -34,3 +38,9 @@ async def get_ck_help() -> List:
|
|||||||
msg_list.append(CK_URL)
|
msg_list.append(CK_URL)
|
||||||
msg_list.append(SK_URL)
|
msg_list.append(SK_URL)
|
||||||
return msg_list
|
return msg_list
|
||||||
|
|
||||||
|
|
||||||
|
async def get_qr_help() -> List:
|
||||||
|
msg_list = []
|
||||||
|
msg_list.append(QRL)
|
||||||
|
return msg_list
|
||||||
|
@ -3,12 +3,15 @@ import json
|
|||||||
import base64
|
import base64
|
||||||
import asyncio
|
import asyncio
|
||||||
from http.cookies import SimpleCookie
|
from http.cookies import SimpleCookie
|
||||||
from typing import Any, Tuple, Union, Literal
|
from typing import Any, List, Tuple, Union, Literal, NoReturn
|
||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from qrcode.constants import ERROR_CORRECT_L
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
|
||||||
from ..utils.message.send_msg import send_forward_msg
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.mhy_api.get_mhy_data import (
|
from ..utils.mhy_api.get_mhy_data import (
|
||||||
check_qrcode,
|
check_qrcode,
|
||||||
@ -19,26 +22,27 @@ from ..utils.mhy_api.get_mhy_data import (
|
|||||||
get_cookie_token_by_stoken,
|
get_cookie_token_by_stoken,
|
||||||
)
|
)
|
||||||
|
|
||||||
disnote = '''免责声明:您将通过扫码完成获取米游社sk以及ck。
|
disnote = '''免责声明:您将通过扫码完成获取米游社sk以及ck。
|
||||||
本Bot将不会保存您的登录状态。
|
登录米游社相当于将账号授权于机器人,可能会带来未知的账号风险。
|
||||||
我方仅提供米游社查询及相关游戏内容服务
|
|
||||||
若您的账号封禁、被盗等处罚与我方无关。
|
若您的账号封禁、被盗等处罚与我方无关。
|
||||||
害怕风险请勿扫码!
|
登录后即代表您同意机器人使用协议并知晓会带来未知的账号风险!
|
||||||
'''
|
若想取消授权,请到米游社退出登录以清除机器人绑定的登录状态。
|
||||||
|
|
||||||
|
请用米游社/原神扫描下方二维码登录:'''
|
||||||
|
|
||||||
|
|
||||||
def get_qrcode_base64(url):
|
def get_qrcode_base64(url):
|
||||||
qr = qrcode.QRCode(
|
qr = qrcode.QRCode(
|
||||||
version=1,
|
version=1,
|
||||||
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
error_correction=ERROR_CORRECT_L,
|
||||||
box_size=10,
|
box_size=10,
|
||||||
border=4,
|
border=4,
|
||||||
)
|
)
|
||||||
qr.add_data(url)
|
qr.add_data(url)
|
||||||
qr.make(fit=True)
|
qr.make(fit=True)
|
||||||
img = qr.make_image(fill_color="black", back_color="white")
|
img = qr.make_image(fill_color='black', back_color='white')
|
||||||
img_byte = io.BytesIO()
|
img_byte = io.BytesIO()
|
||||||
img.save(img_byte, format="PNG")
|
img.save(img_byte, format='PNG') # type: ignore
|
||||||
img_byte = img_byte.getvalue()
|
img_byte = img_byte.getvalue()
|
||||||
return base64.b64encode(img_byte).decode()
|
return base64.b64encode(img_byte).decode()
|
||||||
|
|
||||||
@ -50,50 +54,52 @@ async def refresh(
|
|||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
status_data = await check_qrcode(
|
status_data = await check_qrcode(
|
||||||
code_data["app_id"], code_data["ticket"], code_data["device"]
|
code_data['app_id'], code_data['ticket'], code_data['device']
|
||||||
)
|
)
|
||||||
if status_data["retcode"] != 0:
|
if status_data['retcode'] != 0:
|
||||||
logger.warn("二维码已过期")
|
logger.warning('二维码已过期')
|
||||||
return False, None
|
return False, None
|
||||||
if status_data["data"]["stat"] == "Scanned":
|
if status_data['data']['stat'] == 'Scanned':
|
||||||
if not scanned:
|
if not scanned:
|
||||||
logger.info("二维码已扫描")
|
logger.info('二维码已扫描')
|
||||||
scanned = True
|
scanned = True
|
||||||
continue
|
continue
|
||||||
if status_data["data"]["stat"] == "Confirmed":
|
if status_data['data']['stat'] == 'Confirmed':
|
||||||
logger.info("二维码已确认")
|
logger.info('二维码已确认')
|
||||||
# print(status_data["data"]["payload"]["raw"])
|
|
||||||
break
|
break
|
||||||
return True, json.loads(status_data["data"]["payload"]["raw"])
|
return True, json.loads(status_data['data']['payload']['raw'])
|
||||||
|
|
||||||
|
|
||||||
async def qrcode_login(bot, group_id, user_id) -> str:
|
async def qrcode_login(matcher: Matcher, user_id) -> str:
|
||||||
async def send_group_msg(msg: str):
|
async def send_group_msg(msg: str, at_list: List) -> NoReturn:
|
||||||
await bot.call_action(
|
await matcher.finish(
|
||||||
action='send_group_msg',
|
MessageSegment.room_at_msg(content=msg, at_list=at_list)
|
||||||
group_id=group_id,
|
|
||||||
message=msg,
|
|
||||||
)
|
)
|
||||||
return ""
|
|
||||||
|
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(user_id)
|
||||||
code_data = await create_qrcode_url()
|
code_data = await create_qrcode_url()
|
||||||
try:
|
try:
|
||||||
im = []
|
await matcher.send(
|
||||||
qrc = f'[CQ:image,file=base64://{get_qrcode_base64(code_data["url"])}]'
|
MessageSegment.image(
|
||||||
im.append('请使用米游社扫描下方二维码登录:')
|
f'base64://{get_qrcode_base64(code_data["url"])}'
|
||||||
im.append(qrc)
|
)
|
||||||
im.append(disnote)
|
)
|
||||||
await send_forward_msg(bot, group_id, "扫码小助手", str(user_id), im)
|
await matcher.send(
|
||||||
|
MessageSegment.room_at_msg(
|
||||||
|
content='{$@}' + disnote, at_list=wxid_list
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warn(f"[扫码登录] {group_id} 图片发送失败")
|
logger.warning('[扫码登录] {user_id} 图片发送失败')
|
||||||
status, game_token_data = await refresh(code_data)
|
status, game_token_data = await refresh(code_data)
|
||||||
if status:
|
if status:
|
||||||
assert game_token_data is not None # 骗过 pyright
|
assert game_token_data is not None # 骗过 pyright
|
||||||
logger.info("game_token获取成功")
|
logger.info('[扫码登录]game_token获取成功')
|
||||||
cookie_token = await get_cookie_token(**game_token_data)
|
cookie_token = await get_cookie_token(**game_token_data)
|
||||||
stoken_data = await get_stoken_by_game_token(
|
stoken_data = await get_stoken_by_game_token(
|
||||||
account_id=int(game_token_data["uid"]),
|
account_id=int(game_token_data['uid']),
|
||||||
game_token=game_token_data["token"],
|
game_token=game_token_data['token'],
|
||||||
)
|
)
|
||||||
account_id = game_token_data['uid']
|
account_id = game_token_data['uid']
|
||||||
stoken = stoken_data['data']['token']['token']
|
stoken = stoken_data['data']['token']['token']
|
||||||
@ -103,7 +109,6 @@ async def qrcode_login(bot, group_id, user_id) -> str:
|
|||||||
ck = ck['data']['cookie_token']
|
ck = ck['data']['cookie_token']
|
||||||
cookie_check = f'account_id={account_id};cookie_token={ck}'
|
cookie_check = f'account_id={account_id};cookie_token={ck}'
|
||||||
get_uid = await get_mihoyo_bbs_info(account_id, cookie_check)
|
get_uid = await get_mihoyo_bbs_info(account_id, cookie_check)
|
||||||
# 剔除除了原神之外的其他游戏
|
|
||||||
im = None
|
im = None
|
||||||
if get_uid:
|
if get_uid:
|
||||||
for i in get_uid['data']['list']:
|
for i in get_uid['data']['list']:
|
||||||
@ -112,17 +117,15 @@ async def qrcode_login(bot, group_id, user_id) -> str:
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
im = f'你的米游社账号{account_id}尚未绑定原神账号,请前往米游社操作!'
|
im = f'你的米游社账号{account_id}尚未绑定原神账号,请前往米游社操作!'
|
||||||
return await send_group_msg(im)
|
await send_group_msg(im, wxid_list)
|
||||||
else:
|
else:
|
||||||
im = '请求失败, 请稍后再试...'
|
im = '请求失败, 请稍后再试...'
|
||||||
return await send_group_msg(im)
|
await send_group_msg(im, wxid_list)
|
||||||
|
|
||||||
uid_bind = await select_db(user_id, mode='uid')
|
uid_bind = await select_db(user_id, mode='uid')
|
||||||
# 没有在gsuid绑定uid的情况
|
|
||||||
if uid_bind == "未找到绑定的UID~":
|
if uid_bind == "未找到绑定的UID~":
|
||||||
logger.warning('game_token获取失败')
|
logger.warning('game_token获取失败')
|
||||||
im = '你还没有绑定uid,请输入[绑定uid123456]绑定你的uid,再发送[扫码登录]进行绑定'
|
await matcher.finish(UID_HINT)
|
||||||
return await send_group_msg(im)
|
|
||||||
# 比对gsuid数据库和扫码登陆获取到的uid
|
|
||||||
if str(uid_bind) == uid_check or str(uid_bind) == account_id:
|
if str(uid_bind) == uid_check or str(uid_bind) == account_id:
|
||||||
return SimpleCookie(
|
return SimpleCookie(
|
||||||
{
|
{
|
||||||
@ -133,9 +136,12 @@ async def qrcode_login(bot, group_id, user_id) -> str:
|
|||||||
}
|
}
|
||||||
).output(header='', sep=';')
|
).output(header='', sep=';')
|
||||||
else:
|
else:
|
||||||
logger.warning('game_token获取失败')
|
logger.warning('game_token获取失败:非触发者本人扫码')
|
||||||
im = 'game_token获取失败:被非绑定指定uid用户扫取,取消绑定,请重新发送[扫码登录]登录账号'
|
im = (
|
||||||
|
'{$@}' + f'检测到扫码登录UID{uid_check}与绑定UID{uid_bind}不同,'
|
||||||
|
'gametoken获取失败,请重新发送[扫码登录]进行登录'
|
||||||
|
)
|
||||||
|
await send_group_msg(im, wxid_list)
|
||||||
else:
|
else:
|
||||||
logger.warning('game_token获取失败')
|
logger.warning('game_token获取失败')
|
||||||
im = 'game_token获取失败:二维码已过期'
|
await send_group_msg('{$@}game_token获取失败:二维码已过期', wxid_list)
|
||||||
return await send_group_msg(im)
|
|
||||||
|
@ -2,24 +2,79 @@ import io
|
|||||||
import base64
|
import base64
|
||||||
import asyncio
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
|
from typing import List, NoReturn
|
||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from qrcode.constants import ERROR_CORRECT_L
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
|
||||||
from ..utils.message.send_msg import send_forward_msg
|
from .draw_topup_img import draw_wx, draw_ali
|
||||||
|
from ..utils.message.error_reply import UID_HINT
|
||||||
from ..utils.db_operation.db_operation import select_db
|
from ..utils.db_operation.db_operation import select_db
|
||||||
from ..utils.mhy_api.get_mhy_data import topup, checkorder, fetchgoods
|
from ..utils.mhy_api.get_mhy_data import topup, checkorder, fetchgoods
|
||||||
|
|
||||||
disnote = '''免责声明:
|
disnote = '''免责声明:该充值接口由米游社提供,不对充值结果负责。
|
||||||
该充值接口由米游社提供,不对充值结果负责。
|
请在充值前仔细阅读米哈游的充值条款。'''
|
||||||
请在充值前仔细阅读米哈游的充值条款。
|
|
||||||
'''
|
GOODS = {
|
||||||
|
0: {
|
||||||
|
"title": "创世结晶×60",
|
||||||
|
"aliases": ["创世结晶x60", "结晶×60", "结晶x60", "创世结晶60", "结晶60"],
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
"title": "创世结晶×300",
|
||||||
|
"aliases": ["创世结晶x300", "结晶×300", "结晶x300", "创世结晶300", "结晶300", "30"],
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
"title": "创世结晶×980",
|
||||||
|
"aliases": ["创世结晶x980", "结晶×980", "结晶x980", "创世结晶980", "结晶980", "98"],
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
"title": "创世结晶×1980",
|
||||||
|
"aliases": [
|
||||||
|
"创世结晶x1980",
|
||||||
|
"结晶×1980",
|
||||||
|
"结晶x1980",
|
||||||
|
"创世结晶1980",
|
||||||
|
"结晶1980",
|
||||||
|
"198",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
"title": "创世结晶×3280",
|
||||||
|
"aliases": [
|
||||||
|
"创世结晶x3280",
|
||||||
|
"结晶×3280",
|
||||||
|
"结晶x3280",
|
||||||
|
"创世结晶3280",
|
||||||
|
"结晶3280",
|
||||||
|
"328",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
5: {
|
||||||
|
"title": "创世结晶×6480",
|
||||||
|
"aliases": [
|
||||||
|
"创世结晶x6480",
|
||||||
|
"结晶×6480",
|
||||||
|
"结晶x6480",
|
||||||
|
"创世结晶6480",
|
||||||
|
"结晶6480",
|
||||||
|
"648",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
6: {
|
||||||
|
"title": "空月祝福",
|
||||||
|
"aliases": ["空月", "祝福", "月卡", "小月卡"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_qrcode_base64(url):
|
def get_qrcode_base64(url):
|
||||||
qr = qrcode.QRCode(
|
qr = qrcode.QRCode(
|
||||||
version=1,
|
version=1,
|
||||||
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
error_correction=ERROR_CORRECT_L,
|
||||||
box_size=10,
|
box_size=10,
|
||||||
border=4,
|
border=4,
|
||||||
)
|
)
|
||||||
@ -27,12 +82,12 @@ def get_qrcode_base64(url):
|
|||||||
qr.make(fit=True)
|
qr.make(fit=True)
|
||||||
img = qr.make_image(fill_color="black", back_color="white")
|
img = qr.make_image(fill_color="black", back_color="white")
|
||||||
img_byte = io.BytesIO()
|
img_byte = io.BytesIO()
|
||||||
img.save(img_byte, format="PNG")
|
img.save(img_byte, format="PNG") # type: ignore
|
||||||
img_byte = img_byte.getvalue()
|
img_byte = img_byte.getvalue()
|
||||||
return base64.b64encode(img_byte).decode()
|
return base64.b64encode(img_byte).decode()
|
||||||
|
|
||||||
|
|
||||||
async def refresh(order, uid):
|
async def refresh(order, uid, oid):
|
||||||
times = 0
|
times = 0
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
@ -40,53 +95,91 @@ async def refresh(order, uid):
|
|||||||
if order_status != 900:
|
if order_status != 900:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
return "支付成功"
|
return "{$@}" + f"支付成功!\nUID:{uid}\n订单号:{oid}"
|
||||||
times += 1
|
times += 1
|
||||||
if times > 60:
|
if times > 60:
|
||||||
return "支付超时"
|
return "{$@}" + f"支付超时!\nUID:{uid}\n订单号:{oid}"
|
||||||
|
|
||||||
|
|
||||||
async def topup_(bot, qid, group_id, goods_id):
|
async def topup_(matcher: Matcher, qid, group_id, goods_id, method):
|
||||||
async def send_group_msg(msg: str):
|
async def send_group_msg(msg: str, at_list: List) -> NoReturn:
|
||||||
await bot.call_action(
|
await matcher.finish(
|
||||||
action='send_group_msg',
|
MessageSegment.room_at_msg(content=msg, at_list=at_list)
|
||||||
group_id=group_id,
|
|
||||||
message=msg,
|
|
||||||
)
|
)
|
||||||
return ""
|
|
||||||
|
|
||||||
|
wxid_list = []
|
||||||
|
wxid_list.append(qid)
|
||||||
uid = await select_db(qid, mode="uid")
|
uid = await select_db(qid, mode="uid")
|
||||||
if uid is None:
|
if uid is None:
|
||||||
await send_group_msg("未绑定米游社账号")
|
await send_group_msg("{$@}" + UID_HINT, wxid_list)
|
||||||
return
|
|
||||||
fetchgoods_data = await fetchgoods()
|
fetchgoods_data = await fetchgoods()
|
||||||
try:
|
try:
|
||||||
goods_data = fetchgoods_data[goods_id]
|
goods_data = fetchgoods_data[goods_id]
|
||||||
except Exception:
|
except Exception as e:
|
||||||
await send_group_msg("商品不存在,最大为" + str(len(fetchgoods_data) - 1))
|
logger.warning(f'[充值]错误 {e}')
|
||||||
return
|
await send_group_msg(
|
||||||
try:
|
"{$@}商品不存在,最大为" + str(len(fetchgoods_data) - 1), wxid_list
|
||||||
order = await topup(uid, goods_data)
|
|
||||||
except Exception:
|
|
||||||
await send_group_msg("出错了,可能是cookie过期或接口出错")
|
|
||||||
logger.warn(f"[充值] {group_id} {qid}")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
im = []
|
|
||||||
b64_data = get_qrcode_base64(order["encode_order"])
|
|
||||||
qrc = f'[CQ:image,file=base64://{b64_data}]'
|
|
||||||
im.append(f"充值uid:{uid}")
|
|
||||||
im.append(
|
|
||||||
f"商品名称:{goods_data['goods_name']}×{str(goods_data['goods_unit'])}"
|
|
||||||
if int(goods_data['goods_unit']) > 0
|
|
||||||
else goods_data["goods_name"],
|
|
||||||
)
|
)
|
||||||
im.append(f'商品价格:{int(order["amount"])/100}')
|
try:
|
||||||
im.append(f"订单号:{order['order_no']}")
|
order = await topup(uid, goods_data, method)
|
||||||
im.append(disnote)
|
except Exception as e:
|
||||||
im.append(qrc)
|
logger.warning(f"[充值] {group_id} {qid} 错误:{e}")
|
||||||
await send_forward_msg(bot, group_id, "小助手", str(qid), im)
|
await send_group_msg("{$@}出错了,可能是Cookie过期或接口出错。", wxid_list)
|
||||||
except Exception:
|
try:
|
||||||
|
b64_data = get_qrcode_base64(order["encode_order"])
|
||||||
|
img_b64decode = base64.b64decode(b64_data)
|
||||||
|
qrimage = io.BytesIO(img_b64decode) # 二维码
|
||||||
|
item_icon_url: str = goods_data['goods_icon'] # 图标
|
||||||
|
item_id: str = goods_data['goods_id'] # 商品内部id
|
||||||
|
item_pay_url: str = order['encode_order'] # 支付链接
|
||||||
|
item_name_full = (
|
||||||
|
f"{goods_data['goods_name']}×{str(goods_data['goods_unit'])}"
|
||||||
|
)
|
||||||
|
# 物品名字(非月卡)
|
||||||
|
item_name: str = (
|
||||||
|
item_name_full
|
||||||
|
if int(goods_data['goods_unit']) > 0
|
||||||
|
else goods_data["goods_name"]
|
||||||
|
)
|
||||||
|
# 物品名字
|
||||||
|
item_price: str = order["currency"] + str(
|
||||||
|
int(order["amount"]) / 100
|
||||||
|
) # 价格
|
||||||
|
item_order_no: str = order['order_no'] # 订单号
|
||||||
|
item_create_time: int = order['create_time'] # 创建时间
|
||||||
|
|
||||||
|
if method == 'alipay':
|
||||||
|
img_data = await draw_ali(
|
||||||
|
uid,
|
||||||
|
item_name,
|
||||||
|
item_price,
|
||||||
|
item_order_no,
|
||||||
|
qrimage,
|
||||||
|
item_icon_url,
|
||||||
|
item_create_time,
|
||||||
|
item_id,
|
||||||
|
)
|
||||||
|
return MessageSegment.image(img_data)
|
||||||
|
else:
|
||||||
|
img_data = await draw_wx(
|
||||||
|
uid,
|
||||||
|
item_name,
|
||||||
|
item_price,
|
||||||
|
item_order_no,
|
||||||
|
item_icon_url,
|
||||||
|
item_create_time,
|
||||||
|
item_id,
|
||||||
|
)
|
||||||
|
msg_text = '{$@}' + f' UID:{uid}\n{item_name}\n{item_create_time}'
|
||||||
|
msg_text2 = msg_text + f'\n\nZF:{item_pay_url}\n\n{disnote}'
|
||||||
|
at_msg = MessageSegment.room_at_msg(
|
||||||
|
content=msg_text2, at_list=wxid_list
|
||||||
|
)
|
||||||
|
return MessageSegment.image(img_data) + at_msg
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
logger.warn(f"[充值] {group_id} 图片发送失败")
|
logger.warning(f"[充值] {group_id} 图片发送失败: {e}")
|
||||||
await send_group_msg(await refresh(order, uid))
|
await send_group_msg(
|
||||||
|
await refresh(order, uid, order['order_no']), wxid_list
|
||||||
|
)
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from sqlmodel import SQLModel
|
from sqlmodel import SQLModel
|
||||||
|
from nonebot import get_driver
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot import get_bot, on_startup
|
|
||||||
|
|
||||||
from ..utils.db_operation.db_operation import config_check
|
from ..utils.db_operation.db_operation import config_check
|
||||||
|
|
||||||
config = get_bot().config
|
driver = get_driver()
|
||||||
|
config = driver.config
|
||||||
|
|
||||||
|
|
||||||
async def run_webconsole():
|
async def run_webconsole():
|
||||||
@ -16,22 +17,28 @@ async def run_webconsole():
|
|||||||
user_auth_i18n.set_language('zh_CN')
|
user_auth_i18n.set_language('zh_CN')
|
||||||
|
|
||||||
# 导入app
|
# 导入app
|
||||||
from .mount_app import auth, site
|
try:
|
||||||
|
from .mount_app import auth, site
|
||||||
|
except RuntimeError:
|
||||||
|
logger.warning("当前 Driver 非 ReverseDriver,WebConsole 已禁用")
|
||||||
|
return
|
||||||
|
|
||||||
logger.info('尝试挂载WebConsole')
|
logger.info('尝试挂载WebConsole')
|
||||||
|
|
||||||
await site.db.async_run_sync(
|
await site.db.async_run_sync(
|
||||||
SQLModel.metadata.create_all, is_session=False # type: ignore
|
SQLModel.metadata.create_all, is_session=False # type: ignore
|
||||||
)
|
)
|
||||||
# 创建默认测试用户, 请及时修改密码!!!
|
# 创建默认测试用户, 请及时修改密码!!!
|
||||||
await auth.create_role_user()
|
await auth.create_role_user()
|
||||||
|
|
||||||
logger.info(
|
logger.opt(colors=True).info(
|
||||||
('WebConsole挂载成功:' f'http://{config.HOST}:{config.PORT}/genshinuid')
|
(
|
||||||
|
'WebConsole挂载成功:'
|
||||||
|
f'<blue>http://{config.host}:{config.port}/genshinuid</blue>'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@on_startup
|
@driver.on_startup
|
||||||
async def start_check():
|
async def start_check():
|
||||||
if await config_check('OpenWeb'):
|
if await config_check('OpenWeb'):
|
||||||
await run_webconsole()
|
await run_webconsole()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import fastapi_amis_admin
|
import fastapi_amis_admin
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
|
from nonebot.typing import overrides
|
||||||
from fastapi_user_auth import admin as user_auth_admin
|
from fastapi_user_auth import admin as user_auth_admin
|
||||||
from fastapi_amis_admin.admin import admin as amis_admin
|
from fastapi_amis_admin.admin import admin as amis_admin
|
||||||
from fastapi_amis_admin.utils.translation import i18n as _
|
from fastapi_amis_admin.utils.translation import i18n as _
|
||||||
@ -17,7 +18,6 @@ from fastapi_amis_admin.amis.components import (
|
|||||||
ButtonToolbar,
|
ButtonToolbar,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .nb2 import overrides
|
|
||||||
from ..version import GenshinUID_version
|
from ..version import GenshinUID_version
|
||||||
|
|
||||||
login_html = '''
|
login_html = '''
|
||||||
@ -109,7 +109,7 @@ def attach_page_head(page: Page) -> Page:
|
|||||||
Html(html=login_html),
|
Html(html=login_html),
|
||||||
Grid(
|
Grid(
|
||||||
columns=[
|
columns=[
|
||||||
{'body': [page.body], 'lg': 2, 'md': 4, 'valign': 'middle'}
|
{'body': [page.body], 'lg': 3, 'md': 4, 'valign': 'middle'}
|
||||||
],
|
],
|
||||||
align='center',
|
align='center',
|
||||||
valign='middle',
|
valign='middle',
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
import platform
|
import platform
|
||||||
|
import contextlib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Set, Dict, List, Callable
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Set,
|
||||||
|
List,
|
||||||
|
Union,
|
||||||
|
Callable,
|
||||||
|
Optional,
|
||||||
|
cast,
|
||||||
|
)
|
||||||
|
|
||||||
from quart import Quart
|
import fastapi_amis_admin
|
||||||
from nonebot import get_bot
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from sqlmodel import Relationship
|
from sqlmodel import Relationship
|
||||||
from sqlalchemy.orm import backref
|
from sqlalchemy.orm import backref
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
import fastapi_amis_admin # noqa: F401
|
from nonebot import get_app, get_driver
|
||||||
from fastapi_amis_admin import amis, admin
|
from fastapi_amis_admin import amis, admin
|
||||||
from fastapi_amis_admin.crud import BaseApiOut
|
from fastapi_amis_admin.crud import BaseApiOut
|
||||||
from sqlalchemy.ext.asyncio import AsyncEngine
|
from sqlalchemy.ext.asyncio import AsyncEngine
|
||||||
@ -40,8 +49,8 @@ from fastapi_amis_admin.amis.components import (
|
|||||||
|
|
||||||
from ..version import GenshinUID_version
|
from ..version import GenshinUID_version
|
||||||
from ..genshinuid_user.add_ck import _deal_ck
|
from ..genshinuid_user.add_ck import _deal_ck
|
||||||
from .login_page import amis_admin, user_auth_admin # noqa
|
|
||||||
from ..utils.db_operation.database.db_config import DATABASE_URL
|
from ..utils.db_operation.database.db_config import DATABASE_URL
|
||||||
|
from .login_page import amis_admin, user_auth_admin # noqa # 不要删
|
||||||
from ..utils.db_operation.database.models import (
|
from ..utils.db_operation.database.models import (
|
||||||
Config,
|
Config,
|
||||||
UidData,
|
UidData,
|
||||||
@ -50,21 +59,32 @@ from ..utils.db_operation.database.models import (
|
|||||||
NewCookiesTable,
|
NewCookiesTable,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from quart import Quart
|
||||||
|
from asgiref.typing import Scope, HTTPScope, WebSocketScope
|
||||||
|
|
||||||
|
AppType = Union[FastAPI, 'Quart']
|
||||||
|
|
||||||
|
|
||||||
class FastApiMiddleware:
|
class FastApiMiddleware:
|
||||||
def __init__(self, app: Quart, fastapi: FastAPI, routes: Set[str]) -> None:
|
def __init__(
|
||||||
|
self, app: 'Quart', fastapi: FastAPI, routes: Set[str]
|
||||||
|
) -> None:
|
||||||
self.fastapi = fastapi
|
self.fastapi = fastapi
|
||||||
self.app = app.asgi_app
|
self.app = app.asgi_app
|
||||||
self.routes = routes
|
self.routes = routes
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self, scope: Dict[str, Any], receive: Callable, send: Callable
|
self, scope: 'Scope', receive: Callable, send: Callable
|
||||||
) -> None:
|
) -> None:
|
||||||
if scope['type'] in ('http', 'websocket'):
|
if scope['type'] in ('http', 'websocket'):
|
||||||
|
scope = cast(Union['HTTPScope', 'WebSocketScope'], scope)
|
||||||
for path in self.routes:
|
for path in self.routes:
|
||||||
if scope['path'].startswith(path):
|
if scope['path'].startswith(path):
|
||||||
return await self.fastapi(scope, receive, send)
|
return await self.fastapi(
|
||||||
return await self.app(scope, receive, send)
|
scope, receive, send # type: ignore
|
||||||
|
)
|
||||||
|
return await self.app(scope, receive, send) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
# 自定义后台管理站点
|
# 自定义后台管理站点
|
||||||
@ -89,8 +109,28 @@ class GenshinUIDAdminSite(AuthAdminSite):
|
|||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
# 创建FastAPI应用
|
def get_asgi() -> Optional[AppType]:
|
||||||
app = FastAPI()
|
try:
|
||||||
|
return get_app()
|
||||||
|
except AssertionError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# 从 nb 获取 FastAPI
|
||||||
|
app = get_asgi()
|
||||||
|
if app is None:
|
||||||
|
raise RuntimeError('App is not ReverseDriver')
|
||||||
|
|
||||||
|
with contextlib.suppress(ImportError):
|
||||||
|
from quart import Quart # noqa: F811
|
||||||
|
|
||||||
|
if isinstance(app, Quart):
|
||||||
|
fastapi = FastAPI()
|
||||||
|
app.asgi_app = FastApiMiddleware(app, fastapi, {'/genshinuid'}) # type: ignore
|
||||||
|
app = fastapi
|
||||||
|
|
||||||
|
|
||||||
|
app = cast(FastAPI, app)
|
||||||
settings = Settings(
|
settings = Settings(
|
||||||
database_url_async=DATABASE_URL,
|
database_url_async=DATABASE_URL,
|
||||||
database_url='',
|
database_url='',
|
||||||
@ -99,8 +139,6 @@ settings = Settings(
|
|||||||
site_title='GenshinUID网页控制台',
|
site_title='GenshinUID网页控制台',
|
||||||
language='zh_CN',
|
language='zh_CN',
|
||||||
)
|
)
|
||||||
quart = get_bot().server_app
|
|
||||||
quart.asgi_app = FastApiMiddleware(quart, app, {'/genshinuid'}) # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
# 显示主键
|
# 显示主键
|
||||||
@ -152,16 +190,13 @@ admin.BaseModelAdmin.get_create_form = patched_get_create_form
|
|||||||
# 创建AdminSite实例
|
# 创建AdminSite实例
|
||||||
site = GenshinUIDAdminSite(settings)
|
site = GenshinUIDAdminSite(settings)
|
||||||
auth = site.auth
|
auth = site.auth
|
||||||
config = get_bot().config
|
|
||||||
|
|
||||||
if float(fastapi_amis_admin.__version__[:3]) >= 0.3:
|
if float(fastapi_amis_admin.__version__[:3]) >= 0.3:
|
||||||
|
|
||||||
class MyUser(User, table=True):
|
class MyUser(User, table=True):
|
||||||
point: float = Field(default=0, title=_('Point')) # type: ignore
|
point: float = Field(default=0, title=_('Point')) # type: ignore
|
||||||
phone: str = Field(None, title=_('Tel'), max_length=15) # type: ignore
|
phone: str = Field(None, title=_('Tel'), max_length=15) # type: ignore
|
||||||
parent_id: int = Field(
|
parent_id: int = Field(None, title=_('Parent'), foreign_key='auth_user.id') # type: ignore
|
||||||
None, title=_('Parent'), foreign_key='auth_user.id' # type: ignore
|
|
||||||
)
|
|
||||||
children: List['User'] = Relationship(
|
children: List['User'] = Relationship(
|
||||||
sa_relationship_kwargs=dict(
|
sa_relationship_kwargs=dict(
|
||||||
backref=backref('parent', remote_side='User.id'),
|
backref=backref('parent', remote_side='User.id'),
|
||||||
@ -170,9 +205,10 @@ if float(fastapi_amis_admin.__version__[:3]) >= 0.3:
|
|||||||
|
|
||||||
auth.user_model = MyUser
|
auth.user_model = MyUser
|
||||||
|
|
||||||
|
config = get_driver().config
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=[f'http://{config.HOST}:{config.PORT}/genshinuid'],
|
allow_origins=[f'http://{config.host}:{config.port}'],
|
||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=['*'],
|
allow_methods=['*'],
|
||||||
allow_headers=['*'],
|
allow_headers=['*'],
|
||||||
@ -180,12 +216,17 @@ app.add_middleware(
|
|||||||
|
|
||||||
gsuid_webconsole_help = '''
|
gsuid_webconsole_help = '''
|
||||||
## 初次使用
|
## 初次使用
|
||||||
|
|
||||||
欢迎进入网页控制台!
|
欢迎进入网页控制台!
|
||||||
|
|
||||||
Admin账户可以通过左侧的选项进入不同的数据库直接修改,**首次登陆的Admin账户别忘了修改你的密码!**
|
Admin账户可以通过左侧的选项进入不同的数据库直接修改,**首次登陆的Admin账户别忘了修改你的密码!**
|
||||||
|
|
||||||
普通账户可以通过左侧的选项进行绑定CK或者SK
|
普通账户可以通过左侧的选项进行绑定CK或者SK
|
||||||
|
|
||||||
未来还会加入更多功能!
|
未来还会加入更多功能!
|
||||||
|
|
||||||
## 丨我该如何获取Cookies?[#92](https://github.com/KimigaiiWuyi/GenshinUID/issues/92)([@RemKeeper](https://github.com/RemKeeper))
|
## 丨我该如何获取Cookies?[#92](https://github.com/KimigaiiWuyi/GenshinUID/issues/92)([@RemKeeper](https://github.com/RemKeeper))
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var cookie = document.cookie;
|
var cookie = document.cookie;
|
||||||
var Str_Num = cookie.indexOf('_MHYUUID=');
|
var Str_Num = cookie.indexOf('_MHYUUID=');
|
||||||
@ -198,12 +239,16 @@ if (ask == true) {
|
|||||||
msg = 'Cancel'
|
msg = 'Cancel'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
1. 复制上面全部代码,然后打开[米游社BBS](https://bbs.mihoyo.com/ys/)
|
1. 复制上面全部代码,然后打开[米游社BBS](https://bbs.mihoyo.com/ys/)
|
||||||
2. 在页面上右键检查或者Ctrl+Shift+i
|
2. 在页面上右键检查或者Ctrl+Shift+i
|
||||||
3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
|
3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
|
||||||
4. 然后在和机器人的私聊窗口,粘贴发送即可
|
4. 然后在和机器人的私聊窗口,粘贴发送即可
|
||||||
|
|
||||||
**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
|
**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
|
||||||
|
|
||||||
## 丨获取米游社Stoken([AutoMihoyoBBS](https://github.com/Womsxd/AutoMihoyoBBS#%E8%8E%B7%E5%8F%96%E7%B1%B3%E6%B8%B8%E7%A4%BECookie))
|
## 丨获取米游社Stoken([AutoMihoyoBBS](https://github.com/Womsxd/AutoMihoyoBBS#%E8%8E%B7%E5%8F%96%E7%B1%B3%E6%B8%B8%E7%A4%BECookie))
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var cookie = document.cookie;
|
var cookie = document.cookie;
|
||||||
var ask = confirm('Cookie:' + cookie + '按确认,然后粘贴至Cookies或者Login_ticket选框内');
|
var ask = confirm('Cookie:' + cookie + '按确认,然后粘贴至Cookies或者Login_ticket选框内');
|
||||||
@ -214,10 +259,12 @@ if (ask == true) {
|
|||||||
msg = 'Cancel'
|
msg = 'Cancel'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
1. 复制上面全部代码,然后打开[米游社账户登录界面](http://user.mihoyo.com/)
|
1. 复制上面全部代码,然后打开[米游社账户登录界面](http://user.mihoyo.com/)
|
||||||
2. 在页面上右键检查或者Ctrl+Shift+i
|
2. 在页面上右键检查或者Ctrl+Shift+i
|
||||||
3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
|
3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
|
||||||
4. 然后在和机器人的私聊窗口,粘贴发送即可
|
4. 然后在和机器人的私聊窗口,粘贴发送即可
|
||||||
|
|
||||||
**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
|
**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
|
||||||
|
|
||||||
## 获取CK通则
|
## 获取CK通则
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
from typing import TypeVar, Callable
|
|
||||||
|
|
||||||
T_Wrapped = TypeVar("T_Wrapped", bound=Callable)
|
|
||||||
|
|
||||||
|
|
||||||
def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
|
|
||||||
"""标记一个方法为父类 interface 的 implement"""
|
|
||||||
|
|
||||||
def overrider(func: T_Wrapped) -> T_Wrapped:
|
|
||||||
assert func.__name__ in dir(
|
|
||||||
InterfaceClass
|
|
||||||
), f"Error method: {func.__name__}"
|
|
||||||
return func
|
|
||||||
|
|
||||||
return overrider
|
|
@ -1,161 +1,269 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from nonebot import MessageSegment
|
from nonebot import on_command
|
||||||
from hoshino.typing import CQEvent, HoshinoBot
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot.params import CommandArg
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
|
||||||
from ..base import sv
|
from ..config import priority
|
||||||
|
from ..genshinuid_meta import register_menu
|
||||||
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
from .get_wiki_text import (
|
from .get_wiki_text import (
|
||||||
char_wiki,
|
char_wiki,
|
||||||
audio_wiki,
|
|
||||||
foods_wiki,
|
foods_wiki,
|
||||||
weapon_wiki,
|
weapon_wiki,
|
||||||
enemies_wiki,
|
enemies_wiki,
|
||||||
artifacts_wiki,
|
artifacts_wiki,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
get_weapon = on_command('武器', priority=priority)
|
||||||
|
get_char = on_command('角色', priority=priority)
|
||||||
|
get_cost = on_command('材料', priority=priority)
|
||||||
|
get_polar = on_command('命座', priority=priority)
|
||||||
|
get_talents = on_command('天赋', priority=priority)
|
||||||
|
get_enemies = on_command('原魔', priority=priority)
|
||||||
|
get_audio = on_command('语音', priority=priority)
|
||||||
|
get_artifacts = on_command('圣遗物', priority=priority)
|
||||||
|
get_food = on_command('食物', priority=priority)
|
||||||
|
|
||||||
@sv.on_prefix('语音')
|
# 语音暂时不支持
|
||||||
async def send_audio(bot: HoshinoBot, ev: CQEvent):
|
'''
|
||||||
if ev.message:
|
@get_audio.handle()
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
@handle_exception('语音', '语音发送失败,可能是FFmpeg环境未配置。')
|
||||||
else:
|
@register_menu(
|
||||||
return
|
'角色语音',
|
||||||
if message == '':
|
'语音[ID]',
|
||||||
return
|
'获取角色语音',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'获取角色语音\n'
|
||||||
|
'获取语言ID列表请使用指令 <ft color=(238,120,0)>语音列表</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>语音{列表|</ft>'
|
||||||
|
'<ft color=(0,148,200)>[语音ID]</ft>'
|
||||||
|
'<ft color=(238,120,0)>}</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_audio(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||||
im = await audio_wiki(name, message)
|
im = await audio_wiki(name, message)
|
||||||
if name == '列表':
|
if name == '列表':
|
||||||
await bot.send(ev, MessageSegment.image(im))
|
await matcher.finish(MessageSegment.image(im))
|
||||||
else:
|
else:
|
||||||
if isinstance(im, str):
|
if isinstance(im, str):
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
else:
|
else:
|
||||||
await bot.send(ev, MessageSegment.record(im))
|
await matcher.finish(MessageSegment.record(im))
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('原魔')
|
@get_enemies.handle()
|
||||||
async def send_enemies(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('怪物')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'怪物图鉴',
|
||||||
else:
|
'怪物xx',
|
||||||
return
|
'获取怪物Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取怪物Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>怪物</ft><ft color=(0,148,200)>[怪物名称]</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_enemies(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
im = await enemies_wiki(message)
|
im = await enemies_wiki(message)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('食物')
|
@get_food.handle()
|
||||||
async def send_food(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('食物')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'食物图鉴',
|
||||||
else:
|
'食物xx',
|
||||||
return
|
'获取食物Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取食物Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>食物</ft><ft color=(0,148,200)>[食物名称]</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_food(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
im = await foods_wiki(message)
|
im = await foods_wiki(message)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('圣遗物')
|
@get_artifacts.handle()
|
||||||
async def send_artifacts(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('圣遗物')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'圣遗物图鉴',
|
||||||
else:
|
'圣遗物xx',
|
||||||
return
|
'获取怪物Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取圣遗物Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>圣遗物</ft><ft color=(0,148,200)>[圣遗物名称]</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_artifacts(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
im = await artifacts_wiki(message)
|
im = await artifacts_wiki(message)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('武器')
|
@get_weapon.handle()
|
||||||
async def send_weapon(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('武器')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'武器图鉴',
|
||||||
else:
|
'武器xx',
|
||||||
return
|
'获取武器Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取武器Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>武器</ft><ft color=(0,148,200)>[武器名称]</ft>'
|
||||||
|
'<ft color=(125,125,125)>(级数)</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>武器雾切</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>武器无工之剑90</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_weapon(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||||
level = re.findall(r'\d+', message)
|
level = re.findall(r'\d+', message)
|
||||||
if len(level) == 1:
|
if len(level) == 1:
|
||||||
im = await weapon_wiki(name, level=level[0])
|
im = await weapon_wiki(name, level=level[0])
|
||||||
else:
|
else:
|
||||||
im = await weapon_wiki(name)
|
im = await weapon_wiki(name)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('天赋')
|
# 天赋暂时不支持
|
||||||
async def send_talents(bot: HoshinoBot, ev: CQEvent):
|
'''
|
||||||
if ev.message:
|
@get_talents.handle()
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
@handle_exception('天赋')
|
||||||
else:
|
@register_menu(
|
||||||
return
|
'天赋效果',
|
||||||
if message == '':
|
'天赋[角色][天赋序号]',
|
||||||
return
|
'查询角色天赋技能效果',
|
||||||
|
detail_des=(
|
||||||
|
'介绍:\n'
|
||||||
|
'查询角色天赋技能效果\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>天赋</ft>'
|
||||||
|
'<ft color=(0,148,200)>[角色名称][天赋序号]</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>天赋绫华2</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_talents(
|
||||||
|
bot: Bot,
|
||||||
|
matcher: Matcher,
|
||||||
|
args: Message = CommandArg(),
|
||||||
|
):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||||
num = re.findall(r'\d+', message)
|
num = re.findall(r'\d+', message)
|
||||||
if len(num) == 1:
|
if len(num) == 1:
|
||||||
im = await char_wiki(name, 'talents', num[0])
|
im = await char_wiki(name, 'talents', num[0])
|
||||||
if isinstance(im, list):
|
if isinstance(im, list):
|
||||||
await bot.send_group_forward_msg(group_id=ev.group_id, messages=im)
|
await bot.call_api(
|
||||||
return
|
'send_group_forward_msg', group_id=event.group_id, messages=im
|
||||||
|
)
|
||||||
|
await matcher.finish()
|
||||||
else:
|
else:
|
||||||
im = '参数不正确。'
|
im = '参数不正确。'
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('角色')
|
@get_char.handle()
|
||||||
async def send_char(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('角色')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'角色图鉴',
|
||||||
else:
|
'角色xx',
|
||||||
return
|
'获取角色Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取角色Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>角色</ft><ft color=(0,148,200)>[角色名称]</ft>'
|
||||||
|
'<ft color=(125,125,125)>(等级)</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>角色可莉</ft>\n'
|
||||||
|
'- <ft color=(238,120,0)>角色可莉90</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_char(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||||
level = re.findall(r'\d+', message)
|
level = re.findall(r'\d+', message)
|
||||||
if len(level) == 1:
|
if len(level) == 1:
|
||||||
im = await char_wiki(name, 'char', level=level[0])
|
im = await char_wiki(name, 'char', level=level[0])
|
||||||
else:
|
else:
|
||||||
im = await char_wiki(name)
|
im = await char_wiki(name)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('材料')
|
@get_cost.handle()
|
||||||
async def send_cost(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('材料')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'材料图鉴',
|
||||||
else:
|
'材料xx',
|
||||||
return
|
'获取材料Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取材料Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>材料</ft><ft color=(0,148,200)>[材料名称]</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_cost(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
im = await char_wiki(message, 'costs')
|
im = await char_wiki(message, 'costs')
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
|
||||||
|
|
||||||
@sv.on_prefix('命座')
|
@get_polar.handle()
|
||||||
async def send_polar(bot: HoshinoBot, ev: CQEvent):
|
@handle_exception('命座')
|
||||||
if ev.message:
|
@register_menu(
|
||||||
message = ev.message.extract_plain_text().replace(' ', '')
|
'角色命座图鉴',
|
||||||
else:
|
'命座[角色][等级]',
|
||||||
return
|
'获取角色命座Wiki',
|
||||||
if message == '':
|
detail_des=(
|
||||||
return
|
'介绍:\n'
|
||||||
|
'获取角色命座Wiki\n'
|
||||||
|
' \n'
|
||||||
|
'指令:\n'
|
||||||
|
'- <ft color=(238,120,0)>命座</ft>'
|
||||||
|
'<ft color=(0,148,200)>[角色名称][命座等级]</ft>\n'
|
||||||
|
' \n'
|
||||||
|
'示例:\n'
|
||||||
|
'- <ft color=(238,120,0)>命座胡桃1</ft>'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def send_polar(matcher: Matcher, args: Message = CommandArg()):
|
||||||
|
message = args.extract_plain_text().strip().replace(' ', '')
|
||||||
num = int(re.findall(r'\d+', message)[0]) # str
|
num = int(re.findall(r'\d+', message)[0]) # str
|
||||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||||
if num <= 0 or num > 6:
|
if num <= 0 or num > 6:
|
||||||
await bot.send(ev, '你家{}有{}命?'.format(m, num))
|
await get_polar.finish('你家{}有{}命?'.format(m, num))
|
||||||
return
|
return
|
||||||
im = await char_wiki(m, 'constellations', num)
|
im = await char_wiki(m, 'constellations', num)
|
||||||
await bot.send(ev, im)
|
await matcher.finish(im)
|
||||||
|
@ -2,22 +2,34 @@ import random
|
|||||||
import asyncio
|
import asyncio
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from ..base import sv, logger
|
from nonebot import on_command
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot.matcher import Matcher
|
||||||
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
from nonebot.adapters.ntchat import MessageSegment
|
||||||
|
|
||||||
from .draw_abyss_total import TOTAL_IMG, draw_xk_abyss_img
|
from .draw_abyss_total import TOTAL_IMG, draw_xk_abyss_img
|
||||||
from ..utils.draw_image_tools.send_image_tool import convert_img
|
from ..utils.exception.handle_exception import handle_exception
|
||||||
|
|
||||||
|
draw_total_scheduler = scheduler
|
||||||
|
get_abyss_total = on_command('深渊概览', aliases={'深渊统计', '深渊使用率'})
|
||||||
|
|
||||||
|
|
||||||
@sv.scheduled_job('interval', hours=3)
|
@draw_total_scheduler.scheduled_job('interval', hours=3)
|
||||||
async def scheduled_draw_abyss():
|
async def scheduled_draw_abyss():
|
||||||
await asyncio.sleep(random.randint(0, 60))
|
await asyncio.sleep(random.randint(0, 60))
|
||||||
await draw_xk_abyss_img()
|
await draw_xk_abyss_img()
|
||||||
|
|
||||||
|
|
||||||
@sv.on_fullmatch(('深渊概览', '深渊统计', '深渊使用率'))
|
@get_abyss_total.handle()
|
||||||
async def send_abyss_pic(bot, ev):
|
@handle_exception('深渊概览')
|
||||||
img = await convert_img(TOTAL_IMG)
|
async def send_guide_pic(matcher: Matcher):
|
||||||
logger.info('获得gs帮助图片成功!')
|
if TOTAL_IMG.exists():
|
||||||
await bot.send(ev, img)
|
logger.info('获得深渊概览成功!')
|
||||||
|
with open(TOTAL_IMG, 'rb') as f:
|
||||||
|
await matcher.finish(MessageSegment.image(f.read()))
|
||||||
|
else:
|
||||||
|
await matcher.finish('深渊概览图不存在!')
|
||||||
|
|
||||||
|
|
||||||
threading.Thread(
|
threading.Thread(
|
||||||
|
@ -11,7 +11,7 @@ class UidDataDAL:
|
|||||||
def __init__(self, db_session: Session):
|
def __init__(self, db_session: Session):
|
||||||
self.db_session = db_session
|
self.db_session = db_session
|
||||||
|
|
||||||
async def get_user_data(self, userid: int) -> Optional[UidData]:
|
async def get_user_data(self, userid: str) -> Optional[UidData]:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
获取用户的绑定信息
|
获取用户的绑定信息
|
||||||
@ -37,7 +37,7 @@ class UidDataDAL:
|
|||||||
bind_list.append(item.__dict__)
|
bind_list.append(item.__dict__)
|
||||||
return bind_list
|
return bind_list
|
||||||
|
|
||||||
async def user_exists(self, userid: int) -> bool:
|
async def user_exists(self, userid: str) -> bool:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
是否存在用户的绑定信息
|
是否存在用户的绑定信息
|
||||||
@ -67,7 +67,7 @@ class UidDataDAL:
|
|||||||
uid_list.extend(item.UID.split("_"))
|
uid_list.extend(item.UID.split("_"))
|
||||||
return uid_list
|
return uid_list
|
||||||
|
|
||||||
async def get_uid_list(self, userid: int) -> List[str]:
|
async def get_uid_list(self, userid: str) -> List[str]:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
获得用户的绑定UID列表
|
获得用户的绑定UID列表
|
||||||
@ -83,7 +83,7 @@ class UidDataDAL:
|
|||||||
return uid_list
|
return uid_list
|
||||||
return []
|
return []
|
||||||
|
|
||||||
async def get_uid(self, userid: int) -> str:
|
async def get_uid(self, userid: str) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
获得用户绑定的UID
|
获得用户绑定的UID
|
||||||
@ -98,14 +98,14 @@ class UidDataDAL:
|
|||||||
else:
|
else:
|
||||||
return '未找到绑定的UID~'
|
return '未找到绑定的UID~'
|
||||||
|
|
||||||
async def switch_uid(self, userid: int, uid: Optional[str] = None) -> str:
|
async def switch_uid(self, userid: str, uid: Optional[str] = None) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
切换绑定的UID列表,绑定一个UID的情况下返回无法切换
|
切换绑定的UID列表,绑定一个UID的情况下返回无法切换
|
||||||
切换前 -> 12_13_14
|
切换前 -> 12_13_14
|
||||||
切换后 -> 13_12_14
|
切换后 -> 13_12_14
|
||||||
:参数:
|
:参数:
|
||||||
* userid (int): QQ号。
|
* userid (int): WX号。
|
||||||
* uid (str): 切换的UID, 可选, 不传入的话自动切换下一个。
|
* uid (str): 切换的UID, 可选, 不传入的话自动切换下一个。
|
||||||
:返回:
|
:返回:
|
||||||
* msg (str): 回调信息。
|
* msg (str): 回调信息。
|
||||||
@ -126,7 +126,7 @@ class UidDataDAL:
|
|||||||
else:
|
else:
|
||||||
return '你还没有绑定过UID噢~'
|
return '你还没有绑定过UID噢~'
|
||||||
|
|
||||||
async def get_mysid_list(self, userid: int) -> List[str]:
|
async def get_mysid_list(self, userid: str) -> List[str]:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
获得用户的绑定MYSID列表
|
获得用户的绑定MYSID列表
|
||||||
@ -142,7 +142,7 @@ class UidDataDAL:
|
|||||||
return mys_list
|
return mys_list
|
||||||
return []
|
return []
|
||||||
|
|
||||||
async def get_mysid(self, userid: int) -> str:
|
async def get_mysid(self, userid: str) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
获得用户绑定的MYSID
|
获得用户绑定的MYSID
|
||||||
@ -157,7 +157,7 @@ class UidDataDAL:
|
|||||||
else:
|
else:
|
||||||
return "未找到绑定的MYSID~"
|
return "未找到绑定的MYSID~"
|
||||||
|
|
||||||
async def get_anyid(self, userid: int) -> str:
|
async def get_anyid(self, userid: str) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
获得用户绑定的ID信息
|
获得用户绑定的ID信息
|
||||||
@ -176,7 +176,7 @@ class UidDataDAL:
|
|||||||
else:
|
else:
|
||||||
return '未找到绑定的ID信息~'
|
return '未找到绑定的ID信息~'
|
||||||
|
|
||||||
async def bind_db(self, userid: int, data: dict) -> str:
|
async def bind_db(self, userid: str, data: dict) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
绑定UID或者MYSID
|
绑定UID或者MYSID
|
||||||
@ -229,7 +229,7 @@ class UidDataDAL:
|
|||||||
await self.db_session.flush() # type: ignore
|
await self.db_session.flush() # type: ignore
|
||||||
return _bind
|
return _bind
|
||||||
|
|
||||||
async def delete_db(self, userid: int, data: Optional[dict]) -> str:
|
async def delete_db(self, userid: str, data: Optional[dict]) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
删除用户的绑定UID或者MYSID
|
删除用户的绑定UID或者MYSID
|
||||||
@ -284,7 +284,7 @@ class UidDataDAL:
|
|||||||
|
|
||||||
async def update_db(
|
async def update_db(
|
||||||
self,
|
self,
|
||||||
userid: int,
|
userid: str,
|
||||||
data: Optional[dict],
|
data: Optional[dict],
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -33,7 +33,7 @@ class PushData(SQLModel, table=True):
|
|||||||
|
|
||||||
class UidData(SQLModel, table=True):
|
class UidData(SQLModel, table=True):
|
||||||
__table_args__ = {'keep_existing': True}
|
__table_args__ = {'keep_existing': True}
|
||||||
USERID: int = Field(default=100000000, primary_key=True, title='QQ号')
|
USERID: str = Field(default='WX_100001', primary_key=True, title='WX号')
|
||||||
UID: Optional[str] = Field(title='UID')
|
UID: Optional[str] = Field(title='UID')
|
||||||
MYSID: Optional[str] = Field(title='米游社通行证(废弃)')
|
MYSID: Optional[str] = Field(title='米游社通行证(废弃)')
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class NewCookiesTable(SQLModel, table=True):
|
|||||||
__table_args__ = {'keep_existing': True}
|
__table_args__ = {'keep_existing': True}
|
||||||
UID: int = Field(default=100000000, primary_key=True, title='UID')
|
UID: int = Field(default=100000000, primary_key=True, title='UID')
|
||||||
Cookies: str = Field(title='CK')
|
Cookies: str = Field(title='CK')
|
||||||
QID: int = Field(title='QQ号')
|
QID: str = Field(title='QQ号')
|
||||||
StatusA: str = Field(title='全局推送开关')
|
StatusA: str = Field(title='全局推送开关')
|
||||||
StatusB: str = Field(title='自动签到')
|
StatusB: str = Field(title='自动签到')
|
||||||
StatusC: str = Field(title='自动米游币')
|
StatusC: str = Field(title='自动米游币')
|
||||||
|
@ -27,7 +27,9 @@ async def check_db():
|
|||||||
try:
|
try:
|
||||||
if int(str(row[0])[0]) < 6:
|
if int(str(row[0])[0]) < 6:
|
||||||
aid = re.search(r'account_id=(\d*)', row[1])
|
aid = re.search(r'account_id=(\d*)', row[1])
|
||||||
mihoyo_id_data = aid.group(0).split('=') # type: ignore
|
if not aid:
|
||||||
|
raise Exception('cannot match account_id')
|
||||||
|
mihoyo_id_data = aid.group(0).split('=')
|
||||||
mihoyo_id = mihoyo_id_data[1]
|
mihoyo_id = mihoyo_id_data[1]
|
||||||
mys_data = await get_mihoyo_bbs_info(mihoyo_id, row[1])
|
mys_data = await get_mihoyo_bbs_info(mihoyo_id, row[1])
|
||||||
for i in mys_data['data']['list']:
|
for i in mys_data['data']['list']:
|
||||||
|
@ -92,7 +92,7 @@ async def get_all_stoken() -> List:
|
|||||||
|
|
||||||
|
|
||||||
async def select_db(
|
async def select_db(
|
||||||
userid: int, mode: str = 'auto'
|
userid: str, mode: str = 'auto'
|
||||||
) -> Union[List[str], str, None]:
|
) -> Union[List[str], str, None]:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
@ -126,14 +126,14 @@ async def select_db(
|
|||||||
return im
|
return im
|
||||||
|
|
||||||
|
|
||||||
async def switch_db(userid: int, uid: Optional[str] = None) -> str:
|
async def switch_db(userid: str, uid: Optional[str] = None) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
切换绑定的UID列表,绑定一个UID的情况下返回无法切换
|
切换绑定的UID列表,绑定一个UID的情况下返回无法切换
|
||||||
切换前 -> 12_13_14
|
切换前 -> 12_13_14
|
||||||
切换后 -> 13_14_12
|
切换后 -> 13_14_12
|
||||||
:参数:
|
:参数:
|
||||||
* userid (str): QQ号。
|
* userid (str): WX号。
|
||||||
:返回:
|
:返回:
|
||||||
* im (str): 回调信息。
|
* im (str): 回调信息。
|
||||||
"""
|
"""
|
||||||
@ -144,7 +144,7 @@ async def switch_db(userid: int, uid: Optional[str] = None) -> str:
|
|||||||
return im
|
return im
|
||||||
|
|
||||||
|
|
||||||
async def delete_db(userid: int, data: dict) -> str:
|
async def delete_db(userid: str, data: dict) -> str:
|
||||||
"""
|
"""
|
||||||
:说明:
|
:说明:
|
||||||
删除当前绑定的UID信息
|
删除当前绑定的UID信息
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import hoshino
|
MAIN_PATH = Path() / 'data' / 'GenshinUID'
|
||||||
|
|
||||||
MAIN_PATH = Path(hoshino.config.RES_DIR) / 'GenshinUID'
|
|
||||||
sys.path.append(str(MAIN_PATH))
|
sys.path.append(str(MAIN_PATH))
|
||||||
CONFIG_PATH = MAIN_PATH / 'config.json'
|
CONFIG_PATH = MAIN_PATH / 'config.json'
|
||||||
RESOURCE_PATH = MAIN_PATH / 'resource'
|
RESOURCE_PATH = MAIN_PATH / 'resource'
|
||||||
|
@ -184,10 +184,7 @@ async def get_level_pic(level: int) -> Image.Image:
|
|||||||
async def get_qq_avatar(
|
async def get_qq_avatar(
|
||||||
qid: Optional[Union[int, str]] = None, avatar_url: Optional[str] = None
|
qid: Optional[Union[int, str]] = None, avatar_url: Optional[str] = None
|
||||||
) -> Image.Image:
|
) -> Image.Image:
|
||||||
if qid:
|
avatar_url = 'https://s2.loli.net/2022/01/31/kwCIl3cF1Z2GxnR.png'
|
||||||
avatar_url = f'http://q1.qlogo.cn/g?b=qq&nk={qid}&s=640'
|
|
||||||
elif avatar_url is None:
|
|
||||||
avatar_url = 'https://q1.qlogo.cn/g?b=qq&nk=3399214199&s=640'
|
|
||||||
char_pic = Image.open(BytesIO(get(avatar_url).content)).convert('RGBA')
|
char_pic = Image.open(BytesIO(get(avatar_url).content)).convert('RGBA')
|
||||||
return char_pic
|
return char_pic
|
||||||
|
|
||||||
|
@ -52,4 +52,4 @@ async def convert_img(
|
|||||||
else:
|
else:
|
||||||
async with aiofiles.open(img, 'rb') as fp:
|
async with aiofiles.open(img, 'rb') as fp:
|
||||||
img = await fp.read()
|
img = await fp.read()
|
||||||
return f'[CQ:image,file=base64://{b64encode(img).decode()}]'
|
return f'base64://{b64encode(img).decode()}'
|
||||||
|
@ -1,53 +1,56 @@
|
|||||||
# flake8: noqa
|
from functools import wraps
|
||||||
# from nonebot.log import logger
|
from typing import Optional
|
||||||
# from aiocqhttp.exceptions import ActionFailed
|
|
||||||
# from hoshino.typing import List, CQEvent, Iterable
|
|
||||||
|
|
||||||
# FIXME: - 在 Hoshino 中可用
|
from nonebot.log import logger
|
||||||
# def handle_exception(name: str, log_msg: str = None, fail_msg: str = None): # type: ignore
|
from nonebot.matcher import Matcher
|
||||||
# """
|
from nonebot.exception import FinishedException
|
||||||
# :说明:
|
|
||||||
# 捕获命令执行过程中发生的异常并回报。
|
|
||||||
# :参数:
|
|
||||||
# * ``name: str``: 项目的名称。
|
|
||||||
# * ``log_msg: str = None``: 自定义捕获异常后在日志中留存的信息。留空则使用默认信息。
|
|
||||||
# * ``fail_msg: str = None``: 自定义捕获异常后向用户回报的信息,仅在提供自定义日志信息时有效。开头带@则艾特用户。留空则与日志信息相同。
|
|
||||||
# """
|
|
||||||
|
|
||||||
# def wrapper(func):
|
|
||||||
# @wraps(func)
|
|
||||||
# async def inner(
|
|
||||||
# log_msg: str = log_msg, fail_msg: str = fail_msg, **kwargs
|
|
||||||
# ):
|
|
||||||
# print(kwargs)
|
|
||||||
# matcher: CQEvent = kwargs['matcher']
|
|
||||||
# try:
|
|
||||||
# await func(**kwargs)
|
|
||||||
# except ActionFailed as e:
|
|
||||||
# # 此为bot本身由于风控或网络问题发不出消息,并非代码本身出问题
|
|
||||||
# await matcher.send(f'发送消息失败{e.result["wording"]}')
|
|
||||||
# logger.exception(f'发送{name}消息失败')
|
|
||||||
# except Exception as e:
|
|
||||||
# # 如果e内包含敏感信息,应在此处进行处理
|
|
||||||
# if 'SQL' in str(e):
|
|
||||||
# e = '数据库操作失败!可能正在[校验全部Cookies]\n敏感信息已抹去...请等待一段时间后重试!'
|
|
||||||
# # 代码本身出问题
|
|
||||||
# if log_msg:
|
|
||||||
# if not fail_msg:
|
|
||||||
# fail_msg = log_msg
|
|
||||||
# if fail_msg[0] == '@':
|
|
||||||
# await matcher.send(
|
|
||||||
# f'{fail_msg[1:]}\n错误信息为{e}', at_sender=True
|
|
||||||
# )
|
|
||||||
# else:
|
|
||||||
# await matcher.send(f'{fail_msg}\n错误信息为{e}')
|
|
||||||
# if log_msg[0] == '@':
|
|
||||||
# log_msg = log_msg[1:]
|
|
||||||
# logger.exception(log_msg)
|
|
||||||
# else:
|
|
||||||
# await matcher.send(f'发生错误 {e},请检查后台输出。')
|
|
||||||
# logger.exception(f'获取{name}信息错误')
|
|
||||||
|
|
||||||
# return inner
|
def handle_exception(
|
||||||
|
name: str, log_msg: Optional[str] = None, fail_msg: Optional[str] = None
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
:说明:
|
||||||
|
捕获命令执行过程中发生的异常并回报。
|
||||||
|
:参数:
|
||||||
|
* ``name: str``: 项目的名称。
|
||||||
|
* ``log_msg: str = None``: 自定义捕获异常后在日志中留存的信息。留空则使用默认信息。
|
||||||
|
* ``fail_msg: str = None``: 自定义捕获异常后向用户回报的信息,仅在提供自定义日志信息时有效。
|
||||||
|
开头带@则艾特用户。留空则与日志信息相同。
|
||||||
|
"""
|
||||||
|
|
||||||
# return wrapper
|
def wrapper(func):
|
||||||
|
@wraps(func)
|
||||||
|
async def inner(
|
||||||
|
log_msg: Optional[str] = log_msg,
|
||||||
|
fail_msg: Optional[str] = fail_msg,
|
||||||
|
**kwargs,
|
||||||
|
):
|
||||||
|
matcher: Matcher = kwargs['matcher']
|
||||||
|
try:
|
||||||
|
await func(**kwargs)
|
||||||
|
except FinishedException:
|
||||||
|
# `finish` 会抛出此异常,应予以抛出而不处理
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
# 如果e内包含敏感信息,应在此处进行处理
|
||||||
|
if 'SQL' in str(e):
|
||||||
|
e = '数据库操作失败!可能正在[校验全部Cookies]\n敏感信息已抹去...请等待一段时间后重试!'
|
||||||
|
# 代码本身出问题
|
||||||
|
if log_msg:
|
||||||
|
if not fail_msg:
|
||||||
|
fail_msg = log_msg
|
||||||
|
if fail_msg[0] == '@':
|
||||||
|
await matcher.send(f'{fail_msg[1:]}\n错误信息为{e}')
|
||||||
|
else:
|
||||||
|
await matcher.send(f'{fail_msg}\n错误信息为{e}')
|
||||||
|
if log_msg[0] == '@':
|
||||||
|
log_msg = log_msg[1:]
|
||||||
|
logger.exception(log_msg)
|
||||||
|
else:
|
||||||
|
await matcher.send(f'发生错误 {e},请检查后台输出。')
|
||||||
|
logger.exception(f'获取{name}信息错误')
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from nonebot.adapters.ntchat import Bot
|
||||||
|
|
||||||
async def get_all_friend_list(bot) -> List[int]:
|
|
||||||
|
async def get_all_friend_list(bot: Bot) -> List[int]:
|
||||||
friend_list = []
|
friend_list = []
|
||||||
friend_dict_list = await bot.call_action(action='get_friend_list')
|
friend_dict_list = await bot.call_api('get_contacts')
|
||||||
for friend in friend_dict_list:
|
for friend in friend_dict_list:
|
||||||
friend_list.append(friend['user_id'])
|
friend_list.append(friend['user_id'])
|
||||||
return friend_list
|
return friend_list
|
||||||
|
|
||||||
|
|
||||||
async def get_group_member_list(bot, group_id: int) -> List[int]:
|
async def get_group_member_list(bot: Bot, group_id: int) -> List[int]:
|
||||||
member_list = []
|
member_list = []
|
||||||
group_member_list = await bot.call_api(
|
group_member_list = await bot.call_api(
|
||||||
action='get_group_member_list', group_id=group_id
|
'get_room_members', group_id=group_id
|
||||||
)
|
)
|
||||||
for group_member in group_member_list:
|
for group_member in group_member_list:
|
||||||
member_list.append(group_member['user_id'])
|
member_list.append(group_member['user_id'])
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||||
|
|
||||||
|
|
||||||
# https://v2.nonebot.dev/docs/advanced/di/dependency-injection#class-%E4%BD%9C%E4%B8%BA%E4%BE%9D%E8%B5%96
|
# https://v2.nonebot.dev/docs/advanced/di/dependency-injection#class-%E4%BD%9C%E4%B8%BA%E4%BE%9D%E8%B5%96
|
||||||
class ImageAndAt:
|
class ImageAndAt:
|
||||||
def __init__(self, event):
|
def __init__(self, event: MessageEvent):
|
||||||
self.images = []
|
self.images = []
|
||||||
self.at = []
|
self.at = []
|
||||||
for i in event.message:
|
for i in event.message:
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from ...base import hoshino_bot
|
from nonebot.adapters.qqguild import Bot
|
||||||
|
|
||||||
|
|
||||||
# 发送聊天记录
|
# 发送聊天记录
|
||||||
async def send_forward_msg(
|
async def send_forward_msg(
|
||||||
bot: hoshino_bot,
|
bot: Bot,
|
||||||
group_id: int,
|
userid: int,
|
||||||
name: str,
|
name: str,
|
||||||
uin: str,
|
uin: str,
|
||||||
msgs: List[str],
|
msgs: List[str],
|
||||||
@ -18,6 +18,6 @@ async def send_forward_msg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
messages = [to_json(msg) for msg in msgs]
|
messages = [to_json(msg) for msg in msgs]
|
||||||
await bot.call_action(
|
await bot.call_api(
|
||||||
action='send_group_forward_msg', group_id=group_id, messages=messages
|
"send_private_forward_msg", user_id=userid, messages=messages
|
||||||
)
|
)
|
||||||
|
@ -877,7 +877,7 @@ async def fetchgoods():
|
|||||||
return goodslist["data"]["goods_list"]
|
return goodslist["data"]["goods_list"]
|
||||||
|
|
||||||
|
|
||||||
async def topup(uid, goods):
|
async def topup(uid, goods, method):
|
||||||
device_id = str(uuid.uuid4())
|
device_id = str(uuid.uuid4())
|
||||||
HEADER = copy.deepcopy(_HEADER)
|
HEADER = copy.deepcopy(_HEADER)
|
||||||
HEADER["Cookie"] = await owner_cookies(uid)
|
HEADER["Cookie"] = await owner_cookies(uid)
|
||||||
@ -902,7 +902,7 @@ async def topup(uid, goods):
|
|||||||
"price_tier": goods["tier_id"],
|
"price_tier": goods["tier_id"],
|
||||||
# "price_tier": "Tier_1",
|
# "price_tier": "Tier_1",
|
||||||
"currency": "CNY",
|
"currency": "CNY",
|
||||||
"pay_plat": "alipay",
|
"pay_plat": method,
|
||||||
}
|
}
|
||||||
data = {"order": order, "sign": gen_payment_sign(order)}
|
data = {"order": order, "sign": gen_payment_sign(order)}
|
||||||
HEADER["x-rpc-device_id"] = device_id
|
HEADER["x-rpc-device_id"] = device_id
|
||||||
|
15
GenshinUID/utils/nonebot2/rule.py
Normal file
15
GenshinUID/utils/nonebot2/rule.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from nonebot.rule import Rule
|
||||||
|
from nonebot.params import Depends, CommandArg
|
||||||
|
from nonebot.adapters.ntchat.message import Message
|
||||||
|
|
||||||
|
|
||||||
|
async def full_command(arg: Message = CommandArg()) -> bool:
|
||||||
|
return not bool(str(arg))
|
||||||
|
|
||||||
|
|
||||||
|
def FullCommand() -> Rule:
|
||||||
|
return Rule(full_command)
|
||||||
|
|
||||||
|
|
||||||
|
def FullCommandDepend():
|
||||||
|
return Depends(full_command)
|
15
GenshinUID/utils/nonebot2/utils.py
Normal file
15
GenshinUID/utils/nonebot2/utils.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
from nonebot import get_driver
|
||||||
|
|
||||||
|
|
||||||
|
def get_superusers() -> List[int]:
|
||||||
|
config = get_driver().config
|
||||||
|
superusers: List[int] = []
|
||||||
|
for su in config.superusers:
|
||||||
|
if "onebot:" in su:
|
||||||
|
# su[7:] == onebot:
|
||||||
|
su = su[7:]
|
||||||
|
if su.isdigit():
|
||||||
|
superusers.append(int(su))
|
||||||
|
return superusers
|
12
__init__.py
12
__init__.py
@ -3,11 +3,11 @@ import shutil
|
|||||||
from typing import List
|
from typing import List
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import hoshino
|
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
from nonebot import load_plugins
|
from nonebot import require, load_plugins
|
||||||
|
|
||||||
dir_ = Path(__file__).parent
|
dir_ = Path(__file__).parent
|
||||||
|
require('nonebot_plugin_apscheduler')
|
||||||
|
|
||||||
|
|
||||||
def copy_and_delete_files():
|
def copy_and_delete_files():
|
||||||
@ -27,7 +27,7 @@ def copy_and_delete_files():
|
|||||||
elif path.name in {"resource", "player"}:
|
elif path.name in {"resource", "player"}:
|
||||||
dst = Path().joinpath(
|
dst = Path().joinpath(
|
||||||
(
|
(
|
||||||
hoshino.config.RES_DIR + "/GenshinUID/"
|
"data/GenshinUID/"
|
||||||
f"{'players' if path.name == 'player' else path.name}"
|
f"{'players' if path.name == 'player' else path.name}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -37,7 +37,7 @@ def copy_and_delete_files():
|
|||||||
dst,
|
dst,
|
||||||
dirs_exist_ok=True,
|
dirs_exist_ok=True,
|
||||||
)
|
)
|
||||||
logger.info(f"复制文件夹 {path} -> {dst} 成功")
|
logger.success(f"复制文件夹 {path} -> {dst} 成功")
|
||||||
except shutil.Error as e:
|
except shutil.Error as e:
|
||||||
failed_src: List[Path] = []
|
failed_src: List[Path] = []
|
||||||
exc: str
|
exc: str
|
||||||
@ -56,10 +56,10 @@ def copy_and_delete_files():
|
|||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
logger.info(f"删除文件夹 {path} 成功")
|
logger.success(f"删除文件夹 {path} 成功")
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.warning(f"删除文件夹 {path} 失败:{e.strerror}")
|
logger.warning(f"删除文件夹 {path} 失败:{e.strerror}")
|
||||||
|
|
||||||
|
|
||||||
copy_and_delete_files()
|
copy_and_delete_files()
|
||||||
load_plugins(str(dir_ / 'GenshinUID'), 'hoshino.modules.GenshinUID.GenshinUID')
|
load_plugins(str(dir_ / "GenshinUID"))
|
||||||
|
14
deploy/.env.dev
Normal file
14
deploy/.env.dev
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# 配置 NoneBot2 监听的 IP/主机名(不建议修改)
|
||||||
|
HOST=0.0.0.0
|
||||||
|
# 配置 NoneBot2 监听的端口(不建议修改)
|
||||||
|
PORT=8080
|
||||||
|
# 配置 NoneBot 超级用户(例如你的QQ号)
|
||||||
|
SUPERUSERS=["123456789"]
|
||||||
|
# 配置命令起始字符
|
||||||
|
COMMAND_START=["/", ""]
|
||||||
|
|
||||||
|
# 建议别删下面这行
|
||||||
|
FASTAPI_RELOAD=false
|
||||||
|
# 建议别删上面这行
|
||||||
|
|
||||||
|
更多配置参见:https://v2.nonebot.dev/docs/tutorial/configuration
|
14
deploy/cookiecutter.yml
Normal file
14
deploy/cookiecutter.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
default_context:
|
||||||
|
py: py
|
||||||
|
project_name: nb2
|
||||||
|
use_src: true
|
||||||
|
adapters:
|
||||||
|
- builtin:
|
||||||
|
- module_name: "nonebot.adapters.onebot.v11"
|
||||||
|
project_link: "nonebot-adapter-onebot"
|
||||||
|
name: "OneBot V11"
|
||||||
|
desc: "OneBot V11 协议"
|
||||||
|
author: "yanyongyu"
|
||||||
|
homepage: "https://onebot.adapters.nonebot.dev/"
|
||||||
|
tags: []
|
||||||
|
is_official: true
|
21
deploy/update_pyproject.py
Normal file
21
deploy/update_pyproject.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
import tomlkit
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open("./nb2/pyproject.toml", "r", encoding="utf-8") as f:
|
||||||
|
data = tomlkit.load(f)
|
||||||
|
plugins: List[str] = data["tool"]["nonebot"]["plugins"] # type: ignore
|
||||||
|
if "GenshinUID" in plugins:
|
||||||
|
return
|
||||||
|
plugins.append("GenshinUID")
|
||||||
|
|
||||||
|
with open("./nb2/pyproject.toml", "w", encoding="utf-8") as f:
|
||||||
|
tomlkit.dump(data, f)
|
||||||
|
|
||||||
|
print("Update pyproject.toml done.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
1772
poetry.lock
generated
1772
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,34 +1,3 @@
|
|||||||
[tool.poetry]
|
|
||||||
name = "GenshinUID"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "基于HoshinoBot/NoneBot2/QQ官方频道Bot(PythonSDK)的原神Uid查询/原神Wiki/米社签到/树脂提醒插件"
|
|
||||||
authors = ["KimigaiiWuyi <444835641@qq.com>"]
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = "^3.8"
|
|
||||||
httpx = "^0.23.0"
|
|
||||||
beautifulsoup4 = "^4.11.1"
|
|
||||||
lxml = "^4.9.1"
|
|
||||||
openpyxl = "^3.0.10"
|
|
||||||
aiohttp = "^3.8.1"
|
|
||||||
SQLAlchemy = "^1.4.39"
|
|
||||||
Pillow = "^9.2.0"
|
|
||||||
aiosqlite = "^0.17.0"
|
|
||||||
sqlmodel = "^0.0.8"
|
|
||||||
GitPython = "^3.1.27"
|
|
||||||
fastapi_amis_admin = "^0.2.1"
|
|
||||||
fastapi_user_auth = "^0.2.1"
|
|
||||||
pydantic = "^1.10.2"
|
|
||||||
aiofiles = "^22.1.0"
|
|
||||||
qrcode = {extras = ["pil"], version = "^7.3.1"}
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
|
||||||
flake8 = "^4.0.1"
|
|
||||||
black = "^22.6.0"
|
|
||||||
isort = "^5.11.5"
|
|
||||||
pre-commit = "^2.20.0"
|
|
||||||
|
|
||||||
[tool.black]
|
[tool.black]
|
||||||
line-length = 79
|
line-length = 79
|
||||||
target-version = ["py38", "py39", "py310"]
|
target-version = ["py38", "py39", "py310"]
|
||||||
@ -45,10 +14,63 @@ skip_gitignore = true
|
|||||||
force_sort_within_sections = true
|
force_sort_within_sections = true
|
||||||
extra_standard_library = ["typing_extensions"]
|
extra_standard_library = ["typing_extensions"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
asyncio_mode = "auto"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[tool.poetry]
|
||||||
|
name = "GenshinUID"
|
||||||
|
version = "3.1.0"
|
||||||
|
description = "基于HoshinoBot/NoneBot2/QQ官方频道/微信Bot的原神面板查询/原神Wiki/米社签到/树脂提醒插件"
|
||||||
|
authors = ["KimigaiiWuyi <444835641@qq.com>"]
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
readme = "README.md"
|
||||||
|
homepage = "https://github.com/KimigaiiWuyi/GenshinUID/tree/ntchat"
|
||||||
|
repository = "https://github.com/KimigaiiWuyi/GenshinUID"
|
||||||
|
documentation = "https://github.com/KimigaiiWuyi/GenshinUID/wiki"
|
||||||
|
packages = [
|
||||||
|
{ include = "GenshinUID" }
|
||||||
|
]
|
||||||
|
exclude = ["tests", "deploy"]
|
||||||
|
|
||||||
|
[tool.poetry.urls]
|
||||||
|
"Bug Tracker" = "https://github.com/KimigaiiWuyi/GenshinUID/issues"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.8.1"
|
||||||
|
nonebot2 = ">=2.0.0b4"
|
||||||
|
nonebot-adapter-ntchat = ">=0.3.4"
|
||||||
|
httpx = ">=0.23.0"
|
||||||
|
beautifulsoup4 = ">=4.11.1"
|
||||||
|
lxml = ">=4.9.2"
|
||||||
|
openpyxl = ">=3.0.10"
|
||||||
|
aiohttp = ">=3.8.1"
|
||||||
|
sqlalchemy = ">=1.4.39"
|
||||||
|
pillow = ">=9.2.0"
|
||||||
|
aiosqlite = ">=0.17.0"
|
||||||
|
nonebot-plugin-apscheduler = ">=0.1.4"
|
||||||
|
aiofiles = ">=0.8.0"
|
||||||
|
sqlmodel = ">=0.0.8"
|
||||||
|
gitpython = ">=3.1.27"
|
||||||
|
fastapi-amis-admin = ">=0.2.1"
|
||||||
|
fastapi-user-auth = ">=0.2.1"
|
||||||
|
qrcode = {extras = ["pil"], version = "^7.3.1"}
|
||||||
|
|
||||||
[[tool.poetry.source]]
|
[[tool.poetry.source]]
|
||||||
name = 'aliyun.mirrors'
|
name = "USTC"
|
||||||
url = "http://mirrors.aliyun.com/pypi/simple/"
|
url = "https://pypi.mirrors.ustc.edu.cn/simple"
|
||||||
|
default = false
|
||||||
|
secondary = true
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
flake8 = "^6.0.0"
|
||||||
|
black = "^22.12.0"
|
||||||
|
isort = "^5.11.5"
|
||||||
|
pre-commit = "^2.21.0"
|
||||||
|
nonebug = "^0.2.2"
|
||||||
|
pytest = "^7.2.0"
|
||||||
|
pytest-asyncio = "^0.20.3"
|
||||||
|
pycln = "^2.1.2"
|
||||||
|
114
requirements.txt
114
requirements.txt
@ -1,50 +1,64 @@
|
|||||||
--trusted-host mirrors.aliyun.com
|
aiofiles==23.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
--extra-index-url http://mirrors.aliyun.com/pypi/simple
|
aiohttp==3.8.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
aiosignal==1.3.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
aiofiles==22.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
aiosqlite==0.18.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
aiohttp==3.8.3 ; python_version >= "3.8" and python_version < "4.0"
|
anyio==3.6.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
aiosignal==1.3.1 ; python_version >= "3.8" and python_version < "4.0"
|
apscheduler==3.10.1 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
aiosqlite==0.17.0 ; python_version >= "3.8" and python_version < "4.0"
|
async-timeout==4.0.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
anyio==3.6.2 ; python_version >= "3.8" and python_version < "4.0"
|
attrs==22.2.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
async-timeout==4.0.2 ; python_version >= "3.8" and python_version < "4.0"
|
backports-zoneinfo==0.2.1 ; python_full_version >= "3.8.1" and python_version < "3.9"
|
||||||
attrs==22.2.0 ; python_version >= "3.8" and python_version < "4.0"
|
bcrypt==4.0.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
bcrypt==4.0.1 ; python_version >= "3.8" and python_version < "4.0"
|
beautifulsoup4==4.11.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
beautifulsoup4==4.11.1 ; python_version >= "3.8" and python_version < "4.0"
|
certifi==2022.12.7 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
certifi==2022.12.7 ; python_version >= "3.8" and python_version < "4.0"
|
charset-normalizer==3.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
charset-normalizer==2.1.1 ; python_version >= "3.8" and python_version < "4.0"
|
colorama==0.4.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0" and platform_system == "Windows" or python_full_version >= "3.8.1" and python_version < "4.0" and sys_platform == "win32"
|
||||||
colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" and platform_system == "Windows"
|
dnspython==2.3.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
dnspython==2.2.1 ; python_version >= "3.8" and python_version < "4.0"
|
email-validator==1.3.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
email-validator==1.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
et-xmlfile==1.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
et-xmlfile==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
fastapi-amis-admin==0.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
fastapi-amis-admin==0.2.5 ; python_version >= "3.8" and python_version < "4.0"
|
fastapi-user-auth==0.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
fastapi-user-auth==0.2.4 ; python_version >= "3.8" and python_version < "4.0"
|
fastapi==0.93.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
fastapi==0.88.0 ; python_version >= "3.8" and python_version < "4.0"
|
frozenlist==1.3.3 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
frozenlist==1.3.3 ; python_version >= "3.8" and python_version < "4.0"
|
gitdb==4.0.10 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
gitdb==4.0.10 ; python_version >= "3.8" and python_version < "4.0"
|
gitpython==3.1.31 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
gitpython==3.1.30 ; python_version >= "3.8" and python_version < "4.0"
|
greenlet==2.0.2 ; python_full_version >= "3.8.1" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_full_version < "4.0.0"
|
||||||
greenlet==2.0.1 ; python_version >= "3.8" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32") and python_version < "4.0"
|
h11==0.12.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
h11==0.14.0 ; python_version >= "3.8" and python_version < "4.0"
|
httpcore==0.15.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
httpcore==0.16.3 ; python_version >= "3.8" and python_version < "4.0"
|
httpx==0.23.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
httpx==0.23.1 ; python_version >= "3.8" and python_version < "4.0"
|
idna==3.4 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
idna==3.4 ; python_version >= "3.8" and python_version < "4.0"
|
loguru==0.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
lxml==4.9.2 ; python_version >= "3.8" and python_version < "4.0"
|
lxml==4.9.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
multidict==6.0.4 ; python_version >= "3.8" and python_version < "4.0"
|
multidict==6.0.4 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
openpyxl==3.0.10 ; python_version >= "3.8" and python_version < "4.0"
|
nonebot-adapter-ntchat==0.3.5 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
passlib==1.7.4 ; python_version >= "3.8" and python_version < "4.0"
|
nonebot-plugin-apscheduler==0.2.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
pillow==9.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
nonebot2==2.0.0rc3 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
pydantic==1.10.4 ; python_version >= "3.8" and python_version < "4.0"
|
openpyxl==3.1.1 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
python-multipart==0.0.5 ; python_version >= "3.8" and python_version < "4.0"
|
passlib==1.7.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
qrcode[pil]==7.3.1 ; python_version >= "3.8" and python_version < "4.0"
|
pillow==9.4.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
rfc3986[idna2008]==1.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
pydantic==1.10.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
six==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
|
pydantic[dotenv]==1.10.6 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
smmap==5.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
pygtrie==2.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
sniffio==1.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
pypng==0.20220715.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
soupsieve==2.3.2.post1 ; python_version >= "3.8" and python_version < "4.0"
|
python-dotenv==1.0.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
sqlalchemy-database==0.0.11 ; python_version >= "3.8" and python_version < "4.0"
|
python-multipart==0.0.6 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
sqlalchemy2-stubs==0.0.2a31 ; python_version >= "3.8" and python_version < "4.0"
|
pytz-deprecation-shim==0.1.0.post0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
sqlalchemy==1.4.41 ; python_version >= "3.8" and python_version < "4.0"
|
pytz==2022.7.1 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
sqlmodel==0.0.8 ; python_version >= "3.8" and python_version < "4.0"
|
qrcode[pil]==7.4.2 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
sqlmodelx==0.0.4 ; python_version >= "3.8" and python_version < "4.0"
|
rfc3986[idna2008]==1.5.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
starlette==0.22.0 ; python_version >= "3.8" and python_version < "4.0"
|
setuptools==67.6.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
typing-extensions==4.4.0 ; python_version >= "3.8" and python_version < "4.0"
|
six==1.16.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
yarl==1.8.2 ; python_version >= "3.8" and python_version < "4.0"
|
smmap==5.0.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
sniffio==1.3.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
soupsieve==2.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
sqlalchemy-database==0.1.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
sqlalchemy2-stubs==0.0.2a32 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
sqlalchemy==1.4.41 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
sqlmodel==0.0.8 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
sqlmodelx==0.0.4 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
starlette==0.25.0 ; python_full_version >= "3.8.1" and python_full_version < "4.0.0"
|
||||||
|
tomlkit==0.11.6 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
|
typing-extensions==4.5.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
|
tzdata==2022.7 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
|
tzlocal==4.2 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
|
win32-setctime==1.1.0 ; python_full_version >= "3.8.1" and python_version < "4.0" and sys_platform == "win32"
|
||||||
|
yarl==1.8.2 ; python_full_version >= "3.8.1" and python_version < "4.0"
|
||||||
|
1
tests/.env
Normal file
1
tests/.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
ENVIRONMENT=test
|
4
tests/.env.test
Normal file
4
tests/.env.test
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
LOG_LEVEL=TRACE
|
||||||
|
NICKNAME=["test"]
|
||||||
|
SUPERUSERS=["10000"]
|
||||||
|
COMMAND_START=["", "/"]
|
34
tests/conftest.py
Normal file
34
tests/conftest.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from nonebot.plugin import Plugin
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def load_metadata(nonebug_init: None) -> Optional["Plugin"]:
|
||||||
|
import nonebot
|
||||||
|
|
||||||
|
return nonebot.load_plugin("GenshinUID.genshinuid_meta")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def load_adv(nonebug_init: None) -> Optional["Plugin"]:
|
||||||
|
import nonebot
|
||||||
|
|
||||||
|
return nonebot.load_plugin("GenshinUID.genshinuid_adv")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def load_etc(nonebug_init: None) -> Optional["Plugin"]:
|
||||||
|
import nonebot
|
||||||
|
|
||||||
|
return nonebot.load_plugin("GenshinUID.genshinuid_etcimg")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def load_guide(nonebug_init: None) -> Optional["Plugin"]:
|
||||||
|
import nonebot
|
||||||
|
|
||||||
|
return nonebot.load_plugin("GenshinUID.genshinuid_guide")
|
25
tests/test_adv.py
Normal file
25
tests/test_adv.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import pytest
|
||||||
|
from nonebug import App
|
||||||
|
|
||||||
|
MESSAGE = """「安柏」
|
||||||
|
-=-=-=-=-=-=-=-=-=-
|
||||||
|
推荐5★武器:阿莫斯之弓、天空之翼、终末嗟叹之诗
|
||||||
|
推荐4★武器:绝弦
|
||||||
|
推荐圣遗物搭配:
|
||||||
|
[昔日宗室之仪]四件套"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(argnames="alias", argvalues=["安柏用什么", "安柏怎么养"])
|
||||||
|
async def test_adv_char_chat(app: App, alias, load_adv: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_adv import get_char_adv
|
||||||
|
|
||||||
|
async with app.test_matcher(get_char_adv) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
event = make_event(message=Message(alias))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(event, MESSAGE, True)
|
||||||
|
ctx.should_finished()
|
121
tests/test_etc.py
Normal file
121
tests/test_etc.py
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from nonebug import App
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(argnames="alias", argvalues=["版本规划", "原石预估"])
|
||||||
|
async def test_get_primogems_data(app: App, alias, load_etc: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.version import Genshin_version
|
||||||
|
from GenshinUID.genshinuid_etcimg import get_primogems_data
|
||||||
|
|
||||||
|
with open(
|
||||||
|
Path(
|
||||||
|
(
|
||||||
|
"../GenshinUID/genshinuid_etcimg"
|
||||||
|
f"/primogems_data/{Genshin_version[:3]}.png"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"rb",
|
||||||
|
) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
async with app.test_matcher(get_primogems_data) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
event = make_event(message=Message(alias))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(
|
||||||
|
event,
|
||||||
|
MessageSegment.image(data),
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_primogems_version(app: App, load_etc: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.version import Genshin_version
|
||||||
|
from GenshinUID.genshinuid_etcimg import get_primogems_data
|
||||||
|
|
||||||
|
with open(
|
||||||
|
Path(
|
||||||
|
(
|
||||||
|
"../GenshinUID/genshinuid_etcimg"
|
||||||
|
f"/primogems_data/{Genshin_version[:3]}.png"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"rb",
|
||||||
|
) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
async with app.test_matcher(get_primogems_data) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
event = make_event(message=Message(f"版本规划{Genshin_version[:3]}"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(
|
||||||
|
event,
|
||||||
|
MessageSegment.image(data),
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_primogems_failed(app: App, load_etc: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_etcimg import get_primogems_data
|
||||||
|
|
||||||
|
# primogems_img.exists() is False
|
||||||
|
async with app.test_matcher(get_primogems_data) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message("版本规划1.0"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
# str(args) in version is False
|
||||||
|
async with app.test_matcher(get_primogems_data) as ctx:
|
||||||
|
event = make_event(message=Message("版本规划abc"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
argnames="alias",
|
||||||
|
argvalues=[
|
||||||
|
"伤害乘区",
|
||||||
|
"血量表",
|
||||||
|
"抗性表",
|
||||||
|
"血量排行",
|
||||||
|
"伤害乘区",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_get_img_data(app: App, alias, load_etc: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_etcimg import get_img_data
|
||||||
|
|
||||||
|
with open(
|
||||||
|
Path(f"../GenshinUID/genshinuid_etcimg/img_data/{alias}.jpg"),
|
||||||
|
"rb",
|
||||||
|
) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
async with app.test_matcher(get_img_data) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message(f"查询{alias}"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(event, MessageSegment.image(data), True)
|
||||||
|
ctx.should_finished()
|
123
tests/test_guide.py
Normal file
123
tests/test_guide.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from nonebug import App
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
argnames="alias",
|
||||||
|
argvalues=[
|
||||||
|
"钟离推荐",
|
||||||
|
"钟离攻略",
|
||||||
|
"岩王爷攻略", # alias
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_get_guide_pic(app: App, alias, load_guide: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_guide import get_guide_pic
|
||||||
|
|
||||||
|
async with app.test_matcher(get_guide_pic) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message(alias))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(
|
||||||
|
event,
|
||||||
|
MessageSegment.image(
|
||||||
|
"https://file.microgg.cn/MiniGG/guide/钟离.jpg"
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_guide_pic_traveler(app: App, load_guide: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_guide import get_guide_pic
|
||||||
|
|
||||||
|
async with app.test_matcher(get_guide_pic) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message("旅行者风推荐"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(
|
||||||
|
event,
|
||||||
|
MessageSegment.image(
|
||||||
|
"https://file.microgg.cn/MiniGG/guide/旅行者-风.jpg"
|
||||||
|
),
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_guide_pic_failed(app: App, load_guide: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_guide import get_guide_pic
|
||||||
|
|
||||||
|
async with app.test_matcher(get_guide_pic) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message("蔡徐坤攻略"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
argnames="alias",
|
||||||
|
argvalues=[
|
||||||
|
"参考面板钟离",
|
||||||
|
"参考面板岩王爷", # alias
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_get_bluekun_pic(app: App, alias, load_guide: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_guide import get_bluekun_pic
|
||||||
|
|
||||||
|
with open(Path("../GenshinUID/genshinuid_guide/img/钟离.jpg"), "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
async with app.test_matcher(get_bluekun_pic) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message(alias))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(event, MessageSegment.image(data), True)
|
||||||
|
ctx.should_finished()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
argnames="alias",
|
||||||
|
argvalues=[
|
||||||
|
"岩",
|
||||||
|
"冰",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_get_bluekun_pic_element(app: App, alias, load_guide: None):
|
||||||
|
from utils import make_event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment
|
||||||
|
|
||||||
|
from GenshinUID.genshinuid_guide import get_bluekun_pic
|
||||||
|
|
||||||
|
with open(
|
||||||
|
Path(f"../GenshinUID/genshinuid_guide/img/{alias}.jpg"), "rb"
|
||||||
|
) as f:
|
||||||
|
data = f.read()
|
||||||
|
async with app.test_matcher(get_bluekun_pic) as ctx:
|
||||||
|
bot = ctx.create_bot(base=Bot)
|
||||||
|
|
||||||
|
event = make_event(message=Message(f"参考面板{alias}"))
|
||||||
|
ctx.receive_event(bot, event)
|
||||||
|
ctx.should_call_send(event, MessageSegment.image(data), True)
|
||||||
|
ctx.should_finished()
|
35
tests/test_metadata.py
Normal file
35
tests/test_metadata.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import pytest
|
||||||
|
from nonebug import App
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_metadata(app: App, load_metadata: None):
|
||||||
|
from GenshinUID.genshinuid_meta import __plugin_meta__
|
||||||
|
|
||||||
|
assert __plugin_meta__.name == 'GenshinUID'
|
||||||
|
assert (
|
||||||
|
__plugin_meta__.description == '基于NoneBot2的原神Uid查询/原神Wiki/米游社签到/树脂提醒插件'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_register_menu(app: App, load_metadata: None):
|
||||||
|
from GenshinUID.genshinuid_meta import sub_menus, register_menu
|
||||||
|
|
||||||
|
@register_menu(
|
||||||
|
'test',
|
||||||
|
'trigger',
|
||||||
|
'test register_menu',
|
||||||
|
trigger_method='114514',
|
||||||
|
detail_des='test register_menu',
|
||||||
|
)
|
||||||
|
async def _example() -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert len(sub_menus) == 1
|
||||||
|
menu = sub_menus[0]
|
||||||
|
assert menu['func'] == 'test'
|
||||||
|
assert menu['trigger_condition'] == 'trigger'
|
||||||
|
assert menu['trigger_method'] == '114514'
|
||||||
|
assert menu['brief_des'] == 'test register_menu'
|
||||||
|
assert menu['detail_des'] == 'test register_menu'
|
109
tests/utils.py
Normal file
109
tests/utils.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# https://gist.github.com/38e4df0f6f7879d9324b15ac910229ac
|
||||||
|
from typing import Any, Dict, Optional, cast
|
||||||
|
|
||||||
|
from nonebot.adapters.onebot.v11 import Adapter, Message
|
||||||
|
from nonebot.adapters.onebot.v11.event import Event, Sender
|
||||||
|
|
||||||
|
|
||||||
|
def make_sender(
|
||||||
|
user_id: int = 10001,
|
||||||
|
nickname: str = "test",
|
||||||
|
sex: str = "unknown",
|
||||||
|
age: int = 1,
|
||||||
|
card: str = "test",
|
||||||
|
area: str = "北京",
|
||||||
|
level: str = "1",
|
||||||
|
role: str = "owner",
|
||||||
|
title: str = "test",
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
:说明:
|
||||||
|
生成发送人信息类型。
|
||||||
|
https://github.com/botuniverse/onebot-11/blob/master/event/message.md
|
||||||
|
|
||||||
|
|
||||||
|
:参数:
|
||||||
|
|
||||||
|
* ``user_id: int = 10001``: 发送者 QQ 号。
|
||||||
|
* ``nickname: str = "test"``: 昵称。
|
||||||
|
* ``sex: str = "unknown"``: 性别,`male` 或 `female` 或 `unknown`。
|
||||||
|
* ``age: int = 1``: 年龄。
|
||||||
|
* ``card: str = "test"``: 群名片/备注。
|
||||||
|
* ``area: str = "北京"``: 地区。
|
||||||
|
* ``level: str = "1"``: 成员等级。
|
||||||
|
* ``role: str = "owner"``: 角色,`owner` 或 `admin` 或 `member`。
|
||||||
|
* ``title: str = "test"``: 专属头衔。
|
||||||
|
"""
|
||||||
|
|
||||||
|
return Sender(
|
||||||
|
user_id=user_id,
|
||||||
|
nickname=nickname,
|
||||||
|
sex=sex,
|
||||||
|
age=age,
|
||||||
|
card=card,
|
||||||
|
area=area,
|
||||||
|
level=level,
|
||||||
|
role=role,
|
||||||
|
title=title,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def make_event(
|
||||||
|
sender: Sender = make_sender(),
|
||||||
|
message: Optional[Message] = None,
|
||||||
|
time: int = 0,
|
||||||
|
self_id: int = 10000,
|
||||||
|
post_type: str = "message",
|
||||||
|
message_type: str = "private",
|
||||||
|
sub_type: str = "friend",
|
||||||
|
group_id: int = 10002,
|
||||||
|
anonymous: Optional[Dict[str, Any]] = None,
|
||||||
|
message_id: int = 1,
|
||||||
|
user_id: int = 10001,
|
||||||
|
font: int = 0,
|
||||||
|
**kwargs,
|
||||||
|
) -> Event:
|
||||||
|
"""
|
||||||
|
:说明:
|
||||||
|
|
||||||
|
根据消息类型自动生成事件。
|
||||||
|
https://github.com/botuniverse/onebot-11/blob/master/event/message.md
|
||||||
|
|
||||||
|
:参数:
|
||||||
|
|
||||||
|
* ``time: int = 0``: 事件发生的时间戳。
|
||||||
|
* ``self_id: int = 10000``: 收到事件的机器人 QQ 号。
|
||||||
|
* ``post_type: str = "message"``: 上报类型。
|
||||||
|
* ``message_type: str = "private"``: 消息类型,`friend` 是私聊消息,`group是群消息`。
|
||||||
|
* ``sub_type: str = "friend"``: 消息子类型:
|
||||||
|
* 私聊消息:如果是好友则是 `friend`,如果是群临时会话则是 `group`。
|
||||||
|
* 群消息:正常消息是 normal,匿名消息是 anonymous,系统提示(如「管理员已禁止群内匿名聊天」)是 notice
|
||||||
|
* ``message_id: int = 1``: 消息 ID。
|
||||||
|
* ``user_id: int = 10001``: 发送者 QQ 号。
|
||||||
|
* ``message: Message = None``: 消息内容。
|
||||||
|
* ``font: int = 0``: 字体。
|
||||||
|
* ``sender: Sender = None``: 发送人信息。
|
||||||
|
"""
|
||||||
|
raw_message = message.extract_plain_text() if message else ''
|
||||||
|
return cast(
|
||||||
|
Event,
|
||||||
|
Adapter.json_to_event(
|
||||||
|
{
|
||||||
|
"time": time,
|
||||||
|
"self_id": self_id,
|
||||||
|
"post_type": post_type,
|
||||||
|
"message_type": message_type,
|
||||||
|
"sub_type": sub_type,
|
||||||
|
"message_id": message_id,
|
||||||
|
"user_id": user_id,
|
||||||
|
"message": message,
|
||||||
|
"raw_message": raw_message,
|
||||||
|
"font": font,
|
||||||
|
"sender": sender,
|
||||||
|
"group_id": group_id,
|
||||||
|
"anonymous": anonymous,
|
||||||
|
**kwargs,
|
||||||
|
},
|
||||||
|
str(self_id),
|
||||||
|
),
|
||||||
|
)
|
Reference in New Issue
Block a user