feat(track-log): implement MusicKit event capture and debug logging#17
Merged
flexiondotorg merged 9 commits intomainfrom Mar 22, 2026
Merged
feat(track-log): implement MusicKit event capture and debug logging#17flexiondotorg merged 9 commits intomainfrom
flexiondotorg merged 9 commits intomainfrom
Conversation
… hub - Extract getAssetPath() to src/paths.ts for reuse across modules - Create Player class in src/player.ts as EventEmitter hub for track events - Update src/tray.ts to import getAssetPath() from shared paths module These changes establish the foundation for track logging: a centralised paths utility eliminates duplication, and the Player event hub provides the integration point for dispatching track change events to logging consumers. Signed-off-by: Martin Wimpress <code@wimpress.io>
- Inject IIFE with re-entry guard to prevent duplicate listeners on SPA navigation - Poll for MusicKit availability with 500ms intervals - Attach six event listeners: playbackStateDidChange, nowPlayingItemDidChange, playbackTimeDidChange, repeatModeDidChange, shuffleModeDidChange, volumeDidChange - Expose control object at window.__sidra with nine control methods for testing - IPC bridge implemented (main process wiring) Signed-off-by: Martin Wimpress <code@wimpress.io>
- Inject musicKitHook.js via executeJavaScript() in did-finish-load handler - Instantiate Player after menu setup completion - Register six ipcMain.on listeners forwarding track change events to player handlers Completes end-to-end pipeline: renderer hook captures MusicKit events → IPC forwards payloads → main process player logs and re-emits. Signed-off-by: Martin Wimpress <code@wimpress.io>
…intervals - Add lastTimeLogAt instance field to track last log timestamp - Throttle debug output to max once per 10 seconds while maintaining event emission on every tick - Preserves MPRIS and integration compatibility by keeping events unthrottled Event emission frequency unchanged; only log output is rate-limited to reduce debug noise during continuous playback. Signed-off-by: Martin Wimpress <code@wimpress.io>
- Add PLAYBACK_STATES lookup map to decode numeric state values (0→none, 1→loading, 2→playing, 3→paused, 4→stopped, 5→ended, 6→seeking, 7→waiting, 8→stalled, 9→completed) - Decode state before logging for improved readability - Preserve original numeric payload for event emission to MPRIS and other downstream consumers Improves log readability without affecting message content or APIs. Signed-off-by: Martin Wimpress <code@wimpress.io>
…bug logs - Add REPEAT_MODES and SHUFFLE_MODES lookup maps to translate numeric payloads to human-readable strings (repeat: 0→none, 1→one, 2→all; shuffle: 0→off, 1→songs) - Decode values before logging in handleRepeatModeDidChange and handleShuffleModeDidChange for improved readability - Pass original numeric payloads unchanged to this.emit() to preserve compatibility with MPRIS and other downstream consumers Signed-off-by: Martin Wimpress <code@wimpress.io>
The music.apple.com volume slider writes directly to HTMLMediaElement.volume, bypassing MusicKit's setter where volumeDidChange would normally fire. Poll mk.volume at 250ms intervals and emit IPC events when the value changes to catch all volume adjustments. The existing addEventListener listener is preserved and continues to work for volume changes that do trigger the event. Signed-off-by: Martin Wimpress <code@wimpress.io>
Contributor
There was a problem hiding this comment.
1 issue found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="assets/musicKitHook.js">
<violation number="1" location="assets/musicKitHook.js:51">
P2: Volume changes can be emitted twice because `lastVolume` is not synchronised in the `volumeDidChange` listener, so the poller re-emits the same update.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
When MusicKit's volumeDidChange event fires, the lastVolume guard variable is now updated before sending the IPC message. This prevents the 250ms polling fallback from seeing a stale lastVolume value and emitting a duplicate volume change event. Previously, rapid volume changes from window.__sidra.setVolume() could be reported twice: once by the event listener and again by the poller, because the guard check happened after the IPC send. Signed-off-by: Martin Wimpress <code@wimpress.io>
…round - AGENTS.md: Added src/paths.ts to project structure and documented volume polling workaround for music.apple.com's slider bypassing MusicKit's volumeDidChange event - docs/SPECIFICATION.md: Added MusicKit.js enum values subsection with PlaybackStates (0-9), RepeatMode (0-2), and ShuffleMode (0-1) mappings; explained HTMLMediaElement volume event workaround and polling fallback; documented audioTraits, bitrate, and codec availability caveats Signed-off-by: Martin Wimpress <code@wimpress.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wire MusicKit.js event capture through to main process with debug logging.
The renderer hook injects into music.apple.com, captures track changes and
playback events, and forwards them via IPC to a Player EventEmitter that
logs at debug level. Includes event enum decoding and volume polling for
complete visibility into playback state.
Changes
getAssetPath()tosrc/paths.tsPlayerEventEmitter class to receive IPC events and log at debug levelassets/musicKitHook.jswith all six event listenerssrc/main.tsdid-finish-loadhandlerplaybackTimeDidChangelogging to 10s intervals (event emits every tick for MPRIS)Testing
Performed manual testing with
just runandjust run-debug:[Sidra] MusicKit hooked successfullyin consolejust buildandjust lintpassArchitecture
src/paths.ts(shared utility),src/player.ts(event hub),assets/musicKitHook.js(renderer hook)src/tray.ts,src/main.tsConstraints Maintained
_stateinternals or undocumented propertieswebContents.executeJavaScript()pattern