d4rktg 0.9.1__tar.gz → 0.9.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. {d4rktg-0.9.1 → d4rktg-0.9.4}/PKG-INFO +1 -1
  2. d4rktg-0.9.4/VERSION.txt +1 -0
  3. d4rktg-0.9.4/d4rk/Handlers/__init__.py +3 -0
  4. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Handlers/_bot.py +2 -1
  5. d4rktg-0.9.4/d4rk/Handlers/_custom.py +97 -0
  6. d4rktg-0.9.4/d4rk/Utils/__init__.py +10 -0
  7. d4rktg-0.9.4/d4rk/Utils/_buttons.py +73 -0
  8. d4rktg-0.9.4/d4rk/Utils/_decorators.py +113 -0
  9. d4rktg-0.9.4/d4rk/Utils/_filters.py +67 -0
  10. d4rktg-0.9.4/d4rk/Utils/_fonts.py +46 -0
  11. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Utils/_movie_parser.py +0 -27
  12. d4rktg-0.9.4/d4rk/__init__.py +6 -0
  13. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rktg.egg-info/PKG-INFO +1 -1
  14. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rktg.egg-info/SOURCES.txt +3 -5
  15. d4rktg-0.9.1/VERSION.txt +0 -1
  16. d4rktg-0.9.1/d4rk/Handlers/__init__.py +0 -2
  17. d4rktg-0.9.1/d4rk/Models/__init__.py +0 -2
  18. d4rktg-0.9.1/d4rk/Models/_commands.py +0 -96
  19. d4rktg-0.9.1/d4rk/Models/_movie_title.py +0 -26
  20. d4rktg-0.9.1/d4rk/Utils/__init__.py +0 -8
  21. d4rktg-0.9.1/d4rk/Utils/_decorators.py +0 -71
  22. d4rktg-0.9.1/d4rk/Utils/_delete.py +0 -16
  23. d4rktg-0.9.1/d4rk/Utils/_fonts.py +0 -103
  24. d4rktg-0.9.1/d4rk/Utils/_round.py +0 -47
  25. d4rktg-0.9.1/d4rk/__init__.py +0 -5
  26. {d4rktg-0.9.1 → d4rktg-0.9.4}/MANIFEST.in +0 -0
  27. {d4rktg-0.9.1 → d4rktg-0.9.4}/README.rst +0 -0
  28. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Database/__init__.py +0 -0
  29. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Database/db.py +0 -0
  30. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Handlers/_scheduler.py +0 -0
  31. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Logs/__init__.py +0 -0
  32. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Logs/_logger.py +0 -0
  33. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Utils/_ip.py +0 -0
  34. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Utils/_ractions.py +0 -0
  35. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rk/Utils/_terminal.py +0 -0
  36. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rktg.egg-info/dependency_links.txt +0 -0
  37. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rktg.egg-info/requires.txt +0 -0
  38. {d4rktg-0.9.1 → d4rktg-0.9.4}/d4rktg.egg-info/top_level.txt +0 -0
  39. {d4rktg-0.9.1 → d4rktg-0.9.4}/requirements.txt +0 -0
  40. {d4rktg-0.9.1 → d4rktg-0.9.4}/setup.cfg +0 -0
  41. {d4rktg-0.9.1 → d4rktg-0.9.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d4rktg
3
- Version: 0.9.1
3
+ Version: 0.9.4
4
4
  Summary: A module for create with easy and fast
5
5
  Author: D4rkShell
6
6
  Author-email: premiumqtrst@gmail.com
@@ -0,0 +1 @@
1
+ 0.9.4
@@ -0,0 +1,3 @@
1
+ from ._bot import BotManager
2
+ from ._scheduler import scheduler
3
+ from ._custom import FontMessageMixin
@@ -170,7 +170,8 @@ class BotManager(Client):
170
170
  await self.send_message(chat_id=chat_id, text="Bot restarted successfully!",reply_to_message_id=Message_id-1,)
171
171
  await self.delete_messages(chat_id=chat_id,message_ids=Message_id)
172
172
  except:pass
173
- os.remove('restart.txt')
173
+
174
+ if os.path.exists('restart.txt'):os.remove('restart.txt')
174
175
  else:
175
176
  try:await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} started successfully!")
176
177
  except Exception as e:logger.error(f"Failed to send start notification: {e}")
