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:
@@ -0,0 +1,34 @@
|
||||
package com.radiola.data.repository
|
||||
|
||||
import com.radiola.data.local.AppDatabase
|
||||
import com.radiola.data.local.entity.RecognizedTrackEntity
|
||||
import com.radiola.domain.model.Track
|
||||
import com.radiola.domain.repository.RecognizedTrackRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
class RecognizedTrackRepositoryImpl @Inject constructor(
|
||||
private val db: AppDatabase
|
||||
) : RecognizedTrackRepository {
|
||||
|
||||
override fun getHistory(): Flow<List<Track>> =
|
||||
db.recognizedTrackDao().getAll().map { list -> list.map { it.toDomain() } }
|
||||
|
||||
override suspend fun addTrack(track: Track) {
|
||||
db.recognizedTrackDao().insert(
|
||||
RecognizedTrackEntity(
|
||||
artist = track.artist,
|
||||
song = track.song,
|
||||
stationName = track.stationName,
|
||||
coverUrl = track.coverUrl,
|
||||
timestamp = System.currentTimeMillis()
|
||||
)
|
||||
)
|
||||
db.recognizedTrackDao().cleanupOld()
|
||||
}
|
||||
|
||||
private fun RecognizedTrackEntity.toDomain(): Track = Track(
|
||||
artist = artist, song = song, coverUrl = coverUrl, stationName = stationName
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.radiola.data.repository
|
||||
|
||||
import com.radiola.data.remote.RadiolaApi
|
||||
import com.radiola.domain.model.Track
|
||||
import com.radiola.domain.repository.RecognizeResult
|
||||
import com.radiola.domain.repository.ShazamRepository
|
||||
import retrofit2.HttpException
|
||||
import javax.inject.Inject
|
||||
|
||||
class ShazamRepositoryImpl @Inject constructor(
|
||||
private val api: RadiolaApi
|
||||
) : ShazamRepository {
|
||||
|
||||
override suspend fun recognize(stationId: Int, stationName: String): RecognizeResult {
|
||||
return try {
|
||||
val res = api.recognizeTrack(stationId)
|
||||
if (res.matched && !res.artist.isNullOrBlank() && !res.song.isNullOrBlank()) {
|
||||
RecognizeResult.Found(
|
||||
Track(
|
||||
artist = res.artist,
|
||||
song = res.song,
|
||||
coverUrl = res.coverUrl,
|
||||
stationName = stationName
|
||||
)
|
||||
)
|
||||
} else {
|
||||
RecognizeResult.NotFound
|
||||
}
|
||||
} catch (e: HttpException) {
|
||||
val msg = when (e.code()) {
|
||||
503 -> "Распознавание временно недоступно"
|
||||
400 -> "На этой станции нет музыки"
|
||||
else -> "Не удалось распознать трек"
|
||||
}
|
||||
RecognizeResult.Error(msg)
|
||||
} catch (e: Exception) {
|
||||
RecognizeResult.Error("Нет связи с сервером")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user