aoi/README.md
Rinka Makise-Okabe 5fa857b9cc 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)
2026-04-28 20:15:50 +03:00

160 lines
6.3 KiB
Markdown
Raw Permalink 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.

<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__/`