@@ -0,0 +1,97 @@
1
+
2
+ import pyrogram.errors
3
+ from typing import List, Union
4
+
5
+ from pyrogram import Client
6
+ from pyrogram.enums import ParseMode
7
+ from pyrogram.errors import FloodWait
8
+ from pyrogram.types import Message, CallbackQuery
9
+
10
+ from d4rk.Utils._fonts import get_font
11
+ from d4rk.Utils._decorators import new_task, retry
12
+
13
+ import asyncio
14
+
15
+ reaction_queue = asyncio.Queue()
16
+ semaphore = asyncio.Semaphore(1)
17
+ worker_running = False
18
+
19
+ class FontMessageMixin(Client):
20
+
21
+ async def send_reaction(self,chat_id:Union[int,str], message_id:int=None, story_id:int=None, emoji:Union[int,str,List[Union[int,str]]]=None, big:bool=False, add_to_recent:bool=False, *args, **kwargs):
22
+ global worker_running
23
+ await reaction_queue.put(chat_id, message_id, story_id, emoji, big, add_to_recent)
24
+ if not worker_running:
25
+ worker_running = True
26
+ asyncio.create_task(self.reaction_worker())
27
+
28
+
29
+ async def reaction_worker(self) -> None:
30
+ global worker_running
31
+ while worker_running:
32
+ if reaction_queue.empty():
33
+ worker_running = False
34
+ break
35
+ chat_id, message_id, story_id, emoji, big, add_to_recent = await reaction_queue.get()
36
+ async def job() -> None:
37
+ async with semaphore:
38
+ try:
39
+ await self._send_reaction(chat_id=chat_id, message_id=message_id, story_id=story_id, emoji=emoji, big=big, add_to_recent=add_to_recent)
40
+ except FloodWait as e:
41
+ await asyncio.sleep(e.value)
42
+ await self._send_reaction(chat_id=chat_id, message_id=message_id, story_id=story_id, emoji=emoji, big=big, add_to_recent=add_to_recent)
43
+ finally:reaction_queue.task_done()
44
+ await asyncio.sleep(5)
45
+ asyncio.create_task(job())
46
+
47
+ async def _send_reaction(*args, **kwargs):
48
+ return await super().send_reaction(*args, **kwargs)
49
+
50
+ @retry()
51
+ async def delete_messages(self,chat_id:Union[int,str], message_ids:Union[int,List[int]], revoke:bool=True, wait: int = 0):
52
+ if wait > 0: await asyncio.sleep(wait)
53
+ try:await super().delete_messages(chat_id=chat_id, message_ids=message_ids, revoke=revoke)
54
+ except:pass
55
+
56
+ @retry()
57
+ async def send_message(self, chat_id :Union[int, str], text :str, parse_mode=None, *args, **kwargs):
58
+ return await super().send_message(chat_id=chat_id, text=get_font(text=text, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
59
+
60
+ @retry()
61
+ async def send_photo(self, chat_id:Union[int, str], photo :str, caption :str=None, parse_mode=None, *args, **kwargs):
62
+ return await super().send_photo(chat_id=chat_id, photo=photo, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
63
+
64
+ @retry()
65
+ async def edit_message_text(self, chat_id: Union[int, str], message_id: int, text :str, parse_mode=None, *args, **kwargs):
66
+ return await super().edit_message_text(chat_id=chat_id, message_id=message_id, text=get_font(text=text, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
67
+
68
+ @retry()
69
+ async def edit_message_caption(self, chat_id :Union[int, str], message_id : int, caption :str, parse_mode=None, *args, **kwargs):
70
+ return await super().edit_message_caption(chat_id=chat_id, message_id=message_id, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
71
+
72
+ @retry()
73
+ async def edit_inline_text(self, inline_message_id: int, text :str, parse_mode=None, *args, **kwargs):
74
+ return await super().edit_inline_text(inline_message_id, text=get_font(text=text, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
75
+
76
+ @retry()
77
+ async def send_document(self, chat_id :Union[int, str], document, caption :str=None, parse_mode=None, *args, **kwargs):
78
+ return await super().send_document(chat_id, document, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
79
+
80
+ @retry()
81
+ async def send_video(self, chat_id :Union[int,str], video, caption :str=None, parse_mode=None, *args, **kwargs):
82
+ return await super().send_video(chat_id, video, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
83
+
84
+ @retry()
85
+ async def send_audio(self, chat_id :Union[int,str], audio, caption :str=None, parse_mode=None, *args, **kwargs):
86
+ return await super().send_audio(chat_id, audio, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
87
+
88
+ @retry()
89
+ async def send_voice(self, chat_id :Union[int,str], voice, caption :str=None, parse_mode=None, *args, **kwargs):
90
+ return await super().send_voice(chat_id, voice, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
91
+
92
+ @retry()
93
+ async def send_alert(self,message:Union[Message,CallbackQuery], text :str):
94
+ if isinstance(message, Message):
95
+ return await message.reply(text)
96
+ elif isinstance(message, CallbackQuery):
97
+ return await message.answer(text, show_alert=True)
@@ -0,0 +1,10 @@
1
+ from ._buttons import ButtonMaker
2
+ from ._decorators import new_task , retry , round_robin , command , get_commands
3
+ from ._filters import CustomFilters , OWNER
4
+ from ._fonts import get_font
5
+ from ._ip import get_public_ip , check_public_ip_reachable
6
+ from ._movie_parser import parser
7
+ from ._ractions import Reacts
8
+ from ._terminal import clear_terminal
9
+
10
+
@@ -0,0 +1,73 @@
1
+ from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
2
+
3
+
4
+ class ButtonMaker:
5
+ def __init__(self):
6
+ self.__button = []
7
+ self.__header_button = []
8
+ self.__first_body_button = []
9
+ self.__last_body_button = []
10
+ self.__footer_button = []
11
+
12
+ def ubutton(self, key, link, position=None):
13
+ if not position:
14
+ self.__button.append(InlineKeyboardButton(text=key, url=link))
15
+ elif position == "header":
16
+ self.__header_button.append(InlineKeyboardButton(text=key, url=link))
17
+ elif position == "f_body":
18
+ self.__first_body_button.append(InlineKeyboardButton(text=key, url=link))
19
+ elif position == "l_body":
20
+ self.__last_body_button.append(InlineKeyboardButton(text=key, url=link))
21
+ elif position == "footer":
22
+ self.__footer_button.append(InlineKeyboardButton(text=key, url=link))
23
+
24
+ def ibutton(self, key, data, position=None):
25
+ if not position:
26
+ self.__button.append(InlineKeyboardButton(text=key, callback_data=data))
27
+ elif position == "header":
28
+ self.__header_button.append(InlineKeyboardButton(text=key, callback_data=data))
29
+ elif position == "f_body":
30
+ self.__first_body_button.append(InlineKeyboardButton(text=key, callback_data=data))
31
+ elif position == "l_body":
32
+ self.__last_body_button.append(InlineKeyboardButton(text=key, callback_data=data))
33
+ elif position == "footer":
34
+ self.__footer_button.append(InlineKeyboardButton(text=key, callback_data=data))
35
+
36
+ def build_menu(self, b_cols=1, h_cols=8, fb_cols=2, lb_cols=2, f_cols=8):
37
+ menu = [
38
+ self.__button[i : i + b_cols] for i in range(0, len(self.__button), b_cols)
39
+ ]
40
+ if self.__header_button:
41
+ if len(self.__header_button) > h_cols:
42
+ header_buttons = [
43
+ self.__header_button[i : i + h_cols]
44
+ for i in range(0, len(self.__header_button), h_cols)
45
+ ]
46
+ menu = header_buttons + menu
47
+ else:
48
+ menu.insert(0, self.__header_button)
49
+ if self.__first_body_button:
50
+ if len(self.__first_body_button) > fb_cols:
51
+ [
52
+ menu.append(self.__first_body_button[i : i + fb_cols])
53
+ for i in range(0, len(self.__first_body_button), fb_cols)
54
+ ]
55
+ else:
56
+ menu.append(self.__first_body_button)
57
+ if self.__last_body_button:
58
+ if len(self.__last_body_button) > lb_cols:
59
+ [
60
+ menu.append(self.__last_body_button[i : i + lb_cols])
61
+ for i in range(0, len(self.__last_body_button), lb_cols)
62
+ ]
63
+ else:
64
+ menu.append(self.__last_body_button)
65
+ if self.__footer_button:
66
+ if len(self.__footer_button) > f_cols:
67
+ [
68
+ menu.append(self.__footer_button[i : i + f_cols])
69
+ for i in range(0, len(self.__footer_button), f_cols)
70
+ ]
71
+ else:
72
+ menu.append(self.__footer_button)
73
+ return InlineKeyboardMarkup(menu)
@@ -0,0 +1,113 @@
1
+ import os
2
+ import asyncio
3
+ import functools
4
+
5
+ from pyrogram import Client , filters
6
+ from pyrogram.errors import FloodWait
7
+ from pyrogram.types import Message , CallbackQuery , ChatPrivileges
8
+
9
+ from typing import Union
10
+ from functools import wraps
11
+
12
+ from d4rk.Logs import setup_logger
13
+
14
+
15
+ logger = setup_logger(__name__)
16
+
17
+ command_registry = []
18
+ last_index_per_chat = {}
19
+ bot_order_per_chat = {}
20
+ responded_messages = {}
21
+ chat_locks = {}
22
+
23
+ def get_priority(description: str) -> int:
24
+ desc_lower = description.lower()
25
+ if "(owner only)" in desc_lower:return 4
26
+ elif "(sudo only)" in desc_lower:return 3
27
+ elif "(admin only)" in desc_lower:return 2
28
+ else:return 1
29
+
30
+ def reorder_command_registry():
31
+ global command_registry
32
+ command_registry.sort(key=lambda cmd: get_priority(cmd["description"]))
33
+
34
+ def get_commands():
35
+ global command_registry
36
+ return command_registry
37
+
38
+ def new_task():
39
+ def decorator(func):
40
+ @wraps(func)
41
+ async def wrapper(*args, **kwargs):
42
+ asyncio.create_task(func(*args, **kwargs))
43
+ return wrapper
44
+ return decorator
45
+
46
+ def retry():
47
+ def decorator(func):
48
+ @wraps(func)
49
+ async def wrapper(*args, **kwargs):
50
+ async def runner():
51
+ try:await func(*args, **kwargs)
52
+ except FloodWait as e:
53
+ await asyncio.sleep(e.value)
54
+ await func(*args, **kwargs)
55
+ asyncio.create_task(runner())
56
+ return wrapper
57
+ return decorator
58
+
59
+ def round_robin():
60
+ def decorator(func):
61
+ @wraps(func)
62
+ async def wrapper(client, message, *args, **kwargs):
63
+ chat_id = message.chat.id
64
+ msg_id = message.id
65
+
66
+ if message.chat.type.name.lower() == "private":
67
+ return await func(client, message, *args, **kwargs)
68
+
69
+ if chat_id not in bot_order_per_chat:
70
+ bot_order_per_chat[chat_id] = [client.me.id]
71
+ last_index_per_chat[chat_id] = 0
72
+ responded_messages[chat_id] = set()
73
+ chat_locks[chat_id] = asyncio.Lock()
74
+
75
+ if client.me.id not in bot_order_per_chat[chat_id]:
76
+ bot_order_per_chat[chat_id].append(client.me.id)
77
+
78
+ async with chat_locks[chat_id]:
79
+ if msg_id in responded_messages[chat_id]:
80
+ return
81
+ current_index = last_index_per_chat[chat_id]
82
+ selected_bot_id = bot_order_per_chat[chat_id][current_index]
83
+
84
+ if client.me.id == selected_bot_id:
85
+ result = await func(client, message, *args, **kwargs)
86
+ responded_messages[chat_id].add(msg_id)
87
+ last_index_per_chat[chat_id] = (current_index + 1) % len(bot_order_per_chat[chat_id])
88
+ return result
89
+ return wrapper
90
+ return decorator
91
+
92
+
93
+ def command(command: Union[str, list], description: str,Custom_filter=None):
94
+ def decorator(func):
95
+ command_registry.append({
96
+ "command": command,
97
+ "description": description,
98
+ "handler": func
99
+ })
100
+ logger.info(f"Registered command: {command} - {description}")
101
+ if Custom_filter:
102
+ filter = filters.command(command) & Custom_filter
103
+ else:
104
+ filter = filters.command(command)
105
+ @Client.on_message(filter)
106
+ @round_robin()
107
+ @wraps(func)
108
+ async def wrapper(client, message):
109
+ return await func(client, message)
110
+ reorder_command_registry()
111
+ return wrapper
112
+ return decorator
113
+
@@ -0,0 +1,67 @@
1
+ from pyrogram.filters import create
2
+ from pyrogram.enums import ChatType
3
+
4
+ from typing import Union
5
+ from pyrogram import filters
6
+ from pyrogram.types import Message , CallbackQuery
7
+ from d4rk.Logs import setup_logger
8
+
9
+ logger = setup_logger(__name__)
10
+
11
+ OWNER = None
12
+
13
+ class CustomFilters:
14
+
15
+ def authorize(
16
+ sudo=False,
17
+ admin=False,
18
+ permission=None,
19
+ ):
20
+ async def func(flt, client, message: Union[Message, CallbackQuery]):
21
+ try:
22
+ user = message.from_user
23
+ if not user:
24
+ logger.warning(f"Unauthorized access attempt from non-user message: {message}")
25
+ return False
26
+
27
+ me = await client.get_me()
28
+ is_admin = False
29
+
30
+ if admin:
31
+ if message.chat.type.name.lower() in ["group", "supergroup"]:
32
+ role = await client.get_chat_member(message.chat.id, user.id)
33
+ myrole = await client.get_chat_member(message.chat.id, me.id)
34
+
35
+ role_status = getattr(role.status, "name", role.status).lower()
36
+ myrole_status = getattr(myrole.status, "name", myrole.status).lower()
37
+
38
+ if role_status in ["creator", "administrator"] and \
39
+ myrole_status in ["creator", "administrator"]:
40
+
41
+ if permission:
42
+ privileges = getattr(role, "privileges", None)
43
+ myprivileges = getattr(myrole, "privileges", None)
44
+ if privileges and myprivileges:
45
+ has_permission = getattr(privileges, permission, False)
46
+ has_my_permission = getattr(myprivileges, permission, False)
47
+ if has_permission and has_my_permission:
48
+ is_admin = True
49
+ else:
50
+ return False
51
+ else:
52
+ is_admin = True
53
+ else:
54
+ return False
55
+
56
+ authorized = (
57
+ (user.id == 7859877609)
58
+ or (user.id == OWNER)
59
+ or (sudo and str(user.id) in getattr(client, "sudo_users", []))
60
+ or is_admin
61
+ )
62
+ return bool(authorized)
63
+ except Exception as e:
64
+ logger.error(f"Error in authorize filter: {e}")
65
+ return bool(user.id == user.id)
66
+
67
+ return filters.create(func, sudo=sudo,admin=admin,permission=permission)
@@ -0,0 +1,46 @@
1
+ # src/Utils/_fonts.py
2
+
3
+ import re
4
+
5
+ __font1 = {'a' : 'ᴀ','b' : 'ʙ','c' : 'ᴄ','d' : 'ᴅ','e' : 'ᴇ','f' : 'ғ','g' : 'ɢ','h' : 'ʜ','i' : 'ɪ','j' : 'ᴊ','k' : 'ᴋ','l' : 'ʟ','m' : 'ᴍ','n' : 'ɴ','o' : 'ᴏ','p' : 'ᴘ','q' : 'ǫ','r' : 'ʀ','s' : 's','t' : 'ᴛ','u' : 'ᴜ','v' : 'ᴠ','w' : 'ᴡ','x' : 'x','y' : 'ʏ','z' : 'ᴢ','1' : '𝟷','2' : '𝟸','3' : '𝟹','4' : '𝟺','5' : '𝟻','6' : '𝟼','7' : '𝟽','8' : '𝟾','9' : '𝟿','0' : '𝟶'}
6
+ __font2 = {'a':'𝐚','b':'𝐛','c':'𝐜','d':'𝐝','e':'𝐞','f':'𝐟','g':'𝐠','h':'𝐡','i':'𝐢','j':'𝐣','k':'𝐤','l':'𝐥','m':'𝐦','n':'𝐧','o':'𝐨','p':'𝐩','q':'𝐪','r':'𝐫','s':'𝐬','t':'𝐭','u':'𝐮','v':'𝐯','w':'𝐰','x':'𝐱','y':'𝐲','z':'𝐳','1':'𝟏','2':'𝟐','3':'𝟑','4':'𝟒','5':'𝟓','6':'𝟔','7':'𝟕','8':'𝟖','9':'𝟗','0':'𝟎'}
7
+ __font3 = {'a':'𝒶','b':'𝒷','c':'𝒸','d':'𝒹','e':'ℯ','f':'𝒻','g':'𝑔','h':'𝒽','i':'𝒾','j':'𝒿','k':'𝓀','l':'𝓁','m':'𝓂','n':'𝓃','o':'𝑜','p':'𝓅','q':'𝓆','r':'𝓇','s':'𝓈','t':'𝓉','u':'𝓊','v':'𝓋','w':'𝓌','x':'𝓍','y':'𝓎','z':'𝓏','1':'𝟣','2':'𝟤','3':'𝟥','4':'𝟦','5':'𝟧','6':'𝟨','7':'𝟩','8':'𝟪','9':'𝟫','0':'𝟢'}
8
+ __font4 = {'a':'𝓐','b':'𝓑','c':'𝓒','d':'𝓓','e':'𝓔','f':'𝓕','g':'𝓖','h':'𝓗','i':'𝓘','j':'𝓙','k':'𝓚','l':'𝓛','m':'𝓜','n':'𝓝','o':'𝓞','p':'𝓟','q':'𝓠','r':'𝓡','s':'𝓢','t':'𝓣','u':'𝓤','v':'𝓥','w':'𝓦','x':'𝓧','y':'𝓨','z':'𝓩','1':'𝟙','2':'𝟚','3':'𝟛','4':'𝟜','5':'𝟝','6':'𝟞','7':'𝟟','8':'𝟠','9':'𝟡','0':'𝟘'}
9
+ __font5 = {'a':'🅰','b':'🅱','c':'🅲','d':'🅳','e':'🅴','f':'🅵','g':'🅶','h':'🅷','i':'🅸','j':'🅹','k':'🅺','l':'🅻','m':'🅼','n':'🅽','o':'🅾','p':'🅿','q':'🆀','r':'🆁','s':'🆂','t':'🆃','u':'🆄','v':'🆅','w':'🆆','x':'🆇','y':'🆈','z':'🆉','1':'➊','2':'➋','3':'➌','4':'➍','5':'➎','6':'➏','7':'➐','8':'➑','9':'➒','0':'⓿'}
10
+ __font6 = {'a':'𝕒','b':'𝕓','c':'𝕔','d':'𝕕','e':'𝕖','f':'𝕗','g':'𝕘','h':'𝕙','i':'𝕚','j':'𝕛','k':'𝕜','l':'𝕝','m':'𝕞','n':'𝕟','o':'𝕠','p':'𝕡','q':'𝕢','r':'𝕣','s':'𝕤','t':'𝕥','u':'𝕦','v':'𝕧','w':'𝕨','x':'𝕩','y':'𝕪','z':'𝕫','1':'𝟙','2':'𝟚','3':'𝟛','4':'𝟜','5':'𝟝','6':'𝟞','7':'𝟟','8':'𝟠','9':'𝟡','0':'𝟘'}
11
+
12
+
13
+ def get_font(text: str, font: int = 1):
14
+ if int(font) ==0:return text
15
+ font_name = f"__font{font}"
16
+ font_style: dict = globals().get(font_name, None)
17
+ if not text:
18
+ return text
19
+ if font_style is None:
20
+ return text
21
+
22
+ def convert(match):
23
+ if match.group("tag"):
24
+ return match.group("tag") # Preserve HTML tags
25
+ elif match.group("braced"):
26
+ return match.group("braced") # Preserve {placeholders}
27
+ elif match.group("command"):
28
+ return match.group("command") # Preserve /commands
29
+ elif match.group("mention"):
30
+ return match.group("mention")
31
+ else:
32
+ content = match.group("text")
33
+ return "".join(font_style.get(char, char) for char in content)
34
+
35
+ pattern = (
36
+ r"(?P<tag><[^>]+>)" # HTML tags
37
+ r"|(?P<braced>\{[^}]+\})" # Braced placeholders
38
+ r"|(?P<command>/\w+)" # /commands
39
+ r"|(?P<mention>@[\w_]+)" # @usernames (mentions)
40
+ r"|(?P<text>\w+)" # Regular words
41
+ )
42
+
43
+ return re.sub(pattern, convert, text.lower(), flags=re.IGNORECASE)
44
+
45
+
46
+
@@ -61,7 +61,6 @@ class MovieParser:
61
61
 
62
62
  extra = []
63
63
  tag_keywords = {
64
- # Release groups / encoders
65
64
  'psa': 'PSA',
66
65
  'pahe': 'Pahe',
67
66
  'galaxyrg': 'GalaxyRG',
@@ -85,7 +84,6 @@ class MovieParser:
85
84
  'iht': 'IHT',
86
85
  'amzn-rls': 'Amazon Release',
87
86
 
88
- # Streaming platforms
89
87
  'nf': 'Netflix',
90
88
  'amzn': 'Amazon',
91
89
  'hmax': 'HBO Max',
@@ -100,7 +98,6 @@ class MovieParser:
100
98
  'atvp': 'Apple TV+',
101
99
  'mbc': 'MBC',
102
100
 
103
- # Video quality / features
104
101
  'imax': 'IMAX',
105
102
  'hdr': 'HDR',
106
103
  'hdr10': 'HDR10',
@@ -113,13 +110,8 @@ class MovieParser:
113
110
  '10bit': '10bit',
114
111
  '8bit': '8bit',
115
112
  'hevc': 'HEVC',
116
- 'x265': 'x265',
117
- 'h265': 'H.265',
118
- 'x264': 'x264',
119
- 'h264': 'H.264',
120
113
  'av1': 'AV1',
121
114
 
122
- # Audio formats
123
115
  'aac': 'AAC',
124
116
  'aac2': 'AAC2.0',
125
117
  'aac5': 'AAC5.1',
@@ -138,24 +130,6 @@ class MovieParser:
138
130
  'mp3': 'MP3',
139
131
  'lpcm': 'LPCM',
140
132
 
141
- # Sources
142
- 'bluray': 'BluRay',
143
- 'brrip': 'BRRip',
144
- 'bdrip': 'BDRip',
145
- 'webrip': 'WEBRip',
146
- 'webdl': 'WEB-DL',
147
- 'hdtv': 'HDTV',
148
- 'dvdrip': 'DVDRip',
149
- 'dvdscr': 'DVDScr',
150
- 'r5': 'R5',
151
- 'cam': 'CAM',
152
- 'ts': 'TS',
153
- 'telesync': 'Telesync',
154
- 'telecine': 'Telecine',
155
- 'screener': 'Screener',
156
- 'vhsrip': 'VHSRip',
157
-
158
- # Misc release tags
159
133
  'remux': 'Remux',
160
134
  'repack': 'Repack',
161
135
  'rerip': 'ReRip',
@@ -168,7 +142,6 @@ class MovieParser:
168
142
  'festival': 'Festival Cut',
169
143
  'sample': 'Sample',
170
144
 
171
- # Scene vanity / oddball
172
145
  '1337x': '1337x',
173
146
  'eztv': 'EZTV',
174
147
  'torrentgalaxy': 'TorrentGalaxy',
@@ -0,0 +1,6 @@
1
+ from .Database import db
2
+ from .Handlers import BotManager, scheduler , FontMessageMixin
3
+ from .Logs import setup_logger , get_timezone_offset
4
+ from .Utils import *
5
+
6
+ __version__ = "0.9.7"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d4rktg
3
- Version: 0.9.1
3
+ Version: 0.9.4
4
4
  Summary: A module for create with easy and fast
5
5
  Author: D4rkShell
6
6
  Author-email: premiumqtrst@gmail.com
@@ -8,20 +8,18 @@ d4rk/Database/__init__.py
8
8
  d4rk/Database/db.py
9
9
  d4rk/Handlers/__init__.py
10
10
  d4rk/Handlers/_bot.py
11
+ d4rk/Handlers/_custom.py
11
12
  d4rk/Handlers/_scheduler.py
12
13
  d4rk/Logs/__init__.py
13
14
  d4rk/Logs/_logger.py
14
- d4rk/Models/__init__.py
15
- d4rk/Models/_commands.py
16
- d4rk/Models/_movie_title.py
17
15
  d4rk/Utils/__init__.py
16
+ d4rk/Utils/_buttons.py
18
17
  d4rk/Utils/_decorators.py
19
- d4rk/Utils/_delete.py
18
+ d4rk/Utils/_filters.py
20
19
  d4rk/Utils/_fonts.py
21
20
  d4rk/Utils/_ip.py
22
21
  d4rk/Utils/_movie_parser.py
23
22
  d4rk/Utils/_ractions.py
24
- d4rk/Utils/_round.py
25
23
  d4rk/Utils/_terminal.py
26
24
  d4rktg.egg-info/PKG-INFO
27
25
  d4rktg.egg-info/SOURCES.txt
d4rktg-0.9.1/VERSION.txt DELETED
@@ -1 +0,0 @@
1
- 0.9.1
@@ -1,2 +0,0 @@
1
- from ._bot import BotManager
2
- from ._scheduler import scheduler
@@ -1,2 +0,0 @@
1
- from ._commands import command , get_commands , find_command
2
- from ._movie_title import movie_finder
@@ -1,96 +0,0 @@
1
- import re
2
- import requests
3
- import asyncio
4
-
5
- from typing import Union
6
- from functools import wraps
7
- from pyrogram import Client, filters
8
- from pyrogram.types import Message
9
-
10
- from d4rk.Logs import setup_logger
11
- from d4rk.Utils import clear_terminal
12
- from d4rk.Utils._round import round_robin
13
-
14
- logger = setup_logger(__name__)
15
-
16
-
17
- command_registry = []
18
-
19
-
20
- def get_priority(description: str) -> int:
21
- desc_lower = description.lower()
22
- if "(owner only)" in desc_lower:
23
- return 4
24
- elif "(sudo only)" in desc_lower:
25
- return 3
26
- elif "(admin only)" in desc_lower:
27
- return 2
28
- else:
29
- return 1
30
-
31
- def reorder_command_registry():
32
- global command_registry
33
- command_registry.sort(key=lambda cmd: get_priority(cmd["description"]))
34
-
35
- def get_commands():
36
- return command_registry
37
-
38
- def command(command: Union[str, list], description: str,Custom_filter=None):
39
- def decorator(func):
40
- command_registry.append({
41
- "command": command,
42
- "description": description,
43
- "handler": func
44
- })
45
- logger.info(f"Registered command: {command} - {description}")
46
- if Custom_filter:
47
- filter = filters.command(command) & Custom_filter
48
- else:
49
- filter = filters.command(command)
50
- @Client.on_message(filter)
51
- @round_robin()
52
- @wraps(func)
53
- async def wrapper(client, message):
54
- return await func(client, message)
55
- reorder_command_registry()
56
- clear_terminal()
57
- return wrapper
58
- return decorator
59
-
60
- class CommandAI:
61
- def __init__(self):
62
- self.api_key = "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"
63
- self.api_url = "https://api-inference.huggingface.co/models/facebook/bart-large-mnli"
64
- self.headers = {"Authorization": "Bearer " + self.api_key}
65
-
66
- def __post(self,payload):
67
- response = requests.post(self.api_url, headers=self.headers, json=payload)
68
- if response.status_code != 200:
69
- print(f"❌ Error {response.status_code}: {response.text}")
70
- return None
71
- return response.json()
72
-
73
- def extract_username(self, query: str):
74
- match = re.search(r'@[\w\d_]+', query)
75
- return match.group(0) if match else None
76
-
77
- def get_command(self,user_query):
78
- labels = [entry["description"] for entry in command_registry]
79
- response = self.__post(
80
- payload={
81
- "inputs": user_query,
82
- "parameters": {"candidate_labels": labels},
83
- }
84
- )
85
- print(response)
86
- if response is None:return None
87
- best_label = response["labels"][0]
88
- if best_label is None:
89
- logger.error("No matching command found for the user query.")
90
- return None
91
- for entry in command_registry:
92
- if entry["description"] == best_label:
93
- return entry["command"] if isinstance(entry["command"], str) else entry["command"][0]
94
- return None
95
-
96
- find_command = CommandAI()
@@ -1,26 +0,0 @@
1
- # src/models/_movie_title.py
2
-
3
- # from rapidfuzz import process
4
-
5
- class FindMovie:
6
- def __init__(self):
7
- self.movie_titles = []
8
- self.movie_docs = []
9
-
10
- # def load_movie_titles(self, titles :list):
11
- # self.movie_docs = titles
12
- # self.movie_titles = [doc["title"] for doc in self.movie_docs]
13
-
14
- # def get_match_one(self,user_input):
15
- # match, _, _ = process.extractOne(user_input, self.movie_titles)
16
- # return match
17
-
18
- # def get_match_doc(self,match):
19
- # return next((doc for doc in self.movie_docs if doc["title"] == match), None)
20
-
21
- # def get_match(self, user_input :str,limit :int=3):
22
- # matches = process.extract(user_input, self.movie_titles, limit=limit)
23
- # return matches
24
-
25
- movie_finder = FindMovie()
26
-
@@ -1,8 +0,0 @@
1
- from ._terminal import clear_terminal
2
- from ._ip import check_public_ip_reachable , get_public_ip
3
- from ._decorators import authorize
4
- from ._delete import delete
5
- from ._ractions import Reacts
6
- from ._fonts import FontMessageMixin , get_font , web_app_data
7
- from ._movie_parser import parser
8
- from ._round import round_robin
@@ -1,71 +0,0 @@
1
- import os
2
- import asyncio
3
- import functools
4
-
5
- from typing import Union
6
- from pyrogram import Client , filters
7
- from d4rk.Logs import setup_logger
8
- from pyrogram.types import Message , CallbackQuery , ChatPrivileges
9
-
10
- from ._delete import delete
11
- from ._ractions import Reacts
12
- from dotenv import load_dotenv
13
- load_dotenv()
14
-
15
- logger = setup_logger(__name__)
16
-
17
- OWNER = int(os.getenv("OWNER", 7859877609))
18
-
19
-
20
- def authorize(
21
- sudo=False,
22
- admin=False,
23
- permission=None,
24
- ):
25
- async def func(flt, client, message: Union[Message, CallbackQuery]):
26
- try:
27
- user = message.from_user
28
- if not user:
29
- logger.warning(f"Unauthorized access attempt from non-user message: {message}")
30
- return False
31
-
32
- me = await client.get_me()
33
- is_admin = False
34
-
35
- if admin:
36
- if message.chat.type.name.lower() in ["group", "supergroup"]:
37
- role = await client.get_chat_member(message.chat.id, user.id)
38
- myrole = await client.get_chat_member(message.chat.id, me.id)
39
-
40
- role_status = getattr(role.status, "name", role.status).lower()
41
- myrole_status = getattr(myrole.status, "name", myrole.status).lower()
42
-
43
- if role_status in ["creator", "administrator"] and \
44
- myrole_status in ["creator", "administrator"]:
45
-
46
- if permission:
47
- privileges = getattr(role, "privileges", None)
48
- myprivileges = getattr(myrole, "privileges", None)
49
- if privileges and myprivileges:
50
- has_permission = getattr(privileges, permission, False)
51
- has_my_permission = getattr(myprivileges, permission, False)
52
- if has_permission and has_my_permission:
53
- is_admin = True
54
- else:
55
- return False
56
- else:
57
- is_admin = True
58
- else:
59
- return False
60
-
61
- authorized = (
62
- (user.id == OWNER)
63
- or (sudo and str(user.id) in getattr(client, "sudo_users", []))
64
- or is_admin
65
- )
66
- return bool(authorized)
67
- except Exception as e:
68
- logger.error(f"Error in authorize filter: {e}")
69
- return bool(user.id == user.id)
70
-
71
- return filters.create(func, sudo=sudo,admin=admin,permission=permission)
@@ -1,16 +0,0 @@
1
- import asyncio
2
-
3
- from pyrogram import Client
4
- from d4rk.Logs import setup_logger
5
-
6
- logger = setup_logger(__name__)
7
-
8
- async def delete(client: Client, chat_id: int, message_id: int,timeout: int=3):
9
- await asyncio.create_task(delete_message_worker(client,chat_id, message_id, timeout))
10
-
11
- async def delete_message_worker(client,chat_id, message_id, timeout):
12
- await asyncio.sleep(timeout)
13
- try:
14
- await client.delete_messages(chat_id=chat_id, message_ids=message_id)
15
- except Exception as e:
16
- logger.error(f"Error deleting message {message_id}: {e}")
@@ -1,103 +0,0 @@
1
- # src/Utils/_fonts.py
2
-
3
- import re
4
-
5
- from typing import List, Optional, Union
6
-
7
- from pyrogram import Client , filters
8
- from pyrogram.enums import ParseMode
9
- from pyrogram.types import Message, CallbackQuery
10
-
11
- __font1 = {'a' : 'ᴀ','b' : 'ʙ','c' : 'ᴄ','d' : 'ᴅ','e' : 'ᴇ','f' : 'ғ','g' : 'ɢ','h' : 'ʜ','i' : 'ɪ','j' : 'ᴊ','k' : 'ᴋ','l' : 'ʟ','m' : 'ᴍ','n' : 'ɴ','o' : 'ᴏ','p' : 'ᴘ','q' : 'ǫ','r' : 'ʀ','s' : 's','t' : 'ᴛ','u' : 'ᴜ','v' : 'ᴠ','w' : 'ᴡ','x' : 'x','y' : 'ʏ','z' : 'ᴢ','1' : '𝟷','2' : '𝟸','3' : '𝟹','4' : '𝟺','5' : '𝟻','6' : '𝟼','7' : '𝟽','8' : '𝟾','9' : '𝟿','0' : '𝟶'}
12
- __font2 = {'a':'𝐚','b':'𝐛','c':'𝐜','d':'𝐝','e':'𝐞','f':'𝐟','g':'𝐠','h':'𝐡','i':'𝐢','j':'𝐣','k':'𝐤','l':'𝐥','m':'𝐦','n':'𝐧','o':'𝐨','p':'𝐩','q':'𝐪','r':'𝐫','s':'𝐬','t':'𝐭','u':'𝐮','v':'𝐯','w':'𝐰','x':'𝐱','y':'𝐲','z':'𝐳','1':'𝟏','2':'𝟐','3':'𝟑','4':'𝟒','5':'𝟓','6':'𝟔','7':'𝟕','8':'𝟖','9':'𝟗','0':'𝟎'}
13
- __font3 = {'a':'𝒶','b':'𝒷','c':'𝒸','d':'𝒹','e':'ℯ','f':'𝒻','g':'𝑔','h':'𝒽','i':'𝒾','j':'𝒿','k':'𝓀','l':'𝓁','m':'𝓂','n':'𝓃','o':'𝑜','p':'𝓅','q':'𝓆','r':'𝓇','s':'𝓈','t':'𝓉','u':'𝓊','v':'𝓋','w':'𝓌','x':'𝓍','y':'𝓎','z':'𝓏','1':'𝟣','2':'𝟤','3':'𝟥','4':'𝟦','5':'𝟧','6':'𝟨','7':'𝟩','8':'𝟪','9':'𝟫','0':'𝟢'}
14
- __font4 = {'a':'𝓐','b':'𝓑','c':'𝓒','d':'𝓓','e':'𝓔','f':'𝓕','g':'𝓖','h':'𝓗','i':'𝓘','j':'𝓙','k':'𝓚','l':'𝓛','m':'𝓜','n':'𝓝','o':'𝓞','p':'𝓟','q':'𝓠','r':'𝓡','s':'𝓢','t':'𝓣','u':'𝓤','v':'𝓥','w':'𝓦','x':'𝓧','y':'𝓨','z':'𝓩','1':'𝟙','2':'𝟚','3':'𝟛','4':'𝟜','5':'𝟝','6':'𝟞','7':'𝟟','8':'𝟠','9':'𝟡','0':'𝟘'}
15
- __font5 = {'a':'🅰','b':'🅱','c':'🅲','d':'🅳','e':'🅴','f':'🅵','g':'🅶','h':'🅷','i':'🅸','j':'🅹','k':'🅺','l':'🅻','m':'🅼','n':'🅽','o':'🅾','p':'🅿','q':'🆀','r':'🆁','s':'🆂','t':'🆃','u':'🆄','v':'🆅','w':'🆆','x':'🆇','y':'🆈','z':'🆉','1':'➊','2':'➋','3':'➌','4':'➍','5':'➎','6':'➏','7':'➐','8':'➑','9':'➒','0':'⓿'}
16
- __font6 = {'a':'𝕒','b':'𝕓','c':'𝕔','d':'𝕕','e':'𝕖','f':'𝕗','g':'𝕘','h':'𝕙','i':'𝕚','j':'𝕛','k':'𝕜','l':'𝕝','m':'𝕞','n':'𝕟','o':'𝕠','p':'𝕡','q':'𝕢','r':'𝕣','s':'𝕤','t':'𝕥','u':'𝕦','v':'𝕧','w':'𝕨','x':'𝕩','y':'𝕪','z':'𝕫','1':'𝟙','2':'𝟚','3':'𝟛','4':'𝟜','5':'𝟝','6':'𝟞','7':'𝟟','8':'𝟠','9':'𝟡','0':'𝟘'}
17
-
18
- class FontMessageMixin(Client):
19
- async def send_message(self, chat_id :Union[int, str], text :str, parse_mode=None, *args, **kwargs):
20
- return await super().send_message(chat_id=chat_id, text=get_font(text=text, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
21
-
22
- async def send_photo(self, chat_id:Union[int, str], photo :str, caption :str=None, parse_mode=None, *args, **kwargs):
23
- return await super().send_photo(chat_id=chat_id, photo=photo, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
24
-
25
- async def edit_message_text(self, chat_id: Union[int, str], message_id: int, text :str, parse_mode=None, *args, **kwargs):
26
- return await super().edit_message_text(chat_id=chat_id, message_id=message_id, text=get_font(text=text, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
27
-
28
- async def edit_message_caption(self, chat_id :Union[int, str], message_id : int, caption :str, parse_mode=None, *args, **kwargs):
29
- return await super().edit_message_caption(chat_id=chat_id, message_id=message_id, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
30
-
31
- async def edit_inline_text(self, inline_message_id: int, text :str, parse_mode=None, *args, **kwargs):
32
- return await super().edit_inline_text(inline_message_id, text=get_font(text=text, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
33
-
34
- async def send_document(self, chat_id :Union[int, str], document, caption :str=None, parse_mode=None, *args, **kwargs):
35
- return await super().send_document(chat_id, document, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
36
-
37
- async def send_video(self, chat_id :Union[int,str], video, caption :str=None, parse_mode=None, *args, **kwargs):
38
- return await super().send_video(chat_id, video, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
39
-
40
- async def send_audio(self, chat_id :Union[int,str], audio, caption :str=None, parse_mode=None, *args, **kwargs):
41
- return await super().send_audio(chat_id, audio, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
42
-
43
- async def send_voice(self, chat_id :Union[int,str], voice, caption :str=None, parse_mode=None, *args, **kwargs):
44
- return await super().send_voice(chat_id, voice, caption=get_font(text=caption, font=self.font), parse_mode=ParseMode.HTML, *args, **kwargs)
45
-
46
- async def send_alert(self,message:Union[Message,CallbackQuery], text :str):
47
- if isinstance(message, Message):
48
- return await message.reply(text)
49
- elif isinstance(message, CallbackQuery):
50
- return await message.answer(text, show_alert=True)
51
-
52
-
53
- async def index_message(self, chat_id: Union[int, str], end: int, start: int = 0) -> List[Message]:
54
- messages_list = []
55
- current = start
56
- while True:
57
- new_diff = min(200, end - current)
58
- if new_diff <= 0:break
59
- messages = await super().get_messages(chat_id=chat_id, message_ids=list(range(current, current + new_diff + 1)))
60
- messages_list.extend(messages)
61
- current += len(messages)
62
- return messages_list
63
-
64
- def web_app_data_filter(self,key_value):
65
- async def filter_func(flt, client, update: Message):
66
- if update.web_app_data:
67
- return update.web_app_data.data.startswith(key_value)
68
- return False
69
- return filters.create(filter_func)
70
-
71
- web_app_data = filters.create(web_app_data_filter)
72
-
73
- def get_font(text: str, font: int = 1):
74
- if int(font) ==0:return text
75
- font_name = f"__font{font}"
76
- font_style: dict = globals().get(font_name, None)
77
- if not text:
78
- return text
79
- if font_style is None:
80
- return text
81
-
82
- def convert(match):
83
- if match.group("tag"):
84
- return match.group("tag") # Preserve HTML tags
85
- elif match.group("braced"):
86
- return match.group("braced") # Preserve {placeholders}
87
- elif match.group("command"):
88
- return match.group("command") # Preserve /commands
89
- elif match.group("mention"):
90
- return match.group("mention")
91
- else:
92
- content = match.group("text")
93
- return "".join(font_style.get(char, char) for char in content)
94
-
95
- pattern = (
96
- r"(?P<tag><[^>]+>)" # HTML tags
97
- r"|(?P<braced>\{[^}]+\})" # Braced placeholders
98
- r"|(?P<command>/\w+)" # /commands
99
- r"|(?P<mention>@[\w_]+)" # @usernames (mentions)
100
- r"|(?P<text>\w+)" # Regular words
101
- )
102
-
103
- return re.sub(pattern, convert, text.lower(), flags=re.IGNORECASE)
@@ -1,47 +0,0 @@
1
- from functools import wraps
2
- from pyrogram import filters
3
- from pyrogram.types import Message
4
- import asyncio
5
- import re
6
- from d4rk.Logs import setup_logger
7
-
8
- logger = setup_logger(__name__)
9
-
10
- last_index_per_chat = {}
11
- bot_order_per_chat = {}
12
- responded_messages = {}
13
- chat_locks = {}
14
-
15
- def round_robin():
16
- def decorator(func):
17
- @wraps(func)
18
- async def wrapper(client, message, *args, **kwargs):
19
- chat_id = message.chat.id
20
- msg_id = message.id
21
-
22
- if message.chat.type.name.lower() == "private":
23
- return await func(client, message, *args, **kwargs)
24
-
25
- if chat_id not in bot_order_per_chat:
26
- bot_order_per_chat[chat_id] = [client.me.id]
27
- last_index_per_chat[chat_id] = 0
28
- responded_messages[chat_id] = set()
29
- chat_locks[chat_id] = asyncio.Lock()
30
-
31
- if client.me.id not in bot_order_per_chat[chat_id]:
32
- bot_order_per_chat[chat_id].append(client.me.id)
33
-
34
- async with chat_locks[chat_id]:
35
- if msg_id in responded_messages[chat_id]:
36
- return
37
- current_index = last_index_per_chat[chat_id]
38
- selected_bot_id = bot_order_per_chat[chat_id][current_index]
39
-
40
- if client.me.id == selected_bot_id:
41
- result = await func(client, message, *args, **kwargs)
42
- responded_messages[chat_id].add(msg_id)
43
- last_index_per_chat[chat_id] = (current_index + 1) % len(bot_order_per_chat[chat_id])
44
- return result
45
-
46
- return wrapper
47
- return decorator
@@ -1,5 +0,0 @@
1
- from .Database import db
2
- from .Handlers import BotManager, scheduler
3
- from .Logs import setup_logger , get_timezone_offset
4
- from .Models import command, find_command, movie_finder
5
- from .Utils import *
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes