Repository navigation
fix(bot): Spotify-first provider order + Queue Error recovery - #581
Conversation
Extractor registration order: Spotify → YouTube → SoundCloud → others. SpotifyExtractor gets SPOTIFY_CLIENT_ID/SECRET credentials so spsearch queries work. Text searches now try Spotify before YouTube falling back. Also fixes Queue Error not triggering recovery: adds 'Bridge exhausted' to the isStreamExtractionError check so the YouTube retry kicks in instead of showing a raw discord-player Queue Error embed.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 17 minutes and 49 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR implements Spotify-first search for the play command by adding a Changes
Sequence DiagramssequenceDiagram
actor User
participant PlayCommandProcessor
participant handleSpotifySearch
participant Player as Discord Player
participant SpotifyAPI
participant handleYouTubeSearch
User->>PlayCommandProcessor: play query
PlayCommandProcessor->>handleSpotifySearch: search(query)
handleSpotifySearch->>Player: search(query, {searchEngine: SPOTIFY_SEARCH})
Player->>SpotifyAPI: fetch tracks
SpotifyAPI-->>Player: no results
Player-->>handleSpotifySearch: empty SearchResult
handleSpotifySearch-->>PlayCommandProcessor: {success: false}
PlayCommandProcessor->>handleYouTubeSearch: search(query)
handleYouTubeSearch->>Player: search(query, {searchEngine: YOUTUBE_SEARCH})
Player->>SpotifyAPI: fetch tracks
SpotifyAPI-->>Player: tracks found
Player-->>handleYouTubeSearch: SearchResult
handleYouTubeSearch-->>PlayCommandProcessor: {success: true, tracks}
PlayCommandProcessor-->>User: queue tracks
sequenceDiagram
participant Bot as Bot Initialization
participant registerExtractorsInOrder
participant registerSpotifyExtractor
participant registerRemainingExtractors
participant Player as Discord Player<br/>Extractors
Bot->>registerExtractorsInOrder: async start
registerExtractorsInOrder->>registerSpotifyExtractor: register Spotify
registerSpotifyExtractor->>Player: register(SpotifyExtractor)
alt Spotify registration succeeds
Player-->>registerSpotifyExtractor: registered
registerSpotifyExtractor-->>registerExtractorsInOrder: complete
else Spotify registration fails
Player--xregisterSpotifyExtractor: error
registerSpotifyExtractor-->>registerExtractorsInOrder: warn & continue
end
registerExtractorsInOrder->>registerRemainingExtractors: register others
registerRemainingExtractors->>Player: register(SoundCloud)
registerRemainingExtractors->>Player: register(AppleMusic)
registerRemainingExtractors->>Player: register(Vimeo)
registerRemainingExtractors->>Player: register(Attachments)
Player-->>registerRemainingExtractors: all registered
registerRemainingExtractors-->>registerExtractorsInOrder: complete
registerExtractorsInOrder-->>Bot: ready
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- handleSpotifySearch: success, no results, error paths - PlayCommandProcessor.handleSearchQuery: spotify-win and yt-fallback - playerFactory: spotify extractor error path, remaining extractor error path
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bot/src/handlers/player/playerFactory.ts`:
- Around line 44-48: The player is being exposed before extractor registration
finishes because registerExtractors calls registerExtractorsInOrder() without
awaiting; change the flow so createPlayer (or the function that returns the
Player) awaits extractor bootstrap instead of fire-and-forget: update
registerExtractors to return the Promise from registerExtractorsInOrder (remove
the .catch swallow), and in createPlayer (or the factory that returns the
Player) await registerExtractors(player) and propagate errors so the player is
only returned after registerExtractorsInOrder completes successfully; keep error
logging but do not allow a partially-initialized extractor registry to be
visible to command handlers.
- Around line 68-74: registerSpotifyExtractor and registerRemainingExtractors
currently ignore the return value of player.extractors.register (which can be
null on failure); change both functions to capture the result of await
player.extractors.register(...) into a variable, check for null, and only call
infoLog('Registered ...') when the result is non-null; if null, log an error (or
warning) indicating registration failed and include the extractor name (e.g.,
SpotifyExtractor or relevant extractor identifiers) so behavior matches the
null-check logic already used in loadYoutubeExtractor.
In `@packages/bot/tests/handlers/player/playerFactory.test.ts`:
- Around line 160-181: The test's current check uses typeof ExtractorClass ===
'function', which makes hasSpotify true for any extractor; update the loop and
assertions to explicitly detect the Spotify extractor by its name rather than
any function: change the hasSpotify check inside the loop that inspects
player.extractors.register.mock.calls to only consider the ExtractorClass name
=== 'MockSpotifyExtractor' (remove the typeof branch), wait until that specific
registration appears, then assert that the first call to
player.extractors.register (firstCall) is defined and that firstCall[0].name ===
'MockSpotifyExtractor' to guarantee Spotify was registered first.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a1b9ae3a-9630-4883-a579-4a4b689f3e2d
📒 Files selected for processing (7)
packages/bot/src/functions/music/commands/play/processor.tspackages/bot/src/functions/music/commands/play/youtubeHandler.tspackages/bot/src/handlers/player/errorHandlers.tspackages/bot/src/handlers/player/playerFactory.tspackages/bot/tests/functions/music/commands/play/processor.test.tspackages/bot/tests/functions/music/commands/play/youtubeHandler.test.tspackages/bot/tests/handlers/player/playerFactory.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: SonarCloud Scan
- GitHub Check: Quality Gates
🔇 Additional comments (1)
packages/bot/src/handlers/player/errorHandlers.ts (1)
321-326: Good fix for bridge-exhaustion recovery path.Adding
error.message.includes('Bridge exhausted')correctly classifies that failure and reuses the existing recovery flow instead of exposing a raw Queue Error.
- registerSpotifyExtractor and registerRemainingExtractors now warn when player.extractors.register() returns null (mirrors existing null-check in loadYoutubeExtractor) - fix overly-broad SpotifyExtractor test detection (was matching any function, now checks MockSpotifyExtractor name) - add null-return path tests for both functions
Fixed: null-check added to extractor registration functions; test updated to check MockSpotifyExtractor name specifically.
|
* fix(bot): Spotify-first provider order + Queue Error recovery Extractor registration order: Spotify → YouTube → SoundCloud → others. SpotifyExtractor gets SPOTIFY_CLIENT_ID/SECRET credentials so spsearch queries work. Text searches now try Spotify before YouTube falling back. Also fixes Queue Error not triggering recovery: adds 'Bridge exhausted' to the isStreamExtractionError check so the YouTube retry kicks in instead of showing a raw discord-player Queue Error embed. * test(bot): add coverage for spotify-first provider changes - handleSpotifySearch: success, no results, error paths - PlayCommandProcessor.handleSearchQuery: spotify-win and yt-fallback - playerFactory: spotify extractor error path, remaining extractor error path * fix(bot): check null return from extractor registration - registerSpotifyExtractor and registerRemainingExtractors now warn when player.extractors.register() returns null (mirrors existing null-check in loadYoutubeExtractor) - fix overly-broad SpotifyExtractor test detection (was matching any function, now checks MockSpotifyExtractor name) - add null-return path tests for both functions



Problem
YouTube default provider — text searches always resolved to YouTube even though Spotify produces cleaner metadata with far fewer duplicate entries. The
handleSearchQuerypath hardcodedhandleYouTubeSearch.Queue Error not recovering — when
createResilientStreamexhausted all fallbacks it threwBridge exhausted: no stream for "...". TheisStreamExtractionErrorcheck inerrorHandlers.tsdidn't match that message, so no YouTube retry was attempted and Discord showed the raw "Queue Error" embed.Fixes
playerFactory.ts— extractor registration orderBefore:
loadMulti(DefaultExtractors)→ SoundCloud, Spotify, Apple Music, Vimeo, Attachments → YouTube (async, last)After: Spotify → YouTube → SoundCloud → Apple Music → Vimeo → Attachments
SpotifyExtractorregistered first withSPOTIFY_CLIENT_ID/SPOTIFY_CLIENT_SECRETsospsearch:queries resolveprocessor.ts+youtubeHandler.ts— Spotify-first searchText query flow (
/play some song name):QueryType.SPOTIFY_SEARCH— silently returnssuccess: falseon no resultserrorHandlers.ts— Queue Error fixAdded
error.message.includes('Bridge exhausted')toisStreamExtractionErrorso bridge exhaustion triggers the same YouTube retry + channel notification flow as other stream failures.Summary by CodeRabbit
New Features
Bug Fixes
Tests