реестр: дедуп источников строго по url (2 падавших теста зелёные); инкрементальный abuse-индекс + tgsearch из предыдущей сессии
Some checks failed
ci / test (3.10) (push) Has been cancelled
ci / test (3.11) (push) Has been cancelled
ci / test (3.12) (push) Has been cancelled

This commit is contained in:
ENI
2026-10-27 01:09:30 +03:00
parent d0fca99dda
commit d0b2187319
7 changed files with 601 additions and 24 deletions

View File

@@ -245,6 +245,42 @@ def radar_sources():
return rows
_PANELS = {"rows": [], "at": 0.0}
def panel_sources():
"""Панели new-api из data/panels.json (tools/panel_hunt.py --apply).
Адаптер newapi_pricing тянет /api/pricing и отдаёт находку: сколько моделей
на панели бесплатны. Это не статьи про абузы, а сами раздачи API.
"""
import json
from pathlib import Path
p = Path(__file__).resolve().parents[1] / "data" / "panels.json"
try:
mtime = p.stat().st_mtime
except OSError:
return []
if _PANELS["rows"] and _PANELS["at"] == mtime:
return _PANELS["rows"]
try:
d = json.loads(p.read_text(encoding="utf-8"))
except Exception:
return []
rows = []
for r in d.get("panels") or []:
host = str(r.get("host") or "").strip()
if not host:
continue
name = "pn_" + host.replace(".", "_").replace("-", "_")
rows.append(Source(name=name, category="abuse", kind="site", url="https://" + host,
adapter="newapi_pricing", tags=("panel", "abuse", "freeapi"),
limit=1, detail=False,
extra={"free_count": r.get("free_count") or 0, "models": r.get("models") or 0}))
_PANELS.update(at=mtime, rows=rows)
return rows
def _gen_sources():
"""Сгенерированные наборы: китайские (sources_cn) + дарк-форумы (sources_dark)."""
out = []
@@ -272,11 +308,15 @@ def all_sources():
("name", "category", "kind", "url", "adapter", "tags", "limit", "detail", "extra")}
extra.append(Source(**d))
seen, out = set(), []
for s in SOURCES + _gen_sources() + extra + radar_sources():
for s in SOURCES + _gen_sources() + extra + radar_sources() + panel_sources():
# дедуп строго по url: одна площадка = один источник, даже если пришла из
# реестра, radar_sources и panels.json одновременно (иначе двойной обход и
# двойные записи в базе). Побеждает первое вхождение — порядок списка выше.
key = (s.url or "").rstrip("/").lower()
if key and key in seen:
continue
seen.add(key)
if key:
seen.add(key)
out.append(s)
return out