Improve one-click deployment workflow

This commit is contained in:
Rixuan Shao
2026-06-20 02:13:28 +08:00
parent b5e61a14ea
commit fe6c4a5e7b
6 changed files with 198 additions and 139 deletions
+5
View File
@@ -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
+85 -76
View File
@@ -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、登录桌面、定时器、任务和代理服务。
- 🌗 支持小太阳/小月亮切换白天模式和黑夜模式。
## 🖼️ 界面预览
![Douyin SparkFlow 控制台界面预览](docs/images/ui-preview.png)
> 📘 **截图教程:** 新版 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 趋势
[![GitHub Star 趋势图](https://api.star-history.com/svg?repos=halfwaystudent/douyin-sparkflow&type=Date)](https://star-history.com/#halfwaystudent/douyin-sparkflow&Date)
## 🤝 友情链接
- [Linux Do](https://linux.do/)
## 📄 许可
## 许可
核心应用采用 MIT 协议,详见 [DouYinSparkFlow/LICENSE](DouYinSparkFlow/LICENSE)。
+8 -38
View File
@@ -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
+7
View File
@@ -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
View File
@@ -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 "$@"
+1
View File
@@ -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