""" Утилиты для YouTube Downloader """ import os import json import argparse from datetime import datetime from config import Config from downloader import YouTubeDownloader class DownloadLogger: """Класс для логирования загрузок""" def __init__(self, log_file="download_history.json"): self.log_file = log_file self.history = self.load_history() def load_history(self): """Загружает историю загрузок""" if os.path.exists(self.log_file): try: with open(self.log_file, 'r', encoding='utf-8') as f: return json.load(f) except (json.JSONDecodeError, IOError): return [] return [] def save_history(self): """Сохраняет историю загрузок""" try: with open(self.log_file, 'w', encoding='utf-8') as f: json.dump(self.history, f, indent=2, ensure_ascii=False) except IOError as e: print(f"Ошибка сохранения истории: {e}") def add_download(self, url, title, success=True, error=None): """Добавляет запись о загрузке""" record = { 'timestamp': datetime.now().isoformat(), 'url': url, 'title': title, 'success': success, 'error': error } self.history.append(record) self.save_history() def get_recent_downloads(self, count=10): """Возвращает последние загрузки""" return self.history[-count:] if len(self.history) >= count else self.history def get_failed_downloads(self): """Возвращает неудачные загрузки""" return [record for record in self.history if not record['success']] class BatchDownloader: """Класс для пакетной загрузки из файла со ссылками""" def __init__(self, config=None): self.config = config or Config() self.downloader = YouTubeDownloader(self.config) self.logger = DownloadLogger() def download_from_file(self, file_path, quality='best', audio_only=False): """Загружает все URL из файла""" if not os.path.exists(file_path): print(f"Файл {file_path} не найден") return False with open(file_path, 'r', encoding='utf-8') as f: urls = [line.strip() for line in f if line.strip() and not line.startswith('#')] print(f"Найдено {len(urls)} URL для загрузки") successful = 0 failed = 0 for i, url in enumerate(urls, 1): print(f"\n[{i}/{len(urls)}] Загрузка: {url}") try: # Получаем информацию о видео info = self.downloader.get_video_info(url) title = info['title'] if info else 'Неизвестное название' # Загружаем success = self.downloader.download_video(url, quality, audio_only) if success: successful += 1 self.logger.add_download(url, title, True) print(f"✓ Успешно загружено: {title}") else: failed += 1 self.logger.add_download(url, title, False, "Ошибка загрузки") print(f"✗ Ошибка загрузки: {title}") except Exception as e: failed += 1 self.logger.add_download(url, "Неизвестное название", False, str(e)) print(f"✗ Исключение при загрузке {url}: {str(e)}") print(f"\nРезультаты пакетной загрузки:") print(f"Успешно: {successful}") print(f"Ошибок: {failed}") print(f"Всего: {len(urls)}") return failed == 0 def create_url_list_template(): """Создает шаблон файла со ссылками""" template = """# YouTube URL List Template # Добавьте по одной ссылке YouTube на каждой строке # Строки, начинающиеся с #, игнорируются (комментарии) # Пример видео: # https://www.youtube.com/watch?v=dQw4w9WgXcQ # Пример плейлиста: # https://www.youtube.com/playlist?list=PLrAXtmRdnEQy6nuLMt6VEY # Добавьте ваши ссылки ниже: """ with open('urls.txt', 'w', encoding='utf-8') as f: f.write(template) print("Создан файл urls.txt с шаблоном ссылок") def show_download_history(): """Показывает историю загрузок""" logger = DownloadLogger() recent = logger.get_recent_downloads(20) if not recent: print("История загрузок пуста") return print("Последние загрузки:") print("-" * 80) for record in recent: timestamp = record['timestamp'][:19] # Убираем микросекунды status = "✓" if record['success'] else "✗" title = record['title'][:50] + "..." if len(record['title']) > 50 else record['title'] print(f"{status} {timestamp} | {title}") if not record['success'] and record.get('error'): print(f" Ошибка: {record['error']}") def clean_downloads_folder(): """Очищает папку загрузок""" config = Config() downloads_dir = config.get('output_directory', 'downloads') if not downloads_dir or not os.path.exists(downloads_dir): print(f"Папка {downloads_dir} не существует") return files = os.listdir(downloads_dir) if not files: print(f"Папка {downloads_dir} уже пуста") return print(f"Найдено {len(files)} файлов в {downloads_dir}") confirm = input("Удалить все файлы? (yes/no): ") if confirm.lower() in ['yes', 'y', 'да', 'д']: for file in files: file_path = os.path.join(str(downloads_dir), file) try: if os.path.isfile(file_path): os.remove(file_path) print(f"Удален: {file}") except Exception as e: print(f"Ошибка удаления {file}: {e}") print("Очистка завершена") else: print("Очистка отменена") def main(): parser = argparse.ArgumentParser(description='YouTube Downloader - Утилиты') parser.add_argument('action', choices=[ 'batch', 'history', 'clean', 'template' ], help='Действие для выполнения') parser.add_argument('--file', '-f', help='Файл со ссылками для пакетной загрузки') parser.add_argument('--quality', '-q', default='best', help='Качество видео') parser.add_argument('--audio-only', '-a', action='store_true', help='Только аудио') args = parser.parse_args() if args.action == 'batch': if not args.file: print("Для пакетной загрузки необходимо указать файл со ссылками (--file)") return batch = BatchDownloader() batch.download_from_file(args.file, args.quality, args.audio_only) elif args.action == 'history': show_download_history() elif args.action == 'clean': clean_downloads_folder() elif args.action == 'template': create_url_list_template() if __name__ == '__main__': main()