aa
This commit is contained in:
62
app_web.py
62
app_web.py
@@ -32,6 +32,25 @@ os.environ.setdefault("TELEGRAM_WEB_UI", "1")
|
|||||||
|
|
||||||
logger = logging.getLogger("uvicorn.error")
|
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"
|
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]:
|
def redirect_if_console_unauthed(request: Request) -> Optional[RedirectResponse]:
|
||||||
if is_console_authed(request):
|
if is_console_authed(request):
|
||||||
return None
|
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]:
|
def json_if_console_unauthed(request: Request) -> Optional[JSONResponse]:
|
||||||
@@ -179,6 +198,7 @@ class WebScraperService:
|
|||||||
self.logs: deque[str] = deque(maxlen=1200)
|
self.logs: deque[str] = deque(maxlen=1200)
|
||||||
self.continuous_task: Optional[asyncio.Task] = None
|
self.continuous_task: Optional[asyncio.Task] = None
|
||||||
self.continuous_started_at: Optional[float] = None
|
self.continuous_started_at: Optional[float] = None
|
||||||
|
self.continuous_start_lock = asyncio.Lock()
|
||||||
|
|
||||||
def _append(self, text: str) -> None:
|
def _append(self, text: str) -> None:
|
||||||
ts = time.strftime("%Y-%m-%d %H:%M:%S")
|
ts = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
@@ -425,6 +445,7 @@ class WebScraperService:
|
|||||||
return await self.start_job(f"补抓媒体({len(channels)}个频道)", runner())
|
return await self.start_job(f"补抓媒体({len(channels)}个频道)", runner())
|
||||||
|
|
||||||
async def start_continuous(self) -> str:
|
async def start_continuous(self) -> str:
|
||||||
|
async with self.continuous_start_lock:
|
||||||
await self.ensure_ready()
|
await self.ensure_ready()
|
||||||
if self.is_continuous_running():
|
if self.is_continuous_running():
|
||||||
return "持续抓取已在运行中"
|
return "持续抓取已在运行中"
|
||||||
@@ -678,7 +699,7 @@ async def auth_console_login(request: Request):
|
|||||||
@app.post("/auth/console/logout")
|
@app.post("/auth/console/logout")
|
||||||
async def auth_console_logout(request: Request):
|
async def auth_console_logout(request: Request):
|
||||||
request.session.pop(WEB_CONSOLE_AUTH_KEY, None)
|
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")
|
@app.get("/api/stats/overview")
|
||||||
@@ -727,6 +748,9 @@ async def index(request: Request):
|
|||||||
"account_channels": account_channels,
|
"account_channels": account_channels,
|
||||||
"console_authed": authed,
|
"console_authed": authed,
|
||||||
"need_auth_banner": request.query_params.get("needauth") == "1",
|
"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(),
|
"connected": service.is_connected(),
|
||||||
"job_running": service.is_job_running(),
|
"job_running": service.is_job_running(),
|
||||||
"job_name": service.job_name,
|
"job_name": service.job_name,
|
||||||
@@ -773,7 +797,7 @@ async def save_config(request: Request):
|
|||||||
else:
|
else:
|
||||||
updates[k] = str(form.get(k, "")).strip()
|
updates[k] = str(form.get(k, "")).strip()
|
||||||
write_env_updates(updates)
|
write_env_updates(updates)
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/start")
|
@app.post("/start")
|
||||||
@@ -785,7 +809,7 @@ async def start_scraper(request: Request):
|
|||||||
await service.ensure_ready()
|
await service.ensure_ready()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"初始化失败:{e}")
|
service._append(f"初始化失败:{e}")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/stop")
|
@app.post("/stop")
|
||||||
@@ -794,7 +818,7 @@ async def stop_scraper(request: Request):
|
|||||||
if redir:
|
if redir:
|
||||||
return redir
|
return redir
|
||||||
await service.disconnect()
|
await service.disconnect()
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/channels/add")
|
@app.post("/channels/add")
|
||||||
@@ -807,7 +831,7 @@ async def add_channel(request: Request, channel_spec: str = Form(...)):
|
|||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"添加频道失败:{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")
|
@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()]
|
ids = [str(x).strip() for x in raw_ids if str(x).strip()]
|
||||||
if not ids:
|
if not ids:
|
||||||
service._append("未选择任何频道,请在列表中勾选后再提交。")
|
service._append("未选择任何频道,请在列表中勾选后再提交。")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
for spec in ids:
|
for spec in ids:
|
||||||
try:
|
try:
|
||||||
msg = await service.add_channel(spec)
|
msg = await service.add_channel(spec)
|
||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"添加失败({spec}):{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")
|
@app.post("/channels/remove")
|
||||||
@@ -840,7 +864,7 @@ async def remove_channel(request: Request, channel_spec: str = Form(...)):
|
|||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"移除频道失败:{e}")
|
service._append(f"移除频道失败:{e}")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/jobs/scrape")
|
@app.post("/jobs/scrape")
|
||||||
@@ -853,7 +877,7 @@ async def start_scrape(request: Request, selection: str = Form("all")):
|
|||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"启动抓取失败:{e}")
|
service._append(f"启动抓取失败:{e}")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/jobs/export")
|
@app.post("/jobs/export")
|
||||||
@@ -866,7 +890,7 @@ async def start_export(request: Request, selection: str = Form("all")):
|
|||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"启动导出失败:{e}")
|
service._append(f"启动导出失败:{e}")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/jobs/rescrape")
|
@app.post("/jobs/rescrape")
|
||||||
@@ -879,20 +903,24 @@ async def start_rescrape(request: Request, selection: str = Form("all")):
|
|||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"启动补抓失败:{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")
|
@app.post("/jobs/continuous/start")
|
||||||
async def start_continuous(request: Request):
|
async def start_continuous_route(request: Request):
|
||||||
redir = redirect_if_console_unauthed(request)
|
redir = redirect_if_console_unauthed(request)
|
||||||
if redir:
|
if redir:
|
||||||
return redir
|
return redir
|
||||||
|
|
||||||
|
async def _run_start_continuous() -> None:
|
||||||
try:
|
try:
|
||||||
msg = await service.start_continuous()
|
await service.start_continuous()
|
||||||
service._append(msg)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"启动持续抓取失败:{e}")
|
service._append(f"启动持续抓取失败:{e}")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
|
||||||
|
asyncio.create_task(_run_start_continuous())
|
||||||
|
service._append("已接收「启动持续抓取」:正在后台连接 Telegram 并启动(请勿重复点击;进度见运行日志)。")
|
||||||
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/jobs/continuous/stop")
|
@app.post("/jobs/continuous/stop")
|
||||||
@@ -905,7 +933,7 @@ async def stop_continuous(request: Request):
|
|||||||
service._append(msg)
|
service._append(msg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
service._append(f"停止持续抓取失败:{e}")
|
service._append(f"停止持续抓取失败:{e}")
|
||||||
return RedirectResponse(url="/", status_code=303)
|
return RedirectResponse(url=app_home_url(), status_code=303)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/status")
|
@app.get("/status")
|
||||||
|
|||||||
@@ -764,7 +764,7 @@
|
|||||||
<button type="button" class="btn-ghost" data-open="config">环境配置</button>
|
<button type="button" class="btn-ghost" data-open="config">环境配置</button>
|
||||||
<button type="button" class="btn-ghost" data-open="logs">运行日志</button>
|
<button type="button" class="btn-ghost" data-open="logs">运行日志</button>
|
||||||
{% if console_authed %}
|
{% if console_authed %}
|
||||||
<form method="post" action="/auth/console/logout" style="margin:0;">
|
<form method="post" action="{{ app_url('/auth/console/logout') }}" style="margin:0;">
|
||||||
<button type="submit" class="btn-ghost">退出验证</button>
|
<button type="submit" class="btn-ghost">退出验证</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -859,16 +859,16 @@
|
|||||||
<p class="alert-warn" role="alert">客户端:{{ error }}</p>
|
<p class="alert-warn" role="alert">客户端:{{ error }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="btn-row">
|
<div class="btn-row">
|
||||||
<form method="post" action="/start">
|
<form method="post" action="{{ app_url('/start') }}">
|
||||||
<button class="btn-primary" type="submit">初始化 / 连接 Telegram</button>
|
<button class="btn-primary" type="submit">初始化 / 连接 Telegram</button>
|
||||||
</form>
|
</form>
|
||||||
<form method="post" action="/stop">
|
<form method="post" action="{{ app_url('/stop') }}">
|
||||||
<button class="btn-danger" type="submit">断开 Telegram</button>
|
<button class="btn-danger" type="submit">断开 Telegram</button>
|
||||||
</form>
|
</form>
|
||||||
<form method="post" action="/jobs/continuous/start">
|
<form method="post" action="{{ app_url('/jobs/continuous/start') }}">
|
||||||
<button class="btn-primary" type="submit">启动持续抓取(含心跳)</button>
|
<button class="btn-primary" type="submit">启动持续抓取(含心跳)</button>
|
||||||
</form>
|
</form>
|
||||||
<form method="post" action="/jobs/continuous/stop">
|
<form method="post" action="{{ app_url('/jobs/continuous/stop') }}">
|
||||||
<button class="btn-danger" type="submit">停止持续抓取</button>
|
<button class="btn-danger" type="submit">停止持续抓取</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -892,14 +892,14 @@
|
|||||||
<strong>添加</strong>:<code>@用户名</code>、<code>-100…</code>、<code>https://t.me/xxx</code>。
|
<strong>添加</strong>:<code>@用户名</code>、<code>-100…</code>、<code>https://t.me/xxx</code>。
|
||||||
不支持仅靠群内显示标题。
|
不支持仅靠群内显示标题。
|
||||||
</p>
|
</p>
|
||||||
<form method="post" action="/channels/add" class="form-inline">
|
<form method="post" action="{{ app_url('/channels/add') }}" class="form-inline">
|
||||||
<input type="text" name="channel_spec" placeholder="@channel 或 -100… 或 https://t.me/…" aria-label="要添加的频道" />
|
<input type="text" name="channel_spec" placeholder="@channel 或 -100… 或 https://t.me/…" aria-label="要添加的频道" />
|
||||||
<button class="btn-primary" type="submit">添加</button>
|
<button class="btn-primary" type="submit">添加</button>
|
||||||
</form>
|
</form>
|
||||||
<p class="hint">
|
<p class="hint">
|
||||||
<strong>移除</strong>:<code>all</code>;<code>1,2</code>;<code>-100…</code>;<code>@用户名</code> / t.me(须已在监控中)。
|
<strong>移除</strong>:<code>all</code>;<code>1,2</code>;<code>-100…</code>;<code>@用户名</code> / t.me(须已在监控中)。
|
||||||
</p>
|
</p>
|
||||||
<form method="post" action="/channels/remove" class="form-inline">
|
<form method="post" action="{{ app_url('/channels/remove') }}" class="form-inline">
|
||||||
<input type="text" name="channel_spec" placeholder="all 或 1,2 或 -100… 或 @name" aria-label="要移除的频道" />
|
<input type="text" name="channel_spec" placeholder="all 或 1,2 或 -100… 或 @name" aria-label="要移除的频道" />
|
||||||
<button class="btn-danger" type="submit">移除</button>
|
<button class="btn-danger" type="submit">移除</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -907,15 +907,15 @@
|
|||||||
<div class="ops-block">
|
<div class="ops-block">
|
||||||
<h4>任务(抓取 / 导出 / 补媒体)</h4>
|
<h4>任务(抓取 / 导出 / 补媒体)</h4>
|
||||||
<p class="hint">范围:<code>all</code>、<code>1,3</code>、<code>-100…</code> 或已在监控的 <code>@</code> / 链接。</p>
|
<p class="hint">范围:<code>all</code>、<code>1,3</code>、<code>-100…</code> 或已在监控的 <code>@</code> / 链接。</p>
|
||||||
<form method="post" action="/jobs/scrape" class="form-inline">
|
<form method="post" action="{{ app_url('/jobs/scrape') }}" class="form-inline">
|
||||||
<input type="text" name="selection" value="all" aria-label="抓取范围" />
|
<input type="text" name="selection" value="all" aria-label="抓取范围" />
|
||||||
<button class="btn-primary" type="submit">开始抓取</button>
|
<button class="btn-primary" type="submit">开始抓取</button>
|
||||||
</form>
|
</form>
|
||||||
<form method="post" action="/jobs/export" class="form-inline">
|
<form method="post" action="{{ app_url('/jobs/export') }}" class="form-inline">
|
||||||
<input type="text" name="selection" value="all" aria-label="导出范围" />
|
<input type="text" name="selection" value="all" aria-label="导出范围" />
|
||||||
<button class="btn-primary" type="submit">导出 CSV+JSON</button>
|
<button class="btn-primary" type="submit">导出 CSV+JSON</button>
|
||||||
</form>
|
</form>
|
||||||
<form method="post" action="/jobs/rescrape" class="form-inline">
|
<form method="post" action="{{ app_url('/jobs/rescrape') }}" class="form-inline">
|
||||||
<input type="text" name="selection" value="all" aria-label="补抓范围" />
|
<input type="text" name="selection" value="all" aria-label="补抓范围" />
|
||||||
<button class="btn-primary" type="submit">补抓媒体</button>
|
<button class="btn-primary" type="submit">补抓媒体</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -946,7 +946,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="hint">账号可见频道:勾选后加入监控。标题包含配置项「账号列表隐藏」中任一子串的会话不会出现在此列表(默认隐藏含「远程-到岗-技术招聘」的群,避免选到自有招聘群)。</p>
|
<p class="hint">账号可见频道:勾选后加入监控。标题包含配置项「账号列表隐藏」中任一子串的会话不会出现在此列表(默认隐藏含「远程-到岗-技术招聘」的群,避免选到自有招聘群)。</p>
|
||||||
{% if account_channels %}
|
{% if account_channels %}
|
||||||
<form method="post" action="/channels/add-selected" class="account-pick-form">
|
<form method="post" action="{{ app_url('/channels/add-selected') }}" class="account-pick-form">
|
||||||
<div class="account-pick-toolbar">
|
<div class="account-pick-toolbar">
|
||||||
<button type="button" class="text-btn" id="account-select-all">全选可选项</button>
|
<button type="button" class="text-btn" id="account-select-all">全选可选项</button>
|
||||||
<button type="button" class="text-btn" id="account-select-none">全不选</button>
|
<button type="button" class="text-btn" id="account-select-none">全不选</button>
|
||||||
@@ -988,7 +988,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p class="hint">保存后建议断开并重新连接 Telegram。</p>
|
<p class="hint">保存后建议断开并重新连接 Telegram。</p>
|
||||||
<form method="post" action="/config" class="config-form">
|
<form method="post" action="{{ app_url('/config') }}" class="config-form">
|
||||||
{% for f in fields %}
|
{% for f in fields %}
|
||||||
{% if f.key in binary_env_keys %}
|
{% if f.key in binary_env_keys %}
|
||||||
<div class="field-row field-row-toggle">
|
<div class="field-row field-row-toggle">
|
||||||
@@ -1037,6 +1037,21 @@
|
|||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
window.__URL_PREFIX__ = {{ url_prefix|tojson }};
|
||||||
|
function appPath(p) {
|
||||||
|
p = p.startsWith("/") ? p : ("/" + p);
|
||||||
|
var pre = window.__URL_PREFIX__ || "";
|
||||||
|
return pre ? (pre + p) : p;
|
||||||
|
}
|
||||||
|
function appHomeWithQuery(tail) {
|
||||||
|
var pre = window.__URL_PREFIX__ || "";
|
||||||
|
var base = pre ? (pre + "/") : "/";
|
||||||
|
base = base.replace(/\/*$/, "/");
|
||||||
|
if (!tail) return base;
|
||||||
|
if (tail.charAt(0) !== "?") tail = "?" + tail;
|
||||||
|
return base + tail;
|
||||||
|
}
|
||||||
|
|
||||||
function formatInt(n) {
|
function formatInt(n) {
|
||||||
if (n == null || isNaN(n)) return "—";
|
if (n == null || isNaN(n)) return "—";
|
||||||
return Number(n).toLocaleString("zh-CN");
|
return Number(n).toLocaleString("zh-CN");
|
||||||
@@ -1049,7 +1064,7 @@
|
|||||||
|
|
||||||
async function consoleAuthStatus() {
|
async function consoleAuthStatus() {
|
||||||
try {
|
try {
|
||||||
var r = await fetch("/auth/console/status", { credentials: "same-origin" });
|
var r = await fetch(appPath("/auth/console/status"), { credentials: "same-origin" });
|
||||||
if (!r.ok) return false;
|
if (!r.ok) return false;
|
||||||
var j = await r.json();
|
var j = await r.json();
|
||||||
return j.ok === true;
|
return j.ok === true;
|
||||||
@@ -1086,7 +1101,7 @@
|
|||||||
}
|
}
|
||||||
var pw = authPwd ? authPwd.value : "";
|
var pw = authPwd ? authPwd.value : "";
|
||||||
try {
|
try {
|
||||||
var res = await fetch("/auth/console/login", {
|
var res = await fetch(appPath("/auth/console/login"), {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
@@ -1102,7 +1117,7 @@
|
|||||||
pendingOpenDlgId = null;
|
pendingOpenDlgId = null;
|
||||||
}
|
}
|
||||||
if (authPwd) authPwd.value = "";
|
if (authPwd) authPwd.value = "";
|
||||||
window.location.href = "/" + tail;
|
window.location.href = appHomeWithQuery(tail);
|
||||||
} else {
|
} else {
|
||||||
if (authErr) {
|
if (authErr) {
|
||||||
authErr.textContent = (data && data.error) ? data.error : "验证失败";
|
authErr.textContent = (data && data.error) ? data.error : "验证失败";
|
||||||
@@ -1266,7 +1281,7 @@
|
|||||||
var qs = new URLSearchParams({ days: String(days) });
|
var qs = new URLSearchParams({ days: String(days) });
|
||||||
if (kw) qs.set("keywords", kw);
|
if (kw) qs.set("keywords", kw);
|
||||||
try {
|
try {
|
||||||
var res = await fetch("/api/stats/overview?" + qs.toString());
|
var res = await fetch(appPath("/api/stats/overview") + "?" + qs.toString());
|
||||||
if (!res.ok) throw new Error("HTTP " + res.status);
|
if (!res.ok) throw new Error("HTTP " + res.status);
|
||||||
var data = await res.json();
|
var data = await res.json();
|
||||||
applyStats(data);
|
applyStats(data);
|
||||||
@@ -1307,7 +1322,7 @@
|
|||||||
|
|
||||||
async function refreshStatus() {
|
async function refreshStatus() {
|
||||||
try {
|
try {
|
||||||
var statusResp = await fetch("/api/jobs/status", { credentials: "same-origin" });
|
var statusResp = await fetch(appPath("/api/jobs/status"), { credentials: "same-origin" });
|
||||||
if (statusResp.ok) {
|
if (statusResp.ok) {
|
||||||
var status = await statusResp.json();
|
var status = await statusResp.json();
|
||||||
var runningEl = document.getElementById("job-running");
|
var runningEl = document.getElementById("job-running");
|
||||||
@@ -1355,7 +1370,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var channelsResp = await fetch("/api/channels/monitored", { credentials: "same-origin" });
|
var channelsResp = await fetch(appPath("/api/channels/monitored"), { credentials: "same-origin" });
|
||||||
if (channelsResp.ok) {
|
if (channelsResp.ok) {
|
||||||
var payload = await channelsResp.json();
|
var payload = await channelsResp.json();
|
||||||
var wrap = document.getElementById("monitored-list");
|
var wrap = document.getElementById("monitored-list");
|
||||||
|
|||||||
Reference in New Issue
Block a user