d4rktg 0.0.0__py3-none-any.whl

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.
@@ -0,0 +1 @@
1
+ from .db import db
d4rk/Database/db.py ADDED
@@ -0,0 +1,52 @@
1
+ # src/Database/Mongodb/db.py
2
+
3
+ from pymongo import MongoClient , server_api
4
+
5
+ from d4rk.Logs import setup_logger
6
+
7
+ logger = setup_logger(__name__)
8
+
9
+ class Database:
10
+ client = None
11
+ db = None
12
+ is_connected = False
13
+ def __init__(self):
14
+ pass
15
+
16
+ def connect(self,name: str, collections: list = [],DATABASE_URL: str =None):
17
+ self.database_name = name.replace(" ","")
18
+ self._collections = collections
19
+ self._DATABASE_URL = DATABASE_URL
20
+ if not DATABASE_URL:
21
+ logger.warning("DATABASE_URL is not set in the environment variables.")
22
+ exit()
23
+ try:
24
+ self.client = MongoClient(DATABASE_URL,server_api=server_api.ServerApi('1'))
25
+ self.db = self.client[self.database_name]
26
+ self._load_custom_collections()
27
+ self.is_connected = True
28
+ except Exception as e:
29
+ logger.warning(f"Failed to connect to MongoDB: {e}")
30
+ exit()
31
+ if self.is_connected:
32
+ try:
33
+ self.client.admin.command('ping')
34
+ logger.info(f"successfully connected to {name} Mongodb!")
35
+ except Exception as e:
36
+ logger.warning(f"Something Went Wrong While Connecting To Database! : {e}")
37
+ self.is_connected = False
38
+ exit()
39
+
40
+ def _load_custom_collections(self):
41
+ for CustomClass in self._collections:
42
+ collection_name = str(CustomClass.__name__).title()
43
+ base_collection = self.get_collection(collection_name)
44
+ instance = CustomClass(base_collection)
45
+ setattr(self, collection_name, instance)
46
+ logger.info(f"Loaded collection: {collection_name}")
47
+
48
+ def get_collection(self, collection):
49
+ return self.db[collection]
50
+
51
+ db = Database()
52
+
@@ -0,0 +1,3 @@
1
+ from ._bot import BotManager
2
+ from ._scheduler import scheduler
3
+ from ._custom import FontMessageMixin
d4rk/Handlers/_bot.py ADDED
@@ -0,0 +1,207 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+ import traceback
5
+ import random
6
+ from datetime import datetime, timedelta
7
+
8
+ from pyrogram import Client
9
+ from pyrogram.errors import FloodWait
10
+ from pyrogram.types import BotCommand
11
+ from pyrogram.errors.exceptions.bad_request_400 import AccessTokenExpired
12
+
13
+ from d4rk.Logs import setup_logger
14
+
15
+ logs_sent = False
16
+ logs_lock = asyncio.Lock()
17
+
18
+ logger = setup_logger(__name__)
19
+
20
+ class BotManager(Client):
21
+ _bot: Client = None
22
+ _web = True
23
+ _bot_info = None
24
+ _is_connected = False
25
+ _rename = False
26
+ _flood_data = {}
27
+ _loop = None
28
+ _scheduler_thread = None
29
+ font = 0
30
+ sudo_users = []
31
+
32
+
33
+ def create_client(self,app_name,token):
34
+ self.app_name = app_name
35
+ super().__init__(
36
+ name=app_name,
37
+ api_id=self.api_id,
38
+ api_hash=self.api_hash,
39
+ bot_token=token,
40
+ plugins=self.plugins,
41
+ in_memory=True
42
+ )
43
+
44
+ async def handle_flood_wait(self, wait_time: int):
45
+
46
+ await asyncio.sleep(wait_time)
47
+ try:await self.powerup(self.app_name)
48
+ except:pass
49
+
50
+ def _safe_async(self, coro_func):
51
+ if self._loop:asyncio.run_coroutine_threadsafe(coro_func(), self._loop)
52
+ else:logger.error("Event loop is not set for _safe_async")
53
+
54
+ async def powerup(self,appname):
55
+ if hasattr(self, "db"):
56
+ self.font = self.db.Settings.get(key="font",datatype=str)
57
+ self.sudo_users = self.db.Settings.get(key="sudo_users",datatype=list,default=[])
58
+ if not self.font:
59
+ logger.info("Font not set, defaulting to font 1")
60
+ self.db.Settings.set("font", "1")
61
+ self.font = 1
62
+
63
+ self.create_client(appname,self.token)
64
+ max_retries = 3
65
+ for attempt in range(max_retries):
66
+ try:
67
+ self._loop = asyncio.get_running_loop()
68
+ logger.info(f'Starting bot client... (attempt {attempt + 1}/{max_retries})')
69
+ if not self._is_connected:
70
+ await asyncio.wait_for(super().start(), timeout=60.0)
71
+ self._bot_info = await super().get_me()
72
+ logger.info(f"Bot Client > {self._bot_info.first_name} - @{self._bot_info.username} Started")
73
+ await self.setup_commands()
74
+ self._is_connected = True
75
+ await self.handle_restart()
76
+ break
77
+
78
+ except asyncio.TimeoutError:
79
+ logger.error(f"Bot start timed out (attempt {attempt + 1})")
80
+ if attempt < max_retries - 1:
81
+ logger.info("Retrying in 10 seconds...")
82
+ await asyncio.sleep(10)
83
+
84
+ except FloodWait as e:
85
+ logger.error(f"FloodWait: {e.value} seconds")
86
+ await self.handle_flood_wait(e.value)
87
+ break
88
+
89
+ except AccessTokenExpired:
90
+ logger.error(f"Access token expired (attempt {attempt + 1})")
91
+ except Exception as e:
92
+ logger.error(f"Error starting Client.Stoped !")
93
+ logger.error(traceback.format_exc())
94
+ break
95
+ else:
96
+ logger.error("Failed to start bot after all retry attempts")
97
+
98
+ await self.setup_webserver()
99
+
100
+ async def powerdown(self, *args):
101
+ global logs_sent, logs_lock
102
+ logger.info("Initiating APP to stop...")
103
+ if self._rename:await super().set_bot_info(lang_code='en',name=self.app_name + " (Offline)")
104
+ self.stop_scheduler()
105
+ today = self.TZ_now.strftime("%Y-%m-%d")
106
+ if hasattr(self, '_web_runner') and self._web_runner:
107
+ await self.web_server.cleanup()
108
+
109
+ logger.info("Stopping bot client...")
110
+ if self._is_connected and self.LOGS:
111
+ try:
112
+ await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} stopping...")
113
+ except Exception as e:
114
+ logger.error(f"Error sending stop message for {self._bot_info.first_name}: {e}")
115
+
116
+ async with logs_lock:
117
+ if not logs_sent and self._is_connected:
118
+ logs_sent = True
119
+ try:
120
+ await self.send_document(chat_id=self.LOGS, document=f"logs/log-{today}.txt")
121
+ logger.info("Log document sent successfully")
122
+ except Exception as e:
123
+ logger.error(f"Error sending log document: {e}")
124
+
125
+ if self._is_connected and self.LOGS:
126
+ try:
127
+ await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} stopped successfully!")
128
+ except Exception as e:
129
+ logger.error(f"Error sending stop confirmation for {self._bot_info.first_name}: {e}")
130
+ await super().stop()
131
+ await asyncio.sleep(3)
132
+
133
+ async def reboot(self):
134
+ try:
135
+ if self._rename:await super().set_bot_info(lang_code='en',name=self.app_name + " (restarting..)")
136
+ logger.info("Initiating APP to reboot...")
137
+ self.stop_scheduler()
138
+ today = self.TZ_now.strftime("%Y-%m-%d")
139
+ if hasattr(self, '_web_runner') and self._web_runner:
140
+ await self.web_server.cleanup()
141
+ if self._is_connected:
142
+ try:
143
+ if self.LOGS:
144
+ await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} rebooting...")
145
+ await self.send_document(chat_id=self.LOGS, document=f"logs/log-{today}.txt")
146
+ logger.info(f"{self._bot_info.first_name} - @{self._bot_info.username} is rebooting")
147
+ except Exception as e:
148
+ logger.error(f"Error sending reboot notification: {e}")
149
+ await super().stop()
150
+ self._is_connected = False
151
+ await asyncio.sleep(2)
152
+
153
+ logger.info("Restarting process...")
154
+ os.execl(sys.executable, sys.executable, *sys.argv)
155
+ except Exception as e:
156
+ logger.error(f"Error during reboot: {e}")
157
+ os.execl(sys.executable, sys.executable, *sys.argv)
158
+
159
+ async def handle_restart(self):
160
+ if os.path.exists('restart.txt'):
161
+ with open('restart.txt', 'r') as file:
162
+ data = file.read().split()
163
+ chat_id = int(data[0])
164
+ Message_id = int(data[1])
165
+ try:await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} restarted successfully!")
166
+ except Exception as e:logger.error(f"Failed to send restart notification: {e}")
167
+ try:await self.edit_message_text(chat_id=chat_id,message_id=Message_id, text="Bot restarted successfully!")
168
+ except:
169
+ try:
170
+ await self.send_message(chat_id=chat_id, text="Bot restarted successfully!",reply_to_message_id=Message_id-1,)
171
+ await self.delete_messages(chat_id=chat_id,message_ids=Message_id)
172
+ except:pass
173
+
174
+ if os.path.exists('restart.txt'):os.remove('restart.txt')
175
+ else:
176
+ try:await self.send_message(chat_id=self.LOGS, text=f"{self._bot_info.mention} started successfully!")
177
+ except Exception as e:logger.error(f"Failed to send start notification: {e}")
178
+
179
+
180
+ async def setup_commands(self,set_commands=False):
181
+ if self._rename:
182
+ if self._bot_info.first_name != self.app_name:
183
+ await super().set_bot_info(lang_code='en',name=self.app_name)
184
+ if set_commands:
185
+ commands = await super().get_bot_commands()
186
+ if commands == []:
187
+ b_index = self.TOKEN_INDEX + 1
188
+ bot_commands = [
189
+ BotCommand("start", f"{b_index} Start the bot"),
190
+ BotCommand("help", f"{b_index} Get help"),
191
+ BotCommand("logs", f"{b_index} Get logs (Admin only)"),
192
+ BotCommand("reboot", f"{b_index} Reboot the bot (Admin only)")
193
+ ]
194
+ await super().set_bot_commands(bot_commands)
195
+
196
+ async def send_logs(self):
197
+ logger.info("Sending yesterday logs...")
198
+ if not self._is_connected:
199
+ logger.warning("Bot is not connected")
200
+ if self._is_connected:
201
+
202
+ yesterday = (self.TZ_now - timedelta(days=1)).strftime("%Y-%m-%d")
203
+ try:
204
+ m = await self.send_document(chat_id=self.LOGS, document=f"logs/log-{yesterday}.txt")
205
+ logger.info(f"Logs sent to {m.chat.first_name} - @{m.chat.username}")
206
+ except Exception as e:
207
+ logger.error(f"Error sending logs: {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,33 @@
1
+ import schedule
2
+ import threading
3
+ import time
4
+ from datetime import datetime, timedelta
5
+
6
+ from d4rk.Logs import setup_logger
7
+ logger = setup_logger(__name__)
8
+
9
+ class scheduler:
10
+ async def start_scheduler(self):
11
+ if self._scheduler_thread and self._scheduler_thread.is_alive():
12
+ return
13
+ schedule.clear()
14
+ schedule.every().day.at(time_str="00:01",tz="Asia/Kolkata").do(lambda: self._safe_async(self.send_logs))
15
+ self._stop_scheduler.clear()
16
+ self._scheduler_thread = threading.Thread(target=self._run_scheduler, daemon=True)
17
+ self._scheduler_thread.start()
18
+ logger.info("Background scheduler started for log maintenance")
19
+
20
+ def stop_scheduler(self):
21
+ if self._scheduler_thread:
22
+ self._stop_scheduler.set()
23
+ self._scheduler_thread.join(timeout=5)
24
+ logger.info("Background scheduler stopped")
25
+
26
+ def _run_scheduler(self):
27
+ while not self._stop_scheduler.is_set():
28
+ try:
29
+ schedule.run_pending()
30
+ time.sleep(60) # Check every minute
31
+ except Exception as e:
32
+ if logger:
33
+ logger.error(f"Scheduler error: {e}")
d4rk/Logs/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from ._logger import *
d4rk/Logs/_logger.py ADDED
@@ -0,0 +1,115 @@
1
+ # src/Log/_logger_config.py
2
+
3
+ import os
4
+ import sys
5
+ import logging
6
+
7
+ from datetime import datetime, timezone, timedelta
8
+ from logging.handlers import TimedRotatingFileHandler
9
+
10
+ try:
11
+ import colorama
12
+ colorama.init(strip=False, autoreset=True)
13
+ COLORAMA_AVAILABLE = True
14
+ except ImportError:
15
+ COLORAMA_AVAILABLE = False
16
+
17
+ def get_timezone_offset(time_zone: str = "00:00") -> timezone:
18
+ if time_zone:
19
+ try:
20
+ hours, minutes = time_zone.split(':')
21
+ if hours.startswith("-"):
22
+ return timezone(timedelta(hours=-int(hours), minutes=-int(minutes)))
23
+ else:
24
+ return timezone(timedelta(hours=int(hours), minutes=int(minutes)))
25
+ except ValueError:
26
+ raise ValueError(f"Invalid TIME_ZONE format: {time_zone}")
27
+ return timezone(timedelta(hours=0))
28
+
29
+ TZ = get_timezone_offset(os.getenv("TIME_ZONE", "05:30"))
30
+
31
+ class TimeZoneFormatter(logging.Formatter):
32
+
33
+ def __init__(self, fmt, datefmt=None, use_colors=False):
34
+ super().__init__(fmt, datefmt)
35
+ self.use_colors = use_colors
36
+ self.COLORS = {
37
+ "TIME": "\033[93m", # Light Yellow
38
+ "NAME": "\033[36m", # Cyan
39
+ "FUNC": "\033[34m", # Blue
40
+ "LEVEL": {
41
+ logging.DEBUG: "\033[37m", # White
42
+ logging.INFO: "\033[32m", # Green
43
+ logging.WARNING: "\033[33m", # Yellow
44
+ logging.ERROR: "\033[31m", # Red
45
+ logging.CRITICAL: "\033[41m" # Red background
46
+ }
47
+ }
48
+ self.RESET = "\033[0m"
49
+ def converter(self, timestamp):
50
+ dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
51
+ return dt.astimezone(TZ).timetuple()
52
+
53
+ def formatTime(self, record, datefmt=None):
54
+ dt = datetime.fromtimestamp(record.created, tz=timezone.utc)
55
+ time_zone_time = dt.astimezone(TZ)
56
+ if datefmt:
57
+ return time_zone_time.strftime(datefmt)
58
+ else:
59
+ return time_zone_time.strftime('%Y-%m-%d %H:%M:%S %z')
60
+
61
+ def format(self, record):
62
+ if not self.use_colors:
63
+ return super().format(record)
64
+
65
+ time_str = f"{self.COLORS['TIME']}{self.formatTime(record, self.datefmt)}{self.RESET}"
66
+ name_str = f"{self.COLORS['NAME']}{record.name}{self.RESET}"
67
+ func_str = f"{self.COLORS['FUNC']}{record.funcName}:{record.lineno}{self.RESET}"
68
+ level_color = self.COLORS['LEVEL'].get(record.levelno, "")
69
+ level_str = f"{level_color}{record.levelname}{self.RESET}"
70
+ msg_str = f"{level_color}{record.getMessage()}{self.RESET}"
71
+
72
+ return f"{time_str} - {name_str} - {func_str} - {level_str} - {msg_str}"
73
+
74
+ def setup_logger(name=__name__, log_level=logging.INFO):
75
+ log_dir = "logs"
76
+ if not os.path.exists(log_dir):
77
+ os.makedirs(log_dir)
78
+
79
+ logger = logging.getLogger(name)
80
+ logger.setLevel(log_level)
81
+
82
+ if logger.handlers:
83
+ return logger
84
+
85
+ time_zone_now = datetime.now(TZ)
86
+
87
+ file_handler = TimedRotatingFileHandler(
88
+ filename=os.path.join(log_dir, f"log-{time_zone_now.strftime('%Y-%m-%d')}.txt"),
89
+ when='midnight',
90
+ interval=1,
91
+ backupCount=30
92
+ )
93
+ file_handler.setLevel(log_level)
94
+
95
+
96
+ console_handler = logging.StreamHandler()
97
+ console_handler.setLevel(log_level)
98
+ use_colors = sys.stdout.isatty() and COLORAMA_AVAILABLE
99
+ plain_formatter = TimeZoneFormatter(
100
+ '%(asctime)s - %(name)s - %(funcName)s:%(lineno)d - %(levelname)s - %(message)s',
101
+ datefmt='%Y-%m-%d %H:%M:%S',
102
+ use_colors=False
103
+ )
104
+ formatter = TimeZoneFormatter(
105
+ '%(asctime)s - %(name)s - %(funcName)s:%(lineno)d - %(levelname)s - %(message)s',
106
+ datefmt='%Y-%m-%d %H:%M:%S',
107
+ use_colors=use_colors
108
+ )
109
+
110
+ file_handler.setFormatter(plain_formatter)
111
+ console_handler.setFormatter(formatter)
112
+ logger.addHandler(file_handler)
113
+ logger.addHandler(console_handler)
114
+ logger.propagate = False
115
+ return logger
d4rk/Utils/__init__.py ADDED
@@ -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
+
d4rk/Utils/_buttons.py ADDED
@@ -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
+
d4rk/Utils/_filters.py ADDED
@@ -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)
d4rk/Utils/_fonts.py ADDED
@@ -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
+
d4rk/Utils/_ip.py ADDED
@@ -0,0 +1,21 @@
1
+ import requests
2
+ import socket
3
+ import asyncio
4
+
5
+ def get_public_ip():
6
+ try:
7
+ response = requests.get('https://api.ipify.org?format=json')
8
+ ip_data = response.json()
9
+ ip = ip_data['ip']
10
+ return ip
11
+ except requests.RequestException as e:
12
+ return None
13
+
14
+
15
+ async def check_public_ip_reachable(ip: str, port: int = 8080):
16
+ await asyncio.sleep(1)
17
+ try:
18
+ sock = socket.create_connection((ip, port), timeout=5)
19
+ return True
20
+ except (socket.timeout, socket.error):
21
+ return False
@@ -0,0 +1,184 @@
1
+ import re
2
+ import PTN
3
+ import unicodedata
4
+
5
+ from typing import List, Optional
6
+ from dataclasses import dataclass, field
7
+
8
+ @dataclass
9
+ class Movie:
10
+ title: str
11
+ normalized_title: str
12
+ year: Optional[int]
13
+ resolution: Optional[str]
14
+ quality: Optional[str]
15
+ codec: Optional[str]
16
+ extra: List[str] = field(default_factory=list)
17
+ split: bool = False
18
+ part: Optional[int] = None
19
+
20
+ class MovieParser:
21
+ def __parse_file_name(self, file_name: str):
22
+ file_name = re.sub(r'@[\w_]+', '', file_name.lower()).strip()
23
+ file_name = file_name.replace('_', ' ')
24
+ self.file_name = file_name
25
+ self.extension = self.file_name.split('.')[-1]
26
+ self.movie = PTN.parse(self.file_name)
27
+ self.tags = []
28
+
29
+ def fallback_title(self, file_name):
30
+ name = re.sub(r'\.\w{2,4}$', '', file_name)
31
+ name = name.replace('_', ' ').replace('.', ' ')
32
+ name = re.sub(r'@\w+', '', name)
33
+ name = unicodedata.normalize('NFKC', name)
34
+ tags_pattern = r'\b(480p|720p|1080p|2160p|BR_Rip|WEBRip|HDRip|x264|x265|HEVC|AAC|DD\+?5\.1|[0-9]+MB|1GB|2GB|Tamil|Telugu|Hindi|English|Dubbed|HDTV|WEB-DL|BluRay|Blu-ray|YTS|YIFY|fps)\b'
35
+ name = re.sub(tags_pattern, '', name, flags=re.IGNORECASE)
36
+ name = re.split(r'\b(S\d+|Ep\d+)\b', name, 1)[0]
37
+ name = re.sub(r'\s+', ' ', name).strip()
38
+ return name
39
+
40
+ def fallback_year(self, file_name):
41
+ years = re.findall(r'(?<!\d)(19\d{2}|20\d{2})(?!\d)', file_name)
42
+ return int(years[0]) if years else None
43
+
44
+ def _fix_roman_numerals(self, text: str) -> str:
45
+ roman_pattern = r'\b(i{1,3}|iv|v|vi{0,3}|ix|x{1,3}|xl|l|li{0,3}|lx|xc|c|ci{0,3}|cd|d|dc|cm|m|m{1,3})\b'
46
+ return re.sub(roman_pattern, lambda m: m.group(0).upper(), text, flags=re.IGNORECASE)
47
+
48
+ def extract(self, file_name: str) -> Movie:
49
+ self.__parse_file_name(file_name)
50
+ title = self.movie.get('title', '').replace('.', ' ').strip()
51
+ if not title:title = self.fallback_title(self.file_name)
52
+ else:title = title.replace('.', ' ').strip()
53
+
54
+ year = self.movie.get('year') or self.fallback_year(self.file_name)
55
+ if year and str(year) in title:title = title.replace(str(year), '').strip()
56
+
57
+ resolution = self.movie.get('resolution')
58
+ quality = self.movie.get('quality')
59
+ codec = self.movie.get('codec')
60
+ if codec:codec = codec.replace('H', 'x').replace('.', '')
61
+
62
+ extra = []
63
+ tag_keywords = {
64
+ 'psa': 'PSA',
65
+ 'pahe': 'Pahe',
66
+ 'galaxyrg': 'GalaxyRG',
67
+ 'yify': 'YIFY',
68
+ 'yts': 'YTS',
69
+ 'rarbg': 'RARBG',
70
+ 'ettv': 'ETTV',
71
+ 'evo': 'EVO',
72
+ 'fgt': 'FGT',
73
+ 'ntg': 'NTG',
74
+ 'tigole': 'Tigole',
75
+ 'qxr': 'QxR',
76
+ 'vxt': 'VXT',
77
+ 'cm8': 'CM8',
78
+ 'naisu': 'NAISU',
79
+ 'kog': 'KOGi',
80
+ 'spark': 'SPARKS',
81
+ 'don': 'DON',
82
+ 'lama': 'LAMA',
83
+ 'drone': 'DRONES',
84
+ 'iht': 'IHT',
85
+ 'amzn-rls': 'Amazon Release',
86
+
87
+ 'nf': 'Netflix',
88
+ 'amzn': 'Amazon',
89
+ 'hmax': 'HBO Max',
90
+ 'dsnp': 'Disney+',
91
+ 'hulu': 'Hulu',
92
+ 'appletv': 'Apple TV+',
93
+ 'paramount': 'Paramount+',
94
+ 'peacock': 'Peacock',
95
+ 'crave': 'Crave',
96
+ 'zee5': 'ZEE5',
97
+ 'sony': 'SonyLiv',
98
+ 'atvp': 'Apple TV+',
99
+ 'mbc': 'MBC',
100
+
101
+ 'imax': 'IMAX',
102
+ 'hdr': 'HDR',
103
+ 'hdr10': 'HDR10',
104
+ 'hdr10+': 'HDR10+',
105
+ 'dolbyvision': 'Dolby Vision',
106
+ 'dv': 'Dolby Vision',
107
+ 'visionplus': 'Dolby Vision+',
108
+ '60fps': '60FPS',
109
+ '50fps': '50FPS',
110
+ '10bit': '10bit',
111
+ '8bit': '8bit',
112
+ 'hevc': 'HEVC',
113
+ 'av1': 'AV1',
114
+
115
+ 'aac': 'AAC',
116
+ 'aac2': 'AAC2.0',
117
+ 'aac5': 'AAC5.1',
118
+ 'ac3': 'AC3',
119
+ 'eac3': 'EAC3',
120
+ 'dd': 'Dolby Digital',
121
+ 'ddp': 'Dolby Digital Plus',
122
+ 'ddp5': 'DDP5.1',
123
+ 'truehd': 'TrueHD',
124
+ 'dts': 'DTS',
125
+ 'dtsma': 'DTS-HD MA',
126
+ 'dtsx': 'DTS:X',
127
+ 'atmos': 'Dolby Atmos',
128
+ 'flac': 'FLAC',
129
+ 'opus': 'Opus',
130
+ 'mp3': 'MP3',
131
+ 'lpcm': 'LPCM',
132
+
133
+ 'remux': 'Remux',
134
+ 'repack': 'Repack',
135
+ 'rerip': 'ReRip',
136
+ 'proper': 'Proper',
137
+ 'uncut': 'Uncut',
138
+ 'extended': 'Extended',
139
+ 'directors': "Director's Cut",
140
+ 'criterion': 'Criterion',
141
+ 'uncensored': 'Uncensored',
142
+ 'festival': 'Festival Cut',
143
+ 'sample': 'Sample',
144
+
145
+ '1337x': '1337x',
146
+ 'eztv': 'EZTV',
147
+ 'torrentgalaxy': 'TorrentGalaxy',
148
+ 'scene': 'Scene Release',
149
+ 'internal': 'Internal',
150
+ 'limited': 'Limited',
151
+ 'complete': 'Complete Series',
152
+ 'part': 'Part',
153
+ 'dubbed': 'Dubbed',
154
+ 'subbed': 'Subbed',
155
+ 'multi': 'Multi Audio',
156
+ 'dual': 'Dual Audio',
157
+ 'retail': 'Retail Rip',
158
+ }
159
+
160
+ for k, v in tag_keywords.items():
161
+ if k in self.file_name:
162
+ extra.append(v)
163
+
164
+ if any(k in self.file_name for k in ['dolby', 'atmos']):
165
+ extra.append('DolbyAtmos')
166
+
167
+ match = re.search(r'\.(\d{3})$', file_name)
168
+ split = match is not None
169
+ part = int(match.group(1)) if split else None
170
+
171
+ return Movie(
172
+ title=self._fix_roman_numerals(title.title()),
173
+ normalized_title=re.sub(r'[^a-z0-9&\+]+', ' ', title.lower()).strip(),
174
+ year=year,
175
+ resolution=resolution,
176
+ quality=quality,
177
+ codec=codec,
178
+ extra=extra,
179
+ split=split,
180
+ part=part
181
+ )
182
+
183
+ parser = MovieParser()
184
+
@@ -0,0 +1,79 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass
4
+ class Reacts:
5
+ like: str = "๐Ÿ‘"
6
+ unlike: str = "๐Ÿ‘Ž"
7
+ heart: str = "โค"
8
+ fire: str = "๐Ÿ”ฅ"
9
+ face_with_hearts: str = "๐Ÿฅฐ"
10
+ bye: str = "๐Ÿ‘"
11
+ beaming_face: str = "๐Ÿ˜"
12
+ thinking: str = "๐Ÿค”"
13
+ exploding: str = "๐Ÿคฏ"
14
+ screaming: str = "๐Ÿ˜ฑ"
15
+ anger: str = "๐Ÿคฌ"
16
+ crying: str = "๐Ÿ˜ข"
17
+ party_popper: str = "๐ŸŽ‰"
18
+ star_struck: str = "๐Ÿคฉ"
19
+ vomiting: str = "๐Ÿคฎ"
20
+ shit: str = "๐Ÿ’ฉ"
21
+ folded_hands: str = "๐Ÿ™"
22
+ ok_hand: str = "๐Ÿ‘Œ"
23
+ dove: str = "๐Ÿ•Š"
24
+ lightning: str = "โšก"
25
+ clown: str = "๐Ÿคก"
26
+ yawning: str = "๐Ÿฅฑ"
27
+ woozy: str = "๐Ÿฅด"
28
+ woow: str = "๐Ÿ˜"
29
+ whale: str = "๐Ÿณ"
30
+ heart_on_fire: str = "โคโ€๐Ÿ”ฅ"
31
+ dark_moon: str = "๐ŸŒš"
32
+ hot_dog: str = "๐ŸŒญ"
33
+ hundred: str = "๐Ÿ’ฏ"
34
+ rolling_on_the_floor_laughing: str = "๐Ÿคฃ"
35
+ banana: str = "๐ŸŒ"
36
+ trophy: str = "๐Ÿ†"
37
+ broken_heart: str = "๐Ÿ’”"
38
+ raised_eyebrow: str = "๐Ÿคจ"
39
+ neutral_face: str = "๐Ÿ˜"
40
+ strawberry: str = "๐Ÿ“"
41
+ champagne: str = "๐Ÿพ"
42
+ kiss: str = "๐Ÿ’‹"
43
+ middle_finger: str = "๐Ÿ–•"
44
+ smiling_devil: str = "๐Ÿ˜ˆ"
45
+ sleeping: str = "๐Ÿ˜ด"
46
+ crying_loudly: str = "๐Ÿ˜ญ"
47
+ nerd_face: str = "๐Ÿค“"
48
+ ghost: str = "๐Ÿ‘ป"
49
+ technologist: str = "๐Ÿ‘จโ€๐Ÿ’ป"
50
+ eyes: str = "๐Ÿ‘€"
51
+ jack_o_lantern: str = "๐ŸŽƒ"
52
+ see_no_evil: str = "๐Ÿ™ˆ"
53
+ angel: str = "๐Ÿ˜‡"
54
+ fearful_face: str = "๐Ÿ˜จ"
55
+ handshake: str = "๐Ÿค"
56
+ writing_hand: str = "โœ"
57
+ hugging_face: str = "๐Ÿค—"
58
+ saluting_face: str = "๐Ÿซก"
59
+ santa_claus: str = "๐ŸŽ…"
60
+ christmas_tree: str = "๐ŸŽ„"
61
+ snowman: str = "โ˜ƒ"
62
+ nail_polish: str = "๐Ÿ’…"
63
+ zany_face: str = "๐Ÿคช"
64
+ moai: str = "๐Ÿ—ฟ"
65
+ cool: str = "๐Ÿ†’"
66
+ heart_with_arrow: str = "๐Ÿ’˜"
67
+ hear_no_evil: str = "๐Ÿ™‰"
68
+ unicorn: str = "๐Ÿฆ„"
69
+ face_blowing_kiss: str = "๐Ÿ˜˜"
70
+ pill: str = "๐Ÿ’Š"
71
+ speak_no_evil: str = "๐Ÿ™Š"
72
+ sunglasses: str = "๐Ÿ˜Ž"
73
+ alien: str = "๐Ÿ‘พ"
74
+ man_shrugging: str = "๐Ÿคทโ€โ™‚"
75
+ woman_shrugging: str = "๐Ÿคทโ€โ™€"
76
+
77
+
78
+
79
+
@@ -0,0 +1,7 @@
1
+ import os
2
+
3
+ def clear_terminal():
4
+ if os.name == 'nt':
5
+ os.system('cls')
6
+ else:
7
+ os.system('clear')
d4rk/__init__.py ADDED
@@ -0,0 +1,4 @@
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 *
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: d4rktg
3
+ Version: 0.0.0
4
+ Summary: A module for create with easy and fast
5
+ Author: D4rkShell
6
+ Author-email: premiumqtrst@gmail.com
7
+ Keywords: python,telegram bot,D4rkShell
8
+ Classifier: Development Status :: 1 - Planning
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Description-Content-Type: text/x-rst
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: keywords
19
+ Dynamic: summary
20
+
21
+ # D4rkTG
@@ -0,0 +1,22 @@
1
+ d4rk/__init__.py,sha256=D_LsfqQDH3llMwpc--LZB05e7-uKCOqdIlI-BVSiqMM,164
2
+ d4rk/Database/__init__.py,sha256=TQB5D8PBDCq80jPq6rsC2G939yYYKTh_bCcOWsZ-nA8,18
3
+ d4rk/Database/db.py,sha256=5T-dbHPQp9JF2rQb707SLSSkAaz8ghX4lO7g_Siy7oA,1870
4
+ d4rk/Handlers/__init__.py,sha256=BBdnh4RAPXNJ1loFq6l-5FELzMNSSAkr0JWWiBl3GkA,102
5
+ d4rk/Handlers/_bot.py,sha256=eTPQ0FwGl8BYSWrHE_ui1Zcg5J2IjtoxDlpfbSdoHys,8941
6
+ d4rk/Handlers/_custom.py,sha256=gKvdxJZkfL1bgVfy6cRgymMo6T9hk3fJuQ7IQ_KsenY,5274
7
+ d4rk/Handlers/_scheduler.py,sha256=AyqexO4nxZlIzRfU9vWTfJtTWQVQmP4de7GRPg-3JkA,1236
8
+ d4rk/Logs/__init__.py,sha256=mXWD5jXnyH3_AvS7K_ki3iw5BpoEAvrDFbmr-iEFNnY,22
9
+ d4rk/Logs/_logger.py,sha256=lqfVvCO0vZ_IaGOdIE4HA2KAUQZh7yW2iAHZcBz7F4o,4120
10
+ d4rk/Utils/__init__.py,sha256=YL8lDvupE1mX9DPeM2g9QNpfATph8j2SNCDUZCIeACg,362
11
+ d4rk/Utils/_buttons.py,sha256=gehLWh0NOQSkSNAIuUBEJ8jN2uzNDail2tJboV4656w,3311
12
+ d4rk/Utils/_decorators.py,sha256=Ffd_tXwyzRF3W5fUjuiAxgSGozUVqRPO26lGvB3hFbw,3693
13
+ d4rk/Utils/_filters.py,sha256=r_Dait6tcAg4drqDgBsIYKg7BA4Pd8S1yEbdGHj3A0g,2781
14
+ d4rk/Utils/_fonts.py,sha256=4zpjAmhAhRGzkSaD1b80p_bpwF72mOe7ykcpJFc688w,3690
15
+ d4rk/Utils/_ip.py,sha256=KJJW2QSngshIVWCO5YPXF1wj4IPQzVN5oFofpfzlU5w,559
16
+ d4rk/Utils/_movie_parser.py,sha256=Pyd_eSyzp0bBMfil0YY0zypsDWBk7LoDQBfMOQJh16Y,6204
17
+ d4rk/Utils/_ractions.py,sha256=wOVPyoFnbDuMgoP6NF_gLO1DYcfhERC0trdAK1jWSE8,2170
18
+ d4rk/Utils/_terminal.py,sha256=Anu4OcffY3v6LMOrCskP1cHrJIliomo1Hjownbhh2sQ,125
19
+ d4rktg-0.0.0.dist-info/METADATA,sha256=W6YADmACyrYDpSMTjHiRg8KZCtfDZi8VAhVk7UbTFXY,595
20
+ d4rktg-0.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ d4rktg-0.0.0.dist-info/top_level.txt,sha256=qs1qTnKWImmGi7E0FoJS0OAEOHoVZA9vHRS3Pm6ncAo,5
22
+ d4rktg-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ d4rk