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)