24/7’365 commited on
Commit
0e61bae
·
1 Parent(s): 28a9380

Add member monitoring and edit APIs

Browse files
Files changed (1) hide show
  1. app.py +57 -7
app.py CHANGED
@@ -33,7 +33,7 @@ from telebot import types, apihelper
33
  from telebot.apihelper import ApiTelegramException
34
  from flask import Flask, request, jsonify, send_file, Response
35
  from webdav4.client import Client as WebDAVClient
36
- from telethon import TelegramClient
37
  from telethon.sessions import StringSession
38
  from telethon.extensions import html as tl_html
39
  from apscheduler.schedulers.asyncio import AsyncIOScheduler
@@ -1282,6 +1282,22 @@ def start_telethon_worker():
1282
  TL_LOOP = asyncio.new_event_loop(); asyncio.set_event_loop(TL_LOOP)
1283
  TL_CLIENT = TelegramClient(StringSession(user_session), int(api_id_str), api_hash)
1284
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1285
  async def update_channel_msg():
1286
  current_time = int(time.time()); data_changed = False
1287
  for uid, u_data in DATA.get("users", {}).items():
@@ -1566,6 +1582,19 @@ def api_add_group(uid):
1566
  DATA["users"][uid].setdefault("groups",[]).append({"name":d.get("name",""),"src":d["src"],"tgt":[t for t in tgt if t]})
1567
  save_data(); return jsonify({"ok":True,"user":DATA["users"][uid]})
1568
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1569
  @app.route('/api/groups/<int:idx>', methods=['DELETE'])
1570
  @need_auth
1571
  def api_del_group(uid, idx):
@@ -1578,6 +1607,18 @@ def api_add_channel(uid):
1578
  d = request.json; DATA["users"][uid].setdefault("address_book",{})[d["id"]]=d["name"]; save_data()
1579
  return jsonify({"ok":True,"user":DATA["users"][uid]})
1580
 
 
 
 
 
 
 
 
 
 
 
 
 
1581
  @app.route('/api/channels/<path:cid>', methods=['DELETE'])
1582
  @need_auth
1583
  def api_del_channel(uid, cid):
@@ -1862,15 +1903,24 @@ def api_backup(uid):
1862
  return jsonify({"ok":True})
1863
  except Exception as e: return jsonify({"ok":False,"msg":str(e)})
1864
 
1865
- # ===== 🆕 备份频道成员 =====
1866
- @app.route('/api/backup_members', methods=['POST'])
1867
  @need_auth
1868
- def api_backup_members(uid):
1869
- d = request.json
1870
  ch_id = d.get('ch_id','').strip()
1871
  if not ch_id: return jsonify({"ok":False,"msg":"请输入频道ID"})
1872
- Thread(target=run_backup_members, args=(uid, ch_id)).start()
1873
- return jsonify({"ok":True})
 
 
 
 
 
 
 
 
 
1874
 
1875
  # ===== 批量建频道 =====
1876
  def run_batch_create_channels(uid, channel_names, user_ids, count=1):
 
33
  from telebot.apihelper import ApiTelegramException
34
  from flask import Flask, request, jsonify, send_file, Response
35
  from webdav4.client import Client as WebDAVClient
36
+ from telethon import TelegramClient, events
37
  from telethon.sessions import StringSession
38
  from telethon.extensions import html as tl_html
39
  from apscheduler.schedulers.asyncio import AsyncIOScheduler
 
1282
  TL_LOOP = asyncio.new_event_loop(); asyncio.set_event_loop(TL_LOOP)
1283
  TL_CLIENT = TelegramClient(StringSession(user_session), int(api_id_str), api_hash)
1284
 
1285
+ @TL_CLIENT.on(events.ChatAction)
1286
+ async def record_joined_member(event):
1287
+ if not (event.user_joined or event.user_added): return
1288
+ channel_id = str(event.chat_id); users = await event.get_users()
1289
+ if not isinstance(users, list): users = [users]
1290
+ changed = False
1291
+ for u_data in DATA.get("users", {}).values():
1292
+ for monitor in u_data.get("member_monitors", []):
1293
+ if str(monitor.get("channel_id")) != channel_id: continue
1294
+ records = monitor.setdefault("members", [])
1295
+ for user in users:
1296
+ if not user: continue
1297
+ records.append({"id":user.id,"username":user.username or "","first_name":user.first_name or "","last_name":user.last_name or "","bot":bool(user.bot),"joined_at":int(time.time())})
1298
+ changed = True
1299
+ if changed: await asyncio.to_thread(save_data)
1300
+
1301
  async def update_channel_msg():
