Commit Graph

124 Commits

Author SHA1 Message Date
nk
bd62016026 fix(stations): Royal Radio — https вместо http (ничего не играло)
royalradio.space по http отдаёт 301 на https, а ExoPlayer по умолчанию НЕ
следует кросс-протокольным редиректам (http→https) — поэтому все 10 каналов
Royal Radio не воспроизводились. Потоки переведены на прямой https (200
audio/mpeg). Прод-БД тоже обновлена (для ICY now-playing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:31:09 +03:00
nk
b2aff51c62 feat(stations): оживить главный «Радио Романтика» в разделе Romantika
В разделе Romantika были только саб-каналы (Piano Covers, Love Songs,
Акустика, Прикосновение, Easy Listening), а главный «Romantika» (711) был
отключён — мёртвый поток srv21.gpmradio (и в offline-ids бэкенда). Включил
главный на рабочем HLS (hls-01-gpm.hostingradio.ru/romantika495) + фирменный
логотип Романтики (применяется ко всем каналам сети). Прод-БД: 711 → online.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:18:21 +03:00
nk
4a9622ca92 feat(stations): добавить Like FM (главный канал) в раздел Like FM
Раздел Like FM был пустой — все тематические каналы «Хиты по годам» (101.ru)
закрыты (404). Like FM теперь вещает как единый канал (на сайте — только
региональные FM-частоты того же эфира). Включил главный Like FM на рабочем
HLS (hls-01-gpm.hostingradio.ru/likefm495, Москва 87.9), группа «Like FM»,
+ фирменный логотип. Бэкенд: 718 помечена online (была в offline-ids).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:05:04 +03:00
nk
8d2c53c441 feat(stations): скрывать украинские станции (ROKS, Kiss FM) для РФ
Radio ROKS и Kiss FM (TavR Media, хосты radioroks.ua / kissfm.ua) недоступны
с российских IP без VPN. Теперь для пользователей из РФ они полностью скрыты
— и сами станции (везде, где используется список), и их чипы-категории.

Страна определяется по IP (api.country.is → ipapi.co; при VPN вернёт страну
выходного узла, тогда станции доступны и НЕ скрываются), с фолбэком на страну
SIM/сети/локали устройства, если IP-сервис недоступен (в РФ часто заблокирован).
Код страны кэшируется (DataStore). Фильтр в GetStationsUseCase (combine со
страной) + чипы в StationsViewModel. id 741 «Радио РОКС» (stream.roks.com) —
российская, под правило не попадает.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 14:46:42 +03:00
nk
4697e27eb4 fix(stations): свечение верхнего ряда не обрезается, уходит под чипы
Грид растянут под чипы (верхний contentPadding = высота чипов), а чипы
вынесены отдельным слоем поверх грида с фоном-градиентом (вверху
непрозрачный — маскирует прокрутку, книзу прозрачный). Свечение играющей
станции из верхнего ряда больше не режется границей и мягко проступает
из-под чипов категорий.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 14:27:41 +03:00
nk
b6c0e92758 fix(stations): бесшовная петля свечения играющей станции
Центр свечения по cy двигался с sin(t*1.3) — некратная гармоника давала
скачок на стыке цикла. Заменено на sin(2t): значения и скорость совпадают
на t=0 и t=2π, петля повторяется ровно и плавно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 14:14:46 +03:00
nk
9268e14cc6 feat(stations): свайп по списку листает чипы + свечение играющей станции
1) Горизонтальный свайп по области списка переключает фильтры-чипы в их
   порядке ([Все]+жанры), выбранный чип автоскроллится в зону видимости.
   Вертикальная прокрутка грида сохраняется.

2) У играющей станции в списке — мягкое радиальное свечение позади обложки,
   которое «гуляет» (двигается центр) и вылезает из-под краёв, + эквалайзер-
   бейдж в углу. Источник активной станции — PlayerController.currentStationId.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 14:12:01 +03:00
