Skip to content

Commit

Permalink
Merge pull request #113 from Ljzd-PRO/1.0.0
Browse files Browse the repository at this point in the history
更新至 v1.0.0-beta.1
  • Loading branch information
ERZATZ Type AK9 authored Jun 10, 2023
2 parents ef03dde + 49a3921 commit 22d12c3
Show file tree
Hide file tree
Showing 24 changed files with 4,494 additions and 4,308 deletions.
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,25 @@

# mysTool - 米游社辅助工具插件

**版本 - v0.2.9**
**版本 - v1.0.0-beta.1**

### 📣 更新内容

#### 2023.6.10

改动较大,目前是 Beta 版,可能不稳定

- 大量的代码重构,包括米游社API的客户端实现、用户数据相关、插件配置相关、API相关数据模型
- 修复在 Windows 下无法多进程生成商品图片的问题
- 从显示用户账号绑定的手机号改为显示账号的米游社ID
- 设置、兑换计划功能支持群聊使用
- 登陆绑定只需要进行一次短信验证
- 用户数据文件、插件配置文件 **格式更新,与 v1.0.0 之前的版本不兼容**
- 修复添加兑换任务时出现的UID不存在错误
- 修复商品图片生成完才发出后台正在生成提示的问题
- 异常捕获更加准确
- 改进了一些文本

