1.创建文件夹

mkdir /root/checkin
cd /root/checkin
nano dler_checkin.py

2.编写脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os, json, argparse
from datetime import datetime
import requests
from typing import Optional

BASE = "https://dler.cloud/api/v1"

# 账号与 TG 参数
EMAIL = ""
PASSWORD = ""
TOKEN_EXPIRE_DAYS = 300  # 登录时直接申请 300 天 token

TG_BOT_TOKEN = ""
TG_CHAT_ID = ""

# 文件路径都集中到 /root/checkin/
BASE_DIR = "/root/checkin"
TOKEN_FILE = os.path.join(BASE_DIR, "token.json")
LOG_FILE = os.path.join(BASE_DIR, "dler_checkin.log")

TIMEOUT = 20


def log(msg: str):
    ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    line = f"[{ts}] {msg}"
    print(line)
    try:
        os.makedirs(BASE_DIR, exist_ok=True)
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(line + "\n")
    except Exception:
        pass


def save_token(token: str):
    os.makedirs(BASE_DIR, exist_ok=True)
    with open(TOKEN_FILE, "w", encoding="utf-8") as f:
        json.dump(
            {"access_token": token, "saved_at": datetime.utcnow().isoformat() + "Z"},
            f,
            ensure_ascii=False,
            indent=2,
        )
    log("token 已保存。")


def load_token():
    if not os.path.exists(TOKEN_FILE):
        return None
    try:
        with open(TOKEN_FILE, "r", encoding="utf-8") as f:
            return json.load(f).get("access_token")
    except Exception:
        return None


def telegram_notify(text: str):
    if not TG_BOT_TOKEN or not TG_CHAT_ID:
        return
    try:
        url = f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage"
        r = requests.post(
            url,
            timeout=TIMEOUT,
            data={"chat_id": TG_CHAT_ID, "text": text, "disable_web_page_preview": True},
        )
        if r.status_code != 200:
            log(f"Telegram 通知失败:HTTP {r.status_code} {r.text[:200]}")
    except Exception as e:
        log(f"Telegram 通知异常:{e}")


def api_login():
    url = f"{BASE}/login"
    payload = {"email": EMAIL, "passwd": PASSWORD, "token_expire": TOKEN_EXPIRE_DAYS}
    r = requests.post(url, json=payload, timeout=TIMEOUT)
    try:
        r.raise_for_status()
        data = r.json()
    except Exception as e:
        log(f"登录HTTP异常:{e}; 响应={r.text[:300]}")
        raise
    if not isinstance(data, dict) or data.get("ret") != 200:
        log(f"登录失败:{data}")
        raise RuntimeError("登录失败")
    token = data.get("data", {}).get("token")
    if not token:
        log(f"登录成功但未返回 token:{data}")
        raise RuntimeError("未返回token")
    save_token(token)
    return token


def api_checkin(token: str, multiple: Optional[int]):
    url = f"{BASE}/checkin"
    payload = {"access_token": token}
    if multiple is not None:
        payload["multiple"] = multiple
    r = requests.post(url, json=payload, timeout=TIMEOUT)
    try:
        r.raise_for_status()
        return r.json()
    except Exception as e:
        log(f"签到HTTP异常:{e}; 响应={r.text[:300]}")
        return {"ret": -1, "msg": f"HTTP异常:{e}", "raw": r.text}


def main():
    parser = argparse.ArgumentParser(description="Dler 签到脚本(不自动续期)")
    parser.add_argument("--login", action="store_true", help="仅登录获取token(300天)并保存")
    parser.add_argument("--checkin", action="store_true", help="执行签到(默认动作)")
    parser.add_argument("--multiple", type=int, help="签到倍率,可选,不传则为空")
    args = parser.parse_args()

    do_checkin = args.checkin or (not args.login)

    try:
        if args.login and not do_checkin:
            api_login()
            log("手动登录完成。")
            return

        # 签到
        token = load_token()
        if not token:
            log("未发现本地token,开始首次登录获取。")
            token = api_login()

        data = api_checkin(token, args.multiple)
        ret = data.get("ret")
        msg = data.get("msg", "")
        detail = data.get("data", data)
        log(f"签到结果:ret={ret}, msg={msg}, data={detail}")

        # ===== 通知触发逻辑 =====
        blob = json.dumps(detail, ensure_ascii=False)
        should_notify = False

        # ret==200 -> 视为成功
        if ret == 200:
            should_notify = True
        # 兜底关键词
        keywords = ["流量", "traffic", "增加", "MB", "GiB", "TiB"]
        if any(k in blob for k in keywords):
            should_notify = True

        if should_notify:
            parts = []
            if isinstance(detail, dict):
                for k in ["checkin", "today_used", "used", "unused", "traffic"]:
                    if k in detail:
                        parts.append(f"{k}: {detail[k]}")
            text = "签到通知\n" + ("\n".join(parts) if parts else blob)
            telegram_notify(text)

    except Exception as e:
        log(f"执行异常:{e}")


if __name__ == "__main__":
    main()

3.安装依赖与首次运行

sudo apt-get update
sudo apt-get install -y python3 python3-pip
pip3 install --user requests
chmod +x /path/to/dler_checkin.py

# 首次登录获取并保存 token(300 天)
/usr/bin/env python3 /root/checkin/dler_checkin.py --login
# 也可以直接执行签到
/usr/bin/env python3 /root/checkin/dler_checkin.py --checkin
# 也可以直接执行签到(倍率)
/usr/bin/env python3 /root/checkin/dler_checkin.py --checkin --multiple 100

4.定时任务

1.crontab

crontab -e
*/5 * * * * /usr/bin/python3 /root/checkin/dler_checkin.py --checkin --multiple 100 >> $HOME/dler_cron.out 2>&1

2.systemd

(1)服务单元 /etc/systemd/system/dler-checkin.service

[Unit]
Description=Dler Checkin

[Service]
Type=oneshot
User=%i
ExecStart=/usr/bin/python3 /path/to/dler_checkin.py --checkin --multiple 100

(2)定时器 /etc/systemd/system/dler-checkin.timer

[Unit]
Description=Run dler checkin every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=dler-checkin@%i.service

[Install]
WantedBy=timers.target

(3)启用(把 <username> 换成你的用户名):

sudo systemctl daemon-reload
sudo systemctl enable --now dler-checkin@<username>.timer

5.文件分布

脚本:/root/checkin/dler_checkin.py
日志:/root/checkin/dler_checkin.log
token:/root/checkin/token.json