Version 1.5: Groups

This commit is contained in:
2026-04-16 05:48:51 +02:00
parent ae706bc8bc
commit e9462f6d91
8 changed files with 959 additions and 203 deletions
+29 -7
View File
@@ -128,20 +128,20 @@ final class MAService {
)
}
/// Sync a player to a target (target becomes the sync leader)
/// Group a player under a target leader (MA 2.x: players/cmd/group)
func syncPlayer(playerId: String, targetPlayerId: String) async throws {
logger.debug("Syncing player \(playerId) to \(targetPlayerId)")
logger.debug("Grouping player \(playerId) under \(targetPlayerId)")
_ = try await webSocketClient.sendCommand(
"players/cmd/sync",
args: ["player_id": playerId, "target_player_id": targetPlayerId]
"players/cmd/group",
args: ["player_id": playerId, "target_player": targetPlayerId]
)
}
/// Remove a player from its sync group (or dissolve the group if called on the leader)
/// Remove a player from its group (MA 2.x: players/cmd/ungroup)
func unsyncPlayer(playerId: String) async throws {
logger.debug("Unsyncing player \(playerId)")
logger.debug("Ungrouping player \(playerId)")
_ = try await webSocketClient.sendCommand(
"players/cmd/unsync",
"players/cmd/ungroup",
args: ["player_id": playerId]
)
}
@@ -160,6 +160,16 @@ final class MAService {
logger.debug("Seek response: errorCode=\(String(describing: response.errorCode)) details=\(String(describing: response.details))")
}
/// Set group master volume (0-100) scales all members proportionally
func setGroupVolume(playerId: String, level: Int) async throws {
let clampedLevel = max(0, min(100, level))
logger.debug("Setting group volume to \(clampedLevel) on leader \(playerId)")
_ = try await webSocketClient.sendCommand(
"players/cmd/group_volume",
args: ["player_id": playerId, "volume_level": clampedLevel]
)
}
/// Set volume (0-100)
func setVolume(playerId: String, level: Int) async throws {
let clampedLevel = max(0, min(100, level))
@@ -329,6 +339,18 @@ final class MAService {
)
}
/// Get tracks from the library (with optional pagination and favorite filter)
func getTracks(favorite: Bool? = nil, limit: Int = 50, offset: Int = 0) async throws -> [MAMediaItem] {
logger.debug("Fetching tracks (limit: \(limit), offset: \(offset), favorite: \(String(describing: favorite)))")
var args: [String: Any] = ["limit": limit, "offset": offset]
if let favorite { args["favorite"] = favorite }
return try await webSocketClient.sendCommand(
"music/tracks/library_items",
args: args,
resultType: [MAMediaItem].self
)
}
/// Get radio stations
func getRadios() async throws -> [MAMediaItem] {
logger.debug("Fetching radios")