mirror of
https://github.com/halfwaystudent/douyin-sparkflow.git
synced 2026-09-06 16:07:22 +08:00
Add Docker Compose one-click deployment
This commit is contained in:
@@ -25,7 +25,8 @@ ENV PIP_TRUSTED_HOST=${PIP_TRUSTED_HOST}
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list \
|
||||
RUN set -eux; \
|
||||
sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list \
|
||||
&& sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list \
|
||||
&& ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \
|
||||
&& echo ${TZ} > /etc/timezone \
|
||||
@@ -39,13 +40,14 @@ RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list \
|
||||
websockify \
|
||||
x11vnc \
|
||||
xfonts-intl-chinese \
|
||||
&& curl -fsSL -x http://127.0.0.1:7890 https://download.docker.com/linux/static/stable/x86_64/docker-25.0.3.tgz -o docker.tgz \
|
||||
&& download() { url="$1"; output="$2"; proxy_url="${HTTPS_PROXY:-${https_proxy:-${HTTP_PROXY:-${http_proxy:-}}}}"; if [ -n "$proxy_url" ]; then curl -fsSL -x "$proxy_url" "$url" -o "$output"; else curl -fsSL "$url" -o "$output"; fi; } \
|
||||
&& download https://download.docker.com/linux/static/stable/x86_64/docker-25.0.3.tgz docker.tgz \
|
||||
&& tar xzvf docker.tgz \
|
||||
&& mv docker/docker /usr/bin/docker \
|
||||
&& chmod +x /usr/bin/docker \
|
||||
&& rm -rf docker docker.tgz \
|
||||
&& mkdir -p /usr/local/lib/docker/cli-plugins \
|
||||
&& curl -SL -x http://127.0.0.1:7890 https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-x86_64 -o /usr/local/lib/docker/cli-plugins/docker-compose \
|
||||
&& download https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-x86_64 /usr/local/lib/docker/cli-plugins/docker-compose \
|
||||
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-compose \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def expand_field(field, minimum, maximum, current):
|
||||
values = set()
|
||||
for part in str(field).split(","):
|
||||
part = part.strip()
|
||||
if not part:
|
||||
continue
|
||||
step = 1
|
||||
if "/" in part:
|
||||
part, raw_step = part.split("/", 1)
|
||||
step = max(1, int(raw_step))
|
||||
if part == "*":
|
||||
start, end = minimum, maximum
|
||||
elif "-" in part:
|
||||
raw_start, raw_end = part.split("-", 1)
|
||||
start, end = int(raw_start), int(raw_end)
|
||||
else:
|
||||
start = end = int(part)
|
||||
values.update(range(max(minimum, start), min(maximum, end) + 1, step))
|
||||
return current in values
|
||||
|
||||
|
||||
def cron_dow(now):
|
||||
return (now.weekday() + 1) % 7
|
||||
|
||||
|
||||
def field_matches(field, minimum, maximum, current, *, allow_sunday_alias=False):
|
||||
if allow_sunday_alias and current == 0:
|
||||
return expand_field(field, minimum, maximum, 0) or expand_field(field, minimum, maximum, 7)
|
||||
return expand_field(field, minimum, maximum, current)
|
||||
|
||||
|
||||
def line_should_run(line, now):
|
||||
parts = line.split(maxsplit=5)
|
||||
if len(parts) < 6:
|
||||
return False, ""
|
||||
minute, hour, day, month, weekday, command = parts
|
||||
try:
|
||||
matched = (
|
||||
field_matches(minute, 0, 59, now.minute)
|
||||
and field_matches(hour, 0, 23, now.hour)
|
||||
and field_matches(day, 1, 31, now.day)
|
||||
and field_matches(month, 1, 12, now.month)
|
||||
and field_matches(weekday, 0, 7, cron_dow(now), allow_sunday_alias=True)
|
||||
)
|
||||
except ValueError:
|
||||
return False, ""
|
||||
return matched, command
|
||||
|
||||
|
||||
def read_crontab(path):
|
||||
if not path.exists():
|
||||
return []
|
||||
lines = []
|
||||
for raw_line in path.read_text(encoding="utf-8", errors="replace").splitlines():
|
||||
line = raw_line.strip()
|
||||
if not line or line.startswith("#") or "=" in line.split(maxsplit=1)[0]:
|
||||
continue
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
|
||||
def run_loop(crontab_path):
|
||||
crontab_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
last_minute_key = None
|
||||
print(f"[cron_runner] watching {crontab_path}", flush=True)
|
||||
while True:
|
||||
now = datetime.now()
|
||||
minute_key = now.strftime("%Y-%m-%d %H:%M")
|
||||
if minute_key != last_minute_key:
|
||||
last_minute_key = minute_key
|
||||
for line in read_crontab(crontab_path):
|
||||
matched, command = line_should_run(line, now)
|
||||
if matched and command:
|
||||
print(f"[cron_runner] {now.isoformat(timespec='seconds')} run: {command}", flush=True)
|
||||
subprocess.Popen(["/bin/bash", "-lc", command])
|
||||
time.sleep(15)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
target = Path(sys.argv[1] if len(sys.argv) > 1 else "/host-spool-cron/root")
|
||||
run_loop(target)
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import traceback
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
@@ -132,13 +133,14 @@ def _target_sent_today(account, target_name):
|
||||
|
||||
def login_desktop_api_url():
|
||||
settings = get_app_settings(force_reload=True)
|
||||
return str(settings.get("login_desktop_api_url") or "http://127.0.0.1:18090").rstrip("/")
|
||||
return str(os.getenv("SPARKFLOW_LOGIN_DESKTOP_API_URL") or settings.get("login_desktop_api_url") or "http://127.0.0.1:18090").rstrip("/")
|
||||
|
||||
|
||||
def login_desktop_public_url(request: Request) -> str:
|
||||
host = request.url.hostname or "127.0.0.1"
|
||||
scheme = request.url.scheme or "http"
|
||||
return f"{scheme}://{host}:8788/vnc.html?autoconnect=1&resize=scale&view_only=0"
|
||||
port = str(os.getenv("LOGIN_DESKTOP_PUBLIC_PORT") or "8788").strip() or "8788"
|
||||
return f"{scheme}://{host}:{port}/vnc.html?autoconnect=1&resize=scale&view_only=0"
|
||||
|
||||
|
||||
def call_login_desktop(path: str, *, method: str = "GET", payload: dict | None = None, timeout: int = 20) -> dict:
|
||||
|
||||
Reference in New Issue
Block a user