#!/usr/bin/env python3 """ YouTube Downloader - Приложение для скачивания видео с YouTube Автор: GitHub Copilot """ import sys import click from colorama import Fore, Style from downloader import YouTubeDownloader from config import Config @click.command() @click.argument('url', required=False) @click.option('--quality', '-q', default='best', help='Качество видео (best, 1080p, 720p, 480p, 360p)') @click.option('--audio-only', '-a', is_flag=True, help='Скачать только аудио') @click.option('--output', '-o', default=None, help='Папка для сохранения файлов') @click.option('--playlist', '-p', is_flag=True, help='Скачать весь плейлист') @click.option('--info', '-i', is_flag=True, help='Показать информацию о видео без загрузки') @click.option('--formats', '-f', is_flag=True, help='Показать доступные форматы') @click.option('--config', '-c', default='config.json', help='Путь к файлу конфигурации') @click.option('--batch', '-b', default=None, type=click.Path(exists=True), help='Файл со списком URL для пакетной загрузки') @click.option('--urls', multiple=True, help='Несколько URL через пробел') @click.option('--continue-on-error', is_flag=True, help='Продолжать загрузку при ошибках') def main(url, quality, audio_only, output, playlist, info, formats, config, batch, urls, continue_on_error): """ YouTube Downloader - скачивание видео с YouTube URL: Ссылка на YouTube видео или плейлист (опционально при использовании --batch или --urls) """ # Вывод заголовка print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}") print(f"{Fore.CYAN}{'YouTube Downloader':^60}{Style.RESET_ALL}") print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}") try: # Инициализация конфигурации и загрузчика app_config = Config(config) downloader = YouTubeDownloader(app_config) # Определяем список URL для обработки urls_to_process = [] if batch: # Пакетная загрузка из файла print(f"{Fore.GREEN}Загрузка URL из файла: {batch}{Style.RESET_ALL}") urls_to_process = load_urls_from_file(batch) elif urls: # Множественные URL из командной строки urls_to_process = list(urls) print(f"{Fore.GREEN}Обработка {len(urls_to_process)} URL из командной строки{Style.RESET_ALL}") elif url: # Один URL urls_to_process = [url] else: print(f"{Fore.RED}Ошибка: Необходимо указать URL, --batch файл или --urls{Style.RESET_ALL}") sys.exit(1) # Обработка списка URL if info or formats: # Для info и formats обрабатываем только первый URL process_single_url = urls_to_process[0] if urls_to_process else None if not process_single_url: print(f"{Fore.RED}Ошибка: Нет URL для обработки{Style.RESET_ALL}") sys.exit(1) if not downloader.validate_url(process_single_url): print(f"{Fore.RED}Ошибка: Некорректный URL YouTube{Style.RESET_ALL}") sys.exit(1) if info: show_video_info(downloader, process_single_url) return if formats: show_video_formats(downloader, process_single_url) return # Пакетная загрузка print(f"\n{Fore.GREEN}Начинаю обработку {len(urls_to_process)} URL...{Style.RESET_ALL}") successful = 0 failed = 0 failed_urls = [] for i, current_url in enumerate(urls_to_process, 1): print(f"\n{Fore.CYAN}[{i}/{len(urls_to_process)}] Обработка: {current_url}{Style.RESET_ALL}") # Проверка URL if not downloader.validate_url(current_url): print(f"{Fore.RED}✗ Некорректный URL, пропускаем{Style.RESET_ALL}") failed += 1 failed_urls.append((current_url, "Некорректный URL")) if not continue_on_error: break continue try: success = False if playlist: success = downloader.download_playlist(current_url, quality, audio_only, output) else: success = downloader.download_video(current_url, quality, audio_only, output) if success: successful += 1 print(f"{Fore.GREEN}✓ [{i}/{len(urls_to_process)}] Успешно загружено{Style.RESET_ALL}") else: failed += 1 failed_urls.append((current_url, "Ошибка загрузки")) print(f"{Fore.RED}✗ [{i}/{len(urls_to_process)}] Ошибка загрузки{Style.RESET_ALL}") if not continue_on_error: break except Exception as e: failed += 1 error_msg = str(e)[:100] + "..." if len(str(e)) > 100 else str(e) failed_urls.append((current_url, error_msg)) print(f"{Fore.RED}✗ [{i}/{len(urls_to_process)}] Исключение: {error_msg}{Style.RESET_ALL}") if not continue_on_error: break # Показ результатов print(f"\n{Fore.GREEN}{'='*60}{Style.RESET_ALL}") if len(urls_to_process) > 1: print(f"{Fore.GREEN}Пакетная загрузка завершена!{Style.RESET_ALL}") print(f"{Fore.CYAN}Успешно: {successful}{Style.RESET_ALL}") print(f"{Fore.CYAN}Ошибок: {failed}{Style.RESET_ALL}") print(f"{Fore.CYAN}Всего: {len(urls_to_process)}{Style.RESET_ALL}") if failed_urls: print(f"\n{Fore.YELLOW}Неудачные загрузки:{Style.RESET_ALL}") for url_item, error in failed_urls[:5]: # Показываем только первые 5 short_url = url_item[:50] + "..." if len(url_item) > 50 else url_item print(f" ✗ {short_url}: {error}") if len(failed_urls) > 5: print(f" ... и еще {len(failed_urls) - 5} ошибок") else: if successful > 0: print(f"{Fore.GREEN}Загрузка успешно завершена!{Style.RESET_ALL}") else: print(f"{Fore.RED}Загрузка завершилась с ошибкой{Style.RESET_ALL}") output_path = output or app_config.get("output_directory", "downloads") print(f"{Fore.CYAN}Файлы сохранены в: {output_path}{Style.RESET_ALL}") print(f"{Fore.GREEN}{'='*60}{Style.RESET_ALL}") if failed > 0 and not continue_on_error: sys.exit(1) except KeyboardInterrupt: print(f"\n{Fore.YELLOW}Загрузка прервана пользователем{Style.RESET_ALL}") sys.exit(0) except Exception as e: print(f"\n{Fore.RED}Произошла неожиданная ошибка: {str(e)}{Style.RESET_ALL}") sys.exit(1) @click.group() def cli(): """YouTube Downloader - управление настройками и загрузка видео""" pass @cli.command() @click.option('--output-dir', default='downloads', help='Папка для загрузок по умолчанию') @click.option('--video-quality', default='best', help='Качество видео по умолчанию') @click.option('--audio-format', default='mp3', help='Формат аудио по умолчанию') @click.option('--video-format', default='mp4', help='Формат видео по умолчанию') def configure(output_dir, video_quality, audio_format, video_format): """Настройка параметров по умолчанию""" config = Config() config.set('output_directory', output_dir) config.set('video_quality', video_quality) config.set('audio_format', audio_format) config.set('video_format', video_format) config.save_config() print(f"{Fore.GREEN}Конфигурация сохранена:{Style.RESET_ALL}") print(f" Папка загрузок: {output_dir}") print(f" Качество видео: {video_quality}") print(f" Формат аудио: {audio_format}") print(f" Формат видео: {video_format}") @cli.command() def show_config(): """Показать текущие настройки""" config = Config() print(f"{Fore.CYAN}Текущая конфигурация:{Style.RESET_ALL}") for key, value in config.config.items(): print(f" {key}: {value}") if __name__ == '__main__': # Если запущен без команды, используем основную функцию if len(sys.argv) == 1 or (len(sys.argv) > 1 and not sys.argv[1] in ['configure', 'show-config']): main() else: cli()