diff --git a/universal.py b/universal.py index b0d8454..b12bba1 100644 --- a/universal.py +++ b/universal.py @@ -1,20 +1,17 @@ -# meta developer: @origsama -# requires: yt-dlp curl_cffi +# meta developer: @HoroshoVse +# requires: yt-dlp from .. import loader, utils -import requests -import re import os import asyncio import tempfile -import urllib.parse import json import shutil import sys @loader.tds -class SocialDownloaderMod(loader.Module): - """Скачивание видео из TikTok, Instagram, YouTube, VK""" - strings = {"name": "SocialDownloader"} +class YIDownloaderMod(loader.Module): + """Универсальный скачиватель видео""" + strings = {"name": "YI downloader"} def __init__(self): self.config = loader.ModuleConfig( @@ -67,19 +64,25 @@ class SocialDownloaderMod(loader.Module): caption += f"\n🔗 Оригинал" - await status.delete() - - await message.client.send_file( - message.chat_id, - video_path, - caption=caption, - reply_to=message.reply_to_msg_id or message.id - ) - - os.remove(video_path) + try: + await message.client.send_file( + message.chat_id, + video_path, + caption=caption, + reply_to=message.reply_to_msg_id or message.id + ) + await status.delete() + except Exception as e: + await status.edit(f"❌ Ошибка отправки в Telegram: {str(e)}") + finally: + if os.path.exists(video_path): + os.remove(video_path) except Exception as e: - await status.edit(f"❌ Ошибка: {str(e)}") + try: + await status.edit(f"❌ Ошибка: {str(e)}") + except: + pass def detect_source(self, url): url = url.lower() @@ -106,16 +109,17 @@ class SocialDownloaderMod(loader.Module): cmd = [ sys.executable, '-m', 'yt_dlp', - '-f', 'bestvideo+bestaudio/best', + '-f', 'bestvideo+bestaudio/best', + '--merge-output-format', 'mp4', '--max-filesize', f"{self.config['max_size']}M", '-o', output_template, url ] if source.lower() == 'tiktok': - cmd.extend(['--cookies', 'tiktok_cookies.txt']) + cmd.extend(['--cookies', 'tiktok_cookies.txt', '--downloader', 'default', '--compat-options', 'no-impersonate']) elif source.lower() == 'instagram': - cmd.extend(['--cookies', 'instagram_cookies.txt']) + cmd.extend(['--cookies', 'instagram_cookies.txt', '--downloader', 'default', '--compat-options', 'no-impersonate']) process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE @@ -131,18 +135,20 @@ class SocialDownloaderMod(loader.Module): final_path = os.path.join(tempfile.gettempdir(), file) shutil.copy2(file_path, final_path) - info = await self.get_video_info(url) + info = await self.get_video_info(url, source) return final_path, info return None, "Файл не найден после скачивания" except Exception as e: - print(f"Download error: {e}") return None, str(e) - async def get_video_info(self, url): + async def get_video_info(self, url, source): try: cmd = [sys.executable, '-m', 'yt_dlp', '--dump-json', '--no-playlist', url] + if source.lower() in ['tiktok', 'instagram']: + cmd.extend(['--downloader', 'default', '--compat-options', 'no-impersonate']) + process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) @@ -150,7 +156,6 @@ class SocialDownloaderMod(loader.Module): if process.returncode == 0: data = json.loads(stdout.decode('utf-8')) - duration = data.get('duration', 0) minutes = duration // 60 seconds = duration % 60 @@ -163,95 +168,4 @@ class SocialDownloaderMod(loader.Module): return {} except: return {} - - async def tiktokcmd(self, message): - """<ссылка> - Скачать видео с TikTok""" - args = utils.get_args_raw(message) - if not args: - await utils.answer(message, "❌ Укажи ссылку на TikTok") - return - await self.dlcmd(message) - - async def instacmd(self, message): - """<ссылка> - Скачать видео/фото с Instagram""" - args = utils.get_args_raw(message) - if not args: - await utils.answer(message, "❌ Укажи ссылку на Instagram") - return - await self.dlcmd(message) - - async def ytcmd(self, message): - """<ссылка> [качество] - Скачать видео с YouTube""" - args = utils.get_args_raw(message) - if not args: - await utils.answer(message, "❌ Укажи ссылку на YouTube") - return - - parts = args.split() - url = parts[0] - quality = parts[1] if len(parts) > 1 else 'best' - - await utils.answer(message, f"📥 Скачиваю с YouTube ({quality})...") - - try: - with tempfile.TemporaryDirectory() as temp_dir: - output_template = os.path.join(temp_dir, '%(title)s.%(ext)s') - - format_str = f'bestvideo[height<={quality}]+bestaudio/best[height<={quality}]/best' if quality != 'best' else 'bestvideo+bestaudio/best' - - cmd = [ - sys.executable, '-m', 'yt_dlp', - '-f', format_str, - '--max-filesize', f"{self.config['max_size']}M", - '-o', output_template, - url - ] - - process = await asyncio.create_subprocess_exec( - *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await process.communicate() - - if process.returncode != 0: - err_msg = stderr.decode('utf-8', errors='ignore') - await utils.answer(message, f"❌ Ошибка скачивания:\n{utils.escape_html(err_msg)}") - return - - for file in os.listdir(temp_dir): - file_path = os.path.join(temp_dir, file) - if os.path.isfile(file_path): - final_path = os.path.join(tempfile.gettempdir(), file) - shutil.copy2(file_path, final_path) - - info = await self.get_video_info(url) - - caption = f"🎥 YouTube\n" - if info.get('title'): - caption += f"📝 {info['title']}\n" - if info.get('author'): - caption += f"👤 {info['author']}\n" - if info.get('duration'): - caption += f"⏱ {info['duration']}\n" - caption += f"\n⚙️ {quality}" - - await message.client.send_file( - message.chat_id, - final_path, - caption=caption - ) - - os.remove(final_path) - return - - except Exception as e: - await utils.answer(message, f"❌ Ошибка: {str(e)}") - - async def vkcmd(self, message): - """<ссылка> - Скачать видео с VK""" - args = utils.get_args_raw(message) - if not args: - await utils.answer(message, "❌ Укажи ссылку на VK видео") - return - await self.dlcmd(message) - \ No newline at end of file