# test_ffmpeg.py (ПОВНА ВЕРСІЯ З НАЛАШТУВАННЯМИ ЯКОСТІ ТА FPS)
import os, re, shutil, subprocess, hashlib, random, time
from pathlib import Path
from datetime import datetime
from moviepy.editor import VideoFileClip
from TTS.api import TTS
from pydub import AudioSegment
from PIL import Image, ImageDraw, ImageFont
from faster_whisper import WhisperModel
import torch
import asyncio
import mouse
import json

# Імпорти модулів
from telegram_bot import send_video_preview
from preview_generator import PreviewGenerator
from horizontal_video import HorizontalVideoGenerator
from vertical_video import VerticalVideoGenerator
from tiktok_processor import TikTokVideoGenerator, process_tiktok_videos, create_tts_with_censoring, get_tiktok_duration_settings
from full_vertical_video import FullVerticalVideoGenerator


def select_video_quality():
    """Дозволяє користувачу вибрати якість відео (бітрейт)"""
    print("\n" + "="*60)
    print("???? ВИБІР ЯКОСТІ ВІДЕО (БІТРЕЙТ)")
    print("="*60)
    print("Виберіть якість фінального відео:")
    print()
    print("1. ???? Економна (8 Mbps)")
    print("   • Розмір: ~60 MB на хвилину")
    print("   • Для: швидке завантаження, мобільні мережі")
    print()
    print("2. ???? Стандартна (12 Mbps) - Рекомендовано")
    print("   • Розмір: ~90 MB на хвилину")
    print("   • Для: баланс якості та розміру")
    print()
    print("3. ???? Висока (20 Mbps)")
    print("   • Розмір: ~150 MB на хвилину")
    print("   • Для: YouTube 1080p")
    print()
    print("4. ???? Преміум (35 Mbps)")
    print("   • Розмір: ~260 MB на хвилину")
    print("   • Для: висока деталізація")
    print()
    print("5. ???? Максимальна (50 Mbps)")
    print("   • Розмір: ~375 MB на хвилину")
    print("   • Для: найвища якість, архівування")
    print("="*60)
    
    quality_presets = {
        "1": {
            "name": "Економна",
            "video_bitrate": "8M",
            "audio_bitrate": "128k",
            "preset": "p4",
            "emoji": "????"
        },
        "2": {
            "name": "Стандартна",
            "video_bitrate": "12M",
            "audio_bitrate": "192k",
            "preset": "p4",
            "emoji": "????"
        },
        "3": {
            "name": "Висока",
            "video_bitrate": "20M",
            "audio_bitrate": "256k",
            "preset": "p4",
            "emoji": "????"
        },
        "4": {
            "name": "Преміум",
            "video_bitrate": "35M",
            "audio_bitrate": "320k",
            "preset": "p3",
            "emoji": "????"
        },
        "5": {
            "name": "Максимальна",
            "video_bitrate": "50M",
            "audio_bitrate": "320k",
            "preset": "p2",
            "emoji": "????"
        }
    }
    
    while True:
        choice = input("Ваш вибір (1-5): ").strip()
        if choice in quality_presets:
            selected = quality_presets[choice]
            print(f"\n✅ Вибрано якість: {selected['emoji']} {selected['name']}")
            print(f"   • Відео бітрейт: {selected['video_bitrate']}")
            print(f"   • Аудіо бітрейт: {selected['audio_bitrate']}")
            return selected
        print("❌ Невірний вибір. Введіть число від 1 до 5")


def select_video_fps():
    """Дозволяє користувачу вибрати FPS відео"""
    print("\n" + "="*60)
    print("????️ ВИБІР ЧАСТОТИ КАДРІВ (FPS)")
    print("="*60)
    print("Виберіть частоту кадрів для фінального відео:")
    print()
    print("1. ???? 30 FPS - Стандарт")
    print("   • Розмір: найменший")
    print("   • Для: YouTube, TikTok (стандарт)")
    print("   • Підходить для: більшості контенту")
    print()
    print("2. ⚡ 60 FPS - Плавність")
    print("   • Розмір: +30-40% більше")
    print("   • Для: динамічний контент, ігри")
    print("   • Підходить для: плавних рухів")
    print()
    print("3. ???? 120 FPS - Максимум")
    print("   • Розмір: +80-100% більше")
    print("   • Для: преміум контент, slow-motion")
    print("   • Підходить для: ефектів уповільнення")
    print()
    print("⚠️ УВАГА: Більшість дисплеїв підтримують тільки 60 FPS")
    print("="*60)
    
    fps_presets = {
        "1": {
            "name": "30 FPS",
            "fps": 30,
            "emoji": "????"
        },
        "2": {
            "name": "60 FPS",
            "fps": 60,
            "emoji": "⚡"
        },
        "3": {
            "name": "120 FPS",
            "fps": 120,
            "emoji": "????"
        }
    }
    
    while True:
        choice = input("Ваш вибір (1-3): ").strip()
        if choice in fps_presets:
            selected = fps_presets[choice]
            print(f"\n✅ Вибрано: {selected['emoji']} {selected['name']}")
            return selected
        print("❌ Невірний вибір. Введіть число від 1 до 3")


