111 lines
4.3 KiB
Python
111 lines
4.3 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
import httpx
|
||
|
|
|
||
|
|
from yuxi.utils.logging_config import logger
|
||
|
|
|
||
|
|
TELEGRAM_API_BASE = "https://api.telegram.org"
|
||
|
|
|
||
|
|
|
||
|
|
async def _telegram_api(token: str, method: str, params: dict | None = None) -> dict[str, Any]:
|
||
|
|
url = f"{TELEGRAM_API_BASE}/bot{token}/{method}"
|
||
|
|
async with httpx.AsyncClient(timeout=httpx.Timeout(15.0)) as client:
|
||
|
|
resp = await client.post(url, json=params or {})
|
||
|
|
return resp.json()
|
||
|
|
|
||
|
|
|
||
|
|
async def list_peers(config: dict[str, Any], account_id: str = "default") -> list[dict[str, Any]]:
|
||
|
|
token = config.get("bot_token", "")
|
||
|
|
if not token:
|
||
|
|
logger.warning("[Telegram/Directory] No bot_token in config, cannot list peers")
|
||
|
|
return []
|
||
|
|
|
||
|
|
monitored_chats = config.get("monitored_chats", [])
|
||
|
|
results: list[dict[str, Any]] = []
|
||
|
|
|
||
|
|
for chat_id_str in monitored_chats:
|
||
|
|
try:
|
||
|
|
chat_id = int(chat_id_str) if chat_id_str.lstrip("-").isdigit() else chat_id_str
|
||
|
|
data = await _telegram_api(token, "getChat", {"chat_id": chat_id})
|
||
|
|
if not data.get("ok"):
|
||
|
|
continue
|
||
|
|
|
||
|
|
chat = data.get("result", {})
|
||
|
|
ctype = chat.get("type", "")
|
||
|
|
|
||
|
|
if ctype in ("private", "group", "supergroup"):
|
||
|
|
administrators = await _telegram_api(token, "getChatAdministrators", {"chat_id": chat_id})
|
||
|
|
if administrators.get("ok"):
|
||
|
|
for admin in administrators.get("result", []):
|
||
|
|
user = admin.get("user", {})
|
||
|
|
uid = user.get("id")
|
||
|
|
uname = user.get("first_name", "") or user.get("username", "") or str(uid)
|
||
|
|
results.append(
|
||
|
|
{
|
||
|
|
"id": f"tg:{uid}",
|
||
|
|
"name": uname,
|
||
|
|
"chat_id": str(chat_id),
|
||
|
|
"chat_title": chat.get("title", ""),
|
||
|
|
"is_admin": True,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
|
||
|
|
member_count_data = await _telegram_api(token, "getChatMemberCount", {"chat_id": chat_id})
|
||
|
|
if member_count_data.get("ok"):
|
||
|
|
count = member_count_data.get("result", 0)
|
||
|
|
if count > len([r for r in results if r.get("chat_id") == str(chat_id)]):
|
||
|
|
pass
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.warning(f"[Telegram/Directory] Failed to list peers for chat {chat_id_str}: {e}")
|
||
|
|
continue
|
||
|
|
|
||
|
|
return results
|
||
|
|
|
||
|
|
|
||
|
|
async def list_groups(config: dict[str, Any], account_id: str = "default") -> list[dict[str, Any]]:
|
||
|
|
token = config.get("bot_token", "")
|
||
|
|
if not token:
|
||
|
|
logger.warning("[Telegram/Directory] No bot_token in config, cannot list groups")
|
||
|
|
return []
|
||
|
|
|
||
|
|
monitored_chats = config.get("monitored_chats", [])
|
||
|
|
results: list[dict[str, Any]] = []
|
||
|
|
|
||
|
|
for chat_id_str in monitored_chats:
|
||
|
|
try:
|
||
|
|
chat_id = int(chat_id_str) if chat_id_str.lstrip("-").isdigit() else chat_id_str
|
||
|
|
data = await _telegram_api(token, "getChat", {"chat_id": chat_id})
|
||
|
|
if not data.get("ok"):
|
||
|
|
continue
|
||
|
|
|
||
|
|
chat = data.get("result", {})
|
||
|
|
ctype = chat.get("type", "")
|
||
|
|
|
||
|
|
if ctype in ("group", "supergroup"):
|
||
|
|
count_data = await _telegram_api(token, "getChatMemberCount", {"chat_id": chat_id})
|
||
|
|
member_count = count_data.get("result", 0) if count_data.get("ok") else 0
|
||
|
|
|
||
|
|
results.append(
|
||
|
|
{
|
||
|
|
"id": f"tg:group:{chat_id}",
|
||
|
|
"name": chat.get("title", str(chat_id)),
|
||
|
|
"type": ctype,
|
||
|
|
"member_count": member_count,
|
||
|
|
"description": chat.get("description", ""),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
except Exception as e:
|
||
|
|
logger.warning(f"[Telegram/Directory] Failed to list groups for chat {chat_id_str}: {e}")
|
||
|
|
continue
|
||
|
|
|
||
|
|
return results
|
||
|
|
|
||
|
|
|
||
|
|
async def search_peers(config: dict[str, Any], query: str) -> list[dict[str, Any]]:
|
||
|
|
all_peers = await list_peers(config)
|
||
|
|
query_lower = query.lower()
|
||
|
|
return [p for p in all_peers if query_lower in p.get("name", "").lower() or query_lower in p.get("id", "").lower()]
|