1
1
mirror of https://github.com/danbee/persephone synced 2025-03-04 08:39:11 +00:00

Use MPNowPlayingInfoCenter to player info

This means that the notications bar media player will show track &
artist title, as well as artwork for the album.

It also means that Play/Pause/Next/Previous work without needing
accessibility access
This commit is contained in:
Alan Harper 2020-11-21 14:27:22 +11:00 committed by Dan Barber
parent 3b330f1c78
commit a0f1942ba8
5 changed files with 161 additions and 1 deletions

View File

@ -12,6 +12,8 @@ struct App {
static let store = Store<AppState>(reducer: appReducer, state: nil)
static let trackTimer = TrackTimer()
static let userNotificationsController = UserNotificationsController()
static let mediaInfoController = MediaInfoController()
static let playerStateInfoController = PlayerStateInfoController()
static let mpdServerDelegate = MPDServerDelegate()
static let mpdServerController = MPDServerController(delegate: mpdServerDelegate)
static var mpdClient: MPDClient!

View File

@ -40,7 +40,9 @@ class AppDelegate: NSObject,
}
_ = App.userNotificationsController
_ = App.mediaInfoController
_ = App.playerStateInfoController
_ = App.mpdServerController
}

View File

@ -0,0 +1,76 @@
//
// MediaInfoController.swift
// Persephone
//
// Created by Alan Harper on 18/11/20.
// Copyright © 2020 Dan Barber. All rights reserved.
//
import Foundation
import ReSwift
import MediaPlayer
import Kingfisher
class MediaInfoController {
init() {
App.store.subscribe(self) {
$0.select { $0.playerState.currentSong }
}
}
func notifyTrack(_ song: Song) {
let provider = MPDAlbumArtImageDataProvider(
songUri: song.mpdSong.uriString,
cacheKey: song.album.hash
)
let infoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = [
MPMediaItemPropertyTitle: song.title,
MPMediaItemPropertyArtist: song.artist,
MPMediaItemPropertyAlbumArtist: song.album.artist,
MPMediaItemPropertyAlbumTitle: song.album.title,
MPMediaItemPropertyPlaybackDuration: NSNumber(value: song.duration.timeInSeconds),
MPNowPlayingInfoPropertyMediaType: NSNumber(value: MPNowPlayingInfoMediaType.audio.rawValue),
MPNowPlayingInfoPropertyIsLiveStream: NSNumber(value: false),
] as [String : Any]
if let elapsedTime = App.store.state.playerState.elapsedTimeMs {
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = NSNumber(value: elapsedTime / 1000)
}
if #available(OSX 10.13.2, *) {
_ = KingfisherManager.shared.retrieveImage(
with: .provider(provider),
options: [
.processor(DownsamplingImageProcessor(size: .notificationCoverSize)),
.scaleFactor(2),
]
) { result in
switch result {
case .success(let value):
let artwork = MPMediaItemArtwork.init(boundsSize: CGSize(width: 100.0, height: 100.0)) { (size: CGSize) in value.image }
nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork
infoCenter.nowPlayingInfo = nowPlayingInfo
case .failure:
infoCenter.nowPlayingInfo = nowPlayingInfo
break
}
}
} else {
infoCenter.nowPlayingInfo = nowPlayingInfo
}
}
}
extension MediaInfoController: StoreSubscriber {
typealias StoreSubscriberStateType = Song?
func newState(state: StoreSubscriberStateType) {
guard let song = state else {return}
notifyTrack(song)
}
}

View File

