feat: 添加扫码登录,cookies复写,修正错误提示,添加成长值显示 (#246)

* feat: 添加扫码登录,cookies复写,修正错误提示

* On branch qr_login

* chore: 遵守代码规范

* chore: not invalid-name

* chore: 添加成长值显示

* imp: 更新版本号

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: 0-8-4 <ljd69154@liangjundi.cn>
This commit is contained in:
Night-stars-1 2023-12-18 19:58:12 +08:00 committed by GitHub
parent 5044bcc744
commit 3991a86a41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 277 additions and 53 deletions

3
.gitignore vendored
View File

@ -142,5 +142,4 @@ dmypy.json
logs
data
.pdm-python
test.py
test2.py
test*.py

View File

@ -1,13 +1,15 @@
'''
Date: 2023-11-13 20:29:19
LastEditors: Night-stars-1 nujj1042633805@gmail.com
LastEditTime: 2023-12-03 01:53:48
LastEditTime: 2023-12-18 19:21:36
'''
# new Env("MIUI-Auto-Task") # pylint: disable=missing-module-docstring
# cron 30 8 * * * miuitask.py
import asyncio
from tenacity import RetryError, Retrying, stop_after_attempt
from utils.api.login import Login
from utils.api.sign import BaseSign, CheckIn
from utils.config import ConfigManager
@ -23,24 +25,33 @@ async def main():
"""启动签到"""
print_info()
for account in _conf.accounts:
try:
for attempt in Retrying(stop=stop_after_attempt(2)):
with attempt:
login_obj = Login(account)
if cookies := await login_obj.login():
sign_obj = BaseSign(cookies)
sign_obj = BaseSign(cookies, account.user_agent)
daily_tasks = await sign_obj.check_daily_tasks()
sign_task_obj = sign_obj.AVAILABLE_SIGNS # 签到任务对象合集
for task in daily_tasks:
if not task.showType:
log.info(f"开始执行{task.name}任务")
if task_obj := sign_task_obj.get(task.name): # 签到任务对象
if getattr(account, task_obj.__name__):
token = await get_token(cookies["cUserId"]) if task_obj == CheckIn else None
await task_obj(cookies, token).sign()
else:
log.info(f"任务{task.name}被禁用")
else:
log.error(f"未找到{task.name}任务")
else:
if task.showType:
log.info(f"{task.name}任务已完成")
continue
if not (task_obj := sign_task_obj.get(task.name)): # 签到任务对象
log.error(f"未找到{task.name}任务")
continue
if not getattr(account, task_obj.__name__):
log.info(f"任务{task.name}被禁用")
continue
token = await get_token(cookies["cUserId"]) if task_obj == CheckIn else None
status, reason = await task_obj(cookies, token).sign()
if not status and reason == "cookie":
raise ValueError("Cookie失效")
user_info = await sign_obj.user_info()
log.info(f"{user_info.title} 成长值: {user_info.point}")
except RetryError:
...
notify_me(InterceptHandler.message)

View File

@ -100,11 +100,8 @@ dependencies = [
[[package]]
name = "onepush"
version = "1.2.0"
version = "1.3.0"
requires_python = ">=3.6"
git = "https://github.com/y1ndan/onepush.git"
ref = "main"
revision = "8b09e62330ad74ba3221bfc2b080d1732a1dcc55"
summary = "A Python library to send notifications to your iPhone, Discord, Telegram, WeChat, QQ and DingTalk."
dependencies = [
"pycryptodome",
@ -149,12 +146,28 @@ dependencies = [
"typing-extensions!=4.7.0,>=4.6.0",
]
[[package]]
name = "pypng"
version = "0.20220715.0"
summary = "Pure Python library for saving and loading PNG images"
[[package]]
name = "pyyaml"
version = "6.0.1"
requires_python = ">=3.6"
summary = "YAML parser and emitter for Python"
[[package]]
name = "qrcode"
version = "7.4.2"
requires_python = ">=3.7"
summary = "QR Code image generator"
dependencies = [
"colorama; platform_system == \"Windows\"",
"pypng",
"typing-extensions",
]
[[package]]
name = "requests"
version = "2.31.0"
@ -207,7 +220,7 @@ summary = "A small Python utility to set file creation time on Windows"
lock_version = "4.2"
cross_platform = true
groups = ["default"]
content_hash = "sha256:7c922391569ae98b5aba9438d7da9b0ab1b413b23a1e333df2e61bfab038c0ac"
content_hash = "sha256:fb7c34d8c74d9043647bf7d200afa5a64602e32c03b558cc9d2fb1e81ad1c1e5"
[metadata.files]
"annotated-types 0.6.0" = [
@ -417,6 +430,9 @@ content_hash = "sha256:7c922391569ae98b5aba9438d7da9b0ab1b413b23a1e333df2e61bfab
{url = "https://files.pythonhosted.org/packages/03/0a/4f6fed21aa246c6b49b561ca55facacc2a44b87d65b8b92362a8e99ba202/loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"},
{url = "https://files.pythonhosted.org/packages/9e/30/d87a423766b24db416a46e9335b9602b054a72b96a88a241f2b09b560fa8/loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"},
]
"onepush 1.3.0" = [
{url = "https://files.pythonhosted.org/packages/e1/a2/1d65907128f1b7980d7da0e68b134298ced50d38df8ddf5133e32c8e9f99/onepush-1.3.0-py3-none-any.whl", hash = "sha256:196af2e147a54381b5ffa32565f5f3955a0647328cc283812ce2f87f4bc09f47"},
]
"orjson 3.9.10" = [
{url = "https://files.pythonhosted.org/packages/03/96/4fd0da4f4a5a450054e69439875b4e856654dcbbfea6907d7753b827c937/orjson-3.9.10-cp312-none-win_amd64.whl", hash = "sha256:3e892621434392199efb54e69edfff9f699f6cc36dd9553c5bf796058b14b20d"},
{url = "https://files.pythonhosted.org/packages/09/33/d090754faab1a63ecf80b1df220d6787605caefd570331c757a3553afbf2/orjson-3.9.10-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:92af0d00091e744587221e79f68d617b432425a7e59328ca4c496f774a356071"},
@ -618,6 +634,10 @@ content_hash = "sha256:7c922391569ae98b5aba9438d7da9b0ab1b413b23a1e333df2e61bfab
{url = "https://files.pythonhosted.org/packages/fd/81/7bcde32ca3434ec80861205d5f949fe28247af9712dd7da940f08445c45d/pydantic_core-2.14.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27828f0227b54804aac6fb077b6bb48e640b5435fdd7fbf0c274093a7b78b69c"},
{url = "https://files.pythonhosted.org/packages/ff/1b/937923cfa9df349c632ddead46e57c996103f9bfe904f5ff6cc87472df6e/pydantic_core-2.14.3-cp39-none-win32.whl", hash = "sha256:caa94726791e316f0f63049ee00dff3b34a629b0d099f3b594770f7d0d8f1f56"},
]
"pypng 0.20220715.0" = [
{url = "https://files.pythonhosted.org/packages/3e/b9/3766cc361d93edb2ce81e2e1f87dd98f314d7d513877a342d31b30741680/pypng-0.20220715.0-py3-none-any.whl", hash = "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c"},
{url = "https://files.pythonhosted.org/packages/93/cd/112f092ec27cca83e0516de0a3368dbd9128c187fb6b52aaaa7cde39c96d/pypng-0.20220715.0.tar.gz", hash = "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1"},
]
"pyyaml 6.0.1" = [
{url = "https://files.pythonhosted.org/packages/02/74/b2320ebe006b6a521cf929c78f12a220b9db319b38165023623ed195654b/PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
{url = "https://files.pythonhosted.org/packages/03/5c/c4671451b2f1d76ebe352c0945d4cd13500adb5d05f5a51ee296d80152f7/PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
@ -670,6 +690,10 @@ content_hash = "sha256:7c922391569ae98b5aba9438d7da9b0ab1b413b23a1e333df2e61bfab
{url = "https://files.pythonhosted.org/packages/f1/26/55e4f21db1f72eaef092015d9017c11510e7e6301c62a6cfee91295d13c6/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
{url = "https://files.pythonhosted.org/packages/fe/88/def2e57fe740544f2eefb1645f1d6e0094f56c00f4eade708140b6137ead/PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
]
"qrcode 7.4.2" = [
{url = "https://files.pythonhosted.org/packages/24/79/aaf0c1c7214f2632badb2771d770b1500d3d7cbdf2590ae62e721ec50584/qrcode-7.4.2-py3-none-any.whl", hash = "sha256:581dca7a029bcb2deef5d01068e39093e80ef00b4a61098a2182eac59d01643a"},
{url = "https://files.pythonhosted.org/packages/30/35/ad6d4c5a547fe9a5baf85a9edbafff93fc6394b014fab30595877305fa59/qrcode-7.4.2.tar.gz", hash = "sha256:9dd969454827e127dbd93696b20747239e6d540e082937c90f14ac95b30f5845"},
]
"requests 2.31.0" = [
{url = "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
{url = "https://files.pythonhosted.org/packages/9d/be/10918a2eac4ae9f02f6cfe6414b7a155ccd8f7f9d4380d62fd5b955065c3/requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},

View File

@ -13,6 +13,7 @@ dependencies = [
"tenacity>=8.2.3",
"tzdata>=2023.3",
"onepush>=1.3.0",
"qrcode>=7.4.2",
]
requires-python = ">=3.11"
license = {text = "MIT"}

View File

@ -3,8 +3,9 @@ Date: 2023-11-12 14:05:06
LastEditors: Night-stars-1 nujj1042633805@gmail.com
LastEditTime: 2023-11-13 12:32:26
"""
import time
from os import getenv
from typing import Dict, Union
from typing import Dict, Optional, Tuple, Union
import orjson
@ -13,6 +14,8 @@ from ..data_model import LoginResultHandler
from ..logger import log
from ..request import get, post
from .sign import BaseSign
from ..utils import generate_qrcode
class Login:
"""登录类"""
@ -24,7 +27,7 @@ class Login:
self.password = account.password
self.cookies = account.cookies
async def login(self) -> Union[Dict[str, str], bool]:
async def login(self) -> Union[Dict[str, str], bool]: # pylint: disable=too-many-return-statements
"""登录小米账号"""
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
@ -68,9 +71,17 @@ class Login:
repo_owner = getenv('GITHUB_REPOSITORY_OWNER')
if repo_owner not in [None, "0-8-4"]:
return False
if self.cookies != {} and await BaseSign(self.cookies).check_daily_tasks(nolog=True) != []:
if self.cookies != {} and await BaseSign(self.cookies, self.user_agent).check_daily_tasks(nolog=True) != []:
log.info("Cookie有效跳过登录")
return self.cookies
elif self.cookies.get("passToken") and \
(cookies := await self.get_cookies_by_passtk(user_id=self.uid,
pass_token=self.cookies["passToken"])):
log.info("Cookie无效重新复写")
self.cookies.update(cookies)
self.account.cookies = self.cookies
write_plugin_data()
return cookies
response = await post('https://account.xiaomi.com/pass/serviceLoginAuth2', headers=headers, data=data)
log.debug(response.text)
result = response.text.lstrip('&').lstrip('START').lstrip('&')
@ -83,12 +94,19 @@ class Login:
self.account.cookies = cookies
write_plugin_data()
return cookies
elif not api_data.pwd_wrong:
log.error(f'小米账号登录失败:{api_data.message}')
elif api_data.pwd_wrong:
log.error('小米账号登录失败:用户名或密码不正确')
check_url = await self.qr_login()
userid, cookies = await self.check_login(check_url)
self.cookies.update(cookies)
self.account.cookies = self.cookies
self.account.uid = userid
write_plugin_data()
return cookies
elif api_data.need_captcha:
log.error('当前账号需要短信验证码, 请尝试修改UA或设备ID')
else:
log.error('小米账号登录失败:用户名或密码不正确')
log.error(f'小米账号登录失败:{api_data.message}')
return False
except Exception: # pylint: disable=broad-exception-caught
log.exception("登录小米账号出错")
@ -104,3 +122,103 @@ class Login:
log.exception("社区获取 Cookie 失败")
return False
async def get_cookies_by_passtk(self, user_id: str, pass_token: str) -> Union[Dict[str, str], bool]:
"""使用passToken获取签到cookies"""
try:
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Referer': 'https://web.vip.miui.com/',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-site',
'Upgrade-Insecure-Requests': '1',
'User-Agent': self.user_agent,
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
params = {
'destUrl': 'https://web.vip.miui.com/page/info/mio/mio/checkIn?app_version=dev.230904',
'time': round(time.time() * 1000),
}
cookies = {
"userId": user_id,
"passToken": pass_token
}
response = await get('https://api.vip.miui.com/page/login', params=params, headers=headers)
url = response.headers.get("location")
response = await get(url, cookies=cookies, headers=headers)
url = response.headers.get("location")
response = await get(url, cookies=cookies, headers=headers)
return dict(response.cookies)
except Exception: # pylint: disable=broad-exception-caught
log.exception("从passToken获取 Cookie 失败")
return {}
async def qr_login(self) -> Tuple[str, bytes]:
"""二维码登录"""
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Referer': 'https://account.xiaomi.com/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
'X-Requested-With': 'XMLHttpRequest',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
response = await get(
'https://account.xiaomi.com/longPolling/loginUrl?_group=DEFAULT&_qrsize=240&qs=%253Fcallback%253Dhttps%25253A%25252F%25252Faccount.xiaomi.com%25252Fsts%25253Fsign%25253DZvAtJIzsDsFe60LdaPa76nNNP58%2525253D%252526followup%25253Dhttps%2525253A%2525252F%2525252Faccount.xiaomi.com%2525252Fpass%2525252Fauth%2525252Fsecurity%2525252Fhome%252526sid%25253Dpassport%2526sid%253Dpassport%2526_group%253DDEFAULT&bizDeviceType=&callback=https:%2F%2Faccount.xiaomi.com%2Fsts%3Fsign%3DZvAtJIzsDsFe60LdaPa76nNNP58%253D%26followup%3Dhttps%253A%252F%252Faccount.xiaomi.com%252Fpass%252Fauth%252Fsecurity%252Fhome%26sid%3Dpassport&theme=&sid=passport&needTheme=false&showActiveX=false&serviceParam=%7B%22checkSafePhone%22:false,%22checkSafeAddress%22:false,%22lsrp_score%22:0.0%7D&_locale=zh_CN&_sign=2%26V1_passport%26BUcblfwZ4tX84axhVUaw8t6yi2E%3D&_dc=1702105962382', # pylint: disable=line-too-long
headers=headers,
)
result = response.text.replace("&&&START&&&", "")
data = orjson.loads(result) # pylint: disable=no-member
login_url = data["loginUrl"]
check_url = data["lp"]
generate_qrcode(login_url)
return check_url
async def check_login(self, url: str) -> Tuple[Optional[int], Optional[dict]]:
"""检查扫码登录状态"""
try:
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Referer': 'https://account.xiaomi.com/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0',
'X-Requested-With': 'XMLHttpRequest',
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}
response = await get(url, headers=headers)
result = response.text.replace("&&&START&&&", "")
data = orjson.loads(result) # pylint: disable=no-member
pass_token = data["passToken"]
user_id = str(data["userId"])
cookies = await self.get_cookies_by_passtk(user_id=user_id, pass_token=pass_token)
cookies.update({
"passToken": pass_token
})
return user_id, cookies
except Exception: # pylint: disable=broad-exception-caught
return None, None

View File

@ -2,10 +2,10 @@
import time
from typing import Dict, List, Optional, Type, Union, Any
from typing import Dict, List, Optional, Type, Union, Any, Tuple
from tenacity import RetryError, Retrying, stop_after_attempt
from ..data_model import ApiResultHandler, DailyTasksResult, SignResultHandler
from ..data_model import ApiResultHandler, DailyTasksResult, SignResultHandler, UserInfoResult
from ..request import get, post
from ..logger import log
from ..utils import is_incorrect_return
@ -30,9 +30,10 @@ class BaseSign:
AVAILABLE_SIGNS: Dict[str, Type["BaseSign"]] = {}
"""可用的子类"""
def __init__(self, cookie: Dict, token: Optional[str] = None):
self.cookie = cookie
def __init__(self, cookies: Dict, user_agent: str, token: Optional[str] = None):
self.cookies = cookies
self.token = token
self.user_agent = user_agent
self.headers = {
}
@ -42,7 +43,7 @@ class BaseSign:
for attempt in Retrying(stop=stop_after_attempt(3)):
with attempt:
response = await get('https://api.vip.miui.com/mtop/planet/vip/member/getCheckinPageCakeList',
cookies=self.cookie)
cookies=self.cookies)
log.debug(response.text)
result = response.json()
api_data = ApiResultHandler(result)
@ -68,7 +69,7 @@ class BaseSign:
log.exception("获取每日任务异常")
return []
async def sign(self) -> bool:
async def sign(self) -> Tuple[bool, str]:
"""
每日任务处理器
"""
@ -76,19 +77,19 @@ class BaseSign:
for attempt in Retrying(stop=stop_after_attempt(3)):
with attempt:
params = self.PARAMS.copy()
params['miui_vip_ph'] = self.cookie['miui_vip_ph'] if 'miui_vip_ph' in self.cookie else params
params['miui_vip_ph'] = self.cookies['miui_vip_ph'] if 'miui_vip_ph' in self.cookies else params
params['token'] = self.token if 'token' in params else params
data = self.DATA.copy()
data['miui_vip_ph'] = self.cookie['miui_vip_ph'] if 'miui_vip_ph' in self.cookie else data
data['miui_vip_ph'] = self.cookies['miui_vip_ph'] if 'miui_vip_ph' in self.cookies else data
if 'token' in data:
if self.token:
data['token'] = self.token
else:
log.info(f"未获取到token, 跳过{self.NAME}")
return False
return False, "None"
response = await post(self.URL_SIGN,
params=params, data=data,
cookies=self.cookie, headers=self.headers)
cookies=self.cookies, headers=self.headers)
log.debug(response.text)
result = response.json()
api_data = SignResultHandler(result)
@ -97,20 +98,53 @@ class BaseSign:
log.success(f"{self.NAME}结果: 成长值+{api_data.growth}")
else:
log.success(f"{self.NAME}结果: {api_data.message}")
return True
return True, "None"
elif api_data.ck_invalid:
log.error(f"{self.NAME}失败: Cookie无效")
return False
return False, "cookie"
else:
log.error(f"{self.NAME}失败:{api_data.message}")
return False
return False, "None"
except RetryError as error:
if is_incorrect_return(error):
log.exception(f"{self.NAME} - 服务器没有正确返回 {response.text}")
else:
log.exception("{self.NAME}出错")
return False
return False, "None"
async def user_info(self) -> UserInfoResult:
"""获取用户信息"""
try:
for attempt in Retrying(stop=stop_after_attempt(3)):
with attempt:
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': self.user_agent,
'Request-Container-Mark': 'android',
'Host': 'api.vip.miui.com',
'Connection': 'Keep-Alive',
}
response = await get(
'https://api.vip.miui.com/mtop/planet/vip/homepage/mineInfo',
cookies=self.cookies,
headers=headers,
)
log.debug(response.text)
result = response.json()
api_data = ApiResultHandler(result)
if api_data.success:
return UserInfoResult.model_validate(api_data.data)
else:
log.error(f"获取用户信息失败:{api_data.message}")
return UserInfoResult()
except RetryError as error:
if is_incorrect_return(error):
log.exception(f"用户信息 - 服务器没有正确返回 {response.text}")
else:
log.exception("获取用户信息异常")
return UserInfoResult()
#pylint: disable=trailing-whitespace
class CheckIn(BaseSign):
"""
每日签到

View File

@ -8,7 +8,7 @@ from typing import Dict, List, Optional, Union
import orjson
import yaml # pylint: disable=wrong-import-order
from pydantic import BaseModel, ValidationError, field_validator
from pydantic import BaseModel, ValidationError, field_validator # pylint: disable=no-name-in-module
from .logger import log

View File

@ -1,6 +1,6 @@
"""数据处理模型"""
from typing import (Any, Dict, NamedTuple, Optional)
from pydantic import BaseModel
from pydantic import BaseModel # pylint: disable=no-name-in-module
class ApiResultHandler(BaseModel):
@ -42,7 +42,7 @@ class ApiResultHandler(BaseModel):
"""
是否成功
"""
return self.status in [0, 200] or self.message in ["成功", "OK", "success"]
return (self.status in [0, 200] or self.message in ["成功", "OK", "success"]) and not self.content.get("notificationUrl")
class LoginResultHandler(ApiResultHandler):
@ -65,7 +65,7 @@ class LoginResultHandler(ApiResultHandler):
"""
是否需要验证码
"""
return self.status == 87001 or "验证码" in self.message
return self.status == 87001 or "验证码" in self.message or self.content.get("notificationUrl")
@property
def pwd_wrong(self):
@ -146,3 +146,17 @@ class GeetestResult(NamedTuple):
"""人机验证结果数据"""
validate: str
challenge: str
class UserInfoResult(BaseModel):
"""用户信息数据"""
title: str = "未知"
"""等级名称"""
point: int = 0
"""积分"""
def __init__(self, **kwargs):
if isinstance(kwargs, dict) and kwargs:
kwargs = kwargs.get("userInfo", {}).get("userGrowLevelInfo")
super().__init__(**kwargs)
else:
super().__init__()

View File

@ -10,7 +10,7 @@ from utils.logger import log
def print_info():
"""打印系统信息"""
log.info("MIUI-AUTO-TASK v1.7.3")
log.info("MIUI-AUTO-TASK v1.7.4")
log.info('---------- 系统信息 -------------')
system_info()
log.info('---------- 项目信息 -------------')

View File

@ -2,9 +2,11 @@
import base64
import random
import time
from io import BytesIO
from typing import Type
from urllib.parse import parse_qsl, urlparse
import qrcode
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding, serialization
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
@ -239,3 +241,24 @@ async def get_token(uid: str) -> str | bool:
else:
log.exception("获取TOKEN异常")
return False
def generate_qrcode(url):
"""生成二维码"""
qr = qrcode.QRCode(version=1, # pylint: disable=invalid-name
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4)
qr.add_data(url)
qr.make(fit=True)
img = qr.make_image(fill_color='black', back_color='white')
bio = BytesIO()
img.save(bio)
# 获取二维码的模块 (module) 列表
qr_modules = qr.get_matrix()
chaes = [" ", "██"]
# 在控制台中打印二维码
for row in qr_modules:
line = "".join(chaes[pixel] for pixel in row)
print(line)
log.debug(line)