Major change with own custom client decorator (#170)

* Add kbbi and carbon

* add blacklist command

* style: format code with black and isort (#168)

Format code with black and isort

This commit fixes the style issues introduced in bffcf61 according to the output
from Black and isort.

Details: https://app.deepsource.com/gh/yasirarism/MissKatyPyro/transform/4ddb51cc-a1ca-432a-95c4-1fb5388b405a/

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>

* okk

* style: format code with black and isort (#169)

Format code with black and isort

This commit fixes the style issues introduced in 9355c09 according to the output
from Black and isort.

Details: https://app.deepsource.com/gh/yasirarism/MissKatyPyro/transform/172890f8-d001-4812-8380-9a666a9a3bd5/

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>

* jmm

---------

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
This commit is contained in:
yasirarism 2023-07-05 13:10:44 +07:00 committed by GitHub
parent 9adf448701
commit 9cb6a7d77d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 913 additions and 203 deletions

33
database/blacklist_db.py Normal file
View file

@ -0,0 +1,33 @@
from database import dbname
from typing import List
blacklist_filtersdb = dbname["blacklistFilters"]
async def get_blacklisted_words(chat_id: int) -> List[str]:
_filters = await blacklist_filtersdb.find_one({"chat_id": chat_id})
if not _filters:
return []
return _filters["filters"]
async def save_blacklist_filter(chat_id: int, word: str):
word = word.lower().strip()
_filters = await get_blacklisted_words(chat_id)
_filters.append(word)
await blacklist_filtersdb.update_one(
{"chat_id": chat_id},
{"$set": {"filters": _filters}},
upsert=True,
)
async def delete_blacklist_filter(chat_id: int, word: str) -> bool:
filtersd = await get_blacklisted_words(chat_id)
word = word.lower().strip()
if word in filtersd:
filtersd.remove(word)
await blacklist_filtersdb.update_one(
{"chat_id": chat_id},
{"$set": {"filters": filtersd}},
upsert=True,
)
return True
return False

View file

@ -40,7 +40,7 @@ MOD_NOLOAD = ["subscene_dl"]
HELPABLE = {} HELPABLE = {}
cleanmode = {} cleanmode = {}
botStartTime = time.time() botStartTime = time.time()
misskaty_version = "v2.9.3 - Stable" misskaty_version = "v2.10.1 - Stable"
# Pyrogram Bot Client # Pyrogram Bot Client
app = Client( app = Client(

View file

@ -1,8 +0,0 @@
from pyrogram import filters
def pesanedit(_, __, m):
return bool(m.edit_date)
edited = filters.create(pesanedit)

View file

@ -1,3 +1,4 @@
# skipcq
from .errors import * from .errors import *
from .misc import * from .misc import *
from .permissions import * from .permissions import *

View file

@ -1,67 +0,0 @@
import asyncio
from logging import getLogger
from pyrogram.errors import (
ChatAdminRequired,
ChatWriteForbidden,
FloodWait,
MessageDeleteForbidden,
MessageEmpty,
MessageIdInvalid,
MessageNotModified,
)
LOGGER = getLogger(__name__)
# handler for TG function, so need write exception in every code
# Send MSG Pyro
async def kirimPesan(msg, text, **kwargs):
try:
return await msg.reply(text, **kwargs)
except FloodWait as e:
LOGGER.warning(str(e))
await asyncio.sleep(e.value)
return await kirimPesan(msg, text, **kwargs)
except (ChatWriteForbidden, ChatAdminRequired):
LOGGER.info(
f"Leaving from {msg.chat.title} [{msg.chat.id}] because doesn't have admin permission."
)
return await msg.chat.leave()
except Exception as e:
LOGGER.error(str(e))
return
# Edit MSG Pyro
async def editPesan(msg, text, **kwargs):
try:
return await msg.edit(text, **kwargs)
except FloodWait as e:
LOGGER.warning(str(e))
await asyncio.sleep(e.value)
return await editPesan(msg, text, **kwargs)
except (MessageNotModified, MessageIdInvalid, MessageEmpty):
return
except (ChatWriteForbidden, ChatAdminRequired):
LOGGER.info(
f"Leaving from {msg.chat.title} [{msg.chat.id}] because doesn't have admin permission."
)
return await msg.chat.leave()
except Exception as e:
LOGGER.error(str(e))
return
async def hapusPesan(msg):
try:
return await msg.delete()
except (MessageDeleteForbidden, ChatAdminRequired):
return
except FloodWait as e:
LOGGER.warning(str(e))
await asyncio.sleep(e.value)
return await hapusPesan(msg)
except Exception as e:
LOGGER.error(str(e))

View file

@ -1 +1 @@
from . import bound, listen, methods from . import bound, listen, methods, decorators

View file

@ -1 +1,2 @@
# skipcq
from .message import Message from .message import Message

View file

@ -0,0 +1,4 @@
from .callback import callback
from .command import command
__all__ = ["callback", "command"]

View file

@ -0,0 +1,100 @@
# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram
# Copyright (C) 2021 - 2022 Jayant Hegde Kageri <https://github.com/jayantkageri>
# This file is part of tgEasy.
# tgEasy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# tgEasy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with tgEasy. If not, see <http://www.gnu.org/licenses/>.
import typing
import pyrogram
from pyrogram.methods import Decorators
from ..utils import handle_error
def callback(
self,
data: typing.Union[str, list],
self_admin: typing.Union[bool, bool] = False,
filter: typing.Union[pyrogram.filters.Filter, pyrogram.filters.Filter] = None,
*args,
**kwargs,
):
"""
### `Client.callback`
- A decorater to Register Callback Quiries in simple way and manage errors in that Function itself, alternative for `@pyrogram.Client.on_callback_query(pyrogram.filters.regex('^data.*'))`
- Parameters:
- data (str || list):
- The callback query to be handled for a function
- self_admin (bool) **optional**:
- If True, the command will only executeed if the Bot is Admin in the Chat, By Default False
- filter (`~pyrogram.filters`) **optional**:
- Pyrogram Filters, hope you know about this, for Advaced usage. Use `and` for seaperating filters.
#### Example
.. code-block:: python
import pyrogram
app = pyrogram.Client()
@app.command("start")
async def start(client, message):
await message.reply_text(
f"Hello {message.from_user.mention}",
reply_markup=pyrogram.types.InlineKeyboardMarkup([[
pyrogram.types.InlineKeyboardButton(
"Click Here",
"data"
)
]])
)
@app.callback("data")
async def data(client, CallbackQuery):
await CallbackQuery.answer("Hello :)", show_alert=True)
"""
if filter:
filter = pyrogram.filters.regex(f"^{data}.*") & args["filter"]
else:
filter = pyrogram.filters.regex(f"^{data}.*")
def wrapper(func):
async def decorator(client, CallbackQuery: pyrogram.types.CallbackQuery):
if self_admin:
me = await client.get_chat_member(
CallbackQuery.message.chat.id, (await client.get_me()).id
)
if me.status not in (
pyrogram.enums.ChatMemberStatus.OWNER,
pyrogram.enums.ChatMemberStatus.ADMINISTRATOR,
):
return await CallbackQuery.message.edit_text(
"I must be admin to execute this Command"
)
try:
await func(client, CallbackQuery)
except pyrogram.errors.exceptions.forbidden_403.ChatAdminRequired:
pass
except BaseException as e:
return await handle_error(e, CallbackQuery)
self.add_handler(
pyrogram.handlers.CallbackQueryHandler(decorator, filter)
)
return decorator
return wrapper
Decorators.on_cb = callback

View file

@ -0,0 +1,129 @@
import typing
import pyrogram
from ..utils import handle_error
from pyrogram.methods import Decorators
from misskaty.vars import COMMAND_HANDLER
def command(
self,
command: typing.Union[str, list],
is_disabled: typing.Union[bool, bool] = False,
pm_only: typing.Union[bool, bool] = False,
group_only: typing.Union[bool, bool] = False,
self_admin: typing.Union[bool, bool] = False,
self_only: typing.Union[bool, bool] = False,
no_channel: typing.Union[bool, bool] = False,
handler: typing.Optional[list] = None,
filter: typing.Union[pyrogram.filters.Filter, pyrogram.filters.Filter] = None,
*args,
**kwargs
):
"""
### `tgClient.command`
- A decorater to Register Commands in simple way and manage errors in that Function itself, alternative for `@pyrogram.Client.on_message(pyrogram.filters.command('command'))`
- Parameters:
- command (str || list):
- The command to be handled for a function
- group_only (bool) **optional**:
- If True, the command will only executed in Groups only, By Default False.
- pm_only (bool) **optional**:
- If True, the command will only executed in Private Messages only, By Default False.
- self_only (bool) **optional**:
- If True, the command will only excute if used by Self only, By Default False.
- handler (list) **optional**:
- If set, the command will be handled by the specified Handler, By Default `Config.HANDLERS`.
- self_admin (bool) **optional**:
- If True, the command will only executeed if the Bot is Admin in the Chat, By Default False
- filter (`~pyrogram.filters`) **optional**:
- Pyrogram Filters, hope you know about this, for Advaced usage. Use `and` for seaperating filters.
#### Example
.. code-block:: python
import pyrogram
app = pyrogram.Client()
@app.on_cmd("start", is_disabled=False, group_only=False, pm_only=False, self_admin=False, self_only=False, pyrogram.filters.chat("777000") and pyrogram.filters.text)
async def start(client, message):
await message.reply_text(f"Hello {message.from_user.mention}")
"""
if handler is None:
handler = COMMAND_HANDLER
if filter:
if self_only:
filter = (
pyrogram.filters.command(command, prefixes=handler)
& filter
& pyrogram.filters.me
)
else:
filter = (
pyrogram.filters.command(command, prefixes=handler)
& filter
& pyrogram.filters.me
)
else:
if self_only:
filter = (
pyrogram.filters.command(command, prefixes=handler)
& pyrogram.filters.me
)
else:
filter = pyrogram.filters.command(command, prefixes=handler)
def wrapper(func):
async def decorator(client, message: pyrogram.types.Message):
if is_disabled:
return await message.reply_text("Sorry, this command has been disabled by owner.")
if not message.from_user:
return await message.reply_text("I'm cannot identify user. Use my command in private chat.")
if (
self_admin
and message.chat.type != pyrogram.enums.ChatType.SUPERGROUP
):
return await message.reply_text(
"This command can be used in supergroups only."
)
if self_admin:
me = await client.get_chat_member(
message.chat.id, (await client.get_me()).id
)
if me.status not in (
pyrogram.enums.ChatMemberStatus.OWNER,
pyrogram.enums.ChatMemberStatus.ADMINISTRATOR,
):
return await message.reply_text(
"I must be admin to execute this Command"
)
if (
group_only
and message.chat.type != pyrogram.enums.ChatType.SUPERGROUP
):
return await message.reply_text(
"This command can be used in supergroups only."
)
if pm_only and message.chat.type != pyrogram.enums.ChatType.PRIVATE:
return await message.reply_text(
"This command can be used in PMs only."
)
try:
await func(client, message)
except pyrogram.errors.exceptions.forbidden_403.ChatWriteForbidden:
await client.leave_chat(message.chat.id)
except BaseException as exception:
return await handle_error(exception, message)
self.add_handler(
pyrogram.handlers.MessageHandler(callback=decorator, filters=filter)
)
return decorator
return wrapper
Decorators.on_cmd = command

View file

@ -1 +1,2 @@
# skipcq
from .listen import Chat, Client, MessageHandler, User from .listen import Chat, Client, MessageHandler, User

View file

@ -1,3 +1,4 @@
# skipcq
from .edit_message_text import edit_message_text from .edit_message_text import edit_message_text
from .send_as_file import send_as_file from .send_as_file import send_as_file
from .send_message import send_message from .send_message import send_message

View file

@ -1 +1,5 @@
# skipcq
from .admin_utils import check_rights, is_admin
from .get_user import get_user
from .handler_error import handle_error
from .utils import PyromodConfig, patch, patchable from .utils import PyromodConfig, patch, patchable

View file

@ -0,0 +1,154 @@
# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram
# Copyright (C) 2021 - 2022 Jayant Hegde Kageri <https://github.com/jayantkageri>
# This file is part of tgEasy.
# tgEasy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# tgEasy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with tgEasy. If not, see <http://www.gnu.org/licenses/>.
import typing
import pyrogram
async def check_rights(
chat_id: typing.Union[int, int],
user_id: typing.Union[int, int],
rights: typing.Union[str, list],
client,
) -> bool:
"""
### `check_rights`
- Checks the Rights of an User
- This is an Helper Function for `adminsOnly`
- Parameters:
- chat_id (int):
- The Chat ID of Which Chat have to check the Rights.
- user_id (int):
- The User ID of Whose Rights have to Check.
- rights (str):
- The Rights have to Check.
- client (`pyrogram.Client`):
- From which Client to Check the Rights.
- Returns:
- `True` if the User have the Right.
- `False` if the User don't have the Right.
#### Example
.. code-block:: python
import pyrogram
app = pyrogram.Client()
@app.command("ban", group_only=True, self_admin=True)
async def ban(client, message):
if not await check_rights(message.chat.id, message.from_user.id, "can_restrict_members"):
return await message.reply_text("You don't have necessary rights to use this Command.")
user = await get_user(message)
await message.chat.kick_member(user.id)
"""
try:
user = await client.get_chat_member(chat_id, user_id)
except Exception:
return False
if user.status == "user":
return False
if user.status in (
pyrogram.enums.ChatMemberStatus.OWNER,
pyrogram.enums.ChatMemberStatus.ADMINISTRATOR,
):
permission = []
if user.privileges.can_manage_chat:
permission.append("can_manage_chat")
if user.privileges.can_delete_messages:
permission.append("can_delete_messages")
if user.privileges.can_manage_video_chats:
permission.append("can_manage_video_chats")
if user.privileges.can_restrict_members:
permission.append("can_restrict_members")
if user.privileges.can_promote_members:
permission.append("can_promote_members")
if user.privileges.can_change_info:
permission.append("can_change_info")
if user.privileges.can_post_messages:
permission.append("can_post_messages")
if user.privileges.can_edit_messages:
permission.append("can_edit_messages")
if user.privileges.can_invite_users:
permission.append("can_invite_users")
if user.privileges.can_pin_messages:
permission.append("can_pin_messages")
if user.privileges.is_anonymous:
permission.append("is_anonymous")
if isinstance(rights, str):
return rights in permission
if isinstance(rights, list):
for right in rights:
return right in permission
return False
async def is_admin(
chat_id: typing.Union[int, str], user_id: typing.Union[int, str], client
) -> bool:
"""
### `is_admin`
- A Functions to Check if the User is Admin or not
- Parameters:
- chat_id (int):
- The Chat ID of Which Chat have to check the Admin Status.
- user_id (int):
- The User ID of Whose Admin Status have to Check.
- client (`pyrogram.Client`):
- From which Client to Check the Admin Status.
- Returns:
- `True` if the User is Admin.
- `False` if the User is't Admin.
#### Example
.. code-block:: python
import pyrogram
app = pyrogram.Client()
@app.command("ban", group_only=True, self_admin=True)
@app.adminsOnly("can_restrict_members")
async def ban(client, message):
if await is_admin(message.chat.id, (await get_user(mesasge)).id):
return await message.reply_text("You can't Ban Admins.")
await message.chat.kick_member((await get_user(message)).id)
await message.reply_text("User has been Banned.")
"""
try:
user = await client.get_chat_member(chat_id, user_id)
except Exception:
return False
return user.status in (pyrogram.enums.ChatMemberStatus.OWNER, pyrogram.enums.ChatMemberStatus.ADMINISTRATOR,)

View file

@ -0,0 +1,122 @@
# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram
# Copyright (C) 2021 - 2022 Jayant Hegde Kageri <https://github.com/jayantkageri>
# This file is part of tgEasy.
# tgEasy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# tgEasy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with tgEasy. If not, see <http://www.gnu.org/licenses/>.
import contextlib
import typing
import pyrogram
async def get_user(
m: typing.Union[pyrogram.types.Message, pyrogram.types.CallbackQuery]
) -> pyrogram.types.User or bool:
"""
### `tgEasy.get_user`
- Gets a User from Message/RepliedMessage/CallbackQuery
- Parameters:
- m (`~pyrogram.types.Message` || `~pyrogram.types.CallbackQuery`)
- Returns:
- `pyrogram.types.User` on Success
- `False` on Error
#### Example
.. code-block:: python
from tgEasy import get_user, command, adminsOnly
@command("ban", group_only=True, self_admin=True)
@adminsOnly("can_restrict_members")
async def ban(client, message):
user = await get_user(message)
await message.chat.kick_member(user.id)
"""
if isinstance(m, pyrogram.types.Message):
message = m
client = m._client
if isinstance(m, pyrogram.types.CallbackQuery):
message = m.message
client = message._client
if message.reply_to_message:
if message.reply_to_message.sender_chat:
return False
return await client.get_users(message.reply_to_message.from_user.id)
command = message.command[1] if len(message.command) > 1 else None
if command and (command.startswith("@") or command.isdigit()):
with contextlib.suppress(
pyrogram.errors.exceptions.bad_request_400.UsernameNotOccupied,
pyrogram.errors.exceptions.bad_request_400.UsernameInvalid,
pyrogram.errors.exceptions.bad_request_400.PeerIdInvalid,
IndexError,
):
return await client.get_users(message.command[1])
if message.entities:
for mention in message.entities:
if mention.type == "text_mention":
user = mention.user.id
break
with contextlib.suppress(Exception):
return await client.get_users(user)
return False
async def get_user_adv(
m: typing.Union[pyrogram.types.Message, pyrogram.types.CallbackQuery]
) -> pyrogram.types.User or bool:
"""
### `tgEasy.get_user_adv`
- A Function to Get the User from the Message/CallbackQuery, If there is None arguments, returns the From User.
- Parameters:
- m (`pyrogram.types.Message` || `pyrogram.types.CallbackQuery`):
- Message or Callbackquery.
- Returns:
- `pyrogram.types.User` on Success
- `False` on Error
#### Example
.. code-block:: python
from tgEasy import command, get_user_adv
@command("id")
async def id(client, message):
user = await get_user_adv(message)
await message.reply_text(f"Your ID is `{user.id}`")
"""
if isinstance(m, pyrogram.types.Message):
message = m
if isinstance(m, pyrogram.types.CallbackQuery):
message = m.message
if message.sender_chat:
return False
with contextlib.suppress(IndexError, AttributeError):
if len(message.command) > 1:
if message.command[1].startswith("@"):
return await get_user(message)
if message.command[1].isdigit():
return await get_user(message)
if "text_mention" in message.entities:
return await get_user(message)
if "from_user" in str(message.reply_to_message):
return await get_user(message)
with contextlib.suppress(Exception):
if "sender_chat" in str(message.reply_to_message):
return False
if "from_user" in str(message.reply_to_message):
return await message._client.get_users(
message.reply_to_message.from_user.id
)
return await message._client.get_users(message.from_user.id)

View file

@ -0,0 +1,86 @@
# tgEasy - Easy for a brighter Shine. A monkey pather add-on for Pyrogram
# Copyright (C) 2021 - 2022 Jayant Hegde Kageri <https://github.com/jayantkageri>
# This file is part of tgEasy.
# tgEasy is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# tgEasy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with tgEasy. If not, see <http://www.gnu.org/licenses/>.
import contextlib
import os
import typing
import logging
import pyrogram
import traceback
from datetime import datetime
from misskaty.vars import LOG_CHANNEL
async def handle_error(
error, m: typing.Union[pyrogram.types.Message, pyrogram.types.CallbackQuery]
):
"""
### `handle_error`
- A Function to Handle the Errors in Functions.
- This Sends the Error Log to the Log Group and Replies Sorry Message for the Users.
- This is Helper for all of the functions for handling the Errors.
- Parameters:
- error:
- The Exceptation.
- m (`pyrogram.types.Message` or `pyrogram.types.CallbackQuery`):
- The Message or Callback Query where the Error occurred.
#### Exapmle
.. code-block:: python
import pyrogram
app = tgClient(pyrogram.Client())
@app.command("start")
async def start(client, message):
try:
await message.reply_text("Hi :D') # I intentionally made an bug for Example :/
except Exceptation as e:
return await handle_error(e, message)
"""
logging = logging.getLogger(__name__)
logging.exception(traceback.format_exc())
day = datetime.now()
tgl_now = datetime.now()
cap_day = f"{day.strftime('%A')}, {tgl_now.strftime('%d %B %Y %H:%M:%S')}"
with open(f"crash_{tgl_now.strftime('%d %B %Y')}.txt", "w+", encoding="utf-8") as log:
log.write(traceback.format_exc())
log.close()
if isinstance(m, pyrogram.types.Message):
with contextlib.suppress(Exception):
await m.reply_text(
"An Internal Error Occurred while Processing your Command, the Logs have been sent to the Owners of this Bot. Sorry for Inconvenience"
)
await m._client.send_document(
LOG_CHANNEL, f"crash_{tgl_now.strftime('%d %B %Y')}.txt", caption=f"Crash Report of this Bot\n{cap_day}"
)
if isinstance(m, pyrogram.types.CallbackQuery):
with contextlib.suppress(Exception):
await m.message.delete()
await m.message.reply_text(
"An Internal Error Occurred while Processing your Command, the Logs have been sent to the Owners of this Bot. Sorry for Inconvenience"
)
await m.message._client.send_document(
LOG_CHANNEL, f"crash_{tgl_now.strftime('%d %B %Y')}.txt", caption=f"Crash Report of this Bot\n{cap_day}"
)
os.remove(f"crash_{tgl_now.strftime('%d %B %Y')}.txt")
return True

View file

@ -14,7 +14,6 @@ async def progress_for_pyrogram(current, total, ud_type, message, start, dc_id):
now = time.time() now = time.time()
diff = now - start diff = now - start
if round(diff % 10.00) == 0 or current == total: if round(diff % 10.00) == 0 or current == total:
# if round(current / total * 100, 0) % 5 == 0:
percentage = current * 100 / total percentage = current * 100 / total
elapsed_time = round(diff) elapsed_time = round(diff)
if elapsed_time == 0: if elapsed_time == 0:

View file

@ -106,7 +106,7 @@ async def admin_cache_func(_, cmu):
# Purge CMD # Purge CMD
@app.on_message(filters.command("purge", COMMAND_HANDLER) & filters.group) @app.on_cmd("purge")
@require_admin(permissions=["can_delete_messages"], allow_in_private=True) @require_admin(permissions=["can_delete_messages"], allow_in_private=True)
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -162,7 +162,7 @@ async def purge(self: Client, ctx: Message, strings) -> "Message":
# Kick members # Kick members
@app.on_message(filters.command(["kick", "dkick"], COMMAND_HANDLER) & filters.group) @app.on_cmd(["kick", "dkick"], group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -197,9 +197,7 @@ async def kickFunc(client: Client, ctx: Message, strings) -> "Message":
# Ban/DBan/TBan User # Ban/DBan/TBan User
@app.on_message( @app.on_cmd(["ban", "dban", "tban"], group_only=True)
filters.command(["ban", "dban", "tban"], COMMAND_HANDLER) & filters.group
)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -261,7 +259,7 @@ async def banFunc(client, message, strings):
# Unban members # Unban members
@app.on_message(filters.command("unban", COMMAND_HANDLER) & filters.group) @app.on_cmd("unban", group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -389,7 +387,7 @@ async def list_unban_(c, message, strings):
# Delete messages # Delete messages
@app.on_message(filters.command("del", COMMAND_HANDLER) & filters.group) @app.on_cmd("del", group_only=True)
@adminsOnly("can_delete_messages") @adminsOnly("can_delete_messages")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -406,9 +404,7 @@ async def deleteFunc(_, message, strings):
# Promote Members # Promote Members
@app.on_message( @app.on_cmd(["promote", "fullpromote"], group_only=True)
filters.command(["promote", "fullpromote"], COMMAND_HANDLER) & filters.group
)
@adminsOnly("can_promote_members") @adminsOnly("can_promote_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -462,7 +458,7 @@ async def promoteFunc(client, message, strings):
# Demote Member # Demote Member
@app.on_message(filters.command("demote", COMMAND_HANDLER) & filters.group) @app.on_cmd("demote", group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -494,7 +490,7 @@ async def demote(client, message, strings):
# Pin Messages # Pin Messages
@app.on_message(filters.command(["pin", "unpin"], COMMAND_HANDLER) & filters.group) @app.on_cmd(["pin", "unpin"])
@adminsOnly("can_pin_messages") @adminsOnly("can_pin_messages")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -524,7 +520,7 @@ async def pin(_, message, strings):
# Mute members # Mute members
@app.on_message(filters.command(["mute", "tmute"], COMMAND_HANDLER) & filters.group) @app.on_cmd(["mute", "tmute"], group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -577,7 +573,7 @@ async def mute(client, message, strings):
# Unmute members # Unmute members
@app.on_message(filters.command("unmute", COMMAND_HANDLER) & filters.group) @app.on_cmd("unmute", group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -592,7 +588,7 @@ async def unmute(_, message, strings):
await message.reply_text(strings("unmute_msg").format(umention=umention)) await message.reply_text(strings("unmute_msg").format(umention=umention))
@app.on_message(filters.command(["warn", "dwarn"], COMMAND_HANDLER) & filters.group) @app.on_cmd(["warn", "dwarn"], group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -711,7 +707,7 @@ async def unban_user(_, cq, strings):
# Remove Warn # Remove Warn
@app.on_message(filters.command("rmwarn", COMMAND_HANDLER) & filters.group) @app.on_cmd("rmwarn", group_only=True)
@adminsOnly("can_restrict_members") @adminsOnly("can_restrict_members")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
@ -734,8 +730,7 @@ async def remove_warnings(_, message, strings):
# Warns # Warns
@app.on_message(filters.command("warns", COMMAND_HANDLER) & filters.group) @app.on_cmd("warns", group_only=True)
@capture_err
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
async def check_warns(_, message, strings): async def check_warns(_, message, strings):
@ -766,7 +761,7 @@ async def check_warns(_, message, strings):
@capture_err @capture_err
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
async def report_user(self: Client, ctx: Message, strings) -> "Message": async def report_user(_, ctx: Message, strings) -> "Message":
if not ctx.reply_to_message: if not ctx.reply_to_message:
return await ctx.reply_text(strings("report_no_reply")) return await ctx.reply_text(strings("report_no_reply"))
reply = ctx.reply_to_message reply = ctx.reply_to_message
@ -804,9 +799,9 @@ async def report_user(self: Client, ctx: Message, strings) -> "Message":
await ctx.reply_msg(text, reply_to_message_id=ctx.reply_to_message.id) await ctx.reply_msg(text, reply_to_message_id=ctx.reply_to_message.id)
@app.on_message(filters.command("set_chat_title", COMMAND_HANDLER) & ~filters.private) @app.on_cmd("set_chat_title", group_only=True)
@adminsOnly("can_change_info") @adminsOnly("can_change_info")
async def set_chat_title(self: Client, ctx: Message): async def set_chat_title(_, ctx: Message):
if len(ctx.command) < 2: if len(ctx.command) < 2:
return await ctx.reply_text("**Usage:**\n/set_chat_title NEW NAME") return await ctx.reply_text("**Usage:**\n/set_chat_title NEW NAME")
old_title = ctx.chat.title old_title = ctx.chat.title
@ -817,9 +812,9 @@ async def set_chat_title(self: Client, ctx: Message):
) )
@app.on_message(filters.command("set_user_title", COMMAND_HANDLER) & ~filters.private) @app.on_cmd("set_user_title", group_only=True)
@adminsOnly("can_change_info") @adminsOnly("can_change_info")
async def set_user_title(self: Client, ctx: Message): async def set_user_title(_, ctx: Message):
if not ctx.reply_to_message: if not ctx.reply_to_message:
return await ctx.reply_text("Reply to user's message to set his admin title") return await ctx.reply_text("Reply to user's message to set his admin title")
if not ctx.reply_to_message.from_user: if not ctx.reply_to_message.from_user:
@ -837,9 +832,9 @@ async def set_user_title(self: Client, ctx: Message):
) )
@app.on_message(filters.command("set_chat_photo", COMMAND_HANDLER) & ~filters.private) @app.on_cmd("set_chat_photo", group_only=True)
@adminsOnly("can_change_info") @adminsOnly("can_change_info")
async def set_chat_photo(self: Client, ctx: Message): async def set_chat_photo(_, ctx: Message):
reply = ctx.reply_to_message reply = ctx.reply_to_message
if not reply: if not reply:

View file

@ -18,12 +18,10 @@ from pyrogram.types import Message
from database.afk_db import add_afk, cleanmode_off, cleanmode_on, is_afk, remove_afk from database.afk_db import add_afk, cleanmode_off, cleanmode_on, is_afk, remove_afk
from misskaty import app from misskaty import app
from misskaty.core.decorator.errors import capture_err
from misskaty.core.decorator.permissions import adminsOnly from misskaty.core.decorator.permissions import adminsOnly
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import get_readable_time2 from misskaty.helper import get_readable_time2
from misskaty.helper.localization import use_chat_lang from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER
from utils import put_cleanmode from utils import put_cleanmode
__MODULE__ = "AFK" __MODULE__ = "AFK"
@ -34,11 +32,10 @@ Just type something in group to remove AFK Status."""
# Handle set AFK Command # Handle set AFK Command
@capture_err @app.on_cmd("afk")
@app.on_message(filters.command(["afk"], COMMAND_HANDLER))
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
async def active_afk(self: Client, ctx: Message, strings): async def active_afk(_, ctx: Message, strings):
if ctx.sender_chat: if ctx.sender_chat:
return await ctx.reply_msg(strings("no_channel"), del_in=6) return await ctx.reply_msg(strings("no_channel"), del_in=6)
user_id = ctx.from_user.id user_id = ctx.from_user.id
@ -209,11 +206,11 @@ async def active_afk(self: Client, ctx: Message, strings):
await put_cleanmode(ctx.chat.id, send.id) await put_cleanmode(ctx.chat.id, send.id)
@app.on_message(filters.command("afkdel", COMMAND_HANDLER) & filters.group) @app.on_cmd("afkdel", group_only=True)
@ratelimiter @ratelimiter
@adminsOnly("can_change_info") @adminsOnly("can_change_info")
@use_chat_lang() @use_chat_lang()
async def afk_state(self: Client, ctx: Message, strings): async def afk_state(_, ctx: Message, strings):
if not ctx.from_user: if not ctx.from_user:
return return
if len(ctx.command) == 1: if len(ctx.command) == 1:

View file

@ -14,7 +14,7 @@ async def ban_reply(self: Client, ctx: Message):
return return
ban = await db.get_ban_status(ctx.from_user.id) ban = await db.get_ban_status(ctx.from_user.id)
if (ban.get("is_banned") and ctx.chat.type.value == "private") or ( if (ban.get("is_banned") and ctx.chat.type.value == "private") or (
ban.get("is_banned") and ctx.chat.type.value == "supergroup" and ctx.command ban.get("is_banned") and ctx.chat.type.value == "supergroup" and bool(ctx.command)
): ):
await ctx.reply_msg( await ctx.reply_msg(
f'I am sorry, You are banned to use Me. \nBan Reason: {ban["ban_reason"]}' f'I am sorry, You are banned to use Me. \nBan Reason: {ban["ban_reason"]}'

View file

@ -0,0 +1,120 @@
"""
MIT License
Copyright (c) 2023 TheHamkerCat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import re
from time import time
from pyrogram import filters
from pyrogram.types import ChatPermissions
from misskaty.core.decorator.errors import capture_err
from misskaty import app
from misskaty.vars import SUDO
from misskaty.core.decorator.permissions import adminsOnly
from misskaty.core.decorator.permissions import list_admins
from database.blacklist_db import (
delete_blacklist_filter,
get_blacklisted_words,
save_blacklist_filter,
)
__MODULE__ = "Blacklist"
__HELP__ = """
/blacklisted - Get All The Blacklisted Words In The Chat.
/blacklist [WORD|SENTENCE] - Blacklist A Word Or A Sentence.
/whitelist [WORD|SENTENCE] - Whitelist A Word Or A Sentence.
"""
@app.on_message(filters.command("blacklist") & ~filters.private)
@adminsOnly("can_restrict_members")
async def save_filters(_, message):
if len(message.command) < 2:
return await message.reply_text("Usage:\n/blacklist [WORD|SENTENCE]")
word = message.text.split(None, 1)[1].strip()
if not word:
return await message.reply_text("**Usage**\n__/blacklist [WORD|SENTENCE]__")
chat_id = message.chat.id
await save_blacklist_filter(chat_id, word)
await message.reply_text(f"__**Blacklisted {word}.**__")
@app.on_message(filters.command("blacklisted") & ~filters.private)
@capture_err
async def get_filterss(_, message):
data = await get_blacklisted_words(message.chat.id)
if not data:
await message.reply_text("**No blacklisted words in this chat.**")
else:
msg = f"List of blacklisted words in {message.chat.title} :\n"
for word in data:
msg += f"**-** `{word}`\n"
await message.reply_text(msg)
@app.on_message(filters.command("whitelist") & ~filters.private)
@adminsOnly("can_restrict_members")
async def del_filter(_, message):
if len(message.command) < 2:
return await message.reply_text("Usage:\n/whitelist [WORD|SENTENCE]")
word = message.text.split(None, 1)[1].strip()
if not word:
return await message.reply_text("Usage:\n/whitelist [WORD|SENTENCE]")
chat_id = message.chat.id
deleted = await delete_blacklist_filter(chat_id, word)
if deleted:
return await message.reply_text(f"**Whitelisted {word}.**")
await message.reply_text("**No such blacklist filter.**")
@app.on_message(filters.text & ~filters.private, group=8)
@capture_err
async def blacklist_filters_re(_, message):
text = message.text.lower().strip()
if not text:
return
chat_id = message.chat.id
user = message.from_user
if not user:
return
if user.id in SUDO:
return
list_of_filters = await get_blacklisted_words(chat_id)
for word in list_of_filters:
pattern = r"( |^|[^\w])" + re.escape(word) + r"( |$|[^\w])"
if re.search(pattern, text, flags=re.IGNORECASE):
if user.id in await list_admins(chat_id):
return
try:
await message.chat.restrict_member(
user.id,
ChatPermissions(),
until_date=int(time() + 3600),
)
except Exception:
return
return await app.send_message(
chat_id,
f"Muted {user.mention} [`{user.id}`] for 1 hour "
+ f"due to a blacklist match on {word}.",
)

View file

@ -7,7 +7,6 @@ import html
import openai import openai
from aiohttp import ClientSession from aiohttp import ClientSession
from pyrogram import Client, filters
from pyrogram.errors import MessageTooLong from pyrogram.errors import MessageTooLong
from pyrogram.types import Message from pyrogram.types import Message
@ -16,15 +15,16 @@ from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper import check_time_gap, post_to_telegraph from misskaty.helper import check_time_gap, post_to_telegraph
from misskaty.helper.http import http from misskaty.helper.http import http
from misskaty.helper.localization import use_chat_lang from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER, OPENAI_API, SUDO from misskaty.vars import OPENAI_API, SUDO
openai.api_key = OPENAI_API openai.api_key = OPENAI_API
# This only for testing things, since maybe in future it will got blocked # This only for testing things, since maybe in future it will got blocked
@app.on_message(filters.command("bard", COMMAND_HANDLER)) @app.on_cmd("bard", is_disabled=True)
@use_chat_lang() @use_chat_lang()
async def bard_chatbot(self: Client, ctx: Message, strings): @ratelimiter
async def bard_chatbot(_, ctx: Message, strings):
if len(ctx.command) == 1: if len(ctx.command) == 1:
return await ctx.reply_msg( return await ctx.reply_msg(
strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5 strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5
@ -41,10 +41,10 @@ async def bard_chatbot(self: Client, ctx: Message, strings):
await msg.edit_msg(str(e)) await msg.edit_msg(str(e))
@app.on_message(filters.command("ask", COMMAND_HANDLER)) @app.on_cmd("ask")
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
async def openai_chatbot(self: Client, ctx: Message, strings): async def openai_chatbot(_, ctx: Message, strings):
if len(ctx.command) == 1: if len(ctx.command) == 1:
return await ctx.reply_msg( return await ctx.reply_msg(
strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5 strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5

View file

@ -4,12 +4,12 @@
# * Copyright ©YasirPedia All rights reserved # * Copyright ©YasirPedia All rights reserved
import logging import logging
from pyrogram import Client, filters
from pyrogram.types import Message from pyrogram.types import Message
from misskaty import app from misskaty import app
from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.helper.http import http from misskaty.helper.http import http
from misskaty.vars import COMMAND_HANDLER, CURRENCY_API from misskaty.vars import CURRENCY_API
__MODULE__ = "Currency" __MODULE__ = "Currency"
__HELP__ = """ __HELP__ = """
@ -19,8 +19,9 @@ __HELP__ = """
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@app.on_message(filters.command(["currency"], COMMAND_HANDLER)) @app.on_cmd("currency")
async def currency(self: Client, ctx: Message): @ratelimiter
async def currency(_, ctx: Message):
if CURRENCY_API is None: if CURRENCY_API is None:
return await ctx.reply_msg( return await ctx.reply_msg(
"<code>Oops!!get the API from</code> <a href='https://app.exchangerate-api.com/sign-up'>HERE</a> <code>& add it to config vars</code> (<code>CURRENCY_API</code>)", "<code>Oops!!get the API from</code> <a href='https://app.exchangerate-api.com/sign-up'>HERE</a> <code>& add it to config vars</code> (<code>CURRENCY_API</code>)",
@ -32,10 +33,7 @@ async def currency(self: Client, ctx: Message):
del_in=6, del_in=6,
) )
teks = ctx.text.split() amount, currency_from, currency_to = ctx.text.split()
amount = teks[1]
currency_from = teks[2]
currency_to = teks[3]
if amount.isdigit() or ( if amount.isdigit() or (
amount.replace(".", "", 1).isdigit() and amount.count(".") < 2 amount.replace(".", "", 1).isdigit() and amount.count(".") < 2
): ):

View file

@ -20,7 +20,6 @@ from PIL import Image, ImageDraw, ImageFont
from psutil import Process, boot_time, cpu_count, cpu_percent from psutil import Process, boot_time, cpu_count, cpu_percent
from psutil import disk_usage as disk_usage_percent from psutil import disk_usage as disk_usage_percent
from psutil import net_io_counters, virtual_memory from psutil import net_io_counters, virtual_memory
from pykeyboard import InlineButton, InlineKeyboard
from pyrogram import Client from pyrogram import Client
from pyrogram import __version__ as pyrover from pyrogram import __version__ as pyrover
from pyrogram import enums, filters from pyrogram import enums, filters
@ -56,6 +55,7 @@ __HELP__ = """
/unbanuser [chat id] - Unban user and make their can use bot again /unbanuser [chat id] - Unban user and make their can use bot again
/gban - To Ban A User Globally. /gban - To Ban A User Globally.
/ungban - To remove ban user globbaly. /ungban - To remove ban user globbaly.
/restart - update and restart bot.
**For Public Use** **For Public Use**
/stats - Check statistic bot /stats - Check statistic bot
@ -493,17 +493,11 @@ async def cmd_eval(self: Client, ctx: Message, strings) -> Optional[str]:
# Update and restart bot # Update and restart bot
@app.on_message(filters.command(["update"], COMMAND_HANDLER) & filters.user(SUDO)) @app.on_message(filters.command(["restart"], COMMAND_HANDLER) & filters.user(SUDO))
@use_chat_lang() @use_chat_lang()
async def update_restart(self: Client, ctx: Message, strings) -> "Message": async def update_restart(self: Client, ctx: Message, strings) -> "Message":
try:
out = (await shell_exec("git pull"))[0]
if "Already up to date." in str(out):
return await ctx.reply_msg(strings("already_up"))
await ctx.reply_msg(f"<code>{out}</code>")
except Exception as e:
return await ctx.reply_msg(str(e))
msg = await ctx.reply_msg(strings("up_and_rest")) msg = await ctx.reply_msg(strings("up_and_rest"))
await shell_exec("python3 update.py")
with open("restart.pickle", "wb") as status: with open("restart.pickle", "wb") as status:
pickle.dump([ctx.chat.id, msg.id], status) pickle.dump([ctx.chat.id, msg.id], status)
os.execvp(sys.executable, [sys.executable, "-m", "misskaty"]) os.execvp(sys.executable, [sys.executable, "-m", "misskaty"])

View file

@ -142,7 +142,7 @@ async def clear_reqdict():
shutil.rmtree("GensSS", ignore_errors=True) shutil.rmtree("GensSS", ignore_errors=True)
# @app.on_message(filters.regex(r"makasi|thank|terimakasih|terima kasih|mksh", re.I) & filters.chat(chat)) @app.on_message(filters.regex(r"makasi|thank|terimakasih|terima kasih|mksh", re.I) & filters.chat(chat))
async def thankregex(_, message): async def thankregex(_, message):
pesan = [ pesan = [
f"Sama-sama {message.from_user.first_name}", f"Sama-sama {message.from_user.first_name}",

View file

@ -28,7 +28,7 @@ async def draw_meme_text(image_path, text):
current_h, pad = 10, 5 current_h, pad = 10, 5
if upper_text: if upper_text:
for u_text in textwrap.wrap(upper_text, width=15): for u_text in textwrap.wrap(upper_text, width=15):
u_width, u_height = draw.getbbox(u_text, font=m_font) u_width, u_height = draw.textsize(u_text, font=m_font)
draw.text( draw.text(
xy=(((i_width - u_width) / 2) - 1, int((current_h / 640) * i_width)), xy=(((i_width - u_width) / 2) - 1, int((current_h / 640) * i_width)),
@ -72,7 +72,7 @@ async def draw_meme_text(image_path, text):
current_h += u_height + pad current_h += u_height + pad
if lower_text: if lower_text:
for l_text in textwrap.wrap(lower_text, width=15): for l_text in textwrap.wrap(lower_text, width=15):
u_width, u_height = draw.getbbox(l_text, font=m_font) u_width, u_height = draw.textsize(l_text, font=m_font)
draw.text( draw.text(
xy=( xy=(

View file

@ -10,7 +10,7 @@ from urllib.parse import quote_plus
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from deep_translator import GoogleTranslator from deep_translator import GoogleTranslator
from pykeyboard import InlineButton, InlineKeyboard from pykeyboard import InlineButton, InlineKeyboard
from pyrogram import Client, enums, filters from pyrogram import Client, enums
from pyrogram.errors import ( from pyrogram.errors import (
MediaCaptionTooLong, MediaCaptionTooLong,
MediaEmpty, MediaEmpty,
@ -27,13 +27,11 @@ from pyrogram.types import (
Message, Message,
) )
from database.imdb_db import * from database.imdb_db import add_imdbset, is_imdbset, remove_imdbset
from misskaty import BOT_USERNAME, app from misskaty import app
from misskaty.core.decorator.errors import capture_err
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.core.misskaty_patch.listen.listen import ListenerTimeout from misskaty.core.misskaty_patch.listen.listen import ListenerTimeout
from misskaty.helper import GENRES_EMOJI, get_random_string, http, search_jw from misskaty.helper import GENRES_EMOJI, get_random_string, http, search_jw
from misskaty.vars import COMMAND_HANDLER
from utils import demoji from utils import demoji
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@ -44,10 +42,9 @@ headers = {
# IMDB Choose Language # IMDB Choose Language
@app.on_message(filters.command(["imdb"], COMMAND_HANDLER)) @app.on_cmd("imdb")
@capture_err
@ratelimiter @ratelimiter
async def imdb_choose(self: Client, ctx: Message): async def imdb_choose(_, ctx: Message):
if len(ctx.command) == 1: if len(ctx.command) == 1:
return await ctx.reply_msg( return await ctx.reply_msg(
f" Please add query after CMD!\nEx: <code>/{ctx.command[0]} Jurassic World</code>", f" Please add query after CMD!\nEx: <code>/{ctx.command[0]} Jurassic World</code>",
@ -91,10 +88,9 @@ async def imdb_choose(self: Client, ctx: Message):
pass pass
@app.on_callback_query(filters.regex("^imdbset")) @app.on_cb("imdbset")
@ratelimiter @ratelimiter
@capture_err async def imdblangset(_, query: CallbackQuery):
async def imdblangset(self: Client, query: CallbackQuery):
i, uid = query.data.split("#") i, uid = query.data.split("#")
if query.from_user.id != int(uid): if query.from_user.id != int(uid):
return await query.answer("⚠️ Access Denied!", True) return await query.answer("⚠️ Access Denied!", True)
@ -123,10 +119,9 @@ async def imdblangset(self: Client, query: CallbackQuery):
pass pass
@app.on_callback_query(filters.regex("^setimdb")) @app.on_cb("setimdb")
@ratelimiter @ratelimiter
@capture_err async def imdbsetlang(_, query: CallbackQuery):
async def imdbsetlang(self: Client, query: CallbackQuery):
i, lang, uid = query.data.split("#") i, lang, uid = query.data.split("#")
if query.from_user.id != int(uid): if query.from_user.id != int(uid):
return await query.answer("⚠️ Access Denied!", True) return await query.answer("⚠️ Access Denied!", True)
@ -278,10 +273,9 @@ async def imdb_search_en(kueri, message):
) )
@app.on_callback_query(filters.regex("^imdbcari")) @app.on_cb("imdbcari")
@ratelimiter @ratelimiter
@capture_err async def imdbcari(_, query: CallbackQuery):
async def imdbcari(self: Client, query: CallbackQuery):
BTN = [] BTN = []
i, lang, msg, uid = query.data.split("#") i, lang, msg, uid = query.data.split("#")
if lang == "ind": if lang == "ind":
@ -404,9 +398,8 @@ async def imdbcari(self: Client, query: CallbackQuery):
) )
@app.on_callback_query(filters.regex("^imdbres_id")) @app.on_cb("imdbres_id")
@ratelimiter @ratelimiter
@capture_err
async def imdb_id_callback(self: Client, query: CallbackQuery): async def imdb_id_callback(self: Client, query: CallbackQuery):
i, userid, movie = query.data.split("#") i, userid, movie = query.data.split("#")
if query.from_user.id != int(userid): if query.from_user.id != int(userid):
@ -515,7 +508,7 @@ async def imdb_id_callback(self: Client, query: CallbackQuery):
res_str += "\n" res_str += "\n"
if ott != "": if ott != "":
res_str += f"Tersedia di:\n{ott}\n" res_str += f"Tersedia di:\n{ott}\n"
res_str += f"<b>©️ IMDb by</b> @{BOT_USERNAME}" res_str += f"<b>©️ IMDb by</b> @{self.me.username}"
if trailer := r_json.get("trailer"): if trailer := r_json.get("trailer"):
trailer_url = trailer["url"] trailer_url = trailer["url"]
markup = InlineKeyboardMarkup( markup = InlineKeyboardMarkup(
@ -562,9 +555,8 @@ async def imdb_id_callback(self: Client, query: CallbackQuery):
pass pass
@app.on_callback_query(filters.regex("^imdbres_en")) @app.on_cb("imdbres_en")
@ratelimiter @ratelimiter
@capture_err
async def imdb_en_callback(self: Client, query: CallbackQuery): async def imdb_en_callback(self: Client, query: CallbackQuery):
i, userid, movie = query.data.split("#") i, userid, movie = query.data.split("#")
if query.from_user.id != int(userid): if query.from_user.id != int(userid):
@ -672,7 +664,7 @@ async def imdb_en_callback(self: Client, query: CallbackQuery):
res_str += "\n" res_str += "\n"
if ott != "": if ott != "":
res_str += f"Available On:\n{ott}\n" res_str += f"Available On:\n{ott}\n"
res_str += f"<b>©️ IMDb by</b> @{BOT_USERNAME}" res_str += f"<b>©️ IMDb by</b> @{self.me.username}"
if trailer := r_json.get("trailer"): if trailer := r_json.get("trailer"):
trailer_url = trailer["url"] trailer_url = trailer["url"]
markup = InlineKeyboardMarkup( markup = InlineKeyboardMarkup(

View file

@ -150,9 +150,7 @@ async def convertsrt(self: Client, ctx: Message, strings):
f"ConvertSub: {filename} by {ctx.from_user.first_name if ctx.from_user else ctx.sender_chat.title} [{ctx.from_user.id if ctx.from_user else ctx.sender_chat.id}]" f"ConvertSub: {filename} by {ctx.from_user.first_name if ctx.from_user else ctx.sender_chat.title} [{ctx.from_user.id if ctx.from_user else ctx.sender_chat.id}]"
) )
suffix = "srt" if ctx.command[0] == "converttosrt" else "ass" suffix = "srt" if ctx.command[0] == "converttosrt" else "ass"
(await shell_exec(f"ffmpeg -i '{dl}' 'downloads/{filename}.{suffix}'"))[ await shell_exec(f"ffmpeg -i '{dl}' 'downloads/{filename}.{suffix}'")
0
] # skipcq: PYL-W0106
c_time = time() c_time = time()
await ctx.reply_document( await ctx.reply_document(
f"downloads/{filename}.{suffix}", f"downloads/{filename}.{suffix}",

View file

@ -19,7 +19,12 @@ from gtts import gTTS
from PIL import Image from PIL import Image
from pyrogram import Client, filters from pyrogram import Client, filters
from pyrogram.errors import MessageTooLong, UserNotParticipant from pyrogram.errors import MessageTooLong, UserNotParticipant
from pyrogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup from pyrogram.types import (
CallbackQuery,
InlineKeyboardButton,
InlineKeyboardMarkup,
Message,
)
from misskaty import BOT_USERNAME, app from misskaty import BOT_USERNAME, app
from misskaty.core.decorator.errors import capture_err from misskaty.core.decorator.errors import capture_err
@ -33,6 +38,8 @@ LOGGER = getLogger(__name__)
__MODULE__ = "Misc" __MODULE__ = "Misc"
__HELP__ = """ __HELP__ = """
/carbon [text or reply to text or caption] - Make beautiful snippet code on carbon from text.
/kbbi [keyword] - Search definition on KBBI (For Indonesian People)
/sof [query] - Search your problem in StackOverflow. /sof [query] - Search your problem in StackOverflow.
/google [query] - Search using Google Search. /google [query] - Search using Google Search.
(/tr, /trans, /translate) [lang code] - Translate text using Google Translate. (/tr, /trans, /translate) [lang code] - Translate text using Google Translate.
@ -54,6 +61,70 @@ def remove_html_tags(text):
return re.sub(clean, "", text) return re.sub(clean, "", text)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edge/107.0.1418.42"
}
async def get_content(url):
async with aiohttp.ClientSession() as session:
r = await session.get(url, headers=headers)
return await r.read()
@app.on_cmd("kbbi")
async def kbbi_search(_, ctx: Client):
if len(ctx.command) == 1:
return await ctx.reply_msg("Please add keyword to search definition in kbbi")
r = (await http.get(f"https://yasirapi.eu.org/kbbi?kata={ctx.input}")).json()
if nomsg := r.get("detail"):
return await ctx.reply_msg(nomsg)
kbbi_btn = InlineKeyboardMarkup(
[[InlineKeyboardButton(text="Open in Web", url=r.get("link"))]]
)
res = "<b>Definisi:</b>\n"
for num, a in enumerate(r.get("result"), start=1):
submakna = "".join(f"{a}, " for a in a["makna"][0]["submakna"])[:-2]
contoh = "".join(f"{a}, " for a in a["makna"][0]["contoh"])[:-2]
kt_dasar = "".join(f"{a}, " for a in a["kata_dasar"])[:-2]
bt_takbaku = "".join(f"{a}, " for a in a["bentuk_tidak_baku"])[:-2]
res += f"<b>{a['nama']} ({a['makna'][0]['kelas'][0]['nama']}: {a['makna'][0]['kelas'][0]['deskripsi']})</b>\n<b>Kata Dasar:</b> {kt_dasar if kt_dasar else '-'}\n<b>Bentuk Tidak Baku:</b> {bt_takbaku if bt_takbaku else '-'}\n<b>Submakna:</b> {submakna}\n<b>Contoh:</b> {contoh if contoh else '-'}\n\n"
await ctx.reply(f"{res}<b>By YasirPedia API</b>", reply_markup=kbbi_btn)
@app.on_cmd("carbon")
async def carbon_make(self: Client, ctx: Message):
if len(ctx.command) == 1 and not ctx.reply_to_message:
return await ctx.reply(
"Please reply text to make carbon or add text after command."
)
if not ctx.reply_to_message:
return await ctx.reply(
"Please reply text to make carbon or add text after command."
)
if ctx.reply_to_message.text:
text = ctx.reply_to_message.text
elif ctx.reply_to_message.caption:
text = ctx.reply_to_message.caption
else:
text = ctx.input
json_data = {
"code": text,
"backgroundColor": "#1F816D",
}
response = await http.post(
"https://carbon.yasirapi.eu.org/api/cook", json=json_data
)
fname = (
f"carbonBY_{ctx.from_user.id if ctx.from_user else ctx.sender_chat.title}.png"
)
with open(fname, "wb") as e:
e.write(response.content)
await ctx.reply_photo(fname, caption=f"Generated by @{self.me.username}")
os.remove(fname)
@app.on_message(filters.command("readqr", COMMAND_HANDLER)) @app.on_message(filters.command("readqr", COMMAND_HANDLER))
@ratelimiter @ratelimiter
async def readqr(c, m): async def readqr(c, m):
@ -130,9 +201,6 @@ async def gsearch(client, message):
query = message.text.split(" ", maxsplit=1)[1] query = message.text.split(" ", maxsplit=1)[1]
msg = await message.reply_text(f"**Googling** for `{query}` ...") msg = await message.reply_text(f"**Googling** for `{query}` ...")
try: try:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edge/107.0.1418.42"
}
html = await http.get( html = await http.get(
f"https://www.google.com/search?q={query}&gl=id&hl=id&num=17", f"https://www.google.com/search?q={query}&gl=id&hl=id&num=17",
headers=headers, headers=headers,
@ -210,7 +278,7 @@ async def translate(client, message):
@app.on_message(filters.command(["tts"], COMMAND_HANDLER)) @app.on_message(filters.command(["tts"], COMMAND_HANDLER))
@capture_err @capture_err
@ratelimiter @ratelimiter
async def tts(_, message): async def tts_convert(_, message):
if message.reply_to_message and ( if message.reply_to_message and (
message.reply_to_message.text or message.reply_to_message.caption message.reply_to_message.text or message.reply_to_message.caption
): ):
@ -415,17 +483,6 @@ async def close_callback(bot: Client, query: CallbackQuery):
pass pass
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.1.17 (KHTML, like Gecko) Version/7.1 Safari/537.85.10"
}
async def get_content(url):
async with aiohttp.ClientSession() as session:
r = await session.get(url, headers=headers)
return await r.read()
async def mdlapi(title): async def mdlapi(title):
link = f"https://kuryana.vercel.app/search/q/{title}" link = f"https://kuryana.vercel.app/search/q/{title}"
async with aiohttp.ClientSession() as ses, ses.get(link) as result: async with aiohttp.ClientSession() as ses, ses.get(link) as result:

View file

@ -37,7 +37,7 @@ async def getTitleSub(msg, kueri, CurrentPage, user):
lists = soup.find("div", {"class": "search-result"}) lists = soup.find("div", {"class": "search-result"})
entry = lists.find_all("div", {"class": "title"}) entry = lists.find_all("div", {"class": "title"})
# if "Tidak Ditemukan" in entry[0].text: # if "Tidak Ditemukan" in entry[0].text:
# await editPesan(msg, f"Sorry, could not find any result for: {kueri}") # await msg.edit_msg(f"Sorry, could not find any result for: {kueri}")
# return None, 0, None # return None, 0, None
for sub in entry: for sub in entry:
title = sub.find("a").text title = sub.find("a").text

View file

@ -70,7 +70,7 @@ async def del_msg(client, message):
) )
# @user.on_edited_message(filters.text & filters.chat(-1001455886928)) @user.on_edited_message(filters.text & filters.chat(-1001455886928))
async def edit_msg(client, message): async def edit_msg(client, message):
try: try:
ustat = ( ustat = (

View file

@ -21,7 +21,6 @@ from pyrogram.types import (
from misskaty import app from misskaty import app
from misskaty.core.decorator.errors import capture_err from misskaty.core.decorator.errors import capture_err
from misskaty.core.decorator.ratelimiter import ratelimiter from misskaty.core.decorator.ratelimiter import ratelimiter
from misskaty.core.misskaty_patch.listen.listen import ListenerTimeout
from misskaty.helper.http import http from misskaty.helper.http import http
from misskaty.helper.localization import use_chat_lang from misskaty.helper.localization import use_chat_lang
from misskaty.vars import COMMAND_HANDLER, LOG_CHANNEL from misskaty.vars import COMMAND_HANDLER, LOG_CHANNEL
@ -35,13 +34,10 @@ def rand_key():
return str(uuid4())[:8] return str(uuid4())[:8]
@app.on_message(filters.command(["ytsearch"], COMMAND_HANDLER) & ~filters.channel) @app.on_cmd("ytsearch", no_channel=True)
@capture_err
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
async def ytsearch(self: Client, ctx: Message, strings): async def ytsearch(self: Client, ctx: Message, strings):
if ctx.sender_chat:
return await ctx.reply_msg(strings("no_channel"))
if len(ctx.command) == 1: if len(ctx.command) == 1:
return await ctx.reply_msg(strings("no_query")) return await ctx.reply_msg(strings("no_query"))
query = ctx.text.split(" ", maxsplit=1)[1] query = ctx.text.split(" ", maxsplit=1)[1]
@ -82,7 +78,7 @@ async def ytsearch(self: Client, ctx: Message, strings):
@app.on_message( @app.on_message(
filters.command(["ytdown"], COMMAND_HANDLER) filters.command(["ytdown"], COMMAND_HANDLER)
| filters.regex(YT_REGEX) & ~filters.channel | filters.regex(YT_REGEX) & ~filters.channel & ~filters.via_bot
) )
@capture_err @capture_err
@ratelimiter @ratelimiter
@ -110,7 +106,7 @@ async def ytdownv2(self: Client, ctx: Message, strings):
await ctx.reply_msg(f"Opps, ERROR: {str(err)}") await ctx.reply_msg(f"Opps, ERROR: {str(err)}")
@app.on_callback_query(filters.regex(r"^yt_listall")) @app.on_cb(filters.regex(r"^yt_listall"))
@ratelimiter @ratelimiter
@use_chat_lang() @use_chat_lang()
async def ytdl_listall_callback(self: Client, cq: CallbackQuery, strings): async def ytdl_listall_callback(self: Client, cq: CallbackQuery, strings):

View file

@ -2,14 +2,10 @@
# * @date 2023-06-21 22:12:27 # * @date 2023-06-21 22:12:27
# * @projectName MissKatyPyro # * @projectName MissKatyPyro
# * Copyright ©YasirPedia All rights reserved # * Copyright ©YasirPedia All rights reserved
import os
import sys import sys
from logging import getLogger from logging import getLogger
from os import environ from os import environ
import requests
from dotenv import load_dotenv
LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)

View file

@ -18,7 +18,7 @@ psutil
python-dateutil python-dateutil
telegraph telegraph
hachoir hachoir
Pillow==10.0.0 Pillow==9.5.0
httpx[http2] httpx[http2]
git+https://github.com/yasirarism/vcsi git+https://github.com/yasirarism/vcsi
git+https://github.com/yasirarism/iytdl git+https://github.com/yasirarism/iytdl

View file

@ -1,13 +1,26 @@
import logging from logging import INFO, StreamHandler, basicConfig, getLogger, handlers
import os import os
import subprocess import subprocess
import time
import dotenv import dotenv
import requests import requests
from git import Repo from git import Repo
LOGGER = logging.getLogger(__name__) if os.path.exists("MissKatyLogs.txt"):
with open("MissKatyLogs.txt", "r+") as f:
f.truncate(0)
basicConfig(
level=INFO,
format="[%(asctime)s - %(levelname)s] - %(name)s.%(funcName)s - %(message)s",
datefmt="%d-%b-%y %H:%M:%S",
handlers=[
handlers.RotatingFileHandler("MissKatyLogs.txt", mode="w+", maxBytes=1000000),
StreamHandler(),
],
)
LOGGER = getLogger(__name__)
ENV_URL = os.environ.get("ENV_URL") ENV_URL = os.environ.get("ENV_URL")
try: try:
@ -49,12 +62,6 @@ if all([UPSTREAM_REPO_URL, UPSTREAM_REPO_BRANCH]):
except Exception as e: except Exception as e:
LOGGER.error(e) LOGGER.error(e)
pass pass
# time.sleep(6)
# update = subprocess.run(['pip3', 'install', '-U', '-r', 'requirements.txt'])
# if update.returncode == 0:
# LOGGER.info("Successfully update package pip python")
# else:
# LOGGER.warning("Unsuccessfully update package pip python")
else: else:
LOGGER.warning( LOGGER.warning(
"UPSTREAM_REPO_URL or UPSTREAM_REPO_BRANCH is not defined, Skipping auto update" "UPSTREAM_REPO_URL or UPSTREAM_REPO_BRANCH is not defined, Skipping auto update"