1+ #!/usr/bin/env python3
2+ # -*- coding: utf-8 -*-
3+ """
4+ new Env('阿里云盘签到');
5+ cron: 10 6,18 * * *
6+
7+ 环境变量说明:
8+ 变量名: ALIYUN_ACCOUNTS
9+ 格式: refresh_token#备注名 & refresh_token2#备注名2
10+ 提示: 多个账号用 & 或 换行 分隔;内部参数用 # 分隔。
11+ 进入网页端阿里云盘,按 F12 打开开发者工具,打开控制台输入JSON.parse(localStorage.getItem("token")).refresh_token 然后拼接#备注名即可,例如:
12+ """
13+
14+ import os
15+ import re
16+ import time
17+ import logging
18+ import requests
19+ import random
20+ from typing import Dict
21+
22+ # ==================== 日志配置 ====================
23+ logging .basicConfig (level = logging .INFO , format = '%(asctime)s - %(levelname)s - %(message)s' )
24+ logger = logging .getLogger ("AliYun" )
25+
26+ # ==================== 核心逻辑 ====================
27+ class ALiYun :
28+ def __init__ (self , name : str , refresh_token : str ):
29+ self .session = requests .Session ()
30+ self .name = name
31+ self .refresh_token = refresh_token
32+ self .access_token = ""
33+ self .headers = {
34+ "User-Agent" : "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 AlphaDrive/3.0.0" ,
35+ "Content-Type" : "application/json; charset=utf-8"
36+ }
37+
38+ def _refresh_access_token (self ) -> bool :
39+ """刷新 access_token"""
40+ url = 'https://auth.aliyundrive.com/v2/account/token'
41+ payload = {'grant_type' : 'refresh_token' , 'refresh_token' : self .refresh_token }
42+ try :
43+ res = self .session .post (url , json = payload , timeout = 10 ).json ()
44+ if 'access_token' in res :
45+ self .access_token = res ['access_token' ]
46+ self .refresh_token = res ['refresh_token' ] # 更新持久化的token
47+ return True
48+ logger .error (f"[{ self .name } ] 刷新 Token 失败: { res .get ('message' , '未知错误' )} " )
49+ return False
50+ except Exception as e :
51+ logger .error (f"[{ self .name } ] 刷新请求异常: { e } " )
52+ return False
53+
54+ def check_in (self ) -> Dict :
55+ """执行签到"""
56+ url = 'https://member.aliyundrive.com/v1/activity/sign_in_list'
57+ headers = {** self .headers , "Authorization" : f"Bearer { self .access_token } " }
58+ try :
59+ res = self .session .post (url , params = {'_rx-s' : 'mobile' }, json = {'isReward' : False }, headers = headers , timeout = 10 ).json ()
60+ return res
61+ except Exception as e :
62+ return {"success" : False , "message" : str (e )}
63+
64+ def get_reward (self , day : int ) -> str :
65+ """领取奖励"""
66+ url = 'https://member.aliyundrive.com/v1/activity/sign_in_reward'
67+ headers = {** self .headers , "Authorization" : f"Bearer { self .access_token } " }
68+ try :
69+ res = self .session .post (url , params = {'_rx-s' : 'mobile' }, json = {'signInDay' : day }, headers = headers , timeout = 10 ).json ()
70+ return res .get ('result' , {}).get ('notice' , res .get ('message' , '未获取到奖励明细' ))
71+ except Exception :
72+ return "奖励领取请求异常"
73+
74+ def get_capacity (self ) -> str :
75+ """查询容量"""
76+ def fmt (s ): return f"{ s / 1024 / 1024 / 1024 :.2f} GB" if s > 0 else "0 GB"
77+ url = 'https://api.aliyundrive.com/adrive/v1/user/driveCapacityDetails'
78+ headers = {** self .headers , "Authorization" : f"Bearer { self .access_token } " }
79+ try :
80+ res = self .session .post (url , json = {}, headers = headers , timeout = 10 ).json ()
81+ return (f"总空间: { fmt (res .get ('drive_total_size' , 0 ))} \n "
82+ f"已用空间: { fmt (res .get ('drive_used_size' , 0 ))} " )
83+ except : return "容量查询失败"
84+
85+ def run (self ):
86+ logger .info (f"--- 账号 [{ self .name } ] 开始签到 ---" )
87+ if not self ._refresh_access_token ():
88+ return f"[{ self .name } ] ❌ 登录失效"
89+
90+ res = self .check_in ()
91+ if not res .get ('success' ):
92+ return f"[{ self .name } ] ❌ 签到失败: { res .get ('message' )} "
93+
94+ count = res .get ('result' , {}).get ('signInCount' , 0 )
95+ reward_info = self .get_reward (count )
96+ cap_info = self .get_capacity ()
97+
98+ msg = (f"【{ self .name } 】签到成功!\n "
99+ f"本月累计签到: { count } 天\n "
100+ f"本次奖励: { reward_info } \n "
101+ f"{ cap_info } " )
102+ return msg
103+
104+ # ==================== 通知逻辑 ====================
105+ def send_notify (title , content ):
106+ """简易通知,如果有 notify.py 则尝试调用"""
107+ try :
108+ from notify import send
109+ print (title , content )
110+ except ImportError :
111+ logger .info ("\n --- 通知预览 ---\n " + title + "\n " + content )
112+
113+ # ==================== 主入口 ====================
114+ def main ():
115+ raw_conf = os .getenv ("ALIYUN_ACCOUNTS" , "" )
116+ if not raw_conf :
117+ logger .error ("未找到环境变量 ALIYUN_ACCOUNTS" )
118+ return
119+
120+ # 按 & 或 换行 分隔账号
121+ account_list = re .split (r'[&\n]+' , raw_conf .strip ())
122+ final_reports = []
123+
124+ for idx , acc_str in enumerate (account_list ):
125+ if not acc_str .strip (): continue
126+
127+ # 按 # 分隔 token 和 备注
128+ parts = acc_str .split ('#' )
129+ token = parts [0 ].strip ()
130+ name = parts [1 ].strip () if len (parts ) > 1 else f"账号{ idx + 1 } "
131+
132+ if not token :
133+ logger .warning (f"账号 { name } 缺少 refresh_token,跳过" )
134+ continue
135+
136+ client = ALiYun (name , token )
137+ try :
138+ report = client .run ()
139+ final_reports .append (report )
140+ except Exception as e :
141+ logger .error (f"运行异常: { e } " )
142+ final_reports .append (f"[{ name } ] 运行发生异常" )
143+
144+ # 账号间随机延迟
145+ if idx < len (account_list ) - 1 :
146+ time .sleep (random .randint (3 , 8 ))
147+
148+ if final_reports :
149+ print ("阿里云盘签到报告" , "\n " + "=" * 20 + "\n " + "\n \n " .join (final_reports ))
150+
151+ if __name__ == "__main__" :
152+ main ()
0 commit comments