update

swadhinbiswas committed 2 years ago
2e0fc11
1 parent 8c4f84e
commit 2e0fc11
9 files changed
+671 -19
β–Όapp/__init__.py
+0-0
0
0
β–Όapp/bot/helper/ext-utils/help_message.py
+0-19
1
-mirror="""
2
-<b>πŸ”° Mirror Bot</b>
3
-<b>πŸ”° Version:</b> <code>1.0.0</code>
4
-/cmd link
5
-
6
-<b>By replying to link/file</b>: <code>mirror</code>
7
-
8
-/cmd -n new name -e -up upload destination
9
-<b>Example:</b> <code>/cmd -n new name -e -up upload destination</code>
10
-
11
-<b>NOTE:</b>
12
-1. Commands that start with <b>qb</b> are ONLY for torrents.
13
-
14
-"""
15
-
16
-yt="""<b>πŸ”° YouTube Downloader</b>
17
-
18
-
19
-"""
20
0
β–Όapp/bot/helper/ext-utils/__init__.py β†’ app/bot/helper/ext_utils/__init__.py
+0-0
0
0
β–Όapp/bot/helper/ext_utils/bot_utils.py
+225-0
1
+from aiohttp import ClientSession
2
+
3
+from asyncio import (
4
+ create_subprocess_exec,
5
+ create_subprocess_shell,
6
+ run_coroutine_threadsafe,
7
+ sleep,
8
+)
9
+
10
+from asyncio.subprocess import PIPE
11
+from concurrent.futures import ThreadPoolExecutor
12
+from functools import partial, wraps
13
+
14
+from bot import user_data,config_dict,bot_loop
15
+
16
+from bot.helper.ext_utils.bot_utils import (
17
+ YT_HELP_DICT,
18
+ MIRROR_HELP_DICT,)
19
+from app.bot.helper.ext_utils import telegraph
20
+from bot.helper.telegram_helper.button_build import ButtonMaker
21
+
22
+THREADPOOL = ThreadPoolExecutor(max_workers=1000)
23
+
24
+COMMAND_USAGE = {}
25
+
26
+
27
+class setInterval:
28
+ def __init__(self, interval, action, *args, **kwargs):
29
+ self.interval = interval
30
+ self.action = action
31
+ self.task = bot_loop.create_task(self._set_interval(*args, **kwargs))
32
+
33
+ async def _set_interval(self, *args, **kwargs):
34
+ while True:
35
+ await sleep(self.interval)
36
+ await self.action(*args, **kwargs)
37
+
38
+ def cancel(self):
39
+ self.task.cancel()
40
+
41
+
42
+def create_help_buttons():
43
+ buttons = ButtonMaker()
44
+ for name in list(MIRROR_HELP_DICT.keys())[1:]:
45
+ buttons.ibutton(name, f"help mirror {name}")
46
+ buttons.ibutton("Close", "help close")
47
+ COMMAND_USAGE["mirror"] = [MIRROR_HELP_DICT["main"], buttons.build_menu(3)]
48
+ buttons.reset()
49
+ for name in list(YT_HELP_DICT.keys())[1:]:
50
+ buttons.ibutton(name, f"help yt {name}")
51
+ buttons.ibutton("Close", "help close")
52
+ COMMAND_USAGE["yt"] = [YT_HELP_DICT["main"], buttons.build_menu(3)]
53
+ buttons.reset()
54
+ for name in list(CLONE_HELP_DICT.keys())[1:]:
55
+ buttons.ibutton(name, f"help clone {name}")
56
+ buttons.ibutton("Close", "help close")
57
+ COMMAND_USAGE["clone"] = [CLONE_HELP_DICT["main"], buttons.build_menu(3)]
58
+
59
+
60
+def bt_selection_buttons(id_):
61
+ gid = id_[:12] if len(id_) > 20 else id_
62
+ pincode = "".join([n for n in id_ if n.isdigit()][:4])
63
+ buttons = ButtonMaker()
64
+ BASE_URL = config_dict["BASE_URL"]
65
+ if config_dict["WEB_PINCODE"]:
66
+ buttons.ubutton("Select Files", f"{BASE_URL}/app/files/{id_}")
67
+ buttons.ibutton("Pincode", f"btsel pin {gid} {pincode}")
68
+ else:
69
+ buttons.ubutton(
70
+ "Select Files", f"{BASE_URL}/app/files/{id_}?pin_code={pincode}"
71
+ )
72
+ buttons.ibutton("Done Selecting", f"btsel done {gid} {id_}")
73
+ buttons.ibutton("Cancel", f"btsel cancel {gid}")
74
+ return buttons.build_menu(2)
75
+
76
+
77
+async def get_telegraph_list(telegraph_content):
78
+ path = [
79
+ (
80
+ await telegraph.create_page(
81
+ title="Mirror-Leech-Bot Drive Search", content=content
82
+ )
83
+ )["path"]
84
+ for content in telegraph_content
85
+ ]
86
+ if len(path) > 1:
87
+ await telegraph.edit_telegraph(path, telegraph_content)
88
+ buttons = ButtonMaker()
89
+ buttons.ubutton("πŸ”Ž VIEW", f"https://telegra.ph/{path[0]}")
90
+ return buttons.build_menu(1)
91
+
92
+
93
+def arg_parser(items, arg_base):
94
+ if not items:
95
+ return
96
+ bool_arg_set = {
97
+ "-b",
98
+ "-e",
99
+ "-z",
100
+ "-s",
101
+ "-j",
102
+ "-d",
103
+ "-sv",
104
+ "-ss",
105
+ "-f",
106
+ "-fd",
107
+ "-fu",
108
+ "-sync",
109
+ "-ml",
110
+ }
111
+ t = len(items)
112
+ i = 0
113
+ arg_start = -1
114
+
115
+ while i + 1 <= t:
116
+ part = items[i]
117
+ if part in arg_base:
118
+ if arg_start == -1:
119
+ arg_start = i
120
+ if (
121
+ i + 1 == t
122
+ and part in bool_arg_set
123
+ or part in ["-s", "-j", "-f", "-fd", "-fu", "-sync", "-ml"]
124
+ ):
125
+ arg_base[part] = True
126
+ else:
127
+ sub_list = []
128
+ for j in range(i + 1, t):
129
+ item = items[j]
130
+ if item in arg_base:
131
+ if part in bool_arg_set and not sub_list:
132
+ arg_base[part] = True
133
+ break
134
+ sub_list.append(item)
135
+ i += 1
136
+ if sub_list:
137
+ arg_base[part] = " ".join(sub_list)
138
+ i += 1
139
+ if "link" in arg_base and items[0] not in arg_base:
140
+ link = []
141
+ if arg_start == -1:
142
+ link.extend(iter(items))
143
+ else:
144
+ link.extend(items[r] for r in range(arg_start))
145
+ if link:
146
+ arg_base["link"] = " ".join(link)
147
+
148
+
149
+def getSizeBytes(size):
150
+ size = size.lower()
151
+ if size.endswith("mb"):
152
+ size = size.split("mb")[0]
153
+ size = int(float(size) * 1048576)
154
+ elif size.endswith("gb"):
155
+ size = size.split("gb")[0]
156
+ size = int(float(size) * 1073741824)
157
+ else:
158
+ size = 0
159
+ return size
160
+
161
+
162
+async def get_content_type(url):
163
+ try:
164
+ async with ClientSession() as session:
165
+ async with session.get(url, allow_redirects=True, ssl=False) as response:
166
+ return response.headers.get("Content-Type")
167
+ except:
168
+ return None
169
+
170
+
171
+def update_user_ldata(id_, key, value):
172
+ user_data.setdefault(id_, {})
173
+ user_data[id_][key] = value
174
+
175
+
176
+async def retry_function(func, *args, **kwargs):
177
+ try:
178
+ return await func(*args, **kwargs)
179
+ except:
180
+ return await retry_function(func, *args, **kwargs)
181
+
182
+
183
+async def cmd_exec(cmd, shell=False):
184
+ if shell:
185
+ proc = await create_subprocess_shell(cmd, stdout=PIPE, stderr=PIPE)
186
+ else:
187
+ proc = await create_subprocess_exec(*cmd, stdout=PIPE, stderr=PIPE)
188
+ stdout, stderr = await proc.communicate()
189
+ try:
190
+ stdout = stdout.decode().strip()
191
+ except:
192
+ stdout = "Unable to decode the response!"
193
+ try:
194
+ stderr = stderr.decode().strip()
195
+ except:
196
+ stderr = "Unable to decode the error!"
197
+ return stdout, stderr, proc.returncode
198
+
199
+
200
+def new_task(func):
201
+ @wraps(func)
202
+ def wrapper(*args, **kwargs):
203
+ return bot_loop.create_task(func(*args, **kwargs))
204
+
205
+ return wrapper
206
+
207
+
208
+async def sync_to_async(func, *args, wait=True, **kwargs):
209
+ pfunc = partial(func, *args, **kwargs)
210
+ future = bot_loop.run_in_executor(THREADPOOL, pfunc)
211
+ return await future if wait else future
212
+
213
+
214
+def async_to_sync(func, *args, wait=True, **kwargs):
215
+ future = run_coroutine_threadsafe(func(*args, **kwargs), bot_loop)
216
+ return future.result() if wait else future
217
+
218
+
219
+def new_thread(func):
220
+ @wraps(func)
221
+ def wrapper(*args, wait=False, **kwargs):
222
+ future = run_coroutine_threadsafe(func(*args, **kwargs), bot_loop)
223
+ return future.result() if wait else future
224
+
225
+ return wrapper
0
226
β–Όapp/bot/helper/ext_utils/dbhandelar.py
+37-0
1
+from aiofiles import open as aiopen
2
+from aiofiles.os import path as aiopath,makedirs
3
+from dotenv import load_dotenv,dotenv_values
4
+from motor.motor_asyncio import AsyncIOMotorClient
5
+from pymongo.errors import PyMongoError
6
+from app.settings.config import MONGO_DB_URI,USER_DATA,LOGGER
7
+
8
+class DbManager:
9
+ def __init__(self):
10
+ self._err=False
11
+ self._db=None
12
+ self._conn=None
13
+ self._connect()
14
+
15
+ def connect(self):
16
+ try:
17
+ self._conn = AsyncIOMotorClient(DATABASE_URL)
18
+ self._db = self._conn.mltb
19
+ except PyMongoError as e:
20
+ LOGGER.error(f"Error in DB connection: {e}")
21
+ self._err = True
22
+
23
+
24
+ async def close(self):
25
+ if self._conn:
26
+ self._conn.close()
27
+ LOGGER.info("DB Connection Closed")
28
+
29
+ async def get_metadata(self):
30
+ return await self._db.metadata.find_all()
31
+
32
+
33
+
34
+
35
+
36
+if MONGO_DB_URI:
37
+ bot_loop.run_until_complete(DbManager().connect())
0
38
β–Όapp/bot/helper/ext_utils/help_message.py
+96-0
1
+mirror="""
2
+<b>πŸ”° Mirror Bot</b>
3
+<b>πŸ”° Version:</b> <code>1.0.0</code>
4
+/cmd link
5
+
6
+<b>By replying to link/file</b>: <code>mirror</code>
7
+
8
+/cmd -n new name -e -up upload destination
9
+<b>Example:</b> <code>/cmd -n new name -e -up upload destination</code>
10
+
11
+<b>NOTE:</b>
12
+1. Commands that start with <b>qb</b> are ONLY for torrents.
13
+
14
+"""
15
+
16
+yt="""<b>πŸ”° YouTube Downloader</b>
17
+"<b>Send link along with command line</b>:
18
+
19
+/cmd link
20
+<b>By replying to link</b>:
21
+/cmd -n new name -z password -opt x:y|x1:y1
22
+
23
+Check here all supported <a href='https://github.com/swadhinbiswas/Streamz/blob/main/supportedsite.md'>SITES</a>
24
+Check all yt-dlp api options from this <a href='https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L184'>FILE</a> to convert cli arguments to api options.
25
+
26
+"""
27
+thumb = """<b>Thumbnail for current task</b>: -t
28
+
29
+/cmd link -t tg-message-link(doc or photo)"""
30
+
31
+split_size = """<b>Split size for current task</b>: -sp
32
+
33
+/cmd link -sp (500mb or 2gb or 4000000000)
34
+Note: Only mb and gb are supported or write in bytes without unit!"""
35
+
36
+upload="""<b>Upload Your File </b>: -up
37
+
38
+/cmd link<code> yourlink </code>"""
39
+
40
+
41
+YT_HELP_DICT = {
42
+ "main": yt,
43
+ "New-Name": f"{new_name}\nNote: Don't add file extension",
44
+ "Zip": zip_arg,
45
+ "Quality": qual,
46
+ "Options": yt_opt,
47
+ "Multi-Link": multi_link,
48
+ "Same-Directory": same_dir,
49
+ "Thumb": thumb,
50
+ "Split-Size": split_size,
51
+ "Upload-Destination": upload,
52
+ "Rclone-Flags": rcf,
53
+ "Bulk": bulk,
54
+ "Sample-Video": sample_video,
55
+ "Screenshot": screenshot,
56
+ "Convert-Media": convert_media,
57
+ "Force-Start": force_start,
58
+ "Name-Substitute": name_sub,
59
+ "Mixed-Leech": mixed_leech,
60
+}
61
+
62
+MIRROR_HELP_DICT = {
63
+ "main": mirror,
64
+ "New-Name": new_name,
65
+ "DL-Auth": "<b>Direct link authorization</b>: -au -ap\n\n/cmd link -au username -ap password",
66
+ "Headers": "<b>Direct link custom headers</b>: -h\n\n/cmd link -h key: value key1: value1",
67
+ "Extract/Zip": extract_zip,
68
+ "Torrent-Files": "<b>Bittorrent/JDownloader File Selection</b>: -s\n\n/cmd link -s or by replying to file/link",
69
+ "Torrent-Seed": seed,
70
+ "Multi-Link": multi_link,
71
+ "Same-Directory": same_dir,
72
+ "Thumb": thumb,
73
+ "Split-Size": split_size,
74
+ "Upload-Destination": upload,
75
+ "Rclone-Flags": rcf,
76
+ "Bulk": bulk,
77
+ "Join": join,
78
+ "Rclone-DL": rlone_dl,
79
+ "Tg-Links": tg_links,
80
+ "Sample-Video": sample_video,
81
+ "Screenshot": screenshot,
82
+ "Convert-Media": convert_media,
83
+ "Force-Start": force_start,
84
+ "User-Download": user_download,
85
+ "Name-Substitute": name_sub,
86
+ "Mixed-Leech": mixed_leech,
87
+}
88
+
89
+
90
+
91
+PASSWORD_ERROR_MESSAGE = """
92
+<b>This link requires a password!</b>
93
+- Insert <b>::</b> after the link and write the password after the sign.
94
+
95
+<b>Example:</b> link::my password
96
+"""
0
97
β–Όapp/bot/helper/ext_utils/status.py
+227-0
1
+from html import escape
2
+from psutil import virtual_memory, cpu_percent, disk_usage
3
+from time import time
4
+from asyncio import iscoroutinefunction
5
+
6
+
7
+from bot import (
8
+ DOWNLOAD_DIR,
9
+ task_dict,
10
+ task_dict_lock,
11
+ botStartTime,
12
+ config_dict,
13
+ status_dict,
14
+)
15
+
16
+from bot.helper.ext_utils.bot_utils import sync_to_async
17
+from bot.helper.telegram_helper.button_build import ButtonMaker
18
+
19
+SIZE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB"]
20
+
21
+
22
+
23
+class MirrorStatus:
24
+ STATUS_UPLOADING = "Upload"
25
+ STATUS_DOWNLOADING = "Download"
26
+ STATUS_CLONING = "Clone"
27
+ STATUS_QUEUEDL = "QueueDl"
28
+ STATUS_QUEUEUP = "QueueUp"
29
+ STATUS_PAUSED = "Pause"
30
+ STATUS_ARCHIVING = "Archive"
31
+ STATUS_EXTRACTING = "Extract"
32
+ STATUS_SPLITTING = "Split"
33
+ STATUS_CHECKING = "CheckUp"
34
+ STATUS_SEEDING = "Seed"
35
+ STATUS_SAMVID = "SamVid"
36
+ STATUS_CONVERTING = "Convert"
37
+
38
+
39
+
40
+
41
+STATUSES = {
42
+ "ALL": "All",
43
+ "DL": MirrorStatus.STATUS_DOWNLOADING,
44
+ "UP": MirrorStatus.STATUS_UPLOADING,
45
+ "QD": MirrorStatus.STATUS_QUEUEDL,
46
+ "QU": MirrorStatus.STATUS_QUEUEUP,
47
+ "AR": MirrorStatus.STATUS_ARCHIVING,
48
+ "EX": MirrorStatus.STATUS_EXTRACTING,
49
+ "SD": MirrorStatus.STATUS_SEEDING,
50
+ "CM": MirrorStatus.STATUS_CONVERTING,
51
+ "CL": MirrorStatus.STATUS_CLONING,
52
+ "DF": "Delete File",
53
+}
54
+
55
+async def getTaskByGid(gid: str):
56
+ async with task_dict_lock:
57
+ for tk in task_dict.values():
58
+ if hasattr(tk, "seeding"):
59
+ await sync_to_async(tk.update)
60
+ if tk.gid() == gid:
61
+ return tk
62
+ return None
63
+
64
+
65
+def getSpecificTasks(status, userId):
66
+ if status == "All":
67
+ if userId:
68
+ return [tk for tk in task_dict.values() if tk.listener.userId == userId]
69
+ else:
70
+ return list(task_dict.values())
71
+ elif userId:
72
+ return [
73
+ tk
74
+ for tk in task_dict.values()
75
+ if tk.listener.userId == userId
76
+ and (
77
+ (st := tk.status())
78
+ and st == status
79
+ or status == MirrorStatus.STATUS_DOWNLOADING
80
+ and st not in STATUSES.values()
81
+ )
82
+ ]
83
+ else:
84
+ return [
85
+ tk
86
+ for tk in task_dict.values()
87
+ if (st := tk.status())
88
+ and st == status
89
+ or status == MirrorStatus.STATUS_DOWNLOADING
90
+ and st not in STATUSES.values()
91
+ ]
92
+
93
+
94
+async def getAllTasks(req_status: str, userId):
95
+ async with task_dict_lock:
96
+ return await sync_to_async(getSpecificTasks, req_status, userId)
97
+
98
+
99
+def get_readable_file_size(size_in_bytes: int):
100
+ if size_in_bytes is None:
101
+ return "0B"
102
+ index = 0
103
+ while size_in_bytes >= 1024 and index < len(SIZE_UNITS) - 1:
104
+ size_in_bytes /= 1024
105
+ index += 1
106
+ return (
107
+ f"{size_in_bytes:.2f}{SIZE_UNITS[index]}"
108
+ if index > 0
109
+ else f"{size_in_bytes:.2f}B"
110
+ )
111
+
112
+
113
+def get_readable_time(seconds: int):
114
+ periods = [("d", 86400), ("h", 3600), ("m", 60), ("s", 1)]
115
+ result = ""
116
+ for period_name, period_seconds in periods:
117
+ if seconds >= period_seconds:
118
+ period_value, seconds = divmod(seconds, period_seconds)
119
+ result += f"{int(period_value)}{period_name}"
120
+ return result
121
+
122
+
123
+def speed_string_to_bytes(size_text: str):
124
+ size = 0
125
+ size_text = size_text.lower()
126
+ if "k" in size_text:
127
+ size += float(size_text.split("k")[0]) * 1024
128
+ elif "m" in size_text:
129
+ size += float(size_text.split("m")[0]) * 1048576
130
+ elif "g" in size_text:
131
+ size += float(size_text.split("g")[0]) * 1073741824
132
+ elif "t" in size_text:
133
+ size += float(size_text.split("t")[0]) * 1099511627776
134
+ elif "b" in size_text:
135
+ size += float(size_text.split("b")[0])
136
+ return size
137
+
138
+
139
+def get_progress_bar_string(pct):
140
+ pct = float(pct.strip("%"))
141
+ p = min(max(pct, 0), 100)
142
+ cFull = int(p // 8)
143
+ p_str = "β– " * cFull
144
+ p_str += "β–‘" * (12 - cFull)
145
+ return f"[{p_str}]"
146
+
147
+
148
+async def get_readable_message(sid, is_user, page_no=1, status="All", page_step=1):
149
+ msg = ""
150
+ button = None
151
+
152
+ tasks = await sync_to_async(getSpecificTasks, status, sid if is_user else None)
153
+
154
+ STATUS_LIMIT = config_dict["STATUS_LIMIT"]
155
+ tasks_no = len(tasks)
156
+ pages = (max(tasks_no, 1) + STATUS_LIMIT - 1) // STATUS_LIMIT
157
+ if page_no > pages:
158
+ page_no = (page_no - 1) % pages + 1
159
+ status_dict[sid]["page_no"] = page_no
160
+ elif page_no < 1:
161
+ page_no = pages - (abs(page_no) % pages)
162
+ status_dict[sid]["page_no"] = page_no
163
+ start_position = (page_no - 1) * STATUS_LIMIT
164
+
165
+ for index, task in enumerate(
166
+ tasks[start_position : STATUS_LIMIT + start_position], start=1
167
+ ):
168
+ tstatus = await sync_to_async(task.status) if status == "All" else status
169
+ if task.listener.isSuperChat:
170
+ msg += f"<b>{index + start_position}.<a href='{task.listener.message.link}'>{tstatus}</a>: </b>"
171
+ else:
172
+ msg += f"<b>{index + start_position}.{tstatus}: </b>"
173
+ msg += f"<code>{escape(f'{task.name()}')}</code>"
174
+ if tstatus not in [
175
+ MirrorStatus.STATUS_SPLITTING,
176
+ MirrorStatus.STATUS_SEEDING,
177
+ MirrorStatus.STATUS_SAMVID,
178
+ MirrorStatus.STATUS_CONVERTING,
179
+ MirrorStatus.STATUS_QUEUEUP,
180
+ ]:
181
+ progress = (
182
+ await task.progress()
183
+ if iscoroutinefunction(task.progress)
184
+ else task.progress()
185
+ )
186
+ msg += f"\n{get_progress_bar_string(progress)} {progress}"
187
+ msg += f"\n<b>Processed:</b> {task.processed_bytes()} of {task.size()}"
188
+ msg += f"\n<b>Speed:</b> {task.speed()} | <b>ETA:</b> {task.eta()}"
189
+ if hasattr(task, "seeders_num"):
190
+ try:
191
+ msg += f"\n<b>Seeders:</b> {task.seeders_num()} | <b>Leechers:</b> {task.leechers_num()}"
192
+ except:
193
+ pass
194
+ elif tstatus == MirrorStatus.STATUS_SEEDING:
195
+ msg += f"\n<b>Size: </b>{task.size()}"
196
+ msg += f"\n<b>Speed: </b>{task.seed_speed()}"
197
+ msg += f" | <b>Uploaded: </b>{task.uploaded_bytes()}"
198
+ msg += f"\n<b>Ratio: </b>{task.ratio()}"
199
+ msg += f" | <b>Time: </b>{task.seeding_time()}"
200
+ else:
201
+ msg += f"\n<b>Size: </b>{task.size()}"
202
+ msg += f"\n<b>Gid: </b><code>{task.gid()}</code>\n\n"
203
+
204
+ if len(msg) == 0:
205
+ if status == "All":
206
+ return None, None
207
+ else:
208
+ msg = f"No Active {status} Tasks!\n\n"
209
+ buttons = ButtonMaker()
210
+ if not is_user:
211
+ buttons.ibutton("πŸ“œ", f"status {sid} ov", position="header")
212
+ if len(tasks) > STATUS_LIMIT:
213
+ msg += f"<b>Page:</b> {page_no}/{pages} | <b>Tasks:</b> {tasks_no} | <b>Step:</b> {page_step}\n"
214
+ buttons.ibutton("<<", f"status {sid} pre", position="header")
215
+ buttons.ibutton(">>", f"status {sid} nex", position="header")
216
+ if tasks_no > 30:
217
+ for i in [1, 2, 4, 6, 8, 10, 15]:
218
+ buttons.ibutton(i, f"status {sid} ps {i}", position="footer")
219
+ if status != "All" or tasks_no > 20:
220
+ for label, status_value in list(STATUSES.items())[:9]:
221
+ if status_value != status:
222
+ buttons.ibutton(label, f"status {sid} st {status_value}")
223
+ buttons.ibutton("♻️", f"status {sid} ref", position="header")
224
+ button = buttons.build_menu(8)
225
+ msg += f"<b>CPU:</b> {cpu_percent()}% | <b>FREE:</b> {get_readable_file_size(disk_usage(DOWNLOAD_DIR).free)}"
226
+ msg += f"\n<b>RAM:</b> {virtual_memory().percent}% | <b>UPTIME:</b> {get_readable_time(time() - botStartTime)}"
227
+ return msg, button
0
228
β–Όapp/bot/helper/ext_utils/telegraph_helper.py
+86-0
1
+from asyncio import sleep
2
+from secrets import token_urlsafe
3
+from telegraph.aio import Telegraph
4
+from telegraph.exceptions import RetryAfterError
5
+from app.settings.config import Website_URL, Bot_URL
6
+
7
+from bot import LOGGER
8
+
9
+
10
+class TelegraphHelper:
11
+ def __init__(self, author_name=None, author_url=None):
12
+ self._telegraph = Telegraph(domain="graph.org")
13
+ self._author_name = author_name
14
+ self._author_url = author_url
15
+
16
+ async def create_account(self):
17
+ LOGGER.info("Creating Telegraph Account")
18
+ try:
19
+ await self._telegraph.create_account(
20
+ short_name=token_urlsafe(8),
21
+ author_name=self._author_name,
22
+ author_url=self._author_url,
23
+ )
24
+ except Exception as e:
25
+ LOGGER.error(f"Failed to create Telegraph Account: {e}")
26
+
27
+ async def create_page(self, title, content):
28
+ try:
29
+ return await self._telegraph.create_page(
30
+ title=title,
31
+ author_name=self._author_name,
32
+ author_url=self._author_url,
33
+ html_content=content,
34
+ )
35
+ except RetryAfterError as st:
36
+ LOGGER.warning(
37
+ f"Telegraph Flood control exceeded. I will sleep for {st.retry_after} seconds."
38
+ )
39
+ await sleep(st.retry_after)
40
+ return await self.create_page(title, content)
41
+
42
+ async def edit_page(self, path, title, content):
43
+ try:
44
+ return await self._telegraph.edit_page(
45
+ path=path,
46
+ title=title,
47
+ author_name=self._author_name,
48
+ author_url=self._author_url,
49
+ html_content=content,
50
+ )
51
+ except RetryAfterError as st:
52
+ LOGGER.warning(
53
+ f"Telegraph Flood control exceeded. I will sleep for {st.retry_after} seconds."
54
+ )
55
+ await sleep(st.retry_after)
56
+ return await self.edit_page(path, title, content)
57
+
58
+ async def edit_telegraph(self, path, telegraph_content):
59
+ nxt_page = 1
60
+ prev_page = 0
61
+ num_of_path = len(path)
62
+ for content in telegraph_content:
63
+ if nxt_page == 1:
64
+ content += (
65
+ f'<b><a href="https://telegra.ph/{path[nxt_page]}">Next</a></b>'
66
+ )
67
+ nxt_page += 1
68
+ else:
69
+ if prev_page <= num_of_path:
70
+ content += f'<b><a href="https://telegra.ph/{path[prev_page]}">Prev</a></b>'
71
+ prev_page += 1
72
+ if nxt_page < num_of_path:
73
+ content += f'<b> | <a href="https://telegra.ph/{path[nxt_page]}">Next</a></b>'
74
+ nxt_page += 1
75
+ await self.edit_page(
76
+ path=path[prev_page],
77
+ title="Mirror-leech-bot Torrent Search",
78
+ content=content,
79
+ )
80
+ return
81
+
82
+
83
+telegraph = TelegraphHelper(
84
+ "The Bot for Mirror Data Leeching", f"{Bot_URL}",
85
+ "Streamz", f"{Website_URL}"
86
+)
0
87
β–Όapp/settings/config.py
+0-0
0
0