import os
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QLineEdit, QPushButton,
                             QLabel, QFileDialog, QComboBox, QWidget, QMessageBox, QHBoxLayout, QProgressBar, QScrollArea,
                             QSpacerItem, QSizePolicy)
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt, QThread, pyqtSignal
import requests
from io import BytesIO
import yt_dlp
import time


class YouTubeDownloader(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("YouTube Downloader")
        self.setMinimumSize(600, 500)  # Устанавливаем минимальный размер
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f8f8f8;
                font-family: Arial, sans-serif;
            }
            QLabel {
                font-size: 16px;
                color: #333;
            }
            QLineEdit, QComboBox {
                font-size: 14px;
                padding: 8px;
                border: 1px solid #ccc;
                border-radius: 8px;
            }
            QPushButton {
                font-size: 16px;
                background-color: #e63946;
                color: white;
                border: none;
                padding: 12px 20px;
                border-radius: 8px;
                min-width: 150px;
            }
            QPushButton:hover {
                background-color: #d62828;
            }
            QProgressBar {
                border: 2px solid #e63946;
                border-radius: 8px;
                background-color: #f0f0f0;
            }
            QProgressBar::chunk {
                background-color: #e63946;
            }
            QScrollArea {
                background-color: #fff;
                border: 1px solid #ccc;
                border-radius: 8px;
            }
        """)

        # Central widget
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout()
        central_widget.setLayout(layout)

        # Input field for URL
        self.url_input = QLineEdit()
        self.url_input.setPlaceholderText("Введите URL видео")
        self.url_input.textChanged.connect(self.update_video_info)
        layout.addWidget(self.url_input)

        # Video preview
        self.video_preview = QLabel()
        self.video_preview.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.video_preview.setFixedSize(300, 150)
        self.video_preview.setStyleSheet("border: 1px solid #ccc; border-radius: 8px;")
        layout.addWidget(self.video_preview, alignment=Qt.AlignmentFlag.AlignCenter)

        # Quality selection
        quality_layout = QHBoxLayout()
        self.quality_label = QLabel("Качество:")
        self.quality_combo = QComboBox()
        self.quality_combo.addItem("Выберите качество")
        quality_layout.addWidget(self.quality_label)
        quality_layout.addWidget(self.quality_combo)
        layout.addLayout(quality_layout)

        # Save path selection
        path_layout = QHBoxLayout()
        self.path_input = QLineEdit()
        self.path_input.setPlaceholderText("Путь к папке для сохранения")
        self.path_button = QPushButton("Выбрать путь")
        self.path_button.clicked.connect(self.select_save_path)
        path_layout.addWidget(self.path_input)
        path_layout.addWidget(self.path_button)
        layout.addLayout(path_layout)

        # Progress bar
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        layout.addWidget(self.progress_bar)

        # Speed and estimated time
        self.speed_label = QLabel("Скорость: -- KB/s")
        self.time_label = QLabel("Оставшееся время: -- секунд")
        layout.addWidget(self.speed_label)
        layout.addWidget(self.time_label)

        # Log output area (initially collapsed)
        self.log_area = QScrollArea()
        self.log_area.setWidgetResizable(True)
        self.log_output = QLabel()
        self.log_area.setWidget(self.log_output)
        self.log_area.setFixedHeight(100)  # Set height for log area
        self.log_area.setVisible(False)  # Start hidden
        layout.addWidget(self.log_area)

        # Download button
        self.download_button = QPushButton("Скачать видео")
        self.download_button.clicked.connect(self.download_video)
        layout.addWidget(self.download_button, alignment=Qt.AlignmentFlag.AlignCenter)

        # Stop button
        self.stop_button = QPushButton("Остановить загрузку")
        self.stop_button.setEnabled(False)  # Disabled initially
        self.stop_button.clicked.connect(self.stop_download)
        layout.addWidget(self.stop_button, alignment=Qt.AlignmentFlag.AlignCenter)

        # Toggle log button
        self.toggle_log_button = QPushButton("Показать/Скрыть логи")
        self.toggle_log_button.clicked.connect(self.toggle_log_area)
        layout.addWidget(self.toggle_log_button, alignment=Qt.AlignmentFlag.AlignCenter)

        # Close button with confirmation
        self.close_button = QPushButton("Закрыть программу")
        self.close_button.clicked.connect(self.close_application)
        layout.addWidget(self.close_button, alignment=Qt.AlignmentFlag.AlignCenter)

        # Button layout (2 columns for last 4 buttons)
        button_layout = QHBoxLayout()
        button_layout.addWidget(self.stop_button)
        button_layout.addWidget(self.download_button)
        button_layout.addWidget(self.toggle_log_button)
        button_layout.addWidget(self.close_button)
        layout.addLayout(button_layout)

        # Thread for download process
        self.download_thread = None
        self.download_start_time = None

    def update_video_info(self):
        """Обновление информации о видео, включая загрузку превью."""
        url = self.url_input.text().strip()
        if "youtube.com" in url or "youtu.be" in url:
            try:
                with yt_dlp.YoutubeDL() as ydl:
                    info = ydl.extract_info(url, download=False)
                    self.load_thumbnail(info.get('thumbnail'))
                    self.populate_quality_options(info)
            except Exception as e:
                self.video_preview.clear()
                self.quality_combo.clear()
                self.quality_combo.addItem("Выберите качество")
                self.append_log(f"Ошибка: {e}")
                QMessageBox.warning(self, "Ошибка", f"Не удалось загрузить информацию о видео: {e}")

    def load_thumbnail(self, thumbnail_url):
        """Загружает и отображает превью видео."""
        try:
            response = requests.get(thumbnail_url, timeout=5)
            if response.status_code == 200:
                pixmap = QPixmap()
                pixmap.loadFromData(BytesIO(response.content).read())
                self.video_preview.setPixmap(pixmap.scaled(300, 150, Qt.AspectRatioMode.KeepAspectRatio))
            else:
                self.video_preview.clear()
        except requests.RequestException:
            self.video_preview.clear()

    def populate_quality_options(self, info):
        """Заполняет выпадающий список с доступными качествами видео."""
        self.quality_combo.clear()
        self.quality_combo.addItem("Выберите качество")
        formats = info.get('formats', [])
        for fmt in formats:
            resolution = fmt.get('height', 'unknown')
            ext = fmt.get('ext', 'unknown')
            if resolution != 'unknown':
                self.quality_combo.addItem(f"{resolution}p ({ext})")

    def select_save_path(self):
        """Открывает диалог для выбора папки сохранения."""
        folder = QFileDialog.getExistingDirectory(self, "Выберите папку для сохранения")
        if folder:
            self.path_input.setText(folder)

    def download_video(self):
        """Скачивает видео с YouTube в отдельном потоке."""
        url = self.url_input.text().strip()
        save_path = self.path_input.text().strip()
        quality = self.quality_combo.currentText()

        if not url or not save_path or quality == "Выберите качество":
            QMessageBox.warning(self, "Ошибка", "Пожалуйста, заполните все поля.")
            return

        self.download_thread = DownloadThread(url, save_path, quality, self.update_progress, self.append_log)
        self.download_thread.finished.connect(self.download_finished)
        self.download_thread.start()

        self.download_start_time = time.time()  # Запоминаем время начала загрузки
        self.download_button.setEnabled(False)
        self.stop_button.setEnabled(True)

    def update_progress(self, progress, speed, remaining_time):
        """Обновляет прогресс-бар и выводит скорость и время оставшееся для загрузки."""
        self.progress_bar.setValue(progress)
        self.speed_label.setText(f"Скорость: {speed:.2f} KB/s")
        self.time_label.setText(f"Оставшееся время: {remaining_time:.0f} секунд")

    def append_log(self, message):
        """Добавляет сообщение в область логов."""
        current_log = self.log_output.text()
        new_log = f"{current_log}\n{message}" if current_log else message
        self.log_output.setText(new_log)

    def download_finished(self):
        """Обрабатывает завершение загрузки."""
        self.append_log("Загрузка завершена!")
        self.download_button.setEnabled(True)
        self.stop_button.setEnabled(False)

    def stop_download(self):
        """Останавливает текущую загрузку."""
        if self.download_thread:
            self.download_thread.terminate()
            self.append_log("Загрузка остановлена.")
            self.download_button.setEnabled(True)
            self.stop_button.setEnabled(False)

    def toggle_log_area(self):
        """Переключает видимость области логов."""
        self.log_area.setVisible(not self.log_area.isVisible())

    def close_application(self):
        """Запрашивает подтверждение перед закрытием программы."""
        reply = QMessageBox.question(self, 'Подтверждение', 'Вы уверены, что хотите закрыть программу?',
                                     QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No)
        if reply == QMessageBox.StandardButton.Yes:
            QApplication.quit()


class DownloadThread(QThread):
    progress_signal = pyqtSignal(int, float, float)

    def __init__(self, url, save_path, quality, progress_callback, log_callback):
        super().__init__()
        self.url = url
        self.save_path = save_path
        self.quality = quality
        self.progress_callback = progress_callback
        self.log_callback = log_callback
        self.start_time = None

    def run(self):
        """Скачивание видео с YouTube."""
        ydl_opts = {
            'outtmpl': os.path.join(self.save_path, '%(title)s.%(ext)s'),
            'format': 'best[ext=mp4]/best',  # Скачиваем лучший mp4 файл
            'progress_hooks': [self.progress_hook],
        }
        try:
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                self.log_callback("Начинаем загрузку видео...")
                ydl.download([self.url])
        except Exception as e:
            self.log_callback(f"Ошибка при загрузке: {e}")
            self.progress_signal.emit(0, 0, 0)

    def progress_hook(self, d):
        """Отслеживает прогресс загрузки."""
        if d['status'] == 'downloading':
            percent = d.get('progress', 0)
            speed = d.get('speed', 0) / 1024  # Переводим в KB/s
            eta = d.get('eta', 0)
            elapsed_time = time.time() - self.start_time if self.start_time else 0
            if eta and elapsed_time:
                remaining_time = eta
            else:
                remaining_time = 0
            self.progress_signal.emit(percent, speed, remaining_time)
        elif d['status'] == 'finished':
            self.log_callback("Загрузка завершена!")

    def set_start_time(self, start_time):
        self.start_time = start_time


if __name__ == "__main__":
    app = QApplication([])
    window = YouTubeDownloader()
    window.show()
    app.exec()
 - Отображение скорости загрузки и времени скачивания так и не работает. Так же не работает прогресс бар. Какое бы качество видео не выбиралось, загрузка все равно идет одна и та же, скачивается одно и то же видео, в том же качестве - исправь все это