def apply_video_uniquification(input_video_path, output_video_path, temp_folder, 
                               intensity='medium', quality_settings=None, fps_settings=None):
    """
    Застосовує унікалізацію відео з урахуванням налаштувань якості та FPS
    """
    # Використовуємо стандартні налаштування якщо не передано
    if quality_settings is None:
        quality_settings = {
            "video_bitrate": "12M",
            "audio_bitrate": "192k",
            "preset": "p4"
        }
    
    if fps_settings is None:
        fps_settings = {"fps": 30}
    
    print(f"\n???? Застосування унікалізації відео (режим: {intensity})...")
    print(f"???? Якість: {quality_settings['video_bitrate']} / FPS: {fps_settings['fps']}")
    print("="*60)
    
    seed = random.randint(1000, 9999)
    random.seed(seed)
    print(f"???? Seed унікалізації: {seed}")
    
    # === ПІДГОТОВКА ФІЛЬТРІВ ===
    print(f"\n[10%] ???? Підготовка відео фільтрів...")
    filters = []
    
    # Глобальні корекції кольору
    brightness = random.uniform(-0.02, 0.02)
    contrast = random.uniform(0.98, 1.02)
    saturation = random.uniform(0.98, 1.02)
    filters.append(f"eq=brightness={brightness}:contrast={contrast}:saturation={saturation}")
    print(f" ✓ Корекція кольору: яскравість={brightness:.3f}, контраст={contrast:.3f}")
    
    gamma = random.uniform(0.98, 1.02)
    filters.append(f"eq=gamma={gamma}")
    print(f" ✓ Гама корекція: {gamma:.3f}")
    
    red_adjust = random.uniform(0.98, 1.02)
    blue_adjust = random.uniform(0.98, 1.02)
    green_adjust = random.uniform(0.98, 1.02)
    filters.append(f"colorchannelmixer=rr={red_adjust}:gg={green_adjust}:bb={blue_adjust}")
    print(f" ✓ Баланс білого: R={red_adjust:.3f}, G={green_adjust:.3f}, B={blue_adjust:.3f}")
    
    if intensity in ['medium', 'heavy']:
        master_curve = random.choice([
            "0/0 0.5/0.48 1/1",
            "0/0 0.5/0.52 1/1",
            "0/0.02 1/0.98",
        ])
        filters.append(f"curves=master='{master_curve}'")
        print(f" ✓ Крива контрасту застосована")
    
    if random.random() > 0.5:
        hue_shift = random.uniform(-5, 5)
        filters.append(f"hue=h={hue_shift}")
        print(f" ✓ Зсув відтінку: {hue_shift:.2f}°")
    
    # Додаємо FPS фільтр
    filters.append(f"fps=fps={fps_settings['fps']}")
    print(f" ✓ FPS: {fps_settings['fps']}")
    
    filter_chain = ",".join(filters)
    print(f"\n???? Всього застосовано {len(filters)} відео фільтрів")
    
    # === АУДІО ФІЛЬТРИ ===
    print(f"\n[20%] ???? Підготовка аудіо фільтрів...")
    audio_filters = []
    
    volume_change = random.uniform(0.98, 1.02)
    audio_filters.append(f"volume={volume_change}")
    print(f" ✓ Гучність: {volume_change:.3f}")
    
    if random.random() > 0.3:
        highpass_freq = random.randint(18, 22)
        audio_filters.append(f"highpass=f={highpass_freq}")
        print(f" ✓ Highpass фільтр: {highpass_freq}Hz")
    
    if random.random() > 0.3:
        lowpass_freq = random.randint(19500, 20500)
        audio_filters.append(f"lowpass=f={lowpass_freq}")
        print(f" ✓ Lowpass фільтр: {lowpass_freq}Hz")
    
    if intensity in ['medium', 'heavy'] and random.random() > 0.5:
        bass_gain = random.uniform(-1, 1)
        treble_gain = random.uniform(-1, 1)
        audio_filters.append(f"bass=g={bass_gain}")
        audio_filters.append(f"treble=g={treble_gain}")
        print(f" ✓ EQ: bass={bass_gain:.2f}dB, treble={treble_gain:.2f}dB")
    
    audio_filters.append("aresample=48000")
    print(f" ✓ Sample rate: 48000Hz")
    
    audio_filter_chain = ",".join(audio_filters)
    print(f"\n???? Всього застосовано {len(audio_filters)} аудіо фільтрів")
    
    # === МЕТАДАНІ ===
    print(f"\n[30%] ???? Підготовка метаданих...")
    metadata_options = [
        "-metadata", f"comment=Processed_{seed}",
        "-metadata", f"creation_time={datetime.now().isoformat()}",
        "-metadata", f"encoder=FFmpeg_{random.randint(1000, 9999)}",
        "-metadata", f"title=Video_{random.randint(10000, 99999)}"
    ]
    print(f" ✓ Метадані згенеровано")
    
    # === НАЛАШТУВАННЯ КОДУВАННЯ ===
    print(f"\n[40%] ⚙️ Налаштування параметрів кодування...")
    gop_size = random.randint(28, 32)
    bf_frames = random.randint(2, 4)
    profile = random.choice(['high', 'main']) if intensity in ['medium', 'heavy'] else 'high'
    level = random.choice(['4.0', '4.1', '4.2'])
    
    print(f" ✓ Preset: {quality_settings['preset']}")
    print(f" ✓ Profile: {profile}, Level: {level}")
    print(f" ✓ Video bitrate: {quality_settings['video_bitrate']}")
    print(f" ✓ Audio bitrate: {quality_settings['audio_bitrate']}")
    print(f" ✓ FPS: {fps_settings['fps']}")
    print(f" ✓ GOP size: {gop_size}")
    
    # === ЗАПУСК FFMPEG ===
    print(f"\n[50%] ???? Запуск FFmpeg обробки...")
    print("="*60)
    
    try:
        cmd = [
            "ffmpeg", "-y",
            "-i", str(input_video_path),
            "-filter_complex", f"[0:v]{filter_chain}[v];[0:a]{audio_filter_chain}[a]",
            "-map", "[v]",
            "-map", "[a]",
            "-c:v", "h264_nvenc",
            "-preset", quality_settings['preset'],
            "-profile:v", profile,
            "-level:v", level,
            "-b:v", quality_settings['video_bitrate'],
            "-g", str(gop_size),
            "-bf", str(bf_frames),
            "-c:a", "aac",
            "-b:a", quality_settings['audio_bitrate'],
            "-ar", "48000",
            "-movflags", "+faststart",
            *metadata_options,
            "-map_metadata", "0",
            "-fflags", "+genpts",
            str(output_video_path)
        ]
        
        result = subprocess.run(cmd, check=True, capture_output=True, text=True)
        
        print(f"\n[95%] ✅ Верифікація результату...")
        if not Path(output_video_path).exists():
            raise FileNotFoundError(f"Вихідний файл не створено: {output_video_path}")
        
        output_size = Path(output_video_path).stat().st_size / (1024 * 1024)
        print(f" ✓ Файл створено: {output_size:.2f} MB")
        print(f"\n[100%] ✅ Унікалізація завершена успішно!")
        print(f"???? Якість: {quality_settings['video_bitrate']} @ {fps_settings['fps']} FPS")
        print("="*60)
        return True
        
    except subprocess.CalledProcessError as e:
        print(f"\n❌ Помилка FFmpeg на етапі обробки!")
        print(f"???? Код помилки: {e.returncode}")
        if hasattr(e, 'stderr') and e.stderr:
            print(f"???? Деталі помилки:")
            print(e.stderr[:1000])
        print(f"???? Копіювання оригіналу замість унікалізованого...")
        shutil.copy2(input_video_path, output_video_path)
        return False
    except Exception as e:
        print(f"\n❌ Неочікувана помилка: {e}")
        import traceback
        traceback.print_exc()
        print(f"???? Копіювання оригіналу замість унікалізованого...")
        shutil.copy2(input_video_path, output_video_path)
        return False


def get_uniquification_settings():
    """Запитує у користувача налаштування унікалізації"""
    print("\n" + "="*60)
    print("???? НАЛАШТУВАННЯ УНІКАЛІЗАЦІЇ ВІДЕО")
    print("="*60)
    print("Унікалізація робить кожне відео унікальним для алгоритмів")
    print("платформ, при цьому зміни непомітні для людського ока.")
    print("\nРівні інтенсивності:")
    print("1. ???? Вимкнено - без унікалізації")
    print("2. ???? Легка - мінімальні зміни (рекомендовано)")
    print("3. ⚡ Середня - помірні зміни (найкраще співвідношення)")
    print("4. ???? Сильна - максимальні зміні (для важких випадків)")
    print("="*60)
    
    while True:
        choice = input("Ваш вибір (1-4): ").strip()
        if choice == "1":
            return None
        elif choice == "2":
            return 'light'
        elif choice == "3":
            return 'medium'
        elif choice == "4":
            return 'heavy'
        else:
            print("❌ Невірний вибір. Введіть 1, 2, 3 або 4")


def select_voice():
    """Дозволяє користувачу вибрати голос для озвучки"""
    print("\n" + "="*60)
    print("????️ ВИБІР ГОЛОСУ ДЛЯ ОЗВУЧКИ")
    print("="*60)
    print("Доступні голоси:")
    print("1. ????️ p312 (чоловічий голос)")
    print("2. ???? p284 (жіночий голос)")
    print("="*60)
    
    while True:
        choice = input("Ваш вибір (1-2): ").strip()
        if choice == "1":
            selected_voice = "p312"
            print(f"✅ Вибрано голос: p312 (чоловічий)")
            break
        elif choice == "2":
            selected_voice = "p284"
            print(f"✅ Вибрано голос: p284 (жіночий)")
            break
        else:
            print("❌ Невірний вибір. Введіть 1 або 2")
    
    return selected_voice


def safe_filename(name):
    """Створює безпечну назву файлу"""
    name = re.sub(r'[<>:"/\\|?*\x00-\x1F]', "_", name)
    name = re.sub(r'\s+','_', name).strip("_")
    name = name.rstrip(". ")
    return name[:50]


