1
1
mirror of https://github.com/danbee/persephone synced 2025-03-04 08:39:11 +00:00
persephone/Shared/MPDClient/Extensions/MPDClient+Command.swift
Dan Barber ff88aa8f5e Move the handle idle command into the command queue
My theory is that it's ok to send the `noidle` synchronously but the
subsequent handling of the idle response should be on the command queue.
My hope is that this fixes issues with less than perfect network
connections (and also very occasionally seen on good networks).
2021-12-05 19:10:12 -06:00

171 lines
4.6 KiB
Swift

//
// CommandQueue.swift
// Persephone
//
// Created by Daniel Barber on 2019/3/15.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
extension MPDClient {
func sendCommand(
command: MPDCommand,
userData: Dictionary<String, Any> = [:]
) {
guard command == .connect || isConnected else { return }
switch command {
case .connect:
guard let host = userData["host"] as? String,
let port = userData["port"] as? Int
else { return }
createConnection(host: host, port: port)
case .disconnect:
freeConnection()
// Transport commands
case .prevTrack:
sendPreviousTrack()
case .nextTrack:
sendNextTrack()
case .stop:
sendStop()
case .playPause:
sendPlay()
case .seekCurrentSong:
guard let timeInSeconds = userData["timeInSeconds"] as? Float
else { return }
sendSeekCurrentSong(timeInSeconds: timeInSeconds)
case .setShuffleState:
guard let shuffleState = userData["shuffleState"] as? Bool
else { return }
sendShuffleState(shuffleState: shuffleState)
case .setRepeatState:
guard let repeatState = userData["repeatState"] as? Bool
else { return }
sendRepeatState(repeatState: repeatState)
case .setVolume:
guard let volume = userData["volume"] as? Int
else { return }
sendSetVolume(to: volume)
// Database commands
case .updateDatabase:
sendUpdateDatabase()
// Status commands
case .fetchStatus:
sendRunStatus()
// Queue commands
case .fetchQueue:
sendFetchQueue()
case .playTrack:
guard let queuePos = userData["queuePos"] as? Int
else { return }
sendPlayTrack(at: queuePos)
case .clearQueue:
sendClearQueue()
case .replaceQueue:
guard let songs = userData["songs"] as? [MPDSong]
else { return }
sendReplaceQueue(songs)
case .appendSong:
guard let song = userData["song"] as? MPDSong
else { return }
sendAppendSong(song)
case .removeSong:
guard let queuePos = userData["queuePos"] as? Int
else { return }
sendRemoveSong(at: queuePos)
case .moveSongInQueue:
guard let oldQueuePos = userData["oldQueuePos"] as? Int,
let newQueuePos = userData["newQueuePos"] as? Int
else { return }
sendMoveSongInQueue(at: oldQueuePos, to: newQueuePos)
case .addSongToQueue:
guard let songUri = userData["uri"] as? String,
let queuePos = userData["queuePos"] as? Int
else { return }
sendAddSongToQueue(uri: songUri, at: queuePos)
case .addAlbumToQueue:
guard let album = userData["album"] as? MPDAlbum,
let queuePos = userData["queuePos"] as? Int
else { return }
sendAddAlbumToQueue(album: album, at: queuePos)
// Artist commands
case .fetchAllArtists:
allArtists()
// Album commands
case .fetchAlbums:
guard let filter = userData["filter"] as? String else { return }
albums(filter: filter)
case .playAlbum:
guard let album = userData["album"] as? MPDAlbum else { return }
sendPlayAlbum(album)
case .getAlbumFirstSong:
guard let album = userData["album"] as? MPDAlbum,
let callback = userData["callback"] as? (MPDSong?) -> Void
else { return }
albumFirstSong(for: album, callback: callback)
case .getAlbumSongs:
guard let album = userData["album"] as? MPDAlbum,
let callback = userData["callback"] as? ([MPDSong]) -> Void
else { return }
albumSongs(for: album, callback: callback)
// Song commands
case .fetchAlbumArt:
guard let songUri = userData["songUri"] as? String,
let offset = userData["offset"] as? Int32,
let callback = userData["callback"] as? (Data?) -> Void
else { return }
let imageData = userData["imageData"] as? Data? ?? nil
sendFetchAlbumArt(
forUri: songUri,
imageData: imageData,
offset: offset,
callback: callback
)
}
}
func enqueueCommand(
command: MPDCommand,
priority: BlockOperation.QueuePriority = .normal,
forceIdle: Bool = false,
userData: Dictionary<String, Any> = [:]
) {
guard isConnected else { return }
noIdle()
let commandOperation = BlockOperation() { [unowned self] in
self.sendCommand(command: command, userData: userData)
if self.checkError() {
self.idle(forceIdle)
}
}
commandOperation.queuePriority = priority
commandQueue.addOperation(commandOperation)
}
}