diff --git a/universal.py b/universal.py
index 02c9185..580cd23 100644
--- a/universal.py
+++ b/universal.py
@@ -1,12 +1,14 @@
# meta developer: @origsama
+# requires: yt-dlp
from .. import loader, utils
import requests
import re
import os
-import subprocess
+import asyncio
import tempfile
import urllib.parse
import json
+import shutil
@loader.tds
class SocialDownloaderMod(loader.Module):
@@ -39,7 +41,6 @@ class SocialDownloaderMod(loader.Module):
)
return
- # Определяем источник
source = self.detect_source(args)
if not source:
await utils.answer(message, "❌ Неподдерживаемая ссылка")
@@ -48,14 +49,12 @@ class SocialDownloaderMod(loader.Module):
status = await utils.answer(message, f"📥 Скачиваю с {source}...")
try:
- # Скачиваем видео
video_path, info = await self.download_video(args, source)
if not video_path:
await status.edit("❌ Не удалось скачать видео")
return
- # Формируем описание
caption = f"📹 Видео с {source}\n\n"
if info.get('title'):
caption += f"📝 {info['title']}\n"
@@ -66,7 +65,6 @@ class SocialDownloaderMod(loader.Module):
caption += f"\n🔗 Оригинал"
- # Отправляем
await status.delete()
await message.client.send_file(
@@ -76,16 +74,13 @@ class SocialDownloaderMod(loader.Module):
reply_to=message.reply_to_msg_id or message.id
)
- # Чистим
os.remove(video_path)
except Exception as e:
await status.edit(f"❌ Ошибка: {str(e)}")
def detect_source(self, url):
- """Определяет источник по ссылке"""
url = url.lower()
-
sources = {
'tiktok': ['tiktok.com', 'vm.tiktok.com'],
'instagram': ['instagram.com', 'instagr.am'],
@@ -96,54 +91,45 @@ class SocialDownloaderMod(loader.Module):
'facebook': ['facebook.com', 'fb.com'],
'pinterest': ['pinterest.com', 'pin.it']
}
-
for source, domains in sources.items():
for domain in domains:
if domain in url:
return source.capitalize()
-
return None
async def download_video(self, url, source):
- """Скачивает видео через yt-dlp"""
try:
- # Создаем временную папку
with tempfile.TemporaryDirectory() as temp_dir:
output_template = os.path.join(temp_dir, '%(title)s.%(ext)s')
- # Формируем команду
cmd = [
'yt-dlp',
- '-f', 'best[filesize<50M]', # Лучшее качество до 50 МБ
+ '-f', 'best[filesize<50M]',
'--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'])
elif source.lower() == 'instagram':
cmd.extend(['--cookies', 'instagram_cookies.txt'])
- # Запускаем
- result = subprocess.run(cmd, capture_output=True, text=True)
+ process = await asyncio.create_subprocess_exec(
+ *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
+ )
+ stdout, stderr = await process.communicate()
- if result.returncode != 0:
+ if process.returncode != 0:
return None, {}
- # Ищем скачанный файл
for file in os.listdir(temp_dir):
file_path = os.path.join(temp_dir, file)
if os.path.isfile(file_path):
- # Копируем в постоянное место
- import shutil
final_path = os.path.join(tempfile.gettempdir(), file)
shutil.copy2(file_path, final_path)
- # Получаем информацию
info = await self.get_video_info(url)
-
return final_path, info
return None, {}
@@ -153,19 +139,15 @@ class SocialDownloaderMod(loader.Module):
return None, {}
async def get_video_info(self, url):
- """Получает информацию о видео"""
try:
- cmd = [
- 'yt-dlp',
- '--dump-json',
- '--no-playlist',
- url
- ]
+ cmd = ['yt-dlp', '--dump-json', '--no-playlist', url]
+ process = await asyncio.create_subprocess_exec(
+ *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
+ )
+ stdout, stderr = await process.communicate()
- result = subprocess.run(cmd, capture_output=True, text=True)
-
- if result.returncode == 0:
- data = json.loads(result.stdout)
+ if process.returncode == 0:
+ data = json.loads(stdout.decode('utf-8'))
duration = data.get('duration', 0)
minutes = duration // 60
@@ -176,7 +158,6 @@ class SocialDownloaderMod(loader.Module):
'author': data.get('uploader', data.get('channel', '')),
'duration': f"{minutes}:{seconds:02d}" if duration else ''
}
-
return {}
except:
return {}
@@ -187,7 +168,6 @@ class SocialDownloaderMod(loader.Module):
if not args:
await utils.answer(message, "❌ Укажи ссылку на TikTok")
return
-
await self.dlcmd(message)
async def instacmd(self, message):
@@ -196,7 +176,6 @@ class SocialDownloaderMod(loader.Module):
if not args:
await utils.answer(message, "❌ Укажи ссылку на Instagram")
return
-
await self.dlcmd(message)
async def ytcmd(self, message):
@@ -206,7 +185,6 @@ class SocialDownloaderMod(loader.Module):
await utils.answer(message, "❌ Укажи ссылку на YouTube")
return
- # Разбираем качество если указано
parts = args.split()
url = parts[0]
quality = parts[1] if len(parts) > 1 else 'best'
@@ -225,16 +203,18 @@ class SocialDownloaderMod(loader.Module):
url
]
- result = subprocess.run(cmd, capture_output=True, text=True)
+ process = await asyncio.create_subprocess_exec(
+ *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
+ )
+ stdout, stderr = await process.communicate()
- if result.returncode != 0:
+ if process.returncode != 0:
await utils.answer(message, "❌ Ошибка скачивания")
return
for file in os.listdir(temp_dir):
file_path = os.path.join(temp_dir, file)
if os.path.isfile(file_path):
- import shutil
final_path = os.path.join(tempfile.gettempdir(), file)
shutil.copy2(file_path, final_path)
@@ -267,5 +247,4 @@ class SocialDownloaderMod(loader.Module):
if not args:
await utils.answer(message, "❌ Укажи ссылку на VK видео")
return
-
await self.dlcmd(message)
\ No newline at end of file