nk
603e232dff fix(recordings): шторка записи на весь экран, список треков над навигацией
navigationBarsPadding не применялся в partial-режиме ModalBottomSheet —
список треков налезал на системную навигацию. Включён skipPartiallyExpanded
(как у радио-плеера) + navigationBarsPadding на контенте.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 13:49:08 +03:00
nk
b3912a9dca fix(recordings): список треков не уходит под системную навигацию
У RecordingPlayerSheet не было navigationBarsPadding — нижние строки
списка треков накладывались на кнопки навигации Android. Добавлен отступ
под навбар (вне скролла, чтобы низ всегда был над кнопками).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 13:44:15 +03:00
nk
7df9b62403 feat(recordings): запись HLS-станций (EMG: Европа Плюс и др.)
Раньше запись просто писала тело URL в файл — у HLS это m3u8-плейлист
(текст), а не аудио, поэтому EMG-станции не записывались. Добавлен
HLS-рекордер: резолвит мастер→медиа-плейлист, опрашивает его и докачивает
новые .ts-сегменты, склеивая в файл (валидный MPEG-TS, ExoPlayer играет
и перематывает). На первом проходе пишется только хвост окна — запись
начинается примерно с момента нажатия. Сплошные потоки (ICY) — прежним
путём (recordRaw). Тайм-коды треков работают и для EMG (now-playing с бэка).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 13:39:27 +03:00
nk
fc63814f97 feat(recordings): перемотка записей + тайм-коды треков
1) Перемотка: записи эфира — сырой ADTS-AAC/MP3 без индексов, ExoPlayer
   считал их неперематываемыми (старт всегда с нуля). Включён CBR-seeking
   (DefaultExtractorsFactory.setConstantBitrateSeekingEnabled) — seek работает.

2) Тайм-коды треков: при записи фиксируются смены now-playing с offset от
   начала (модель TrackMarker, колонка markers в recordings, миграция v6,
   захват через NowPlayingRepository — свой поллинг, не зависит от экрана).
   В плеере записи — список «Треки в записи»: тайм-код + название, тап
   переходит к моменту, текущий трек подсвечен.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 13:18:23 +03:00
nk
777f5d5082 fix(favorites): не терять избранное после перезапуска приложения
refreshStations пересоздавал каталог с isFavorite=false, а insertAll
(OnConflictStrategy.REPLACE) затирал строки — отметки «избранное»
пропадали при каждом старте. Перед вставкой считываем текущие id
избранного (getFavoriteIdsOnce) и проставляем их новым записям.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 12:53:55 +03:00
nk
6aa2588641 fix(player): не обрезать низ плеера на телефонах (скролл + компактнее)
Плеер живёт в ModalBottomSheet без скролла. На телефонах с высоким dpi
высоты в dp меньше (480dpi → ~800dp против ~914dp у эмулятора 420dpi),
из-за чего низ — кнопка «Текст песни» — обрезался шторкой и был виден
лишь полоской. Добавлен verticalScroll (низ доступен на любом экране) и
ужата высота (обложка 220→190, крупные отступы), чтобы влезало без скролла.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 12:51:15 +03:00
nk
c77c131a09 fix(player): крупная видимая кнопка «Текст песни» (пилюля с фоном)
На реальном телефоне мелкий TextButton (13sp + иконка 16dp в приглушённом
акценте) почти не виден. Заменён на пилюлю с фоном surface2: иконка 20dp,
текст 15sp medium — читается на физическом экране.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 12:44:44 +03:00
nk
5ffaf9a924 feat(player): переключатель качества звука на экране воспроизведения
Перепроверены все 594 рабочие станции на наличие битрейт-вариантов
потока (скрипт-пробер). У 71 станции найдено по 2–4 качества
(Record-флагманы 96/64/32, zaycev 256/128/48, ВГТРК 192/128/64,
НАШЕ/Орфей/Шансон HQ и др.) — записаны в поле qualities в stations.json.
HLS (EMG) и Love (UID-привязка) корректно пропущены.