1302
  current_time = int(time.time()); data_changed = False
1303
  for uid, u_data in DATA.get("users", {}).items():
 
1582
  DATA["users"][uid].setdefault("groups",[]).append({"name":d.get("name",""),"src":d["src"],"tgt":[t for t in tgt if t]})
1583
  save_data(); return jsonify({"ok":True,"user":DATA["users"][uid]})
1584
 
1585
+ @app.route('/api/groups/<int:idx>', methods=['PUT'])
1586
+ @need_auth
1587
+ def api_edit_group(uid, idx):
1588
+ d = request.json or {}; tgt = d.get("tgt", [])
1589
+ if isinstance(tgt, str): tgt = [tgt]
1590
+ targets = [str(t).strip() for t in tgt if str(t).strip()]
1591
+ if not str(d.get("src", "")).strip() or not targets:
1592
+ return jsonify({"ok":False,"msg":"来源频道和目标频道不能为空"})
1593
+ try:
1594
+ DATA["users"][uid]["groups"][idx] = {"name":str(d.get("name", "")).strip(), "src":str(d["src"]).strip(), "tgt":targets}
1595
+ save_data(); return jsonify({"ok":True,"user":DATA["users"][uid]})
1596
+ except (IndexError, KeyError): return jsonify({"ok":False,"msg":"索引无效"})
1597
+
1598
  @app.route('/api/groups/<int:idx>', methods=['DELETE'])
1599
  @need_auth
1600
  def api_del_group(uid, idx):
 
1607
  d = request.json; DATA["users"][uid].setdefault("address_book",{})[d["id"]]=d["name"]; save_data()
1608
  return jsonify({"ok":True,"user":DATA["users"][uid]})
1609
 
1610
+ @app.route('/api/channels/<path:cid>', methods=['PUT'])
1611
+ @need_auth
1612
+ def api_edit_channel(uid, cid):
1613
+ d = request.json or {}; new_id = str(d.get("id", "")).strip(); name = str(d.get("name", "")).strip()
1614
+ if not new_id or not name: return jsonify({"ok":False,"msg":"频道 ID 和备注不能为空"})
1615
+ ab = DATA["users"][uid].setdefault("address_book", {})
1616
+ if cid not in ab: return jsonify({"ok":False,"msg":"频道不存在"})
1617
+ if new_id != cid and new_id in ab: return jsonify({"ok":False,"msg":"新频道 ID 已存在"})
1618
+ if new_id != cid: del ab[cid]
1619
+ ab[new_id] = name; save_data()
1620
+ return jsonify({"ok":True,"user":DATA["users"][uid]})
1621
+
1622
  @app.route('/api/channels/<path:cid>', methods=['DELETE'])
1623
  @need_auth
1624
  def api_del_channel(uid, cid):
 
1903
  return jsonify({"ok":True})
1904
  except Exception as e: return jsonify({"ok":False,"msg":str(e)})
1905
 
1906
+ # ===== 频道成员入群监控 =====
1907
+ @app.route('/api/member_monitors', methods=['POST'])
1908
  @need_auth
1909
+ def api_add_member_monitor(uid):
1910
+ d = request.json or {}
1911
  ch_id = d.get('ch_id','').strip()
1912
  if not ch_id: return jsonify({"ok":False,"msg":"请输入频道ID"})
1913
+ monitors = DATA["users"][uid].setdefault("member_monitors", [])
1914
+ if any(str(item.get("channel_id")) == ch_id for item in monitors): return jsonify({"ok":False,"msg":"该频道已在监控中"})
1915
+ monitors.append({"channel_id":ch_id,"started_at":int(time.time()),"members":[]})
1916
+ save_data(); return jsonify({"ok":True,"user":DATA["users"][uid]})
1917
+
1918
+ @app.route('/api/member_monitors/<path:cid>', methods=['DELETE'])
1919
+ @need_auth
1920
+ def api_del_member_monitor(uid, cid):
1921
+ monitors = DATA["users"][uid].setdefault("member_monitors", [])
1922
+ DATA["users"][uid]["member_monitors"] = [m for m in monitors if str(m.get("channel_id")) != cid]
1923
+ save_data(); return jsonify({"ok":True,"user":DATA["users"][uid]})
1924
 
1925
  # ===== 批量建频道 =====
1926
  def run_batch_create_channels(uid, channel_names, user_ids, count=1):