mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-18 15:14:18 +02:00
Added and updated repositories 2026-01-27 01:17:35
This commit is contained in:
@@ -42,6 +42,7 @@ from .. import loader, utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@loader.tds
|
||||
class YTDLMod(loader.Module):
|
||||
"""Downloads and sends audio/video from YouTube"""
|
||||
@@ -50,46 +51,47 @@ class YTDLMod(loader.Module):
|
||||
"name": "YTDL",
|
||||
"_cls_doc": "Downloads and sends audio/video from YouTube",
|
||||
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> There is no arguments or they are invalid",
|
||||
"downloading_video": "<emoji document_id=5215484787325676090>🕐</emoji> Video is downloading...",
|
||||
"downloaded_video": "<emoji document_id=5854762571659218443>✅</emoji> Video is downloaded!",
|
||||
"downloading_audio": "<emoji document_id=5215484787325676090>🕐</emoji> Audio is downloading...",
|
||||
"downloaded_audio": "<emoji document_id=5854762571659218443>✅</emoji> Audio is downloaded!",
|
||||
"downloading": "<emoji document_id=5215484787325676090>🕐</emoji> Downloading...",
|
||||
"done": "<emoji document_id=5854762571659218443>✅</emoji> Done!",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"_cls_doc": "Скачивает и отправляет аудио/видео с Ютуба",
|
||||
"invalid_args": "<emoji document_id=5854929766146118183>❌</emoji> Нет аргументов или они неверны",
|
||||
"downloading_video": "<emoji document_id=5215484787325676090>🕐</emoji> Видео скачивается...",
|
||||
"downloaded_video": "<emoji document_id=5854762571659218443>✅</emoji> Видео загружено!",
|
||||
"downloading_audio": "<emoji document_id=5215484787325676090>🕐</emoji> Аудио скачивается...",
|
||||
"downloaded_audio": "<emoji document_id=5854762571659218443>✅</emoji> Аудио загружено!",
|
||||
"downloading": "<emoji document_id=5215484787325676090>🕐</emoji> Скачиваю...",
|
||||
"done": "<emoji document_id=5854762571659218443>✅</emoji> Готово!",
|
||||
}
|
||||
|
||||
|
||||
def _validate_url(self, url: str) -> bool:
|
||||
"""Validate URL format"""
|
||||
if not url:
|
||||
return False
|
||||
|
||||
url_pattern = re.compile(
|
||||
r'^(?:https?://)?(?:www\.|m\.)?(?:youtube\.com|youtu\.be|music\.youtube\.com)/(?:watch\?v=|playlist\?list=|channel/|@|live/|shorts/)?[\w-]+',
|
||||
re.IGNORECASE
|
||||
r"^(?:https?://)?(?:www\.|m\.)?(?:youtube\.com|youtu\.be|music\.youtube\.com)/(?:watch\?v=|playlist\?list=|channel/|@|live/|shorts/)?[\w-]+",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
return url_pattern.match(url) is not None
|
||||
|
||||
async def get_target(self):
|
||||
system = platform.system()
|
||||
machine = platform.machine().lower()
|
||||
machine = platform.machine().lower()
|
||||
|
||||
if system == "Windows":
|
||||
return "Windows"
|
||||
|
||||
|
||||
if system == "Darwin":
|
||||
return "aarch64-apple-darwin" if machine == "arm64" else "x86_64-apple-darwin"
|
||||
|
||||
return (
|
||||
"aarch64-apple-darwin" if machine == "arm64" else "x86_64-apple-darwin"
|
||||
)
|
||||
|
||||
if system == "Linux":
|
||||
return "aarch64-unknown-linux-gnu" if machine in ("aarch64", "arm64") else "x86_64-unknown-linux-gnu"
|
||||
return (
|
||||
"aarch64-unknown-linux-gnu"
|
||||
if machine in ("aarch64", "arm64")
|
||||
else "x86_64-unknown-linux-gnu"
|
||||
)
|
||||
|
||||
return "x86_64-unknown-linux-gnu"
|
||||
|
||||
@@ -106,138 +108,131 @@ class YTDLMod(loader.Module):
|
||||
async def client_ready(self, client, db):
|
||||
deno_path = Path("deno")
|
||||
deno_which = shutil.which("deno")
|
||||
|
||||
# Trying to fix previous shitcode...
|
||||
if self.get("deno_source") == "file":
|
||||
self.set("deno_source", str(deno_path.resolve()))
|
||||
|
||||
if not deno_which and not deno_path.is_file():
|
||||
logger.warning("Deno is not installed, attempting installation...")
|
||||
target = await self.get_target()
|
||||
if target == "Windows":
|
||||
logger.critical("Windows platform is unsupported by this module. All future commands will fail. Please, unload the module.")
|
||||
return
|
||||
logger.critical(
|
||||
"Windows platform is unsupported by this module. All future commands will fail. Please, unload the module."
|
||||
)
|
||||
return
|
||||
async with aiohttp.ClientSession() as session:
|
||||
download_link = f"https://github.com/denoland/deno/releases/latest/download/deno-{target}.zip"
|
||||
async with session.get(download_link) as resp:
|
||||
if resp.status == 200:
|
||||
async with aiofiles.open("deno.zip", mode='wb') as f:
|
||||
async for chunk in resp.content.iter_chunked(8192):
|
||||
await f.write(chunk)
|
||||
async with aiofiles.open("deno.zip", mode="wb") as f:
|
||||
async for chunk in resp.content.iter_chunked(8192):
|
||||
await f.write(chunk)
|
||||
else:
|
||||
logger.critical(f"Failed to download Deno: HTTP {resp.status}")
|
||||
self.set("deno_source", "install_failed")
|
||||
return
|
||||
if Path("deno.zip").is_file():
|
||||
with zipfile.ZipFile("deno.zip","r") as zip_ref:
|
||||
with zipfile.ZipFile("deno.zip", "r") as zip_ref:
|
||||
zip_ref.extractall()
|
||||
os.remove("deno.zip")
|
||||
os.chmod(deno_path, 0o755)
|
||||
self.set("deno_source", "file")
|
||||
self.set("deno_source", str(deno_path.resolve()))
|
||||
elif deno_which:
|
||||
self.set("deno_source", deno_which)
|
||||
|
||||
@loader.command(
|
||||
en_doc="Download video",
|
||||
ru_doc="Скачать видео"
|
||||
)
|
||||
|
||||
@loader.command(en_doc="Download video", ru_doc="Скачать видео")
|
||||
async def ytdlvcmd(self, message):
|
||||
args = utils.get_args(message)
|
||||
if not args or not self._validate_url(args[0]) or len(args) > 1:
|
||||
await utils.answer(message, self.strings['invalid_args'])
|
||||
await utils.answer(message, self.strings["invalid_args"])
|
||||
return
|
||||
|
||||
|
||||
source = self.get('deno_source')
|
||||
deno_path = Path('deno').resolve() if source == 'file' else source if source != 'install_failed' else None
|
||||
if not deno_path:
|
||||
logger.critical("Deno wasn't installed in auto-mode. Please, install it manually or resolve the issue and reboot userbot.")
|
||||
source = self.get("deno_source")
|
||||
if source == "install_failed" or not Path(source).is_file():
|
||||
logger.critical(
|
||||
"Deno wasn't installed in auto-mode. Please, install it manually or resolve the issue and reboot userbot."
|
||||
)
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings['downloading_video'])
|
||||
|
||||
|
||||
await utils.answer(message, self.strings["downloading"])
|
||||
|
||||
filename_prefix = f"video_{message.id}"
|
||||
ydl_opts = {
|
||||
'quiet': True,
|
||||
'outtmpl': f'{filename_prefix}.%(ext)s',
|
||||
'js_runtimes': {'deno': {'path': str(deno_path)}},
|
||||
|
||||
'extractor_args': {
|
||||
'youtube': {
|
||||
'player_client': ['mweb', 'android'],
|
||||
"quiet": True,
|
||||
"outtmpl": f"{filename_prefix}.%(ext)s",
|
||||
"js_runtimes": {"deno": {"path": source}},
|
||||
"postprocessors": [
|
||||
{
|
||||
"key": "FFmpegVideoConvertor",
|
||||
"preferedformat": "mp4",
|
||||
}
|
||||
},
|
||||
|
||||
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
|
||||
|
||||
'postprocessors': [{
|
||||
'key': 'FFmpegVideoConvertor',
|
||||
'preferedformat': 'mp4',
|
||||
}],
|
||||
'postprocessor_args': {
|
||||
'video_convertor': [
|
||||
'-c:v', 'libx264',
|
||||
'-pix_fmt', 'yuv420p',
|
||||
'-preset', 'veryfast',
|
||||
'-crf', '23',
|
||||
'-c:a', 'aac'
|
||||
],
|
||||
"postprocessor_args": {
|
||||
"video_convertor": [
|
||||
"-c:v",
|
||||
"libx264",
|
||||
"-pix_fmt",
|
||||
"yuv420p",
|
||||
"-preset",
|
||||
"veryfast",
|
||||
"-crf",
|
||||
"23",
|
||||
"-c:a",
|
||||
"aac",
|
||||
],
|
||||
'merger': [
|
||||
'-movflags', 'faststart'
|
||||
]
|
||||
"merger": ["-movflags", "faststart"],
|
||||
},
|
||||
}
|
||||
if self.get('youtube_cookie'):
|
||||
ydl_opts['cookiefile'] = self.get('youtube_cookie')
|
||||
if self.get("youtube_cookie"):
|
||||
ydl_opts["cookiefile"] = self.get("youtube_cookie")
|
||||
with YoutubeDL(ydl_opts) as ydl:
|
||||
info = ydl.extract_info(args[0], download=True)
|
||||
filename = ydl.prepare_filename(info)
|
||||
await self.client.send_file(message.chat_id, filename, caption=self.strings['downloaded_video'])
|
||||
await message.delete()
|
||||
filename = ydl.prepare_filename(info).split(".")[0] + ".mp4"
|
||||
await utils.answer(message, self.strings['done'], file=filename, invert_media=True)
|
||||
os.remove(filename)
|
||||
|
||||
@loader.command(
|
||||
en_doc="Download audio",
|
||||
ru_doc="Скачать аудио"
|
||||
)
|
||||
@loader.command(en_doc="Download audio", ru_doc="Скачать аудио")
|
||||
async def ytdlacmd(self, message):
|
||||
args = utils.get_args(message)
|
||||
if not args or not self._validate_url(args[0]) or len(args) > 1:
|
||||
await utils.answer(message, self.strings['invalid_args'])
|
||||
await utils.answer(message, self.strings["invalid_args"])
|
||||
return
|
||||
|
||||
|
||||
source = self.get('deno_source')
|
||||
deno_path = Path('deno').resolve() if source == 'file' else source if source != 'install_failed' else None
|
||||
if not deno_path:
|
||||
logger.critical("Deno wasn't installed in auto-mode. Please, install it manually or resolve the issue and reboot userbot.")
|
||||
source = self.get("deno_source")
|
||||
if source == "install_failed" or not Path(source).is_file():
|
||||
logger.critical(
|
||||
"Deno wasn't installed in auto-mode. Please, install it manually or resolve the issue and reboot userbot."
|
||||
)
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings['downloading_audio'])
|
||||
|
||||
|
||||
await utils.answer(message, self.strings["downloading"])
|
||||
|
||||
filename_prefix = f"audio_{message.id}"
|
||||
ydl_opts = {
|
||||
'quiet': True,
|
||||
'outtmpl': f'{filename_prefix}.%(ext)s',
|
||||
'js_runtimes': {'deno': {'path': str(deno_path)}},
|
||||
|
||||
'postprocessors': [
|
||||
{
|
||||
'key': 'FFmpegExtractAudio',
|
||||
'preferredcodec': 'mp3',
|
||||
'preferredquality': '0',
|
||||
},
|
||||
{
|
||||
'key': 'FFmpegMetadata',
|
||||
'add_metadata': True,
|
||||
},
|
||||
{
|
||||
'key': 'EmbedThumbnail',
|
||||
},
|
||||
],
|
||||
'writethumbnail': True,
|
||||
"quiet": True,
|
||||
"outtmpl": f"{filename_prefix}.%(ext)s",
|
||||
"js_runtimes": {"deno": {"path": source}},
|
||||
"postprocessors": [
|
||||
{
|
||||
"key": "FFmpegExtractAudio",
|
||||
"preferredcodec": "mp3",
|
||||
"preferredquality": "0",
|
||||
},
|
||||
{
|
||||
"key": "FFmpegMetadata",
|
||||
"add_metadata": True,
|
||||
},
|
||||
{
|
||||
"key": "EmbedThumbnail",
|
||||
},
|
||||
],
|
||||
"writethumbnail": True,
|
||||
}
|
||||
if self.get('youtube_cookie'):
|
||||
ydl_opts['cookiefile'] = self.get('youtube_cookie')
|
||||
if self.get("youtube_cookie"):
|
||||
ydl_opts["cookiefile"] = self.get("youtube_cookie")
|
||||
with YoutubeDL(ydl_opts) as ydl:
|
||||
info = ydl.extract_info(args[0], download=True)
|
||||
filename = ydl.prepare_filename(info).split(".")[0] + ".mp3"
|
||||
await self.client.send_file(message.chat_id, filename, caption=self.strings['downloaded_audio'])
|
||||
await message.delete()
|
||||
|
||||
|
||||
|
||||
await utils.answer(message, self.strings['done'], file=filename)
|
||||
os.remove(filename)
|
||||
|
||||
Reference in New Issue
Block a user