mirror of
https://github.com/halfwaystudent/douyin-sparkflow.git
synced 2026-09-05 15:38:58 +08:00
Improve one-click deployment workflow
This commit is contained in:
+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 "$@"
|
||||
|
||||
Reference in New Issue
Block a user