diff --git a/Persephone.xcodeproj/project.pbxproj b/Persephone.xcodeproj/project.pbxproj index 2847cea..f1098ad 100644 --- a/Persephone.xcodeproj/project.pbxproj +++ b/Persephone.xcodeproj/project.pbxproj @@ -17,10 +17,11 @@ E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; }; E465049A21E94DF500A70F4C /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E465049921E94DF500A70F4C /* WindowController.swift */; }; - E4E8CC902204EC7F0024217A /* MPDClientDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* MPDClientDelegate.swift */; }; + E4A642DA22090CBE00067D21 /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A642D922090CBE00067D21 /* Status.swift */; }; + E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; }; E4E8CC922204F4B80024217A /* QueueController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueController.swift */; }; - E4E8CC942206097F0024217A /* MPDClientNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC932206097F0024217A /* MPDClientNotificationHandler.swift */; }; - E4E8CC9A22075D370024217A /* MPDClientSong.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* MPDClientSong.swift */; }; + E4E8CC942206097F0024217A /* NotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC932206097F0024217A /* NotificationHandler.swift */; }; + E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -107,10 +108,11 @@ E41B22EA21FB966C00D544F6 /* queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = queue.h; sourceTree = ""; }; E41B22EB21FB966C00D544F6 /* playlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = playlist.h; sourceTree = ""; }; E465049921E94DF500A70F4C /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = ""; }; - E4E8CC8F2204EC7F0024217A /* MPDClientDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClientDelegate.swift; sourceTree = ""; }; + E4A642D922090CBE00067D21 /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = ""; }; + E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = ""; }; E4E8CC912204F4B80024217A /* QueueController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueController.swift; sourceTree = ""; }; - E4E8CC932206097F0024217A /* MPDClientNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClientNotificationHandler.swift; sourceTree = ""; }; - E4E8CC9922075D370024217A /* MPDClientSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClientSong.swift; sourceTree = ""; }; + E4E8CC932206097F0024217A /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = ""; }; + E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -172,9 +174,7 @@ E465049921E94DF500A70F4C /* WindowController.swift */, E40786242110CE70006887B1 /* Info.plist */, E40786252110CE70006887B1 /* Persephone.entitlements */, - E4E8CC932206097F0024217A /* MPDClientNotificationHandler.swift */, - E4E8CC9922075D370024217A /* MPDClientSong.swift */, - E4E8CC8F2204EC7F0024217A /* MPDClientDelegate.swift */, + E4A642DB220912FA00067D21 /* MPDClient */, E41B22C521FB932700D544F6 /* MPDClient.swift */, ); path = Persephone; @@ -257,6 +257,17 @@ path = mpd; sourceTree = ""; }; + E4A642DB220912FA00067D21 /* MPDClient */ = { + isa = PBXGroup; + children = ( + E4E8CC932206097F0024217A /* NotificationHandler.swift */, + E4E8CC9922075D370024217A /* Song.swift */, + E4E8CC8F2204EC7F0024217A /* Delegate.swift */, + E4A642D922090CBE00067D21 /* Status.swift */, + ); + path = MPDClient; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -393,13 +404,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E4A642DA22090CBE00067D21 /* Status.swift in Sources */, E407861E2110CE6E006887B1 /* ViewController.swift in Sources */, - E4E8CC942206097F0024217A /* MPDClientNotificationHandler.swift in Sources */, + E4E8CC942206097F0024217A /* NotificationHandler.swift in Sources */, E465049A21E94DF500A70F4C /* WindowController.swift in Sources */, E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */, E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */, - E4E8CC9A22075D370024217A /* MPDClientSong.swift in Sources */, - E4E8CC902204EC7F0024217A /* MPDClientDelegate.swift in Sources */, + E4E8CC9A22075D370024217A /* Song.swift in Sources */, + E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */, E4E8CC922204F4B80024217A /* QueueController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Persephone/MPDClient.swift b/Persephone/MPDClient.swift index 5afc1e5..b29556c 100644 --- a/Persephone/MPDClient.swift +++ b/Persephone/MPDClient.swift @@ -13,15 +13,17 @@ class MPDClient { var delegate: MPDClientDelegate? static let stateChanged = Notification.Name("MPDClientStateChanged") static let queueChanged = Notification.Name("MPDClientQueueChanged") + static let queuePosChanged = Notification.Name("MPDClientQueuePosChanged") static let stateKey = "state" static let queueKey = "queue" + static let queuePosKey = "song" let HOST = "localhost" let PORT: UInt32 = 6600 private var connection: OpaquePointer? - private var status: OpaquePointer? + var status: Status? private var queue: [Song] = [] private let commandQueue = DispatchQueue(label: "commandQueue") @@ -65,11 +67,11 @@ class MPDClient { else { return } self.connection = connection - self.status = status + self.status = Status(status) fetchQueue() - self.delegate?.didUpdateState(mpdClient: self, state: self.getState()) + self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state()) self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue) idle() } @@ -77,10 +79,6 @@ class MPDClient { func disconnect() { noIdle() commandQueue.async { [unowned self] in - for song in self.queue { - song.free() - } - mpd_status_free(self.status) mpd_connection_free(self.connection) } } @@ -93,10 +91,6 @@ class MPDClient { sendCommand(command: .fetchQueue) } - func getState() -> mpd_state { - return mpd_status_get_state(status) - } - func playPause() { queueCommand(command: .playPause) } @@ -136,7 +130,7 @@ class MPDClient { case .fetchStatus: guard let status = mpd_run_status(connection) else { break } - self.status = status + self.status = Status(status) case .fetchQueue: self.queue = [] @@ -150,13 +144,13 @@ class MPDClient { } func sendNextTrack() { - if [MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(getState()) { + if [MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(status?.state()) { mpd_run_next(connection) } } func sendPreviousTrack() { - if [MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(getState()) { + if [MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(status?.state()) { mpd_run_previous(connection) } } @@ -166,7 +160,7 @@ class MPDClient { } func sendPlay() { - if getState() == MPD_STATE_STOP { + if status?.state() == MPD_STATE_STOP { mpd_run_play(connection) } else { mpd_run_toggle_pause(connection) @@ -195,7 +189,7 @@ class MPDClient { } if mpdIdle.contains(.player) { self.fetchStatus() - self.delegate?.didUpdateState(mpdClient: self, state: self.getState()) + self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state()) } if !mpdIdle.isEmpty { self.idle() diff --git a/Persephone/MPDClientDelegate.swift b/Persephone/MPDClient/Delegate.swift similarity index 85% rename from Persephone/MPDClientDelegate.swift rename to Persephone/MPDClient/Delegate.swift index 9674e8e..7ee5911 100644 --- a/Persephone/MPDClientDelegate.swift +++ b/Persephone/MPDClient/Delegate.swift @@ -12,4 +12,5 @@ import mpdclient protocol MPDClientDelegate { func didUpdateState(mpdClient: MPDClient, state: mpd_state) func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song]) + func didUpdateQueuePos(mpdClient: MPDClient, song: Int32) } diff --git a/Persephone/MPDClientNotificationHandler.swift b/Persephone/MPDClient/NotificationHandler.swift similarity index 51% rename from Persephone/MPDClientNotificationHandler.swift rename to Persephone/MPDClient/NotificationHandler.swift index 4dece19..2ab7b1e 100644 --- a/Persephone/MPDClientNotificationHandler.swift +++ b/Persephone/MPDClient/NotificationHandler.swift @@ -13,21 +13,32 @@ class MPDClientNotificationHandler: MPDClientDelegate { let notificationQueue = DispatchQueue.main func didUpdateState(mpdClient: MPDClient, state: mpd_state) { - self.notificationQueue.async { - NotificationCenter.default.post( - name: MPDClient.stateChanged, - object: AppDelegate.mpdClient, - userInfo: [MPDClient.stateKey: state] - ) - } + sendNotification( + name: MPDClient.stateChanged, + userInfo: [MPDClient.stateKey: state] + ) } func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song]) { + sendNotification( + name: MPDClient.queueChanged, + userInfo: [MPDClient.queueKey: queue] + ) + } + + func didUpdateQueuePos(mpdClient: MPDClient, song: Int32) { + sendNotification( + name: MPDClient.queuePosChanged, + userInfo: [MPDClient.queuePosKey: song] + ) + } + + private func sendNotification(name: Notification.Name, userInfo: [AnyHashable : Any]) { self.notificationQueue.async { NotificationCenter.default.post( - name: MPDClient.queueChanged, + name: name, object: AppDelegate.mpdClient, - userInfo: [MPDClient.queueKey: queue] + userInfo: userInfo ) } } diff --git a/Persephone/MPDClientSong.swift b/Persephone/MPDClient/Song.swift similarity index 96% rename from Persephone/MPDClientSong.swift rename to Persephone/MPDClient/Song.swift index 6db3619..a89c0a4 100644 --- a/Persephone/MPDClientSong.swift +++ b/Persephone/MPDClient/Song.swift @@ -17,7 +17,7 @@ extension MPDClient { self.mpdSong = mpdSong } - func free() { + deinit { mpd_song_free(mpdSong) } diff --git a/Persephone/MPDClient/Status.swift b/Persephone/MPDClient/Status.swift new file mode 100644 index 0000000..df07fd3 --- /dev/null +++ b/Persephone/MPDClient/Status.swift @@ -0,0 +1,32 @@ +// +// MPDClientStatus.swift +// Persephone +// +// Created by Daniel Barber on 2019/2/04. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import Foundation +import mpdclient + +extension MPDClient { + class Status { + let mpdStatus: OpaquePointer + + init(_ mpdStatus: OpaquePointer) { + self.mpdStatus = mpdStatus + } + + deinit { + mpd_status_free(mpdStatus) + } + + func state() -> mpd_state { + return mpd_status_get_state(mpdStatus) + } + + func song() -> Int32 { + return mpd_status_get_song_pos(mpdStatus) + } + } +}