feat(media): auto-detect Pear Desktop for seamless YouTube Music sync

When Pear Desktop (com.github.th-ch.youtube-music) is running,
MusicManager now automatically switches to YouTubeMusicController
for seamless media sync without requiring manual settings changes.

Changes:
- Added NSWorkspace notification observers for app launch/terminate
- Auto-switches to YouTubeMusicController when Pear Desktop launches
- Reverts to user's preferred controller when Pear Desktop terminates
- Checks for Pear Desktop at startup
- Respects manual settings changes (won't override user preference)
This commit is contained in:
AmriteshKhare 2026-03-09 14:25:01 +05:30
commit 2dae54b6d7

View file

@ -71,6 +71,10 @@ class MusicManager: ObservableObject {
// Active controller
private var activeController: (any MediaControllerProtocol)?
// Pear Desktop auto-detection
private static let pearDesktopBundleID = YouTubeMusicConfiguration.default.bundleIdentifier
private var isPearDesktopAutoSwitched: Bool = false
// Published properties for UI
@Published var songTitle: String = "I'm Handsome"
@Published var artistName: String = "Me"
@ -126,10 +130,14 @@ class MusicManager: ObservableObject {
// Listen for changes to the default controller preference
NotificationCenter.default.publisher(for: Notification.Name.mediaControllerChanged)
.sink { [weak self] _ in
self?.isPearDesktopAutoSwitched = false
self?.setActiveControllerBasedOnPreference()
}
.store(in: &cancellables)
// Observe Pear Desktop launch/terminate for auto-detection
setupPearDesktopAutoDetection()
// Initialize deprecation check asynchronously
Task { @MainActor in
do {
@ -140,10 +148,54 @@ class MusicManager: ObservableObject {
self.isNowPlayingDeprecated = false
}
// Check if Pear Desktop is already running at startup
let pearDesktopRunning = NSWorkspace.shared.runningApplications.contains {
$0.bundleIdentifier == Self.pearDesktopBundleID
}
if pearDesktopRunning {
print("[MusicManager] Pear Desktop detected at startup, auto-switching to YouTubeMusicController")
self.isPearDesktopAutoSwitched = true
if let controller = self.createController(for: .youtubeMusic) {
self.setActiveController(controller)
}
} else {
// Initialize the active controller after deprecation check
self.setActiveControllerBasedOnPreference()
}
}
}
// MARK: - Pear Desktop Auto-Detection
private func setupPearDesktopAutoDetection() {
NSWorkspace.shared.notificationCenter.publisher(for: NSWorkspace.didLaunchApplicationNotification)
.sink { [weak self] notification in
guard let self = self,
let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication,
app.bundleIdentifier == Self.pearDesktopBundleID else { return }
print("[MusicManager] Pear Desktop launched, auto-switching to YouTubeMusicController")
self.isPearDesktopAutoSwitched = true
if let controller = self.createController(for: .youtubeMusic) {
self.setActiveController(controller)
}
}
.store(in: &cancellables)
NSWorkspace.shared.notificationCenter.publisher(for: NSWorkspace.didTerminateApplicationNotification)
.sink { [weak self] notification in
guard let self = self,
let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication,
app.bundleIdentifier == Self.pearDesktopBundleID else { return }
print("[MusicManager] Pear Desktop terminated, reverting to preferred controller")
if self.isPearDesktopAutoSwitched {
self.isPearDesktopAutoSwitched = false
self.setActiveControllerBasedOnPreference()
}
}
.store(in: &cancellables)
}
deinit {
destroy()