I add command /id and /dowmp4 for dowload video with Youtube and i improve code.

It's version 0.2.1
This commit is contained in:
Niken
2025-10-04 23:18:56 +03:00
parent 5197518029
commit c5f6da31ba
6 changed files with 228 additions and 3 deletions
+159
View File
@@ -0,0 +1,159 @@
import asyncio
import tempfile
import os
import logging
import glob
import json
import dropbox
import sys
import io
import unicodedata
import uuid
from urllib.parse import unquote
from config import Config
# Настройка кодировки для всего приложения
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
logger = logging.getLogger(__name__)
DROPBOX_TOKEN = Config.Token
LIMIT = 2 * 1024 * 1024 * 1024 # 2 ГБ
async def safe_filename(name: str) -> str:
"""Создает безопасное имя файла"""
# Нормализуем Unicode символы
normalized = unicodedata.normalize('NFKD', name)
# Убираем акценты и специальные символы, оставляем только ASCII
ascii_name = normalized.encode('ascii', 'ignore').decode('ascii')
# Заменяем проблемные символы
safe_name = "".join(c if c.isalnum() or c in (' ', '-', '_', '.') else '_' for c in ascii_name)
# Убираем множественные подчеркивания и обрезаем длину
safe_name = '_'.join(filter(None, safe_name.split('_')))
return safe_name[:100] or f"video_{uuid.uuid4().hex[:8]}"
async def get_video_info(url: str) -> dict:
"""Получает информацию о видео через yt-dlp"""
try:
process = await asyncio.create_subprocess_exec(
'yt-dlp',
'--dump-json',
'--no-playlist',
url,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode == 0:
result = json.loads(stdout.decode('utf-8', errors='ignore'))
logger.info(f"Информация о видео получена: {result.get('title', 'Unknown')}")
return result
else:
error_msg = stderr.decode('utf-8', errors='ignore')
logger.warning(f"yt-dlp ошибка: {error_msg}")
except Exception as e:
logger.error(f"Не удалось получить информацию о видео: {e}")
return None
async def download_mp4_to_dropbox(url: str) -> tuple[str, dict]:
"""Скачивает MP4 в среднем качестве БЫСТРО, загружает в Dropbox"""
with tempfile.TemporaryDirectory() as temp_dir:
output_template = os.path.join(temp_dir, "video.%(ext)s")
try:
logger.info(f"Запускаю yt-dlp для: {url}")
video_info = await get_video_info(url)
title = "Unknown_Title"
uploader = "Unknown_Uploader"
duration = 0
if video_info:
title = await safe_filename(video_info.get('title', 'Unknown_Title'))
uploader = await safe_filename(video_info.get('uploader', 'Unknown_Uploader'))
duration = video_info.get('duration', 0)
logger.info(f"Обработано видео: {title}")
# ОПТИМИЗИРОВАННЫЕ НАСТРОЙКИ ДЛЯ СКОРОСТИ
download_process = await asyncio.create_subprocess_exec(
'yt-dlp',
'-f', 'bestvideo[height<=720][filesize<800M]+bestaudio/best[height<=720][filesize<800M]',
'--no-playlist',
'-o', output_template,
'--ignore-errors',
'--no-warnings',
'--format-sort', 'quality,res:720,size:800M',
'--concurrent-fragments', '4',
url,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await asyncio.wait_for(download_process.communicate(), timeout=600) # Уменьшил таймаут
# Остальной код без изменений...
if download_process.returncode != 0:
error_msg = stderr.decode('utf-8', errors='ignore') if stderr else "Unknown error"
logger.error(f"Ошибка скачивания: {error_msg}")
raise Exception(f"Ошибка скачивания: {error_msg}")
mp4_files = glob.glob(os.path.join(temp_dir, "*.mp4"))
if not mp4_files:
video_files = glob.glob(os.path.join(temp_dir, "*.*"))
video_files = [f for f in video_files if f.lower().endswith(('.mp4', '.mkv', '.avi', '.mov', '.webm'))]
if video_files:
mp4_files = [video_files[0]]
if mp4_files:
actual_file = mp4_files[0]
size = os.path.getsize(actual_file)
if size > LIMIT:
raise Exception("Файл превышает лимит 2 ГБ")
safe_title = await safe_filename(title)
final_filename = f"{safe_title}.mp4"
dbx = dropbox.Dropbox(DROPBOX_TOKEN)
dropbox_path = f"/{final_filename}"
logger.info(f"Загружаем файл в Dropbox: {dropbox_path} (размер: {size / (1024 * 1024):.1f} MB)")
with open(actual_file, "rb") as f:
file_data = f.read()
dbx.files_upload(
file_data,
dropbox_path,
mode=dropbox.files.WriteMode("overwrite")
)
shared_link = dbx.sharing_create_shared_link_with_settings(dropbox_path)
link = shared_link.url.replace("?dl=0", "?dl=1")
metadata = {
'title': title,
'uploader': uploader,
'duration': duration,
'filesize': size,
'quality': 'optimized for speed'
}
logger.info(f"Успешно загружено в Dropbox: {link}")
return link, metadata
raise Exception("Видео файл не найден после скачивания")
except asyncio.TimeoutError:
raise Exception("Таймаут загрузки (10 минут)")
except Exception as e:
logger.error(f"Общая ошибка: {e}")
raise e