Files
omni-parse/omni/tgsess.py
2026-10-27 01:09:30 +03:00

135 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Telegram через свою сессию (Telethon): глубина и закрытые каналы.
Зачем, если есть веб-превью t.me/s: превью отдаёт ~20 последних постов и ничего
не отдаёт для каналов с выключенным превью. Сессия тянет 200+ постов и читает
каналы/группы, куда аккаунт уже вступил.
Конфиг только через env (секретов в репозитории нет):
OMNI_TG_SESSION путь к .session без расширения
OMNI_TG_API_ID api_id (my.telegram.org)
OMNI_TG_API_HASH api_hash
OMNI_TG_LIMIT сколько постов тянуть на канал (по умолчанию 100)
Если env не задан — модуль молча выключен, парсер работает на веб-превью.
"""
import asyncio
import os
import re
from datetime import datetime, timezone
SERVICE_RE = re.compile(
r"^(channel (created|photo|name|description|username|deleted)|pinned|message pinned|"
r"channel photo (updated|removed)|joined|left|invite link)", re.I)
def enabled():
try:
from . import config
config.tg_cfg()
except Exception:
pass
return bool(os.environ.get("OMNI_TG_SESSION") and os.environ.get("OMNI_TG_API_ID")
and os.environ.get("OMNI_TG_API_HASH"))
def _key(handle):
return handle.strip().strip("/").split("/")[-1].lstrip("@")
async def _pull(handles, limit, session, api_id, api_hash, timeout=40):
from telethon import TelegramClient
client = TelegramClient(session, api_id, api_hash, connection_retries=1, timeout=timeout / 2)
out = []
await asyncio.wait_for(client.connect(), timeout)
try:
for h in handles:
hh = _key(h)
rec = {"handle": hh, "posts": []}
try:
ent = await asyncio.wait_for(client.get_entity(hh), timeout)
msgs = await asyncio.wait_for(client.get_messages(ent, limit=limit), timeout)
rec["title"] = getattr(ent, "title", "") or hh
rec["id"] = getattr(ent, "id", None)
for m in msgs:
text = (getattr(m, "message", "") or "").strip()
if not text or SERVICE_RE.match(text):
continue
rec["posts"].append({
"id": getattr(m, "id", None),
"url": "https://t.me/%s/%s" % (hh, getattr(m, "id", "")),
"title": text.splitlines()[0][:300],
"text": text[:6000],
"views": getattr(m, "views", None),
"date": (m.date.astimezone(timezone.utc).isoformat()
if isinstance(getattr(m, "date", None), datetime) else ""),
"channel": hh,
})
except Exception as e:
rec["error"] = type(e).__name__
out.append(rec)
finally:
try:
await asyncio.wait_for(client.disconnect(), 10)
except Exception:
pass
return out
def fetch(handles, limit=None):
"""Список словарей {handle, title, id, posts[]} по каналам. Пусто, если нет env."""
if not enabled():
return []
try:
from . import config
config.tg_cfg()
except Exception:
pass
session = os.environ["OMNI_TG_SESSION"]
api_id = int(os.environ["OMNI_TG_API_ID"])
api_hash = os.environ["OMNI_TG_API_HASH"]
lim = int(limit or os.environ.get("OMNI_TG_LIMIT") or 100)
return asyncio.run(_pull(list(handles), lim, session, api_id, api_hash))
async def _search(query, limit, session, api_id, api_hash, timeout=60):
"""Глобальный поиск каналов/групп по запросу (contacts.SearchRequest)."""
from telethon import TelegramClient
from telethon.tl.functions.contacts import SearchRequest
client = TelegramClient(session, api_id, api_hash, connection_retries=1, timeout=timeout / 2)
await asyncio.wait_for(client.connect(), timeout)
try:
res = await asyncio.wait_for(client(SearchRequest(q=str(query), limit=int(limit))), timeout)
out = []
for ch in getattr(res, "chats", []) or []:
uname = getattr(ch, "username", None)
if not uname:
continue
out.append({"username": uname, "title": getattr(ch, "title", "") or "",
"id": getattr(ch, "id", None),
"broadcast": bool(getattr(ch, "broadcast", False)),
"megagroup": bool(getattr(ch, "megagroup", False)),
"participants": getattr(ch, "participants_count", None) or 0,
"query": str(query)})
return out
finally:
try:
await asyncio.wait_for(client.disconnect(), 10)
except Exception:
pass
def search(query, limit=40):
"""Каналы по ключевому слову. Пусто, если сессия не настроена."""
if not enabled():
return []
try:
from . import config
config.tg_cfg()
except Exception:
pass
session = os.environ["OMNI_TG_SESSION"]
api_id = int(os.environ["OMNI_TG_API_ID"])
api_hash = os.environ["OMNI_TG_API_HASH"]
return asyncio.run(_search(query, limit, session, api_id, api_hash))