24/7’365 commited on
Commit ·
0e61bae
1
Parent(s): 28a9380
Add member monitoring and edit APIs
Browse files
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/
|
| 1867 |
@need_auth
|
| 1868 |
-
def
|
| 1869 |
-
d = request.json
|
| 1870 |
ch_id = d.get('ch_id','').strip()
|
| 1871 |
if not ch_id: return jsonify({"ok":False,"msg":"请输入频道ID"})
|
| 1872 |
-
|
| 1873 |
-
return jsonify({"ok":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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):
|