Queue, Favorites, Providers, Now playing

This commit is contained in:
2026-04-06 11:46:04 +02:00
parent e7e9a59e70
commit 56199db301
12 changed files with 462 additions and 58 deletions
@@ -192,6 +192,19 @@ final class MAService {
]
)
}
/// Add media item to the end of a player's queue
func enqueueMedia(playerId: String, uri: String) async throws {
logger.debug("Enqueuing media \(uri) on player \(playerId)")
_ = try await webSocketClient.sendCommand(
"player_queues/play_media",
args: [
"queue_id": playerId,
"media": [uri],
"option": "add"
]
)
}
/// Play from queue index
func playIndex(playerId: String, index: Int) async throws {
@@ -328,6 +341,22 @@ final class MAService {
)
}
/// Get playlist tracks
func getPlaylistTracks(playlistUri: String) async throws -> [MAMediaItem] {
logger.debug("Fetching tracks for playlist \(playlistUri)")
guard let (provider, itemId) = parseMAUri(playlistUri) else {
throw MAWebSocketClient.ClientError.serverError("Invalid playlist URI: \(playlistUri)")
}
return try await webSocketClient.sendCommand(
"music/playlists/playlist_tracks",
args: [
"item_id": itemId,
"provider_instance_id_or_domain": provider
],
resultType: [MAMediaItem].self
)
}
/// Get album tracks
func getAlbumTracks(albumUri: String) async throws -> [MAMediaItem] {
logger.debug("Fetching tracks for album \(albumUri)")
@@ -344,6 +373,36 @@ final class MAService {
)
}
// MARK: - Favorites
/// Add an item to favorites by URI
func addFavorite(uri: String) async throws {
logger.debug("Adding favorite: \(uri)")
_ = try await webSocketClient.sendCommand(
"music/favorites/add_item",
args: ["item": uri]
)
}
/// Remove an item from favorites.
/// The server expects media_type (e.g. "artist") and library_item_id (e.g. "123").
/// These are extracted from the URI format: library://artist/123
func removeFavorite(uri: String) async throws {
logger.debug("Removing favorite: \(uri)")
guard let url = URL(string: uri),
let host = url.host else {
throw MAWebSocketClient.ClientError.serverError("Invalid URI for favorite removal: \(uri)")
}
let itemId = url.path.isEmpty ? host : String(url.path.dropFirst())
_ = try await webSocketClient.sendCommand(
"music/favorites/remove_item",
args: [
"media_type": host,
"library_item_id": itemId
]
)
}
/// Search library
func search(query: String, mediaTypes: [MediaType]? = nil) async throws -> [MAMediaItem] {
logger.debug("🔍 Searching for '\(query)'")