feat: WebSocket now-playing via Socket.IO from backend

This commit is contained in:
nk
2026-06-02 19:52:15 +03:00
parent a83672b455
commit bcb999ace9
1159 changed files with 15703 additions and 9918 deletions

View File

@@ -0,0 +1,78 @@
package com.radiola.data.remote
import com.radiola.domain.model.Track
import io.socket.client.IO
import io.socket.client.Socket
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NowPlayingSocketClient @Inject constructor(
private val json: Json
) {
private val _nowPlaying = MutableStateFlow<Map<Int, Track>>(emptyMap())
val nowPlaying: StateFlow<Map<Int, Track>> = _nowPlaying
private var socket: Socket? = null
fun connect() {
if (socket != null) return
try {
val opts = IO.Options().apply {
transports = arrayOf("websocket")
}
socket = IO.socket("http://121.127.37.212:3000/now-playing", opts)
socket?.on("now-playing") { args ->
if (args.isNotEmpty()) {
val data = args[0] as? String ?: return@on
handleNowPlayingEvent(data)
}
}
socket?.on(Socket.EVENT_CONNECT) {
android.util.Log.d("NowPlayingSocket", "Connected")
}
socket?.on(Socket.EVENT_DISCONNECT) {
android.util.Log.d("NowPlayingSocket", "Disconnected")
}
socket?.on(Socket.EVENT_CONNECT_ERROR) { args ->
android.util.Log.e("NowPlayingSocket", "Connect error: ${args.joinToString()}")
}
socket?.connect()
} catch (e: Exception) {
android.util.Log.e("NowPlayingSocket", "Failed to connect", e)
}
}
fun disconnect() {
socket?.disconnect()
socket = null
}
private fun handleNowPlayingEvent(data: String) {
try {
val obj = json.parseToJsonElement(data).jsonObject
val stationId = obj["stationId"]?.jsonPrimitive?.content?.toIntOrNull() ?: return
val song = obj["song"]?.jsonPrimitive?.content ?: return
val artist = obj["artist"]?.jsonPrimitive?.content ?: return
val coverUrl = obj["coverUrl"]?.jsonPrimitive?.content
val track = Track(
artist = artist,
song = song,
coverUrl = coverUrl,
stationName = ""
)
_nowPlaying.value = _nowPlaying.value.toMutableMap().apply {
put(stationId, track)
}
} catch (e: Exception) {
android.util.Log.e("NowPlayingSocket", "Failed to parse event", e)
}
}
}

View File

@@ -1,5 +1,6 @@
package com.radiola.data.repository
import com.radiola.data.remote.NowPlayingSocketClient
import com.radiola.data.remote.RecordApi
import com.radiola.data.remote.ApiMapper.toDomain
import com.radiola.domain.model.Track
@@ -10,16 +11,21 @@ import kotlinx.coroutines.flow.map
import javax.inject.Inject
class NowPlayingRepositoryImpl @Inject constructor(
private val api: RecordApi
private val api: RecordApi,
private val socketClient: NowPlayingSocketClient
) : NowPlayingRepository {
private val _nowPlaying = MutableStateFlow<Map<Int, Track>>(emptyMap())
override fun getNowPlaying(stationId: Int): Flow<Track?> {
return _nowPlaying.map { it[stationId] }
init {
socketClient.connect()
}
override fun getAllNowPlaying(): Flow<Map<Int, Track>> = _nowPlaying
override fun getNowPlaying(stationId: Int): Flow<Track?> {
return socketClient.nowPlaying.map { it[stationId] }
}
override fun getAllNowPlaying(): Flow<Map<Int, Track>> = socketClient.nowPlaying
override suspend fun refreshNowPlaying(): Result<Unit> {
return try {