mirror of
https://github.com/anasty17/mirror-leech-telegram-bot.git
synced 2025-01-08 12:07:33 +08:00
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:
parent
819ada9c25
commit
3a298b6c36
@ -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
|
||||
|
@ -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>.
|
||||
"""
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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'
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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")))
|
||||
|
Loading…
Reference in New Issue
Block a user