Version one on the App Store
This commit is contained in:
@@ -16,6 +16,7 @@ final class MAPlayerManager {
|
||||
// MARK: - Properties
|
||||
|
||||
private(set) var players: [String: MAPlayer] = [:]
|
||||
private(set) var playerQueues: [String: MAPlayerQueue] = [:]
|
||||
private(set) var queues: [String: [MAQueueItem]] = [:]
|
||||
|
||||
private weak var service: MAService?
|
||||
@@ -77,36 +78,43 @@ final class MAPlayerManager {
|
||||
|
||||
private func handlePlayerUpdated(_ event: MAEvent) async {
|
||||
guard let data = event.data else { return }
|
||||
|
||||
|
||||
do {
|
||||
let player = try data.decode(as: MAPlayer.self)
|
||||
await MainActor.run {
|
||||
players[player.playerId] = player
|
||||
logger.debug("Updated player: \(player.name) - \(player.state.rawValue)")
|
||||
logger.debug("Updated player: \(player.name) state=\(player.state.rawValue) item=\(player.currentItem?.name ?? "nil")")
|
||||
}
|
||||
} catch {
|
||||
logger.error("Failed to decode player update: \(error.localizedDescription)")
|
||||
logger.error("Failed to decode player_updated event: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func handleQueueUpdated(_ event: MAEvent) async {
|
||||
guard let data = event.data,
|
||||
let dict = data.value as? [String: Any],
|
||||
let queueId = dict["queue_id"] as? String else {
|
||||
guard let data = event.data else { return }
|
||||
|
||||
// The event data IS the PlayerQueue object — decode it directly for current_item
|
||||
if let queue = try? data.decode(as: MAPlayerQueue.self), !queue.queueId.isEmpty {
|
||||
await MainActor.run {
|
||||
playerQueues[queue.queueId] = queue
|
||||
logger.debug("Updated queue state for player \(queue.queueId), current: \(queue.currentItem?.name ?? "nil")")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reload queue for this player
|
||||
guard let service else { return }
|
||||
|
||||
|
||||
// Fallback: extract queue_id and fetch from API
|
||||
guard let dict = data.value as? [String: Any],
|
||||
let queueId = dict["queue_id"] as? String,
|
||||
let service else { return }
|
||||
|
||||
do {
|
||||
let items = try await service.getQueue(playerId: queueId)
|
||||
let queue = try await service.getPlayerQueue(playerId: queueId)
|
||||
await MainActor.run {
|
||||
queues[queueId] = items
|
||||
logger.debug("Updated queue for player \(queueId): \(items.count) items")
|
||||
playerQueues[queueId] = queue
|
||||
logger.debug("Fetched queue state for player \(queueId), current: \(queue.currentItem?.name ?? "nil")")
|
||||
}
|
||||
} catch {
|
||||
logger.error("Failed to reload queue: \(error.localizedDescription)")
|
||||
logger.error("Failed to reload queue state: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,18 +125,40 @@ final class MAPlayerManager {
|
||||
|
||||
// MARK: - Data Loading
|
||||
|
||||
/// Load all players
|
||||
/// Load all players and their queue states
|
||||
func loadPlayers() async throws {
|
||||
guard let service else {
|
||||
guard let service else {
|
||||
throw MAWebSocketClient.ClientError.notConnected
|
||||
}
|
||||
|
||||
|
||||
logger.info("Loading players")
|
||||
let playerList = try await service.getPlayers()
|
||||
|
||||
|
||||
await MainActor.run {
|
||||
players = Dictionary(uniqueKeysWithValues: playerList.map { ($0.playerId, $0) })
|
||||
}
|
||||
|
||||
// Concurrently fetch queue state for each player to get current_item
|
||||
var queueResults: [String: MAPlayerQueue] = [:]
|
||||
await withTaskGroup(of: (String, MAPlayerQueue?).self) { group in
|
||||
for player in playerList {
|
||||
let pid = player.playerId
|
||||
group.addTask {
|
||||
let queue = try? await service.getPlayerQueue(playerId: pid)
|
||||
return (pid, queue)
|
||||
}
|
||||
}
|
||||
for await (pid, queue) in group {
|
||||
if let queue { queueResults[pid] = queue }
|
||||
}
|
||||
}
|
||||
|
||||
await MainActor.run {
|
||||
for (pid, queue) in queueResults {
|
||||
playerQueues[pid] = queue
|
||||
}
|
||||
logger.info("Loaded queue states for \(queueResults.count) players")
|
||||
}
|
||||
}
|
||||
|
||||
/// Load queue for specific player
|
||||
@@ -189,6 +219,16 @@ final class MAPlayerManager {
|
||||
try await service.setVolume(playerId: playerId, level: level)
|
||||
}
|
||||
|
||||
func syncPlayer(playerId: String, targetPlayerId: String) async throws {
|
||||
guard let service else { throw MAWebSocketClient.ClientError.notConnected }
|
||||
try await service.syncPlayer(playerId: playerId, targetPlayerId: targetPlayerId)
|
||||
}
|
||||
|
||||
func unsyncPlayer(playerId: String) async throws {
|
||||
guard let service else { throw MAWebSocketClient.ClientError.notConnected }
|
||||
try await service.unsyncPlayer(playerId: playerId)
|
||||
}
|
||||
|
||||
func playMedia(playerId: String, uri: String) async throws {
|
||||
guard let service else {
|
||||
throw MAWebSocketClient.ClientError.notConnected
|
||||
|
||||
Reference in New Issue
Block a user