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:
nk
2026-06-07 18:38:17 +03:00
parent 251809df33
commit 69682268f3
16 changed files with 371 additions and 28 deletions

View File

@@ -5,11 +5,13 @@ import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.radiola.data.local.dao.AlarmDao
import com.radiola.data.local.dao.RecognizedTrackDao
import com.radiola.data.local.dao.RecordingDao
import com.radiola.data.local.dao.StationDao
import com.radiola.data.local.dao.TagDao
import com.radiola.data.local.dao.TrackHistoryDao
import com.radiola.data.local.entity.AlarmEntity
import com.radiola.data.local.entity.RecognizedTrackEntity
import com.radiola.data.local.entity.RecordingEntity
import com.radiola.data.local.entity.StationEntity
import com.radiola.data.local.entity.TagEntity
@@ -78,9 +80,27 @@ val MIGRATION_6_7 = object : Migration(6, 7) {
}
}
// Добавляем таблицу истории распознанных треков (Shazam)
val MIGRATION_7_8 = object : Migration(7, 8) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS recognized_track (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
artist TEXT NOT NULL,
song TEXT NOT NULL,
stationName TEXT NOT NULL,
coverUrl TEXT,
timestamp INTEGER NOT NULL
)
""".trimIndent()
)
}
}
@Database(
entities = [StationEntity::class, TrackHistoryEntity::class, TagEntity::class, RecordingEntity::class, AlarmEntity::class],
version = 7
entities = [StationEntity::class, TrackHistoryEntity::class, TagEntity::class, RecordingEntity::class, AlarmEntity::class, RecognizedTrackEntity::class],
version = 8
)
abstract class AppDatabase : RoomDatabase() {
abstract fun stationDao(): StationDao
@@ -88,4 +108,5 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun tagDao(): TagDao
abstract fun recordingDao(): RecordingDao
abstract fun alarmDao(): AlarmDao
abstract fun recognizedTrackDao(): RecognizedTrackDao
}