#### 2023.5.18
- 多进程生成商品图片(多核),加快图片生成速度
- 修复部分商品兑换时间错误的问题(如米游社商品晚了一周)
Expand Down Expand Up @@ -61,7 +76,7 @@
/帮助
```

> ⚠️ 注意 此处没有使用 [🔗 插件命令头](https://github.com/Ljzd-PRO/nonebot-plugin-mystool/wiki/Configuration-Config#command_start)
> ⚠️ 注意 此处没有使用 [🔗 插件命令头](https://github.com/Ljzd-PRO/nonebot-plugin-mystool/wiki/Configuration-Config#commandstart)
## 其他

Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "nonebot-plugin-mystool"
version = "v0.2.9"
version = "v1.0.0-beta.1"
description = "NoneBot2插件|米游社工具-每日米游币任务、游戏签到、商品兑换、免抓包登录、原神树脂提醒"
license = "MIT"
authors = [
Expand All @@ -24,11 +24,11 @@ packages = [

[tool.poetry.dependencies]
python = ">=3.9,<4.0"
httpx = "^0.24.0"
httpx = "^0.24.1"
nonebot_plugin_apscheduler = ">=0.2.0"
ntplib = "^0.4.0"
Pillow = "^9.5.0"
requests = "^2.30.0"
requests = "^2.31.0"
nonebot_adapter_onebot = "^2.2.3"
tenacity = "^8.2.2"

Expand Down
42 changes: 1 addition & 41 deletions src/nonebot_plugin_mystool/__init__.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,9 @@
"""
# mysTool - 米游社辅助工具插件
**版本 - v0.2.9**
## 使用说明
### 🛠️ NoneBot2 机器人部署和插件安装
请查看 -> [🔗Installation](https://github.com/Ljzd-PRO/nonebot-plugin-mystool/wiki/Installation)
### 📖 插件具体使用说明
请查看 -> [🔗Wiki 文档](https://github.com/Ljzd-PRO/nonebot-plugin-mystool/wiki)
### ❓ 获取插件帮助信息
#### 插件命令
```
/帮助
```
> ⚠️ 注意 此处没有使用 [🔗 插件命令头](https://github.com/Ljzd-PRO/nonebot-plugin-mystool/wiki/Configuration-Config#command_start)
## 其他
### [📃源码说明](https://github.com/Ljzd-PRO/nonebot-plugin-mystool/wiki/Source-Structure)
### 适配 [绪山真寻Bot](https://github.com/HibiKier/zhenxun_bot) 的分支
- https://github.com/MWTJC/zhenxun-plugin-mystool
- https://github.com/ayakasuki/nonebot-plugin-mystool
"""

import pkgutil
from pathlib import Path

from nonebot.plugin import PluginMetadata

from .data import create_files

VERSION = "v0.2.9"
'''插件版本号'''
from .plugin_data import VERSION

__plugin_meta__ = PluginMetadata(
name=f"❖米游社小助手插件❖\n版本 - {VERSION}\n",
Expand All @@ -66,9 +29,6 @@
extra={"version": VERSION}
)

# 需要最先执行的函数
create_files()

# 加载其它代码

FILE_PATH = Path(__file__).parent.absolute()
Expand Down
184 changes: 66 additions & 118 deletions src/nonebot_plugin_mystool/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,150 +2,98 @@
### 米游社收货地址相关
"""
import asyncio
import traceback
from typing import List, Literal, Union
from typing import Union

import httpx
import tenacity
from nonebot import on_command
from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
from nonebot.matcher import Matcher
from nonebot.params import Arg, ArgPlainText, T_State

from .config import config as conf
from .data import Address, UserAccount, UserData
from .utils import NtpTime, check_login, custom_attempt_times, logger, COMMAND_BEGIN
from .plugin_data import PluginDataManager, write_plugin_data
from .simple_api import get_address
from .user_data import UserAccount
from .utils import COMMAND_BEGIN

HEADERS = {
"Host": "api-takumi.mihoyo.com",
"Accept": "application/json, text/plain, */*",
"Origin": "https://user.mihoyo.com",
"Connection": "keep-alive",
"x-rpc-device_id": None,
"x-rpc-client_type": "5",
"User-Agent": conf.device.USER_AGENT_MOBILE,
"Referer": "https://user.mihoyo.com/",
"Accept-Language": "zh-CN,zh-Hans;q=0.9",
"Accept-Encoding": "gzip, deflate, br"
}
URL = "https://api-takumi.mihoyo.com/account/address/list?t={}"
_conf = PluginDataManager.plugin_data_obj

address_matcher = on_command(_conf.preference.command_start + '地址', priority=4, block=True)

async def get(account: UserAccount, retry: bool = True) -> Union[List[Address], Literal[-1, -2, -3]]:
"""
获取用户的地址数据
address_matcher.name = '地址'
address_matcher.usage = '跟随指引,获取地址ID,用于兑换米游币商品。在获取地址ID前,如果你还没有设置米游社收获地址,请前往官网或App设置'

- 若返回 `-1` 说明用户登录失效
- 若返回 `-2` 说明服务器没有正确返回
- 若返回 `-3` 说明请求失败

:param account: 用户账户数据
:param retry: 是否允许重试
"""
address_list = []
headers = HEADERS.copy()
headers["x-rpc-device_id"] = account.deviceID
try:
async for attempt in tenacity.AsyncRetrying(stop=custom_attempt_times(retry), reraise=True,
wait=tenacity.wait_fixed(conf.SLEEP_TIME_RETRY)):
with attempt:
async with httpx.AsyncClient() as client:
res = await client.get(URL.format(
round(NtpTime.time() * 1000)), headers=headers, cookies=account.cookie, timeout=conf.TIME_OUT)
if not check_login(res.text):
logger.info(
f"{conf.LOG_HEAD}获取地址数据 - 用户 {account.phone} 登录失效")
logger.debug(f"{conf.LOG_HEAD}网络请求返回: {res.text}")
return -1
for address in res.json()["data"]["list"]:
address_list.append(Address(address))
except KeyError:
logger.error(f"{conf.LOG_HEAD}获取地址数据 - 服务器没有正确返回")
logger.debug(f"{conf.LOG_HEAD}网络请求返回: {res.text}")
logger.debug(f"{conf.LOG_HEAD}{traceback.format_exc()}")
return -2
except Exception:
logger.error(f"{conf.LOG_HEAD}获取地址数据 - 请求失败")
logger.debug(f"{conf.LOG_HEAD}{traceback.format_exc()}")
return -3
return address_list


get_address = on_command(conf.COMMAND_START + '地址', priority=4, block=True)

get_address.name = '地址'
get_address.usage = '跟随指引,获取地址ID,用于兑换米游币商品。在获取地址ID前,如果你还没有设置米游社收获地址,请前往官网或App设置'


@get_address.handle()
async def _(event: Union[PrivateMessageEvent, GroupMessageEvent], matcher: Matcher, state: T_State):
@address_matcher.handle()
async def _(event: Union[PrivateMessageEvent, GroupMessageEvent], matcher: Matcher):
if isinstance(event, GroupMessageEvent):
await get_address.finish("⚠️为了保护您的隐私,请添加机器人好友后私聊进行地址设置。")
user_account = UserData.read_account_all(event.user_id)
state['qq_account'] = event.user_id
state['user_account'] = user_account
await address_matcher.finish("⚠️为了保护您的隐私,请添加机器人好友后私聊进行地址设置。")
user = _conf.users.get(event.user_id)
user_account = user.accounts if user else None
if not user_account:
await get_address.finish(f"⚠️你尚未绑定米游社账户,请先使用『{COMMAND_BEGIN}登录』进行登录")
await address_matcher.finish(f"⚠️你尚未绑定米游社账户,请先使用『{COMMAND_BEGIN}登录』进行登录")
else:
await get_address.send("请跟随指引设置收货地址ID,如果你还没有设置米游社收获地址,请前往官网或App设置。\n🚪过程中发送“退出”即可退出")
await address_matcher.send(
"请跟随指引设置收货地址ID,如果你还没有设置米游社收获地址,请前往官网或App设置。\n🚪过程中发送“退出”即可退出")
if len(user_account) == 1:
matcher.set_arg('phone', Message(str(user_account[0].phone)))
account = next(iter(user_account.values()))
matcher.set_arg('bbs_uid', Message(account.bbs_uid))
else:
phones = [str(user_account[i].phone) for i in range(len(user_account))]
uids = map(lambda x: x.bbs_uid, user_account.values())
msg = "您有多个账号,您要设置以下哪个账号的收货地址?\n"
msg += "📱" + "\n📱".join(phones)
msg += "\n".join(map(lambda x: f"🆔{x}", uids))
await matcher.send(msg)


@get_address.got('phone')
async def _(_: PrivateMessageEvent, state: T_State, phone=Arg()):
if isinstance(phone, Message):
phone = phone.extract_plain_text().strip()
if phone == '退出':
await get_address.finish('🚪已成功退出')
user_account = state['user_account']
qq_account = state['qq_account']
phones = [str(user_account[i].phone) for i in range(len(user_account))]
account = None
if phone in phones:
account = UserData.read_account(qq_account, int(phone))
else:
await get_address.reject('⚠️您发送的账号不在以上账号内,请重新发送')
@address_matcher.got('bbs_uid')
async def _(event: PrivateMessageEvent, state: T_State, uid=Arg("bbs_uid")):
if isinstance(uid, Message):
uid = uid.extract_plain_text().strip()
if uid == '退出':
await address_matcher.finish('🚪已成功退出')

user_account = _conf.users[event.user_id].accounts
if uid not in user_account:
await address_matcher.reject('⚠️您发送的账号不在以上账号内,请重新发送')
account = user_account[uid]
state['account'] = account
state['address_list']: List[Address] = await get(account)
if isinstance(state['address_list'], int):
if state['address_list'] == -1:
await get_address.finish(f"⚠️账户 {account.phone} 登录失效,请重新登录")
await get_address.finish("⚠️获取失败,请稍后重新尝试")
if state['address_list']:
await get_address.send("以下为查询结果:")
for address in state['address_list']:
address_string = f"""\
\n省 ➢ {address.province}\
\n市 ➢ {address.city}\
\n区/县 ➢ {address.county}\
\n详细地址 ➢ {address.detail}\
\n联系电话 ➢ {address.phone}\
\n联系人 ➢ {address.name}\
\n地址ID ➢ {address.address_id}\
""".strip()
await get_address.send(address_string)
await asyncio.sleep(0.2)

address_status, address_list = await get_address(account)
state['address_list'] = address_list
if not address_status:
if address_status.login_expired:
await address_matcher.finish(f"⚠️账户 {account.bbs_uid} 登录失效,请重新登录")
await address_matcher.finish("⚠️获取失败,请稍后重新尝试")

if address_list:
address_text = map(
lambda x: f"省 ➢ {x.province_name}" \
f"\n市 ➢ {x.city_name}" \
f"\n区/县 ➢ {x.county_name}" \
f"\n详细地址 ➢ {x.addr_ext}" \
f"\n联系电话 ➢ {x.phone}" \
f"\n联系人 ➢ {x.connect_name}" \
f"\n地址ID ➢ {x.id}",
address_list
)
msg = "以下为查询结果:" \
"\n\n" + "\n- - -\n".join(address_text)
await address_matcher.send(msg)
await asyncio.sleep(0.2)
else:
await get_address.finish("⚠️您还没有配置地址,请先前往米游社配置地址!")
await address_matcher.finish("⚠️您还没有配置地址,请先前往米游社配置地址!")


@get_address.got('address_id', prompt='请发送你要选择的地址ID')
@address_matcher.got('address_id', prompt='请发送你要选择的地址ID')
async def _(_: PrivateMessageEvent, state: T_State, address_id=ArgPlainText()):
if address_id == "退出":
await get_address.finish("🚪已成功退出")
result_address = list(
filter(lambda address: address.address_id == address_id, state['address_list']))
if result_address:
await address_matcher.finish("🚪已成功退出")

address_filter = filter(lambda x: x.id == address_id, state['address_list'])
address = next(address_filter, None)
if address is not None:
account: UserAccount = state["account"]
account.address = result_address[0]
UserData.set_account(account, state['qq_account'], account.phone)
await get_address.finish(f"🎉已成功设置账户 {account.phone} 的地址")
account.address = address
write_plugin_data()
await address_matcher.finish(f"🎉已成功设置账户 {account.bbs_uid} 的地址")
else:
await get_address.reject("⚠️您发送的地址ID与查询结果不匹配,请重新发送")
await address_matcher.reject("⚠️您发送的地址ID与查询结果不匹配,请重新发送")
Loading

0 comments on commit 22d12c3

Please sign in to comment.