# Архитектура GenAudioBookInfo построен по принципам **Чистой архитектуры** (Clean Architecture / Hexagonal Architecture). Бизнес-логика не зависит от внешних библиотек, баз данных или UI-фреймворков. --- ## Слои ``` ┌──────────────────────────────────────────────────────────┐ │ cmd/genaudiobookinfo/main.go (Composition Root / DI) │ ├──────────────────────────────────────────────────────────┤ │ presentation/ TUI, ConsoleLogger, Presenter │ ├──────────────────────────────────────────────────────────┤ │ usecase/ Бизнес-логика. Нет зависимостей │ │ от infra, только интерфейсы │ ├──────────────────────────────────────────────────────────┤ │ domain/ Сущности + интерфейсы (порты) │ ├──────────────────────────────────────────────────────────┤ │ infrastructure/ Адаптеры: FS, HTTP, теги, YAML │ └──────────────────────────────────────────────────────────┘ ``` Зависимости направлены **внутрь**: `main → usecase → domain ← infrastructure`. --- ## Структура папок ``` genaudiobookinfo/ ├── cmd/ │ └── genaudiobookinfo/ │ └── main.go # Точка входа, DI, TUI запуск ├── internal/ │ ├── domain/ │ │ ├── audiobook.go # Агрегат AudioBookInfo, EnrichedBookInfo │ │ ├── llm.go # Интерфейс LLMClient │ │ ├── ports.go # Все порты: FolderLister, MetadataExtractor, │ │ │ # TorrentSearcher, ResultWriter, CoverDownloader, │ │ │ # ProcessLogger, ProcessResult │ │ └── torrent.go # Сущности TorrentInfo, TorrentDetail │ ├── usecase/ │ │ └── scan_audiobooks.go # Конвейер (Pipeline + Fan-Out/Fan-In) │ ├── infrastructure/ # Адаптеры (реализации портов) │ │ ├── folder_lister.go # FSFolderLister │ │ ├── metadata_extractor.go # TagMetadataExtractor (dhowden/tag) │ │ ├── torrapi_client.go # TorrAPIClient (HTTP) │ │ ├── result_writer.go # FSResultWriter (создание папок, JSON, копирование) │ │ ├── cover_downloader.go # HTTPCoverDownloader │ │ ├── openrouter_client.go # OpenRouterClient (LLM через REST) │ │ ├── audio_utils.go # Утилиты: длительность, формат, список файлов │ │ ├── console_windows.go # SetConsoleUTF8 для Windows │ │ └── console_other.go # Заглушка для non-Windows │ ├── nameparser/ │ │ └── parser.go # Разбор "Автор - Название" из имени папки │ └── presentation/ │ ├── tui_logger.go # TUILogger (Bubbletea, Dracula) │ ├── console_logger.go # ConsoleLogger (fallback без TUI) │ └── console_presenter.go # Финальная сводка в stdout ├── config.yaml ├── go.mod ├── go.sum ├── Makefile └── README.md ``` --- ## Интерфейсы (порты) Определены в `internal/domain/ports.go`: | Интерфейс | Назначение | Адаптер | |---|---|---| | `FolderLister` | Перечислить подпапки | `FSFolderLister` | | `MetadataExtractor` | Извлечь теги из аудиофайла | `TagMetadataExtractor` | | `TorrentSearcher` | Поиск + детали раздачи | `TorrAPIClient` | | `ResultWriter` | Записать результат на диск | `FSResultWriter` | | `CoverDownloader` | Скачать обложку | `HTTPCoverDownloader` | | `LLMClient` | Нормализовать автора/название | `OpenRouterClient` | | `ProcessLogger` | Отчитываться о прогрессе | `TUILogger` / `ConsoleLogger` | --- ## Паттерны | Паттерн | Где применён | |---|---| | Pipeline | `ExecuteForFolders` → `processOneBook` → writer | | Fan-Out / Fan-In | Worker Pool в `ExecuteForFolders` | | Semaphore | `searchSem` — ограничение параллелизма к TorrAPI | | Dependency Injection | `main.go` — Composition Root без фреймворка | | Repository / Port-Adapter | Все `infrastructure/` адаптеры | | Strategy | `ProcessLogger` — TUI или Console выбирается в `main.go` | | Graceful Shutdown | `context.WithTimeout` + `signal.Notify` (SIGINT, SIGTERM) | --- ## TUI (Bubbletea) `presentation/tui_logger.go` реализует полноэкранный интерфейс: - **Верхняя панель**: текущая книга, статус, прогресс-бар `N / Total`, спиннер, последние 5 событий - **Нижняя панель**: полный лог с цветами (Dracula palette) Цветовая схема: | Тип | Цвет | |---|---| | INFO | `#00FFFF` cyan | | WARN | `#FFFF00` yellow | | ERROR | `#FF5555` red | | OK | `#50FA7B` green | | DEBUG | `#6272A4` gray |