@ -0,0 +1,72 @@
//
// MediaInfoController.swift
// Persephone
//
// Created by Alan Harper on 18/11/20.
// Copyright © 2020 Dan Barber. All rights reserved.
//
import Foundation
import ReSwift
import MediaPlayer
import Kingfisher
class PlayerStateInfoController {
init() {
App.store.subscribe(self) {
$0.select { $0.playerState.state }
}
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.addTarget { _ in
App.mpdClient.playPause()
return .success
}
commandCenter.togglePlayPauseCommand.addTarget { _ in
App.mpdClient.playPause()
return .success
}
commandCenter.pauseCommand.addTarget { _ in
App.mpdClient.playPause()
return .success
}
commandCenter.nextTrackCommand.addTarget { _ in
App.mpdClient.nextTrack()
return .success
}
commandCenter.previousTrackCommand.addTarget { _ in
App.mpdClient.prevTrack()
return .success
}
}
func notifyState(_ state: MPDClient.MPDStatus.State?) {
let infoCenter = MPNowPlayingInfoCenter.default()
switch(state) {
case .unknown:
infoCenter.playbackState = .unknown
break;
case .paused:
infoCenter.playbackState = .paused
break;
case .stopped:
infoCenter.playbackState = .stopped
break;
case .playing:
infoCenter.playbackState = .playing
break;
case .none:
return
}
}
}
extension PlayerStateInfoController: StoreSubscriber {
typealias StoreSubscriberStateType = MPDClient.MPDStatus.State?
func newState(state: StoreSubscriberStateType) {
notifyState(state)
}
}

View File

@ -307,6 +307,8 @@
E4FF7190227601B400D4C412 /* PreferencesReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FF718F227601B400D4C412 /* PreferencesReducer.swift */; };
E4FF71922276029000D4C412 /* PreferencesActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FF71912276029000D4C412 /* PreferencesActions.swift */; };
E4FF71942276043A00D4C412 /* MPDServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FF71932276043A00D4C412 /* MPDServer.swift */; };
E72BF0CE2567F45E00419CB0 /* PlayerStateInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72BF0CD2567F45E00419CB0 /* PlayerStateInfoController.swift */; };
E7AF1B642565124D00057784 /* MediaInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7AF1B632565124D00057784 /* MediaInfoController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -650,6 +652,8 @@
E4FF718F227601B400D4C412 /* PreferencesReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesReducer.swift; sourceTree = "<group>"; };
E4FF71912276029000D4C412 /* PreferencesActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesActions.swift; sourceTree = "<group>"; };
E4FF71932276043A00D4C412 /* MPDServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDServer.swift; sourceTree = "<group>"; };
E72BF0CD2567F45E00419CB0 /* PlayerStateInfoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStateInfoController.swift; sourceTree = "<group>"; };
E7AF1B632565124D00057784 /* MediaInfoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInfoController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -958,6 +962,8 @@
E489E3A222B9D31800CA8CBD /* DraggedSongView.swift */,
E489E3A322B9D31800CA8CBD /* DraggedSongView.xib */,
E4B11BB52275374B0075461B /* UserNotificationsController.swift */,
E7AF1B632565124D00057784 /* MediaInfoController.swift */,
E72BF0CD2567F45E00419CB0 /* PlayerStateInfoController.swift */,
);
path = Shared;
sourceTree = "<group>";
@ -1643,6 +1649,7 @@
E48059D82426D73600362CF3 /* database.c in Sources */,
E43AC1F522C6A4F4001E483C /* DraggedAlbum.swift in Sources */,
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
E72BF0CE2567F45E00419CB0 /* PlayerStateInfoController.swift in Sources */,
E4B11BB62275374B0075461B /* UserNotificationsController.swift in Sources */,
E43AC1F622C6AD0B001E483C /* AlbumViewController+NSCollectionViewDelegate.swift in Sources */,
E4B11B68226A4FA00075461B /* QueueState.swift in Sources */,
@ -1674,6 +1681,7 @@
E4805A0A2426D73600362CF3 /* sync.c in Sources */,
E4DA820623D6236200C1EE58 /* NSSize.swift in Sources */,
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
E7AF1B642565124D00057784 /* MediaInfoController.swift in Sources */,
E48059E42426D73600362CF3 /* run.c in Sources */,
E4805A1A2426D73600362CF3 /* cmessage.c in Sources */,
E48059C42426D73600362CF3 /* replay_gain.c in Sources */,