Initial commit

This commit is contained in:
2026-05-19 17:42:12 +03:00
commit 001f9ce691
4 changed files with 550 additions and 0 deletions

150
docs/Specification.md Normal file
View File

@@ -0,0 +1,150 @@
# ЦЕЛЬ ПРОЕКТА
## 1. Общее описание проекта
**NaviWatcher** — это автономный сервисный инструмент (демон), предназначенный для автоматического мониторинга музыкальных коллекций, хранящихся в Navidrome (или любом сервере с поддержкой Subsonic API).
**Основная задача:** сопоставлять текущую медиатеку пользователя с полной дискографией артистов во внешних базах данных (MusicBrainz), находить отсутствующие релизы (альбомы, синглы, сборники) и уведомлять об этом пользователя через Telegram и встроенный веб-интерфейс.
## 2. Технологический стек
* **Язык программирования:** Go 1.21+
* **База данных:** SQLite 3 (для хранения кэша, настроек и состояний).
* **HTTP-сервер:** Стандартная библиотека Go (`net/http`) + `html/template`.
* **Внешние зависимости (библиотеки):**
* `github.com/mattn/go-sqlite3` — драйвер базы данных.
* `github.com/lithammer/fuzzysearch` — библиотека для нечеткого сравнения строк.
* `gopkg.in/yaml.v3` — парсинг конфигурационных файлов.
### 2.1. Аутентификация в Navidrome (Subsonic API)
NaviWatcher взаимодействует с Navidrome через **Subsonic API v1.16.1** (эндпоинты `/rest/*`).
Используется **токенная аутентификация** — стандартный метод Subsonic API:
* Формула токена: `token = md5(password + salt)`
* Salt генерируется клиентом случайно при каждом запросе.
* Пароль пользователя **не передаётся** в открытом виде.
* Это обеспечивает совместимость с любыми Subsonic-совместимыми серверами (Navidrome, Airsonic, Ampache).
**Пример запроса:**
```
/rest/getArtists?u=watcher_service&t=<md5_hash>&s=<random_salt>&v=1.16.1&c=NaviWatcher
```
**Создание сервисного пользователя в Navidrome:**
1. В веб-интерфейсе Navidrome: Settings → Users → Add User.
2. Задать username и надёжный пароль.
3. Убедиться, что роль имеет доступ к нужным медиатекам.
4. Указать эти данные в `config.yaml` (поля `user` и `password`).
## 3. Архитектура системы
Проект разделен на логические модули:
1. **Navidrome Client:** Взаимодействие с Subsonic API v1.16.1 (чтение артистов и локальных альбомов). Аутентификация — токенная (md5), пароль не передаётся в открытом виде. Используются эндпоинты: `getArtists`, `getArtist`, `getAlbum`, `ping`.
2. **MusicBrainz Provider:** Запрос дискографий с механизмом кэширования и соблюдением Rate Limit (1 запрос в секунду).
3. **Scanner Engine:** Логика нормализации строк и сравнения списков (Diff).
4. **Database Layer:** Персистентное хранение данных и пользовательских фильтров.
5. **Notifier:** Планировщик задач и отправка уведомлений в Telegram.
6. **Web UI:** Интерфейс для просмотра находок и управления исключениями.
## 4. Алгоритмы и бизнес-логика
### 4.1. Работа с внешними данными (MusicBrainz)
Для минимизации дубликатов (разные издания одного альбома) сервис должен работать с сущностью **Release Group (RG)**, а не с конкретными релизами.
* **Кэширование:** Данные о дискографии артиста сохраняются в SQLite на 24 часа. Повторные запросы в этот период идут только в БД.
### 4.2. Фильтрация контента
При получении списка Release Groups из MusicBrainz применяется многоуровневый фильтр:
1. **По статусу:** Игнорировать `Bootleg`, `Promotion`, `Pseudo-Release`.
2. **По типу (глобально):** Разрешены `Album`, `Single`, `EP`, `Compilation`.
3. **По типу (персонально для артиста):** Возможность отключить `Single` или `Compilation` для конкретного исполнителя через Web UI.
4. **По вторичным признакам:** Опциональное игнорирование `Live`, `Remix`, `Soundtrack`.
### 4.3. Сравнение (Fuzzy Matching)
Чтобы избежать ложных срабатываний (например, «The Wall» vs «The Wall (Remastered)»), используется алгоритм:
1. **Нормализация:** Приведение к нижнему регистру, удаление спецсимволов, удаление года (20xx), удаление ключевых слов в скобках (Deluxe, Anniversary, Expanded).
2. **Сравнение:** Если коэффициент сходства строк выше 0.85 (настраиваемо), альбом считается «уже имеющимся».
### 4.4. Жизненный цикл уведомлений
1. Найден новый релиз -> Проверка, нет ли его в таблице `ignored_releases` или `notifications_sent`.
2. Если нет -> Добавление в очередь на отправку.
3. Раз в сутки -> Отправка сводного сообщения в Telegram -> Пометка в `notifications_sent`.
## 5. Модель данных (SQLite)
### Таблица `artist_settings`
Хранит параметры мониторинга для каждого артиста из Navidrome.
* `id`: string (MBID или имя)
* `name`: string
* `ignore_singles`: boolean (default: false)
* `ignore_compilations`: boolean (default: false)
* `monitored`: boolean (default: true)
### Таблица `external_releases`
Кэш релизов, найденных во внешнем мире.
* `rgid`: string (MusicBrainz Release Group ID) — Primary Key.
* `artist_id`: string (FK)
* `title`: string
* `type`: string (album/single/ep)
* `release_date`: string
* `is_ignored`: boolean (флаг скрытия из списка новинок)
### Таблица `notifications_sent`
* `rgid`: string (FK)
* `sent_at`: datetime
## 6. Требования к интерфейсу
### 6.1. Web UI (Dashboard)
* **Главный экран:** Список артистов, у которых есть «Missing Albums».
* **Страница артиста:**
* Список альбомов в Navidrome (Source: Subsonic).
* Список найденных новинок (Source: MB Cache).
* Действия: «Игнорировать этот релиз», «Игнорировать все синглы артиста».
* **Страница «Архив»:** Просмотр ранее проигнорированных релизов с возможностью их восстановления.
### 6.2. Telegram
* Сообщение должно содержать список имен артистов и количество найденных новинок.
* Ссылка на Web UI для детального просмотра.
## 7. Конфигурация (config.yaml)
```yaml
server:
host: "0.0.0.0"
port: 8080
# Basic Auth для доступа к веб-интерфейсу
username: "admin"
password: "password123"
navidrome:
url: "http://localhost:4533"
user: "watcher_service"
password: "user_password"
# Токен и salt генерируются автоматически при каждом запросе (md5(password + salt))
musicbrainz:
user_agent: "NaviWatcher/1.0 ( mail@example.com )"
cache_ttl: 24h
telegram:
enabled: true
token: "bot_token"
chat_id: "your_chat_id"
cron_schedule: "0 10 * * *" # Каждый день в 10:00
scanner:
fuzzy_threshold: 0.85
ignore_bootlegs: true
include_compilations: true
```
## 8. Программные требования и ограничения
1. **Rate Limiting:** MusicBrainz API позволяет делать не более 1 запроса в секунду. Демон должен строго соблюдать этот интервал.
2. **Concurrency:** Запросы к Navidrome и MusicBrainz должны выполняться в отдельных горутинах, чтобы веб-интерфейс оставался отзывчивым.
3. **Graceful Shutdown:** При получении сигнала завершения (SIGTERM) демон должен корректно закрыть соединение с SQLite.
4. **Static Files:** Все HTML-шаблоны должны быть встроены в бинарный файл (использование `//go:embed`).
5. **Docker:** Проект должен быть запущен через `docker compose`.