Repository navigation
Add an audio-track selector for multi-audio videos - #28
Conversation
Closes #27 Multi-audio (dubbed) videos now get an audio-language menu next to the captions control (and an "Audio" entry in the overflow menu on narrow bars). It mirrors the existing captions plumbing: - YouTubeAudioTrack model + protocol methods on the playback controller - WebView JS reads getAvailableAudioTracks()/getAudioTrack() and switches by index into the player's live track array, so the opaque player track objects never cross the JS bridge (switching is exact) - YouTubePlayerService exposes audioTracks/activeAudioTrackId, refreshed alongside captions and quality - The control is hidden entirely for single-audio videos Display names are heuristic (opaque object → player-response audioTrack.displayName → "Audio N"); switching is exact regardless. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
| func availableAudioTracks() async -> [YouTubeAudioTrack] | ||
| func currentAudioTrackId() async -> String? | ||
| func setAudioTrack(id: String) |
There was a problem hiding this comment.
Suggestion: The test target's MockYouTubeWatchPlaybackController conforms directly to this protocol but does not implement these three newly required methods, so adding the requirements causes the test target to fail to compile until the mock is updated or default protocol implementations are provided. [api mismatch]
Severity Level: Critical 🚨
- ❌ Test target fails compilation for every build.
- ❌ All service tests are blocked by protocol nonconformance.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** Sources/Kaset/Services/Player/YouTubePlayerService.swift
**Line:** 37:39
**Comment:**
*Api Mismatch: The test target's `MockYouTubeWatchPlaybackController` conforms directly to this protocol but does not implement these three newly required methods, so adding the requirements causes the test target to fail to compile until the mock is updated or default protocol implementations are provided.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| self.audioTracks = await self.playbackController.availableAudioTracks() | ||
| self.activeAudioTrackId = await self.playbackController.currentAudioTrackId() |
There was a problem hiding this comment.
Suggestion: These awaits can suspend while the user navigates to another video. The only video-id guard runs before the quality, caption-state, and audio queries, so an old refresh can resume afterward and overwrite the new video's audioTracks and activeAudioTrackId state. Recheck currentVideo?.videoId == videoId immediately before applying these results, or associate the refresh with a generation token. [stale reference]
Severity Level: Critical 🚨
- ⚠️ New video can display previous audio tracks.
- ⚠️ Audio checkmark can identify the wrong active track.
- ⚠️ Quality and caption state can also be overwritten by the same race.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** Sources/Kaset/Services/Player/YouTubePlayerService.swift
**Line:** 1262:1263
**Comment:**
*Stale Reference: These awaits can suspend while the user navigates to another video. The only video-id guard runs before the quality, caption-state, and audio queries, so an old refresh can resume afterward and overwrite the new video's `audioTracks` and `activeAudioTrackId` state. Recheck `currentVideo?.videoId == videoId` immediately before applying these results, or associate the refresh with a generation token.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| /// Selects an alternate audio track (dubbed language) by id. | ||
| func selectAudioTrack(id: String) { | ||
| self.activeAudioTrackId = id | ||
| self.playbackController.setAudioTrack(id: id) | ||
| HapticService.toggle() |
There was a problem hiding this comment.
Suggestion: The service marks the requested track active before the JavaScript switch succeeds, while setAudioTrack has no completion result and swallows all player errors. If the player disappears during navigation or rejects the switch, the checkmark remains on the requested track even though playback still uses the previous track. Update the state only after confirming the switch, or refresh the active track after the command completes. [logic error]
Severity Level: Major ⚠️
- ⚠️ Audio menu checkmark can disagree with actual playback.
- ⚠️ Navigation or player errors can leave stale selection state.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** Sources/Kaset/Services/Player/YouTubePlayerService.swift
**Line:** 1325:1329
**Comment:**
*Logic Error: The service marks the requested track active before the JavaScript switch succeeds, while `setAudioTrack` has no completion result and swallows all player errors. If the player disappears during navigation or rejects the switch, the checkmark remains on the requested track even though playback still uses the previous track. Update the state only after confirming the switch, or refresh the active track after the command completes.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const resp = playerResponse(); | ||
| const fmts = (resp && resp.streamingData && resp.streamingData.adaptiveFormats) || []; | ||
| fmts.forEach(function(f) { | ||
| const dn = f && f.audioTrack && f.audioTrack.displayName; | ||
| if (dn && !seenName[dn]) { seenName[dn] = true; responseNames.push(dn); } | ||
| }); |
There was a problem hiding this comment.
Suggestion: responseNames is deduplicated across adaptive formats and then indexed against the live audio-track array. Adaptive formats can contain several formats for one language or use an order different from the player track array, so the menu can display one language while selecting a different track. Map each live track using its own identifying metadata rather than assuming these arrays share the same order. [logic error]
Severity Level: Major ⚠️
- ⚠️ Multi-audio menu can show incorrect language labels.
- ⚠️ Users may select tracks based on misleading names.
- ⚠️ Playback switching remains exact but discoverability is impaired.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** Sources/Kaset/Views/YouTube/YouTubeWatchWebView+Scripts.swift
**Line:** 1373:1378
**Comment:**
*Logic Error: `responseNames` is deduplicated across adaptive formats and then indexed against the live audio-track array. Adaptive formats can contain several formats for one language or use an order different from the player track array, so the menu can display one language while selecting a different track. Map each live track using its own identifying metadata rather than assuming these arrays share the same order.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
User description
Closes #27
Multi-audio (dubbed) videos now get an audio-language menu next to the captions control — and an "Audio" entry in the overflow menu when the player bar is narrow. Single-audio videos show nothing new.
How it works
Mirrors the existing captions plumbing end to end:
YouTubeAudioTrackmodel + three protocol methods on the playback controllergetAvailableAudioTracks()/getAudioTrack()and switches by index into the player's live track array, so the opaque player track objects never cross the JS bridge — switching is exactYouTubePlayerServiceexposesaudioTracks/activeAudioTrackId, refreshed alongside captions and qualityKnown ceiling
Display names are heuristic (opaque track object → player-response
audioTrack.displayName→ generic "Audio N"); switching is exact regardless. Marked with aponytail:comment pointing at the dump-and-map fix if names come out wrong on a real multi-audio video.🤖 Generated with Claude Code
CodeAnt-AI Description
Let viewers switch between available audio languages while watching multi-audio videos
What Changed
Impact
✅ Audio-language switching during playback✅ Audio controls shown only when applicable✅ Clear active-track indication💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.