abuse: полный пересчёт индекса только по явному вызову (env не тормозит scan)
This commit is contained in:
@@ -12,7 +12,7 @@ import urllib.parse
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
from . import feeds, net, sources, source_state, store
|
||||
from . import feeds, net, panel_api, sources, source_state, store
|
||||
|
||||
WEB = pathlib.Path(__file__).resolve().parent.parent / "web"
|
||||
JOBS = {}
|
||||
@@ -353,8 +353,14 @@ class Handler(BaseHTTPRequestHandler):
|
||||
sort = (q.get("sort") or ["score"])[0]
|
||||
priced = (q.get("priced") or ["0"])[0] in ("1", "true", "on")
|
||||
typ = (q.get("type") or ["all"])[0]
|
||||
src = (q.get("src") or [""])[0].strip() or None
|
||||
days = _intv(q, "days", 0, 0, 3650)
|
||||
since = None
|
||||
if days:
|
||||
import datetime as _dt
|
||||
since = (_dt.date.today() - _dt.timedelta(days=days)).isoformat()
|
||||
rows, total = store.browse2(q=query, names=_names_in_category(cat), limit=limit, offset=offset,
|
||||
sort=sort, priced=priced, typ=typ)
|
||||
sort=sort, priced=priced, typ=typ, since=since, src=src)
|
||||
for _r in rows:
|
||||
_r["title"] = _clean_txt(_r.get("title"), 180)
|
||||
_r["text"] = _clean_txt(_r.get("text"), 260)
|
||||
@@ -387,6 +393,71 @@ class Handler(BaseHTTPRequestHandler):
|
||||
self.wfile.write(data)
|
||||
return
|
||||
|
||||
if path.startswith("/api/item/"):
|
||||
try:
|
||||
iid = int(path.rsplit("/", 1)[-1])
|
||||
except ValueError:
|
||||
return self._json({"error": "bad id"}, 400)
|
||||
return self._json(panel_api.item_detail(iid))
|
||||
|
||||
if path == "/api/timeline":
|
||||
days = _intv(q, "days", 30, 1, 365)
|
||||
cat = (q.get("category") or [None])[0]
|
||||
return self._json(panel_api.timeline(days=days, cat=cat))
|
||||
|
||||
if path == "/api/suggest":
|
||||
return self._json(panel_api.suggest((q.get("q") or [""])[0], _intv(q, "limit", 8, 1, 20)))
|
||||
|
||||
if path == "/api/health":
|
||||
return self._json(panel_api.health())
|
||||
|
||||
if path == "/api/tg/status":
|
||||
return self._json(panel_api.tg_status())
|
||||
|
||||
if path == "/api/tg/search":
|
||||
term = (q.get("q") or [""])[0].strip()
|
||||
if len(term) < 2:
|
||||
return self._json({"ok": False, "error": "нужно минимум 2 символа", "channels": []})
|
||||
return self._json(panel_api.tg_search(term, limit=_intv(q, "limit", 40, 1, 100),
|
||||
min_members=_intv(q, "min", 0, 0, 10_000_000)))
|
||||
|
||||
if path == "/api/source":
|
||||
name = (q.get("name") or [""])[0].strip()
|
||||
return self._json(panel_api.source_detail(name) if name else {"error": "name required"})
|
||||
|
||||
if path == "/api/watch":
|
||||
return self._json(panel_api.watch_list(hits=_intv(q, "hits", 3, 1, 10)))
|
||||
|
||||
if path == "/api/digest":
|
||||
days = _intv(q, "days", 1, 1, 30)
|
||||
res = panel_api.digest(days=days, limit=_intv(q, "limit", 30, 5, 100))
|
||||
if (q.get("download") or ["0"])[0] in ("1", "true"):
|
||||
data = res["md"].encode("utf-8")
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/markdown; charset=utf-8")
|
||||
self.send_header("Content-Disposition", 'attachment; filename="omni-digest.md"')
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
return
|
||||
return self._json(res)
|
||||
|
||||
if path == "/api/export.json":
|
||||
cat = (q.get("category") or [None])[0]
|
||||
rows, total = store.browse2(q=(q.get("q") or [""])[0].strip(),
|
||||
names=_names_in_category(cat),
|
||||
limit=_intv(q, "limit", 500, 1, 5000),
|
||||
sort=(q.get("sort") or ["score"])[0],
|
||||
typ=(q.get("type") or ["all"])[0])
|
||||
data = json.dumps({"total": total, "items": rows}, ensure_ascii=False, indent=1).encode("utf-8")
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/json; charset=utf-8")
|
||||
self.send_header("Content-Disposition", 'attachment; filename="omni.json"')
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
return
|
||||
|
||||
if path.startswith("/api/job/"):
|
||||
jid = path.rsplit("/", 1)[-1]
|
||||
return self._json(JOBS.get(jid) or {"state": "unknown"})
|
||||
@@ -414,6 +485,25 @@ class Handler(BaseHTTPRequestHandler):
|
||||
res = _d.discover(limit_hosts=hosts, workers=8, max_add=add, dry=dry)
|
||||
return self._json(res)
|
||||
|
||||
if u.path == "/api/tg/pull":
|
||||
handles = [h for h in (body.get("handles") or []) if isinstance(h, str)][:20]
|
||||
if not handles:
|
||||
return self._json({"error": "handles required"}, 400)
|
||||
jid = _jid("tg")
|
||||
_job(jid, state="running")
|
||||
threading.Thread(target=lambda: _job(jid, **panel_api.tg_pull(handles, int(body.get("limit") or 100))),
|
||||
daemon=True).start()
|
||||
return self._json({"job": jid})
|
||||
|
||||
if u.path == "/api/watch/add":
|
||||
return self._json(panel_api.watch_add(body.get("q"), body.get("type") or "all"))
|
||||
|
||||
if u.path == "/api/watch/remove":
|
||||
rid = body.get("id")
|
||||
if not rid:
|
||||
return self._json({"error": "id required"}, 400)
|
||||
return self._json(panel_api.watch_remove(str(rid)))
|
||||
|
||||
if u.path == "/api/feed":
|
||||
jid = _jid("feed")
|
||||
_job(jid, state="running")
|
||||
|
||||
Reference in New Issue
Block a user