Files
NaviWatcher/README.md
Vladimir Zagainov 47d4ec4e32 fix: address code review findings
- Fix notifications_sent PK: changed from (rgid, sent_at) to rgid-only PK
  to prevent duplicate RGID rows across seconds. Use INSERT OR REPLACE
  instead of INSERT OR IGNORE for true idempotency.
- Add foreign key constraints to DDL (artist_id references artist_settings,
  rgid references external_releases) per specification.
- Enable PRAGMA foreign_keys=ON and PRAGMA busy_timeout=5000 for concurrent
  access safety.
- Fix GetNotificationSentAt query: add ORDER BY sent_at DESC LIMIT 1 for
  deterministic results.
- Fix config test: change YAML key from 'chat' to 'chat_id' to match struct
  tag, add ChatID assertion.
- Fix migration tracking test: correct error message from "expected 4" to
  "expected 3".
- Remove dead code in TestLoadConfig_InvalidPort: eliminate unused YAML
  template and remove port 0 case (valid, not invalid).
- Remove unused path parameter from buildConfigWithPort helper.
- Remove pointless 100ms sleep in run() and unused time import.
- Remove tautological TestDefaultConfigPath test.
- Update README.md: Go version 1.21+ to 1.25+, placeholder passwords to
  CHANGE_ME.
- Update config.yaml.example: placeholder passwords to CHANGE_ME.
- Update all database tests to insert parent rows first for FK satisfaction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-20 11:07:28 +03:00

218 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
### 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).
- **Configurable filters** — ignore bootlegs, singles, compilations, live albums, remixes, soundtracks per artist or globally.
- **MusicBrainz caching** — 24-hour TTL cache to minimize API calls and respect rate limits (1 req/sec).
- **Telegram notifications** — daily summary messages with links to the web UI.
- **Web dashboard** — 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`
### 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
ignore_bootlegs: true
include_compilations: true
```
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 for settings, cache, and state |
| **Notifier** | Scheduled Telegram notifications |
| **Web UI** | Dashboard for browsing and managing missing releases |
### 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-издания, год в скобках, спецсимволы).
- **Гибкие фильтры** — игнорирование бутлегов, синглов, компиляций, лайвов, ремиксаундов — глобально или для конкретного артиста.
- **Кэширование 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
ignore_bootlegs: true
include_compilations: true
```
Полную справку по конфигурации и архитектуру см. в [docs/Specification.md](docs/Specification.md).
### Архитектура
| Модуль | Назначение |
|--------|------------|
| **Navidrome Client** | Взаимодействие с Subsonic API v1.16.1 (токенная аутентификация) |
| **MusicBrainz Provider** | Загрузка дискографий с кэшированием и rate limiting |
| **Scanner Engine** | Нормализация строк и нечёткое сравнение |
| **Database Layer** | Хранение настроек, кэша и состояния в SQLite |
| **Notifier** | Планировщик уведомлений в Telegram |
| **Web UI** | Панель управления отсутствющими релизами |
### Лицензия
[WTFPL](License.md) — Do What The Fuck You Want To Public License