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.2.1: real lyrics via LRCLIB + stream envelope fix + TimelineView vinyl Critical fix · adapter stream was silently empty v2.2.0 parsed the stream subprocess's JSON at the wrong layer. The `stream` mode wraps every emit as: {"type":"data","diff":<bool>,"payload":{title,...}} but Swift was decoding as AdapterStreamPayload directly (the shape used by `get`, which is flat). Result: every `stream rx` had title="" because the real data was nested inside payload, so hasTrack was always false and onUpdate never fired. Users saw "nothing playing" even while Apple Music was running. New AdapterStreamEnvelope decodes the wrapper, extracts payload, and also honours `diff: false` to reset currentInfo before merging (stale fields from the previous track were otherwise leaking). Added bootstrap path · cold start with music already playing When the adapter subprocess is spawned AFTER Apple Music is already playing, the stream's initial emit can be an empty baseline. A parallel one-shot `perl adapter.pl get` at spawn+300ms catches the current track immediately. Added file-based debug log at /tmp/mio-plugin-music-debug.log NSLog / os_log are unreliably filtered on macOS 15, and we can't attach Xcode to a plugin loaded from a signed host. A line-oriented log at a fixed path is the one channel that's always readable post- mortem. Lines include stream rx / bootstrap / parse failures. Real lyrics · LRCLIB integration - New LyricsService fetches synced lyrics via https://lrclib.net/api/get (exact) + /search (fallback), parses LRC format with regex [mm:ss.xx]. In-memory LRU cache (32 entries, 1-hour TTL). Negative-caches "not found" so obscure tracks don't re-hit the API every render. - NowPlayingState gains syncedLyrics + currentLyricIndex @Published. applyAdapterUpdate detects track changes and refreshes lyrics detached; the 1s playback timer updates currentLyricIndex. - DesktopLyricsViews replaces the placeholder text with real lyric text from syncedLyrics[currentLyricIndex ± 1]. Falls back to sensible dots when no lyrics loaded / instrumentals. Bonus · robust vinyl spin via TimelineView withAnimation(.linear.repeatForever) loses the animation when SwiftUI re-creates the view (window hide/show, style switch). Replaced with TimelineView driven by wall-clock — angle = (elapsed * 45°/s) % 360. Smooth across hours, no drift, pauses correctly via `paused: !isPlaying`. Borrowed approach from Atoll (github.com/Ebullioscopic/Atoll) MusicManager.swift:756-935: same LRCLIB endpoints, same LRC regex shape, same per-second sync model. Credited in LICENSE-THIRD-PARTY. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:55:04 +00:00
<string>2.2.1</string>
<key>CFBundleVersion</key>
v2.2.1: real lyrics via LRCLIB + stream envelope fix + TimelineView vinyl Critical fix · adapter stream was silently empty v2.2.0 parsed the stream subprocess's JSON at the wrong layer. The `stream` mode wraps every emit as: {"type":"data","diff":<bool>,"payload":{title,...}} but Swift was decoding as AdapterStreamPayload directly (the shape used by `get`, which is flat). Result: every `stream rx` had title="" because the real data was nested inside payload, so hasTrack was always false and onUpdate never fired. Users saw "nothing playing" even while Apple Music was running. New AdapterStreamEnvelope decodes the wrapper, extracts payload, and also honours `diff: false` to reset currentInfo before merging (stale fields from the previous track were otherwise leaking). Added bootstrap path · cold start with music already playing When the adapter subprocess is spawned AFTER Apple Music is already playing, the stream's initial emit can be an empty baseline. A parallel one-shot `perl adapter.pl get` at spawn+300ms catches the current track immediately. Added file-based debug log at /tmp/mio-plugin-music-debug.log NSLog / os_log are unreliably filtered on macOS 15, and we can't attach Xcode to a plugin loaded from a signed host. A line-oriented log at a fixed path is the one channel that's always readable post- mortem. Lines include stream rx / bootstrap / parse failures. Real lyrics · LRCLIB integration - New LyricsService fetches synced lyrics via https://lrclib.net/api/get (exact) + /search (fallback), parses LRC format with regex [mm:ss.xx]. In-memory LRU cache (32 entries, 1-hour TTL). Negative-caches "not found" so obscure tracks don't re-hit the API every render. - NowPlayingState gains syncedLyrics + currentLyricIndex @Published. applyAdapterUpdate detects track changes and refreshes lyrics detached; the 1s playback timer updates currentLyricIndex. - DesktopLyricsViews replaces the placeholder text with real lyric text from syncedLyrics[currentLyricIndex ± 1]. Falls back to sensible dots when no lyrics loaded / instrumentals. Bonus · robust vinyl spin via TimelineView withAnimation(.linear.repeatForever) loses the animation when SwiftUI re-creates the view (window hide/show, style switch). Replaced with TimelineView driven by wall-clock — angle = (elapsed * 45°/s) % 360. Smooth across hours, no drift, pauses correctly via `paused: !isPlaying`. Borrowed approach from Atoll (github.com/Ebullioscopic/Atoll) MusicManager.swift:756-935: same LRCLIB endpoints, same LRC regex shape, same per-second sync model. Credited in LICENSE-THIRD-PARTY. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 23:55:04 +00:00
<string>10</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>