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>
This commit is contained in:
18
app/src/main/java/com/radiola/domain/model/MusicGenres.kt
Normal file
18
app/src/main/java/com/radiola/domain/model/MusicGenres.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.radiola.domain.model
|
||||
|
||||
/**
|
||||
* Клиентский признак «музыкальная ли станция». На разговорных/юмористических/
|
||||
* новостных станциях распознавать нечего — кнопку Shazam там не показываем.
|
||||
* Список синхронизирован с backend (common/station-classification.ts).
|
||||
*/
|
||||
object MusicGenres {
|
||||
private val NON_MUSIC = setOf(
|
||||
"Станция Кассиопея", "Юмор ФМ", "Рассказы", "Радио Вера",
|
||||
"Comedy Radio", "ВГТРК", "Старое радио",
|
||||
)
|
||||
|
||||
fun isMusicStation(genre: String?): Boolean {
|
||||
if (genre.isNullOrBlank()) return true
|
||||
return genre.trim() !in NON_MUSIC
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.radiola.domain.repository
|
||||
|
||||
import com.radiola.domain.model.Track
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface RecognizedTrackRepository {
|
||||
fun getHistory(): Flow<List<Track>>
|
||||
suspend fun addTrack(track: Track)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.radiola.domain.repository
|
||||
|
||||
import com.radiola.domain.model.Track
|
||||
|
||||
sealed interface RecognizeResult {
|
||||
data class Found(val track: Track) : RecognizeResult
|
||||
data object NotFound : RecognizeResult
|
||||
data class Error(val message: String) : RecognizeResult
|
||||
}
|
||||
|
||||
interface ShazamRepository {
|
||||
suspend fun recognize(stationId: Int, stationName: String): RecognizeResult
|
||||
}
|
||||
Reference in New Issue
Block a user