main
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3import asyncio
4from typing import Literal
5from urllib.parse import urlparse
6
7from pyrogram.types import Message
8
9from config import DEVICE_NAME
10from custom.config import CHANNEL_EMBY_SEARCH, GROUP_DEV, USER_BENNY, USER_XIAOHAO
11from database.kv import get_cf_kv
12from emby.account import all_accounts, emby_login
13from emby.api import get_items_count
14from emby.constant import ITEM_TYPE
15from emby.register import save_accounts
16from emby.search import emby_search
17from messages.progress import modify_progress
18from messages.utils import blockquote, delete_message, remove_prefix, startswith_prefix
19from utils import strings_list, to_int, true
20
21CREDENTIAL_HEADER = "emby,enable,bot,server,user,pass,keepalive,nsfw"
22
23
24async def emby_entrypoint(message: Message):
25 """Emby相关."""
26 cid = message.chat.id
27 # VPS上的账号不响应 开发Group 的消息
28 if cid == GROUP_DEV and DEVICE_NAME in ["BennyBot-JP", "BennyBot-US", "BennyBot-CN"]:
29 return
30
31 if str(message.text).startswith(CREDENTIAL_HEADER):
32 if await set_credentials(message):
33 await delete_message(message)
34 return
35
36 if not (cid == CHANNEL_EMBY_SEARCH or startswith_prefix(message.content, prefix="/emby")):
37 return
38 if message.content == "/emby":
39 await count_items(message)
40 return
41 if message.content == "/embyget":
42 if message.from_user.id in [USER_BENNY, USER_XIAOHAO]:
43 await show_credentials(message, formats="text")
44 else:
45 await message.reply("❌权限不足", quote=True)
46 return
47 if message.content == "/embyset":
48 if message.from_user.id in [USER_BENNY, USER_XIAOHAO]:
49 await show_credentials(message, formats="csv")
50 else:
51 await message.reply("❌权限不足", quote=True)
52 return
53
54 # search emby
55 query = remove_prefix(message.content, prefix="/emby")
56 if not query:
57 return
58 status = await message.reply(f"🔍正在搜索: {query}", quote=True)
59 if cid == CHANNEL_EMBY_SEARCH:
60 summary, _, telegraph_url = await emby_search(query, allow_nsfw=True)
61 else:
62 summary, _, telegraph_url = await emby_search(query)
63 if not summary:
64 await modify_progress(status, text="❌没有找到任何结果", force_update=True)
65 return
66 summary = f"⚡️[即时预览]({telegraph_url})\n{blockquote(summary)}" if telegraph_url else blockquote(summary)
67 await modify_progress(status, text=summary, force_update=True)
68
69
70async def count_items(message: Message):
71 async def count(acc_name: str, config: dict, *, refresh: bool = False) -> str:
72 credentials = await emby_login(acc_name, refresh=refresh)
73 if not credentials:
74 return f"🤖[{acc_name}](t.me/{config['bot']}): ❌"
75 resp = await get_items_count(credentials)
76 if resp.get("hx_error"):
77 return await count(acc_name, config, refresh=True) if not refresh else f"🤖[{acc_name}](t.me/{config['bot']}): ❌"
78 return f"🤖[{acc_name}](t.me/{config['bot']}): {ITEM_TYPE['Movie']}{resp['MovieCount']} {ITEM_TYPE['Series']}{resp['EpisodeCount']}"
79
80 accounts = await all_accounts()
81 tasks = [count(acc_name, config) for acc_name, config in accounts.items()]
82 res = await asyncio.gather(*tasks)
83 await message.reply("\n".join(res), quote=True)
84
85
86async def show_credentials(message: Message, formats: Literal["text", "csv"] = "text"):
87 if formats == "text":
88 accounts = await all_accounts() # {"account_name": {"bot": "bot_handle", "server": "https://example.com", "username": "username", "password": "password"}}
89 msg = "⚠️除非特别说明, 否则所有服务器协议均为 **HTTPS**, 端口均为 **443**\n"
90 no_proto = ""
91 with_proto = ""
92 for acc_name, config in accounts.items():
93 r18 = "🔞" if config.get("nsfw") else ""
94 parsed = urlparse(config["server"])
95 no_proto += f"\n【{r18}`{acc_name}`】"
96 with_proto += f"\n【{r18}`{acc_name}`】"
97 if parsed.scheme == "http":
98 no_proto += "\n⚠️协议: **HTTP**"
99 no_proto += f"\n服务器: `{parsed.hostname}`"
100 with_proto += f"\n服务器: `{parsed.scheme}://{parsed.hostname}`"
101 if parsed.port is not None and parsed.port != 443:
102 no_proto += f"\n⚠️端口: `{parsed.port}`"
103 with_proto = with_proto[:-1] + f":{parsed.port}`"
104 no_proto += f"\n用户名: `{config['username']}`\n密码: `{config['password']}`\n"
105 with_proto += f"\n用户名: `{config['username']}`\n密码: `{config['password']}`\n"
106 await message.reply(msg + no_proto, quote=True)
107 await message.reply(msg + with_proto, quote=True)
108
109 elif formats == "csv":
110 kv = await get_cf_kv("emby")
111 msg = CREDENTIAL_HEADER
112 for name, c in sorted(kv.items(), key=lambda x: x[1]["enable"], reverse=True):
113 msg += f"\n{name},{c['enable']},@{c['bot']},{c['server']},{c['username']},{c['password']},{c.get('keepalive', '0')},{c.get('nsfw', '')}"
114 msg += f"\n{CREDENTIAL_HEADER}"
115 reply = await message.reply(msg, quote=True)
116 await asyncio.sleep(5)
117 await delete_message(reply)
118
119
120async def set_credentials(message: Message) -> bool:
121 if message.from_user.id not in [USER_BENNY, USER_XIAOHAO]:
122 return False
123 texts = message.text.split("\n")[1:]
124 credentials = {}
125 for line in texts:
126 name, enable, bot, server, user, passwd, keepalive, nsfw = line.split(",")
127 if name == strings_list(CREDENTIAL_HEADER)[0]:
128 continue
129 keepalive = to_int(keepalive)
130 credentials[name] = {
131 "enable": true(enable),
132 "bot": bot.lstrip("@").strip(),
133 "server": server.strip(),
134 "username": user.strip(),
135 "password": passwd.strip(),
136 "keepalive": keepalive,
137 "nsfw": true(nsfw),
138 }
139 if not isinstance(keepalive, int) or keepalive <= 0:
140 del credentials[name]["keepalive"]
141 if not true(nsfw):
142 del credentials[name]["nsfw"]
143 if credentials:
144 return await save_accounts(credentials)
145 return False