Files
export-telegram-group-members/common.py
T
tiennm99 f03099a18e feat: store session and exports in redis for cross-device portability
Replace the device-bound Telethon .session file and local CSV folders with
Redis-backed storage so the tool runs on any device from just .env.

- StringSession persisted at <prefix>:session:<phone> (no re-login per device)
- each group export saved as one self-contained JSON key per run:
  <prefix>:run:<phone>:<yyyymmddhhmmss>:<group_id>
- REDIS_PREFIX namespaces all keys; applied via a single key() helper
- no cross-key references: deleting any key cannot corrupt another's state
- list_exports() lists history, tolerant of deleted/corrupt keys
2026-06-08 16:49:34 +07:00

63 lines
1.9 KiB
Python

"""Export persistence in Redis.
Each group's members are stored per export as one self-contained JSON key:
<prefix>:run:<phone>:<yyyymmddhhmmss>:<group_id>
-> {group_id, title, time, members:[{id,username,first_name,last_name}]}
All groups in a single run share one timestamp. No key references another, so
deleting any key can never corrupt another's state. Writing a group export is a
single atomic SET; listing scans the run keys.
"""
import json
from datetime import datetime
from config import key, phone, redis_client
def new_run_time():
"""Timestamp shared by every group in one run: yyyymmddhhmmss."""
return datetime.now().strftime('%Y%m%d%H%M%S')
def member_dict(member):
return {
'id': member.id,
'username': member.username,
'first_name': member.first_name,
'last_name': member.last_name,
}
def save_group_export(group_id, title, members, run_time):
"""Atomically persist one group's members for a run as a single JSON value."""
record = {
'group_id': group_id,
'title': title,
'time': run_time,
'members': [member_dict(m) for m in members],
}
redis_client.set(
key('run', phone, run_time, str(group_id)),
json.dumps(record, ensure_ascii=False),
)
def list_exports():
"""Return all group-export records, sorted by (time, group_id).
Tolerates keys deleted mid-scan and corrupt/non-JSON values (skips them).
"""
records = []
for export_key in redis_client.scan_iter(match=key('run', phone, '*')):
raw = redis_client.get(export_key)
if raw is None: # deleted between scan and get
continue
try:
records.append(json.loads(raw))
except (ValueError, TypeError): # corrupt / non-JSON value: skip, don't abort
continue
records.sort(key=lambda r: (r.get('time', ''), r.get('group_id', 0)))
return records