mirror of
https://github.com/HChaZZY/NodeSeek-Signin.git
synced 2025-12-06 11:33:49 +08:00
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.git
|
||||||
|
.github
|
||||||
|
.venv
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.dockerignore
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
35
.env.example
Normal file
35
.env.example
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# 账户配置
|
||||||
|
USER1=your_username1
|
||||||
|
PASS1=your_password1
|
||||||
|
# USER2=your_username2
|
||||||
|
# PASS2=your_password2
|
||||||
|
|
||||||
|
# --- 验证码配置 (二选一) ---
|
||||||
|
|
||||||
|
# 方案A: 自建 CloudFreed 服务
|
||||||
|
SOLVER_TYPE=turnstile
|
||||||
|
API_BASE_URL=http://your_cloudflare_service_ip:3000
|
||||||
|
CLIENTT_KEY=your_cloudfreed_client_key
|
||||||
|
|
||||||
|
# 方案B: YesCaptcha 服务
|
||||||
|
# SOLVER_TYPE=yescaptcha
|
||||||
|
# # YesCaptcha 国内节点: https://cn.yescaptcha.com, 国际节点: https://api.yescaptcha.com
|
||||||
|
# API_BASE_URL=https://api.yescaptcha.com
|
||||||
|
# CLIENTT_KEY=your_yescaptcha_client_key
|
||||||
|
|
||||||
|
# 功能配置
|
||||||
|
# NS_RANDOM=true
|
||||||
|
|
||||||
|
# 每日运行时间配置
|
||||||
|
# 支持固定时间 (例如 '09:00') 或随机时间范围 (例如 '08:00-10:59')
|
||||||
|
# 如果不设置,默认为 '08:00-10:59'
|
||||||
|
# RUN_AT=09:00
|
||||||
|
RUN_AT=08:00-10:59
|
||||||
|
|
||||||
|
# 通知配置
|
||||||
|
# TG_BOT_TOKEN=
|
||||||
|
# TG_USER_ID=
|
||||||
|
# TG_THREAD_ID=
|
||||||
|
|
||||||
|
# 模拟Docker环境,用于本地测试
|
||||||
|
# IN_DOCKER=true
|
||||||
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Python virtual environment
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# Python cache
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Sensitive configuration
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Cookie data files
|
||||||
|
cookie/*
|
||||||
|
!cookie/.gitkeep
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# IDE/Editor configuration
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 使用轻量级的 Python 基础镜像
|
||||||
|
FROM python:3.9-alpine
|
||||||
|
|
||||||
|
# 设置时区为 GMT+8
|
||||||
|
RUN apk add --no-cache tzdata ca-certificates
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
|
|
||||||
|
# 设置工作目录
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制 requirements.txt 并安装依赖
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# 复制所有 .py 文件到工作目录
|
||||||
|
COPY *.py ./
|
||||||
|
|
||||||
|
# 设置默认启动命令
|
||||||
|
CMD ["python", "scheduler.py"]
|
||||||
101
README.md
101
README.md
@@ -11,13 +11,14 @@
|
|||||||
|
|
||||||
## 📝 项目介绍
|
## 📝 项目介绍
|
||||||
|
|
||||||
这是一个用于 NodeSeek 论坛自动签到的工具,支持通过 GitHub Actions 或青龙面板进行定时自动签到操作。签到模式默认为随机签到,帮助用户轻松获取论坛每日"鸡腿"奖励。
|
这是一个用于 NodeSeek 论坛自动签到的工具,支持通过 GitHub Actions、青龙面板或 Docker Compose 进行定时自动签到操作。签到模式默认为随机签到,帮助用户轻松获取论坛每日"鸡腿"奖励。
|
||||||
|
|
||||||
|
|
||||||
## ✨ 功能特点
|
## ✨ 功能特点
|
||||||
|
|
||||||
- 📅 支持 GitHub Actions 自动运行
|
- 📅 支持 GitHub Actions 自动运行
|
||||||
- 🦉 支持青龙面板定时任务
|
- 🦉 支持青龙面板定时任务
|
||||||
|
- 🐳 支持 Docker Compose 一键部署
|
||||||
- 🍪 支持 Cookie 或账号密码登录方式
|
- 🍪 支持 Cookie 或账号密码登录方式
|
||||||
- 👥 支持多账号批量签到
|
- 👥 支持多账号批量签到
|
||||||
- 🔐 支持多种验证码解决方案
|
- 🔐 支持多种验证码解决方案
|
||||||
@@ -55,7 +56,60 @@ ql repo https://github.com/yowiv/NodeSeek-Signin.git
|
|||||||
|
|
||||||
然后在环境变量中添加所需配置。
|
然后在环境变量中添加所需配置。
|
||||||
|
|
||||||
### 方式三:账号密码登录(自动获取新Cookie)
|
### 方式三:Docker Compose
|
||||||
|
|
||||||
|
这种部署方式可以实现本地自动化定时签到,并支持自动处理验证码。
|
||||||
|
|
||||||
|
**第一步:克隆项目**
|
||||||
|
|
||||||
|
首先,将整个项目克隆到你的服务器上:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yowiv/NodeSeek-Signin.git
|
||||||
|
cd NodeSeek-Signin
|
||||||
|
```
|
||||||
|
|
||||||
|
**第二步:配置环境变量**
|
||||||
|
|
||||||
|
将 `.env.example` 文件复制或重命名为 `.env`,然后编辑 `.env` 文件,填入你的配置信息。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
你需要根据注释提示,填写以下关键信息:
|
||||||
|
- **账户信息**: `USER1`, `PASS1`, `USER2`, `PASS2` 等。
|
||||||
|
- **验证码服务**: 如果使用账号密码登录,必须配置验证码服务。推荐使用 `yescaptcha`,并填入 `CLIENTT_KEY`。
|
||||||
|
- **定时任务**: `RUN_AT` 变量用于设置签到任务的执行时间。
|
||||||
|
- **固定时间**: 如 `10:30`,表示每天上午10点30分执行。
|
||||||
|
- **时间范围**: 如 `10:00-18:00`,表示在每天上午10点到下午6点之间随机选择一个时间点执行。
|
||||||
|
- **默认值**: 如果不设置,默认为 `09:00-21:00`。
|
||||||
|
|
||||||
|
**第三步:启动服务**
|
||||||
|
|
||||||
|
在存放 `docker-compose.yml` 和 `.env` 文件的目录下,执行以下命令在后台构建并启动服务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**第四步:查看日志**
|
||||||
|
|
||||||
|
你可以使用以下命令实时查看容器的日志,以确认服务是否正常运行和签到是否成功:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
**第五步:停止服务**
|
||||||
|
|
||||||
|
如果需要停止并移除服务容器,可以执行以下命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式四:账号密码登录(自动获取新Cookie)
|
||||||
|
|
||||||
当 Cookie 失效时,系统会尝试使用账号密码方式登录并获取新的 Cookie。登录需要通过验证码验证,支持以下两种验证码解决方案:
|
当 Cookie 失效时,系统会尝试使用账号密码方式登录并获取新的 Cookie。登录需要通过验证码验证,支持以下两种验证码解决方案:
|
||||||
|
|
||||||
@@ -171,6 +225,7 @@ PASS3=密码3
|
|||||||
| `USER1`、`USER2`... | 可选 | - | NodeSeek 论坛用户名,当 Cookie 失效时使用 |
|
| `USER1`、`USER2`... | 可选 | - | NodeSeek 论坛用户名,当 Cookie 失效时使用 |
|
||||||
| `PASS1`、`PASS2`... | 可选 | - | NodeSeek 论坛密码 |
|
| `PASS1`、`PASS2`... | 可选 | - | NodeSeek 论坛密码 |
|
||||||
| `NS_RANDOM` | 可选 | true | 是否随机签到(true/false) |
|
| `NS_RANDOM` | 可选 | true | 是否随机签到(true/false) |
|
||||||
|
| `RUN_AT` | 可选 | `09:00-21:00` | **仅Docker Compose可用**。设置定时任务执行时间,支持固定时间 `10:30` 或时间范围 `10:00-18:00` |
|
||||||
| `SOLVER_TYPE` | 可选 | turnstile | 验证码解决方案(turnstile/yescaptcha) |
|
| `SOLVER_TYPE` | 可选 | turnstile | 验证码解决方案(turnstile/yescaptcha) |
|
||||||
| `API_BASE_URL` | 条件必需 | - | CloudFreed 服务地址,当 SOLVER_TYPE=turnstile 时必填 |
|
| `API_BASE_URL` | 条件必需 | - | CloudFreed 服务地址,当 SOLVER_TYPE=turnstile 时必填 |
|
||||||
| `CLIENTT_KEY` | 必需 | - | 验证码服务客户端密钥 |
|
| `CLIENTT_KEY` | 必需 | - | 验证码服务客户端密钥 |
|
||||||
@@ -187,3 +242,45 @@ PASS3=密码3
|
|||||||
## ⚠️ 免责声明
|
## ⚠️ 免责声明
|
||||||
|
|
||||||
本项目仅供学习交流使用,请遵守 NodeSeek 论坛的相关规定和条款。
|
本项目仅供学习交流使用,请遵守 NodeSeek 论坛的相关规定和条款。
|
||||||
|
|
||||||
|
## 👨💻 本地开发与测试
|
||||||
|
|
||||||
|
为了方便在本地进行开发和调试,项目提供了一套零侵入的测试方案。你可以按照以下步骤在本地环境中运行签到脚本。
|
||||||
|
|
||||||
|
### 第一步:创建虚拟环境
|
||||||
|
|
||||||
|
首先,建议创建一个独立的 Python 虚拟环境,以避免依赖冲突。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m venv .venv
|
||||||
|
# Windows
|
||||||
|
.venv\Scripts\activate
|
||||||
|
# macOS / Linux
|
||||||
|
source .venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第二步:安装依赖
|
||||||
|
|
||||||
|
项目包含两份依赖文件:`requirements.txt` 用于生产环境,`requirements-dev.txt` 包含本地测试所需的额外库。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
pip install -r requirements-dev.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第三步:配置环境变量
|
||||||
|
|
||||||
|
将环境变量示例文件 `.env.example` 复制一份并重命名为 `.env`,然后根据你的需求填入测试配置,例如账号密码和验证码服务密钥。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env```
|
||||||
|
|
||||||
|
### 第四步:运行测试
|
||||||
|
|
||||||
|
配置完成后,执行以下命令即可运行一次性的签到测试。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python test_run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
该脚本会自动加载 `.env` 文件中的环境变量,并执行主签到程序,让你可以在本地快速验证签到逻辑是否正常工作。
|
||||||
|
|||||||
0
cookie/.gitkeep
Normal file
0
cookie/.gitkeep
Normal file
13
docker-compose.yml
Normal file
13
docker-compose.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
services:
|
||||||
|
nodeseek-signin:
|
||||||
|
build: .
|
||||||
|
image: nodeseek-signin:latest
|
||||||
|
container_name: nodeseek-signin
|
||||||
|
command: ["python", "scheduler.py"]
|
||||||
|
environment:
|
||||||
|
- IN_DOCKER=true
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- ./cookie:/app/cookie
|
||||||
|
restart: always
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import json
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
from curl_cffi import requests
|
from curl_cffi import requests
|
||||||
@@ -20,6 +19,10 @@ except ImportError:
|
|||||||
# ---------------- 环境检测函数 ----------------
|
# ---------------- 环境检测函数 ----------------
|
||||||
def detect_environment():
|
def detect_environment():
|
||||||
"""检测当前运行环境"""
|
"""检测当前运行环境"""
|
||||||
|
# 优先检测是否在 Docker 环境中
|
||||||
|
if os.environ.get("IN_DOCKER") == "true":
|
||||||
|
return "docker"
|
||||||
|
|
||||||
# 检测是否在青龙环境中
|
# 检测是否在青龙环境中
|
||||||
ql_path_markers = ['/ql/data/', '/ql/config/', '/ql/', '/.ql/']
|
ql_path_markers = ['/ql/data/', '/ql/config/', '/ql/', '/.ql/']
|
||||||
in_ql_env = False
|
in_ql_env = False
|
||||||
@@ -138,12 +141,31 @@ def save_cookie_to_ql(var_name: str, cookie: str):
|
|||||||
print(f"青龙面板环境变量操作异常: {str(e)}")
|
print(f"青龙面板环境变量操作异常: {str(e)}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# ---------------- Docker Cookie 文件保存 ----------------
|
||||||
|
COOKIE_FILE_PATH = "./cookie/NS_COOKIE.txt"
|
||||||
|
|
||||||
|
def save_cookie_to_file(cookie_str: str):
|
||||||
|
"""将Cookie保存到文件"""
|
||||||
|
try:
|
||||||
|
# 确保目录存在
|
||||||
|
os.makedirs(os.path.dirname(COOKIE_FILE_PATH), exist_ok=True)
|
||||||
|
with open(COOKIE_FILE_PATH, "w") as f:
|
||||||
|
f.write(cookie_str)
|
||||||
|
print(f"Cookie 已成功保存到文件: {COOKIE_FILE_PATH}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"保存Cookie到文件失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
# ---------------- 统一变量保存函数 ----------------
|
# ---------------- 统一变量保存函数 ----------------
|
||||||
def save_cookie(var_name: str, cookie: str):
|
def save_cookie(var_name: str, cookie: str):
|
||||||
"""根据当前环境保存Cookie到相应位置"""
|
"""根据当前环境保存Cookie到相应位置"""
|
||||||
env_type = detect_environment()
|
env_type = detect_environment()
|
||||||
|
|
||||||
if env_type == "qinglong":
|
if env_type == "docker":
|
||||||
|
print("检测到Docker环境,保存Cookie到文件...")
|
||||||
|
return save_cookie_to_file(cookie)
|
||||||
|
elif env_type == "qinglong":
|
||||||
print("检测到青龙环境,保存变量到青龙面板...")
|
print("检测到青龙环境,保存变量到青龙面板...")
|
||||||
return save_cookie_to_ql(var_name, cookie)
|
return save_cookie_to_ql(var_name, cookie)
|
||||||
elif env_type == "github":
|
elif env_type == "github":
|
||||||
@@ -393,7 +415,21 @@ if __name__ == "__main__":
|
|||||||
break
|
break
|
||||||
|
|
||||||
# 读取现有Cookie
|
# 读取现有Cookie
|
||||||
all_cookies = os.getenv("NS_COOKIE", "")
|
all_cookies = ""
|
||||||
|
if detect_environment() == "docker":
|
||||||
|
print(f"Docker环境,尝试从 {COOKIE_FILE_PATH} 读取Cookie...")
|
||||||
|
if os.path.exists(COOKIE_FILE_PATH):
|
||||||
|
try:
|
||||||
|
with open(COOKIE_FILE_PATH, "r") as f:
|
||||||
|
all_cookies = f.read().strip()
|
||||||
|
print("成功从文件加载Cookie。")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"从文件读取Cookie失败: {e}")
|
||||||
|
else:
|
||||||
|
print("Cookie文件不存在,将使用空Cookie。")
|
||||||
|
else:
|
||||||
|
all_cookies = os.getenv("NS_COOKIE", "")
|
||||||
|
|
||||||
cookie_list = all_cookies.split("&")
|
cookie_list = all_cookies.split("&")
|
||||||
cookie_list = [c.strip() for c in cookie_list if c.strip()]
|
cookie_list = [c.strip() for c in cookie_list if c.strip()]
|
||||||
|
|
||||||
|
|||||||
1
requirements-dev.txt
Normal file
1
requirements-dev.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python-dotenv
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
curl_cffi
|
||||||
|
requests
|
||||||
|
tzdata
|
||||||
125
scheduler.py
Normal file
125
scheduler.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
import random
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
from datetime import timezone, timedelta
|
||||||
|
|
||||||
|
# 测试程序时使用
|
||||||
|
# from dotenv import load_dotenv
|
||||||
|
# load_dotenv()
|
||||||
|
|
||||||
|
GMT8 = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
def get_run_config():
|
||||||
|
"""
|
||||||
|
从环境变量 RUN_AT 读取并解析运行时间配置。
|
||||||
|
- 'HH:MM': 固定时间
|
||||||
|
- 'HH:MM-HH:MM': 随机时间范围
|
||||||
|
- 未设置或格式错误: 默认为 '08:00-10:59'
|
||||||
|
返回一个元组 (mode, value)
|
||||||
|
"""
|
||||||
|
run_at_env = os.environ.get('RUN_AT', '08:00-10:59')
|
||||||
|
|
||||||
|
if re.fullmatch(r'\d{2}:\d{2}', run_at_env):
|
||||||
|
print(f"检测到固定时间模式: {run_at_env}", flush=True)
|
||||||
|
return 'fixed', run_at_env
|
||||||
|
|
||||||
|
if re.fullmatch(r'\d{2}:\d{2}-\d{2}:\d{2}', run_at_env):
|
||||||
|
print(f"检测到随机时间范围模式: {run_at_env}", flush=True)
|
||||||
|
return 'range', run_at_env
|
||||||
|
|
||||||
|
if os.environ.get('RUN_AT'):
|
||||||
|
print(f"警告: 环境变量 RUN_AT 的格式 '{run_at_env}' 无效。", flush=True)
|
||||||
|
|
||||||
|
print("将使用默认随机时间范围 '08:00-10:59'。", flush=True)
|
||||||
|
return 'range', '08:00-10:59'
|
||||||
|
|
||||||
|
def calculate_next_run_time(mode, value):
|
||||||
|
"""
|
||||||
|
根据当前时间和配置计算下一次运行的 datetime 对象。
|
||||||
|
智能寻找下一个可用的运行时间点(今天或明天),并使用 GMT+8 时区。
|
||||||
|
"""
|
||||||
|
now = datetime.datetime.now(GMT8)
|
||||||
|
|
||||||
|
if mode == 'fixed':
|
||||||
|
h, m = map(int, value.split(':'))
|
||||||
|
next_run_attempt = now.replace(hour=h, minute=m, second=0, microsecond=0)
|
||||||
|
if next_run_attempt > now:
|
||||||
|
return next_run_attempt
|
||||||
|
else:
|
||||||
|
return next_run_attempt + datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
elif mode == 'range':
|
||||||
|
start_str, end_str = value.split('-')
|
||||||
|
start_h, start_m = map(int, start_str.split(':'))
|
||||||
|
end_h, end_m = map(int, end_str.split(':'))
|
||||||
|
|
||||||
|
start_time = datetime.time(start_h, start_m)
|
||||||
|
end_time = datetime.time(end_h, end_m)
|
||||||
|
|
||||||
|
start_today = now.replace(hour=start_h, minute=start_m, second=0, microsecond=0)
|
||||||
|
|
||||||
|
if now < start_today:
|
||||||
|
target_date = now.date()
|
||||||
|
else:
|
||||||
|
target_date = now.date() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
start_target = datetime.datetime.combine(target_date, start_time, tzinfo=GMT8)
|
||||||
|
end_target = datetime.datetime.combine(target_date, end_time, tzinfo=GMT8)
|
||||||
|
|
||||||
|
if start_target > end_target:
|
||||||
|
end_target += datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
start_timestamp = int(start_target.timestamp())
|
||||||
|
end_timestamp = int(end_target.timestamp())
|
||||||
|
|
||||||
|
random_timestamp = random.randint(start_timestamp, end_timestamp)
|
||||||
|
return datetime.datetime.fromtimestamp(random_timestamp, tz=GMT8)
|
||||||
|
|
||||||
|
def run_checkin_task():
|
||||||
|
"""
|
||||||
|
执行 nodeseek_sign.py 脚本。
|
||||||
|
"""
|
||||||
|
print(f"[{datetime.datetime.now(GMT8).strftime('%Y-%m-%d %H:%M:%S')}] 开始执行签到任务...", flush=True)
|
||||||
|
try:
|
||||||
|
subprocess.run([sys.executable, "nodeseek_sign.py"], check=True)
|
||||||
|
print(f"[{datetime.datetime.now(GMT8).strftime('%Y-%m-%d %H:%M:%S')}] 签到任务执行完毕。", flush=True)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("错误: 'nodeseek_sign.py' 未找到。请确保它与 scheduler.py 位于同一目录。", flush=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"签到任务执行失败,返回码: {e.returncode}", flush=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"执行签到任务时发生未知错误: {e}", flush=True)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
主调度循环。
|
||||||
|
"""
|
||||||
|
print("调度器启动...", flush=True)
|
||||||
|
mode, value = get_run_config()
|
||||||
|
print(f"调度模式: '{mode}', 配置值: '{value}'", flush=True)
|
||||||
|
|
||||||
|
# run_checkin_task() # 启动时执行,用于测试程序
|
||||||
|
|
||||||
|
while True:
|
||||||
|
next_run_time = calculate_next_run_time(mode, value)
|
||||||
|
now = datetime.datetime.now(GMT8)
|
||||||
|
sleep_duration = (next_run_time - now).total_seconds()
|
||||||
|
|
||||||
|
if sleep_duration > 0:
|
||||||
|
print(f"下一次签到任务计划在: {next_run_time.strftime('%Y-%m-%d %H:%M:%S')}", flush=True)
|
||||||
|
hours, remainder = divmod(sleep_duration, 3600)
|
||||||
|
minutes, _ = divmod(remainder, 60)
|
||||||
|
print(f"程序将休眠 {int(hours)} 小时 {int(minutes)} 分钟。", flush=True)
|
||||||
|
time.sleep(sleep_duration)
|
||||||
|
else:
|
||||||
|
print("计算出的下一个运行时间已过,等待 60 秒后重试...", flush=True)
|
||||||
|
time.sleep(60)
|
||||||
|
|
||||||
|
run_checkin_task()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
14
test_run.py
Normal file
14
test_run.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
加载 .env 文件并执行签到脚本
|
||||||
|
"""
|
||||||
|
load_dotenv()
|
||||||
|
print(".env 文件已加载,正在准备执行签到脚本...")
|
||||||
|
subprocess.run([sys.executable, "nodeseek_sign.py"])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user