main
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3import re
4
5from loguru import logger
6from pyrogram.client import Client
7from pyrogram.types import Message, ReplyParameters
8
9from config import DB, FAVORITE
10from database.r2 import get_cf_r2, set_cf_r2
11from messages.parser import parse_msg
12from messages.sender import send2tg
13from messages.utils import delete_message, equal_prefix, set_reaction, startswith_prefix
14from utils import slim_cid, strings_list, to_int
15
16HELP = f"""⭐️**收藏消息**
17- `{FAVORITE.SAVE_PREFIX} keyword` : 保存消息为"keyword"到收藏夹
18- `{FAVORITE.SEND_PREFIX} keyword` : 从收藏夹发送"keyword"的消息
19
20保存同一条消息为多个关键词时, 需使用逗号分隔
21"""
22
23
24async def save_favorite(client: Client, message: Message, **kwargs):
25 """Save message to Favorites."""
26 # send docs if message == "/save"
27 if equal_prefix(message.text, prefix=FAVORITE.SAVE_PREFIX):
28 await send2tg(client, message, texts=HELP, **kwargs)
29 return
30 if not message.reply_to_message:
31 return
32 info = parse_msg(message, silent=True)
33 if not startswith_prefix(info["text"], prefix=FAVORITE.SAVE_PREFIX):
34 return
35 # check if user can use this command
36 if str(info["uid"]) not in strings_list(FAVORITE.TIDS_ALLOW_SAVE):
37 await message.reply(f"👤{info['full_name']}无权使用【保存收藏】功能\n🆔{info['uid']}", quote=True)
38 return
39 if not all([DB.CF_R2_ENABLED, FAVORITE.BACKUP_CHAT]):
40 await message.reply("【保存收藏】功能缺失必要参数设置", quote=True)
41 return
42
43 await set_reaction(client, message, reaction="👌")
44 keyword = info["text"].removeprefix(FAVORITE.SAVE_PREFIX).strip()
45 is_force_save = keyword.startswith(("!", "!")) # noqa: RUF001
46 keyword = keyword.removeprefix("!").removeprefix("!") # noqa: RUF001
47 msg_to_save = message.reply_to_message
48
49 # custom chat_id and message_id
50 if "cid=" in keyword and "mid=" in keyword:
51 cid = msg_to_save.chat.id
52 mid = msg_to_save.id
53 if matched := re.search(r"cid=(-?\w+)", keyword, re.IGNORECASE):
54 cid = to_int(matched.group(1))
55 keyword = re.sub(r"cid=(-?\w+)", "", keyword).strip()
56 if matched := re.search(r"mid=(\d+)", keyword, re.IGNORECASE):
57 mid = to_int(matched.group(1))
58 keyword = re.sub(r"mid=(\d+)", "", keyword).strip()
59 msg: Message = await client.get_messages(cid, mid) # type: ignore
60 if isinstance(msg, Message):
61 msg_to_save = msg
62 else:
63 await send2tg(client, message, texts=f"❌获取此消息失败, 可能是消息已被删除或者无访问权限.\nChatID={cid}, MessageID={mid}", **kwargs)
64 return
65
66 if not keyword:
67 return
68 keywords = strings_list(keyword.replace(",", ",")) # noqa: RUF001
69 # check if key is existed
70 for key in keywords:
71 if not is_force_save and await get_cf_r2(FAVORITE.R2_PREFIX + key):
72 await send2tg(client, message, texts=f"⚠️【{key}】已存在\n🔄请使用以下命令覆盖收藏:\n`{FAVORITE.SAVE_PREFIX}! {keyword}`", **kwargs)
73 return
74
75 # forward message to backup chat
76 if msg_to_save.media_group_id:
77 messages = await client.get_media_group(msg_to_save.chat.id, msg_to_save.id)
78 save_msgs: list[Message] = await client.forward_messages(
79 chat_id=to_int(FAVORITE.BACKUP_CHAT),
80 from_chat_id=msg_to_save.chat.id,
81 message_ids=[m.id for m in messages],
82 ) # type: ignore
83 save_msg = save_msgs[0]
84 else:
85 save_msg: Message = await msg_to_save.forward(to_int(FAVORITE.BACKUP_CHAT)) # type: ignore
86 metainfo = " ".join([f"#{key}" for key in keywords]) + f"\nhttps://t.me/c/{slim_cid(msg_to_save.chat.id)}/{msg_to_save.id}"
87 await save_msg.reply(metainfo, quote=True)
88 save_info = parse_msg(save_msg, silent=True, use_cache=False)
89 # only allow standard type
90 keys_to_remove = []
91 for k, v in save_info.items():
92 if not isinstance(v, (str, int, float, list, dict)):
93 keys_to_remove.append(k)
94 [save_info.pop(k) for k in keys_to_remove]
95 for key in keywords:
96 if not await set_cf_r2(FAVORITE.R2_PREFIX + key, save_info, silent=True):
97 logger.error(f"保存【{key}】到收藏失败")
98 await set_reaction(client, message, reaction="💔")
99 return
100 logger.success(f"【{key}】已保存到收藏")
101 await set_reaction(client, message, reaction="✍️")
102 await delete_message(message)
103
104
105async def send_favorite(client: Client, message: Message, **kwargs):
106 """Send message from Favorites."""
107 # send docs if message == "/fav"
108 if equal_prefix(message.text, prefix=FAVORITE.SEND_PREFIX):
109 await send2tg(client, message, texts=HELP, **kwargs)
110 return
111 info = parse_msg(message, silent=True)
112 if not startswith_prefix(info["text"], prefix=FAVORITE.SEND_PREFIX):
113 return
114 # check if user can use this command
115 if FAVORITE.TIDS_ALLOW_SEND != "all" and str(info["uid"]) not in strings_list(FAVORITE.TIDS_ALLOW_SEND):
116 await message.reply(f"👤{info['full_name']}无权使用【发送收藏】功能\n🆔{info['uid']}", quote=True)
117 return
118 if not all([DB.CF_R2_ENABLED]):
119 await message.reply("【发送收藏】功能缺失必要参数设置", quote=True)
120 return
121 keyword: str = info["text"].removeprefix(FAVORITE.SEND_PREFIX).strip()
122 if not keyword:
123 return
124
125 await set_reaction(client, message, reaction="👌")
126 save_key = f"{FAVORITE.R2_PREFIX}{keyword}"
127 # check if key is existed
128 save_info = await get_cf_r2(save_key)
129 if not save_info:
130 await send2tg(client, message, texts=f"【{keyword}】不存在", **kwargs)
131 await set_reaction(client, message, reaction="💔")
132 return
133 reply_message_id = message.reply_to_message.id if message.reply_to_message else None
134 reply = ReplyParameters(message_id=reply_message_id) # type: ignore
135 if save_info.get("media_group_id"):
136 succ = await client.copy_media_group(chat_id=info["cid"], from_chat_id=save_info["cid"], message_id=save_info["mid"], reply_parameters=reply)
137 else:
138 succ = await client.copy_message(chat_id=info["cid"], from_chat_id=save_info["cid"], message_id=save_info["mid"], reply_parameters=reply)
139 if isinstance(succ, Message) or (isinstance(succ, list) and all(isinstance(s, Message) for s in succ)):
140 await set_reaction(client, message)
141 else:
142 await set_reaction(client, message, reaction="💔")
143 await delete_message(message)