904b9b3d-c0eb-42f3-acef-958.../Info.plist

36 lines
1.3 KiB
Plaintext
Raw Normal View History

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>MusicPlugin</string>
<key>CFBundleIdentifier</key>
<string>com.mioisland.plugin.music-player</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Music Player</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
v2.0.4: latency razor — event-driven + running-app gate + parallel probing Target: push state-change detection latency under 200ms in the common case, and cold start under 2s. Changes: 1. Event-driven primary path, poll becomes safety-net - Poll interval 1.5s → 15s. Was firing 40 AppleScript probes per minute on a Mac that's playing nothing. - MediaRemote notifications + DistributedNotificationCenter broadcasts (com.spotify.client.PlaybackStateChanged, com.apple.Music.playerInfo, com.apple.iTunes.playerInfo) already handle track changes in <100ms. The 1.5s poll was just backup, and now 15s is enough backup. 2. NSWorkspace launch/terminate observers - New observers on NSWorkspace.didLaunchApplicationNotification + didTerminateApplicationNotification. When Spotify, Apple Music, or Chrome launches / quits, refresh fires immediately instead of waiting for the next poll. Beats the old path by up to 15s on first-launch-of-day scenarios. 3. Running-app gate (NSWorkspace.runningApplications) - Each source now exposes `static var isRunning` via NSWorkspace.shared.runningApplications.contains(bundleId). - Router checks before probing. AppleScript `with timeout of 2 seconds` still trips when the target app isn't running, so avoiding those probes saves up to 6s per refresh on a clean Mac. 4. MediaRemote 15.4+ entitlement memoization - When MRMediaRemoteGetNowPlayingInfo returns an empty dict AND at least one player app is running (likelyBlocked heuristic), mark MediaRemote blocked for 60s and skip in the router. Saves ~50ms per refresh on restricted macOS versions and lets the first-pass AppleScript probe happen without a preceding MR round-trip. - Retries every 60s in case the gate state changes (macOS minor update / user-granted entitlement). 5. Parallel fallback probing - Old router was serial: MediaRemote → Spotify → Music → Chrome. Cold start worst-case 4-6s when all three AppleScript sources trip their 2s timeouts. - New router uses `async let` to fan out every live candidate concurrently. First-in-priority-order non-nil result wins. Cold start worst-case now ≈ slowest single AppleScript probe. 6. Sticky-source fast path survives - When the last-successful source is still a live candidate (its app still running, MR still not blocked), try it alone first. On steady-state playback this is one round-trip per refresh, same as before. 7. Transport control perceived latency - scheduleRefresh(after: 0.3) → 0.1 for togglePlay/next/prev/seek. UI already flips optimistically; the 100ms re-sync is enough to catch the real app state without feeling laggy. Reference: Atoll (github.com/Ebullioscopic/Atoll) uses a bundled mediaremote-adapter framework + Perl stream client to bypass the macOS 15.4 MediaRemote entitlement gate entirely. That's a bigger lift and left for a future phase — this commit wrings out the latency that's achievable without that adapter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 07:02:36 +00:00
<string>2.0.4</string>
<key>CFBundleVersion</key>
v2.0.4: latency razor — event-driven + running-app gate + parallel probing Target: push state-change detection latency under 200ms in the common case, and cold start under 2s. Changes: 1. Event-driven primary path, poll becomes safety-net - Poll interval 1.5s → 15s. Was firing 40 AppleScript probes per minute on a Mac that's playing nothing. - MediaRemote notifications + DistributedNotificationCenter broadcasts (com.spotify.client.PlaybackStateChanged, com.apple.Music.playerInfo, com.apple.iTunes.playerInfo) already handle track changes in <100ms. The 1.5s poll was just backup, and now 15s is enough backup. 2. NSWorkspace launch/terminate observers - New observers on NSWorkspace.didLaunchApplicationNotification + didTerminateApplicationNotification. When Spotify, Apple Music, or Chrome launches / quits, refresh fires immediately instead of waiting for the next poll. Beats the old path by up to 15s on first-launch-of-day scenarios. 3. Running-app gate (NSWorkspace.runningApplications) - Each source now exposes `static var isRunning` via NSWorkspace.shared.runningApplications.contains(bundleId). - Router checks before probing. AppleScript `with timeout of 2 seconds` still trips when the target app isn't running, so avoiding those probes saves up to 6s per refresh on a clean Mac. 4. MediaRemote 15.4+ entitlement memoization - When MRMediaRemoteGetNowPlayingInfo returns an empty dict AND at least one player app is running (likelyBlocked heuristic), mark MediaRemote blocked for 60s and skip in the router. Saves ~50ms per refresh on restricted macOS versions and lets the first-pass AppleScript probe happen without a preceding MR round-trip. - Retries every 60s in case the gate state changes (macOS minor update / user-granted entitlement). 5. Parallel fallback probing - Old router was serial: MediaRemote → Spotify → Music → Chrome. Cold start worst-case 4-6s when all three AppleScript sources trip their 2s timeouts. - New router uses `async let` to fan out every live candidate concurrently. First-in-priority-order non-nil result wins. Cold start worst-case now ≈ slowest single AppleScript probe. 6. Sticky-source fast path survives - When the last-successful source is still a live candidate (its app still running, MR still not blocked), try it alone first. On steady-state playback this is one round-trip per refresh, same as before. 7. Transport control perceived latency - scheduleRefresh(after: 0.3) → 0.1 for togglePlay/next/prev/seek. UI already flips optimistically; the 100ms re-sync is enough to catch the real app state without feeling laggy. Reference: Atoll (github.com/Ebullioscopic/Atoll) uses a bundled mediaremote-adapter framework + Perl stream client to bypass the macOS 15.4 MediaRemote entitlement gate entirely. That's a bigger lift and left for a future phase — this commit wrings out the latency that's achievable without that adapter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 07:02:36 +00:00
<string>6</string>
<key>NSPrincipalClass</key>
<string>MusicPlugin.MusicPlugin</string>
<!--
Optional size hint for the expanded plugin panel.
Host reads these on plugin load and caps the expanded area to the
requested dimensions instead of the default ~620x780. Both keys
must be present. Range: width 280-1200, height 180-900. Values
outside that range are ignored and the host falls back to default.
-->
<key>MioPluginPreferredWidth</key>
<integer>440</integer>
<key>MioPluginPreferredHeight</key>
<integer>340</integer>
</dict>
</plist>