16 Commits

Author SHA1 Message Date
nk
a3434ed894 perf(backend): индексы, кэш чартов, пропуск upsert, фикс N+1 обогащения
- track_plays(played_at,track_id,station_id) покрывающий + tracks(first_seen_at) WHERE
  pending частичный (применены CONCURRENTLY на проде + миграция idempotent)
- ChartsService.getTopTracks: in-memory TTL-кэш 90с по (period,genre,limit) → детальная
  страница и параллельные запросы не пересчитывают тяжёлые агрегации
- NowPlayingService.ingest: не пишем now_playing и не шлём сокет, если трек не изменился
  (было ~20k бесполезных upsert/час)
- enrichNowPlaying: вместо N+1 (300 upsert/мин) — один batched findMany по normKey

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:20:25 +03:00
nk
426fd0e197 feat(now-playing): Новое Радио BY — now-playing с правильной кодировкой + Wake Up
5 мейнов live.novoeradio.by отдают ICY, но кириллица в windows-1251 (общий
поллер читал UTF-8 → каша). NovoeByNowPlayingService (@Interval 30с): свой ICY-
ридер с декодом UTF-8→fallback 1251, джинглы без трека пропускаем, обложка через
обогащение. Исключён из общего ICY-поллера. Маунт Wake Up исправлен
(wakeupshow→wakeup, был 404/offline) в seed и прод-БД.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 21:20:06 +03:00
nk
cb0e401854 feat(now-playing): ГУСЬ (radiogoose) — now-playing + обложки, починка потоков
Сеть ГУСЬ (16 каналов) на AzuraCast (radiogoose.ru). Потоки в каталоге были
многострочными (url1\nurl2) → клиент рвал воспроизведение, health-check метил
offline, станции скрывались. Почищены на канонический https://radiogoose.ru/listen/{slug}/play.
GooseNowPlayingService (@Interval 30с): AzuraCast API /api/nowplaying/{slug} →
now_playing.song {artist,title,art}, ingest + isOnline=true. Исключён из ICY-поллера.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 20:22:28 +03:00
nk
fd26e4df57 chore(stations): удалены мёртвые каналы Зайцева New year/Hvilya
Потоки zaycevfm.cdnvideo.ru мертвы (000), станции оффлайн. Удалены из seed
и из прод-БД (station_id 399, 402).
2026-06-05 20:07:20 +03:00
nk
35f9a2b7cc chore(stations): Royal Radio — https вместо http (301-редирект)
10 каналов royalradio.space переведены на https (http отдавал 301→https,
ExoPlayer не шёл по кросс-протокольному редиректу). Прод-БД обновлена точечно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:31:13 +03:00
nk
c2e941f1c3 chore(stations): Romantika (711) — рабочий HLS вместо мёртвого srv21
Главный Радио Романтика был в offline-ids (мёртвый srv21.gpmradio). Обновлён
на hls-01-gpm.hostingradio.ru/romantika495. Прод-БД поправлена точечно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:18:25 +03:00
nk
326bbbc0ee chore(stations): Like FM (718) — рабочий HLS, группа Like FM
Старый поток srv21.gpmradio мёртв (станция была в offline-ids). Обновлён на
hls-01-gpm.hostingradio.ru/likefm495 (главный Like FM), groupId 27. Прод-БД
обновлена точечно (без полного reseed, чтобы не сбросить жанры now-playing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:05:09 +03:00
nk
d46020bd37 chore(stations): Love Radio -> потоки n340 (синхр. с клиентом)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:14:26 +03:00
nk
c2f638e1a1 chore(stations): синхр. — отключены 67 мёртвых станций
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:48:45 +03:00
nk
982c42cdf2 chore(stations): синхр. — отключены мёртвые EP-каналы Acoustic/ResiDance
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:05:15 +03:00
nk
3049b1ec89 chore(stations): актуальные emgsound HLS-потоки для 8 каналов Европы Плюс
Europa Plus/Top 40/New/Party/Urban/Acoustic/ResiDance/Fresh переведены со старых
потоков на emgsound HLS — теперь их ловит EMG-поллер (now-playing + обложки).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:47:27 +03:00
nk
0efba7c691 feat(enrich): обогащение треков через Discogs + самохостинг обложек (WebP)
При первом появлении трека подтягиваем жанр/стиль/лейбл/год из 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>
2026-06-03 13:28:22 +03:00
nk
38fe92d695 feat(charts): сбор статистики проигрываний и API чартов
- модели 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
2026-06-02 23:40:13 +03:00
nk
d082a1ce07 chore: add debug logs to now-playing polling 2026-06-02 19:40:19 +03:00
nk
7823b17d55 feat: now-playing polling from Record API with station mapping and WebSocket broadcast 2026-06-02 19:31:48 +03:00
nk
8aadd62e3c feat: bootstrap NestJS backend with auth, stations, users, health-check, now-playing 2026-06-02 13:54:00 +03:00