2022-09-17 16:28:51 +00:00
|
|
|
import asyncio
|
2022-07-26 10:07:31 +00:00
|
|
|
import hashlib
|
|
|
|
import os
|
2022-09-17 16:28:51 +00:00
|
|
|
from multiprocessing import RLock
|
2022-09-09 08:37:15 +00:00
|
|
|
from pathlib import Path
|
2022-09-17 16:28:51 +00:00
|
|
|
from typing import Optional, Tuple, Union, cast
|
2022-07-26 10:07:31 +00:00
|
|
|
|
|
|
|
import aiofiles
|
|
|
|
import genshin
|
|
|
|
import httpx
|
|
|
|
from genshin import Client, types
|
|
|
|
from httpx import UnsupportedProtocol
|
|
|
|
|
2022-09-08 01:08:37 +00:00
|
|
|
from core.bot import bot
|
|
|
|
from core.cookies.services import CookiesService, PublicCookiesService
|
|
|
|
from core.error import ServiceNotFoundError
|
2022-08-11 13:18:12 +00:00
|
|
|
from core.user.services import UserService
|
2022-09-01 01:51:01 +00:00
|
|
|
from utils.error import UrlResourcesNotFoundError
|
2022-09-08 01:08:37 +00:00
|
|
|
from utils.log import logger
|
|
|
|
from utils.models.base import RegionEnum
|
2022-07-26 10:07:31 +00:00
|
|
|
|
|
|
|
USER_AGENT: str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " \
|
|
|
|
"Chrome/90.0.4430.72 Safari/537.36"
|
|
|
|
REQUEST_HEADERS: dict = {'User-Agent': USER_AGENT}
|
|
|
|
current_dir = os.getcwd()
|
|
|
|
cache_dir = os.path.join(current_dir, "cache")
|
|
|
|
if not os.path.exists(cache_dir):
|
|
|
|
os.mkdir(cache_dir)
|
|
|
|
|
2022-09-08 01:08:37 +00:00
|
|
|
cookies_service = bot.services.get(CookiesService)
|
|
|
|
cookies_service = cast(CookiesService, cookies_service)
|
|
|
|
user_service = bot.services.get(UserService)
|
|
|
|
user_service = cast(UserService, user_service)
|
|
|
|
public_cookies_service = bot.services.get(PublicCookiesService)
|
|
|
|
public_cookies_service = cast(PublicCookiesService, public_cookies_service)
|
|
|
|
|
2022-07-31 15:47:57 +00:00
|
|
|
REGION_MAP = {
|
|
|
|
"1": RegionEnum.HYPERION,
|
|
|
|
"2": RegionEnum.HYPERION,
|
|
|
|
"5": RegionEnum.HYPERION,
|
|
|
|
"6": RegionEnum.HOYOLAB,
|
|
|
|
"7": RegionEnum.HOYOLAB,
|
|
|
|
"8": RegionEnum.HOYOLAB,
|
|
|
|
"9": RegionEnum.HOYOLAB,
|
2022-07-26 10:07:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def sha1(text: str) -> str:
|
|
|
|
_sha1 = hashlib.sha1()
|
|
|
|
_sha1.update(text.encode())
|
|
|
|
return _sha1.hexdigest()
|
|
|
|
|
|
|
|
|
2022-09-09 08:37:15 +00:00
|
|
|
async def url_to_file(url: str, return_path: bool = False) -> str:
|
2022-07-26 10:07:31 +00:00
|
|
|
url_sha1 = sha1(url)
|
|
|
|
url_file_name = os.path.basename(url)
|
|
|
|
_, extension = os.path.splitext(url_file_name)
|
|
|
|
temp_file_name = url_sha1 + extension
|
|
|
|
file_dir = os.path.join(cache_dir, temp_file_name)
|
|
|
|
if not os.path.exists(file_dir):
|
|
|
|
async with httpx.AsyncClient(headers=REQUEST_HEADERS) as client:
|
|
|
|
try:
|
|
|
|
data = await client.get(url)
|
2022-09-08 01:08:37 +00:00
|
|
|
except UnsupportedProtocol:
|
|
|
|
logger.error(f"连接不支持 url[{url}]")
|
2022-07-26 10:07:31 +00:00
|
|
|
return ""
|
|
|
|
if data.is_error:
|
2022-09-08 01:08:37 +00:00
|
|
|
logger.error(f"请求出现错误 url[{url}] status_code[{data.status_code}]")
|
2022-09-01 01:51:01 +00:00
|
|
|
raise UrlResourcesNotFoundError(url)
|
|
|
|
if data.status_code != 200:
|
2022-09-08 01:08:37 +00:00
|
|
|
logger.error(f"url_to_file 获取url[{url}] 错误 status_code[f{data.status_code}]")
|
2022-09-01 01:51:01 +00:00
|
|
|
raise UrlResourcesNotFoundError(url)
|
2022-07-26 10:07:31 +00:00
|
|
|
async with aiofiles.open(file_dir, mode='wb') as f:
|
|
|
|
await f.write(data.content)
|
2022-09-08 01:08:37 +00:00
|
|
|
logger.debug(f"url_to_file 获取url[{url}] 并下载到 file_dir[{file_dir}]")
|
2022-09-09 08:37:15 +00:00
|
|
|
|
|
|
|
if return_path:
|
|
|
|
return file_dir
|
|
|
|
|
|
|
|
return Path(file_dir).as_uri()
|
2022-07-26 10:07:31 +00:00
|
|
|
|
|
|
|
|
2022-09-08 01:08:37 +00:00
|
|
|
async def get_genshin_client(user_id: int, region: Optional[RegionEnum] = None) -> Client:
|
|
|
|
if user_service is None:
|
|
|
|
raise ServiceNotFoundError(UserService)
|
|
|
|
if cookies_service is None:
|
|
|
|
raise ServiceNotFoundError(CookiesService)
|
2022-07-26 10:07:31 +00:00
|
|
|
user = await user_service.get_user_by_id(user_id)
|
2022-07-31 15:47:57 +00:00
|
|
|
if region is None:
|
|
|
|
region = user.region
|
2022-08-05 13:22:21 +00:00
|
|
|
cookies = await cookies_service.get_cookies(user_id, region)
|
2022-07-31 15:47:57 +00:00
|
|
|
if region == RegionEnum.HYPERION:
|
2022-08-05 12:21:10 +00:00
|
|
|
uid = user.yuanshen_uid
|
2022-08-05 13:22:21 +00:00
|
|
|
client = genshin.Client(cookies=cookies.cookies, game=types.Game.GENSHIN, region=types.Region.CHINESE, uid=uid)
|
2022-07-31 15:47:57 +00:00
|
|
|
elif region == RegionEnum.HOYOLAB:
|
2022-08-05 12:21:10 +00:00
|
|
|
uid = user.genshin_uid
|
2022-08-05 13:22:21 +00:00
|
|
|
client = genshin.Client(cookies=cookies.cookies,
|
2022-07-31 07:55:14 +00:00
|
|
|
game=types.Game.GENSHIN, region=types.Region.OVERSEAS, lang="zh-cn", uid=uid)
|
2022-07-31 15:47:57 +00:00
|
|
|
else:
|
2022-08-05 14:45:54 +00:00
|
|
|
raise TypeError("region is not RegionEnum.NULL")
|
2022-07-26 10:07:31 +00:00
|
|
|
return client
|
|
|
|
|
|
|
|
|
2022-09-08 01:08:37 +00:00
|
|
|
async def get_public_genshin_client(user_id: int) -> Tuple[Client, Optional[int]]:
|
|
|
|
if user_service is None:
|
|
|
|
raise ServiceNotFoundError(UserService)
|
|
|
|
if public_cookies_service is None:
|
|
|
|
raise ServiceNotFoundError(PublicCookiesService)
|
|
|
|
user = await user_service.get_user_by_id(user_id)
|
|
|
|
region = user.region
|
|
|
|
cookies = await public_cookies_service.get_cookies(user_id, region)
|
|
|
|
if region == RegionEnum.HYPERION:
|
|
|
|
uid = user.yuanshen_uid
|
|
|
|
client = genshin.Client(cookies=cookies.cookies, game=types.Game.GENSHIN, region=types.Region.CHINESE)
|
|
|
|
elif region == RegionEnum.HOYOLAB:
|
|
|
|
uid = user.genshin_uid
|
|
|
|
client = genshin.Client(cookies=cookies.cookies,
|
|
|
|
game=types.Game.GENSHIN, region=types.Region.OVERSEAS, lang="zh-cn")
|
|
|
|
else:
|
|
|
|
raise TypeError("region is not RegionEnum.NULL")
|
|
|
|
return client, uid
|
|
|
|
|
|
|
|
|
2022-07-31 15:47:57 +00:00
|
|
|
def region_server(uid: Union[int, str]) -> RegionEnum:
|
|
|
|
if isinstance(uid, int):
|
|
|
|
region = REGION_MAP.get(str(uid)[0])
|
|
|
|
elif isinstance(uid, str):
|
|
|
|
region = REGION_MAP.get(str(uid)[0])
|
|
|
|
else:
|
2022-08-06 09:21:58 +00:00
|
|
|
raise TypeError("UID variable type error")
|
2022-07-31 15:47:57 +00:00
|
|
|
if region:
|
|
|
|
return region
|
2022-07-26 10:07:31 +00:00
|
|
|
else:
|
2022-07-31 15:47:57 +00:00
|
|
|
raise TypeError(f"UID {uid} isn't associated with any region")
|
2022-09-17 16:28:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
def mkdir(path: Path) -> Path:
|
|
|
|
"""根据路径依次创建文件夹"""
|
|
|
|
path_list = []
|
|
|
|
|
|
|
|
parent = path.parent if path.suffix else path
|
|
|
|
while not parent.exists():
|
|
|
|
path_list.append(parent)
|
|
|
|
try:
|
|
|
|
parent.mkdir(exist_ok=True)
|
|
|
|
except FileNotFoundError:
|
|
|
|
parent = parent.parent
|
|
|
|
|
|
|
|
while path_list:
|
|
|
|
path_list.pop().mkdir(exist_ok=True)
|
|
|
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
class Event:
|
|
|
|
"""一个线程安装的事件对象"""
|
|
|
|
_event: asyncio.Event = asyncio.Event()
|
|
|
|
_lock = RLock()
|
|
|
|
|
|
|
|
async def wait(self) -> bool:
|
|
|
|
return await self._event.wait()
|
|
|
|
|
|
|
|
def set(self):
|
|
|
|
with self._lock:
|
|
|
|
self._event.set()
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
with self._lock:
|
|
|
|
self._event.clear()
|
|
|
|
|
|
|
|
def is_set(self) -> bool:
|
|
|
|
with self._lock:
|
|
|
|
return self._event.is_set()
|