def get_available_fonts(fonts_dir):
    """Сканує папку fonts і повертає словник з доступними шрифтами (TTF та OTF)"""
    fonts = {}
    
    # Словник для маппінгу файлів шрифтів до їх системних назв
    font_mapping = {
        # TTF файли
        "NotoSans-ExtraBold.ttf": ("Noto Sans ExtraBold", "Noto Sans ExtraBold (жирний, читабельний)"),
        "KOMIKAX_.ttf": ("Komika Axis", "Komika Axis (комічний стиль)"),
        "Arial.ttf": ("Arial", "Arial (стандартний)"),
        "arial.ttf": ("Arial", "Arial (стандартний)"),
        "calibri.ttf": ("Calibri", "Calibri (сучасний)"),
        "Calibri.ttf": ("Calibri", "Calibri (сучасний)"),
        "times.ttf": ("Times New Roman", "Times New Roman (класичний)"),
        "TimesNewRoman.ttf": ("Times New Roman", "Times New Roman (класичний)"),
        "OpenSans-Bold.ttf": ("Open Sans Bold", "Open Sans Bold (веб-шрифт)"),
        "Roboto-Bold.ttf": ("Roboto Bold", "Roboto Bold (Google шрифт)"),
        "Montserrat-Bold.ttf": ("Montserrat Bold", "Montserrat Bold (сучасний)"),
        "Poppins-Bold.ttf": ("Poppins Bold", "Poppins Bold (трендовий)"),
        "Inter-Bold.ttf": ("Inter Bold", "Inter Bold (UI шрифт)"),
        # OTF файли
        "NotoSans-ExtraBold.otf": ("Noto Sans ExtraBold", "Noto Sans ExtraBold (жирний, OTF)"),
        "KOMIKAX_.otf": ("Komika Axis", "Komika Axis (комічний стиль, OTF)"),
        "Arial.otf": ("Arial", "Arial (стандартний, OTF)"),
        "arial.otf": ("Arial", "Arial (стандартний, OTF)"),
        "calibri.otf": ("Calibri", "Calibri (сучасний, OTF)"),
        "Calibri.otf": ("Calibri", "Calibri (сучасний, OTF)"),
        "OpenSans-Bold.otf": ("Open Sans Bold", "Open Sans Bold (веб-шрифт, OTF)"),
        "Roboto-Bold.otf": ("Roboto Bold", "Roboto Bold (Google шрифт, OTF)"),
        "Montserrat-Bold.otf": ("Montserrat Bold", "Montserrat Bold (сучасний, OTF)"),
        "Poppins-Bold.otf": ("Poppins Bold", "Poppins Bold (трендовий, OTF)"),
        "Inter-Bold.otf": ("Inter Bold", "Inter Bold (UI шрифт, OTF)"),
        "Proxima-Nova-Bold.otf": ("Proxima Nova Bold", "Proxima Nova Bold (преміум, OTF)"),
        "Futura-Bold.otf": ("Futura Bold", "Futura Bold (геометричний, OTF)"),
        "Helvetica-Bold.otf": ("Helvetica Bold", "Helvetica Bold (класичний, OTF)"),
        "Gotham-Bold.otf": ("Gotham Bold", "Gotham Bold (сучасний, OTF)"),
        "Avenir-Heavy.otf": ("Avenir Heavy", "Avenir Heavy (елегантний, OTF)"),
    }
    
    if not fonts_dir.exists():
        print(f"⚠️ Папка шрифтів не існує: {fonts_dir}")
        return fonts
    
    # Скануємо як TTF, так і OTF файли
    font_extensions = ["*.ttf", "*.otf", "*.TTF", "*.OTF"]
    for pattern in font_extensions:
        for font_file in fonts_dir.glob(pattern):
            filename = font_file.name
            if filename in font_mapping:
                ass_name, description = font_mapping[filename]
                fonts[filename] = {
                    'path': font_file,
                    'ass_name': ass_name,
                    'description': description,
                    'type': font_file.suffix.upper()[1:]
                }
            else:
                # Для невідомих шрифтів використовуємо ім'я файлу без розширення
                font_name = font_file.stem.replace("_", " ").replace("-", " ")
                font_type = font_file.suffix.upper()[1:]
                fonts[filename] = {
                    'path': font_file,
                    'ass_name': font_name,
                    'description': f"{font_name} (автовизначення, {font_type})",
                    'type': font_type
                }
    
    return fonts


def select_fonts(fonts_dir):
    """Дозволяє користувачу вибрати шрифти для preview та субтитрів"""
    print("\n" + "="*60)
    print("???? ВИБІР ШРИФТІВ")
    print("="*60)
    
    available_fonts = get_available_fonts(fonts_dir)
    
    if not available_fonts:
        print("❌ Шрифти не знайдено в папці fonts!")
        print("Перевірте, що у папці є файли .ttf або .otf")
        return {
            'preview': {
                'path': fonts_dir / "NotoSans-ExtraBold.ttf",
                'name': "Noto Sans ExtraBold"
            },
            'subtitles': {
                'path': fonts_dir / "KOMIKAX_.ttf",
                'name': "Komika Axis"
            }
        }
    
    print("Доступні шрифти:")
    font_list = list(available_fonts.items())
    for i, (filename, info) in enumerate(font_list, 1):
        type_icon = "????" if info['type'] == "TTF" else "????" if info['type'] == "OTF" else "????"
        print(f"{i}. {type_icon} {info['description']}")
    print("="*60)
    
    # Вибір шрифту для preview
    print("????️ Виберіть шрифт для PREVIEW (заголовків на превью):")
    while True:
        try:
            choice = input(f"Ваш вибір (1-{len(font_list)}): ").strip()
            choice_idx = int(choice) - 1
            if 0 <= choice_idx < len(font_list):
                preview_font = font_list[choice_idx]
                break
            print(f"❌ Введіть число від 1 до {len(font_list)}")
        except ValueError:
            print("❌ Введіть дійсне число!")
    
    print(f"✅ Шрифт для preview: {preview_font[1]['description']}")
    
    # Вибір шрифту для субтитрів
    print("\n???? Виберіть шрифт для СУБТИТРІВ:")
    print("(Можете вибрати той же шрифт або інший)")
    while True:
        try:
            choice = input(f"Ваш вибір (1-{len(font_list)}): ").strip()
            choice_idx = int(choice) - 1
            if 0 <= choice_idx < len(font_list):
                subtitles_font = font_list[choice_idx]
                break
            print(f"❌ Введіть число від 1 до {len(font_list)}")
        except ValueError:
            print("❌ Введіть дійсне число!")
    
    print(f"✅ Шрифт для субтитрів: {subtitles_font[1]['description']}")
    
    return {
        'preview': {
            'path': preview_font[1]['path'],
            'name': preview_font[1]['ass_name']
        },
        'subtitles': {
            'path': subtitles_font[1]['path'],
            'name': subtitles_font[1]['ass_name']
        }
    }


def get_speed_settings():
    """Дозволяє користувачу налаштувати прискорення відео"""
    print("\n" + "="*60)
    print("⚡ НАЛАШТУВАННЯ ПРИСКОРЕННЯ ВІДЕО")
    print("="*60)
    print("Виберіть режим прискорення:")
    print("1. ⚡ Без прискорення (оригінальна швидкість)")
    print("2. ???? Фіксоване прискорення для всіх відео")
    print("3. ???? Прискорення до цільової тривалості")
    print("4. ⚙️ Інтерактивне налаштування для кожного відео")
    print("="*60)
    
    while True:
        choice = input("Ваш вибір (1-4): ").strip()
        if choice in ["1", "2", "3", "4"]:
            break
        print("❌ Невірний вибір. Введіть 1, 2, 3 або 4")
    
    speed_config = {
        'mode': choice,
        'youtube_horizontal': {'enabled': False, 'speed': 1.0, 'target_duration': None},
        'youtube_vertical': {'enabled': False, 'speed': 1.0, 'target_duration': None},
        'youtube_full_vertical': {'enabled': False, 'speed': 1.0, 'target_duration': None},
        'tiktok': {'enabled': False, 'speed': 1.0, 'target_duration': None}
    }
    
    if choice == "1":
        print("✅ Вибрано режим без прискорення")
        return speed_config
    elif choice == "2":
        print("\n???? Налаштування фіксованого прискорення:")
        while True:
            try:
                speed = float(input("Введіть коефіцієнт прискорення (1.0-4.0, наприклад 1.5): "))
                if 1.0 <= speed <= 4.0:
                    break
                print("❌ Коефіцієнт має бути від 1.0 до 4.0")
            except ValueError:
                print("❌ Введіть дійсне число!")
        
        speed_config['youtube_horizontal'] = {'enabled': True, 'speed': speed, 'target_duration': None}
        speed_config['youtube_vertical'] = {'enabled': True, 'speed': speed, 'target_duration': None}
        speed_config['youtube_full_vertical'] = {'enabled': True, 'speed': speed, 'target_duration': None}
        speed_config['tiktok'] = {'enabled': True, 'speed': speed, 'target_duration': None}
        print(f"✅ Всі відео будуть прискорені в {speed}x")
    
    elif choice == "3":
        print("\n???? Налаштування прискорення до цільової тривалості:")
        
        # YouTube горизонтальне
        print("\n???? YouTube горизонтальне відео:")
        enable = input("Прискорювати YouTube горизонтальні відео? (y/n): ").lower() == 'y'
        if enable:
            while True:
                try:
                    target = float(input("Цільова тривалість (секунди): "))
                    if target > 10:
                        break
                    print("❌ Тривалість має бути більше 10 секунд")
                except ValueError:
                    print("❌ Введіть дійсне число!")
            speed_config['youtube_horizontal'] = {'enabled': True, 'speed': None, 'target_duration': target}
        
        # YouTube вертикальне (Shorts)
        print("\n???? YouTube Shorts відео:")
        enable = input("Прискорювати YouTube Shorts? (y/n): ").lower() == 'y'
        if enable:
            while True:
                try:
                    target = float(input("Цільова тривалість (секунди, макс 60): "))
                    if 10 <= target <= 60:
                        break
                    print("❌ Тривалість має бути від 10 до 60 секунд")
                except ValueError:
                    print("❌ Введіть дійсне число!")
            speed_config['youtube_vertical'] = {'enabled': True, 'speed': None, 'target_duration': target}
        
        # YouTube вертикальне 9:16
        print("\n???? YouTube вертикальне відео (9:16):")
        enable = input("Прискорювати YouTube вертикальні відео? (y/n): ").lower() == 'y'
        if enable:
            while True:
                try:
                    target = float(input("Цільова тривалість (секунди): "))
                    if target > 10:
                        break
                    print("❌ Тривалість має бути більше 10 секунд")
                except ValueError:
                    print("❌ Введіть дійсне число!")
            speed_config['youtube_full_vertical'] = {'enabled': True, 'speed': None, 'target_duration': target}
        
        # TikTok
        print("\n???? TikTok відео:")
        enable = input("Прискорювати TikTok відео? (y/n): ").lower() == 'y'
        if enable:
            while True:
                try:
                    target = float(input("Цільова тривалість кожної частини (секунди): "))
                    if target > 15:
                        break
                    print("❌ Тривалість має бути більше 15 секунд")
                except ValueError:
                    print("❌ Введіть дійсне число!")
            speed_config['tiktok'] = {'enabled': True, 'speed': None, 'target_duration': target}
    
    elif choice == "4":
        print("✅ Вибрано інтерактивний режим")
        print("Для кожного відео буде запропоновано налаштування прискорення")
        speed_config['mode'] = 'interactive'
    
    return speed_config


