Files
myfirstprogram/addons/dowloadmp4_to_youtube/dowmp4.py
T

160 lines
6.3 KiB
Python

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