mirror of
https://github.com/halfwaystudent/douyin-sparkflow.git
synced 2026-09-04 23:17:51 +08:00
Improve one-click deployment workflow
This commit is contained in:
@@ -6,6 +6,11 @@ LOGIN_DESKTOP_WEB_PORT=8788
|
||||
PROXY_HTTP_PORT=7890
|
||||
PROXY_CONTROLLER_PORT=9090
|
||||
|
||||
# Used by deploy/install-server.sh when it creates state/cron/root for the first time.
|
||||
# Format: HH:00-HH:00/Nm. Example below runs every 20 minutes from 10:00 to 17:59,
|
||||
# runs one final regular send at 18:00, then an unsent fallback at 18:20.
|
||||
DEFAULT_SCHEDULE=10:00-18:00/20m
|
||||
|
||||
# Optional: paste a Mihomo/Clash subscription URL here, then run ./refresh_proxy.sh.
|
||||
PROXY_SUB_URL=
|
||||
PROXY_USER_AGENT=clash-verge/1.7.7
|
||||
|
||||
@@ -1,100 +1,102 @@
|
||||
# 🔥 douyin-sparkflow
|
||||
# Douyin SparkFlow
|
||||
|
||||
Douyin SparkFlow 提供一个面向个人自用场景的抖音火花维护工具。项目包含 Web 管理面板、登录桌面、定时任务和代理配置模板,默认通过 Docker Compose 部署。
|
||||
Douyin SparkFlow 是一个个人自用的抖音火花维护工具,包含 Web 管理后台、扫码登录桌面、定时发送任务和代理配置模板。项目默认使用 Docker Compose 部署。
|
||||
|
||||
## 🧭 上游项目
|
||||
本项目基于 [2061360308/DouYinSparkFlow](https://github.com/2061360308/DouYinSparkFlow) 二次开发,补充了 Web 管理、Docker 部署、登录桌面、发送可靠性和运行维护能力。
|
||||
|
||||
本项目基于 [2061360308/DouYinSparkFlow](https://github.com/2061360308/DouYinSparkFlow) 进行二次开发,主要补充 Web 管理、Docker Compose 部署和运行维护相关能力。
|
||||
## 功能
|
||||
|
||||
## ✨ 功能特性
|
||||
- Web 面板管理账号、目标好友、发送窗口和日志。
|
||||
- 浏览器扫码登录并保存登录状态。
|
||||
- 按每日时间窗口自动发送,也支持手动补发未成功或未发送目标。
|
||||
- 通过 Mihomo/Clash 代理配置访问网络。
|
||||
- 登录桌面、Web 后台、定时器、任务容器和代理容器统一编排。
|
||||
- 发送确认、好友列表扫描、账号级临时故障冷却等可靠性保护。
|
||||
|
||||
- 🖥️ Web 面板管理账号、目标好友和发送窗口。
|
||||
- 🔐 浏览器扫码登录并保存本地登录态。
|
||||
- ⏱️ 定时执行续火花任务,支持手动触发和日志查看。
|
||||
- 🌐 可选 Mihomo/Clash 代理订阅配置。
|
||||
- 🐳 Docker Compose 编排 Web、登录桌面、定时器、任务和代理服务。
|
||||
- 🌗 支持小太阳/小月亮切换白天模式和黑夜模式。
|
||||
|
||||
## 🖼️ 界面预览
|
||||
|
||||

|
||||
|
||||
> 📘 **截图教程:** 新版 Web 面板将概览、登录工作区、账号与目标、运行与系统拆成独立视图。按截图完成首次配置,请直接阅读 [Douyin SparkFlow 使用教程](docs/usage.md)。
|
||||
|
||||
## ⚠️ 免责声明
|
||||
## 免责声明
|
||||
|
||||
本项目仅用于个人学习、研究和自用场景,不是抖音、字节跳动或相关平台的官方工具,也未获得其授权、背书或关联。
|
||||
|
||||
使用本项目时,请遵守所在地法律法规、抖音平台规则和相关服务协议。请勿将本项目用于商业用途、批量营销、骚扰他人、刷量引流、规避平台风控,或任何可能损害平台、他人账号及第三方权益的行为。
|
||||
使用本项目时,请遵守所在地法律法规、平台规则和相关服务协议。请勿用于商业营销、批量骚扰、刷量引流、规避平台风控,或任何可能损害平台、他人账号及第三方权益的行为。
|
||||
|
||||
本项目会在使用者授权登录后,按照使用者配置的账号、好友和发送窗口执行自动化操作。由此产生的账号异常、限流、封禁、数据丢失、服务中断、消息误发、隐私泄露或其他损失,均由使用者自行承担。项目作者和贡献者不对使用本项目产生的任何直接或间接后果负责。
|
||||
请妥善保管 `.env`、登录状态、Cookie、代理配置、运行日志和账号数据,不要提交到公开仓库,也不要分享给不可信第三方。继续部署、运行或修改本项目,即表示你理解并接受以上说明。
|
||||
|
||||
请妥善保管 `.env`、登录态、Cookie、代理配置和运行日志等敏感信息,不要提交到公开仓库,也不要分享给不可信的第三方。如果平台规则、接口页面或风控策略发生变化,请立即停止使用并自行评估风险。
|
||||
## 服务器一键安装
|
||||
|
||||
继续部署、运行或修改本项目,即表示你已理解并接受以上说明;如果你不同意,请停止使用本项目。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
在服务器上推荐使用这条一键安装命令,适合 `raw.githubusercontent.com` 访问较慢或超时的环境:
|
||||
推荐在服务器上使用 Git clone 方式安装,适合 `raw.githubusercontent.com` 访问较慢的环境:
|
||||
|
||||
```bash
|
||||
apt update && apt install -y git curl gnupg ca-certificates && rm -rf /opt/douyin-sparkflow && git clone --depth=1 https://github.com/halfwaystudent/douyin-sparkflow.git /opt/douyin-sparkflow && cd /opt/douyin-sparkflow && bash deploy/install-server.sh
|
||||
```
|
||||
|
||||
如果 GitHub 克隆时出现 `GnuTLS recv error`,先切到 HTTP/1.1 后重试:
|
||||
|
||||
```bash
|
||||
git config --global http.version HTTP/1.1
|
||||
git config --global http.lowSpeedLimit 1000
|
||||
git config --global http.lowSpeedTime 60
|
||||
```
|
||||
|
||||
指定安装目录或代理订阅:
|
||||
|
||||
```bash
|
||||
APP_ROOT=/opt/douyin-sparkflow PROXY_SUB_URL='你的 Mihomo/Clash 订阅链接' bash -c 'apt update && apt install -y git curl gnupg ca-certificates && rm -rf "$APP_ROOT" && git clone --depth=1 https://github.com/halfwaystudent/douyin-sparkflow.git "$APP_ROOT" && cd "$APP_ROOT" && bash deploy/install-server.sh'
|
||||
```
|
||||
|
||||
如果你的服务器可以稳定访问 `raw.githubusercontent.com`,也可以使用精简版:
|
||||
如果服务器能稳定访问 raw GitHub,也可以使用:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/halfwaystudent/douyin-sparkflow/main/deploy/install-server.sh | bash
|
||||
```
|
||||
|
||||
部署完成后检查容器状态:
|
||||
常用环境变量:
|
||||
|
||||
```bash
|
||||
APP_ROOT=/opt/douyin-sparkflow
|
||||
BRANCH=main
|
||||
WEB_PORT=8787
|
||||
LOGIN_DESKTOP_WEB_PORT=8788
|
||||
PROXY_SUB_URL='你的 Mihomo/Clash 订阅链接'
|
||||
DEFAULT_SCHEDULE='10:00-18:00/20m'
|
||||
```
|
||||
|
||||
安装完成后检查容器:
|
||||
|
||||
```bash
|
||||
cd /opt/douyin-sparkflow
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
正常状态应包含:
|
||||
正常应看到:
|
||||
|
||||
- `douyin-web`:`Up`,Web 面板服务。
|
||||
- `login-desktop`:`Up`,扫码登录桌面。
|
||||
- `douyin-scheduler`:`Up`,定时发送和自动兜底。
|
||||
- `mihomo`:`Up`,代理服务。
|
||||
- `douyin-task`:`Exited` 或 `Stopped` 是正常的,它是一次性手动任务容器,不需要常驻。
|
||||
- `douyin-web`:Web 管理后台。
|
||||
- `login-desktop`:扫码登录桌面。
|
||||
- `douyin-scheduler`:读取 `state/cron/root` 的定时器。
|
||||
- `mihomo`:代理服务。
|
||||
- `douyin-task`:一次性任务容器,未常驻是正常的。
|
||||
|
||||
确认 `douyin-web` 已启动后访问:
|
||||
访问地址:
|
||||
|
||||
- Web 面板:`http://服务器IP:8787`
|
||||
- 登录桌面:Web 面板中的“登录桌面”入口,默认端口 `8788`
|
||||
|
||||
如果外网打不开 Web 面板,请在云服务器安全组、轻量云防火墙或 1Panel 防火墙中放行:
|
||||
如果外网打不开,请在云服务器安全组、系统防火墙或 1Panel 防火墙中放行:
|
||||
|
||||
- `8787/tcp`:Web 管理面板。
|
||||
- `8787/tcp`:Web 管理后台。
|
||||
- `8788/tcp`:扫码登录桌面。
|
||||
|
||||
首次使用:
|
||||
## 无损更新
|
||||
|
||||
1. 创建管理员账号。
|
||||
2. 打开登录工作区并扫码登录抖音。
|
||||
3. 保存登录态。
|
||||
4. 刷新好友列表并选择目标好友。
|
||||
5. 设置发送窗口,例如 `10:00-18:00/10m`。
|
||||
更新代码和容器,但保留运行数据:
|
||||
|
||||
## 💻 本地运行
|
||||
```bash
|
||||
cd /opt/douyin-sparkflow
|
||||
ACTION=update bash deploy/install-server.sh
|
||||
```
|
||||
|
||||
更新不会覆盖这些运行态文件:
|
||||
|
||||
- `.env`
|
||||
- `state/`
|
||||
- `proxy/config.yaml`
|
||||
- `DouYinSparkFlow/logs/`
|
||||
- `DouYinSparkFlow/usersData.json`
|
||||
- `DouYinSparkFlow/config.json`
|
||||
- `DouYinSparkFlow/webui_settings.json`
|
||||
|
||||
## 本地运行
|
||||
|
||||
Windows 需要先启动 Docker Desktop:
|
||||
|
||||
@@ -102,7 +104,7 @@ Windows 需要先启动 Docker Desktop:
|
||||
.\deploy\install-local.ps1
|
||||
```
|
||||
|
||||
如需配置代理订阅:
|
||||
带代理订阅:
|
||||
|
||||
```powershell
|
||||
.\deploy\install-local.ps1 -ProxySubUrl "你的 Mihomo/Clash 订阅链接"
|
||||
@@ -114,19 +116,33 @@ Linux/macOS:
|
||||
./deploy/install-local.sh
|
||||
```
|
||||
|
||||
本地脚本会创建 `.env`、运行态目录和默认代理配置,并执行 `docker compose up -d --build`。
|
||||
本地脚本会创建 `.env`、`state/cron/root`、`state/login-profile`、`proxy/config.yaml` 和 `DouYinSparkFlow/logs`,然后执行 `docker compose up -d --build`。
|
||||
|
||||
## ⚙️ 配置说明
|
||||
## 配置
|
||||
|
||||
`.env.example` 是部署模板。首次安装时会复制为 `.env`。常用配置:
|
||||
|
||||
```bash
|
||||
WEB_PORT=8787
|
||||
LOGIN_DESKTOP_WEB_PORT=8788
|
||||
PROXY_SUB_URL=
|
||||
DEFAULT_SCHEDULE=10:00-18:00/20m
|
||||
PLAYWRIGHT_BASE_IMAGE=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/mcr.microsoft.com/playwright/python:v1.56.0-jammy
|
||||
```
|
||||
|
||||
如果 `.env` 中的 `PROXY_SUB_URL` 为空,项目会使用 `proxy/config.example.yaml` 生成直连代理配置。
|
||||
|
||||
首次构建需要拉取 Playwright 基础镜像。默认 `.env.example` 使用国内同步源;如果同步源不可用,可以将 `.env` 中的 `PLAYWRIGHT_BASE_IMAGE` 改为:
|
||||
默认定时任务写入 `state/cron/root`:
|
||||
|
||||
```bash
|
||||
PLAYWRIGHT_BASE_IMAGE=mcr.microsoft.com/playwright/python:v1.56.0-jammy
|
||||
```cron
|
||||
*/20 10-17 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
0 18 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
20 18 * * * cd /app && env SPARKFLOW_MANUAL_RUN=1 SPARKFLOW_MANUAL_UNSENT_ONLY=1 PYTHONUNBUFFERED=1 python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
```
|
||||
|
||||
## 🧰 常用命令
|
||||
你也可以在 Web 面板里修改发送窗口,Web 会更新同一个 cron 文件。
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
@@ -134,26 +150,26 @@ docker compose logs -f web
|
||||
docker compose logs -f scheduler
|
||||
docker compose up -d --build
|
||||
docker compose down
|
||||
./refresh_proxy.sh
|
||||
```
|
||||
|
||||
刷新代理订阅:
|
||||
手动跑一次发送任务:
|
||||
|
||||
```bash
|
||||
./refresh_proxy.sh
|
||||
docker compose restart proxy
|
||||
docker compose run --rm task
|
||||
```
|
||||
|
||||
## 📁 项目结构
|
||||
## 项目结构
|
||||
|
||||
- `DouYinSparkFlow/`:核心应用、Web UI、登录桌面和发送任务。
|
||||
- `docker-compose.yml`:容器编排入口。
|
||||
- `deploy/`:服务器和本地部署脚本。
|
||||
- `proxy/config.example.yaml`:代理配置模板。
|
||||
- `proxy/config.example.yaml`:直连代理配置模板。
|
||||
- `.env.example`:部署环境变量模板。
|
||||
|
||||
## 🗃️ 运行时文件
|
||||
## 运行时文件
|
||||
|
||||
以下路径由应用在部署或运行时生成,通常不纳入版本控制。迁移或备份实例时,可根据实际需要处理这些文件:
|
||||
以下文件由部署或运行生成,通常不纳入版本控制:
|
||||
|
||||
- `.env`
|
||||
- `state/`
|
||||
@@ -161,17 +177,10 @@ docker compose restart proxy
|
||||
- `proxy/config.yaml`
|
||||
- `DouYinSparkFlow/logs/`
|
||||
- `DouYinSparkFlow/usersData.json`
|
||||
- `DouYinSparkFlow/config.json`
|
||||
- `DouYinSparkFlow/webui_settings.json`
|
||||
- `DouYinSparkFlow/.im_sdk_cache/`
|
||||
|
||||
## 📈 GitHub Star 趋势
|
||||
|
||||
[](https://star-history.com/#halfwaystudent/douyin-sparkflow&Date)
|
||||
|
||||
## 🤝 友情链接
|
||||
|
||||
- [Linux Do](https://linux.do/)
|
||||
|
||||
## 📄 许可
|
||||
## 许可
|
||||
|
||||
核心应用采用 MIT 协议,详见 [DouYinSparkFlow/LICENSE](DouYinSparkFlow/LICENSE)。
|
||||
|
||||
@@ -58,43 +58,6 @@ function Get-EnvValue {
|
||||
return $DefaultValue
|
||||
}
|
||||
|
||||
function Set-ProxyConfigLine {
|
||||
param(
|
||||
[string]$Path,
|
||||
[string]$Key,
|
||||
[string]$Value
|
||||
)
|
||||
$line = "${Key}: $Value"
|
||||
$content = Get-Content -Path $Path -ErrorAction SilentlyContinue
|
||||
$escapedKey = [regex]::Escape($Key)
|
||||
$found = $false
|
||||
$next = foreach ($item in $content) {
|
||||
if ($item -match "^${escapedKey}:") {
|
||||
$found = $true
|
||||
$line
|
||||
} else {
|
||||
$item
|
||||
}
|
||||
}
|
||||
if (-not $found) {
|
||||
$next = @($next) + $line
|
||||
}
|
||||
Set-Content -Path $Path -Value $next -Encoding utf8
|
||||
}
|
||||
|
||||
function Refresh-ProxyConfig {
|
||||
param([string]$Url)
|
||||
if (-not $Url) {
|
||||
return
|
||||
}
|
||||
$userAgent = Get-EnvValue -Path ".env" -Key "PROXY_USER_AGENT" -DefaultValue "clash-verge/1.7.7"
|
||||
Invoke-WebRequest -Uri $Url -Headers @{ "User-Agent" = $userAgent } -OutFile "proxy/config.yaml"
|
||||
Set-ProxyConfigLine -Path "proxy/config.yaml" -Key "mixed-port" -Value "7890"
|
||||
Set-ProxyConfigLine -Path "proxy/config.yaml" -Key "allow-lan" -Value "true"
|
||||
Set-ProxyConfigLine -Path "proxy/config.yaml" -Key "bind-address" -Value "'*'"
|
||||
Set-ProxyConfigLine -Path "proxy/config.yaml" -Key "external-controller" -Value "'0.0.0.0:9090'"
|
||||
}
|
||||
|
||||
Require-Command docker
|
||||
docker compose version | Out-Null
|
||||
|
||||
@@ -110,8 +73,15 @@ New-Item -ItemType Directory -Force -Path "proxy", "state/cron", "state/login-pr
|
||||
if (-not (Test-Path "proxy/config.yaml")) {
|
||||
Copy-Item "proxy/config.example.yaml" "proxy/config.yaml"
|
||||
}
|
||||
if (-not (Test-Path "state/cron/root") -or (Get-Item "state/cron/root").Length -eq 0) {
|
||||
@(
|
||||
"*/20 10-17 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1",
|
||||
"0 18 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1",
|
||||
"20 18 * * * cd /app && env SPARKFLOW_MANUAL_RUN=1 SPARKFLOW_MANUAL_UNSENT_ONLY=1 PYTHONUNBUFFERED=1 python main.py --doTask >> /app/logs/app.log 2>&1"
|
||||
) | Set-Content -Path "state/cron/root" -Encoding utf8
|
||||
}
|
||||
|
||||
Refresh-ProxyConfig -Url $ProxySubUrl
|
||||
bash ./refresh_proxy.sh
|
||||
|
||||
docker compose up -d --build
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@ mkdir -p proxy state/cron state/login-profile DouYinSparkFlow/logs
|
||||
if [ ! -f "proxy/config.yaml" ]; then
|
||||
cp "proxy/config.example.yaml" "proxy/config.yaml"
|
||||
fi
|
||||
if [ ! -s "state/cron/root" ]; then
|
||||
cat > "state/cron/root" <<'CRON'
|
||||
*/20 10-17 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
0 18 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
20 18 * * * cd /app && env SPARKFLOW_MANUAL_RUN=1 SPARKFLOW_MANUAL_UNSENT_ONLY=1 PYTHONUNBUFFERED=1 python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
CRON
|
||||
fi
|
||||
|
||||
bash ./refresh_proxy.sh
|
||||
docker compose up -d --build
|
||||
|
||||
+92
-25
@@ -4,6 +4,8 @@ set -euo pipefail
|
||||
REPO_URL="${REPO_URL:-https://github.com/halfwaystudent/douyin-sparkflow.git}"
|
||||
BRANCH="${BRANCH:-main}"
|
||||
APP_ROOT="${APP_ROOT:-/opt/douyin-sparkflow}"
|
||||
ACTION="${ACTION:-install}"
|
||||
DEFAULT_SCHEDULE="${DEFAULT_SCHEDULE:-10:00-18:00/20m}"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
SUDO="sudo"
|
||||
@@ -19,6 +21,10 @@ run_root() {
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '\n[install-server] %s\n' "$*"
|
||||
}
|
||||
|
||||
install_base_tools() {
|
||||
if command -v curl >/dev/null 2>&1 && command -v git >/dev/null 2>&1 && command -v gpg >/dev/null 2>&1; then
|
||||
return
|
||||
@@ -28,6 +34,9 @@ install_base_tools() {
|
||||
run_root apt-get install -y ca-certificates curl git gnupg
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
run_root yum install -y ca-certificates curl git
|
||||
else
|
||||
echo "Install curl, git, and ca-certificates first." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -50,6 +59,7 @@ ensure_docker() {
|
||||
if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
log "Installing Docker and Compose plugin"
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
install_docker_debian
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
@@ -64,11 +74,16 @@ ensure_docker() {
|
||||
prepare_repo() {
|
||||
run_root mkdir -p "$(dirname "$APP_ROOT")"
|
||||
if [ -d "$APP_ROOT/.git" ]; then
|
||||
run_root git -C "$APP_ROOT" reset --hard
|
||||
log "Updating existing repository at $APP_ROOT"
|
||||
run_root git -C "$APP_ROOT" fetch origin "$BRANCH"
|
||||
run_root git -C "$APP_ROOT" checkout -B "$BRANCH" "origin/$BRANCH"
|
||||
run_root git -C "$APP_ROOT" reset --hard "origin/$BRANCH"
|
||||
else
|
||||
if [ -e "$APP_ROOT" ] && [ "$ACTION" = "install" ]; then
|
||||
echo "$APP_ROOT exists but is not a git checkout. Move it aside or set ACTION=update after fixing it." >&2
|
||||
exit 1
|
||||
fi
|
||||
log "Cloning $REPO_URL#$BRANCH into $APP_ROOT"
|
||||
run_root git clone --branch "$BRANCH" "$REPO_URL" "$APP_ROOT"
|
||||
fi
|
||||
}
|
||||
@@ -77,69 +92,121 @@ set_env_value() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
local value="$3"
|
||||
if grep -q "^${key}=" "$file"; then
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp)"
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp)"
|
||||
if [ -f "$file" ]; then
|
||||
awk -v key="$key" -v value="$value" '
|
||||
BEGIN { replaced = 0 }
|
||||
$0 ~ "^" key "=" { print key "=" value; replaced = 1; next }
|
||||
{ print }
|
||||
END { if (!replaced) print key "=" value }
|
||||
' "$file" > "$tmp_file"
|
||||
run_root cp "$tmp_file" "$file"
|
||||
rm -f "$tmp_file"
|
||||
else
|
||||
printf '%s=%s\n' "$key" "$value" | run_root tee -a "$file" >/dev/null
|
||||
printf '%s=%s\n' "$key" "$value" > "$tmp_file"
|
||||
fi
|
||||
run_root cp "$tmp_file" "$file"
|
||||
rm -f "$tmp_file"
|
||||
}
|
||||
|
||||
read_env_value() {
|
||||
local file="$1"
|
||||
local key="$2"
|
||||
if [ ! -f "$file" ]; then
|
||||
return 0
|
||||
fi
|
||||
grep -E "^${key}=" "$file" | tail -n 1 | cut -d= -f2- || true
|
||||
}
|
||||
|
||||
write_default_cron() {
|
||||
local cron_file="$APP_ROOT/state/cron/root"
|
||||
if [ -s "$cron_file" ]; then
|
||||
return
|
||||
fi
|
||||
if [ "$DEFAULT_SCHEDULE" != "10:00-18:00/20m" ]; then
|
||||
echo "DEFAULT_SCHEDULE=$DEFAULT_SCHEDULE will be saved to .env. The initial cron file uses the built-in 10:00-18:00/20m schedule; adjust it from the Web UI after first login." >&2
|
||||
fi
|
||||
cat > /tmp/douyin-sparkflow-cron <<'CRON'
|
||||
*/20 10-17 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
0 18 * * * cd /app && python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
20 18 * * * cd /app && env SPARKFLOW_MANUAL_RUN=1 SPARKFLOW_MANUAL_UNSENT_ONLY=1 PYTHONUNBUFFERED=1 python main.py --doTask >> /app/logs/app.log 2>&1
|
||||
CRON
|
||||
run_root cp /tmp/douyin-sparkflow-cron "$cron_file"
|
||||
rm -f /tmp/douyin-sparkflow-cron
|
||||
}
|
||||
|
||||
prepare_runtime_files() {
|
||||
if [ ! -f "$APP_ROOT/.env" ]; then
|
||||
run_root cp "$APP_ROOT/.env.example" "$APP_ROOT/.env"
|
||||
local env_file="$APP_ROOT/.env"
|
||||
if [ ! -f "$env_file" ]; then
|
||||
run_root cp "$APP_ROOT/.env.example" "$env_file"
|
||||
fi
|
||||
set_env_value "$APP_ROOT/.env" "APP_ROOT" "$APP_ROOT"
|
||||
for key in TZ WEB_PORT LOGIN_DESKTOP_WEB_PORT PROXY_HTTP_PORT PROXY_CONTROLLER_PORT PROXY_SUB_URL PLAYWRIGHT_BASE_IMAGE HTTP_PROXY_BUILD HTTPS_PROXY_BUILD ALL_PROXY_BUILD; do
|
||||
|
||||
set_env_value "$env_file" "APP_ROOT" "$APP_ROOT"
|
||||
set_env_value "$env_file" "DEFAULT_SCHEDULE" "$DEFAULT_SCHEDULE"
|
||||
|
||||
for key in TZ WEB_PORT LOGIN_DESKTOP_WEB_PORT PROXY_HTTP_PORT PROXY_CONTROLLER_PORT PROXY_SUB_URL PROXY_USER_AGENT PLAYWRIGHT_BASE_IMAGE HTTP_PROXY_BUILD HTTPS_PROXY_BUILD ALL_PROXY_BUILD PIP_INDEX_URL PIP_TRUSTED_HOST; do
|
||||
if [ -n "${!key:-}" ]; then
|
||||
set_env_value "$APP_ROOT/.env" "$key" "${!key}"
|
||||
set_env_value "$env_file" "$key" "${!key}"
|
||||
fi
|
||||
done
|
||||
|
||||
local current_sub
|
||||
current_sub="$(grep '^PROXY_SUB_URL=' "$APP_ROOT/.env" | sed 's/^PROXY_SUB_URL=//' || true)"
|
||||
current_sub="$(read_env_value "$env_file" PROXY_SUB_URL)"
|
||||
if [ -z "$current_sub" ] && [ -t 0 ]; then
|
||||
printf 'Proxy subscription URL, optional and hidden: '
|
||||
printf 'Proxy subscription URL (optional, hidden; press Enter to skip): '
|
||||
read -r -s input_sub || true
|
||||
printf '\n'
|
||||
if [ -n "${input_sub:-}" ]; then
|
||||
set_env_value "$APP_ROOT/.env" "PROXY_SUB_URL" "$input_sub"
|
||||
set_env_value "$env_file" "PROXY_SUB_URL" "$input_sub"
|
||||
fi
|
||||
fi
|
||||
|
||||
run_root mkdir -p "$APP_ROOT/proxy" "$APP_ROOT/state/cron" "$APP_ROOT/state/login-profile" "$APP_ROOT/DouYinSparkFlow/logs"
|
||||
run_root mkdir -p \
|
||||
"$APP_ROOT/proxy" \
|
||||
"$APP_ROOT/state/cron" \
|
||||
"$APP_ROOT/state/login-profile" \
|
||||
"$APP_ROOT/DouYinSparkFlow/logs"
|
||||
|
||||
if [ ! -f "$APP_ROOT/proxy/config.yaml" ]; then
|
||||
run_root cp "$APP_ROOT/proxy/config.example.yaml" "$APP_ROOT/proxy/config.yaml"
|
||||
fi
|
||||
write_default_cron
|
||||
}
|
||||
|
||||
main() {
|
||||
install_base_tools
|
||||
ensure_docker
|
||||
prepare_repo
|
||||
prepare_runtime_files
|
||||
compose_up() {
|
||||
cd "$APP_ROOT"
|
||||
log "Refreshing proxy configuration"
|
||||
run_root bash "$APP_ROOT/refresh_proxy.sh"
|
||||
run_root env DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose up -d --build
|
||||
log "Building and starting containers"
|
||||
run_root env DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker compose up -d --build proxy web login-desktop scheduler
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local env_file="$APP_ROOT/.env"
|
||||
local web_port login_port host_ip
|
||||
web_port="$(grep '^WEB_PORT=' "$APP_ROOT/.env" | sed 's/^WEB_PORT=//')"
|
||||
login_port="$(grep '^LOGIN_DESKTOP_WEB_PORT=' "$APP_ROOT/.env" | sed 's/^LOGIN_DESKTOP_WEB_PORT=//')"
|
||||
web_port="$(read_env_value "$env_file" WEB_PORT)"
|
||||
login_port="$(read_env_value "$env_file" LOGIN_DESKTOP_WEB_PORT)"
|
||||
host_ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
host_ip="${host_ip:-127.0.0.1}"
|
||||
echo
|
||||
echo "Douyin SparkFlow is running."
|
||||
echo "Web UI: http://${host_ip}:${web_port:-8787}"
|
||||
echo "Login desktop: http://${host_ip}:${login_port:-8788}/vnc.html?autoconnect=1&resize=scale&view_only=0"
|
||||
echo "Next: create the admin password, open the login desktop, scan the QR code, select target friends, and set the send window."
|
||||
echo
|
||||
echo "Runtime files preserved outside git: .env, state/, proxy/config.yaml, DouYinSparkFlow/logs/, usersData.json, webui_settings.json."
|
||||
echo "Update later with: ACTION=update bash $APP_ROOT/deploy/install-server.sh"
|
||||
}
|
||||
|
||||
main() {
|
||||
case "$ACTION" in
|
||||
install|update) ;;
|
||||
*) echo "ACTION must be install or update" >&2; exit 1 ;;
|
||||
esac
|
||||
install_base_tools
|
||||
ensure_docker
|
||||
prepare_repo
|
||||
prepare_runtime_files
|
||||
compose_up
|
||||
print_summary
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -49,6 +49,7 @@ services:
|
||||
volumes:
|
||||
- ./DouYinSparkFlow:/app
|
||||
- ./DouYinSparkFlow/logs:/app/logs
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./state/cron:/host-spool-cron
|
||||
- .:/opt/douyin-sparkflow
|
||||
|
||||
|
||||
Reference in New Issue
Block a user