main
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3import asyncio
4import contextlib
5import random
6import re
7from urllib.parse import urlparse
8
9from glom import glom
10from loguru import logger
11from pyrogram.client import Client
12from pyrogram.types import Message
13
14from config import TZ
15from custom.config import ACCOUNT_NAME, GROUP_JSQ, USER_BENNY, USER_XIAOHAO
16from database.kv import get_cf_kv, set_cf_kv
17from database.r2 import set_cf_r2
18from messages.utils import delete_message, set_reaction
19from utils import match_urls, nowdt, strings_list
20
21EMBY_SKIP_REG_BOT = "lilyembybot"
22
23
24async def emby_register(client: Client, message: Message) -> None:
25 await log_emby_register(client, message)
26 if not glom(message, "from_user.is_bot", default=False):
27 return
28 bot_name = glom(message, "from_user.username", default="")
29 # start register, send /start to bot
30 markup_text = glom(message, "reply_markup.inline_keyboard.0.0.text", default="")
31 markup_url = glom(message, "reply_markup.inline_keyboard.0.0.url", default="")
32 if ("自由注册" in message.content or "定时注册" in message.content) and markup_text == "👆🏻 点击注册" and markup_url:
33 reg_bot = markup_url.split("/")[-1]
34 if not reg_bot.endswith("bot"):
35 return
36 allow_reg_count = 0
37 if count_matched := re.search(r"剩余可注册 \| (\d+)", str(message.content)):
38 allow_reg_count = int(count_matched.group(1))
39 if allow_reg_count <= 0:
40 return
41 logger.warning(f"【Emby】{reg_bot} 已开启注册!")
42 if bot_name not in strings_list(EMBY_SKIP_REG_BOT) and allow_reg_count >= 5 and nowdt(tz=TZ).hour >= 8: # 至少 5 个名额
43 await client.send_message(reg_bot, "/start")
44 if ACCOUNT_NAME == "xiaohao":
45 fwd_message = await message.forward(GROUP_JSQ)
46 # get continue duration
47 duration_seconds = 1200 # default 20 min
48 if duration_matched := re.search(r"⏳ 可持续时间 \| (\d+) min", message.content):
49 duration_seconds = int(duration_matched.group(1)) * 60
50 duration_seconds = min(duration_seconds, allow_reg_count * 5) # 预估每个注册名额最多够 5s
51 duration_seconds = min(duration_seconds, 1800) # 最多 30 min
52 duration_seconds = max(duration_seconds, 300) # 最少 5 min
53 await asyncio.sleep(duration_seconds)
54 await delete_message(fwd_message)
55
56 # join group and channel
57 if ACCOUNT_NAME == "xiaohao" and str(message.content).startswith("💢 拜托啦"):
58 urls = glom(message, "reply_markup.inline_keyboard.**.url", default=[])
59 urls = {x for x in urls if str(x).startswith(("t.me/", "https://t.me/", "http://t.me/"))}
60 for url in urls:
61 with contextlib.suppress(Exception):
62 await client.join_chat(url.replace("http://", "https://"))
63
64 # init account
65 if "重新召唤面板" in message.content:
66 await client.send_message(message.chat.id, "/start")
67
68 # click `create` button
69 callback_data = glom(message, "reply_markup.inline_keyboard.**.callback_data", default=[])
70 if "create" in callback_data and bot_name not in {"sntp_lite_emby_bot", "shrekpublic_bot"}:
71 logger.warning(f"【Emby】{glom(message, 'from_user.username', default='')} 正在创建账户!")
72 resp = await client.request_callback_answer(message.chat.id, message.id, callback_data="create")
73 logger.warning(f"【Emby】{glom(resp, 'message', default='')}")
74
75 # set account credentials (only for bot)
76 if glom(message, "chat.type.name", default="") != "BOT":
77 return
78 if "您已进入注册状态" in str(message.content):
79 username = fakeuser()
80 safecode = random.randint(1000, 9999)
81 notice = f"【Emby】@{bot_name} 正在设置账户: {username} [{safecode}]"
82 logger.warning(notice)
83 await client.send_message(message.from_user.id, f"{username} {safecode}")
84 await client.send_message(USER_BENNY, notice)
85
86 if "创建用户成功" in str(message.content):
87 await message.forward(USER_BENNY)
88
89
90def fakeuser() -> str:
91 """生成一个随机的用户名, 格式为1个随机的声母 + 2个字母 + 4位年份数字."""
92 shengmu = "bpmfdtnlgkhjqxrzcsyw"
93 letters = "abcdefghijklmnopqrstuvwxyz"
94 return random.choice(shengmu) + "".join(random.choices(letters, k=2)) + str(random.randint(1980, 1999))
95
96
97async def log_emby_register(client: Client, message: Message) -> None:
98 """记录Emby注册相关的消息."""
99 if not glom(message, "forward_origin.sender_user.is_bot", default=False):
100 return
101 if glom(message, "from_user.id", default=0) not in [USER_BENNY, USER_XIAOHAO]:
102 return
103 emby_user = ""
104 emby_pass = ""
105 emby_server = ""
106 bot_name = glom(message, "forward_origin.sender_user.username", default="")
107
108 if str(message.content).startswith("▎创建用户成功🎉"):
109 await set_reaction(client, message, "✍️")
110 # 解析注册信息
111 if urls := match_urls(str(message.content)):
112 emby_server = urls[0]
113
114 for line in str(message.content).splitlines():
115 if line.startswith("· 用户名称 |"):
116 emby_user = line.removeprefix("· 用户名称 |").strip()
117 elif line.startswith("· 用户密码 |"):
118 emby_pass = line.removeprefix("· 用户密码 |").strip()
119 if not all([emby_user, emby_pass, emby_server]):
120 return
121
122 # 添加注册信息
123 accounts = await get_cf_kv("emby")
124 succ = False
125 for name, account in accounts.items():
126 if account["bot"] == bot_name:
127 succ = True
128 accounts[name]["enable"] = True
129 accounts[name]["username"] = emby_user
130 accounts[name]["password"] = emby_pass
131 accounts[name]["server"] = emby_server
132 break
133 if not succ:
134 accounts[bot_name] = {
135 "bot": bot_name,
136 "enable": True,
137 "username": emby_user,
138 "password": emby_pass,
139 "server": emby_server,
140 "keepalive": 5,
141 }
142
143 await save_accounts(accounts)
144 await set_reaction(client, message, "🎉")
145
146 if str(message.content).startswith("▎↓目前线路 & 用户密码:"):
147 if urls := match_urls(str(message.content)):
148 emby_server = urls[0]
149
150 for line in str(message.content).splitlines():
151 if line.startswith("▎↓目前线路 & 用户密码:"):
152 emby_pass = line.removeprefix("▎↓目前线路 & 用户密码:").strip()
153 if not any([emby_pass, emby_server]):
154 return
155 accounts = await get_cf_kv("emby")
156 for name, account in accounts.items():
157 if account["bot"] == bot_name:
158 accounts[name]["enable"] = True
159 if emby_pass:
160 accounts[name]["password"] = emby_pass
161 if emby_server:
162 accounts[name]["username"] = emby_server
163 break
164 await save_accounts(accounts)
165 await set_reaction(client, message, "🎉")
166
167 if str(message.content).startswith("▎欢迎进入用户面板!"):
168 enabled = None
169 for line in str(message.content).splitlines():
170 if line.startswith("· 📊 当前状态 |"):
171 status = line.removeprefix("· 📊 当前状态 |").strip()
172 enabled = status == "正常"
173 elif line.startswith("· 💠 账号名称 |"):
174 emby_user = line.removeprefix("· 💠 账号名称 |").strip()
175
176 if not (enabled is not None and emby_user):
177 return
178 accounts = await get_cf_kv("emby")
179 for name, account in accounts.items():
180 if account["bot"] == bot_name:
181 if enabled is not None:
182 accounts[name]["enable"] = enabled
183 if emby_user:
184 accounts[name]["username"] = emby_user
185 break
186 await save_accounts(accounts)
187 await set_reaction(client, message, "🎉")
188
189
190async def save_accounts(accounts: dict) -> bool:
191 # 生成clash rules
192 yaml_rules = "payload:\n"
193 txt_rules = ""
194 for conf in accounts.values():
195 host = urlparse(conf["server"]).hostname
196 yaml_rules += f" - {host}\n"
197 txt_rules += f"{host}\n"
198 await set_cf_r2("gfw/domain-emby.yml", yaml_rules, mime_type="text/plain")
199 await set_cf_r2("gfw/domain-emby.txt", txt_rules, mime_type="text/plain")
200 return await set_cf_kv("emby", accounts, silent=True)