mirror of
https://github.com/baiqwerdvd/ArknightsUID.git
synced 2025-05-04 19:17:33 +08:00
✨ 完成 skd bind
This commit is contained in:
parent
78c2d97165
commit
bc4c1983ec
6
ArknightsUID/arknightsuid_config/ark_config.py
Normal file
6
ArknightsUID/arknightsuid_config/ark_config.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from gsuid_core.utils.plugins_config.gs_config import StringConfig
|
||||||
|
|
||||||
|
from ..utils.resource.RESOURCE_PATH import CONFIG_PATH
|
||||||
|
from .config_default import CONIFG_DEFAULT
|
||||||
|
|
||||||
|
arkconfig = StringConfig('ArknightsUID', CONFIG_PATH, CONIFG_DEFAULT)
|
13
ArknightsUID/arknightsuid_config/config_default.py
Normal file
13
ArknightsUID/arknightsuid_config/config_default.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
from gsuid_core.utils.plugins_config.models import (
|
||||||
|
GSC,
|
||||||
|
GsStrConfig,
|
||||||
|
)
|
||||||
|
|
||||||
|
CONIFG_DEFAULT: dict[str, GSC] = {
|
||||||
|
'ArknightsPrefix': GsStrConfig(
|
||||||
|
'插件命令前缀(确认无冲突再修改)',
|
||||||
|
'用于本插件的前缀设定',
|
||||||
|
'ark',
|
||||||
|
),
|
||||||
|
}
|
20
ArknightsUID/arknightsuid_resource/__init__.py
Normal file
20
ArknightsUID/arknightsuid_resource/__init__.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# from gsuid_core.bot import Bot
|
||||||
|
# from gsuid_core.logger import logger
|
||||||
|
# from gsuid_core.models import Event
|
||||||
|
# from gsuid_core.sv import SV
|
||||||
|
|
||||||
|
# from ..utils.resource.download_all_resource import download_all_resource
|
||||||
|
|
||||||
|
# sv_download_config = SV('下载资源', pm=2)
|
||||||
|
|
||||||
|
|
||||||
|
# @sv_download_config.on_fullmatch(('下载全部资源'))
|
||||||
|
# async def send_download_resource_msg(bot: Bot, ev: Event):
|
||||||
|
# await bot.send('正在开始下载~可能需要较久的时间!')
|
||||||
|
# im = await download_all_resource()
|
||||||
|
# await bot.send(im)
|
||||||
|
|
||||||
|
|
||||||
|
# async def startup():
|
||||||
|
# logger.info('[资源文件下载] 正在检查与下载缺失的资源文件,可能需要较长时间,请稍等')
|
||||||
|
# logger.info(f'[资源文件下载] {await download_all_resource()}')
|
13
ArknightsUID/arknightsuid_start/__init__.py
Normal file
13
ArknightsUID/arknightsuid_start/__init__.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# from ..arknightsuid_resource import startup
|
||||||
|
|
||||||
|
|
||||||
|
# async def all_start():
|
||||||
|
# try:
|
||||||
|
# await startup()
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.exception(e)
|
||||||
|
|
||||||
|
|
||||||
|
# threading.Thread(target=lambda: asyncio.run(all_start()), daemon=True).start()
|
73
ArknightsUID/arknightsuid_user/__init__.py
Normal file
73
ArknightsUID/arknightsuid_user/__init__.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
from gsuid_core.bot import Bot
|
||||||
|
from gsuid_core.models import Event
|
||||||
|
from gsuid_core.sv import SV
|
||||||
|
|
||||||
|
from ..utils.ark_prefix import PREFIX
|
||||||
|
from ..utils.database.models import ArknightsBind
|
||||||
|
from ..utils.message import send_diff_msg
|
||||||
|
from .deal_skd_cred import deal_skd_cred
|
||||||
|
|
||||||
|
# from .draw_user_card import get_user_card
|
||||||
|
|
||||||
|
sv_user_config = SV('ark用户管理', pm=2)
|
||||||
|
sv_user_add = SV('ark用户添加')
|
||||||
|
sv_user_info = SV('ark用户信息')
|
||||||
|
ark_skd_cred_add = SV('森空岛cred绑定')
|
||||||
|
# sv_user_help = SV('ark绑定帮助')
|
||||||
|
|
||||||
|
|
||||||
|
# @sv_user_info.on_fullmatch((f'{PREFIX}绑定信息'))
|
||||||
|
# async def send_bind_card(bot: Bot, ev: Event):
|
||||||
|
# await bot.logger.info('ark开始执行[查询用户绑定状态]')
|
||||||
|
# uid_list = await get_user_card(ev.bot_id, ev.user_id)
|
||||||
|
# await bot.logger.info('ark[查询用户绑定状态]完成!等待图片发送中...')
|
||||||
|
# await bot.send(uid_list)
|
||||||
|
|
||||||
|
|
||||||
|
@sv_user_info.on_command(
|
||||||
|
(f'{PREFIX}绑定uid', f'{PREFIX}切换uid', f'{PREFIX}删除uid', f'{PREFIX}解绑uid')
|
||||||
|
)
|
||||||
|
async def send_link_uid_msg(bot: Bot, ev: Event):
|
||||||
|
await bot.logger.info("开始执行[绑定/解绑用户信息]")
|
||||||
|
qid = ev.user_id
|
||||||
|
await bot.logger.info(f"[绑定/解绑]UserID: {qid}")
|
||||||
|
|
||||||
|
ark_uid = ev.text.strip()
|
||||||
|
if ark_uid and not ark_uid.isdigit():
|
||||||
|
return await bot.send("你输入了错误的格式!")
|
||||||
|
|
||||||
|
if '绑定' in ev.command:
|
||||||
|
data = await ArknightsBind.insert_uid(qid, ev.bot_id, ark_uid, ev.group_id)
|
||||||
|
return await send_diff_msg(
|
||||||
|
bot,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
0: f'绑定ARK_UID{ark_uid}成功!',
|
||||||
|
-1: f'ARK_UID{ark_uid}的位数不正确!',
|
||||||
|
-2: f'ARK_UID{ark_uid}已经绑定过了!',
|
||||||
|
-3: '你输入了错误的格式!',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif '切换' in ev.command:
|
||||||
|
data = await ArknightsBind.switch_uid_by_game(qid, ev.bot_id, ark_uid)
|
||||||
|
if isinstance(data, list):
|
||||||
|
return await bot.send(f'切换ARK_UID{ark_uid}成功!')
|
||||||
|
else:
|
||||||
|
return await bot.send(f'尚未绑定该ARK_UID{ark_uid}')
|
||||||
|
else:
|
||||||
|
data = await ArknightsBind.delete_uid(qid, ev.bot_id, ark_uid)
|
||||||
|
return await send_diff_msg(
|
||||||
|
bot,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
0: f'删除ARK_UID{ark_uid}成功!',
|
||||||
|
-1: f'该ARK_UID{ark_uid}不在已绑定列表中!',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ark_skd_cred_add.on_prefix(("skd添加cred", "森空岛添加CRED"))
|
||||||
|
async def send_ark_skd_add_cred_msg(bot: Bot, ev: Event):
|
||||||
|
im = await deal_skd_cred(ev.bot_id, ev.text, ev.user_id)
|
||||||
|
await bot.send(im)
|
21
ArknightsUID/arknightsuid_user/deal_skd_cred.py
Normal file
21
ArknightsUID/arknightsuid_user/deal_skd_cred.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
from ..utils.ark_api import ark_skd_api
|
||||||
|
from ..utils.database.models import ArknightsUser
|
||||||
|
|
||||||
|
ERROR_HINT = '添加失败,格式为:用户ID - Cred\n \
|
||||||
|
例如:1810461245 - VropL583Sb1hClS5buQ4nSASkDlL8tMT'
|
||||||
|
|
||||||
|
|
||||||
|
async def deal_skd_cred(bot_id: str, cred: str, user_id: str) -> str:
|
||||||
|
if '-' not in cred:
|
||||||
|
return ERROR_HINT
|
||||||
|
_ck = cred.replace(' ', '').split('-')
|
||||||
|
if len(_ck) != 2 or not _ck[0] or not _ck[0].isdigit() or not _ck[1]:
|
||||||
|
return ERROR_HINT
|
||||||
|
|
||||||
|
check_cred = await ark_skd_api.check_cred_valid(_ck[1])
|
||||||
|
if check_cred:
|
||||||
|
return 'Cred无效!'
|
||||||
|
uid, cred = _ck[0], _ck[1]
|
||||||
|
await ArknightsUser.insert_data(user_id, bot_id,
|
||||||
|
Cred=cred, uid=uid, skd_uid=check_cred)
|
||||||
|
return '添加成功!'
|
@ -0,0 +1 @@
|
|||||||
|
ARK_USER_ME = 'https://zonai.skland.com/api/v1/user/me'
|
86
ArknightsUID/utils/api/skd/request.py
Normal file
86
ArknightsUID/utils/api/skd/request.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
from copy import deepcopy
|
||||||
|
from typing import Any, Literal
|
||||||
|
|
||||||
|
from aiohttp import ClientSession, ContentTypeError, TCPConnector
|
||||||
|
from gsuid_core.logger import logger
|
||||||
|
|
||||||
|
from ...database.models import ArknightsUser
|
||||||
|
from ...models.skland.models import ArknightsUserMeModel
|
||||||
|
from .api import ARK_USER_ME
|
||||||
|
|
||||||
|
|
||||||
|
class BaseArkApi:
|
||||||
|
ssl_verify = True
|
||||||
|
_HEADER = {
|
||||||
|
"Host": "zonai.skland.com",
|
||||||
|
"Origin": "https://www.skland.com",
|
||||||
|
"Referer": "https://www.skland.com/",
|
||||||
|
"content-type": "application/json; charset=UTF-8",
|
||||||
|
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
|
||||||
|
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
|
||||||
|
}
|
||||||
|
|
||||||
|
async def check_cred_valid(self, Cred: str) -> bool | str:
|
||||||
|
header = deepcopy(self._HEADER)
|
||||||
|
header['Cred'] = Cred
|
||||||
|
raw_data = await self._ark_request(ARK_USER_ME, header=header)
|
||||||
|
unpack_data = self.unpack(raw_data)
|
||||||
|
if isinstance(unpack_data, int):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return ArknightsUserMeModel(**unpack_data).user.id_
|
||||||
|
|
||||||
|
def unpack(self, raw_data: dict | int) -> dict | int:
|
||||||
|
if isinstance(raw_data, dict):
|
||||||
|
return raw_data["data"]
|
||||||
|
else:
|
||||||
|
return raw_data
|
||||||
|
|
||||||
|
async def _ark_request(
|
||||||
|
self,
|
||||||
|
url: str,
|
||||||
|
method: Literal["GET", "POST"] = "GET",
|
||||||
|
header: dict[str, Any] = _HEADER,
|
||||||
|
params: dict[str, Any] | None = None,
|
||||||
|
data: dict[str, Any] | None = None,
|
||||||
|
) -> dict | int:
|
||||||
|
if "Cred" not in header:
|
||||||
|
target_user_id = (
|
||||||
|
data["friendUserId"]
|
||||||
|
if data and "friendUserId" in data
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
Cred: str | None = await ArknightsUser.get_random_cookie(
|
||||||
|
target_user_id if target_user_id else "18888888"
|
||||||
|
)
|
||||||
|
if Cred is None:
|
||||||
|
return -61
|
||||||
|
arkUser = await ArknightsUser.base_select_data(ArknightsUser, Cred=Cred)
|
||||||
|
if arkUser is None:
|
||||||
|
return -61
|
||||||
|
header["Cred"] = Cred
|
||||||
|
|
||||||
|
async with ClientSession(
|
||||||
|
connector=TCPConnector(verify_ssl=self.ssl_verify)
|
||||||
|
) as client:
|
||||||
|
async with client.request(
|
||||||
|
method,
|
||||||
|
url=url,
|
||||||
|
headers=header,
|
||||||
|
params=params,
|
||||||
|
json=data,
|
||||||
|
timeout=300,
|
||||||
|
) as resp:
|
||||||
|
try:
|
||||||
|
raw_data = await resp.json()
|
||||||
|
except ContentTypeError:
|
||||||
|
_raw_data = await resp.text()
|
||||||
|
raw_data = {"code": -999, "data": _raw_data}
|
||||||
|
if (
|
||||||
|
raw_data
|
||||||
|
and 'code' in raw_data
|
||||||
|
and raw_data['code'] != 0
|
||||||
|
):
|
||||||
|
return raw_data['code']
|
||||||
|
logger.debug(raw_data)
|
||||||
|
return raw_data
|
3
ArknightsUID/utils/ark_api.py
Normal file
3
ArknightsUID/utils/ark_api.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from .api.skd.request import BaseArkApi
|
||||||
|
|
||||||
|
ark_skd_api = BaseArkApi()
|
3
ArknightsUID/utils/ark_prefix.py
Normal file
3
ArknightsUID/utils/ark_prefix.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from ..arknightsuid_config.ark_config import arkconfig
|
||||||
|
|
||||||
|
PREFIX = arkconfig.get_config('ArknightsPrefix').data
|
34
ArknightsUID/utils/database/models.py
Normal file
34
ArknightsUID/utils/database/models.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from gsuid_core.utils.database.base_models import (
|
||||||
|
Bind,
|
||||||
|
User,
|
||||||
|
)
|
||||||
|
from gsuid_core.webconsole.mount_app import GsAdminModel, PageSchema, site
|
||||||
|
from sqlmodel import Field
|
||||||
|
|
||||||
|
|
||||||
|
class ArknightsBind(Bind, table=True):
|
||||||
|
uid: str | None = Field(default=None, title='明日方舟UID')
|
||||||
|
|
||||||
|
|
||||||
|
class ArknightsUser(User, table=True):
|
||||||
|
uid: str | None = Field(default=None, title='明日方舟UID')
|
||||||
|
skd_uid: str | None = Field(default=None, title='SKD用户ID')
|
||||||
|
cred: str | None = Field(default=None, title='SKD凭证')
|
||||||
|
|
||||||
|
|
||||||
|
@site.register_admin
|
||||||
|
class ArknightsBindadmin(GsAdminModel):
|
||||||
|
pk_name = 'id'
|
||||||
|
page_schema = PageSchema(label='方舟绑定管理', icon='fa fa-users') # type: ignore
|
||||||
|
|
||||||
|
# 配置管理模型
|
||||||
|
model = ArknightsBind
|
||||||
|
|
||||||
|
|
||||||
|
@site.register_admin
|
||||||
|
class ArknightsUseradmin(GsAdminModel):
|
||||||
|
pk_name = 'id'
|
||||||
|
page_schema = PageSchema(label='方舟SKD CRED管理', icon='fa fa-database') # type: ignore
|
||||||
|
|
||||||
|
# 配置管理模型
|
||||||
|
model = ArknightsUser
|
22
ArknightsUID/utils/download.py
Normal file
22
ArknightsUID/utils/download.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
|
from aiohttp.client import ClientSession
|
||||||
|
from aiohttp.client_exceptions import ClientConnectorError
|
||||||
|
from gsuid_core.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
async def download_file(
|
||||||
|
url: str,
|
||||||
|
path: Path,
|
||||||
|
name: str,
|
||||||
|
):
|
||||||
|
sess = ClientSession()
|
||||||
|
try:
|
||||||
|
async with sess.get(url) as res:
|
||||||
|
content = await res.read()
|
||||||
|
except ClientConnectorError:
|
||||||
|
logger.warning(f"[wzry]{name}下载失败")
|
||||||
|
return url, path, name
|
||||||
|
async with aiofiles.open(path / name, "wb") as f:
|
||||||
|
await f.write(content)
|
16
ArknightsUID/utils/message.py
Normal file
16
ArknightsUID/utils/message.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from gsuid_core.bot import Bot
|
||||||
|
|
||||||
|
|
||||||
|
async def send_diff_msg(bot: Bot, code: Any, data: dict | None = None):
|
||||||
|
if data is None:
|
||||||
|
data = {
|
||||||
|
0: '绑定UID成功!',
|
||||||
|
-1: 'UID的位数不正确!',
|
||||||
|
-2: 'UID已经绑定过了!',
|
||||||
|
-3: '你输入了错误的格式!',
|
||||||
|
}
|
||||||
|
for retcode in data:
|
||||||
|
if code == retcode:
|
||||||
|
return await bot.send(data[retcode])
|
@ -1,5 +1,100 @@
|
|||||||
from msgspec import Struct, field
|
from msgspec import Struct, field
|
||||||
|
|
||||||
|
################
|
||||||
|
# ArknightsUserMeModel Start
|
||||||
|
################
|
||||||
|
|
||||||
|
class UserMeInfoApply(Struct):
|
||||||
|
nickname: str
|
||||||
|
profile: str
|
||||||
|
|
||||||
|
|
||||||
|
class UserMeModerator(Struct):
|
||||||
|
isModerator: bool
|
||||||
|
|
||||||
|
|
||||||
|
class UserGameStatusAp(Struct):
|
||||||
|
current: int
|
||||||
|
max_: int = field(name='max')
|
||||||
|
lastApAddTime: int
|
||||||
|
completeRecoveryTime: int
|
||||||
|
|
||||||
|
|
||||||
|
class UserGameStatusSecretary(Struct):
|
||||||
|
charId: str
|
||||||
|
skinId: str
|
||||||
|
|
||||||
|
|
||||||
|
class UserGameStatusAvatar(Struct):
|
||||||
|
type_: str = field(name='type')
|
||||||
|
id_: str = field(name='id')
|
||||||
|
|
||||||
|
|
||||||
|
class UserGameStatus(Struct):
|
||||||
|
uid: str
|
||||||
|
name: str
|
||||||
|
level: int
|
||||||
|
avatar: UserGameStatusAvatar
|
||||||
|
registerTs: int
|
||||||
|
mainStageProgress: str
|
||||||
|
secretary: UserGameStatusSecretary
|
||||||
|
resume: str
|
||||||
|
subscriptionEnd: int
|
||||||
|
ap: UserGameStatusAp
|
||||||
|
storeTs: int
|
||||||
|
lastOnlineTs: int
|
||||||
|
charCnt: int
|
||||||
|
furnitureCnt: int
|
||||||
|
skinCnt: int
|
||||||
|
|
||||||
|
|
||||||
|
class UserMeInfoRts(Struct):
|
||||||
|
liked: str
|
||||||
|
collect: str
|
||||||
|
comment: str
|
||||||
|
follow: str
|
||||||
|
fans: str
|
||||||
|
black: str
|
||||||
|
pub: str
|
||||||
|
|
||||||
|
|
||||||
|
class UserMeInfo(Struct):
|
||||||
|
id_: str = field(name='id')
|
||||||
|
nickname: str
|
||||||
|
profile: str
|
||||||
|
avatarCode: int
|
||||||
|
avatar: str
|
||||||
|
backgroundCode: int
|
||||||
|
isCreator: bool
|
||||||
|
creatorIdentifiers: list[str]
|
||||||
|
status: int
|
||||||
|
operationStatus: int
|
||||||
|
identity: int
|
||||||
|
kind: int
|
||||||
|
latestIpLocation: str
|
||||||
|
moderatorStatus: int
|
||||||
|
moderatorChangeTime: int
|
||||||
|
gender: int
|
||||||
|
birthday: str
|
||||||
|
|
||||||
|
|
||||||
|
class ArknightsUserMeModel(Struct):
|
||||||
|
user: UserMeInfo
|
||||||
|
userRts: UserMeInfoRts
|
||||||
|
userSanctionList: list[str]
|
||||||
|
gameStatus: UserGameStatus
|
||||||
|
moderator: UserMeModerator
|
||||||
|
userInfoApply: UserMeInfoApply
|
||||||
|
|
||||||
|
################
|
||||||
|
# ArknightsUserMeModel End
|
||||||
|
################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
################
|
||||||
|
# ArknightsPlayerInfoModel Start
|
||||||
|
################
|
||||||
|
|
||||||
class PlayerSkinAsset(Struct):
|
class PlayerSkinAsset(Struct):
|
||||||
pass
|
pass
|
||||||
@ -480,3 +575,8 @@ class ArknightsPlayerInfoModel(Struct, omit_defaults=True, gc=False):
|
|||||||
manufactureFormulaInfoMap: dict[str, PlayerManufactureFormulaInfo]
|
manufactureFormulaInfoMap: dict[str, PlayerManufactureFormulaInfo]
|
||||||
charAssets: list[PlayerCharAsset]
|
charAssets: list[PlayerCharAsset]
|
||||||
skinAssets: list[PlayerSkinAsset]
|
skinAssets: list[PlayerSkinAsset]
|
||||||
|
|
||||||
|
|
||||||
|
################
|
||||||
|
# ArknightsPlayerInfoModel End
|
||||||
|
################
|
||||||
|
23
ArknightsUID/utils/resource/RESOURCE_PATH.py
Normal file
23
ArknightsUID/utils/resource/RESOURCE_PATH.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from gsuid_core.data_store import get_res_path
|
||||||
|
|
||||||
|
MAIN_PATH = get_res_path() / 'ArknightsUID'
|
||||||
|
sys.path.append(str(MAIN_PATH))
|
||||||
|
|
||||||
|
CU_BG_PATH = MAIN_PATH / 'bg'
|
||||||
|
CONFIG_PATH = MAIN_PATH / 'config.json'
|
||||||
|
PLAYER_PATH = MAIN_PATH / 'players'
|
||||||
|
RESOURCE_PATH = MAIN_PATH / 'resource'
|
||||||
|
|
||||||
|
def init_dir():
|
||||||
|
for i in [
|
||||||
|
MAIN_PATH,
|
||||||
|
CU_BG_PATH,
|
||||||
|
PLAYER_PATH,
|
||||||
|
RESOURCE_PATH,
|
||||||
|
]:
|
||||||
|
i.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
init_dir()
|
11
ArknightsUID/utils/resource/download_all_resource.py
Normal file
11
ArknightsUID/utils/resource/download_all_resource.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
|
from .download_from_cos import download_all_file_from_cos
|
||||||
|
|
||||||
|
|
||||||
|
async def download_all_resource():
|
||||||
|
ret = await asyncio.gather(download_all_file_from_cos())
|
||||||
|
ret = [str(x) for x in ret if x]
|
||||||
|
if ret:
|
||||||
|
return '\n'.join(ret)
|
||||||
|
return 'sr全部资源下载完成!'
|
101
ArknightsUID/utils/resource/download_from_cos.py
Normal file
101
ArknightsUID/utils/resource/download_from_cos.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from aiohttp.client import ClientSession
|
||||||
|
from gsuid_core.logger import logger
|
||||||
|
from msgspec import json as msgjson
|
||||||
|
|
||||||
|
from .download_url import download_file
|
||||||
|
from .RESOURCE_PATH import RESOURCE_PATH
|
||||||
|
|
||||||
|
with open(
|
||||||
|
Path(__file__).parent / 'resource_map.json', encoding='UTF-8'
|
||||||
|
) as f:
|
||||||
|
resource_map = msgjson.decode(
|
||||||
|
f.read(),
|
||||||
|
type=dict[str, dict[str, dict[str, dict[str, int | str]]]],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def download_all_file_from_cos():
|
||||||
|
async def _download(tasks: list[asyncio.Task]):
|
||||||
|
failed_list.extend(
|
||||||
|
list(filter(lambda x: x is not None, await asyncio.gather(*tasks)))
|
||||||
|
)
|
||||||
|
tasks.clear()
|
||||||
|
logger.info('[cos]下载完成!')
|
||||||
|
|
||||||
|
failed_list: list[tuple[str, str, str, str]] = []
|
||||||
|
TASKS = []
|
||||||
|
async with ClientSession() as sess:
|
||||||
|
for res_type in ['resource']:
|
||||||
|
logger.info('[cos]开始下载资源文件...')
|
||||||
|
resource_type_list = [
|
||||||
|
'character',
|
||||||
|
'character_portrait',
|
||||||
|
'character_preview',
|
||||||
|
'consumable',
|
||||||
|
'element',
|
||||||
|
'light_cone',
|
||||||
|
'relic',
|
||||||
|
'skill',
|
||||||
|
]
|
||||||
|
for resource_type in resource_type_list:
|
||||||
|
file_dict = resource_map[res_type][resource_type]
|
||||||
|
logger.info(
|
||||||
|
f'[cos]数据库[{resource_type}]中存在{len(file_dict)}个内容!'
|
||||||
|
)
|
||||||
|
temp_num = 0
|
||||||
|
for file_name, file_info in file_dict.items():
|
||||||
|
name = file_name
|
||||||
|
size = file_info['size']
|
||||||
|
url = file_info['url']
|
||||||
|
if isinstance(url, int):
|
||||||
|
continue
|
||||||
|
path = Path(RESOURCE_PATH / resource_type / name)
|
||||||
|
if path.exists():
|
||||||
|
is_diff = size == os.stat(path).st_size
|
||||||
|
else:
|
||||||
|
is_diff = True
|
||||||
|
if (
|
||||||
|
not path.exists()
|
||||||
|
or not os.stat(path).st_size
|
||||||
|
or not is_diff
|
||||||
|
):
|
||||||
|
logger.info(f'[cos]开始下载[{resource_type}]_[{name}]...')
|
||||||
|
temp_num += 1
|
||||||
|
TASKS.append(
|
||||||
|
asyncio.wait_for(
|
||||||
|
download_file(
|
||||||
|
url, res_type, resource_type, name, sess
|
||||||
|
),
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# await download_file(url, FILE_TO_PATH[file], name)
|
||||||
|
if len(TASKS) >= 10:
|
||||||
|
await _download(TASKS)
|
||||||
|
else:
|
||||||
|
await _download(TASKS)
|
||||||
|
if temp_num == 0:
|
||||||
|
im = f'[cos]数据库[{resource_type}]无需下载!'
|
||||||
|
else:
|
||||||
|
im = f'[cos]数据库[{resource_type}]已下载{temp_num}个内容!'
|
||||||
|
temp_num = 0
|
||||||
|
logger.info(im)
|
||||||
|
if failed_list:
|
||||||
|
logger.info(f'[cos]开始重新下载失败的{len(failed_list)}个文件...')
|
||||||
|
for url, res_type, resource_type, name in failed_list:
|
||||||
|
TASKS.append(
|
||||||
|
asyncio.wait_for(
|
||||||
|
download_file(url, res_type, resource_type, name, sess),
|
||||||
|
timeout=60,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if len(TASKS) >= 10:
|
||||||
|
await _download(TASKS)
|
||||||
|
else:
|
||||||
|
await _download(TASKS)
|
||||||
|
if count := len(failed_list):
|
||||||
|
logger.error(f'[cos]仍有{count}个文件未下载,请使用命令 `下载全部资源` 重新下载')
|
59
ArknightsUID/utils/resource/download_url.py
Normal file
59
ArknightsUID/utils/resource/download_url.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
import aiofiles
|
||||||
|
from aiohttp.client import ClientSession
|
||||||
|
from aiohttp.client_exceptions import ClientConnectorError
|
||||||
|
from gsuid_core.logger import logger
|
||||||
|
|
||||||
|
from .RESOURCE_PATH import RESOURCE_PATH
|
||||||
|
|
||||||
|
PATHDICT = {
|
||||||
|
'resource': RESOURCE_PATH,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def download(
|
||||||
|
url: str,
|
||||||
|
res_type: str,
|
||||||
|
resource_type: str,
|
||||||
|
name: str,
|
||||||
|
) -> tuple[str, str, str] | None:
|
||||||
|
"""
|
||||||
|
:说明:
|
||||||
|
下载URL保存入目录
|
||||||
|
:参数:
|
||||||
|
* url: `str`
|
||||||
|
资源下载地址。
|
||||||
|
* res_type: `str`
|
||||||
|
资源类型,`resource`或`wiki`。
|
||||||
|
* resource_type: `str`
|
||||||
|
资源文件夹名
|
||||||
|
* name: `str`
|
||||||
|
资源保存名称
|
||||||
|
:返回(失败才会有返回值):
|
||||||
|
url: `str`
|
||||||
|
resource_type: `str`
|
||||||
|
name: `str`
|
||||||
|
"""
|
||||||
|
async with ClientSession() as sess:
|
||||||
|
return await download_file(url, res_type, resource_type, name, sess)
|
||||||
|
|
||||||
|
|
||||||
|
async def download_file(
|
||||||
|
url: str,
|
||||||
|
res_type: str,
|
||||||
|
resource_type: str,
|
||||||
|
name: str,
|
||||||
|
sess: ClientSession | None = None,
|
||||||
|
) -> tuple[str, str, str] | None:
|
||||||
|
if sess is None:
|
||||||
|
sess = ClientSession()
|
||||||
|
try:
|
||||||
|
async with sess.get(url) as res:
|
||||||
|
content = await res.read()
|
||||||
|
except ClientConnectorError:
|
||||||
|
logger.warning(f"[cos]{name}下载失败")
|
||||||
|
return url, resource_type, name
|
||||||
|
async with aiofiles.open(
|
||||||
|
PATHDICT[res_type] / resource_type / name, "wb"
|
||||||
|
) as f:
|
||||||
|
await f.write(content)
|
0
__nest__.py
Normal file
0
__nest__.py
Normal file
Loading…
x
Reference in New Issue
Block a user