aa
This commit is contained in:
102
app_web.py
102
app_web.py
@@ -32,6 +32,25 @@ os.environ.setdefault("TELEGRAM_WEB_UI", "1")
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
|
||||
|
||||
def web_url_prefix() -> str:
|
||||
"""反代子路径时设置 WEB_URL_PREFIX=/前缀(勿尾斜杠),与 nginx location 一致。"""
|
||||
return (os.getenv("WEB_URL_PREFIX") or "").strip().rstrip("/")
|
||||
|
||||
|
||||
def with_url_prefix(path: str) -> str:
|
||||
path = path if path.startswith("/") else f"/{path}"
|
||||
pre = web_url_prefix()
|
||||
return f"{pre}{path}" if pre else path
|
||||
|
||||
|
||||
def app_home_url(*, needauth: bool = False) -> str:
|
||||
pre = web_url_prefix()
|
||||
base = f"{pre}/" if pre else "/"
|
||||
if needauth:
|
||||
return f"{base}?needauth=1"
|
||||
return base
|
||||
|
||||
WEB_CONSOLE_AUTH_KEY = "web_console_authenticated"
|
||||
|
||||
|
||||
@@ -53,7 +72,7 @@ def is_console_authed(request: Request) -> bool:
|
||||
def redirect_if_console_unauthed(request: Request) -> Optional[RedirectResponse]:
|
||||
if is_console_authed(request):
|
||||
return None
|
||||
return RedirectResponse(url="/?needauth=1", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(needauth=True), status_code=303)
|
||||
|
||||
|
||||
def json_if_console_unauthed(request: Request) -> Optional[JSONResponse]:
|
||||
@@ -179,6 +198,7 @@ class WebScraperService:
|
||||
self.logs: deque[str] = deque(maxlen=1200)
|
||||
self.continuous_task: Optional[asyncio.Task] = None
|
||||
self.continuous_started_at: Optional[float] = None
|
||||
self.continuous_start_lock = asyncio.Lock()
|
||||
|
||||
def _append(self, text: str) -> None:
|
||||
ts = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
@@ -425,25 +445,26 @@ class WebScraperService:
|
||||
return await self.start_job(f"补抓媒体({len(channels)}个频道)", runner())
|
||||
|
||||
async def start_continuous(self) -> str:
|
||||
await self.ensure_ready()
|
||||
if self.is_continuous_running():
|
||||
return "持续抓取已在运行中"
|
||||
if not self.scraper.state.get("channels"):
|
||||
raise ValueError("当前没有监控频道,请先添加频道。")
|
||||
async with self.continuous_start_lock:
|
||||
await self.ensure_ready()
|
||||
if self.is_continuous_running():
|
||||
return "持续抓取已在运行中"
|
||||
if not self.scraper.state.get("channels"):
|
||||
raise ValueError("当前没有监控频道,请先添加频道。")
|
||||
|
||||
async def runner():
|
||||
try:
|
||||
await self._run_and_capture(self.scraper.continuous_scraping())
|
||||
except asyncio.CancelledError:
|
||||
self._append("持续抓取任务已取消。")
|
||||
raise
|
||||
except Exception as e:
|
||||
self._append(f"持续抓取异常:{e}")
|
||||
async def runner():
|
||||
try:
|
||||
await self._run_and_capture(self.scraper.continuous_scraping())
|
||||
except asyncio.CancelledError:
|
||||
self._append("持续抓取任务已取消。")
|
||||
raise
|
||||
except Exception as e:
|
||||
self._append(f"持续抓取异常:{e}")
|
||||
|
||||
self.continuous_started_at = time.time()
|
||||
self.continuous_task = asyncio.create_task(runner())
|
||||
self._append("已启动持续抓取(含心跳逻辑)。")
|
||||
return "持续抓取已启动"
|
||||
self.continuous_started_at = time.time()
|
||||
self.continuous_task = asyncio.create_task(runner())
|
||||
self._append("已启动持续抓取(含心跳逻辑)。")
|
||||
return "持续抓取已启动"
|
||||
|
||||
async def stop_continuous(self) -> str:
|
||||
if not self.is_continuous_running():
|
||||
@@ -678,7 +699,7 @@ async def auth_console_login(request: Request):
|
||||
@app.post("/auth/console/logout")
|
||||
async def auth_console_logout(request: Request):
|
||||
request.session.pop(WEB_CONSOLE_AUTH_KEY, None)
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.get("/api/stats/overview")
|
||||
@@ -727,6 +748,9 @@ async def index(request: Request):
|
||||
"account_channels": account_channels,
|
||||
"console_authed": authed,
|
||||
"need_auth_banner": request.query_params.get("needauth") == "1",
|
||||
"app_url": with_url_prefix,
|
||||
"url_prefix": web_url_prefix(),
|
||||
"app_home": app_home_url(),
|
||||
"connected": service.is_connected(),
|
||||
"job_running": service.is_job_running(),
|
||||
"job_name": service.job_name,
|
||||
@@ -773,7 +797,7 @@ async def save_config(request: Request):
|
||||
else:
|
||||
updates[k] = str(form.get(k, "")).strip()
|
||||
write_env_updates(updates)
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/start")
|
||||
@@ -785,7 +809,7 @@ async def start_scraper(request: Request):
|
||||
await service.ensure_ready()
|
||||
except Exception as e:
|
||||
service._append(f"初始化失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/stop")
|
||||
@@ -794,7 +818,7 @@ async def stop_scraper(request: Request):
|
||||
if redir:
|
||||
return redir
|
||||
await service.disconnect()
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/channels/add")
|
||||
@@ -807,7 +831,7 @@ async def add_channel(request: Request, channel_spec: str = Form(...)):
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"添加频道失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/channels/add-selected")
|
||||
@@ -820,14 +844,14 @@ async def add_channels_selected(request: Request):
|
||||
ids = [str(x).strip() for x in raw_ids if str(x).strip()]
|
||||
if not ids:
|
||||
service._append("未选择任何频道,请在列表中勾选后再提交。")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
for spec in ids:
|
||||
try:
|
||||
msg = await service.add_channel(spec)
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"添加失败({spec}):{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/channels/remove")
|
||||
@@ -840,7 +864,7 @@ async def remove_channel(request: Request, channel_spec: str = Form(...)):
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"移除频道失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/jobs/scrape")
|
||||
@@ -853,7 +877,7 @@ async def start_scrape(request: Request, selection: str = Form("all")):
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"启动抓取失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/jobs/export")
|
||||
@@ -866,7 +890,7 @@ async def start_export(request: Request, selection: str = Form("all")):
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"启动导出失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/jobs/rescrape")
|
||||
@@ -879,20 +903,24 @@ async def start_rescrape(request: Request, selection: str = Form("all")):
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"启动补抓失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/jobs/continuous/start")
|
||||
async def start_continuous(request: Request):
|
||||
async def start_continuous_route(request: Request):
|
||||
redir = redirect_if_console_unauthed(request)
|
||||
if redir:
|
||||
return redir
|
||||
try:
|
||||
msg = await service.start_continuous()
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"启动持续抓取失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
|
||||
async def _run_start_continuous() -> None:
|
||||
try:
|
||||
await service.start_continuous()
|
||||
except Exception as e:
|
||||
service._append(f"启动持续抓取失败:{e}")
|
||||
|
||||
asyncio.create_task(_run_start_continuous())
|
||||
service._append("已接收「启动持续抓取」:正在后台连接 Telegram 并启动(请勿重复点击;进度见运行日志)。")
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.post("/jobs/continuous/stop")
|
||||
@@ -905,7 +933,7 @@ async def stop_continuous(request: Request):
|
||||
service._append(msg)
|
||||
except Exception as e:
|
||||
service._append(f"停止持续抓取失败:{e}")
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||
|
||||
|
||||
@app.get("/status")
|
||||
|
||||
Reference in New Issue
Block a user