File size: 10,912 Bytes
11ae35a
ca4eb6d
f0f9ad9
11ae35a
 
 
9015bc5
87abec5
6cef7ec
11ae35a
ca4eb6d
87abec5
11ae35a
 
 
87abec5
11ae35a
 
 
 
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6dcea66
 
 
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89ad488
ca4eb6d
 
 
 
 
 
 
 
 
 
c62ca93
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89ad488
 
 
 
 
 
 
 
ca4eb6d
 
 
 
 
 
 
5bc27d3
ca4eb6d
 
 
 
 
5bc27d3
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ea508b7
ca4eb6d
 
 
 
 
 
 
9015bc5
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9015bc5
ca4eb6d
 
 
 
 
 
6cef7ec
 
 
 
ca4eb6d
 
 
 
 
c15d499
ca4eb6d
 
 
 
 
 
9015bc5
ca4eb6d
c15d499
ca4eb6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9da6fea
709df35
096ee5f
8e6421c
709df35
9da6fea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
096ee5f
66ec5ae
096ee5f
 
66ec5ae
096ee5f
9da6fea
 
 
 
 
 
af1662b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
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 <b>{m.chat.title}</b>:\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'<code>{i}</code>' 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 <code>{k}</code> already exists!")

    if not keyword:
        return await m.reply_text(
            f"<code>{m.text}</code>\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"<code>{m.text}</code>\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 <code>"double quotes"</code>',
        )

    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 '<code>{', '.join(keyword.split('|'))}</code>' in <b>{m.chat.title}</b>!",
        )
    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 <b>{m.chat.title}</b>.",
            )
            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(
            "<b>Error:</b> Cannot find a type for this filter!!",
            quote=True,
        )

    msgtype = getfilter["msgtype"]
    if not msgtype:
        return await m.reply_text("<b>Error:</b> 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 "`<keyword>`" `<reply message>`: 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 `<filter keyword>`: 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."""