// // NowPlayingItem.swift // Underbar // // Created by Shadowfacts on 7/13/19. // Copyright © 2019 Shadowfacts. All rights reserved. // import Cocoa import MediaToolbox class NowPlayingItem: NSCustomTouchBarItem { var nowPlayingClientID: String? var nowPlayingTitle: String? var nowPlayingArtist: String? var nowPlayingAlbum: String? var nowPlayingArtwork: Data? var button: NSButton! var lastPressTime: Date? = nil var multiPressCount: Int = 0 var multiPressWorkItem: DispatchWorkItem? = nil override init(identifier: NSTouchBarItem.Identifier) { super.init(identifier: identifier) button = NSButton(title: "Test\nline 2", target: self, action: #selector(buttonPressed)) button.alignment = .left button.widthAnchor.constraint(equalToConstant: 200).isActive = true let longPressRecognizer = NSPressGestureRecognizer(target: self, action: #selector(buttonLongPressed)) longPressRecognizer.allowedTouchTypes = .direct button.addGestureRecognizer(longPressRecognizer) view = button MRMediaRemoteRegisterForNowPlayingNotifications(.global(qos: .utility)) registerForNotifications() updateMediaInfo() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func registerForNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .init(kMRMediaRemoteNowPlayingApplicationClientStateDidChange), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .mrNowPlayingPlaybackQueueChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .mrNowPlayingPlaybackQueueChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(updateMediaInfo), name: .mrMediaRemoteNowPlayingApplicationIsPlayingDidChange, object: nil) } @objc func updateMediaInfo() { MRMediaRemoteGetNowPlayingInfo(.main) { [weak self] (info) in guard let self = self, let info = info else { return } self.nowPlayingTitle = info[kMRMediaRemoteNowPlayingInfoTitle] as? String self.nowPlayingArtist = info[kMRMediaRemoteNowPlayingInfoArtist] as? String self.nowPlayingAlbum = info[kMRMediaRemoteNowPlayingInfoAlbum] as? String self.nowPlayingArtwork = info[kMRMediaRemoteNowPlayingInfoArtworkData] as? Data self.updateButtonTitle() self.updateButtonImage() } MRMediaRemoteGetNowPlayingClient(.main) { (client) in guard let client = client else { self.nowPlayingClientID = nil return } self.nowPlayingClientID = MRNowPlayingClientGetBundleIdentifier(client) } } func updateButtonTitle() { let attributedStr = NSMutableAttributedString() let line1 = NSAttributedString(string: nowPlayingTitle ?? "Unknown") attributedStr.append(line1) attributedStr.setAttributes([.font: NSFont.systemFont(ofSize: 12)], range: NSRange(location: 0, length: line1.length)) attributedStr.append(NSAttributedString(string: "\n")) let line2 = NSAttributedString(string: (nowPlayingArtist ?? "Unknown") + " | " + (nowPlayingAlbum ?? "Unknown")) attributedStr.append(line2) attributedStr.setAttributes([.font: NSFont.systemFont(ofSize: 10)], range: NSRange(location: line1.length + 1, length: line2.length)) button.attributedTitle = attributedStr } func updateButtonImage() { // todo: custom spotify artwork helper if let data = nowPlayingArtwork, let image = NSImage(data: data) { button.image = image button.imagePosition = .imageLeft } else { button.image = nil } } @objc func buttonPressed() { if let lastPressTime = lastPressTime, lastPressTime.timeIntervalSinceNow < 0.2 { multiPressCount += 1 multiPressWorkItem?.cancel() } else { self.lastPressTime = Date() multiPressCount = 1 } multiPressWorkItem = DispatchWorkItem { self.handleMultiPress(presses: self.multiPressCount) self.lastPressTime = nil self.multiPressCount = 0 self.multiPressWorkItem = nil } DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: multiPressWorkItem!) } func handleMultiPress(presses: Int) { switch presses { case 1: MRMediaRemoteSendCommand(kMRTogglePlayPause, nil) case 2: MRMediaRemoteSendCommand(kMRNextTrack, nil) case 3: MRMediaRemoteSendCommand(kMRPreviousTrack, nil) default: break } } @objc func buttonLongPressed(recognizer: NSPressGestureRecognizer) { if recognizer.state == .began, let nowPlayingClientID = nowPlayingClientID { NSWorkspace.shared.launchApplication(withBundleIdentifier: nowPlayingClientID, options: .default, additionalEventParamDescriptor: nil, launchIdentifier: nil) } } }