Commit Graph

13 Commits

Author SHA1 Message Date
nk
c0ee47b699 fix(app): таймаут 30с для запроса распознавания Shazam
Бэкенд-распознавание асинхронное (чанк аудио + поллинг ~до 18с) — точечно
поднимаем readTimeout до 30с только для пути shazam/recognize (базовый 10с мал).
Bump backend submodule (двухстадийный флоу shazam-api.com).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 18:45:08 +03:00
nk
69682268f3 feat(app): кнопка «Распознать трек» (Shazam) + история распознанных
- кнопка распознавания в плеере: видна только на музыкальных станциях без
  метаданных эфира (track == null), показывает спиннер и результат через Toast
- распознанный трек отображается в плеере и пишется в ОТДЕЛЬНУЮ историю
  распознанных (не дублируется в историю эфирных треков — гейт по ключу)
- экран Истории: переключатель «Треки эфира | Распознанные», два списка
- Room: таблица recognized_track (миграция 7→8), DAO/репозиторий
- ShazamRepository → POST /shazam/recognize/{stationId}, маппинг 503/400 в текст
- MusicGenres.isMusicStation — клиентский гейт (синхронизирован с бэкендом)
- bump backend submodule (модуль shazam)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 18:38:17 +03:00
nk
84c2b33473 perf(android): ленивый плеер записей, O(n) merge каталога, @Immutable, лог только в debug
- RecordingPlaybackController: ExoPlayer создаётся лениво (на первый play) и
  освобождается в stop() — раньше второй плеер висел в памяти всю сессию у каждого.
  Поллер позиции 500мс крутится только во время игры (был вечный 2 Гц main-loop).
- StationRepositoryImpl.refreshStations: merge каталога O(n) через apiById/apiByName
  индексы вместо .find на каждую станцию (было O(n²) ~700×700 на холодном старте).
  Убраны verbose Log.d-трейсы (оставлен Log.e/.w на ошибки).
- Track/Station/StreamQuality помечены @Immutable — read-only модели, иначе
  списки tags/qualities делали класс нестабильным → лишние рекомпозиции списков.
- HttpLoggingInterceptor только при BuildConfig.DEBUG (включён buildConfig feature):
  в релизе нет оверхеда на каждый запрос и утечки URL в logcat.
2026-06-06 17:13:48 +03:00
nk
861b0e2b8f feat: будильник с радиостанцией + выбор битрейта по умолчанию
Будильник (Settings → Будильник): несколько будильников, время, станция, дни недели,
fade-in пробуждения. AlarmManager.setAlarmClock (вне doze) + фолбэк, BootReceiver
перепланирует после перезагрузки, AlarmReceiver→PlayerService (foreground) →
PlayerController.startAlarmPlayback (нарастание громкости). Room: AlarmEntity/Dao, БД v7.
Выбор битрейта по умолчанию в Settings (Авто/Эконом/Стандарт/Высокое) → preferredBitrate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:25:42 +03:00
nk
4a33aa6fb5 feat(covers): клиентское обогащение обложек через iTunes (обход бана сервера)
Серверный IP забанен Apple (iTunes search 429), а Deezer из РФ пуст — обложки
перестали наливаться. Теперь iTunes-поиск делает КЛИЕНТ (его IP не забанен):
для now-playing-треков без обложки ищет арт в iTunes и шлёт ССЫЛКУ на наш
бэкенд (POST /covers/submit), сервер качает её (CDN из РФ доступен) и кладёт
WebP — дальше обложка приходит всем через /now-playing. Дедуп по треку +
троттлинг 1.5с (CoverEnrichmentManager). Сервер: host-whitelist (SSRF),
идемпотентность (first-write-wins).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 16:59:32 +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
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
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
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
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
d0e5f4e8c5 feat(charts): раздел «Чарты» (клиент) + детальная страница трека с графиком
- вкладка «Чарты» в навигации; экран: периоды (День/Неделя/Месяц/Всё),
  ранжированный список треков (ранг, обложка, проигрывания, тренд)
- детальная карточка трека: метрики, график популярности (Canvas), лайк,
  кнопки музыкальных сервисов, кнопка «Текст песни» (ссылка на лицензированный
  Musixmatch — полный текст не встраиваем, авторское право)
- ChartsRepository/LyricsRepository + эндпоинты charts/* в RadiolaApi (DTO)
- превью-данные пока бэкенд не отдаёт charts (помечено TODO)
2026-06-02 23:24:42 +03:00
nk
a83672b455 feat: auth screen with auto-redirect, sync favorites/history with backend 2026-06-02 19:12:07 +03:00
nk
9d68459df6 feat(di): add Hilt AppModule with Retrofit, Room and repository bindings 2026-06-01 12:19:33 +03:00