From 1f918cd4089a97a0a6c497af39e6a4b900eb4627 Mon Sep 17 00:00:00 2001 From: mango Date: Wed, 25 Feb 2026 17:36:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=BB=98=E8=AE=A4=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E6=B1=A0=E9=87=8D=E7=BD=AE=E8=AE=A2=E9=98=85=E9=93=BE=E6=8E=A5?= =?UTF-8?q?+=E6=98=BE=E7=A4=BA=E5=BD=93=E5=89=8D=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/bot.py b/bot.py index 0c1a428..fdbe0a8 100644 --- a/bot.py +++ b/bot.py @@ -15,6 +15,11 @@ SUB_SECRET = os.environ.get('SUB_SECRET', 'changeme') SUB_HOST = os.environ.get('SUB_HOST', 'substore.mjjtop.com') WAITING_ADD = set() # user_ids waiting to add sub +def get_default_secret(): + """获取默认节点池的 secret,优先用 data.json 里的,没有就用环境变量""" + data = load_data() + return data.get('default_secret', SUB_SECRET) + def load_data(): if os.path.exists(DATA_FILE): with open(DATA_FILE) as f: @@ -135,22 +140,39 @@ async def cb_menu(update: Update, context: ContextTypes.DEFAULT_TYPE): if action == 'menu_default': cnt = len(data['subs']) alive_cnt = len([s for s in data['subs'] if s.get('alive', True)]) + host = SUB_HOST + url = f"https://{host}/{get_default_secret()}/download?target=ClashMeta" buttons = [ [InlineKeyboardButton("📋 节点列表", callback_data='menu_list'), InlineKeyboardButton("📥 获取订阅", callback_data='menu_get')], [InlineKeyboardButton("➕ 添加节点", callback_data='menu_add'), InlineKeyboardButton("🗑 删除节点", callback_data='menu_del')], + [InlineKeyboardButton("🔄 重置订阅链接", callback_data='menu_reset_secret')], [InlineKeyboardButton("◀️ 返回主菜单", callback_data='menu_home')], ] try: await q.edit_message_text( - f'📦 *默认节点池*\n\n总计 {cnt} 个节点,{alive_cnt} 个可用', + f'📦 *默认节点池*\n\n总计 {cnt} 个节点,{alive_cnt} 个可用\n🔗 订阅链接:\n`{url}`', parse_mode='Markdown', reply_markup=InlineKeyboardMarkup(buttons)) except: await send_del(q.message, - f'📦 *默认节点池*\n\n总计 {cnt} 个节点,{alive_cnt} 个可用', + f'📦 *默认节点池*\n\n总计 {cnt} 个节点,{alive_cnt} 个可用\n🔗 订阅链接:\n`{url}`', parse_mode='Markdown', reply_markup=InlineKeyboardMarkup(buttons)) + elif action == 'menu_reset_secret': + new_secret = secrets.token_hex(16) + data['default_secret'] = new_secret + save_data(data) + host = SUB_HOST + url = f"https://{host}/{new_secret}/download?target=ClashMeta" + buttons = [[InlineKeyboardButton("◀️ 返回", callback_data='menu_default')]] + try: + await q.edit_message_text(f"✅ 默认订阅链接已重置\n\n旧链接已失效\n新链接:\n`{url}`", + parse_mode='Markdown', reply_markup=InlineKeyboardMarkup(buttons)) + except: + await send_del(q.message, f"✅ 默认订阅链接已重置\n\n旧链接已失效\n新链接:\n`{url}`", + parse_mode='Markdown', reply_markup=InlineKeyboardMarkup(buttons)) + elif action == 'menu_home': default_cnt = len([s for s in data['subs'] if s.get('alive', True)]) sg_cnt = len(data.get('sub_groups', [])) @@ -280,7 +302,7 @@ async def cb_getsub(update: Update, context: ContextTypes.DEFAULT_TYPE): cm = gen_clash_meta([s]) await send_del(q.message, f'```yaml\n{cm}\n```', parse_mode='Markdown') elif fmt == 'url': - url = f'https://substore.mjjtop.com/{SUB_SECRET}/download?target=ClashMeta' + url = f'https://substore.mjjtop.com/{get_default_secret()}/download?target=ClashMeta' await send_del(q.message, f'📎 订阅URL:\n{url}') return @@ -303,7 +325,7 @@ async def cb_getsub(update: Update, context: ContextTypes.DEFAULT_TYPE): proto, fmt = parts[1], parts[2] subs = alive if proto == 'all' else [s for s in alive if s['type'] == proto] if fmt == 'clash': - url = f'https://substore.mjjtop.com/{SUB_SECRET}/download?target=ClashMeta' + url = f'https://substore.mjjtop.com/{get_default_secret()}/download?target=ClashMeta' if proto != 'all': url += f'&type={proto}' return await send_del(q.message, f'📎 Clash Meta 订阅链接:\n{url}') links = '\n'.join(s['link'] for s in subs) @@ -317,7 +339,7 @@ async def cb_getsub(update: Update, context: ContextTypes.DEFAULT_TYPE): return if action == 'get_all_clash': - url = f'https://substore.mjjtop.com/{SUB_SECRET}/download?target=ClashMeta' + url = f'https://substore.mjjtop.com/{get_default_secret()}/download?target=ClashMeta' await send_del(q.message, f'📎 Clash Meta 订阅链接:\n{url}') return @@ -408,7 +430,7 @@ async def cb_multiout(update: Update, context: ContextTypes.DEFAULT_TYPE): await send_del(q.message, f'```yaml\n{cm}\n```', parse_mode='Markdown') elif fmt == 'url': names = ','.join(urllib.request.quote(s['name']) for s in chosen) - url = f'https://substore.mjjtop.com/{SUB_SECRET}/download?target=ClashMeta&name={names}' + url = f'https://substore.mjjtop.com/{get_default_secret()}/download?target=ClashMeta&name={names}' await send_del(q.message, f'📎 订阅URL:\n{url}') elif fmt == 'b64': links = '\n'.join(s['link'] for s in chosen) @@ -599,7 +621,7 @@ class SubHandler(BaseHTTPRequestHandler): # 匹配默认分组或自定义分组 alive = [] - if path == f'/{SUB_SECRET}/download': + if path == f'/{get_default_secret()}/download': data = load_data() alive = [s for s in data['subs'] if s.get('alive', True)] else: