Queue mgmt, Podcast support, Favorites section.
This commit is contained in:
@@ -231,17 +231,47 @@ final class MAService {
|
||||
}
|
||||
|
||||
/// Move queue item
|
||||
func moveQueueItem(playerId: String, fromIndex: Int, toIndex: Int) async throws {
|
||||
logger.debug("Moving queue item from \(fromIndex) to \(toIndex)")
|
||||
func moveQueueItem(playerId: String, queueItemId: String, posShift: Int) async throws {
|
||||
logger.debug("Moving queue item \(queueItemId) by \(posShift) positions")
|
||||
_ = try await webSocketClient.sendCommand(
|
||||
"player_queues/move_item",
|
||||
args: [
|
||||
"queue_id": playerId,
|
||||
"queue_item_id": fromIndex,
|
||||
"pos_shift": toIndex - fromIndex
|
||||
"queue_item_id": queueItemId,
|
||||
"pos_shift": posShift
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func setQueueShuffle(playerId: String, enabled: Bool) async throws {
|
||||
logger.debug("Setting shuffle \(enabled) on queue \(playerId)")
|
||||
_ = try await webSocketClient.sendCommand(
|
||||
"player_queues/shuffle",
|
||||
args: [
|
||||
"queue_id": playerId,
|
||||
"shuffle_enabled": enabled
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func setQueueRepeatMode(playerId: String, mode: RepeatMode) async throws {
|
||||
logger.debug("Setting repeat mode \(mode.rawValue) on queue \(playerId)")
|
||||
_ = try await webSocketClient.sendCommand(
|
||||
"player_queues/repeat",
|
||||
args: [
|
||||
"queue_id": playerId,
|
||||
"repeat_mode": mode.rawValue
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func clearQueue(playerId: String) async throws {
|
||||
logger.debug("Clearing queue \(playerId)")
|
||||
_ = try await webSocketClient.sendCommand(
|
||||
"player_queues/clear",
|
||||
args: ["queue_id": playerId]
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Library
|
||||
|
||||
@@ -302,6 +332,31 @@ final class MAService {
|
||||
resultType: [MAPlaylist].self
|
||||
)
|
||||
}
|
||||
|
||||
/// Get all podcasts in the library
|
||||
func getPodcasts() async throws -> [MAPodcast] {
|
||||
logger.debug("Fetching podcasts")
|
||||
return try await webSocketClient.sendCommand(
|
||||
"music/podcasts/library_items",
|
||||
resultType: [MAPodcast].self
|
||||
)
|
||||
}
|
||||
|
||||
/// Get all episodes for a podcast
|
||||
func getPodcastEpisodes(podcastUri: String) async throws -> [MAMediaItem] {
|
||||
logger.debug("Fetching episodes for podcast \(podcastUri)")
|
||||
guard let (provider, itemId) = parseMAUri(podcastUri) else {
|
||||
throw MAWebSocketClient.ClientError.serverError("Invalid podcast URI: \(podcastUri)")
|
||||
}
|
||||
return try await webSocketClient.sendCommand(
|
||||
"music/podcasts/podcast_episodes",
|
||||
args: [
|
||||
"item_id": itemId,
|
||||
"provider_instance_id_or_domain": provider
|
||||
],
|
||||
resultType: [MAMediaItem].self
|
||||
)
|
||||
}
|
||||
|
||||
/// Get full artist details (includes biography in metadata.description).
|
||||
/// Results are cached in memory once biography data is available, so repeated
|
||||
@@ -460,6 +515,7 @@ final class MAService {
|
||||
let artists: [MAMediaItem]?
|
||||
let playlists: [MAMediaItem]?
|
||||
let radios: [MAMediaItem]?
|
||||
let podcasts: [MAMediaItem]?
|
||||
}
|
||||
|
||||
let searchResults = try result.decode(as: SearchResults.self)
|
||||
@@ -471,6 +527,7 @@ final class MAService {
|
||||
if let artists = searchResults.artists { allItems.append(contentsOf: artists) }
|
||||
if let playlists = searchResults.playlists { allItems.append(contentsOf: playlists) }
|
||||
if let radios = searchResults.radios { allItems.append(contentsOf: radios) }
|
||||
if let podcasts = searchResults.podcasts { allItems.append(contentsOf: podcasts) }
|
||||
|
||||
logger.info("✅ Decoded \(allItems.count) search results (albums: \(searchResults.albums?.count ?? 0), tracks: \(searchResults.tracks?.count ?? 0), artists: \(searchResults.artists?.count ?? 0), radios: \(searchResults.radios?.count ?? 0))")
|
||||
return allItems
|
||||
|
||||
Reference in New Issue
Block a user