mirror of
https://github.com/0-8-4/miui-auto-tasks.git
synced 2024-11-21 14:48:20 +00:00
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:
parent
5044bcc744
commit
3991a86a41
3
.gitignore
vendored
3
.gitignore
vendored
@ -142,5 +142,4 @@ dmypy.json
|
||||
logs
|
||||
data
|
||||
.pdm-python
|
||||
test.py
|
||||
test2.py
|
||||
test*.py
|
47
miuitask.py
47
miuitask.py
@ -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:
|
||||
login_obj = Login(account)
|
||||
if cookies := await login_obj.login():
|
||||
sign_obj = BaseSign(cookies)
|
||||
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__):
|
||||
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, account.user_agent)
|
||||
daily_tasks = await sign_obj.check_daily_tasks()
|
||||
sign_task_obj = sign_obj.AVAILABLE_SIGNS # 签到任务对象合集
|
||||
for task in daily_tasks:
|
||||
log.info(f"开始执行{task.name}任务")
|
||||
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
|
||||
await task_obj(cookies, token).sign()
|
||||
else:
|
||||
log.info(f"任务{task.name}被禁用")
|
||||
else:
|
||||
log.error(f"未找到{task.name}任务")
|
||||
else:
|
||||
log.info(f"{task.name}任务已完成")
|
||||
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)
|
||||
|
||||
|
||||
|
34
pdm.lock
34
pdm.lock
@ -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"},
|
||||
|
@ -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"}
|
||||
|
@ -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,14 +94,21 @@ 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
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
log.exception("登录小米账号出错")
|
||||
return False
|
||||
|
||||
@ -100,7 +118,107 @@ class Login:
|
||||
response = await get(url, follow_redirects=False)
|
||||
log.debug(response.text)
|
||||
return dict(response.cookies)
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
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
|
||||
|
@ -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):
|
||||
"""
|
||||
每日签到
|
||||
|
@ -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
|
||||
|
||||
|
@ -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__()
|
||||
|
@ -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('---------- 项目信息 -------------')
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user