profile reads getuserhome.php (power/level/alliance); news and info hit public getsite_new.php / getindex.php. Store private endpoints authenticate with the UID alone as Usertoken — no password needed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
206 lines
5.8 KiB
Python
206 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
||
"""Last-Z Gift Center CLI"""
|
||
|
||
import argparse
|
||
import os
|
||
import sys
|
||
|
||
import requests
|
||
from dotenv import load_dotenv
|
||
|
||
load_dotenv()
|
||
|
||
BASE_URL = "https://giftcenter.last-z.com"
|
||
STORE_URL = "https://store.last-z.com"
|
||
|
||
LOGIN_ERRORS = {
|
||
10006: "Token 已過期",
|
||
10007: "請稍後再試",
|
||
10017: "需要充值記錄",
|
||
10018: "UID 不存在",
|
||
10019: "不支援的幣別",
|
||
10020: "操作過於頻繁",
|
||
10022: "帳號警告",
|
||
10023: "不支援的地區",
|
||
10024: "帳號已刪除",
|
||
10002001: "系統錯誤",
|
||
10002002: "請求逾時",
|
||
10002003: "未預期的錯誤",
|
||
}
|
||
|
||
REDEEM_ERRORS = {
|
||
"E001": "系統錯誤",
|
||
"E002": "系統錯誤",
|
||
"E003": "系統錯誤",
|
||
"E004": "禮品碼不存在",
|
||
"E005": "禮品碼已過期",
|
||
"E006": "禮品碼已被使用",
|
||
"E007": "兌換次數已達上限",
|
||
"E008": "系統錯誤",
|
||
"E009": "請稍後再試",
|
||
}
|
||
|
||
|
||
def get_uid():
|
||
uid = os.getenv("UID")
|
||
if not uid:
|
||
print("錯誤:請在 .env 設定 UID=your_uid_here", file=sys.stderr)
|
||
sys.exit(1)
|
||
return uid
|
||
|
||
|
||
def cmd_login(args):
|
||
uid = args.uid or get_uid()
|
||
try:
|
||
resp = requests.get(f"{BASE_URL}/getcodeuser.php", params={"uid": uid}, timeout=10)
|
||
resp.raise_for_status()
|
||
data = resp.json()
|
||
except requests.RequestException as e:
|
||
print(f"請求失敗:{e}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
if data.get("code") == 0:
|
||
r = data["result"]
|
||
print(f"登入成功")
|
||
print(f" 名稱 : {r.get('name')}")
|
||
print(f" UID : {uid}")
|
||
print(f" SID : {r.get('sid')}")
|
||
print(f" 國家 : {r.get('country')}")
|
||
print(f" 等級 : {r.get('level')}")
|
||
else:
|
||
code = data.get("code", 10002001)
|
||
print(f"登入失敗:{LOGIN_ERRORS.get(code, f'錯誤碼 {code}')}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
|
||
def cmd_redeem(args):
|
||
uid = args.uid or get_uid()
|
||
code = args.code
|
||
try:
|
||
resp = requests.get(
|
||
f"{BASE_URL}/code.php",
|
||
headers={"Usertoken": uid},
|
||
params={"uid": uid, "code": code},
|
||
timeout=10,
|
||
)
|
||
resp.raise_for_status()
|
||
data = resp.json()
|
||
except requests.RequestException as e:
|
||
print(f"請求失敗:{e}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
error_code = data.get("errorCode")
|
||
if error_code == "ok":
|
||
print(f"兌換成功!禮品碼 {code} 已套用")
|
||
else:
|
||
msg = REDEEM_ERRORS.get(error_code, f"未知錯誤碼 {error_code}")
|
||
print(f"兌換失敗:{msg}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
|
||
def store_post(endpoint):
|
||
# store.last-z.com 公開端點,免 token
|
||
try:
|
||
resp = requests.post(f"{STORE_URL}/{endpoint}", json={}, timeout=10)
|
||
resp.raise_for_status()
|
||
return resp.json()
|
||
except requests.RequestException as e:
|
||
print(f"請求失敗:{e}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
|
||
def cmd_news(args):
|
||
data = store_post("getsite_new.php")
|
||
announces = data.get("version_announce", [])
|
||
if not announces:
|
||
print("目前沒有公告")
|
||
return
|
||
for a in announces:
|
||
print(f"[{a.get('createTime')}] {a.get('title')}")
|
||
print(f" 👍 {a.get('like_count', 0)} 👎 {a.get('dislike_count', 0)}")
|
||
|
||
|
||
def cmd_info(args):
|
||
data = store_post("getindex.php")
|
||
print(f"地區 : {data.get('clientCountry')}")
|
||
print(f"APK 下載 : {data.get('apkurl')}")
|
||
print(f"Token : {data.get('token')}")
|
||
|
||
|
||
def store_auth(endpoint, uid):
|
||
# store.last-z.com 私人端點只認 UID 當 Usertoken(無密碼)
|
||
try:
|
||
resp = requests.post(
|
||
f"{STORE_URL}/{endpoint}",
|
||
headers={"Usertoken": uid},
|
||
json={"uid": uid},
|
||
timeout=10,
|
||
)
|
||
return resp.json()
|
||
except (requests.RequestException, ValueError) as e:
|
||
print(f"請求失敗:{e}", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
|
||
PROFILE_FIELDS = {
|
||
"name": "名稱",
|
||
"uid": "UID",
|
||
"baseLevel": "總部等級",
|
||
"power": "戰力",
|
||
"likeCount": "點贊量",
|
||
"armyKill": "殺敵數量",
|
||
"giftLevel": "送禮等級",
|
||
"kingWinNum": "稱王次數",
|
||
"allianceName": "聯盟",
|
||
"abbr": "聯盟縮寫",
|
||
}
|
||
|
||
|
||
def cmd_profile(args):
|
||
uid = args.uid or get_uid()
|
||
data = store_auth("getuserhome.php", uid)
|
||
if data.get("code") != 0:
|
||
print(f"讀取失敗:{data.get('message') or data.get('code')}", file=sys.stderr)
|
||
sys.exit(1)
|
||
info = data.get("info", {})
|
||
for key, label in PROFILE_FIELDS.items():
|
||
if key in info:
|
||
print(f" {label}\t: {info[key]}")
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(description="Last-Z Gift Center CLI")
|
||
parser.add_argument("--uid", help="指定 UID(覆蓋 .env)")
|
||
sub = parser.add_subparsers(dest="command", required=True)
|
||
|
||
# login
|
||
p_login = sub.add_parser("login", help="登入並查看帳號資訊")
|
||
p_login.add_argument("--uid", help="指定 UID(覆蓋 .env)")
|
||
p_login.set_defaults(func=cmd_login)
|
||
|
||
# redeem
|
||
p_redeem = sub.add_parser("redeem", help="兌換禮品碼")
|
||
p_redeem.add_argument("code", help="禮品碼")
|
||
p_redeem.add_argument("--uid", help="指定 UID(覆蓋 .env)")
|
||
p_redeem.set_defaults(func=cmd_redeem)
|
||
|
||
# news
|
||
p_news = sub.add_parser("news", help="查看遊戲公告")
|
||
p_news.set_defaults(func=cmd_news)
|
||
|
||
# info
|
||
p_info = sub.add_parser("info", help="查看地區與最新 APK 下載連結")
|
||
p_info.set_defaults(func=cmd_info)
|
||
|
||
# profile
|
||
p_profile = sub.add_parser("profile", help="顯示完整帳號資料(戰力/等級/聯盟)")
|
||
p_profile.add_argument("--uid", help="指定 UID(覆蓋 .env)")
|
||
p_profile.set_defaults(func=cmd_profile)
|
||
|
||
args = parser.parse_args()
|
||
args.func(args)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|