def get_interactive_speed_settings(video_type, original_duration):
    """Запитує у користувача налаштування прискорення для конкретного відео"""
    type_names = {
        'youtube_horizontal': 'YouTube горизонтальне',
        'youtube_vertical': 'YouTube Shorts',
        'youtube_full_vertical': 'YouTube вертикальне 9:16',
        'tiktok': 'TikTok частина'
    }
    
    print(f"\n⚙️ Налаштування для {type_names.get(video_type, video_type)}")
    print(f"⏱️ Поточна тривалість: {original_duration:.1f} секунд")
    
    choice = input("Прискорювати це відео? (y/n): ").lower()
    if choice != 'y':
        return {'enabled': False, 'speed': 1.0, 'target_duration': None}
    
    print("Виберіть спосіб:")
    print("1. Фіксоване прискорення (наприклад, 1.5x)")
    print("2. До цільової тривалості")
    
    while True:
        method = input("Ваш вибір (1-2): ").strip()
        if method in ["1", "2"]:
            break
        print("❌ Введіть 1 або 2")
    
    if method == "1":
        while True:
            try:
                speed = float(input("Коефіцієнт прискорення (1.0-4.0): "))
                if 1.0 <= speed <= 4.0:
                    break
                print("❌ Коефіцієнт має бути від 1.0 до 4.0")
            except ValueError:
                print("❌ Введіть дійсне число!")
        
        final_duration = original_duration / speed
        print(f"✅ Швидкість {speed}x, фінальна тривалість: {final_duration:.1f}с")
        return {'enabled': True, 'speed': speed, 'target_duration': None}
    else:
        max_duration = 300 if video_type == 'tiktok' else (60 if 'vertical' in video_type and video_type != 'youtube_full_vertical' else 600)
        while True:
            try:
                target = float(input(f"Цільова тривалість (10-{max_duration}с): "))
                if 10 <= target <= max_duration:
                    break
                print(f"❌ Тривалість має бути від 10 до {max_duration} секунд")
            except ValueError:
                print("❌ Введіть дійсне число!")
        
        required_speed = original_duration / target
        if required_speed > 4.0:
            print(f"⚠️ Потрібне прискорення {required_speed:.1f}x перевищує максимум 4.0x")
            required_speed = 4.0
            final_duration = original_duration / required_speed
            print(f"Буде використано максимальне прискорення 4.0x, тривалість: {final_duration:.1f}с")
        else:
            print(f"✅ Прискорення {required_speed:.1f}x до {target}с")
        
        return {'enabled': True, 'speed': required_speed, 'target_duration': target}


def apply_video_speedup(input_video_path, output_video_path, speed_factor, temp_folder):
    """Прискорює відео зі збереженням якості"""
    if speed_factor <= 1.0:
        shutil.copy2(input_video_path, output_video_path)
        return Path(output_video_path)
    
    print(f"⚡ Прискорення відео в {speed_factor:.2f}x...")
    temp_video = temp_folder / f"speedup_temp_{random.randint(1000, 9999)}.mp4"
    
    try:
        cmd = [
            "ffmpeg", "-y",
            "-i", str(input_video_path),
            "-filter_complex", f"[0:v]setpts={1/speed_factor}*PTS[v];[0:a]atempo={speed_factor}[a]",
            "-map", "[v]",
            "-map", "[a]",
            "-c:v", "h264_nvenc",
            "-preset", "p4",
            "-b:v", "20M",
            "-c:a", "aac",
            "-b:a", "128k",
            "-movflags", "+faststart",
            str(temp_video)
        ]
        
        result = subprocess.run(cmd, check=True, capture_output=True, text=True)
        shutil.move(str(temp_video), str(output_video_path))
        print(f"✅ Відео прискорено успішно")
        return Path(output_video_path)
        
    except subprocess.CalledProcessError as e:
        print(f"❌ Помилка при прискоренні відео: {e}")
        print(f"FFmpeg stderr: {e.stderr}")
        shutil.copy2(input_video_path, output_video_path)
        return Path(output_video_path)
    finally:
        if temp_video.exists():
            temp_video.unlink()


def select_background_folder(backgrounds_dir):
    """Дозволяє користувачу вибрати папку з фоновими відео"""
    print("\n" + "="*60)
    print("???? ВИБІР ФОНОВИХ ВІДЕО")
    print("="*60)
    
    bg_folders = [f for f in backgrounds_dir.iterdir() if f.is_dir()]
    
    if not bg_folders:
        print("❌ Папки з фоновими відео не знайдено!")
        print(f"Створіть папки в: {backgrounds_dir}")
        return None
    
    for i, folder in enumerate(bg_folders, 1):
        video_files = list(folder.glob("*.mp4")) + list(folder.glob("*.mov")) + list(folder.glob("*.avi"))
        print(f"{i}. ???? {folder.name} ({len(video_files)} відео)")
    print("="*60)
    
    while True:
        try:
            choice = input(f"Виберіть папку (1-{len(bg_folders)}): ").strip()
            choice_idx = int(choice) - 1
            if 0 <= choice_idx < len(bg_folders):
                selected_folder = bg_folders[choice_idx]
                video_files = list(selected_folder.glob("*.mp4")) + list(selected_folder.glob("*.mov")) + list(selected_folder.glob("*.avi"))
                if not video_files:
                    print(f"❌ У папці {selected_folder.name} немає відео файлів!")
                    continue
                print(f"✅ Вибрано папку: {selected_folder.name} ({len(video_files)} відео)")
                return selected_folder
            else:
                print(f"❌ Невірний вибір. Введіть число від 1 до {len(bg_folders)}")
        except ValueError:
            print(f"❌ Невірний вибір. Введіть число від 1 до {len(bg_folders)}")


def chunk_words(words, n=2):
    """Групує слова для субтитрів"""
    chunks = []
    i = 0
    while i < len(words):
        group = words[i:i+n]
        text = " ".join([w["word"] for w in group])
        start = group[0]["start"]
        end = group[-1]["end"]
        chunks.append({"text": text, "start": start, "end": end})
        i += n
    return chunks


