Add all supported audios formats

- remux and re-encode not added i have added it and many errors raised.
- refactor yt selection

Signed-off-by: anasty17 <e.anastayyar@gmail.com>
This commit is contained in:
anasty17 2023-04-21 08:38:01 +03:00
parent 819ada9c25
commit 3a298b6c36
9 changed files with 256 additions and 210 deletions

View File

@ -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

View File

@ -44,6 +44,7 @@ Check here all <a href='https://rclone.org/flags/'>RcloneFlags</a>.
2. Options (<b>s, m: and multi</b>) should be added randomly before link and before any other option.
3. Options (<b>n:, pswd: and opt:</b>) 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 <a href='https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L184'>FILE</a>.
"""

View File

@ -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)

View File

@ -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: <code>{self.remote}{self.path}</code>'
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: <i>Download</i>' if self.list_status ==
'rcd' else '\nTransfer Type: <i>Upload</i>')
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')

View File

@ -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'

View File

@ -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"

View File

@ -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"<b>Name: </b><code>{rss_d.entries[item_num]['title'].replace('>', '').replace('<', '')}</code>\n"
item_info += f"<b>Link: </b><code>{link}</code>\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)

View File

@ -317,8 +317,9 @@ Check all available qualities options <a href="https://github.com/yt-dlp/yt-dlp#
async def send_users_settings(client, message):
if msg := ''.join(f'<code>{u}</code>: {escape(str(d))}\n\n' for u, d in user_data.items()):
if len(msg.encode()) > 4000:
with BytesIO(str.encode(msg)) as ofile:
msg_ecd = msg.encode()
if len(msg_ecd) > 4000:
with BytesIO(msg_ecd) as ofile:
ofile.name = 'users_settings.txt'
await sendFile(message, ofile)
else:

View File

@ -1,16 +1,18 @@
#!/usr/bin/env python3
from pyrogram.handlers import MessageHandler, CallbackQueryHandler
from pyrogram.filters import command, regex
from asyncio import sleep
from pyrogram.filters import command, regex, user
from asyncio import sleep, wait_for, Event, wrap_future
from re import split as re_split
from aiohttp import ClientSession
from aiofiles.os import path as aiopath
from yt_dlp import YoutubeDL
from functools import partial
from time import time
from bot import DOWNLOAD_DIR, bot, config_dict, user_data, LOGGER
from bot.helper.telegram_helper.message_utils import sendMessage, editMessage
from bot.helper.telegram_helper.button_build import ButtonMaker
from bot.helper.ext_utils.bot_utils import get_readable_file_size, is_url, new_task, sync_to_async, new_task, is_rclone_path
from bot.helper.ext_utils.bot_utils import get_readable_file_size, is_url, new_task, sync_to_async, new_task, is_rclone_path, new_thread, get_readable_time
from bot.helper.mirror_utils.download_utils.yt_dlp_download import YoutubeDLHelper
from bot.helper.mirror_utils.rclone_utils.list import RcloneList
from bot.helper.telegram_helper.bot_commands import BotCommands
@ -18,7 +20,201 @@ from bot.helper.telegram_helper.filters import CustomFilters
from bot.helper.listeners.tasks_listener import MirrorLeechListener
from bot.helper.ext_utils.help_messages import YT_HELP_MESSAGE
listener_dict = {}
@new_task
async def select_format(client, query, obj):
data = query.data.split()
message = query.message
await query.answer()
if data[1] == 'dict':
b_name = data[2]
await obj.qual_subbuttons(b_name)
elif data[1] == 'mp3':
await obj.mp3_subbuttons()
elif data[1] == 'audio':
await obj.audio_format()
elif data[1] == 'aq':
if data[2] == 'back':
await obj.audio_format()
else:
await obj.audio_quality(data[2])
elif data[1] == 'back':
await obj.back_to_main()
elif data[1] == 'cancel':
await editMessage(message, 'Task has been cancelled.')
obj.qual = None
obj.is_cancelled = True
obj.event.set()
else:
if data[1] == 'sub':
obj.qual = obj.formats[data[2]][data[3]][1]
elif '|' in data[1]:
obj.qual = obj.formats[data[1]]
else:
obj.qual = data[1]
obj.event.set()
class YtSelection:
def __init__(self, client, message):
self.__message = message
self.__user_id = message.from_user.id
self.__client = client
self.__is_m4a = False
self.__reply_to = None
self.__time = time()
self.__timeout = 120
self.__is_playlist = False
self.is_cancelled = False
self.__main_buttons = None
self.event = Event()
self.formats = {}
self.qual = None
@new_thread
async def __event_handler(self):
pfunc = partial(select_format, obj=self)
handler = self.__client.add_handler(CallbackQueryHandler(
pfunc, filters=regex('^ytq') & user(self.__user_id)), group=-1)
try:
await wait_for(self.event.wait(), timeout=self.__timeout)
except:
await editMessage(self.__reply_to, 'Timed Out. Task has been cancelled!')
self.qual = None
self.is_cancelled = True
self.event.set()
finally:
self.__client.remove_handler(*handler)
async def get_quality(self, result):
future = self.__event_handler()
buttons = ButtonMaker()
if 'entries' in result:
self.__is_playlist = True
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'
self.formats[b_data] = video_format
buttons.ibutton(f'{i}-mp4', f'ytq {b_data}')
video_format = f'bv*[height<=?{i}][ext=webm]+ba/b[height<=?{i}]'
b_data = f'{i}|webm'
self.formats[b_data] = video_format
buttons.ibutton(f'{i}-webm', f'ytq {b_data}')
buttons.ibutton('MP3', 'ytq mp3')
buttons.ibutton('Audio Formats', 'ytq audio')
buttons.ibutton('Best Videos', 'ytq bv*+ba/b')
buttons.ibutton('Best Audios', 'ytq ba/b')
buttons.ibutton('Cancel', 'ytq cancel', 'footer')
self.__main_buttons = buttons.build_menu(3)
msg = f'Choose Playlist Videos Quality:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
else:
format_dict = result.get('formats')
if format_dict is not None:
for item in format_dict:
if item.get('tbr'):
format_id = item['format_id']
if item.get('filesize'):
size = item['filesize']
elif item.get('filesize_approx'):
size = item['filesize_approx']
else:
size = 0
if item.get('video_ext') == 'none' and item.get('acodec') != 'none':
if item.get('audio_ext') == 'm4a':
self.__is_m4a = True
b_name = f"{item['acodec']}-{item['ext']}"
v_format = f'ba[format_id={format_id}]'
elif item.get('height'):
height = item['height']
ext = item['ext']
fps = item['fps'] if item.get('fps') else ''
b_name = f'{height}p{fps}-{ext}'
ba_ext = '[ext=m4a]' if self.__is_m4a and ext == 'mp4' else ''
v_format = f'bv*[format_id={format_id}]+ba{ba_ext}/b[height=?{height}]'
else:
continue
self.formats.setdefault(b_name, {})[f"{item['tbr']}"] = [
size, v_format]
for b_name, tbr_dict in self.formats.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'ytq sub {b_name} {tbr}')
else:
buttons.ibutton(b_name, f'ytq dict {b_name}')
buttons.ibutton('MP3', 'ytq mp3')
buttons.ibutton('Audio Formats', 'ytq audio')
buttons.ibutton('Best Video', 'ytq bv*+ba/b')
buttons.ibutton('Best Audio', 'ytq ba/b')
buttons.ibutton('Cancel', 'ytq cancel', 'footer')
self.__main_buttons = buttons.build_menu(2)
msg = f'Choose Video Quality:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
self.__reply_to = await sendMessage(self.__message, msg, self.__main_buttons)
await wrap_future(future)
if not self.is_cancelled:
await self.__reply_to.delete()
return self.qual
async def back_to_main(self):
if self.__is_playlist:
msg = f'Choose Playlist Videos Quality:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
else:
msg = f'Choose Video Quality:\nTimeout: {get_readable_time(self.__timeout-(time()-self.__time))}'
await editMessage(self.__reply_to, msg, self.__main_buttons)
async def qual_subbuttons(self, b_name):
buttons = ButtonMaker()
tbr_dict = self.formats[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'ytq sub {b_name} {tbr}')
buttons.ibutton('Back', 'ytq back', 'footer')
buttons.ibutton('Cancel', 'ytq cancel', 'footer')
subbuttons = buttons.build_menu(2)
msg = f'Choose Bit rate for <b>{b_name}</b>:\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>{b_name}</b>:", 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")))