This commit is contained in:
HibiKier
2022-08-21 13:37:03 +08:00
parent 40fed798a1
commit 7efcff13bb
37 changed files with 1977 additions and 967 deletions
@@ -19,6 +19,9 @@ class Genshin(db.Model):
resin_remind = db.Column(db.Boolean(), default=False) # 树脂提醒
resin_recovery_time = db.Column(db.DateTime(timezone=True)) # 满树脂提醒日期
bind_group = db.Column(db.BigInteger())
login_ticket = db.Column(db.String(), default="")
stuid = db.Column(db.String(), default="")
stoken = db.Column(db.String(), default="")
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
@@ -386,3 +389,96 @@ class Genshin(db.Model):
for u in await cls.query.with_for_update().gino.all():
if u.today_query_uid:
await u.update(today_query_uid="").apply()
@classmethod
async def set_stuid(cls, uid: int, stuid: str) -> bool:
"""
说明:
设置stuid
参数:
:param uid: 原神uid
:param stuid: stuid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(stuid=stuid).apply()
return True
return False
@classmethod
async def set_stoken(cls, uid: int, stoken: str) -> bool:
"""
说明:
设置stoken
参数:
:param uid: 原神uid
:param stoken: stoken
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(stoken=stoken).apply()
return True
return False
@classmethod
async def set_login_ticket(cls, uid: int, login_ticket: str) -> bool:
"""
说明:
设置login_ticket
参数:
:param uid: 原神uid
:param login_ticket: login_ticket
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(login_ticket=login_ticket).apply()
return True
return False
# 获取login_ticket
@classmethod
async def get_login_ticket(cls, uid: int) -> Optional[str]:
"""
说明:
获取login_ticket
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.login_ticket
return None
# 获取stuid
@classmethod
async def get_stuid(cls, uid: int) -> Optional[str]:
"""
说明:
获取stuid
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.stuid
return None
# 获取stoken
@classmethod
async def get_stoken(cls, uid: int) -> Optional[str]:
"""
说明:
获取stoken
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid)
user = await query.gino.first()
if user:
return user.stoken
return None
@@ -5,6 +5,8 @@ from .._models import Genshin
from services.log import logger
from nonebot.params import CommandArg, Command
from typing import Tuple
from utils.http_utils import AsyncHttpx
import json
__zx_plugin_name__ = "原神绑定"
@@ -39,6 +41,10 @@ bind = on_command(
unbind = on_command("原神解绑", priority=5, block=True)
web_Api = "https://api-takumi.mihoyo.com"
bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
@bind.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
@@ -81,6 +87,33 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message
if msg.endswith('"') or msg.endswith("'"):
msg = msg[:-1]
await Genshin.set_cookie(uid, msg)
cookie = msg
# 用: 代替=, ,代替;
cookie = '{"' + cookie.replace('=', '": "').replace("; ", '","') + '"}'
print(cookie)
cookie_json = json.loads(cookie)
print(cookie_json)
login_ticket = cookie_json['login_ticket']
# try:
res = await AsyncHttpx.get(url=bbs_Cookie_url.format(login_ticket))
res.encoding = "utf-8"
data = json.loads(res.text)
print(data)
if "成功" in data["data"]["msg"]:
stuid = str(data["data"]["cookie_info"]["account_id"])
res = await AsyncHttpx.get(url=bbs_Cookie_url2.format(
login_ticket, stuid))
res.encoding = "utf-8"
data = json.loads(res.text)
stoken = data["data"]["list"][0]["token"]
# await Genshin.set_cookie(uid, cookie)
await Genshin.set_stoken(uid, stoken)
await Genshin.set_stuid(uid, stuid)
await Genshin.set_login_ticket(uid, login_ticket)
# except Exception as e:
# await bind.finish("获取登陆信息失败,请检查cookie是否正确或更新cookie")
elif data["data"]["msg"] == "登录信息已失效,请重新登录":
await bind.finish("登录信息失效,请重新获取最新cookie进行绑定")
_x = f"已成功为uid:{uid} 设置cookie"
if isinstance(event, GroupMessageEvent):
await Genshin.set_bind_group(uid, event.group_id)
@@ -1,4 +1,5 @@
from .data_source import get_sign_reward_list, genshin_sign
from ..mihoyobbs_sign import mihoyobbs_sign
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
from nonebot import on_command
from services.log import logger
@@ -51,10 +52,13 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
if cmd == "原神我硬签":
try:
msg = await genshin_sign(uid)
return_data = await mihoyobbs_sign(event.user_id)
await genshin_matcher.send(return_data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到"
)
logger.info(msg)
# 硬签,移除定时任务
try:
for i in range(3):
@@ -66,7 +70,7 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
await u.clear_sign_time(uid)
next_date = await Genshin.random_sign_time(uid)
add_job(event.user_id, uid, next_date)
msg += f"因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
msg += f"\n因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
except Exception as e:
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
logger.info(
@@ -1,7 +1,7 @@
from utils.http_utils import AsyncHttpx
from configs.config import Config
from services.log import logger
from .._utils import random_hex, get_old_ds
from ..mihoyobbs_sign.setting import *
from .._models import Genshin
from typing import Optional, Dict
import hashlib
@@ -21,30 +21,37 @@ async def genshin_sign(uid: int) -> Optional[str]:
return "签到失败..."
status = data["message"]
if status == "OK":
sign_info = await _get_sign_info(uid)
if sign_info:
sign_info = sign_info["data"]
sign_list = await get_sign_reward_list()
get_reward = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["name"]
reward_num = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["cnt"]
get_im = f"本次签到获得:{get_reward}x{reward_num}"
if status == "OK" and sign_info["is_sign"]:
return f"\n原神签到成功!\n{get_im}\n本月漏签次数:{sign_info['sign_cnt_missed']}"
try:
sign_info = await _get_sign_info(uid)
if sign_info:
sign_info = sign_info["data"]
sign_list = await get_sign_reward_list()
get_reward = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["name"]
reward_num = sign_list["data"]["awards"][
int(sign_info["total_sign_day"]) - 1
]["cnt"]
get_im = f"本次签到获得:{get_reward}x{reward_num}"
logger.info("get_im:" + get_im + "\nsign_info:" + str(sign_info))
if status == "OK" and sign_info["is_sign"]:
return f"原神签到成功!\n{get_im}\n本月漏签次数:{sign_info['sign_cnt_missed']}"
except Exception as e:
logger.error(f"原神签到发生错误 UID:{str(data)}")
return f"原神签到发生错误: {str(data)}"
else:
return status
return None
if data["data"]["risk_code"] == 375:
return "原神签到失败\n账号可能被风控,请前往米游社手动签到!"
return str(data)
# 获取请求Header里的DS 当web为true则生成网页端的DS
def get_ds(web: bool) -> str:
if web:
n = "9nQiU3AV0rJSIBWgdynfoGMGKaklfbM7"
n = mihoyobbs_Salt_web
else:
n = "9nQiU3AV0rJSIBWgdynfoGMGKaklfbM7"
n = mihoyobbs_Salt
i = str(timestamp())
r = random_text(6)
c = md5("salt=" + n + "&t=" + i + "&r=" + r)
@@ -82,24 +89,15 @@ async def _sign(uid: int, server_id: str = "cn_gf01") -> Optional[Dict[str, str]
server_id = "cn_qd01"
try:
cookie = await Genshin.get_user_cookie(uid, True)
headers['DS'] = get_ds(web=True)
headers['Referer'] = 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true' \
f'&act_id={genshin_Act_id}&utm_source=bbs&utm_medium=mys&utm_campaign=icon'
headers['Cookie'] = cookie
headers['x-rpc-device_id'] = get_device_id(cookie)
req = await AsyncHttpx.post(
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign",
headers={
'Accept': 'application/json, text/plain, */*',
'DS': get_ds(web=True),
'Origin': 'https://webstatic.mihoyo.com',
'x-rpc-app_version': "2.34.1",
'User-Agent': 'Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) '
'Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.3.0',
'x-rpc-client_type': "5",
'Referer': 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,en-US;q=0.8',
'X-Requested-With': 'com.mihoyo.hyperion',
"Cookie": cookie,
'x-rpc-device_id': get_device_id(cookie)
},
json={"act_id": "e202009291139501", "uid": uid, "region": server_id},
url=genshin_Signurl,
headers=headers,
json={"act_id": genshin_Act_id, "uid": uid, "region": server_id},
)
return req.json()
except Exception as e:
@@ -1,4 +1,5 @@
from .data_source import genshin_sign
from ..mihoyobbs_sign import mihoyobbs_sign
from models.group_member_info import GroupInfoUser
from utils.message_builder import at
from services.log import logger
@@ -57,6 +58,11 @@ async def _sign(user_id: int, uid: int, count: int):
:param uid: uid
:param count: 执行次数
"""
try:
return_data = await mihoyobbs_sign(user_id)
except Exception as e:
logger.error(f"mihoyobbs_sign error:{e}")
return_data = "米游社签到失败,请尝试发送'米游社签到'进行手动签到"
if count < 3:
try:
msg = await genshin_sign(uid)
@@ -101,6 +107,7 @@ async def _sign(user_id: int, uid: int, count: int):
bot = get_bot()
if bot:
if user_id in [x["user_id"] for x in await bot.get_friend_list()]:
await bot.send_private_msg(user_id=user_id, message=return_data)
await bot.send_private_msg(user_id=user_id, message=msg)
else:
if not (group_id := await Genshin.get_bind_group(uid)):
@@ -0,0 +1,79 @@
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot import on_command
from services.log import logger
# from .init_task import add_job, scheduler, _sign
# from apscheduler.jobstores.base import JobLookupError
from .._models import Genshin
from nonebot.params import Command
from typing import Tuple
from .mihoyobbs import *
__zx_plugin_name__ = "米游社自动签到"
__plugin_usage__ = """
usage:
发送'米游社签到'或绑定原神自动签到
即可手动/自动进行米游社签到
(若启用了原神自动签到会在签到原神同时完成米游币领取)
--> 每天白嫖90-110米游币不香吗
注:需要重新绑定原神cookie!!!
遇到问题请提issue或@作者
""".strip()
__plugin_des__ = "米游社自动签到任务"
__plugin_cmd__ = ["米游社签到", "米游社我硬签"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HDU_Nbsp"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神签到"],
}
mihoyobbs_matcher = on_command(
"米游社签到", aliases={"米游社我硬签"}, priority=5, block=True
)
@mihoyobbs_matcher.handle()
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
await mihoyobbs_matcher.send("提交米游社签到申请")
return_data = await mihoyobbs_sign(event.user_id)
if return_data:
await mihoyobbs_matcher.finish(return_data)
else:
await mihoyobbs_matcher.finish("米游社签到失败,请查看控制台输出")
async def mihoyobbs_sign(user_id):
uid = await Genshin.get_user_uid(user_id)
stuid = await Genshin.get_stuid(uid)
stoken = await Genshin.get_stoken(uid)
cookie = await Genshin.get_user_cookie(uid)
bbs = mihoyobbs.Mihoyobbs(stuid=stuid, stoken=stoken, cookie=cookie)
await bbs.init()
return_data = ""
if bbs.Task_do["bbs_Sign"] and bbs.Task_do["bbs_Read_posts"] and bbs.Task_do["bbs_Like_posts"] and \
bbs.Task_do["bbs_Share"]:
return_data += f"今天的米游社签到任务已经全部完成了!\n" \
f"一共获得{mihoyobbs.today_have_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
logger.info(f"今天已经全部完成了!一共获得{mihoyobbs.today_have_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
else:
i = 0
print("开始签到")
print(mihoyobbs.today_have_get_coins)
while mihoyobbs.today_get_coins != 0 and i < 3:
# if i > 0:
await bbs.refresh_list()
await bbs.signing()
await bbs.read_posts()
await bbs.like_posts()
await bbs.share_post()
await bbs.get_tasks_list()
i += 1
return_data += "\n" + f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币\n" \
f"还能获得{mihoyobbs.today_get_coins}个米游币\n目前有{mihoyobbs.Have_coins}个米游币"
logger.info(f"今天已经获得{mihoyobbs.today_have_get_coins}个米游币,"
f"还能获得{mihoyobbs.today_get_coins}个米游币,目前有{mihoyobbs.Have_coins}个米游币")
return return_data
@@ -0,0 +1,6 @@
class CookieError(Exception):
def __init__(self, info):
self.info = info
def __str__(self):
return repr(self.info)
@@ -0,0 +1,193 @@
from services.log import logger
from .error import CookieError
from utils.http_utils import AsyncHttpx
from .setting import *
from .tools import *
import json
today_get_coins = 0
today_have_get_coins = 0 # 这个变量以后可能会用上,先留着了
Have_coins = 0
class Mihoyobbs:
def __init__(self, stuid: str, stoken: str, cookie: str) -> None:
self.postsList = None
self.headers = {
"DS": get_ds(web=False),
"cookie": f'stuid={stuid};stoken={stoken}',
"x-rpc-client_type": mihoyobbs_Client_type,
"x-rpc-app_version": mihoyobbs_Version,
"x-rpc-sys_version": "6.0.1",
"x-rpc-channel": "miyousheluodi",
"x-rpc-device_id": get_device_id(cookie=cookie),
"x-rpc-device_name": random_text(random.randint(1, 10)),
"x-rpc-device_model": "Mi 10",
"Referer": "https://app.mihoyo.com",
"Host": "bbs-api.mihoyo.com",
"User-Agent": "okhttp/4.8.0"
}
self.Task_do = {
"bbs_Sign": False,
"bbs_Read_posts": False,
"bbs_Read_posts_num": 3,
"bbs_Like_posts": False,
"bbs_Like_posts_num": 5,
"bbs_Share": False
}
async def init(self):
await self.get_tasks_list()
# 如果这三个任务都做了就没必要获取帖子了
if self.Task_do["bbs_Read_posts"] and self.Task_do["bbs_Like_posts"] and self.Task_do["bbs_Share"]:
pass
else:
self.postsList = await self.get_list()
async def refresh_list(self) -> None:
self.postsList = await self.get_list()
# 获取任务列表,用来判断做了哪些任务
async def get_tasks_list(self):
global today_get_coins
global today_have_get_coins
global Have_coins
logger.info("正在获取任务列表")
req = await AsyncHttpx.get(url=bbs_Tasks_list, headers=self.headers)
data = req.json()
if "err" in data["message"] or data["retcode"] == -100:
logger.error("获取任务列表失败,你的cookie可能已过期,请重新设置cookie。")
raise CookieError('Cookie expires')
else:
today_get_coins = data["data"]["can_get_points"]
today_have_get_coins = data["data"]["already_received_points"]
Have_coins = data["data"]["total_points"]
# 如果当日可获取米游币数量为0直接判断全部任务都完成了
if today_get_coins == 0:
self.Task_do["bbs_Sign"] = True
self.Task_do["bbs_Read_posts"] = True
self.Task_do["bbs_Like_posts"] = True
self.Task_do["bbs_Share"] = True
else:
# 如果第0个大于或等于62则直接判定任务没做
if data["data"]["states"][0]["mission_id"] >= 62:
logger.info(f"今天可以获得{today_get_coins}个米游币")
pass
else:
logger.info(f"还有任务未完成,今天还能获得{today_get_coins}米游币")
for i in data["data"]["states"]:
# 58是讨论区签到
if i["mission_id"] == 58:
if i["is_get_award"]:
self.Task_do["bbs_Sign"] = True
# 59是看帖子
elif i["mission_id"] == 59:
if i["is_get_award"]:
self.Task_do["bbs_Read_posts"] = True
else:
self.Task_do["bbs_Read_posts_num"] -= i["happened_times"]
# 60是给帖子点赞
elif i["mission_id"] == 60:
if i["is_get_award"]:
self.Task_do["bbs_Like_posts"] = True
else:
self.Task_do["bbs_Like_posts_num"] -= i["happened_times"]
# 61是分享帖子
elif i["mission_id"] == 61:
if i["is_get_award"]:
self.Task_do["bbs_Share"] = True
# 分享帖子,是最后一个任务,到这里了下面都是一次性任务,直接跳出循环
break
# 获取要帖子列表
async def get_list(self) -> list:
temp_list = []
logger.info("正在获取帖子列表......")
req = await AsyncHttpx.get(url=bbs_List_url.format(mihoyobbs_List_Use[0]["forumId"]),
headers=self.headers)
data = req.json()["data"]["list"]
for n in range(5):
r_l = random.choice(data)
while r_l["post"]["subject"] in str(temp_list):
r_l = random.choice(data)
temp_list.append([r_l["post"]["post_id"], r_l["post"]["subject"]])
# temp_list.append([data["data"]["list"][n]["post"]["post_id"], data["data"]["list"][n]["post"]["subject"]])
logger.info("已获取{}个帖子".format(len(temp_list)))
return temp_list
# 进行签到操作
async def signing(self):
if self.Task_do["bbs_Sign"]:
logger.info("讨论区任务已经完成过了~")
else:
logger.info("正在签到......")
header = {}
header.update(self.headers)
for i in mihoyobbs_List_Use:
header["DS"] = get_ds2("", json.dumps({"gids": i["id"]}))
req = await AsyncHttpx.post(url=bbs_Sign_url, json={"gids": i["id"]}, headers=header)
data = req.json()
if "err" not in data["message"]:
logger.info(str(i["name"] + data["message"]))
time.sleep(random.randint(2, 8))
else:
logger.error("签到失败,你的cookie可能已过期,请重新设置cookie。")
raise CookieError('Cookie expires')
# 看帖子
async def read_posts(self):
if self.Task_do["bbs_Read_posts"]:
logger.info("看帖任务已经完成过了~")
else:
logger.info("正在看帖......")
for i in range(self.Task_do["bbs_Read_posts_num"]):
req = await AsyncHttpx.get(url=bbs_Detail_url.format(self.postsList[i][0]), headers=self.headers)
data = req.json()
if data["message"] == "OK":
logger.debug("看帖:{} 成功".format(self.postsList[i][1]))
time.sleep(random.randint(2, 8))
# 点赞
async def like_posts(self):
if self.Task_do["bbs_Like_posts"]:
logger.info("点赞任务已经完成过了~")
else:
logger.info("正在点赞......")
for i in range(self.Task_do["bbs_Like_posts_num"]):
req = await AsyncHttpx.post(url=bbs_Like_url, headers=self.headers,
json={"post_id": self.postsList[i][0], "is_cancel": False})
data = req.json()
if data["message"] == "OK":
logger.debug("点赞:{} 成功".format(self.postsList[i][1]))
# 判断取消点赞是否打开
# if config.config["mihoyobbs"]["un_like"] :
# time.sleep(random.randint(2, 8))
# req = httpx.post(url=bbs_Like_url, headers=self.headers,
# json={"post_id": self.postsList[i][0], "is_cancel": True})
# data = req.json()
# if data["message"] == "OK":
# logger.debug("取消点赞:{} 成功".format(self.postsList[i][1]))
time.sleep(random.randint(2, 8))
# 分享操作
async def share_post(self):
if self.Task_do["bbs_Share"]:
logger.info("分享任务已经完成过了~")
else:
logger.info("正在执行分享任务......")
for i in range(3):
req = await AsyncHttpx.get(url=bbs_Share_url.format(self.postsList[0][0]), headers=self.headers)
data = req.json()
if data["message"] == "OK":
logger.debug("分享:{} 成功".format(self.postsList[0][1]))
logger.info("分享任务执行成功......")
break
else:
logger.debug(f"分享任务执行失败,正在执行第{i + 2}次,共3次")
time.sleep(random.randint(2, 8))
time.sleep(random.randint(2, 8))
@@ -0,0 +1,124 @@
# 米游社的Salt
mihoyobbs_Salt = "z8DRIUjNDT7IT5IZXvrUAxyupA1peND9"
mihoyobbs_Salt2 = "t0qEgfub6cvueAPgR5m9aQWWVciEer7v"
mihoyobbs_Salt_web = "9nQiU3AV0rJSIBWgdynfoGMGKaklfbM7"
# 米游社的版本
mihoyobbs_Version = "2.34.1" # Slat和Version相互对应
# 米游社的客户端类型
mihoyobbs_Client_type = "2" # 1为ios 2为安卓
mihoyobbs_Client_type_web = "5" # 4为pc web 5为mobile web
# 米游社的分区列表
mihoyobbs_List = [{
"id": "1",
"forumId": "1",
"name": "崩坏3",
"url": "https://bbs.mihoyo.com/bh3/"
}, {
"id": "2",
"forumId": "26",
"name": "原神",
"url": "https://bbs.mihoyo.com/ys/"
}, {
"id": "3",
"forumId": "30",
"name": "崩坏2",
"url": "https://bbs.mihoyo.com/bh2/"
}, {
"id": "4",
"forumId": "37",
"name": "未定事件簿",
"url": "https://bbs.mihoyo.com/wd/"
}, {
"id": "5",
"forumId": "34",
"name": "大别野",
"url": "https://bbs.mihoyo.com/dby/"
}, {
"id": "6",
"forumId": "52",
"name": "崩坏:星穹铁道",
"url": "https://bbs.mihoyo.com/sr/"
}, {
"id": "8",
"forumId": "57",
"name": "绝区零",
"url": "https://bbs.mihoyo.com/zzz/"
}]
game_id2name = {
"bh2_cn": "崩坏2",
"bh3_cn": "崩坏3",
"nxx_cn": "未定事件簿",
"hk4e_cn": "原神",
}
# Config Load之后run里面进行列表的选择
mihoyobbs_List_Use = [{
"id": "2",
"forumId": "26",
"name": "原神",
"url": "https://bbs.mihoyo.com/ys/"
},
# 不玩原神可以把签到讨论区换为大别墅
# {
# "id": "5",
# "forumId": "34",
# "name": "大别野",
# "url": "https://bbs.mihoyo.com/dby/"
# }
]
# 游戏签到的请求头
headers = {
'Accept': 'application/json, text/plain, */*',
'DS': "",
'Origin': 'https://webstatic.mihoyo.com',
'x-rpc-app_version': mihoyobbs_Version,
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) '
f'Version/4.0 Chrome/103.0.5060.129 Mobile Safari/537.36 miHoYoBBS/{mihoyobbs_Version}',
'x-rpc-client_type': mihoyobbs_Client_type_web,
'Referer': '',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,en-US;q=0.8',
'X-Requested-With': 'com.mihoyo.hyperion',
"Cookie": "",
'x-rpc-device_id': ""
}
# 通用设置
bbs_Api = "https://bbs-api.mihoyo.com"
web_Api = "https://api-takumi.mihoyo.com"
account_Info_url = web_Api + "/binding/api/getUserGameRolesByCookie?game_biz="
# 米游社的API列表
bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
bbs_Tasks_list = bbs_Api + "/apihub/sapi/getUserMissionsState" # 获取任务列表
bbs_Sign_url = bbs_Api + "/apihub/app/api/signIn" # post
bbs_List_url = bbs_Api + "/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1"
bbs_Detail_url = bbs_Api + "/post/api/getPostFull?post_id={}"
bbs_Share_url = bbs_Api + "/apihub/api/getShareConf?entity_id={}&entity_type=1"
bbs_Like_url = bbs_Api + "/apihub/sapi/upvotePost" # post json
# 崩坏2自动签到相关的相关设置
honkai2_Act_id = "e202203291431091"
honkai2_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={honkai2_Act_id}'
honkai2_Is_signurl = web_Api + "/event/luna/info?lang=zh-cn&act_id={}&region={}&uid={}"
honkai2_Sign_url = web_Api + "/event/luna/sign"
# 崩坏3自动签到相关的设置
honkai3rd_Act_id = "e202207181446311"
honkai3rd_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={honkai3rd_Act_id}'
honkai3rd_Is_signurl = web_Api + "/event/luna/info?lang=zh-cn&act_id={}&region={}&uid={}"
honkai3rd_Sign_url = web_Api + "/event/luna/sign"
# 未定事件簿自动签到相关设置
tearsofthemis_Act_id = "e202202251749321"
tearsofthemis_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={tearsofthemis_Act_id}'
tearsofthemis_Is_signurl = honkai2_Is_signurl
tearsofthemis_Sign_url = honkai2_Sign_url # 和二崩完全一致
# 原神自动签到相关的设置
genshin_Act_id = "e202009291139501"
genshin_checkin_rewards = f'{web_Api}/event/bbs_sign_reward/home?act_id={genshin_Act_id}'
genshin_Is_signurl = web_Api + "/event/bbs_sign_reward/info?act_id={}&region={}&uid={}"
genshin_Signurl = web_Api + "/event/bbs_sign_reward/sign"
@@ -0,0 +1,65 @@
import uuid
import time
import random
import string
import hashlib
from .setting import *
# md5计算
def md5(text: str) -> str:
md5 = hashlib.md5()
md5.update(text.encode())
return md5.hexdigest()
# 随机文本
def random_text(num: int) -> str:
return ''.join(random.sample(string.ascii_lowercase + string.digits, num))
# 时间戳
def timestamp() -> int:
return int(time.time())
# 获取请求Header里的DS 当web为true则生成网页端的DS
def get_ds(web: bool) -> str:
if web:
n = mihoyobbs_Salt_web
else:
n = mihoyobbs_Salt
i = str(timestamp())
r = random_text(6)
c = md5("salt=" + n + "&t=" + i + "&r=" + r)
return f"{i},{r},{c}"
# 获取请求Header里的DS(版本2) 这个版本ds之前见到都是查询接口里的
def get_ds2(q: str, b: str) -> str:
n = mihoyobbs_Salt2
i = str(timestamp())
r = str(random.randint(100001, 200000))
add = f'&b={b}&q={q}'
c = md5("salt=" + n + "&t=" + i + "&r=" + r + add)
return f"{i},{r},{c}"
# 生成一个device id
def get_device_id(cookie) -> str:
return str(uuid.uuid3(uuid.NAMESPACE_URL, cookie))
# 获取签到的奖励名称
def get_item(raw_data: dict) -> str:
temp_name = raw_data["name"]
temp_cnt = raw_data["cnt"]
return f"{temp_name}x{temp_cnt}"
# 获取明天早晨0点的时间戳
def next_day() -> int:
now_time = int(time.time())
next_day_time = now_time - now_time % 86400 + time.timezone + 86400
return next_day_time
@@ -26,12 +26,17 @@ memo_path.mkdir(exist_ok=True, parents=True)
@driver.on_startup
async def _():
for name, url in zip(
["resin.png", "task.png", "resin_discount.png"],
[
"resin.png", "task.png", "resin_discount.png", "chengehu.png",
"zhibian.png"
],
[
"https://upload-bbs.mihoyo.com/upload/2021/09/29/8819732/54266243c7d15ba31690c8f5d63cc3c6_71491376413333325"
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
"https://patchwiki.biligame.com/images/ys/thumb/c/cc/6k6kuj1kte6m1n7hexqfrn92z6h4yhh.png/60px-委托任务logo.png",
"https://patchwiki.biligame.com/images/ys/d/d9/t1hv6wpucbwucgkhjntmzroh90nmcdv.png",
"https://s3.bmp.ovh/imgs/2022/07/24/28d9338c7da4bcb2.png",
"https://genshin.honeyhunterworld.com/img/gadget/i_3016.png",
],
):
file = memo_path / name
@@ -40,7 +45,8 @@ async def _():
logger.info(f"已下载原神便签资源 -> {file}...")
async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[str, MessageSegment]]:
async def get_user_memo(user_id: int, uid: int,
uname: str) -> Optional[Union[str, MessageSegment]]:
uid = str(uid)
if uid[0] in ["1", "2"]:
server_id = "cn_gf01"
@@ -54,12 +60,16 @@ async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[st
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
url=
f"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
headers={
"DS": get_ds(f"role_id={uid}&server={server_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"x-rpc-app_version": Config.get_config("genshin",
"mhyVersion"),
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin",
"client_type"),
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
},
@@ -75,11 +85,18 @@ async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
return "发生了一些错误,请稍后再试", 998
def create_border(
image_name: str, content: str, notice_text: str, value: str
) -> BuildImage:
border = BuildImage(500, 100, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20)
text_bk = BuildImage(350, 96, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf")
def create_border(image_name: str, content: str, notice_text: str,
value: str) -> BuildImage:
border = BuildImage(500,
75,
color="#E0D9D1",
font="HYWenHei-85W.ttf",
font_size=20)
text_bk = BuildImage(350,
75,
color="#F5F1EB",
font_size=23,
font="HYWenHei-85W.ttf")
_x = 70 if image_name == "resin.png" else 50
_px = 10 if image_name == "resin.png" else 20
text_bk.paste(
@@ -88,7 +105,7 @@ def create_border(
True,
center_type="by_height",
)
text_bk.text((87, 20), content)
text_bk.text((87, 15), content)
text_bk.paste(
BuildImage(
0,
@@ -98,18 +115,19 @@ def create_border(
font="HYWenHei-85W.ttf",
font_size=17,
),
(87, 50),
(87, 45),
True,
)
font_width, _ = border.getsize(value)
border.text((350 + 76 - int(font_width / 2), 0), value, center_type="by_height")
border.text((350 + 76 - int(font_width / 2), 0),
value,
center_type="by_height")
border.paste(text_bk, (2, 0), center_type="by_height")
return border
async def parse_data_and_draw(
user_id: int, uid: str, server_id: str, uname: str
) -> Union[str, MessageSegment]:
async def parse_data_and_draw(user_id: int, uid: str, server_id: str,
uname: str) -> Union[str, MessageSegment]:
data, code = await get_memo(uid, server_id)
if code != 200:
return data
@@ -120,13 +138,11 @@ async def parse_data_and_draw(
if not role_avatar.exists():
await AsyncHttpx.download_file(x["avatar_side_icon"], role_avatar)
return await asyncio.get_event_loop().run_in_executor(
None, _parse_data_and_draw, data, user_avatar, uid, uname
)
None, _parse_data_and_draw, data, user_avatar, uid, uname)
def _parse_data_and_draw(
data: dict, user_avatar: BytesIO, uid: int, uname: str
) -> Union[str, MessageSegment]:
def _parse_data_and_draw(data: dict, user_avatar: BytesIO, uid: int,
uname: str) -> Union[str, MessageSegment]:
current_resin = data["current_resin"] # 当前树脂
max_resin = data["max_resin"] # 最大树脂
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
@@ -137,17 +153,37 @@ def _parse_data_and_draw(
current_expedition_num = data["current_expedition_num"] # 当前挖矿人数
max_expedition_num = data["max_expedition_num"] # 每日挖矿最大人数
expeditions = data["expeditions"] # 挖矿详情
current_coin = data["current_home_coin"] # 当前宝钱
max_coin = data["max_home_coin"] # 最大宝钱
coin_recovery_time = data["home_coin_recovery_time"] # 宝钱全部回复时间
transformer_available = data["transformer"]["obtained"] # 参量质变仪可获取
transformer_state = data["transformer"]["recovery_time"][
"reached"] # 参量质变仪状态
transformer_recovery_time = data["transformer"]["recovery_time"][
"Day"] # 参量质变仪回复时间
transformer_recovery_hour = data["transformer"]["recovery_time"][
"Hour"] # 参量质变仪回复时间
coin_minute, coin_second = divmod(int(coin_recovery_time), 60)
coin_hour, coin_minute = divmod(coin_minute, 60)
#print(data)
minute, second = divmod(int(resin_recovery_time), 60)
hour, minute = divmod(minute, 60)
A = BuildImage(1030, 520, color="#f1e9e1", font_size=15, font="HYWenHei-85W.ttf")
A = BuildImage(1030,
570,
color="#f1e9e1",
font_size=15,
font="HYWenHei-85W.ttf")
A.text((10, 15), "原神便笺 | Create By ZhenXun", (198, 186, 177))
ava = BuildImage(100, 100, background=user_avatar)
ava.circle()
A.paste(ava, (40, 40), True)
A.paste(
BuildImage(0, 0, plain_text=uname, font_size=20, font="HYWenHei-85W.ttf"),
BuildImage(0,
0,
plain_text=uname,
font_size=20,
font="HYWenHei-85W.ttf"),
(160, 62),
True,
)
@@ -177,26 +213,52 @@ def _parse_data_and_draw(
"今日委托已全部完成" if finished_task_num == total_task_num else "今日委托完成数量不足",
f"{finished_task_num}/{total_task_num}",
)
A.paste(border, (10, 265))
A.paste(border, (10, 235))
border = create_border(
"resin_discount.png",
"值得铭记的强敌",
"本周剩余消耗减半次数",
f"{remain_resin_discount_num}/{resin_discount_num_limit}",
)
A.paste(border, (10, 375))
expeditions_border = BuildImage(
470, 430, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20
A.paste(border, (10, 315))
border = create_border(
"chengehu.png",
"洞天财翁-洞天宝钱",
"洞天财翁已达到存储上限"
if current_coin == max_coin else f"{coin_hour}小时{coin_minute}分钟后存满",
f"{current_coin}/{max_coin}",
)
expeditions_text = BuildImage(
466, 426, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
A.paste(border, (10, 395))
border = create_border(
"zhibian.png",
"参量质变仪",
"不存在" if not transformer_available else
"已准备完成 " if transformer_state else f"{transformer_recovery_hour}小时后可使用" if not transformer_recovery_time else f"{transformer_recovery_time}天后可使用",
"不存在" if not transformer_available else
"可使用" if transformer_state else "冷却中",
)
A.paste(border, (10, 475))
expeditions_border = BuildImage(470,
510,
color="#E0D9D1",
font="HYWenHei-85W.ttf",
font_size=20)
expeditions_text = BuildImage(466,
506,
color="#F5F1EB",
font_size=23,
font="HYWenHei-85W.ttf")
expeditions_text.text(
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}", (100, 100, 98)
)
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}",
(100, 100, 98))
h = 45
for x in expeditions:
_bk = BuildImage(400, 66, color="#ECE3D8", font="HYWenHei-85W.ttf", font_size=21)
_bk = BuildImage(400,
82,
color="#ECE3D8",
font="HYWenHei-85W.ttf",
font_size=21)
file_name = x["avatar_side_icon"].split("_")[-1]
role_avatar = memo_path / "role_avatar" / file_name
_ava_img = BuildImage(75, 75, background=role_avatar)
@@ -227,7 +289,7 @@ def _parse_data_and_draw(
_bk.circle_corner(20)
expeditions_text.paste(_bk, (25, h), True)
h += 75
h += 75 + 16
expeditions_border.paste(expeditions_text, center_type="center")