def create_ass_subtitles(chunks, ass_path, font_name="Komika Axis", font_size=48, vertical=False):
    """Створює ASS файл субтитрів з вказаним шрифтом"""
    if vertical:
        font_size = 28
        margin_v = 250
        margin_lr = 100
    else:
        margin_v = 0
        margin_lr = 30
    
    ass_content = f"""[Script Info]
Title: Generated Subtitles
ScriptType: v4.00+

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,{font_name},{font_size},&H00FFFFFF,&H000000FF,&H00000000,&H80000000,1,0,0,0,100,100,0,0,1,3,0,5,{margin_lr},{margin_lr},{margin_v},1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
"""
    
    for chunk in chunks:
        start_time = format_ass_time(chunk["start"])
        end_time = format_ass_time(chunk["end"])
        text = chunk["text"].replace("\\", "\\\\").replace("{", "\\{").replace("}", "\\}")
        
        if vertical:
            words = text.split()
            lines = []
            current_line = ""
            max_chars = 20
            
            for word in words:
                if len(word) > max_chars:
                    if current_line:
                        lines.append(current_line.strip())
                        current_line = ""
                    while len(word) > max_chars:
                        lines.append(word[:max_chars-1] + "-")
                        word = word[max_chars-1:]
                    if word:
                        current_line = word
                elif len(current_line + " " + word) <= max_chars:
                    current_line += (" " + word if current_line else word)
                else:
                    if current_line:
                        lines.append(current_line.strip())
                    current_line = word
            
            if current_line:
                lines.append(current_line.strip())
            
            text = "\\N".join(lines)
        
        ass_content += f"Dialogue: 0,{start_time},{end_time},Default,,0,0,0,,{text}\n"
    
    with open(ass_path, 'w', encoding='utf-8-sig') as f:
        f.write(ass_content)


