diff --git a/README.md b/README.md
index 20ec5624..42048c0e 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,7 @@ In each single file there is a major change from base code, it's almost totaly d
- Custom default video quality for each user
- Fix download progress
- Embed original thumbnail and add it for leech
+- All supported audio formats
### Database
- Mongo Database support
- Store bot settings
diff --git a/bot/helper/ext_utils/help_messages.py b/bot/helper/ext_utils/help_messages.py
index 63d1330f..6ca4e025 100644
--- a/bot/helper/ext_utils/help_messages.py
+++ b/bot/helper/ext_utils/help_messages.py
@@ -44,6 +44,7 @@ Check here all RcloneFlags.
2. Options (s, m: and multi) should be added randomly before link and before any other option.
3. Options (n:, pswd: and opt:) should be added randomly after the link if link along with the cmd or after cmd if by reply.
4. You can always add video quality from yt-dlp api options.
+5. Don't add file extension while rename using `n:`
Check all yt-dlp api options from this FILE.
"""
diff --git a/bot/helper/mirror_utils/download_utils/yt_dlp_download.py b/bot/helper/mirror_utils/download_utils/yt_dlp_download.py
index 60fa235e..6b28a51e 100644
--- a/bot/helper/mirror_utils/download_utils/yt_dlp_download.py
+++ b/bot/helper/mirror_utils/download_utils/yt_dlp_download.py
@@ -191,12 +191,18 @@ class YoutubeDLHelper:
{'add_chapters': True, 'add_infojson': 'if_exists', 'add_metadata': True, 'key': 'FFmpegMetadata'}]
if qual.startswith('ba/b-'):
- mp3_info = qual.split('-')
- qual = mp3_info[0]
- rate = mp3_info[1]
+ audio_info = qual.split('-')
+ qual = audio_info[0]
+ audio_format = audio_info[1]
+ rate = audio_info[2]
self.opts['postprocessors'].append(
- {'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': rate})
- self.__ext = '.mp3'
+ {'key': 'FFmpegExtractAudio', 'preferredcodec': audio_format, 'preferredquality': rate})
+ if audio_format == 'vorbis':
+ self.__ext = '.ogg'
+ elif audio_format == 'alac':
+ self.__ext = '.m4a'
+ else:
+ self.__ext = f'.{audio_format}'
self.opts['format'] = qual
@@ -226,7 +232,6 @@ class YoutubeDLHelper:
elif not self.__listener.isLeech:
self.opts['writethumbnail'] = False
-
msg, button = await stop_duplicate_check(name, self.__listener)
if msg:
await self.__listener.onDownloadError(msg, button)
diff --git a/bot/helper/mirror_utils/rclone_utils/list.py b/bot/helper/mirror_utils/rclone_utils/list.py
index cf3c7225..f0baa7b7 100644
--- a/bot/helper/mirror_utils/rclone_utils/list.py
+++ b/bot/helper/mirror_utils/rclone_utils/list.py
@@ -15,7 +15,6 @@ from bot.helper.telegram_helper.message_utils import sendMessage, editMessage
from bot.helper.ext_utils.bot_utils import cmd_exec, new_thread, get_readable_file_size, new_task, get_readable_time
LIST_LIMIT = 6
-TIMEOUT = 240
@new_task
@@ -92,6 +91,7 @@ class RcloneList:
self.__sections = []
self.__reply_to = None
self.__time = time()
+ self.__timeout = 240
self.remote = ''
self.is_cancelled = False
self.query_proc = False
@@ -111,7 +111,7 @@ class RcloneList:
handler = self.__client.add_handler(CallbackQueryHandler(
pfunc, filters=regex('^rcq') & user(self.__user_id)), group=-1)
try:
- await wait_for(self.event.wait(), timeout=240)
+ await wait_for(self.event.wait(), timeout=self.__timeout)
except:
self.path = ''
self.remote = 'Timed Out. Task has been cancelled!'
@@ -173,7 +173,7 @@ class RcloneList:
msg += f' | Page: {int(page)}/{pages} | Page Step: {self.page_step}'
msg += f'\n\nItem Type: {self.item_type}\nConfig Path: {self.config_path}'
msg += f'\nCurrent Path: {self.remote}{self.path}
'
- msg += f'\nTimeout: {get_readable_time(TIMEOUT-(time()-self.__time))}'
+ msg += f'\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
await self.__send_list_message(msg, button)
async def get_path(self, itype=''):
@@ -218,7 +218,7 @@ class RcloneList:
('\nTransfer Type: Download' if self.list_status ==
'rcd' else '\nTransfer Type: Upload')
msg += f'\nConfig Path: {self.config_path}'
- msg += f'\nTimeout: {get_readable_time(TIMEOUT-(time()-self.__time))}'
+ msg += f'\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
buttons = ButtonMaker()
for remote in self.__sections:
buttons.ibutton(remote, f'rcq re {remote}:')
@@ -233,7 +233,7 @@ class RcloneList:
msg = 'Choose Rclone config:' + \
('\nTransfer Type: Download' if self.list_status ==
'rcd' else '\nTransfer Type: Upload')
- msg += f'\nTimeout: {get_readable_time(TIMEOUT-(time()-self.__time))}'
+ msg += f'\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
buttons = ButtonMaker()
buttons.ibutton('Owner Config', 'rcq owner')
buttons.ibutton('My Config', 'rcq user')
diff --git a/bot/helper/mirror_utils/upload_utils/pyrogramEngine.py b/bot/helper/mirror_utils/upload_utils/pyrogramEngine.py
index 6ac99e54..ee434cc0 100644
--- a/bot/helper/mirror_utils/upload_utils/pyrogramEngine.py
+++ b/bot/helper/mirror_utils/upload_utils/pyrogramEngine.py
@@ -229,8 +229,9 @@ class TgUploader:
if not is_image and thumb is None:
file_name = ospath.splitext(file)[0]
- if await aiopath.isfile(f"{self.__path}/yt-dlp-thumb/{file_name}.jpg"):
- thumb = f"{self.__path}/yt-dlp-thumb/{file_name}.jpg"
+ thumb_path = f"{self.__path}/yt-dlp-thumb/{file_name}.jpg"
+ if await aiopath.isfile(thumb_path):
+ thumb = thumb_path
if self.__as_doc or force_document or (not is_video and not is_audio and not is_image):
key = 'documents'
diff --git a/bot/modules/bot_settings.py b/bot/modules/bot_settings.py
index b68c4c8c..400445e8 100644
--- a/bot/modules/bot_settings.py
+++ b/bot/modules/bot_settings.py
@@ -806,7 +806,7 @@ async def edit_bot_settings(client, query):
await event_handler(client, query, pfunc, rfunc)
elif data[1] == 'editaria' and STATE == 'view':
value = aria2_options[data[2]]
- if len(value) > 200:
+ if len(str(value)) > 200:
await query.answer()
with BytesIO(str.encode(value)) as out_file:
out_file.name = f"{data[2]}.txt"
diff --git a/bot/modules/rss.py b/bot/modules/rss.py
index 57827cd5..bcbe2e1e 100644
--- a/bot/modules/rss.py
+++ b/bot/modules/rss.py
@@ -9,9 +9,10 @@ from functools import partial
from aiohttp import ClientSession
from apscheduler.triggers.interval import IntervalTrigger
from re import split as re_split
+from io import BytesIO
from bot import scheduler, rss_dict, LOGGER, DATABASE_URL, config_dict, bot
-from bot.helper.telegram_helper.message_utils import sendMessage, editMessage, sendRss
+from bot.helper.telegram_helper.message_utils import sendMessage, editMessage, sendRss, sendFile
from bot.helper.telegram_helper.filters import CustomFilters
from bot.helper.telegram_helper.bot_commands import BotCommands
from bot.helper.ext_utils.db_handler import DbManger
@@ -273,7 +274,14 @@ async def rssGet(client, message, pre_event):
link = rss_d.entries[item_num]['link']
item_info += f"Name: {rss_d.entries[item_num]['title'].replace('>', '').replace('<', '')}
\n"
item_info += f"Link: {link}
\n\n"
- await editMessage(msg, item_info)
+ item_info_ecd = item_info.encode()
+ if len(item_info_ecd) > 4000:
+ with BytesIO(item_info_ecd) as out_file:
+ out_file.name = f"rssGet {title} items_no. {count}.txt"
+ await sendFile(message, out_file)
+ await msg.delete()
+ else:
+ await editMessage(msg, item_info)
except IndexError as e:
LOGGER.error(str(e))
await editMessage(msg, "Parse depth exceeded. Try again with a lower value.")
@@ -282,7 +290,7 @@ async def rssGet(client, message, pre_event):
await editMessage(msg, str(e))
except Exception as e:
LOGGER.error(str(e))
- await sendMessage(message, f"Enter a vaild value!. {e}")
+ await sendMessage(message, f"Enter a valid value!. {e}")
await updateRssMenu(pre_event)
@@ -297,7 +305,7 @@ async def rssEdit(client, message, pre_event):
await sendMessage(message, f'{item}. Wrong Input format. Read help message before editing!')
continue
elif not rss_dict[user_id].get(title, False):
- await sendMessage(message, "Enter a vaild title. Title not found!")
+ await sendMessage(message, "Enter a valid title. Title not found!")
continue
inf_lists = []
exf_lists = []
@@ -415,7 +423,7 @@ async def rssListener(client, query):
buttons.ibutton("Back", f"rss back {user_id}")
buttons.ibutton("Close", f"rss close {user_id}")
button = buttons.build_menu(2)
- await editMessage(message, 'Send one title with vlaue seperated by space get last X items.\nTitle Value\nTimeout: 60 sec.', button)
+ await editMessage(message, 'Send one title with vlaue separated by space get last X items.\nTitle Value\nTimeout: 60 sec.', button)
pfunc = partial(rssGet, pre_event=query)
await event_handler(client, query, pfunc)
elif data[1] in ['unsubscribe', 'pause', 'resume']:
@@ -435,7 +443,7 @@ async def rssListener(client, query):
buttons.ibutton("Unsub AllMyFeeds", f"rss uallunsub {user_id}")
buttons.ibutton("Close", f"rss close {user_id}")
button = buttons.build_menu(2)
- await editMessage(message, f'Send one or more rss titles seperated by space to {data[1]}.\nTimeout: 60 sec.', button)
+ await editMessage(message, f'Send one or more rss titles separated by space to {data[1]}.\nTimeout: 60 sec.', button)
pfunc = partial(rssUpdate, pre_event=query, state=data[1])
await event_handler(client, query, pfunc)
elif data[1] == 'edit':
@@ -448,7 +456,7 @@ async def rssListener(client, query):
buttons.ibutton("Back", f"rss back {user_id}")
buttons.ibutton("Close", f"rss close {user_id}")
button = buttons.build_menu(2)
- msg = '''Send one or more rss titles with new filters or command seperated by new line.
+ msg = '''Send one or more rss titles with new filters or command separated by new line.
Examples:
Title1 c: mirror exf: none inf: 1080 or 720 opt: up: remote:path/subdir
Title2 c: none inf: none opt: none
@@ -526,7 +534,7 @@ Timeout: 60 sec.
buttons.ibutton("Back", f"rss back {user_id}")
buttons.ibutton("Close", f"rss close {user_id}")
button = buttons.build_menu(2)
- msg = 'Send one or more user_id seperated by space to delete their resources.\nTimeout: 60 sec.'
+ msg = 'Send one or more user_id separated by space to delete their resources.\nTimeout: 60 sec.'
await editMessage(message, msg, button)
pfunc = partial(rssDelete, pre_event=query)
await event_handler(client, query, pfunc)
diff --git a/bot/modules/users_settings.py b/bot/modules/users_settings.py
index fad13663..17da46cf 100644
--- a/bot/modules/users_settings.py
+++ b/bot/modules/users_settings.py
@@ -317,8 +317,9 @@ Check all available qualities options {b_name}:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
+ await editMessage(self.__reply_to, msg, subbuttons)
+
+ async def mp3_subbuttons(self):
+ i = 's' if self.__is_playlist else ''
+ buttons = ButtonMaker()
+ audio_qualities = [64, 128, 320]
+ for q in audio_qualities:
+ audio_format = f'ba/b-mp3-{q}'
+ buttons.ibutton(f'{q}K-mp3', f'ytq {audio_format}')
+ buttons.ibutton('Back', 'ytq back')
+ buttons.ibutton('Cancel', 'ytq cancel')
+ subbuttons = buttons.build_menu(3)
+ msg = f'Choose mp3 Audio{i} Bitrate:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
+ await editMessage(self.__reply_to, msg, subbuttons)
+
+ async def audio_format(self):
+ i = 's' if self.__is_playlist else ''
+ buttons = ButtonMaker()
+ for frmt in ['aac', 'alac', 'flac', 'm4a', 'opus', 'vorbis', 'wav']:
+ audio_format = f'ba/b-{frmt}-'
+ buttons.ibutton(frmt, f'ytq aq {audio_format}')
+ buttons.ibutton('Back', 'ytq back', 'footer')
+ buttons.ibutton('Cancel', 'ytq cancel', 'footer')
+ subbuttons = buttons.build_menu(3)
+ msg = f'Choose Audio{i} Format:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
+ await editMessage(self.__reply_to, msg, subbuttons)
+
+ async def audio_quality(self, format):
+ i = 's' if self.__is_playlist else ''
+ buttons = ButtonMaker()
+ for qual in range(11):
+ audio_format = f'{format}{qual}'
+ buttons.ibutton(qual, f'ytq {audio_format}')
+ buttons.ibutton('Back', 'ytq aq back')
+ buttons.ibutton('Cancel', 'ytq aq cancel')
+ subbuttons = buttons.build_menu(5)
+ msg = f'Choose Audio{i} Qaulity:\n0 is best and 10 is worst\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
+ await editMessage(self.__reply_to, msg, subbuttons)
def extract_info(link):
@@ -41,20 +237,10 @@ async def _mdisk(link, name):
return name, link
-async def _auto_cancel(msg, task_id):
- await sleep(120)
- try:
- del listener_dict[task_id]
- await editMessage(msg, 'Timed out! Task has been cancelled.')
- except:
- pass
-
-
@new_task
async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
mssg = message.text
user_id = message.from_user.id
- msg_id = message.id
qual = ''
select = False
multi = 0
@@ -76,7 +262,7 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
elif x.startswith('m:'):
marg = x.split('m:', 1)
if len(marg) > 1:
- folder_name = f"/{marg[1]}"
+ folder_name = f'/{marg[1]}'
if not sameDir:
sameDir = set()
sameDir.add(message.id)
@@ -97,8 +283,8 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
await sleep(4)
nextmsg = await client.get_messages(chat_id=message.chat.id, message_ids=message.reply_to_message_id + 1)
ymsg = mssg.split(maxsplit=mi+1)
- ymsg[mi] = f"{multi - 1}"
- nextmsg = await sendMessage(nextmsg, " ".join(ymsg))
+ ymsg[mi] = f'{multi - 1}'
+ nextmsg = await sendMessage(nextmsg, ' '.join(ymsg))
nextmsg = await client.get_messages(chat_id=message.chat.id, message_ids=nextmsg.id)
if len(folder_name) > 0:
sameDir.add(nextmsg.id)
@@ -129,7 +315,7 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
0].strip() if len(up) > 1 else None
if username := message.from_user.username:
- tag = f"@{username}"
+ tag = f'@{username}'
else:
tag = message.from_user.mention
@@ -138,7 +324,7 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
link = reply_to.text.split('\n', 1)[0].strip()
if not reply_to.from_user.is_bot:
if username := reply_to.from_user.username:
- tag = f"@{username}"
+ tag = f'@{username}'
else:
tag = reply_to.from_user.mention
@@ -163,7 +349,7 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
else:
config_path = 'rclone.conf'
if not await aiopath.exists(config_path):
- await sendMessage(message, f"Rclone Config: {config_path} not Exists!")
+ await sendMessage(message, f'Rclone Config: {config_path} not Exists!')
return
if up == 'rcl' and not isLeech:
@@ -180,7 +366,7 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
result = await sync_to_async(extract_info, link)
except Exception as e:
msg = str(e).replace('<', ' ').replace('>', ' ')
- await sendMessage(message, f"{tag} {msg}")
+ await sendMessage(message, f'{tag} {msg}')
__run_multi()
return
@@ -199,170 +385,14 @@ async def _ytdl(client, message, isZip=False, isLeech=False, sameDir={}):
else:
qual = config_dict.get('YT_DLP_QUALITY')
- if qual:
- playlist = 'entries' in result
- LOGGER.info(f"Downloading with YT-DLP: {link}")
- ydl = YoutubeDLHelper(listener)
- await ydl.add_download(link, path, name, qual, playlist, opt)
- else:
- buttons = ButtonMaker()
- best_video = "bv*+ba/b"
- best_audio = "ba/b"
- formats_dict = {}
- if 'entries' in result:
- for i in ['144', '240', '360', '480', '720', '1080', '1440', '2160']:
- video_format = f"bv*[height<=?{i}][ext=mp4]+ba[ext=m4a]/b[height<=?{i}]"
- b_data = f"{i}|mp4"
- formats_dict[b_data] = video_format
- buttons.ibutton(f"{i}-mp4", f"qu {msg_id} {b_data} t")
- video_format = f"bv*[height<=?{i}][ext=webm]+ba/b[height<=?{i}]"
- b_data = f"{i}|webm"
- formats_dict[b_data] = video_format
- buttons.ibutton(f"{i}-webm", f"qu {msg_id} {b_data} t")
- buttons.ibutton("MP3", f"qu {msg_id} mp3 t")
- buttons.ibutton("Best Videos", f"qu {msg_id} {best_video} t")
- buttons.ibutton("Best Audios", f"qu {msg_id} {best_audio} t")
- buttons.ibutton("Cancel", f"qu {msg_id} cancel")
- mbuttons = buttons.build_menu(3)
- bmsg = await sendMessage(message, 'Choose Playlist Videos Quality:', mbuttons)
- else:
- formats = result.get('formats')
- is_m4a = False
- if formats is not None:
- for frmt in formats:
- if frmt.get('tbr'):
-
- format_id = frmt['format_id']
-
- if frmt.get('filesize'):
- size = frmt['filesize']
- elif frmt.get('filesize_approx'):
- size = frmt['filesize_approx']
- else:
- size = 0
-
- if frmt.get('video_ext') == 'none' and frmt.get('acodec') != 'none':
- if frmt.get('audio_ext') == 'm4a':
- is_m4a = True
- b_name = f"{frmt['acodec']}-{frmt['ext']}"
- v_format = f"ba[format_id={format_id}]"
- elif frmt.get('height'):
- height = frmt['height']
- ext = frmt['ext']
- fps = frmt['fps'] if frmt.get('fps') else ''
- b_name = f"{height}p{fps}-{ext}"
- ba_ext = '[ext=m4a]' if is_m4a and ext == 'mp4' else ''
- v_format = f"bv*[format_id={format_id}]+ba{ba_ext}/b[height=?{height}]"
- else:
- continue
-
- formats_dict.setdefault(b_name, {})[str(frmt['tbr'])] = [
- size, v_format]
-
- for b_name, tbr_dict in formats_dict.items():
- if len(tbr_dict) == 1:
- tbr, v_list = next(iter(tbr_dict.items()))
- buttonName = f"{b_name} ({get_readable_file_size(v_list[0])})"
- buttons.ibutton(
- buttonName, f"qu {msg_id} {b_name}|{tbr}")
- else:
- buttons.ibutton(b_name, f"qu {msg_id} dict {b_name}")
- buttons.ibutton("MP3", f"qu {msg_id} mp3")
- buttons.ibutton("Best Video", f"qu {msg_id} {best_video}")
- buttons.ibutton("Best Audio", f"qu {msg_id} {best_audio}")
- buttons.ibutton("Cancel", f"qu {msg_id} cancel")
- mbuttons = buttons.build_menu(2)
- bmsg = await sendMessage(message, 'Choose Video Quality:', mbuttons)
-
- listener_dict[msg_id] = [listener, user_id, link,
- name, mbuttons, opt, formats_dict, path]
- await _auto_cancel(bmsg, msg_id)
-
-
-async def _qual_subbuttons(task_id, b_name, msg):
- buttons = ButtonMaker()
- tbr_dict = listener_dict[task_id][6][b_name]
- for tbr, d_data in tbr_dict.items():
- button_name = f"{tbr}K ({get_readable_file_size(d_data[0])})"
- buttons.ibutton(button_name, f"qu {task_id} {b_name}|{tbr}")
- buttons.ibutton("Back", f"qu {task_id} back")
- buttons.ibutton("Cancel", f"qu {task_id} cancel")
- subbuttons = buttons.build_menu(2)
- await editMessage(msg, f"Choose Bit rate for {b_name}:", subbuttons)
-
-
-async def _mp3_subbuttons(task_id, msg, playlist=False):
- buttons = ButtonMaker()
- audio_qualities = [64, 128, 320]
- for q in audio_qualities:
- if playlist:
- i = 's'
- audio_format = f"ba/b-{q} t"
- else:
- i = ''
- audio_format = f"ba/b-{q}"
- buttons.ibutton(f"{q}K-mp3", f"qu {task_id} {audio_format}")
- buttons.ibutton("Back", f"qu {task_id} back")
- buttons.ibutton("Cancel", f"qu {task_id} cancel")
- subbuttons = buttons.build_menu(2)
- await editMessage(msg, f"Choose Audio{i} Bitrate:", subbuttons)
-
-
-@new_task
-async def select_format(client, query):
- user_id = query.from_user.id
- data = query.data.split()
- message = query.message
- task_id = int(data[1])
- try:
- task_info = listener_dict[task_id]
- except:
- await editMessage(message, "This is an old task")
- return
- uid = task_info[1]
- if user_id != uid and not await CustomFilters.sudo(client, query):
- await query.answer(text="This task is not for you!", show_alert=True)
- return
- elif data[2] == "dict":
- await query.answer()
- b_name = data[3]
- await _qual_subbuttons(task_id, b_name, message)
- return
- elif data[2] == "back":
- await query.answer()
- await editMessage(message, 'Choose Video Quality:', task_info[4])
- return
- elif data[2] == "mp3":
- await query.answer()
- playlist = len(data) == 4
- await _mp3_subbuttons(task_id, message, playlist)
- return
- elif data[2] == "cancel":
- await query.answer()
- await editMessage(message, 'Task has been cancelled.')
- del listener_dict[task_id]
- else:
- await query.answer()
- listener = task_info[0]
- link = task_info[2]
- name = task_info[3]
- opt = task_info[5]
- qual = data[2]
- path = task_info[7]
- if len(data) == 4:
- playlist = True
- if '|' in qual:
- qual = task_info[6][qual]
- else:
- playlist = False
- if '|' in qual:
- b_name, tbr = qual.split('|')
- qual = task_info[6][b_name][tbr][1]
- LOGGER.info(f"Downloading with YT-DLP: {link}")
- await message.delete()
- del listener_dict[task_id]
- ydl = YoutubeDLHelper(listener)
- await ydl.add_download(link, path, name, qual, playlist, opt)
+ if not qual:
+ qual = await YtSelection(client, message).get_quality(result)
+ if qual is None:
+ return
+ LOGGER.info(f'Downloading with YT-DLP: {link}')
+ playlist = 'entries' in result
+ ydl = YoutubeDLHelper(listener)
+ await ydl.add_download(link, path, name, qual, playlist, opt)
async def ytdl(client, message):
@@ -388,4 +418,3 @@ bot.add_handler(MessageHandler(ytdlleech, filters=command(
BotCommands.YtdlLeechCommand) & CustomFilters.authorized))
bot.add_handler(MessageHandler(ytdlZipleech, filters=command(
BotCommands.YtdlZipLeechCommand) & CustomFilters.authorized))
-bot.add_handler(CallbackQueryHandler(select_format, filters=regex("^qu")))