diff --git a/omni/abuse.py b/omni/abuse.py index 4a9dc37..8cf0e89 100644 --- a/omni/abuse.py +++ b/omni/abuse.py @@ -48,9 +48,15 @@ RULES = [ COMPILED = [(tag, label, w, [re.compile(p, re.I) for p in pats]) for tag, label, w, pats in RULES] TAG_LABEL = {t: l for t, l, _, _ in RULES} STRONG = {"keys", "promo", "trial", "resale"} +# на специализированных абуз-площадках хватает одного признака: сам источник тематический +ABUSE_SRC_SC = 14 # категории-источники, которые вообще имеют смысл для абузов ABUSE_CATS = {"abuse", "forum", "community", "company_cn"} # «статьи»: слова про ключи и утечки там — текст, а не раздача +# мусор: заголовок из эмодзи/одного слова без текста — не находка +JUNK_TITLE = re.compile(r"^[\W_\d]{0,40}$", re.U) +# «сливать трафик» — арбитраж, не слив базы +TRAFFIC_NOISE = re.compile(r"слива\w*\s+(трафик|убт|ubt)|pinterest|арбитраж|арбит|tiktok", re.I) NOISE = re.compile(r"(blog|devto|medium|substack|newsletter|docs?|wiki)", re.I) @@ -88,6 +94,13 @@ def _qualifies(source, title, text, tags): strong = bool(set(hits) & STRONG) cat = SRC_CAT.get(source) blob = (title or "") + " " + (text or "") + if len(re.sub(r"\W", "", title or "")) < 8: + return 0, [] + if "leak" in hits and TRAFFIC_NOISE.search(blob) and not re.search(r"combo|dump|утечк|база", blob, re.I): + hits = [h for h in hits if h != "leak"] + sc -= 26 + if not hits: + return 0, [] raw_key = bool(re.search(r"(sk-[A-Za-z0-9_\-]{20,}|gh[pousr]_[A-Za-z0-9]{20,})", blob)) if NOISE.search(source or "") and not raw_key: return 0, [] @@ -97,6 +110,8 @@ def _qualifies(source, title, text, tags): return 0, [] elif cat not in ABUSE_CATS and not raw_key: return 0, [] + if cat == "abuse" and sc >= ABUSE_SRC_SC: + return sc, hits if strong and sc >= 24: return sc, hits if len(hits) >= 2 and sc >= 40: diff --git a/omni/bot.py b/omni/bot.py index 018b583..1be494f 100644 --- a/omni/bot.py +++ b/omni/bot.py @@ -589,5 +589,34 @@ def run_forever(): time.sleep(0.3) + +def _single_instance(): + """Один процесс на токен: второй инстанс выходит, иначе TelegramConflictError и бот молчит.""" + import os, sys, time, tempfile + path = os.path.join(tempfile.gettempdir(), "omni_bot.lock") + try: + if os.path.exists(path): + age = time.time() - os.path.getmtime(path) + try: + pid = int((open(path, encoding="utf-8").read() or "0").strip() or 0) + except ValueError: + pid = 0 + if pid and age < 6 * 3600: + alive = False + try: + import psutil + alive = psutil.pid_exists(pid) and "omni" in " ".join(psutil.Process(pid).cmdline() or []) + except Exception: + alive = False + if alive: + print("уже запущен pid %s - выхожу" % pid, flush=True) + sys.exit(0) + open(path, "w", encoding="utf-8").write(str(os.getpid())) + os.utime(path, None) + except Exception as e: + print("lock skip", e, flush=True) + + if __name__ == "__main__": + _single_instance() run_forever() \ No newline at end of file