Files
gilfanovrandClaude Opus 5.5 8a06244ef4 rpi: выгрузка Telegram второго аккаунта (tg_export с Mac) — stacks/rpi-tg-export
Пользователь tgexport, сессия /var/lib/tg-export (600), тексты в /mnt/backup/tg (группа astra),
докачка раз в сутки без медиа, итог в backup-metrics. Вход делает владелец.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:26:35 +03:00

73 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Выгрузка публичной группы/канала, в которой мы не состоим.
`export.py run` ходит по iter_dialogs и потому видит только свои чаты.
Здесь сущность резолвится по @username и история читается напрямую.
uv run fetch_public.py @cyschools --since 2026-03-04
"""
from __future__ import annotations
import argparse
import asyncio
import datetime as dt
import json
from pathlib import Path
from telethon import TelegramClient
import export as ex
ex.load_dotenv(ex.ROOT / ".env")
async def main_async(args) -> None:
api_id, api_hash = ex.require_credentials()
client = TelegramClient(args.session, api_id, api_hash)
client.flood_sleep_threshold = 24 * 60 * 60
await client.start()
try:
entity = await client.get_entity(args.chat)
dialog_id = int(f"-100{entity.id}")
folder = Path(args.out) / "chats" / f"{dialog_id}_{ex.slugify(getattr(entity, 'title', args.chat))}"
folder.mkdir(parents=True, exist_ok=True)
since = dt.datetime.fromisoformat(args.since).replace(tzinfo=dt.timezone.utc)
(folder / "meta.json").write_text(json.dumps({
"id": dialog_id,
"name": getattr(entity, "title", None),
"kind": ex.dialog_kind(entity),
"username": getattr(entity, "username", None),
"fetched_since": args.since,
}, ensure_ascii=False, indent=2), encoding="utf-8")
cache: dict = {}
n = 0
with (folder / "messages.jsonl").open("w", encoding="utf-8") as jsonl, \
(folder / "messages_pretty.jsonl").open("w", encoding="utf-8") as pretty:
async for msg in client.iter_messages(entity, offset_date=since, reverse=True):
record = msg.to_dict()
sender = await ex.sender_label(client, msg, cache)
jsonl.write(json.dumps(record, ensure_ascii=False, cls=ex.Encoder) + "\n")
pretty.write(json.dumps(ex.simplify_message(msg, sender, record),
ensure_ascii=False, cls=ex.Encoder) + "\n")
n += 1
if n % 1000 == 0:
print(f" … {n} ({msg.date:%Y-%m-%d})", flush=True)
print(f"{folder.name}: {n} сообщений")
finally:
await client.disconnect()
def main() -> None:
p = argparse.ArgumentParser()
p.add_argument("chat")
p.add_argument("--since", required=True)
p.add_argument("--out", default=str(ex.ROOT / "out"))
p.add_argument("--session", default=str(ex.ROOT / "tg_export.session"))
asyncio.run(main_async(p.parse_args()))
if __name__ == "__main__":
main()