Клиент: модель StreamQuality, хранение в Room (миграция v5),
предпочтение битрейта в настройках. На экране плеера — чип текущего
качества (виден только если вариантов ≥2) и шторка «Качество звука»
со ступенями; переключение на лету без сброса now-playing, выбор
запоминается между станциями.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 12:36:47 +03:00
nk
5b256a3421 feat(love): логотипы каналов Love Radio (меньше, с отступами) как обложки
Сгенерены из их SVG на фирменном цвете канала, захостены у нас (/covers/love_*_s.webp),
заданы через StationLogos.byName. Вместо унылых буквенных плиток — фирменные логотипы.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:33:39 +03:00
nk
320cac546b feat(love): воспроизведение Love Radio через сессионный UID + now-playing главного
Потоки Love защищены: клиент берёт UID из их player/config (со своего IP) и
подставляет в n340-поток — играет музыка. LoveStreamResolver + LoveApi. Каталог
переведён на n340. Now-playing главного Love Radio по ICY; саб-каналы трек не
отдают нигде — показываем без трека.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:14:52 +03:00
nk
615e3435e3 feat(stations): клиент скрывает оффлайн-станции с бэкенда (системно)
При обновлении каталога тянем GET /stations/offline-ids и удаляем эти станции
из локальной БД. Мёртвые плитки теперь пропадают сами (бэк их метит health-check'ом),
без пересборки приложения. Фолбэк на статичный enabled, если бэк недоступен.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 18:04:35 +03:00
nk
4c4c6e05d8 chore(stations): отключить 67 мёртвых станций (потоки не отвечают)
Свип по всем потокам (корректная проверка: живой = пришли заголовки 200,
мёртвый = ошибка/4xx/5xx/нет ответа). Помечены enabled=false. Активных 595/697.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:48:30 +03:00
nk
4a45cb575e chore(stations): отключить мёртвые каналы Европы Плюс (Acoustic, ResiDance)
Потоки не отвечают (000/404), meta now-playing пуст — каналы не вещают.
enabled=false → скрыты в приложении.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:05:00 +03:00
nk
1ef60b6053 fix(now-playing): матч текущего трека по id станции, а не по имени
Станции с одинаковым именем в разных сетях (напр. «Deep» у Record и DFM)
показывали один и тот же трек — матч был по lowercase-имени. Каталожный id
(== station.id) уникален и совпадает со stationId в /now-playing, поэтому
матчим по id. Убран весь by-name путь (репозиторий, плеер, карточки).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:54:24 +03:00
nk
eeceb754ea feat(stations): актуальные emgsound HLS-потоки линейки Европы Плюс
8 каналов EP (Europa Plus/Top 40/New/Party/Urban/Acoustic/ResiDance/Fresh)
переведены на рабочие emgsound HLS — играют + получают now-playing/обложки.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 15:47:45 +03:00
nk
b93bec028e feat(player): показывать название станции под «В ЭФИРЕ» над обложкой
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:55:48 +03:00
nk
72ecbae866 fix(player): матч now-playing по имени станции (обложки DFM в плеере)
Плеер искал now-playing по числовому id станции, а у локальных станций (DFM)
id не совпадает с каталожным → API-путь с обложкой не срабатывал, плеер падал
на ICY из потока (без обложки). Теперь getNowPlaying матчит по id, затем по
имени станции (как карточки). DFM-обложки появляются и в плеере.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:36:39 +03:00
nk
77772789bb fix(ui): подпись играющего трека на карточке станции даже без обложки трека
Раньше now-track (трек/исполнитель + обложка) показывался ТОЛЬКО при наличии
обложки трека — поэтому DFM-станции без обогащённой обложки оставались пустой
плиткой. Теперь: если трек известен — всегда показываем подпись, а фоном берём
обложку трека → лого станции → плитку. DFM работает как Record.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:16:41 +03:00
nk
99503fc77a feat(charts): фильтр по жанру + жанр/стиль/лейбл/год на детальной трека
Подтягиваем обогащённые данные с бэкенда (Discogs): genre/styles/label/year
в чартах и детальной странице.

- ChartEntry/TrackStats + DTO: добавлены genre/styles/label/year
- RadiolaApi: getCharts(?genre=), новый getGenres()
- ChartsViewModel: состояние выбранного жанра + список жанров, перезагрузка
- ChartsScreen: ряд чипов-фильтров по жанру (Все + жанры),
  жанр/стили чипами и «Лейбл · Год» на детальной
- убран демо-fallback (SAMPLE_CHARTS) — бэкенд живой

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:55:35 +03:00
nk
b0c3dae20a feat(stations): локальные обложки Comedy FM/Spa/StandUp/Женский StandUp
вшиты в ресурсы (res/drawable), привязаны по имени станции (приоритет над
логотипом по домену). Загрузка через android.resource:// в Coil.
2026-06-03 12:35:03 +03:00
nk
5e22db5571 feat(stations): кураторские логотипы по домену сайта (Comedy Radio)
StationLogos: карта домен -> URL логотипа для сетей без своего API обложек.
Comedy Radio (Comedy FM/Club/Spa, comedy-radio.ru) -> официальный apple-touch
логотип. Расширяемо по сетям.
2026-06-03 12:26:11 +03:00
nk
ee689ce380 feat(stations): обложка текущего трека на карточке станции + подпись
Для станций без своей обложки (и для Radio Record — единый стиль) карточка
показывает обложку играющего трека с тёмным градиентом и подписью трек/исполнитель.
Источник — /now-playing (теперь с name станции), матч по имени, обновление 20с.
Приоритет: трек -> логотип станции -> фирменная плитка.
2026-06-03 12:18:19 +03:00
nk
9d115b148e fix(lyrics): краш при открытии текста — Unspecified lineHeight
bodyLarge.lineHeight не задан (Unspecified), умножение на 1.4f бросало
IllegalArgumentException (Cannot perform operation for Unspecified type).
Задан конкретный lineHeight = 22.sp.
2026-06-03 11:55:31 +03:00
nk
ba32973beb feat(lyrics): тексты песен внутри приложения через LRCLIB
- LrcLibApi (api/get + api/search, User-Agent), DI @Named(lrclib) Retrofit
- LyricsRepository.fetchLyrics -> LyricsResult (plain/synced/instrumental)
- LyricsViewModel + LyricsSheet (загрузка/инструментал/найдено/не найдено),
  прокрутка + атрибуция LRCLIB
- кнопка «Текст песни» открывает встроенный экран (плеер + деталь трека чартов),
  вместо ссылки в браузере
2026-06-03 11:47:00 +03:00
nk
5fd97d27fd fix(stations): обложки Record только для Record-станций + своя плитка остальным
- сети, отличные от Radio Record (DFM, HitFM и др.), больше не получают
  обложки Radio Record (обогащение Record API гейтится по source=record)
- станции без обложки рисуют свою фирменную плитку: цвет по названию + инициалы
  (вместо общего значка/чужой обложки)
2026-06-03 11:36:24 +03:00
nk
32e5108d98 fix(stations): подтягивать обложки/потоки Record по названию станции
Локальные станции (assets/stations.json, id 1,2,3...) обогащались данными
Record только по id, но id Record-каталога другие (15016...) и prefix в
ассетах нет — поэтому совпадений почти не было и обложки не грузились.
Добавлен фолбэк-матч по названию станции (стабильный общий ключ).
2026-06-03 11:22:57 +03:00
nk
a50a108f63 fix(ui): иконочный таб-бар, заголовок станций, ровные кнопки плеера, рабочая ссылка на текст
- таб-бар только иконки (6 разделов не помещались с подписями)
- «Откройте радио» -> «Выберите радиостанцию»
- кнопки плеера (лайк/prev/next/запись) единого размера 24/48, ряд SpaceBetween
  (кнопка записи больше не обрезается и не выбивается размером)
- текст песни: Musixmatch резал соединение -> веб-поиск трека (открывается)
2026-06-03 11:15:29 +03:00
nk
fc9b23f62c fix(player): now-playing с нашего бэкенда вместо сырого Record-эндпоинта
Record /stations/now использует id now-слотов, не совпадающие с id каталога,
поэтому клиент не находил трек по station.id (трек/обложка не показывались).
Теперь берём GET /now-playing с нашего бэка (корректный маппинг recordSync,
ключ = id станции) -> плеер показывает название трека и обложку.
2026-06-03 10:59:59 +03:00
nk
eca0c49ad4 fix(ui): тёмный сплэш с фирменной иконкой вместо белого экрана
- Theme.Radiola -> тёмная (windowBackground #0C1410), прозрачные системные бары
- Theme.Radiola.Splash (core-splashscreen): фон #0C1410 + иконка приложения
- installSplashScreen() в MainActivity; тема сплэша на launcher-активити
2026-06-03 00:27:29 +03:00
nk
e190444577 feat: фирменная иконка приложения + внутренний плеер записей
- адаптивная иконка лаунчера: градиентный фон (C2F25B->6FA53C) + монограмма R
  (foreground + monochrome для тем Android 13), манифест -> @mipmap
- воспроизведение своих записей ВНУТРИ приложения вместо внешнего плеера:
  RecordingPlaybackController (отдельный ExoPlayer, останавливает радио),
  RecordingPlayerSheet с перемоткой (Slider), play/pause, +/-15с, таймеры
2026-06-03 00:13:12 +03:00
nk
d0e5f4e8c5 feat(charts): раздел «Чарты» (клиент) + детальная страница трека с графиком
- вкладка «Чарты» в навигации; экран: периоды (День/Неделя/Месяц/Всё),
  ранжированный список треков (ранг, обложка, проигрывания, тренд)
- детальная карточка трека: метрики, график популярности (Canvas), лайк,
  кнопки музыкальных сервисов, кнопка «Текст песни» (ссылка на лицензированный
  Musixmatch — полный текст не встраиваем, авторское право)
- ChartsRepository/LyricsRepository + эндпоинты charts/* в RadiolaApi (DTO)
- превью-данные пока бэкенд не отдаёт charts (помечено TODO)
2026-06-02 23:24:42 +03:00
nk
a4af72a6e6 polish(ui): плавные обложки, бегущая строка длинных названий, тактильный отклик
- Coil crossfade для всех обложек (Images.crossfadeModel) — без «моргания» при загрузке
- basicMarquee для длинных названий трека (плеер и мини-плеер) вместо обрезки
- haptic feedback на play/pause и добавление в избранное (плеер, мини-плеер, карточка)
2026-06-02 22:55:18 +03:00
nk
310d6c3177 fix(player): отображение трека и обложки — объединение REST и socket now-playing
REST-поллинг (refreshNowPlaying -> api.getNowPlaying, 200 OK) писал данные в
_nowPlaying, который нигде не читался; getNowPlaying() брал только сокет (пустой).
Теперь getNowPlaying/getAllNowPlaying объединяют оба источника (socket ?: REST),
поэтому название трека, обложка и deep-link сервисов работают.
2026-06-02 22:55:18 +03:00
nk
cefd0be009 fix(ui): отступы под системную навигацию + подписи сервисов + краш навбара
- навбар и мини-плеер: navigationBarsPadding — не налезают на системные кнопки
- плеер: navigationBarsPadding снизу, ряд сервисов не уходит под системную панель
- подписи сервисов без обрезки слов (Яндекс / ВК Музыка / YT Music и т.д.)
- фикс NPE при холодном старте: навбар обращается к NavDestinations напрямую,
  не к companion-списку (порядок инициализации Kotlin)
2026-06-02 22:55:17 +03:00
nk
af13272852 fix(ui): единый скролл на экране станций + всегда видимый навбар
- StationsScreen: закреплённые заголовок/поиск/жанры, одна прокручиваемая
  сетка станций; поиск и фильтры больше не исчезают при пустом результате
  (+ кнопка «Сбросить фильтры»)
- таб-бар показывается без обязательного входа (скрыт только на экране входа)
- старт сразу со «Станций» — авторизация необязательна, вход из Настроек
2026-06-02 22:55:17 +03:00
nk
220d1d6fa1 feat(ui): мягкие переходы между экранами (fade + лёгкий slide) 2026-06-02 22:55:17 +03:00
nk
f604ad42e8 feat(ui): рестайл всех экранов + плеер + официальные mono-логотипы сервисов
- экраны (Станции/Избранное/История/Записи/Настройки/Вход): двухцветные
  заголовки, токены темы, EmptyState, анимации появления и перестановки
- AuthScreen: брендовый локап (AppMark + RadiolaWordmark)
- PlayerBottomSheet: живой эфир — LiveEqualizer вместо перемотки,
  Crossfade трека и play/pause, pressScale, анимация избранного/записи
- кнопки музыкальных сервисов: монохромные официальные логотипы
  (vector drawable из Simple Icons CC0 + Yandex), маппинг serviceLogoRes
- DeeplinkBottomSheet: сетка сервисов с логотипами
2026-06-02 22:55:17 +03:00
nk
d652dc399a feat(ui): рестайл общих компонентов под дизайн-систему
- StationCard: обложка/иконка-заглушка, анимированное сердечко, pressScale
- MiniPlayer: elevated-бар, метка «СЕЙЧАС ИГРАЕТ», Crossfade play/pause
- SearchBar: surface-поле, акцентный курсор, скругление 14
- FilterChips: акцентный активный чип с анимацией цвета
- EmptyState: иконка-плашка + текст
- TrackListItem: thumb-заглушка, pressScale
2026-06-02 22:55:17 +03:00
nk
ae406554de feat(ui): дизайн-система radiOLA — палитра, тема, типографика, бренд, motion, pill таб-бар
- цветовые токены тёмно-зелёной темы + RadiolaColors (CompositionLocal)
- darkColorScheme + всегда тёмная тема, фирменные shapes
- типографика с весами/размерами под макет
- Brand: AppMark (градиентный R), RadiolaWordmark, MonoMark
- Motion: спеки движения, pressScale, живой эквалайзер
- pill-таб-бар с анимированной активной вкладкой
2026-06-02 22:55:17 +03:00
nk
2f686bcc57 chore: add .gitignore and remove build artifacts from index 2026-06-02 22:50:00 +03:00
nk
bcb999ace9 feat: WebSocket now-playing via Socket.IO from backend 2026-06-02 19:52:15 +03:00
nk
a83672b455 feat: auth screen with auto-redirect, sync favorites/history with backend 2026-06-02 19:12:07 +03:00
nk
d4adb1e7be fix: add launcher icons and update manifest references 2026-06-01 13:35:28 +03:00