Initial commit: Aoi (Аой-тян) — Matrix notifier for Navidrome and discovery-playlist

- aoi.py: poller for Navidrome (main + anime libraries), discovery playlists, release watch for liked/rated artists
- Last.fm enrichment (bio, tags); Bandcamp search links
- config.example.json: safe template; config.json gitignored
- deploy/aoi.service: systemd unit (production)
- assets/banner.png + aoi-avatar.png: persona banner + bot avatar
- Russian README in line with sibling bots (rada/watcher)
This commit is contained in:
Rinka Makise-Okabe 2026-04-28 20:15:50 +03:00
commit 5fa857b9cc
8 changed files with 1155 additions and 0 deletions

160
README.md Normal file
View file

@ -0,0 +1,160 @@
<p align="center">
<img src="assets/banner.png" alt="Aoi banner" width="40%">
</p>
# Aoi
**Aoi** (Аой-тян) — домашний Matrix-бот для музыкальной библиотеки. Она следит за Navidrome и discovery-playlist, аккуратно докладывает о новых альбомах, свежих Discovery-плейлистах и предстоящих релизах любимых артистов, обогащая карточки данными Last.fm и ссылками на внешние источники.
## Что умеет
| Блок | Что происходит |
| --- | --- |
| Navidrome albums | Поллинг библиотек `main` и `anime` — новые альбомы превращаются в карточки с обложкой, описанием, тегами и рейтингом. |
| Discovery playlists | Свежесгенерированные плейлисты discovery-playlist (имя содержит «Discovery») приходят в Matrix отдельным постом. |
| Release watch | Аналитика по любимым/высоко оцененным артистам: анонсы и фактические релизы из дискографии, отслеживаемой discovery-playlist. |
| Rich-описания | Last.fm-биография, теги, обложка из `album.getInfo`, ссылки на Last.fm и поиск Bandcamp. |
| Baseline | На первом запуске можно зафиксировать всё уже существующее как «уже видела», чтобы не получить спам с историей. |
| State & dedupe | SQLite хранит увиденные альбомы, плейлисты и релизы — повторов не будет. |
## Как устроена логика
Aoi не делает запросов к LLM и не пытается «угадывать» — она опирается на конкретные источники и кеширует увиденное:
1. По расписанию опрашивает Navidrome и discovery-playlist (раздельные интервалы для альбомов, плейлистов и релизов).
2. Сравнивает с локальным state и забирает только новые сущности.
3. Обогащает карточки Last.fm-данными при наличии ключа.
4. Шлёт карточку в Matrix-комнату с обложкой, описанием и ссылками.
5. Помечает сущность как обработанную в SQLite.
Каждый источник работает независимо, так что падение Navidrome не валит discovery, и наоборот.
## Сообщения в Matrix
Карточка нового альбома выглядит примерно так:
```text
🎧 Новый альбом в Navidrome
Artist — Album Title (2026)
━━ ОПИСАНИЕ ━━
Краткая биография/описание альбома из Last.fm…
━━ ТЕГИ ━━
shoegaze · indie · dream-pop
🔗 Last.fm: https://www.last.fm/music/Artist/Album
🔗 Bandcamp: https://bandcamp.com/search?q=Artist+Album
```
Discovery-плейлисты приходят отдельной карточкой со списком треков, release watch — отдельной с пометкой типа релиза (`announced`, `released`).
## Файлы проекта
| Файл | Назначение |
| --- | --- |
| `aoi.py` | Основной сервис. |
| `config.example.json` | Безопасный пример конфигурации. |
| `config.json` | Локальная конфигурация с секретами, не коммитится. |
| `requirements.txt` | Python-зависимости. |
| `deploy/aoi.service` | systemd unit для production. |
| `assets/banner.png` | Баннер README. |
| `aoi.db` | SQLite-состояние, не коммитится. |
| `aoi.log` | Лог сервиса, не коммитится. |
## Конфигурация
Создать конфиг из примера:
```bash
cp config.example.json config.json
```
Заполнить:
- `matrix.homeserver`, `matrix.room_id`, `matrix.access_token`, `matrix.user_id`;
- `bot.name` (по умолчанию `Аой-тян`) и `bot.avatar_path` для Matrix-профиля;
- `navidrome.url`, `navidrome.username`, `navidrome.password`, идентификаторы библиотек;
- `discovery.db_path` — путь к SQLite базе discovery-playlist;
- `metadata.lastfm_api_key` — ключ Last.fm для био и тегов;
- `polling.*` — интервалы опроса источников;
- `polling.baseline_existing_on_first_run``true` на первом запуске, чтобы не спамить историей.
Production-путь:
```text
/storage/scripts/aoi
```
## Установка
В production Aoi использует виртуальное окружение Watcher (общие зависимости):
```bash
cd /storage/scripts/watcher
python3 -m venv .venv
. .venv/bin/activate
pip install -r /storage/scripts/aoi/requirements.txt
```
Можно завести отдельный venv — тогда обновить `deploy/aoi.service`.
## Запуск
```bash
/storage/scripts/watcher/.venv/bin/python /storage/scripts/aoi/aoi.py
```
Healthcheck:
```bash
curl -fsS http://127.0.0.1:18323/healthz
```
Ожидаемый ответ:
```json
{"ok":true}
```
## systemd
Unit хранится в репозитории:
```text
deploy/aoi.service
```
Установка или обновление:
```bash
sudo cp /storage/scripts/aoi/deploy/aoi.service /etc/systemd/system/aoi.service
sudo systemctl daemon-reload
sudo systemctl enable aoi.service
sudo systemctl restart aoi.service
```
Операции:
```bash
sudo systemctl restart aoi.service
systemctl --no-pager -l status aoi.service
journalctl -u aoi.service -f
tail -f /storage/scripts/aoi/aoi.log
```
## Ручные команды
```bash
curl -X POST http://127.0.0.1:18323/run/navidrome-albums
curl -X POST http://127.0.0.1:18323/run/discovery-playlists
curl -X POST http://127.0.0.1:18323/run/release-watch
```
## Что не коммитить
- `config.json`
- `*.db`
- `*.log`
- `.venv/`
- `__pycache__/`