def format_ass_time(seconds):
    """Конвертує секунди в формат часу ASS (H:MM:SS.CC)"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = seconds % 60
    return f"{hours}:{minutes:02d}:{secs:05.2f}"


def apply_subtitles_ass(video_path, chunks, story_id, vertical=False, temp_folder=None, font_name="Komika Axis"):
    """Додає субтитри використовуючи ASS файл з вказаним шрифтом"""
    if not chunks:
        return video_path
    
    print(f"???? Створення ASS субтитрів для {len(chunks)} фрагментів...")
    print(f"???? Використовується шрифт: {font_name}")
    
    suffix = "_vertical" if vertical else ""
    ass_path = temp_folder / f"{story_id}_subtitles{suffix}.ass"
    
    create_ass_subtitles(chunks, ass_path, font_name=font_name, font_size=56, vertical=vertical)
    
    output_video = temp_folder / f"{story_id}_with_subtitles{suffix}.mp4"
    ass_path_escaped = str(ass_path).replace("\\", "/").replace(":", "\\:")
    
    cmd = [
        "ffmpeg", "-y",
        "-i", str(video_path),
        "-vf", f"ass='{ass_path_escaped}'",
        "-c:v", "h264_nvenc",
        "-preset", "p4",
        "-b:v", "20M",
        "-c:a", "copy",
        str(output_video)
    ]
    
    try:
        print(f"✍️ Додавання субтитрів...")
        subprocess.run(cmd, check=True, capture_output=True, text=True)
        print(f"✅ Субтитри успішно додано")
        return output_video
    except subprocess.CalledProcessError as e:
        print(f"❌ Помилка при додаванні субтитрів: {e}")
        return video_path


def select_video_type():
    """Дозволяє користувачу вибрати тип відео для генерації"""
    print("\n" + "="*60)
    print("???? ВИБІР ТИПУ ВІДЕО")
    print("="*60)
    print("1. ???? YouTube відео (горизонтальне + shorts)")
    print("2. ???? TikTok відео (розділені на частини)")
    print("3. ???? Обидва типи")
    print("4. ???? YouTube вертикальне відео (9:16)")
    print("5. ???? Горизонтальне + вертикальне + shorts")
    print("6. ???? Вертикальне + shorts")
    print("7. ???? Всі типи YouTube відео")
    print("="*60)
    
    while True:
        choice = input("Ваш вибір (1-7): ").strip()
        if choice in ["1", "2", "3", "4", "5", "6", "7"]:
            return choice
        print("❌ Невірний вибір. Введіть число від 1 до 7")


def select_template_for_video(template_mode, default_template, preview_generator):
    """Вибирає template для поточного відео залежно від режиму"""
    if template_mode == "fixed":
        return default_template
    elif template_mode == "interactive":
        template_name, _ = preview_generator.select_template()
        return template_name
    else:  # auto
        return default_template


def process_youtube_story(story_path, horizontal_generator, vertical_generator, full_vertical_generator, 
                          selected_template, coqui_tts, asr_model, temp_folder, final_dir, speed_config, 
                          video_type, sub_font_name="Komika Axis", uniquification_intensity=None,
                          quality_settings=None, fps_settings=None):
    """Обробляє YouTube історію з розширеними опціями та унікалізацією"""
    
    story_txt = story_path.read_text(encoding="utf-8").strip()
    preview_path = story_path.with_name(f"{story_path.stem}_preview.txt")
    description_path = story_path.with_name(f"{story_path.stem}_description.txt")
    
    if not preview_path.exists() or not description_path.exists():
        print(f"❌ Не знайдено preview або description для {story_path.name}")
        return
    
    preview_txt = preview_path.read_text(encoding="utf-8").strip()
    description_txt = description_path.read_text(encoding="utf-8").strip()
    
    if not story_txt or not preview_txt or not description_txt:
        print(f"❌ Порожні файли для {story_path.name}")
        return
    
    story_id = hashlib.md5(story_txt.encode()).hexdigest()
    video_title = safe_filename(preview_txt)
    output_dir = final_dir / video_title
    output_dir.mkdir(parents=True, exist_ok=True)
    
    print(f"???? Використовується template: {selected_template}")
    
    # === ГЕНЕРАЦІЯ АУДІО ===
    print(f"????️ Генерація аудіо...")
    audio_preview = coqui_tts(preview_txt)
    audio_story = coqui_tts(story_txt)
    final_audio = audio_preview + AudioSegment.silent(duration=500) + audio_story
    original_duration = final_audio.duration_seconds
    
    audio_path = temp_folder / f"{story_id}_voice.wav"
    final_audio.export(audio_path, format="wav")
    
    horizontal_preview_path = None
    
    # === ГОРИЗОНТАЛЬНЕ ВІДЕО ===
    if video_type in ["1", "3", "5", "7"] and horizontal_generator:
        print(f"???? Створення горизонтального відео...")
        
        horizontal_speed_settings = speed_config['youtube_horizontal']
        if speed_config['mode'] == 'interactive':
            horizontal_speed_settings = get_interactive_speed_settings('youtube_horizontal', original_duration)
        
        combined_video, horizontal_preview_path = horizontal_generator.create_horizontal_video(
            story_id, preview_txt, audio_preview, audio_story, selected_template
        )
        
        # Субтитри
        print(f"???? Розпізнавання мовлення...")
        story_offset = audio_preview.duration_seconds + 0.5
        segments, _ = asr_model.transcribe(str(audio_path), word_timestamps=True)
        words = [{"word": w.word.strip(), "start": w.start, "end": w.end} 
                for seg in segments for w in seg.words if w.start >= story_offset]
        chunks = chunk_words(words)
        
        if chunks:
            final_video = apply_subtitles_ass(combined_video, chunks, story_id, 
                                             temp_folder=temp_folder, font_name=sub_font_name)
        else:
            print("⚠️ Субтитри не знайдено")
            final_video = combined_video
        
        # Прискорення
        horizontal_output_path = output_dir / f"{video_title}.mp4"
        temp_before_unique = temp_folder / f"temp_horizontal_before_unique_{story_id}.mp4"
        
        if horizontal_speed_settings['enabled'] and horizontal_speed_settings.get('speed', 1.0) > 1.0:
            print(f"⚡ Прискорення горизонтального відео...")
            speed_factor = horizontal_speed_settings.get('speed')
            if horizontal_speed_settings.get('target_duration'):
                speed_factor = original_duration / horizontal_speed_settings['target_duration']
                speed_factor = min(speed_factor, 4.0)
            
            horizontal_generator.finalize_video(final_video, audio_path, temp_before_unique)
            apply_video_speedup(temp_before_unique, temp_before_unique, speed_factor, temp_folder)
        else:
            horizontal_generator.finalize_video(final_video, audio_path, temp_before_unique)
        
        # Унікалізація
        if uniquification_intensity:
            apply_video_uniquification(temp_before_unique, horizontal_output_path, temp_folder, 
                                      uniquification_intensity, quality_settings, fps_settings)
        else:
            shutil.copy2(temp_before_unique, horizontal_output_path)
        
        if temp_before_unique.exists():
            temp_before_unique.unlink()
        
        print(f"✅ Горизонтальне відео створено: {horizontal_output_path}")
    
    # === ВЕРТИКАЛЬНЕ ВІДЕО (SHORTS) ===
    if video_type in ["1", "3", "5", "6", "7"] and vertical_generator:
        try:
            print(f"???? Створення Shorts відео...")
            
            vertical_speed_settings = speed_config['youtube_vertical']
            
            combined_shorts_video, shorts_audio_path = vertical_generator.create_shorts_video(
                story_txt, preview_txt, story_id, horizontal_preview_path, coqui_tts
            )
            
            if speed_config['mode'] == 'interactive':
                shorts_duration = AudioSegment.from_wav(shorts_audio_path).duration_seconds
                vertical_speed_settings = get_interactive_speed_settings('youtube_vertical', shorts_duration)
            
            # Субтитри для Shorts
            print(f"???? Розпізнавання мовлення для Shorts...")
            segments_shorts, _ = asr_model.transcribe(str(shorts_audio_path), word_timestamps=True)
            audio_preview_shorts = coqui_tts(preview_txt)
            story_start_time = audio_preview_shorts.duration_seconds + 0.5
            
            story_words = []
            for seg in segments_shorts:
                for w in seg.words:
                    if w.start >= story_start_time:
                        story_words.append({"word": w.word.strip(), "start": w.start, "end": w.end})
            
            chunks_shorts = chunk_words(story_words)
            
            if chunks_shorts:
                final_shorts_video = apply_subtitles_ass(combined_shorts_video, chunks_shorts, 
                                                        f"{story_id}_shorts", vertical=True, 
                                                        temp_folder=temp_folder, font_name=sub_font_name)
            else:
                print("⚠️ Субтитри не знайдено для Shorts")
                final_shorts_video = combined_shorts_video
            
            # Прискорення Shorts
            shorts_path = output_dir / f"short_{video_title}.mp4"
            temp_shorts_before_unique = temp_folder / f"temp_shorts_before_unique_{story_id}.mp4"
            
            if vertical_speed_settings['enabled'] and vertical_speed_settings.get('speed', 1.0) > 1.0:
                print(f"⚡ Прискорення вертикального відео...")
                speed_factor = vertical_speed_settings.get('speed')
                if vertical_speed_settings.get('target_duration'):
                    speed_factor = AudioSegment.from_wav(shorts_audio_path).duration_seconds / vertical_speed_settings['target_duration']
                    speed_factor = min(speed_factor, 4.0)
                
                vertical_generator.finalize_shorts_video(final_shorts_video, shorts_audio_path, temp_shorts_before_unique)
                apply_video_speedup(temp_shorts_before_unique, temp_shorts_before_unique, speed_factor, temp_folder)
            else:
                vertical_generator.finalize_shorts_video(final_shorts_video, shorts_audio_path, temp_shorts_before_unique)
            
            # Унікалізація
            if uniquification_intensity:
                apply_video_uniquification(temp_shorts_before_unique, shorts_path, temp_folder, 
                                          uniquification_intensity, quality_settings, fps_settings)
            else:
                shutil.copy2(temp_shorts_before_unique, shorts_path)
            
            if temp_shorts_before_unique.exists():
                temp_shorts_before_unique.unlink()
            
            print(f"???? Shorts відео створено: {shorts_path}")
            
        except Exception as e:
            print(f"❌ Помилка при створенні Shorts відео: {e}")
    
    # === ВІДЕО З ВЕРТИКАЛЬНИМ ФОРМАТОМ (9:16) ===
    if video_type in ["4", "5", "6", "7"] and full_vertical_generator:
        try:
            print(f"???? Створення вертикального відео...")
            
            full_vertical_speed_settings = speed_config['youtube_full_vertical']
            if speed_config['mode'] == 'interactive':
                full_vertical_speed_settings = get_interactive_speed_settings('youtube_full_vertical', original_duration)
            
            # Створюємо горизонтальне preview якщо ще не створено
            if horizontal_preview_path is None:
                temp_preview_path = temp_folder / f"{story_id}_temp_preview.png"
                preview_gen = PreviewGenerator(
                    templates_dir=temp_folder.parent / "templates",
                    font_path=temp_folder.parent / "fonts/NotoSans-ExtraBold.ttf",
                    shorts_resolution=(1080, 1920)
                )
                preview_gen.draw_horizontal_preview(preview_txt, temp_preview_path, selected_template)
                horizontal_preview_path = temp_preview_path
            
            combined_vertical_video = full_vertical_generator.create_full_vertical_video(
                story_id, preview_txt, audio_preview, audio_story, horizontal_preview_path
            )
            
            # Додаємо субтитри
            if 'chunks' in locals():
                final_vertical_video = apply_subtitles_ass(combined_vertical_video, chunks, 
                                                          f"{story_id}_vertical", vertical=True, 
                                                          temp_folder=temp_folder, font_name=sub_font_name)
            else:
                # Якщо горизонтального відео не було, створюємо субтитри знову
                story_offset = audio_preview.duration_seconds + 0.5
                segments, _ = asr_model.transcribe(str(audio_path), word_timestamps=True)
                words = [{"word": w.word.strip(), "start": w.start, "end": w.end} 
                        for seg in segments for w in seg.words if w.start >= story_offset]
                chunks = chunk_words(words)
                
                if chunks:
                    final_vertical_video = apply_subtitles_ass(combined_vertical_video, chunks, 
                                                              f"{story_id}_vertical", vertical=True, 
                                                              temp_folder=temp_folder, font_name=sub_font_name)
                else:
                    print("⚠️ Субтитри не знайдено для вертикального відео")
                    final_vertical_video = combined_vertical_video
            
            # Прискорення вертикального відео
            vertical_path = output_dir / f"vertical_{video_title}.mp4"
            temp_vertical_before_unique = temp_folder / f"temp_vertical_before_unique_{story_id}.mp4"
            
            if full_vertical_speed_settings['enabled'] and full_vertical_speed_settings.get('speed', 1.0) > 1.0:
                print(f"⚡ Прискорення вертикального відео...")
                speed_factor = full_vertical_speed_settings.get('speed')
                if full_vertical_speed_settings.get('target_duration'):
                    speed_factor = original_duration / full_vertical_speed_settings['target_duration']
                    speed_factor = min(speed_factor, 4.0)
                
                full_vertical_generator.finalize_full_vertical_video(final_vertical_video, audio_path, temp_vertical_before_unique)
                apply_video_speedup(temp_vertical_before_unique, temp_vertical_before_unique, speed_factor, temp_folder)
            else:
                full_vertical_generator.finalize_full_vertical_video(final_vertical_video, audio_path, temp_vertical_before_unique)
            
            # Унікалізація
            if uniquification_intensity:
                apply_video_uniquification(temp_vertical_before_unique, vertical_path, temp_folder, 
                                          uniquification_intensity, quality_settings, fps_settings)
            else:
                shutil.copy2(temp_vertical_before_unique, vertical_path)
            
            if temp_vertical_before_unique.exists():
                temp_vertical_before_unique.unlink()
            
            print(f"???? Вертикальне відео створено: {vertical_path}")
            
        except Exception as e:
            print(f"❌ Помилка при створенні вертикального відео: {e}")
    
    # Зберігаємо файли
    if horizontal_preview_path and horizontal_preview_path.exists():
        Image.open(horizontal_preview_path).convert("RGB").save(output_dir / "preview.jpg", "JPEG")
    
    (output_dir / "description.txt").write_text(description_txt, encoding="utf-8")
    
    for f in [story_path, preview_path, description_path]:
        f.write_text("", encoding="utf-8")
    
    print(f"\n✅ {story_path.name} → відео створено успішно")
    
    time.sleep(2)
    mouse.move(random.randint(0, 1920), random.randint(0, 1080), duration=1)
    time.sleep(2)
    
    # Надсилаємо превью в Telegram
    try:
        print(f"???? Надсилання превью в Telegram...")
        preview_jpg_path = output_dir / "preview.jpg"
        if preview_jpg_path.exists():
            asyncio.run(send_video_preview(preview_txt, str(preview_jpg_path)))
            print(f"✅ Превью успішно надіслано в Telegram")
    except Exception as e:
        print(f"❌ Помилка при надсиланні превью: {e}")


def process_youtube_videos(stories_dir, generators, default_template, template_mode, preview_generator, 
                           coqui_tts, asr_model, temp_folder, final_dir, speed_config, video_type, 
                           sub_font_name="Komika Axis", uniquification_intensity=None, 
                           quality_settings=None, fps_settings=None):
    """Обробляє YouTube відео з розширеними опціями та унікалізацією"""
    
    story_files = list(stories_dir.glob("*.txt"))
    story_files = [f for f in story_files 
                   if not f.name.endswith("_preview.txt") and not f.name.endswith("_description.txt")]
    
    if not story_files:
        print("❌ YouTube історій не знайдено")
        return 0
    
    print(f"???? Знайдено {len(story_files)} YouTube історій для обробки")
    
    processed_count = 0
    for i, story in enumerate(story_files, 1):
        print(f"\n{'='*60}")
        print(f"???? [{i}/{len(story_files)}] Обробка YouTube історії → {story.name}")
        print(f"{'='*60}")
        
        try:
            # Вибираємо template для цього відео
            selected_template = select_template_for_video(template_mode, default_template, preview_generator)
            if selected_template is None:
                print("❌ Template не вибрано, пропускаємо відео")
                continue
            
            process_youtube_story(
                story, 
                generators.get('horizontal'), 
                generators.get('vertical'), 
                generators.get('full_vertical'),
                selected_template, 
                coqui_tts, 
                asr_model, 
                temp_folder, 
                final_dir, 
                speed_config, 
                video_type, 
                sub_font_name, 
                uniquification_intensity,
                quality_settings,
                fps_settings
            )
            processed_count += 1
            
        except Exception as e:
            print(f"❌ Помилка з {story.name}: {e}")
            import traceback
            traceback.print_exc()
    
    return processed_count


def main():
    """Головна функція з розширеними опціями відео та унікалізацією"""
    
    print("="*60)
    print("???? ГЕНЕРАТОР ВІДЕО З НАЛАШТУВАННЯМИ ЯКОСТІ")
    print("="*60)
    
    # Запитуємо про вимкнення ПК
    off = int(input("Введіть 1 щоб вимкнути ПК після завершення скрипта: "))
    
    # === НОВІ НАЛАШТУВАННЯ ЯКОСТІ ТА FPS ===
    QUALITY_SETTINGS = select_video_quality()
    FPS_SETTINGS = select_video_fps()
    
    # --- Шляхи ---
    ROOT = Path(r"K:/test_ffmpeg_drama")
    BACKGROUNDS_DIR = ROOT / "backgrounds"
    STORIES_DIR = ROOT / "stories"
    TIKTOK_STORIES_DIR = ROOT / "tiktok_stories"
    TEMP_FOLDER = ROOT / "temp"
    TEMP_TIKTOK_FOLDER = ROOT / "temp_tiktok"
    FINAL_DIR = ROOT / "final_videos"
    FINAL_TIKTOK_DIR = ROOT / "final_tiktok_videos"
    TEMPLATES_DIR = ROOT / "templates"
    FONTS_DIR = ROOT / "fonts"
    BEEP_SOUND_PATH = ROOT / "beep.wav"
    
    # --- Ініціалізація папок ---
    for folder in [BACKGROUNDS_DIR, STORIES_DIR, TIKTOK_STORIES_DIR, FINAL_DIR, 
                   FINAL_TIKTOK_DIR, TEMPLATES_DIR, FONTS_DIR]:
        folder.mkdir(parents=True, exist_ok=True)
    
    # === ВИБІР ГОЛОСУ ===
    VOICE = select_voice()
    
    # === ВИБІР ШРИФТІВ ===
    font_config = select_fonts(FONTS_DIR)
    FONT_PREVIEW = font_config['preview']['path']
    SUB_FONT_NAME = font_config['subtitles']['name']
    
    print(f"\n????️ Налаштування озвучки:")
    print(f" ???? Голос: {VOICE}")
    print(f"\n???? Налаштування шрифтів:")
    print(f" ????️ Preview: {FONT_PREVIEW.name}")
    print(f" ???? Субтитри: {SUB_FONT_NAME}")
    
    # === НАЛАШТУВАННЯ УНІКАЛІЗАЦІЇ ===
    UNIQUIFICATION_INTENSITY = get_uniquification_settings()
    if UNIQUIFICATION_INTENSITY:
        intensity_names = {'light': '???? Легка', 'medium': '⚡ Середня', 'heavy': '???? Сильна'}
        print(f"\n???? Унікалізація: {intensity_names[UNIQUIFICATION_INTENSITY]}")
    else:
        print(f"\n???? Унікалізація: ???? Вимкнено")
    
    # --- Вибір фонових відео ---
    SOURCE_FOLDER = select_background_folder(BACKGROUNDS_DIR)
    if SOURCE_FOLDER is None:
        print("❌ Неможливо продовжити без фонових відео")
        return
    
    # Вибір типу відео
    video_type = select_video_type()
    
    # Налаштування прискорення відео
    speed_config = get_speed_settings()
    
    # Налаштування TikTok тривалості (якщо потрібно)
    tiktok_min_duration = 63
    tiktok_target_duration = 105
    if video_type in ["2", "3"]:
        tiktok_min_duration, tiktok_target_duration = get_tiktok_duration_settings()
    
    # --- Параметри ---
    DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
    if DEVICE == "cuda":
        torch.cuda.empty_cache()
        torch.backends.cudnn.benchmark = True
        torch.set_float32_matmul_precision("high")
        torch.set_default_device(DEVICE)
    
    RESOLUTION = (1920, 1080)
    SHORTS_RESOLUTION = (1080, 1920)
    VERTICAL_RESOLUTION = (1080, 1920)
    FADE_DURATION = 1
    SHORTS_TARGET_DURATION = 59
    
    # Очищуємо temp папки залежно від типу відео
    if video_type in ["1", "3", "4", "5", "6", "7"]:
        shutil.rmtree(TEMP_FOLDER, ignore_errors=True)
        TEMP_FOLDER.mkdir(parents=True, exist_ok=True)
    
    if video_type in ["2", "3"]:
        shutil.rmtree(TEMP_TIKTOK_FOLDER, ignore_errors=True)
        TEMP_TIKTOK_FOLDER.mkdir(parents=True, exist_ok=True)
    
    # --- Ініціалізація TTS та ASR ---
    MODEL = "tts_models/en/vctk/vits"
    tts = TTS(model_name=MODEL, progress_bar=False)
    ASR_MODEL = WhisperModel("small", device=DEVICE, compute_type="float16" if DEVICE == "cuda" else "int8")
    
    # --- Ініціалізація генераторів ---
    try:
        preview_generator = PreviewGenerator(
            templates_dir=TEMPLATES_DIR,
            font_path=FONT_PREVIEW,
            shorts_resolution=SHORTS_RESOLUTION
        )
        
        print("\n???? Налаштування template для відео:")
        print("Ви можете:")
        print("1. Вибрати один template для всіх відео")
        print("2. Вибирати template для кожного відео окремо")
        print("3. Використовувати перший доступний template")
        
        template_choice = input("Ваш вибір (1-3): ").strip()
        
        if template_choice == "1":
            DEFAULT_TEMPLATE = preview_generator.select_template()[0]
            TEMPLATE_MODE = "fixed"
            print(f"✅ Вибрано template: {DEFAULT_TEMPLATE}")
        elif template_choice == "2":
            DEFAULT_TEMPLATE = None
            TEMPLATE_MODE = "interactive"
        else:
            DEFAULT_TEMPLATE = list(preview_generator.templates.keys())[0]
            TEMPLATE_MODE = "auto"
            print(f"✅ Буде використовуватись template: {DEFAULT_TEMPLATE}")
    
    except FileNotFoundError as e:
        print(f"❌ Помилка з template: {e}")
        example_template = TEMPLATES_DIR / "template_default_x40_y224_w1837_h751.png"
        if not example_template.exists():
            example_img = Image.new('RGBA', (1920, 1080), (255, 255, 255, 0))
            example_img.save(example_template)
        
        preview_generator = PreviewGenerator(
            templates_dir=TEMPLATES_DIR,
            font_path=FONT_PREVIEW,
            shorts_resolution=SHORTS_RESOLUTION
        )
        DEFAULT_TEMPLATE = "template_default_x40_y224_w1837_h751"
        TEMPLATE_MODE = "auto"
    
    # --- Створення TTS функції з цензурою ---
    coqui_tts = create_tts_with_censoring(tts, TEMP_FOLDER, BEEP_SOUND_PATH, VOICE)
    
    # --- Ініціалізація генераторів відео з новими налаштуваннями ---
    generators = {}
    
    if video_type in ["1", "3", "4", "5", "6", "7"]:
        # Горизонтальний генератор
        generators['horizontal'] = HorizontalVideoGenerator(
            source_folder=SOURCE_FOLDER,
            temp_folder=TEMP_FOLDER,
            preview_generator=preview_generator,
            resolution=RESOLUTION,
            fade_duration=FADE_DURATION,
            quality_settings=QUALITY_SETTINGS,
            fps_settings=FPS_SETTINGS
        )
        
        # Вертикальний генератор (для shorts)
        if video_type in ["1", "3", "5", "6", "7"]:
            generators['vertical'] = VerticalVideoGenerator(
                source_folder=SOURCE_FOLDER,
                temp_folder=TEMP_FOLDER,
                preview_generator=preview_generator,
                shorts_resolution=SHORTS_RESOLUTION,
                target_duration=SHORTS_TARGET_DURATION,
                quality_settings=QUALITY_SETTINGS,
                fps_settings=FPS_SETTINGS
            )
        
        # Повний вертикальний генератор (9:16)
        if video_type in ["4", "5", "6", "7"]:
            generators['full_vertical'] = FullVerticalVideoGenerator(
                source_folder=SOURCE_FOLDER,
                temp_folder=TEMP_FOLDER,
                preview_generator=preview_generator,
                vertical_resolution=VERTICAL_RESOLUTION,
                fade_duration=FADE_DURATION,
                quality_settings=QUALITY_SETTINGS,
                fps_settings=FPS_SETTINGS
            )
    
    if video_type in ["2", "3"]:
        tiktok_tts = create_tts_with_censoring(tts, TEMP_TIKTOK_FOLDER, BEEP_SOUND_PATH, VOICE)
        generators['tiktok'] = TikTokVideoGenerator(
            source_folder=SOURCE_FOLDER,
            temp_folder=TEMP_TIKTOK_FOLDER,
            preview_generator=preview_generator,
            tts_func=tiktok_tts,
            asr_model=ASR_MODEL,
            tiktok_resolution=SHORTS_RESOLUTION,
            target_part_duration=tiktok_target_duration,
            min_part_duration=tiktok_min_duration,
            quality_settings=QUALITY_SETTINGS,
            fps_settings=FPS_SETTINGS
        )
    
    # Показуємо налаштування
    print(f"\n⚡ НАЛАШТУВАННЯ:")
    video_type_names = {
        "1": "???? YouTube відео (горизонтальне + shorts)",
        "2": "???? TikTok відео",
        "3": "???? YouTube + TikTok відео",
        "4": "???? YouTube вертикальне відео",
        "5": "???? Горизонтальне + вертикальне + shorts",
        "6": "???? Вертикальне + shorts",
        "7": "???? Всі типи YouTube відео"
    }
    print(f"Режим: {video_type_names[video_type]}")
    print(f"???? Фонові відео: {SOURCE_FOLDER.name}")
    print(f"????️ Голос: {VOICE}")
    print(f"???? Якість: {QUALITY_SETTINGS['name']} ({QUALITY_SETTINGS['video_bitrate']})")
    print(f"????️ FPS: {FPS_SETTINGS['fps']}")
    
    if UNIQUIFICATION_INTENSITY:
        intensity_names = {'light': '???? Легка', 'medium': '⚡ Середня', 'heavy': '???? Сильна'}
        print(f"???? Унікалізація: {intensity_names[UNIQUIFICATION_INTENSITY]}")
    
    # --- Обробка відео ---
    if video_type == "2":  # Тільки TikTok
        print(f"\n???? РЕЖИМ: Тільки TikTok відео")
        print(f"???? Використовуються фонові відео з: {SOURCE_FOLDER.name}")
        print(f"⚙️ Налаштування: мінімум {tiktok_min_duration}с, ціль {tiktok_target_duration}с")
        
        process_tiktok_videos(
            TIKTOK_STORIES_DIR,
            generators['tiktok'],
            generators.get('horizontal'),
            DEFAULT_TEMPLATE,
            TEMPLATE_MODE,
            preview_generator,
            tiktok_tts,
            ASR_MODEL,
            speed_config
        )
    
    elif video_type == "3":  # Обидва типи
        print(f"\n???? РЕЖИМ: YouTube + TikTok відео")
        print(f"???? Використовуються фонові відео з: {SOURCE_FOLDER.name}")
        print(f"⚙️ TikTok налаштування: мінімум {tiktok_min_duration}с, ціль {tiktok_target_duration}с")
        
        # Спочатку YouTube
        youtube_processed = process_youtube_videos(
            STORIES_DIR,
            generators,
            DEFAULT_TEMPLATE,
            TEMPLATE_MODE,
            preview_generator,
            coqui_tts,
            ASR_MODEL,
            TEMP_FOLDER,
            FINAL_DIR,
            speed_config,
            "1",
            SUB_FONT_NAME,
            UNIQUIFICATION_INTENSITY,
            QUALITY_SETTINGS,
            FPS_SETTINGS
        )
        
        # Потім TikTok
        tiktok_processed = process_tiktok_videos(
            TIKTOK_STORIES_DIR,
            generators['tiktok'],
            generators.get('horizontal'),
            DEFAULT_TEMPLATE,
            TEMPLATE_MODE,
            preview_generator,
            tiktok_tts,
            ASR_MODEL,
            speed_config
        )
        
        print(f"\n???? Загальний підсумок:")
        print(f"???? YouTube відео оброблено: {youtube_processed}")
        print(f"???? TikTok відео оброблено: {tiktok_processed}")
    
    else:  # YouTube варіанти (1, 4, 5, 6, 7)
        mode_names = {
            "1": "???? YouTube відео (горизонтальне + shorts)",
            "4": "???? YouTube вертикальне відео",
            "5": "???? Горизонтальне + вертикальне + shorts",
            "6": "???? Вертикальне + shorts",
            "7": "???? Всі типи YouTube відео"
        }
        print(f"\n{mode_names[video_type]}")
        print(f"???? Використовуються фонові відео з: {SOURCE_FOLDER.name}")
        
        processed = process_youtube_videos(
            STORIES_DIR,
            generators,
            DEFAULT_TEMPLATE,
            TEMPLATE_MODE,
            preview_generator,
            coqui_tts,
            ASR_MODEL,
            TEMP_FOLDER,
            FINAL_DIR,
            speed_config,
            video_type,
            SUB_FONT_NAME,
            UNIQUIFICATION_INTENSITY,
            QUALITY_SETTINGS,
            FPS_SETTINGS
        )
        
        print(f"\n???? Підсумок: оброблено {processed} відео")
    
    print(f"\n✅ Всі відео оброблено!")
    
    # Вимкнення ПК
    if off == 1:
        print("???? Вимкнення комп'ютера через 3 хвилини...")
        time.sleep(180)
        os.system("shutdown /s /t 1")
    else:
        print("???? Генератор відео завершив роботу успішно!")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n⚠️ Скрипт перервано користувачем")
    except Exception as e:
        print(f"\n❌ Критична помилка: {e}")
        import traceback
        traceback.print_exc()
Made on
Tilda