Underbar/Underbar/Items/NowPlayingItem.swift

149 lines
5.4 KiB
Swift

//
// 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)
}
}
}