from re import escape as re_escape
from secrets import choice
from traceback import format_exc
from pyrogram import filters
from pyrogram.enums import ChatMemberStatus as CMS
from pyrogram.enums import ParseMode as PM
from pyrogram.errors import RPCError
from pyrogram.types import CallbackQuery, Message
from Powers.bot_class import LOGGER, Gojo
from Powers.database.filters_db import Filters
from Powers.utils.cmd_senders import send_cmd
from Powers.utils.custom_filters import admin_filter, command, owner_filter
from Powers.utils.kbhelpers import ikb
from Powers.utils.msg_types import Types, get_filter_type
from Powers.utils.regex_utils import regex_searcher
from Powers.utils.string import (build_keyboard,
escape_mentions_using_curly_brackets,
parse_button, split_quotes)
# Initialise
db = Filters()
@Gojo.on_message(command("filters") & filters.group & ~filters.bot)
async def view_filters(_, m: Message):
filters_chat = f"Filters in {m.chat.title}:\n"
all_filters = db.get_all_filters(m.chat.id)
actual_filters = [j for i in all_filters for j in i.split("|")]
if not actual_filters:
await m.reply_text(f"There are no filters in {m.chat.title}")
return
filters_chat += "\n".join(
[
f" • {' | '.join([f'{i}
' for i in i.split('|')])}"
for i in all_filters
],
)
return await m.reply_text(filters_chat, disable_web_page_preview=True)
@Gojo.on_message(command(["filter", "addfilter"]) & admin_filter & ~filters.bot)
async def add_filter(_, m: Message):
args = m.text.split(" ", 1)
all_filters = db.get_all_filters(m.chat.id)
actual_filters = {j for i in all_filters for j in i.split("|")}
if (len(all_filters) >= 50) and (len(actual_filters) >= 150):
await m.reply_text(
"Only 50 filters and 150 aliases are allowed per chat!\nTo add more filters, remove the existing ones.",
)
return
if not m.reply_to_message and len(m.text.split()) < 3:
return await m.reply_text("Please read help section for how to save a filter!")
if m.reply_to_message and len(args) < 2:
return await m.reply_text("Please read help section for how to save a filter!")
extracted = await split_quotes(args[1])
keyword = extracted[0].lower()
# for k in keyword.split("|"):
# if k in actual_filters:
# return await m.reply_text(f"Filter {k}
already exists!")
if not keyword:
return await m.reply_text(
f"{m.text}
\n\nError: You must give a name for this Filter!",
)
if keyword.startswith("<") or keyword.startswith(">"):
return await m.reply_text("Cannot save a filter which starts with '<' or '>'")
eee, msgtype, file_id = await get_filter_type(m)
lol = eee if m.reply_to_message else extracted[1]
teks = lol if msgtype == Types.TEXT else eee
if not m.reply_to_message and msgtype == Types.TEXT and len(m.text.split()) < 3:
return await m.reply_text(
f"{m.text}
\n\nError: There is no text in here!",
)
if not teks and not msgtype:
return await m.reply_text(
'Please provide keyword for this filter reply with!\nEnclose filter in "double quotes"
',
)
if not msgtype:
return await m.reply_text(
"Please provide data for this filter reply with!",
)
if add := db.save_filter(m.chat.id, keyword, teks, msgtype, file_id):
await m.reply_text(
f"Saved filter for '{', '.join(keyword.split('|'))}
' in {m.chat.title}!",
)
await m.stop_propagation()
@Gojo.on_message(command(["stop", "unfilter"]) & admin_filter & ~filters.bot)
async def stop_filter(_, m: Message):
args = m.command
if len(args) <= 1:
return await m.reply_text("What should I stop replying to?")
chat_filters = db.get_all_filters(m.chat.id)
act_filters = {j for i in chat_filters for j in i.split("|")}
if not chat_filters:
return await m.reply_text("No filters active here!")
for keyword in act_filters:
if keyword == m.text.split(None, 1)[1].lower():
db.rm_filter(m.chat.id, m.text.split(None, 1)[1].lower())
await m.reply_text(
f"Okay, I'll stop replying to that filter and it's aliases in {m.chat.title}.",
)
await m.stop_propagation()
await m.reply_text(
"That's not a filter - Click: /filters to get currently active filters.",
)
await m.stop_propagation()
@Gojo.on_message(
command(
["rmallfilters", "removeallfilters", "stopall", "stopallfilters"],
)
& owner_filter,
)
async def rm_allfilters(_, m: Message):
if all_bls := db.get_all_filters(m.chat.id):
return await m.reply_text(
"Are you sure you want to clear all filters?",
reply_markup=ikb(
[[("⚠️ Confirm", "rm_allfilters"), ("❌ Cancel", "close_admin")]],
),
)
else:
return await m.reply_text("No filters to stop in this chat.")
@Gojo.on_callback_query(filters.regex("^rm_allfilters$"))
async def rm_allfilters_callback(_, q: CallbackQuery):
user_id = q.from_user.id
user_status = (await q.message.chat.get_member(user_id)).status
if user_status not in {CMS.OWNER, CMS.ADMINISTRATOR}:
await q.answer(
"You're not even an admin, don't try this explosive shit!",
show_alert=True,
)
return
if user_status != CMS.OWNER:
await q.answer(
"You're just an admin, not owner\nStay in your limits!",
show_alert=True,
)
return
db.rm_all_filters(q.message.chat.id)
await q.message.edit_text(f"Cleared all filters for {q.message.chat.title}")
await q.answer("Cleared all Filters!", show_alert=True)
return
async def send_filter_reply(c: Gojo, m: Message, trigger: str):
"""Reply with assigned filter for the trigger"""
getfilter = db.get_filter(m.chat.id, trigger)
if m and not m.from_user:
return
if not getfilter:
return await m.reply_text(
"Error: Cannot find a type for this filter!!",
quote=True,
)
msgtype = getfilter["msgtype"]
if not msgtype:
return await m.reply_text("Error: Cannot find a type for this filter!!")
try:
# support for random filter texts
splitter = "%%%"
filter_reply = getfilter["filter_reply"].split(splitter)
filter_reply = choice(filter_reply)
except KeyError:
filter_reply = ""
parse_words = [
"first",
"last",
"fullname",
"id",
"mention",
"username",
"chatname",
]
text = await escape_mentions_using_curly_brackets(m, filter_reply, parse_words)
teks, button = await parse_button(text)
button = await build_keyboard(button)
button = ikb(button) if button else None
textt = teks
try:
if msgtype == Types.TEXT:
if button:
try:
await m.reply_text(
textt,
parse_mode=PM.MARKDOWN,
reply_markup=button,
disable_web_page_preview=True,
quote=True,
)
return
except RPCError as ef:
await m.reply_text(
"An error has occured! Cannot parse note.",
quote=True,
)
LOGGER.error(ef)
LOGGER.error(format_exc())
return
else:
await m.reply_text(
textt,
parse_mode=PM.MARKDOWN,
quote=True,
disable_web_page_preview=True,
)
return
elif msgtype in (
Types.STICKER,
Types.VIDEO_NOTE,
Types.CONTACT,
Types.ANIMATED_STICKER,
):
await (await send_cmd(c, msgtype))(
m.chat.id,
getfilter["fileid"],
reply_markup=button,
reply_to_message_id=m.id,
)
else:
await (await send_cmd(c, msgtype))(
m.chat.id,
getfilter["fileid"],
caption=textt,
parse_mode=PM.MARKDOWN,
reply_markup=button,
reply_to_message_id=m.id,
)
except Exception as ef:
await m.reply_text(f"Error in filters: {ef}")
return msgtype
return msgtype
@Gojo.on_message(filters.text & filters.group & ~filters.bot, group=69)
async def filters_watcher(c: Gojo, m: Message):
chat_filters = db.get_all_filters(m.chat.id)
actual_filters = {j for i in chat_filters for j in i.split("|")}
for trigger in actual_filters:
pattern = r"( |^|[^\w])" + re_escape(trigger) + r"( |$|[^\w])"
match = await regex_searcher(pattern, m.text.lower())
if match:
try:
msgtype = await send_filter_reply(c, m, trigger)
except Exception as ef:
await m.reply_text(f"Error: {ef}")
LOGGER.error(ef)
LOGGER.error(format_exc())
break
continue
return
__PLUGIN__ = "filters"
_DISABLE_CMDS_ = ["filters"]
__alt_name__ = ["filters", "autoreply"]
__HELP__ = """
**Filters**
• /filters: List all active filters saved in the chat.
**Admin only:**
• /filter "``" ``: Add a filter to this chat. The bot will now reply that message whenever 'keyword'
is mentioned. If you reply to a sticker with a keyword, the bot will reply with that sticker.
If you want your keyword to be a sentence, use quotes. eg: /filter "hey there" How are you doin?
**Example:**
`/filter "filtername" Reply Text`
Aliases for filters can be too set, just put '|' between the filternames you want.
**Example:**
`/filter "filtername1|filtername2" Reply Text`
Using the you can make a single filter work on 2 filternames without manually adding another one.
• /stop ``: Stop that filter.
**Note:**
For filters with aliases, if you stop one alias, the filter will stop working on other aliases too.
**For Example:**
If you stop the "filtername1" from above example, the bot will not respond to "filtername2".
**Chat creator only:**
• /removeallfilters: Remove all chat filters at once.
**Note:**
Currently there is a limit of 50 filters and 120 aliases per chat.
All filter keywords are in lowercase."""