Обложка ICY-станций (DFM) теперь подтягивается из обогащённого трека по normKey
в момент ответа API, а не записи now_playing — появляется сразу после обогащения,
без ожидания следующего опроса станции (~6 мин).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ICY-станции (DFM и пр.) теперь полноценно «как Record»:
- ICY-поллер вызывает recordPlay → треки идут в чарты и обогащаются Discogs,
откуда берётся обложка (раньше now_playing писался напрямую, мимо чартов)
- обложка now-playing: если источник не дал (ICY всегда null) — подставляем
обложку обогащённого трека из нашей БД по normKey (NowPlayingService.resolveCover)
- ротация курсора по всем станциям (окно 70) вместо первых 50 по кругу —
раньше 363 из 413 станций не опрашивались
- общий NowPlayingService.ingest для Record и ICY (дедуп логики)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
В базе ~22к треков — прежние 30/10мин слишком медленно. Батч подобран под
троттлинг очереди (~50 запросов/мин, под лимитом Discogs 60/мин), пропускаем
тик если прошлый батч ещё не дожёван.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
При первом появлении трека подтягиваем жанр/стиль/лейбл/год из Discogs
и сохраняем обложку в едином формате WebP 500x500 у себя (/covers). Дальше
пользователю отдаём только из своей БД — внешние сервисы в рантайме не дёргаем.
- Track: +genre/styles/label/year/discogsId/enrichStatus (миграция)
- EnrichModule: DiscogsService (поиск), CoverStorageService (sharp->webp),
EnrichmentService (очередь с троттлингом + бэкафилл-крон каждые 10 мин)
- charts: фильтр чартов по жанру (?genre=), GET /charts/genres,
жанр/стиль/лейбл/год в выдаче чарта и детальной странице
- main: раздача /covers статикой; docker: volume covers_data + env
DISCOGS_TOKEN/PUBLIC_BASE_URL/COVERS_DIR
- убран MusicBrainz-фолбэк (заменён Discogs)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Клиенту нужен now-playing с правильным маппингом id (Record now-эндпоинт
использует id now-слотов, не каталога). Отдаём текущие треки по станциям
с stationId = catalog id, чтобы клиент сопоставлял по station.id.
Record API при эфире шоу/джингла возвращает название станции/сети как трек
(пустой artist/song или совпадение с названием станции). Такие записи
накапливали проигрывания и забивали топ. Теперь recordPlay их пропускает
(кэш названий станций).
- модели Track / TrackPlay / TrackLike (+ миграция add_charts)
- сбор проигрываний в now-playing-поллере: при смене трека на станции
пишется TrackPlay (нормализация artist+song -> Track), fire-and-forget
обогащение через MusicBrainz (album/releaseDate)
- ChartsModule: GET /charts/tracks (период day/week/month/all, ранг, тренд,
проигрывания, станции, лайки), GET /charts/tracks/:id (метрики, таймлайны
популярности и лайков по дням, топ станций, isLiked), POST/DELETE like
- OptionalAuthGuard для публичной детальной страницы с опц. userId