# NaviWatcher > **Language:** [English](#english) | [Русский](#русский) --- ## English NaviWatcher is an autonomous service daemon that monitors your Navidrome music collection, compares it against artist discographies from MusicBrainz, and notifies you about missing releases via Telegram and a built-in web interface. ### How It Works 1. **Scans** your Navidrome library via Subsonic API to get the list of artists and albums. 2. **Fetches** full artist discographies from MusicBrainz (using Release Groups to avoid duplicate editions). 3. **Compares** local collection with external data using fuzzy matching (configurable threshold, default 0.85). 4. **Notifies** you about missing albums/singles/EPs through daily Telegram digests and a web dashboard *(not yet implemented — see Implementation Status)*. ### Features - **Subsonic API compatible** — works with Navidrome, Airsonic, Ampache, and other Subsonic-compatible servers. - **Fuzzy matching** — smart string normalization (ignores remastered/deluxe/anniversary editions, year suffixes, special characters). - **Per-artist filters** — opt out of Singles and Compilations per artist (via `artist_settings`); type filtering includes only Album/Single/EP primary types (plus release groups whose secondary types include Single/EP/Compilation). - **MusicBrainz caching** — 24-hour TTL cache to minimize API calls and respect rate limits (1 req/sec). - **Telegram notifications** — *(not yet implemented)* daily summary messages with links to the web UI. - **Web dashboard** — *(not yet implemented)* browse missing albums, ignore releases, manage artist-specific settings. - **Single binary deployment** — all HTML templates embedded via `//go:embed`. - **Docker support** — ready for `docker compose` deployment. ### Technology Stack - **Language:** Go 1.25+ - **Database:** SQLite 3 - **HTTP Server:** Go standard library (`net/http` + `html/template`) - **Key dependencies:** - `github.com/mattn/go-sqlite3` — SQLite driver - `github.com/lithammer/fuzzysearch` — fuzzy string matching - `gopkg.in/yaml.v3` — configuration parsing ### Quick Start 1. **Create a service user in Navidrome:** - Go to Settings → Users → Add User - Set a username and password - Ensure the user has access to your music libraries 2. **Configure NaviWatcher:** ```bash cp config.yaml.example config.yaml # Edit config.yaml with your settings ``` 3. **Build and run:** ```bash go build -o naviwatcher ./naviwatcher ``` 4. **Or use Docker:** ```bash docker compose up -d ``` 5. **Access the web UI** at `http://localhost:8080` > **Note (current status):** On startup the service opens a local SQLite database at > `naviwatcher.db` in the working directory (existing databases are auto-migrated) and > performs a compute-only scan of all monitored artists, logging the count of missing > releases. `musicbrainz.user_agent` is required and validated at startup. The notifier > and Web UI are not yet wired into the running service — scan results are logged only. ### Configuration ```yaml server: host: "0.0.0.0" port: 8080 username: "admin" password: "CHANGE_ME" navidrome: url: "http://localhost:4533" user: "watcher_service" password: "CHANGE_ME" 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 * * *" scanner: fuzzy_threshold: 0.85 ``` See [docs/Specification.md](docs/Specification.md) for the full configuration reference and architecture details. ### Architecture | Module | Purpose | |--------|---------| | **Navidrome Client** | Subsonic API v1.16.1 communication (token-based auth) | | **MusicBrainz Provider** | Discography fetching with rate limiting and caching | | **Scanner Engine** | String normalization and fuzzy comparison | | **Database Layer** | SQLite persistence: `artist_settings`, `local_albums` (Navidrome sync), `external_releases` (MusicBrainz cache), `notifications_sent` | | **Notifier** | Scheduled Telegram notifications | | **Web UI** | Dashboard for browsing and managing missing releases | ### Implementation Status - **Scanner Engine** — implemented (compute-only). The missing-release detection core is complete: string normalization lives in `internal/normalize`, similarity scoring and the diff engine (`FindMissingReleases`, `ScanArtist`, `ScanAll`) in `internal/scanner`. It uses the configurable `scanner.fuzzy_threshold` (default 0.85), normalizes titles (ignoring `(Remastered)`/year/special-char variants), and skips releases marked ignored. - **Notifier and Web UI** — not yet implemented (out of scope for the scanner plan). `main.run()` currently performs a compute-only scan and logs missing-release counts; it does not persist results or send notifications. ### License [WTFPL](License.md) — Do What The Fuck You Want To Public License --- ## Русский NaviWatcher — это автономный сервис-демон для мониторинга музыкальной коллекции в Navidrome. Он сравнивает вашу медиатеку с полными дискографиями артистов из MusicBrainz и уведомляет об отсутствующих релизах через Telegram и веб-интерфейс. ### Как это работает 1. **Сканирует** библиотеку Navidrome через Subsonic API — получает список артистов и альбомов. 2. **Загружает** полные дискографии артистов из MusicBrainz (использует Release Groups, чтобы избежать дубликатов изданий). 3. **Сравнивает** локальную коллекцию с внешними данными через нечёткое сравнение строк (настраиваемый порог, по умолчанию 0.85). 4. **Уведомляет** об отсутствующих альбомах/синглах/EP через ежедневные дайджесты в Telegram и веб-панель *(пока не реализовано — см. раздел «Статус реализации»)*. ### Возможности - **Совместим с Subsonic API** — работает с Navidrome, Airsonic, Ampache и другими Subsonic-совместимыми серверами. - **Нечёткое сравнение** — умная нормализация строк (игнорирует ремастеры, deluxe/anniversary-издания, год в скобках, спецсимволы). - **Фильтры по артистам** — отключение синглов и компиляций для конкретного артиста (через `artist_settings`); фильтрация по типам включает только основные типы Album/Single/EP (а также группы релизов, чьи вторичные типы содержат Single/EP/Compilation). - **Кэширование MusicBrainz** — TTL 24 часа для минимизации запросов и соблюдения лимитов (1 запрос/сек). - **Уведомления в Telegram** — *(пока не реализовано)* ежедневные сводки со ссылками на веб-интерфейс. - **Веб-панель** — *(пока не реализовано)* просмотр отсутствующих альбомов, игнорирование релизов, управление настройками артистов. - **Один бинарный файл** — все HTML-шаблоны встроены через `//go:embed`. - **Поддержка Docker** — готов к развёртыванию через `docker compose`. ### Технологический стек - **Язык:** Go 1.21+ - **База данных:** SQLite 3 - **HTTP-сервер:** стандартная библиотека Go (`net/http` + `html/template`) - **Ключевые зависимости:** - `github.com/mattn/go-sqlite3` — драйвер SQLite - `github.com/lithammer/fuzzysearch` — нечёткое сравнение строк - `gopkg.in/yaml.v3` — парсинг конфигурации ### Быстрый старт 1. **Создайте сервисного пользователя в Navidrome:** - Перейдите в Settings → Users → Add User - Задайте имя пользователя и пароль - Убедитесь, что у пользователя есть доступ к медиатекам 2. **Настройте NaviWatcher:** ```bash cp config.yaml.example config.yaml # Отредактируйте config.yaml ``` 3. **Соберите и запустите:** ```bash go build -o naviwatcher ./naviwatcher ``` 4. **Или используйте Docker:** ```bash docker compose up -d ``` 5. **Откройте веб-интерфейс** по адресу `http://localhost:8080` ### Конфигурация ```yaml server: host: "0.0.0.0" port: 8080 username: "admin" password: "CHANGE_ME" navidrome: url: "http://localhost:4533" user: "watcher_service" password: "CHANGE_ME" 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 * * *" scanner: fuzzy_threshold: 0.85 ``` Полную справку по конфигурации и архитектуру см. в [docs/Specification.md](docs/Specification.md). ### Архитектура | Модуль | Назначение | |--------|------------| | **Navidrome Client** | Взаимодействие с Subsonic API v1.16.1 (токенная аутентификация) | | **MusicBrainz Provider** | Загрузка дискографий с кэшированием и rate limiting | | **Scanner Engine** | Нормализация строк и нечёткое сравнение | | **Database Layer** | SQLite: `artist_settings`, `local_albums` (синхронизация из Navidrome), `external_releases` (кэш MusicBrainz), `notifications_sent` | | **Notifier** | Планировщик уведомлений в Telegram | | **Web UI** | Панель управления отсутствющими релизами | ### Статус реализации - **Scanner Engine** — реализован (только вычисления). Ядро поиска отсутствующих релизов готово: нормализация строк в `internal/normalize`, оценка схожести и движок сравнения (`FindMissingReleases`, `ScanArtist`, `ScanAll`) в `internal/scanner`. Используется настраиваемый `scanner.fuzzy_threshold` (по умолчанию 0.85), игнорируются варианты `(Remastered)`/год/спецсимволы, пропускаются отмеченные как игнорируемые. - **Notifier и Web UI** — пока не реализованы (вне рамок плана сканера). `main.run()` выполняет только вычислительное сканирование и логирует количество отсутствующих релизов; результаты не сохраняются и уведомления не отправляются. ### Лицензия [WTFPL](License.md) — Do What The Fuck You Want To Public License