Compare commits
3 Commits
71d0873821
...
19a69c4204
Author | SHA1 | Date | |
---|---|---|---|
19a69c4204 | |||
ac2529f718 | |||
35e3a329c0 |
123
TongCheng/README.md
Normal file
123
TongCheng/README.md
Normal file
@ -0,0 +1,123 @@
|
||||
# 同程旅行自动签到脚本
|
||||
|
||||
这是一个基于Python的自动化脚本,用于自动完成同程旅行APP的每日签到和任务,获取里程奖励。脚本支持多账号配置,自动处理日常任务,并通过青龙面板提供通知功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- **自动签到**:每日自动完成签到任务
|
||||
- **任务处理**:自动识别并完成各类日常任务
|
||||
- **多账号支持**:通过环境变量配置多个账号,支持使用换行符或`#`分隔
|
||||
- **通知功能**:支持通过青龙面板发送执行结果通知
|
||||
- **智能重试**:任务失败时自动重试,提高成功率
|
||||
- **数据统计**:记录签到天数、里程变化等信息
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 环境准备
|
||||
|
||||
首先需要准备好运行环境:
|
||||
|
||||
1. 安装青龙面板(建议版本2.10.0以上)
|
||||
2. 确保青龙面板已安装以下依赖:
|
||||
- aiohttp
|
||||
- requests
|
||||
|
||||
### 2. 获取抓包信息
|
||||
|
||||
1. 打开并登录“同程旅行”APP
|
||||
2. 开启抓包工具(如Charles、Fiddler等)
|
||||
3. 点击APP右下角“我的”-“签到”
|
||||
4. 抓取请求域名`https://app.17u.cn`请求头中的三个参数:
|
||||
- `phone`:手机号
|
||||
- `apptoken`:认证令牌
|
||||
- `device`:设备标识
|
||||
|
||||
### 3. 配置环境变量
|
||||
|
||||
在青龙面板中添加环境变量:
|
||||
|
||||
1. 打开青龙面板,进入「环境变量」页面
|
||||
2. 点击「添加变量」按钮
|
||||
3. 变量名:`tongcheng`
|
||||
4. 变量值格式:
|
||||
```
|
||||
phone&apptoken&device
|
||||
```
|
||||
多账号之间支持用换行符或`#`分隔,例如:
|
||||
```
|
||||
# 使用换行符分隔(推荐)
|
||||
13800138000&abcdef123456&device1
|
||||
13900139000&abcdef789012&device2
|
||||
|
||||
# 或使用#分隔
|
||||
13800138000&abcdef123456&device1#13900139000&abcdef789012&device2
|
||||
```
|
||||
|
||||
### 4. 添加脚本
|
||||
|
||||
1. 在青龙面板中,进入「脚本管理」页面
|
||||
2. 点击「添加脚本」按钮
|
||||
3. 输入脚本名称(如`tc_signin.py`)
|
||||
4. 将脚本代码复制到编辑器中
|
||||
5. 点击「保存」按钮
|
||||
|
||||
### 5. 设置定时任务
|
||||
|
||||
1. 在青龙面板中,进入「定时任务」页面
|
||||
2. 点击「添加任务」按钮
|
||||
3. 任务名称:自定义(如`同程旅行签到`)
|
||||
4. 命令:
|
||||
```bash
|
||||
task tc_signin.py
|
||||
```
|
||||
5. 定时规则:设置执行频率(如`0 0 * * *`表示每天0点执行)
|
||||
6. 点击「保存」按钮
|
||||
|
||||
## 通知配置
|
||||
|
||||
脚本支持通过青龙面板的通知功能发送执行结果,需要确保青龙面板已正确配置通知方式(如Server酱、Telegram等)。
|
||||
|
||||
如果通知功能无法正常工作,脚本会在日志中记录详细的错误信息,帮助排查问题。
|
||||
|
||||
## 脚本更新说明
|
||||
|
||||
### 版本1.6更新内容
|
||||
|
||||
- 优化环境变量解析,支持使用换行符分隔多账号
|
||||
- 增强环境变量格式验证和错误处理
|
||||
- 优化日志输出,明确显示解析到的账号数量
|
||||
- 保留之前所有功能和优化
|
||||
|
||||
### 版本1.5更新内容
|
||||
|
||||
- 优化通知模块,解决异步环境下通知失败问题
|
||||
- 使用线程池执行同步通知函数,避免阻塞事件循环
|
||||
- 增强错误处理,提供更详细的通知失败信息
|
||||
- 保留之前的所有功能和优化
|
||||
|
||||
### 版本1.4更新内容
|
||||
|
||||
- 修复推送服务失败的问题
|
||||
- 优化notify模块导入逻辑
|
||||
- 添加详细的路径查找和错误日志
|
||||
- 保留之前的所有功能和优化
|
||||
|
||||
## 常见问题
|
||||
|
||||
1. **脚本执行失败**:
|
||||
- 检查环境变量是否正确配置
|
||||
- 确认抓包获取的参数是否有效
|
||||
- 查看脚本执行日志,定位具体错误原因
|
||||
|
||||
2. **通知未收到**:
|
||||
- 检查青龙面板通知配置是否正确
|
||||
- 查看脚本日志,确认通知是否发送成功
|
||||
- 检查通知服务提供商的状态
|
||||
|
||||
3. **任务执行不完全**:
|
||||
- 脚本有内置的重试机制,但部分任务可能需要手动完成
|
||||
- 检查任务列表中是否有特殊任务需要额外操作
|
||||
|
||||
## 免责声明
|
||||
|
||||
本脚本仅供学习交流使用,请勿用于商业用途。使用本脚本可能违反同程旅行的用户协议,请谨慎使用。开发者不对因使用本脚本而导致的任何问题负责。
|
473
TongCheng/tc_signin.py
Normal file
473
TongCheng/tc_signin.py
Normal file
@ -0,0 +1,473 @@
|
||||
"""
|
||||
描述: 打开并登录“同程旅行”APP,开启抓包,点击APP右下角“我的”-“签到”,进去后抓包域名https://app.17u.cn请求头中的phone、apptoken、device三个参数。
|
||||
环境变量:
|
||||
变量名:tongcheng
|
||||
变量格式:phone&apptoken&device
|
||||
多账号之间支持用#或换行分隔:
|
||||
phone1&apptoken1&device1
|
||||
phone2&apptoken2&device2
|
||||
需要依赖:aiohttp
|
||||
签到奖励:日常任务得里程,签到满360天得价值200元里程
|
||||
----------------------
|
||||
版本: 1.6
|
||||
更新说明:
|
||||
1. 优化环境变量解析,支持使用换行符分隔多账号
|
||||
2. 增强环境变量格式验证和错误处理
|
||||
3. 优化日志输出,明确显示解析到的账号数量
|
||||
4. 保留之前所有功能和优化
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
import asyncio
|
||||
import aiohttp
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import random
|
||||
import sys
|
||||
import traceback # 用于获取详细的错误堆栈信息
|
||||
|
||||
# 手机号脱敏处理
|
||||
def mask_phone(phone):
|
||||
if len(phone) == 11:
|
||||
return phone[:3] + '****' + phone[7:]
|
||||
return phone
|
||||
|
||||
# 从环境变量获取账号信息
|
||||
def get_accounts():
|
||||
accounts = []
|
||||
tongcheng_env = os.getenv('tongcheng', '')
|
||||
|
||||
if not tongcheng_env:
|
||||
print("未找到环境变量 tongcheng")
|
||||
return accounts
|
||||
|
||||
# 支持使用#或换行符分隔多账号
|
||||
# 先尝试按换行符分割
|
||||
lines = tongcheng_env.strip().split('\n')
|
||||
if len(lines) > 1:
|
||||
print(f"发现{len(lines)}行配置,尝试按行解析...")
|
||||
account_list = lines
|
||||
else:
|
||||
# 尝试按#分割
|
||||
print("未发现换行符,尝试按#分割...")
|
||||
account_list = tongcheng_env.split('#')
|
||||
|
||||
valid_accounts = 0
|
||||
invalid_accounts = 0
|
||||
|
||||
for account in account_list:
|
||||
account = account.strip()
|
||||
if not account:
|
||||
continue
|
||||
|
||||
try:
|
||||
phone, apptoken, device = account.split('&')
|
||||
if not phone or not apptoken or not device:
|
||||
raise ValueError("参数为空")
|
||||
|
||||
accounts.append({
|
||||
'phone': phone,
|
||||
'apptoken': apptoken,
|
||||
'device': device
|
||||
})
|
||||
valid_accounts += 1
|
||||
print(f" ✅ 解析账号: {mask_phone(phone)}")
|
||||
|
||||
except Exception as e:
|
||||
invalid_accounts += 1
|
||||
print(f" ❌ 无效账号配置: {account} - 错误: {str(e)}")
|
||||
|
||||
print(f"🔍 共解析出{valid_accounts}个有效账号,{invalid_accounts}个无效配置")
|
||||
return accounts
|
||||
|
||||
# 获取请求头
|
||||
def get_headers(phone, apptoken, device, payload):
|
||||
payload_str = json.dumps(payload)
|
||||
headers = {
|
||||
'accept': 'application/json, text/plain, */*',
|
||||
'phone': phone,
|
||||
'channel': '1',
|
||||
'apptoken': apptoken,
|
||||
'sec-fetch-site': 'same-site',
|
||||
'accept-language': 'zh-CN,zh-Hans;q=0.9',
|
||||
'accept-encoding': 'gzip, deflate, br',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'origin': 'https://m.17u.cn',
|
||||
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 TcTravel/11.0.0 tctype/wk',
|
||||
'referer': 'https://m.17u.cn/',
|
||||
'content-length': str(len(payload_str.encode('utf-8'))),
|
||||
'device': device,
|
||||
'sec-fetch-dest': 'empty'
|
||||
}
|
||||
return headers
|
||||
|
||||
# 获取当前日期
|
||||
def get_today_date():
|
||||
return datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
# 异步执行任务
|
||||
async def execute_task(session, phone, apptoken, device, task_code, title, browser_time):
|
||||
# 开始任务
|
||||
start_url = "https://app.17u.cn/welfarecenter/task/start"
|
||||
start_payload = {"taskCode": task_code}
|
||||
start_headers = get_headers(phone, apptoken, device, start_payload)
|
||||
|
||||
task_id = None
|
||||
async with session.post(start_url, json=start_payload, headers=start_headers) as response:
|
||||
data = await response.json()
|
||||
if data['code'] != 2200:
|
||||
print(f" - ❌ 做任务【{title}】失败,跳过当前任务")
|
||||
# 即使任务开始失败,也尝试获取task_id
|
||||
task_id = data.get('data')
|
||||
if not task_id:
|
||||
return False, f"任务【{title}】开始失败"
|
||||
else:
|
||||
task_id = data['data']
|
||||
print(f" - 🚀 开始执行任务【{title}】,等待{browser_time}秒...")
|
||||
# 等待浏览时间
|
||||
await asyncio.sleep(browser_time)
|
||||
|
||||
if task_id:
|
||||
# 完成任务
|
||||
finish_url = "https://app.17u.cn/welfarecenter/task/finish"
|
||||
finish_payload = {"id": task_id}
|
||||
finish_headers = get_headers(phone, apptoken, device, finish_payload)
|
||||
|
||||
async with session.post(finish_url, json=finish_payload, headers=finish_headers) as response:
|
||||
data = await response.json()
|
||||
if data['code'] != 2200:
|
||||
print(f" - ⚠️ 任务【{title}】完成失败,尝试重新提交...")
|
||||
await asyncio.sleep(2)
|
||||
async with session.post(finish_url, json=finish_payload, headers=finish_headers) as retry_response:
|
||||
data = await retry_response.json()
|
||||
if data['code'] != 2200:
|
||||
print(f" - ❌ 任务【{title}】完成失败,继续尝试领取奖励")
|
||||
|
||||
print(f" - ✅ 任务【{title}】完成成功,开始领取奖励")
|
||||
|
||||
# 领取奖励
|
||||
reward_url = "https://app.17u.cn/welfarecenter/task/receive"
|
||||
reward_payload = {"id": task_id}
|
||||
reward_headers = get_headers(phone, apptoken, device, reward_payload)
|
||||
|
||||
# 添加奖励领取重试逻辑
|
||||
max_retries = 2
|
||||
for retry in range(max_retries + 1):
|
||||
async with session.post(reward_url, json=reward_payload, headers=reward_headers) as response:
|
||||
data = await response.json()
|
||||
if data['code'] == 2200:
|
||||
print(f" - 🎁 任务【{title}】领取奖励成功")
|
||||
return True, f"任务【{title}】领取奖励成功"
|
||||
elif retry < max_retries:
|
||||
print(f" - ⚠️ 任务【{title}】领取奖励失败,正在进行第{retry + 1}次重试...")
|
||||
await asyncio.sleep(2)
|
||||
else:
|
||||
print(f" - ❌ 任务【{title}】领取奖励失败,已重试{max_retries}次,请尝试手动领取")
|
||||
return False, f"任务【{title}】领取奖励失败"
|
||||
return False, f"任务【{title}】开始失败"
|
||||
|
||||
# 异步处理单个账号的所有任务
|
||||
async def process_account(session, account):
|
||||
phone = account['phone']
|
||||
apptoken = account['apptoken']
|
||||
device = account['device']
|
||||
|
||||
# 存储当前账号的通知内容
|
||||
account_notify_content = []
|
||||
|
||||
print(f"\n🔄 开始处理用户{mask_phone(phone)}的任务")
|
||||
account_notify_content.append(f"🔄 开始处理用户{mask_phone(phone)}的任务")
|
||||
|
||||
# 获取签到状态
|
||||
sign_url = "https://app.17u.cn/welfarecenter/index/signIndex"
|
||||
sign_headers = get_headers(phone, apptoken, device, {})
|
||||
|
||||
async with session.post(sign_url, json={}, headers=sign_headers) as response:
|
||||
data = await response.json()
|
||||
|
||||
if data['data'] is None:
|
||||
print(" ❌ Token失效,请更新")
|
||||
account_notify_content.append(" ❌ Token失效,请更新")
|
||||
return False, account_notify_content
|
||||
|
||||
today_sign = data['data']['todaySign']
|
||||
mileage = data['data']['mileageBalance']['mileage']
|
||||
print(f" 今日{'✅ 已' if today_sign else '⏳ 未'}签到,当前剩余里程{mileage}")
|
||||
account_notify_content.append(f" 今日{'✅ 已' if today_sign else '⏳ 未'}签到,当前剩余里程{mileage}")
|
||||
|
||||
if not today_sign:
|
||||
# 执行签到
|
||||
sign_in_url = "https://app.17u.cn/welfarecenter/index/sign"
|
||||
sign_in_payload = {"type": 1, "day": get_today_date()}
|
||||
sign_in_headers = get_headers(phone, apptoken, device, sign_in_payload)
|
||||
|
||||
async with session.post(sign_in_url, json=sign_in_payload, headers=sign_in_headers) as response:
|
||||
data = await response.json()
|
||||
if data['code'] != 2200:
|
||||
print(" ❌ 签到失败")
|
||||
account_notify_content.append(" ❌ 签到失败")
|
||||
return False, account_notify_content
|
||||
print(" ✅ 签到成功")
|
||||
account_notify_content.append(" ✅ 签到成功")
|
||||
|
||||
# 获取任务列表
|
||||
task_list_url = "https://app.17u.cn/welfarecenter/task/taskList?version=11.1.2.1"
|
||||
task_list_headers = get_headers(phone, apptoken, device, {})
|
||||
|
||||
async with session.post(task_list_url, json={}, headers=task_list_headers) as response:
|
||||
data = await response.json()
|
||||
if data['code'] != 2200:
|
||||
print(" ❌ 获取任务列表失败,跳过当前账号")
|
||||
account_notify_content.append(" ❌ 获取任务列表失败,跳过当前账号")
|
||||
return False, account_notify_content
|
||||
|
||||
tasks = []
|
||||
for task in data['data']:
|
||||
if task['state'] == 1 and task['browserTime'] != 0:
|
||||
tasks.append({
|
||||
'taskCode': task['taskCode'],
|
||||
'title': task['title'],
|
||||
'browserTime': task['browserTime']
|
||||
})
|
||||
|
||||
if not tasks:
|
||||
print(" ✅ 没有待完成的任务")
|
||||
account_notify_content.append(" ✅ 没有待完成的任务")
|
||||
return True, account_notify_content
|
||||
|
||||
print(f"\n 📋 本次共有{len(tasks)}个待做任务")
|
||||
account_notify_content.append(f"\n 📋 本次共有{len(tasks)}个待做任务")
|
||||
|
||||
# 记录任务完成情况
|
||||
success_tasks = []
|
||||
failed_tasks = []
|
||||
|
||||
# 将任务分批处理,每批3个
|
||||
for i in range(0, len(tasks), 3):
|
||||
batch = tasks[i:i+3]
|
||||
batch_num = i // 3 + 1
|
||||
total_batches = (len(tasks) + 2) // 3
|
||||
|
||||
print(f"\n 🔄 开始执行第{batch_num}/{total_batches}批任务:")
|
||||
account_notify_content.append(f"\n 🔄 开始执行第{batch_num}/{total_batches}批任务:")
|
||||
for task in batch:
|
||||
print(f" - 📌 {task['title']} (需要浏览{task['browserTime']}秒)")
|
||||
account_notify_content.append(f" - 📌 {task['title']} (需要浏览{task['browserTime']}秒)")
|
||||
|
||||
# 创建当前批次任务的协程
|
||||
batch_coroutines = [
|
||||
execute_task(session, phone, apptoken, device, task['taskCode'], task['title'], task['browserTime'])
|
||||
for task in batch
|
||||
]
|
||||
# 并发执行当前批次的任务
|
||||
results = await asyncio.gather(*batch_coroutines)
|
||||
|
||||
# 处理任务结果
|
||||
for success, message in results:
|
||||
if success:
|
||||
success_tasks.append(message)
|
||||
else:
|
||||
failed_tasks.append(message)
|
||||
|
||||
# 批次间隔
|
||||
if batch_num < total_batches:
|
||||
wait_time = random.uniform(1, 2)
|
||||
print(f"\n ⏳ 等待{wait_time:.1f}秒后执行下一批任务...")
|
||||
account_notify_content.append(f"\n ⏳ 等待{wait_time:.1f}秒后执行下一批任务...")
|
||||
await asyncio.sleep(wait_time)
|
||||
|
||||
# 添加任务结果统计
|
||||
account_notify_content.append("\n 📊 任务执行统计:")
|
||||
account_notify_content.append(f" - ✅ 成功完成 {len(success_tasks)} 个任务")
|
||||
for msg in success_tasks:
|
||||
account_notify_content.append(f" - {msg}")
|
||||
|
||||
if failed_tasks:
|
||||
account_notify_content.append(f" - ❌ 失败 {len(failed_tasks)} 个任务")
|
||||
for msg in failed_tasks:
|
||||
account_notify_content.append(f" - {msg}")
|
||||
|
||||
# 获取积分信息
|
||||
info_url = "https://app.17u.cn/welfarecenter/index/signIndex"
|
||||
info_headers = get_headers(phone, apptoken, device, {})
|
||||
|
||||
async with session.post(info_url, json={}, headers=info_headers) as response:
|
||||
data = await response.json()
|
||||
if data['code'] == 2200:
|
||||
cycle_sign_num = data['data']['cycleSighNum']
|
||||
continuous_history = data['data']['continuousHistory']
|
||||
mileage = data['data']['mileageBalance']['mileage']
|
||||
today_mileage = data['data']['mileageBalance']['todayMileage']
|
||||
|
||||
# 获取特殊连续签到信息
|
||||
special_info = data['data'].get('specialContinuousInfo', {})
|
||||
next_reward_mileage = special_info.get('nextRewardMileage', 0)
|
||||
need_sign = special_info.get('needSign', 0)
|
||||
next_reward_day = special_info.get('nextRewardDay', 0)
|
||||
|
||||
print(f"\n 📊 任务完成情况:")
|
||||
account_notify_content.append(f"\n 📊 任务完成情况:")
|
||||
print(f" - 📅 周期内连续签到{cycle_sign_num}天,已连续签到{continuous_history}天")
|
||||
account_notify_content.append(f" - 📅 周期内连续签到{cycle_sign_num}天,已连续签到{continuous_history}天")
|
||||
if need_sign > 0 and next_reward_day > 0:
|
||||
print(f" - 🎯 再签{need_sign}天,可获得「{next_reward_day}日奖励」(最高{next_reward_mileage}里程)")
|
||||
account_notify_content.append(f" - 🎯 再签{need_sign}天,可获得「{next_reward_day}日奖励」(最高{next_reward_mileage}里程)")
|
||||
print(f" - 💰 今日获取{today_mileage}里程,当前剩余{mileage}里程")
|
||||
account_notify_content.append(f" - 💰 今日获取{today_mileage}里程,当前剩余{mileage}里程")
|
||||
|
||||
return True, account_notify_content
|
||||
|
||||
# 异步发送通知
|
||||
async def async_send_notification(send_func, title, content, loop=None):
|
||||
if not loop:
|
||||
loop = asyncio.get_running_loop()
|
||||
|
||||
# 创建线程池执行器
|
||||
with ThreadPoolExecutor(max_workers=1) as executor:
|
||||
try:
|
||||
# 在单独的线程中执行同步的通知函数
|
||||
result = await loop.run_in_executor(executor, lambda: send_func(title, content))
|
||||
print("✅ 通知发送成功")
|
||||
return True, result
|
||||
except Exception as e:
|
||||
# 获取详细的错误堆栈信息
|
||||
error_stack = traceback.format_exc()
|
||||
print(f"❌ 通知发送失败: {str(e)}")
|
||||
print(f"错误堆栈信息:\n{error_stack}")
|
||||
return False, str(e)
|
||||
|
||||
# 主函数
|
||||
async def main():
|
||||
# 存储所有账号的通知内容
|
||||
all_notify_title = "同程旅行任务执行结果"
|
||||
all_notify_content = []
|
||||
|
||||
# 尝试导入通知模块
|
||||
send = None
|
||||
notify_found = False
|
||||
print("\n🔍 正在查找青龙面板通知模块...")
|
||||
|
||||
# 青龙面板默认路径
|
||||
QL_SCRIPTS_DIR = '/ql/scripts'
|
||||
sys.path.append(QL_SCRIPTS_DIR)
|
||||
|
||||
# 添加notify可能存在的其他路径
|
||||
POSSIBLE_PATHS = [
|
||||
'/ql', # 青龙根目录
|
||||
'/ql/data/scripts', # 新版青龙数据目录
|
||||
'/ql/repo', # 青龙脚本仓库目录
|
||||
'/ql/repo/QLDependency', # QLDependency仓库目录
|
||||
'/ql/config', # 配置目录
|
||||
os.path.dirname(__file__), # 当前脚本目录
|
||||
os.path.join(os.path.dirname(__file__), 'notify') # 当前目录下的notify文件夹
|
||||
]
|
||||
|
||||
# 检查每个路径是否存在并尝试导入
|
||||
for path in POSSIBLE_PATHS:
|
||||
notify_path = os.path.join(path, 'notify.py')
|
||||
print(f" - 检查路径: {notify_path}")
|
||||
if os.path.exists(notify_path):
|
||||
print(f" ✅ 找到通知模块文件")
|
||||
try:
|
||||
# 临时添加路径到sys.path
|
||||
if path not in sys.path:
|
||||
sys.path.append(path)
|
||||
from notify import send
|
||||
print(f" ✅ 成功导入通知模块")
|
||||
notify_found = True
|
||||
break
|
||||
except Exception as e:
|
||||
print(f" ❌ 导入失败: {str(e)}")
|
||||
else:
|
||||
print(f" ❌ 文件不存在")
|
||||
|
||||
# 如果未找到通知模块,创建一个模拟函数
|
||||
if not notify_found:
|
||||
print("❌ 未找到青龙面板通知模块,请确保notify.py存在于正确的路径")
|
||||
print("❌ 脚本将继续执行,但无法发送通知")
|
||||
def dummy_send(title, content):
|
||||
print(f"\n📧 通知内容 (未发送):\n{title}\n\n{content}")
|
||||
return "Notification not sent - notify.py not found"
|
||||
send = dummy_send
|
||||
|
||||
# 继续执行主程序
|
||||
accounts = get_accounts()
|
||||
if not accounts:
|
||||
print("❌ 没有找到有效的账号信息,请添加环境变量")
|
||||
print("❌ 环境变量名称tongcheng 格式为:phone&apptoken&device")
|
||||
all_notify_content.append("❌ 没有找到有效的账号信息,请添加环境变量")
|
||||
all_notify_content.append("❌ 环境变量名称tongcheng 格式为:phone&apptoken&device")
|
||||
# 异步发送通知
|
||||
loop = asyncio.get_running_loop()
|
||||
await async_send_notification(send, all_notify_title, "\n".join(all_notify_content), loop)
|
||||
return
|
||||
|
||||
print(f"🔍 本次共获取到 {len(accounts)} 个账号")
|
||||
all_notify_content.append(f"🔍 本次共获取到 {len(accounts)} 个账号")
|
||||
|
||||
# 统计信息
|
||||
total_accounts = len(accounts)
|
||||
success_accounts = 0
|
||||
failed_accounts = 0
|
||||
|
||||
# 存储每个账号的结果
|
||||
account_results = []
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# 串行处理每个账号
|
||||
for i, account in enumerate(accounts, 1):
|
||||
print(f"\n📱 开始处理第 {i}/{len(accounts)} 个账号")
|
||||
account_result = {
|
||||
'phone': mask_phone(account['phone']),
|
||||
'success': False,
|
||||
'content': []
|
||||
}
|
||||
|
||||
success, content = await process_account(session, account)
|
||||
|
||||
account_result['success'] = success
|
||||
account_result['content'] = content
|
||||
|
||||
account_results.append(account_result)
|
||||
|
||||
# 统计账号执行情况
|
||||
if success:
|
||||
success_accounts += 1
|
||||
else:
|
||||
failed_accounts += 1
|
||||
|
||||
if i < len(accounts):
|
||||
wait_time = random.uniform(2, 3)
|
||||
print(f"\n⏳ 等待 {wait_time:.1f} 秒后处理下一个账号...")
|
||||
await asyncio.sleep(wait_time)
|
||||
|
||||
# 构建聚合通知
|
||||
all_notify_content.append("\n\n📊 总体执行统计:")
|
||||
all_notify_content.append(f" - 账号总数:{total_accounts}")
|
||||
all_notify_content.append(f" - 成功:{success_accounts}")
|
||||
all_notify_content.append(f" - 失败:{failed_accounts}")
|
||||
|
||||
all_notify_content.append("\n\n===== 详细结果 =====")
|
||||
|
||||
# 添加每个账号的结果
|
||||
for result in account_results:
|
||||
all_notify_content.append(f"\n\n📱 账号:{result['phone']}")
|
||||
all_notify_content.append(f"{'✅ 成功' if result['success'] else '❌ 失败'}")
|
||||
all_notify_content.extend(result['content'])
|
||||
|
||||
# 发送聚合通知
|
||||
print("\n📤 正在发送通知...")
|
||||
loop = asyncio.get_running_loop()
|
||||
notify_success, notify_result = await async_send_notification(send, all_notify_title, "\n".join(all_notify_content), loop)
|
||||
|
||||
# 记录通知发送结果
|
||||
if not notify_success:
|
||||
all_notify_content.append("\n\n⚠️ 通知发送失败,请检查notify.py配置")
|
||||
all_notify_content.append(f"错误信息:{notify_result}")
|
||||
|
||||
print("✅ 脚本执行完成")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
@ -1,277 +1,277 @@
|
||||
# -*- coding: utf-8 -*
|
||||
'''
|
||||
定时自定义
|
||||
0 0 1 * * ?
|
||||
new Env('iKuuu签到');
|
||||
'''
|
||||
import requests
|
||||
import re
|
||||
import json
|
||||
import os
|
||||
import datetime
|
||||
import urllib.parse
|
||||
import sys
|
||||
import time
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
# 添加青龙脚本根目录到Python路径
|
||||
QL_SCRIPTS_DIR = '/ql/scripts' # 青龙脚本默认目录
|
||||
sys.path.append(QL_SCRIPTS_DIR)
|
||||
|
||||
# 添加notify可能存在的其他路径
|
||||
POSSIBLE_PATHS = [
|
||||
'/ql', # 青龙根目录
|
||||
'/ql/data/scripts', # 新版青龙数据目录
|
||||
'/ql/scripts/notify', # 自定义通知目录
|
||||
os.path.dirname(__file__) # 当前脚本目录
|
||||
]
|
||||
|
||||
for path in POSSIBLE_PATHS:
|
||||
if os.path.exists(os.path.join(path, 'notify.py')):
|
||||
sys.path.append(path)
|
||||
break
|
||||
|
||||
try:
|
||||
from notify import send
|
||||
except ImportError:
|
||||
print("⚠️ 无法加载通知模块,请检查路径配置")
|
||||
send = lambda title, content: None # 创建空函数防止报错
|
||||
|
||||
# 初始域名
|
||||
ikun_host = "ikuuu.one" # 自动更新于2025-04-29 13:08:20
|
||||
backup_hosts = ["ikuuu.one", "ikuuu.pw", "ikuuu.me"] # 备用域名列表
|
||||
|
||||
def get_latest_ikun_host():
|
||||
test_url = f"https://{ikun_host}/"
|
||||
try:
|
||||
response = requests.get(test_url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
if "官网域名已更改" in response.text or "Domain deprecated" in response.text:
|
||||
print("检测到域名变更通知,正在提取新域名...")
|
||||
h2_matches = re.findall(r'<h2>.*?(?:域名|domain)[::]\s*([a-zA-Z0-9.-]+)</h2>', response.text)
|
||||
if h2_matches:
|
||||
return h2_matches[0]
|
||||
js_matches = re.findall(r'https?://([a-zA-Z0-9.-]+)/auth/login', response.text)
|
||||
if js_matches:
|
||||
return js_matches[0]
|
||||
fallback_match = re.search(r'(?:域名|domain)[::]\s*([a-zA-Z0-9.-]+)', response.text)
|
||||
if fallback_match:
|
||||
return fallback_match.group(1)
|
||||
print("⚠️ 检测到域名变更但无法提取新域名")
|
||||
return None
|
||||
else:
|
||||
print("✅ 当前域名正常")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"域名检测异常: {e}")
|
||||
return None
|
||||
|
||||
def update_self_host(new_host):
|
||||
script_path = os.path.abspath(__file__)
|
||||
with open(script_path, "r", encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
updated = False
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip().startswith("ikun_host = "):
|
||||
lines[i] = f'ikun_host = "{new_host}" # 自动更新于{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}\n'
|
||||
updated = True
|
||||
break
|
||||
if updated:
|
||||
with open(script_path, "w", encoding="utf-8") as f:
|
||||
f.writelines(lines)
|
||||
print(f"✅ 脚本已更新至域名: {new_host}")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ 域名更新失败")
|
||||
return False
|
||||
|
||||
def test_host_reachable(host):
|
||||
try:
|
||||
response = requests.get(f"https://{host}/", timeout=10)
|
||||
return response.status_code == 200
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_remaining_flow(cookies):
|
||||
"""获取用户剩余流量信息"""
|
||||
user_url = f'https://{ikun_host}/user'
|
||||
try:
|
||||
# 获取用户页面
|
||||
user_page = requests.get(user_url, cookies=cookies, timeout=15)
|
||||
if user_page.status_code != 200:
|
||||
return "获取流量失败", "状态码: " + str(user_page.status_code)
|
||||
|
||||
# 使用BeautifulSoup解析HTML
|
||||
soup = BeautifulSoup(user_page.text, 'html.parser')
|
||||
|
||||
# 查找包含剩余流量的卡片
|
||||
flow_cards = soup.find_all('div', class_='card card-statistic-2')
|
||||
for card in flow_cards:
|
||||
h4_tag = card.find('h4')
|
||||
if h4_tag and '剩余流量' in h4_tag.text:
|
||||
# 查找流量数值
|
||||
counter_span = card.find('span', class_='counter')
|
||||
if counter_span:
|
||||
flow_value = counter_span.text.strip()
|
||||
|
||||
# 查找流量单位
|
||||
unit_text = ""
|
||||
next_sibling = counter_span.next_sibling
|
||||
if next_sibling:
|
||||
unit_text = next_sibling.strip()
|
||||
|
||||
return flow_value, unit_text
|
||||
|
||||
# 如果没有找到,尝试其他方式
|
||||
flow_div = soup.find('div', string='剩余流量')
|
||||
if flow_div:
|
||||
parent_div = flow_div.find_parent('div', class_='card-body')
|
||||
if parent_div:
|
||||
flow_text = parent_div.get_text(strip=True).replace('剩余流量', '')
|
||||
return flow_text.split()[0], flow_text.split()[1] if len(flow_text.split()) > 1 else ""
|
||||
|
||||
return "未找到", "流量信息"
|
||||
|
||||
except Exception as e:
|
||||
return "流量获取异常", str(e)
|
||||
|
||||
def ikuuu_signin(email, password):
|
||||
params = {'email': email, 'passwd': password, 'code': ''}
|
||||
login_url = f'https://{ikun_host}/auth/login'
|
||||
try:
|
||||
# 登录请求
|
||||
login_res = requests.post(login_url, data=params, timeout=15)
|
||||
if login_res.status_code != 200:
|
||||
flow_value, flow_unit = "登录失败", "无法获取"
|
||||
return False, f"登录失败(状态码{login_res.status_code})", flow_value, flow_unit
|
||||
|
||||
login_data = login_res.json()
|
||||
if login_data.get('ret') != 1:
|
||||
flow_value, flow_unit = "登录失败", "无法获取"
|
||||
return False, f"登录失败:{login_data.get('msg', '未知错误')}", flow_value, flow_unit
|
||||
|
||||
# 获取用户剩余流量
|
||||
cookies = login_res.cookies
|
||||
flow_value, flow_unit = get_remaining_flow(cookies)
|
||||
|
||||
# 执行签到
|
||||
checkin_res = requests.post(f'https://{ikun_host}/user/checkin', cookies=cookies, timeout=15)
|
||||
if checkin_res.status_code != 200:
|
||||
return False, f"签到失败(状态码{checkin_res.status_code})", flow_value, flow_unit
|
||||
|
||||
checkin_data = checkin_res.json()
|
||||
if checkin_data.get('ret') == 1:
|
||||
return True, f"成功 | {checkin_data.get('msg', '')}", flow_value, flow_unit
|
||||
else:
|
||||
return False, f"签到失败:{checkin_data.get('msg', '未知错误')}", flow_value, flow_unit
|
||||
except json.JSONDecodeError:
|
||||
return False, "响应解析失败", "未知", "未知"
|
||||
except requests.exceptions.Timeout:
|
||||
return False, "请求超时", "未知", "未知"
|
||||
except Exception as e:
|
||||
return False, f"请求异常:{str(e)}", "未知", "未知"
|
||||
|
||||
def send_qinglong_notification(results):
|
||||
"""
|
||||
使用青龙面板内置通知系统发送通知
|
||||
需要青龙面板已配置通知渠道(如钉钉、企业微信等)
|
||||
"""
|
||||
title = "iKuuu签到通知"
|
||||
|
||||
# 构建消息内容
|
||||
success_count = sum(1 for res in results if res['success'])
|
||||
failure_count = len(results) - success_count
|
||||
|
||||
message = [
|
||||
f"🔔 签到完成 | 成功:{success_count} 失败:{failure_count}",
|
||||
"================================"
|
||||
]
|
||||
|
||||
for index, res in enumerate(results, 1):
|
||||
status = "✅ 成功" if res['success'] else "❌ 失败"
|
||||
message.append(f"{index}. {res['email']}")
|
||||
message.append(f" 状态:{status}")
|
||||
message.append(f" 详情:{res['message']}")
|
||||
message.append(f" 剩余流量:{res['flow_value']} {res['flow_unit']}")
|
||||
message.append("--------------------------------")
|
||||
|
||||
# 添加统计信息
|
||||
message.append("\n🕒 执行时间:" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
try:
|
||||
# 发送通知(青龙自动处理多通知渠道)
|
||||
send(title, "\n".join(message))
|
||||
print("✅ 通知已发送")
|
||||
except Exception as e:
|
||||
print(f"⚠️ 通知发送失败,请检查通知配置: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# ==================== 域名更新逻辑 ====================
|
||||
print(f"当前域名: {ikun_host}")
|
||||
latest_host = get_latest_ikun_host()
|
||||
if latest_host:
|
||||
print(f"检测到新域名: {latest_host}")
|
||||
if update_self_host(latest_host):
|
||||
ikun_host = latest_host
|
||||
|
||||
# ==================== 域名可用性检查 ====================
|
||||
if not test_host_reachable(ikun_host):
|
||||
print("主域名不可用,尝试备用域名...")
|
||||
found = False
|
||||
for host in backup_hosts:
|
||||
if test_host_reachable(host):
|
||||
ikun_host = host
|
||||
print(f"切换到备用域名: {ikun_host}")
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
print("❌ 所有域名均不可用")
|
||||
exit(1)
|
||||
|
||||
# ==================== 账户处理 ====================
|
||||
accounts = []
|
||||
account_str = os.getenv('IKUUU_ACCOUNTS')
|
||||
if not account_str:
|
||||
print("❌ 未找到环境变量 IKUUU_ACCOUNTS")
|
||||
exit(1)
|
||||
|
||||
for line in account_str.strip().splitlines():
|
||||
if ':' in line:
|
||||
email, pwd = line.split(':', 1)
|
||||
accounts.append((email.strip(), pwd.strip()))
|
||||
else:
|
||||
print(f"⚠️ 忽略无效账户行: {line}")
|
||||
|
||||
if not accounts:
|
||||
print("❌ 未找到有效账户")
|
||||
exit(1)
|
||||
|
||||
# ==================== 执行签到 ====================
|
||||
results = []
|
||||
for email, pwd in accounts:
|
||||
print(f"\n处理账户: {email}")
|
||||
success, msg, flow_value, flow_unit = ikuuu_signin(email, pwd)
|
||||
results.append({
|
||||
'email': email,
|
||||
'success': success,
|
||||
'message': msg,
|
||||
'flow_value': flow_value,
|
||||
'flow_unit': flow_unit
|
||||
})
|
||||
print(f"结果: {'成功' if success else '失败'} - {msg}")
|
||||
print(f"剩余流量: {flow_value} {flow_unit}")
|
||||
|
||||
# 账户间延迟防止请求过快
|
||||
time.sleep(1)
|
||||
|
||||
# ==================== 结果通知 ====================
|
||||
print("\n正在发送通知...")
|
||||
send_qinglong_notification(results)
|
||||
|
||||
# ==================== 本地结果输出 ====================
|
||||
print("\n签到结果汇总:")
|
||||
for res in results:
|
||||
print(f"邮箱: {res['email']}")
|
||||
print(f"状态: {'成功' if res['success'] else '失败'}")
|
||||
print(f"详情: {res['message']}")
|
||||
# -*- coding: utf-8 -*
|
||||
'''
|
||||
定时自定义
|
||||
0 0 1 * * ?
|
||||
new Env('iKuuu签到');
|
||||
'''
|
||||
import requests
|
||||
import re
|
||||
import json
|
||||
import os
|
||||
import datetime
|
||||
import urllib.parse
|
||||
import sys
|
||||
import time
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
# 添加青龙脚本根目录到Python路径
|
||||
QL_SCRIPTS_DIR = '/ql/scripts' # 青龙脚本默认目录
|
||||
sys.path.append(QL_SCRIPTS_DIR)
|
||||
|
||||
# 添加notify可能存在的其他路径
|
||||
POSSIBLE_PATHS = [
|
||||
'/ql', # 青龙根目录
|
||||
'/ql/data/scripts', # 新版青龙数据目录
|
||||
'/ql/scripts/notify', # 自定义通知目录
|
||||
os.path.dirname(__file__) # 当前脚本目录
|
||||
]
|
||||
|
||||
for path in POSSIBLE_PATHS:
|
||||
if os.path.exists(os.path.join(path, 'notify.py')):
|
||||
sys.path.append(path)
|
||||
break
|
||||
|
||||
try:
|
||||
from notify import send
|
||||
except ImportError:
|
||||
print("⚠️ 无法加载通知模块,请检查路径配置")
|
||||
send = lambda title, content: None # 创建空函数防止报错
|
||||
|
||||
# 初始域名
|
||||
ikun_host = "ikuuu.one" # 自动更新于2025-04-29 13:08:20
|
||||
backup_hosts = ["ikuuu.one", "ikuuu.pw", "ikuuu.me"] # 备用域名列表
|
||||
|
||||
def get_latest_ikun_host():
|
||||
test_url = f"https://{ikun_host}/"
|
||||
try:
|
||||
response = requests.get(test_url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
if "官网域名已更改" in response.text or "Domain deprecated" in response.text:
|
||||
print("检测到域名变更通知,正在提取新域名...")
|
||||
h2_matches = re.findall(r'<h2>.*?(?:域名|domain)[::]\s*([a-zA-Z0-9.-]+)</h2>', response.text)
|
||||
if h2_matches:
|
||||
return h2_matches[0]
|
||||
js_matches = re.findall(r'https?://([a-zA-Z0-9.-]+)/auth/login', response.text)
|
||||
if js_matches:
|
||||
return js_matches[0]
|
||||
fallback_match = re.search(r'(?:域名|domain)[::]\s*([a-zA-Z0-9.-]+)', response.text)
|
||||
if fallback_match:
|
||||
return fallback_match.group(1)
|
||||
print("⚠️ 检测到域名变更但无法提取新域名")
|
||||
return None
|
||||
else:
|
||||
print("✅ 当前域名正常")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"域名检测异常: {e}")
|
||||
return None
|
||||
|
||||
def update_self_host(new_host):
|
||||
script_path = os.path.abspath(__file__)
|
||||
with open(script_path, "r", encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
updated = False
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip().startswith("ikun_host = "):
|
||||
lines[i] = f'ikun_host = "{new_host}" # 自动更新于{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}\n'
|
||||
updated = True
|
||||
break
|
||||
if updated:
|
||||
with open(script_path, "w", encoding="utf-8") as f:
|
||||
f.writelines(lines)
|
||||
print(f"✅ 脚本已更新至域名: {new_host}")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ 域名更新失败")
|
||||
return False
|
||||
|
||||
def test_host_reachable(host):
|
||||
try:
|
||||
response = requests.get(f"https://{host}/", timeout=10)
|
||||
return response.status_code == 200
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_remaining_flow(cookies):
|
||||
"""获取用户剩余流量信息"""
|
||||
user_url = f'https://{ikun_host}/user'
|
||||
try:
|
||||
# 获取用户页面
|
||||
user_page = requests.get(user_url, cookies=cookies, timeout=15)
|
||||
if user_page.status_code != 200:
|
||||
return "获取流量失败", "状态码: " + str(user_page.status_code)
|
||||
|
||||
# 使用BeautifulSoup解析HTML
|
||||
soup = BeautifulSoup(user_page.text, 'html.parser')
|
||||
|
||||
# 查找包含剩余流量的卡片
|
||||
flow_cards = soup.find_all('div', class_='card card-statistic-2')
|
||||
for card in flow_cards:
|
||||
h4_tag = card.find('h4')
|
||||
if h4_tag and '剩余流量' in h4_tag.text:
|
||||
# 查找流量数值
|
||||
counter_span = card.find('span', class_='counter')
|
||||
if counter_span:
|
||||
flow_value = counter_span.text.strip()
|
||||
|
||||
# 查找流量单位
|
||||
unit_text = ""
|
||||
next_sibling = counter_span.next_sibling
|
||||
if next_sibling:
|
||||
unit_text = next_sibling.strip()
|
||||
|
||||
return flow_value, unit_text
|
||||
|
||||
# 如果没有找到,尝试其他方式
|
||||
flow_div = soup.find('div', string='剩余流量')
|
||||
if flow_div:
|
||||
parent_div = flow_div.find_parent('div', class_='card-body')
|
||||
if parent_div:
|
||||
flow_text = parent_div.get_text(strip=True).replace('剩余流量', '')
|
||||
return flow_text.split()[0], flow_text.split()[1] if len(flow_text.split()) > 1 else ""
|
||||
|
||||
return "未找到", "流量信息"
|
||||
|
||||
except Exception as e:
|
||||
return "流量获取异常", str(e)
|
||||
|
||||
def ikuuu_signin(email, password):
|
||||
params = {'email': email, 'passwd': password, 'code': ''}
|
||||
login_url = f'https://{ikun_host}/auth/login'
|
||||
try:
|
||||
# 登录请求
|
||||
login_res = requests.post(login_url, data=params, timeout=15)
|
||||
if login_res.status_code != 200:
|
||||
flow_value, flow_unit = "登录失败", "无法获取"
|
||||
return False, f"登录失败(状态码{login_res.status_code})", flow_value, flow_unit
|
||||
|
||||
login_data = login_res.json()
|
||||
if login_data.get('ret') != 1:
|
||||
flow_value, flow_unit = "登录失败", "无法获取"
|
||||
return False, f"登录失败:{login_data.get('msg', '未知错误')}", flow_value, flow_unit
|
||||
|
||||
# 获取用户剩余流量
|
||||
cookies = login_res.cookies
|
||||
flow_value, flow_unit = get_remaining_flow(cookies)
|
||||
|
||||
# 执行签到
|
||||
checkin_res = requests.post(f'https://{ikun_host}/user/checkin', cookies=cookies, timeout=15)
|
||||
if checkin_res.status_code != 200:
|
||||
return False, f"签到失败(状态码{checkin_res.status_code})", flow_value, flow_unit
|
||||
|
||||
checkin_data = checkin_res.json()
|
||||
if checkin_data.get('ret') == 1:
|
||||
return True, f"成功 | {checkin_data.get('msg', '')}", flow_value, flow_unit
|
||||
else:
|
||||
return False, f"签到失败:{checkin_data.get('msg', '未知错误')}", flow_value, flow_unit
|
||||
except json.JSONDecodeError:
|
||||
return False, "响应解析失败", "未知", "未知"
|
||||
except requests.exceptions.Timeout:
|
||||
return False, "请求超时", "未知", "未知"
|
||||
except Exception as e:
|
||||
return False, f"请求异常:{str(e)}", "未知", "未知"
|
||||
|
||||
def send_qinglong_notification(results):
|
||||
"""
|
||||
使用青龙面板内置通知系统发送通知
|
||||
需要青龙面板已配置通知渠道(如钉钉、企业微信等)
|
||||
"""
|
||||
title = "iKuuu签到通知"
|
||||
|
||||
# 构建消息内容
|
||||
success_count = sum(1 for res in results if res['success'])
|
||||
failure_count = len(results) - success_count
|
||||
|
||||
message = [
|
||||
f"🔔 签到完成 | 成功:{success_count} 失败:{failure_count}",
|
||||
"================================"
|
||||
]
|
||||
|
||||
for index, res in enumerate(results, 1):
|
||||
status = "✅ 成功" if res['success'] else "❌ 失败"
|
||||
message.append(f"{index}. {res['email']}")
|
||||
message.append(f" 状态:{status}")
|
||||
message.append(f" 详情:{res['message']}")
|
||||
message.append(f" 剩余流量:{res['flow_value']} {res['flow_unit']}")
|
||||
message.append("--------------------------------")
|
||||
|
||||
# 添加统计信息
|
||||
message.append("\n🕒 执行时间:" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
try:
|
||||
# 发送通知(青龙自动处理多通知渠道)
|
||||
send(title, "\n".join(message))
|
||||
print("✅ 通知已发送")
|
||||
except Exception as e:
|
||||
print(f"⚠️ 通知发送失败,请检查通知配置: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# ==================== 域名更新逻辑 ====================
|
||||
print(f"当前域名: {ikun_host}")
|
||||
latest_host = get_latest_ikun_host()
|
||||
if latest_host:
|
||||
print(f"检测到新域名: {latest_host}")
|
||||
if update_self_host(latest_host):
|
||||
ikun_host = latest_host
|
||||
|
||||
# ==================== 域名可用性检查 ====================
|
||||
if not test_host_reachable(ikun_host):
|
||||
print("主域名不可用,尝试备用域名...")
|
||||
found = False
|
||||
for host in backup_hosts:
|
||||
if test_host_reachable(host):
|
||||
ikun_host = host
|
||||
print(f"切换到备用域名: {ikun_host}")
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
print("❌ 所有域名均不可用")
|
||||
exit(1)
|
||||
|
||||
# ==================== 账户处理 ====================
|
||||
accounts = []
|
||||
account_str = os.getenv('IKUUU_ACCOUNTS')
|
||||
if not account_str:
|
||||
print("❌ 未找到环境变量 IKUUU_ACCOUNTS")
|
||||
exit(1)
|
||||
|
||||
for line in account_str.strip().splitlines():
|
||||
if ':' in line:
|
||||
email, pwd = line.split(':', 1)
|
||||
accounts.append((email.strip(), pwd.strip()))
|
||||
else:
|
||||
print(f"⚠️ 忽略无效账户行: {line}")
|
||||
|
||||
if not accounts:
|
||||
print("❌ 未找到有效账户")
|
||||
exit(1)
|
||||
|
||||
# ==================== 执行签到 ====================
|
||||
results = []
|
||||
for email, pwd in accounts:
|
||||
print(f"\n处理账户: {email}")
|
||||
success, msg, flow_value, flow_unit = ikuuu_signin(email, pwd)
|
||||
results.append({
|
||||
'email': email,
|
||||
'success': success,
|
||||
'message': msg,
|
||||
'flow_value': flow_value,
|
||||
'flow_unit': flow_unit
|
||||
})
|
||||
print(f"结果: {'成功' if success else '失败'} - {msg}")
|
||||
print(f"剩余流量: {flow_value} {flow_unit}")
|
||||
|
||||
# 账户间延迟防止请求过快
|
||||
time.sleep(1)
|
||||
|
||||
# ==================== 结果通知 ====================
|
||||
print("\n正在发送通知...")
|
||||
send_qinglong_notification(results)
|
||||
|
||||
# ==================== 本地结果输出 ====================
|
||||
print("\n签到结果汇总:")
|
||||
for res in results:
|
||||
print(f"邮箱: {res['email']}")
|
||||
print(f"状态: {'成功' if res['success'] else '失败'}")
|
||||
print(f"详情: {res['message']}")
|
||||
print(f"剩余流量: {res['flow_value']} {res['flow_unit']}\n{'-'*40}")
|
Loading…
Reference in New Issue
Block a user