Repository navigation
fix: stabilize autoplay recommendations and shuffle behavior #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |
| - Frontend theming now maps legacy `lucky-*` classes to the Lucky purple/gold palette | ||
| - Frontend typography now uses Lucky type tokens (`Sora`, `Manrope`, `JetBrains Mono`) instead of the old default stack | ||
| - Vercel build now generates Prisma client before shared/frontend builds to prevent missing generated client errors | ||
| - Autoplay no longer keeps cycling the same recommendations; queue top-up now uses anti-repeat filtering and keeps a 4-track buffer | ||
| - Shuffle now works reliably while autoplay is enabled because autoplay maintains enough upcoming tracks | ||
| - Web music repeat mode now supports `autoplay` end-to-end (bot mapper, backend validation, shared/frontend types) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move the Line 43 documents a new end-to-end capability, not a bug fix. Keeping it under 🤖 Prompt for AI Agents |
||
| - OAuth callback now reuses the same redirect URI across auth start/callback token exchange, with forwarded-host fallback for proxied HTTPS deployments | ||
| - E2E stability improvements: dashboard/servers/track-history tests now use deterministic locators and route-delay handling | ||
|
Comment on lines
+41
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the PR reference to these release notes. These new unreleased bullets should point back to As per coding guidelines, "Update CHANGELOG.md with all changes, include breaking changes documentation, and reference issues and PRs". 🤖 Prompt for AI Agents |
||
|
|
||
| ### Changed | ||
|
|
||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -112,8 +112,10 @@ export function setupPlaybackRoutes(app: Express): void { | |
| asyncHandler(async (req: AuthenticatedRequest, res: Response) => { | ||
| const guildId = param(req.params.guildId) | ||
| const { mode } = req.body | ||
| if (!['off', 'track', 'queue'].includes(mode)) { | ||
| throw AppError.badRequest('Mode must be off, track, or queue') | ||
| if (!['off', 'track', 'queue', 'autoplay'].includes(mode)) { | ||
| throw AppError.badRequest( | ||
| 'Mode must be off, track, queue, or autoplay', | ||
| ) | ||
|
Comment on lines
114
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Move repeat-mode validation into the backend schema layer. This works, but it keeps HTTP input validation duplicated inside the route and creates another string-literal source of truth for repeat modes. Please push this through a Suggested direction- const { mode } = req.body
- if (!['off', 'track', 'queue', 'autoplay'].includes(mode)) {
- throw AppError.badRequest(
- 'Mode must be off, track, queue, or autoplay',
- )
- }
+ const { mode } = repeatModeBodySchema.parse(req.body)export const repeatModeBodySchema = z.object({
mode: z.enum(['off', 'track', 'queue', 'autoplay']),
})As per coding guidelines "packages/backend/src/**/*.ts: Validation must use Zod schemas in 🤖 Prompt for AI Agents |
||
| } | ||
| res.json( | ||
| await musicControlService.sendCommand( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import type { Request } from 'express' | ||
|
|
||
| const getForwardedHeader = ( | ||
| req: Request, | ||
| headerName: string, | ||
| ): string | undefined => { | ||
| const value = req.headers[headerName] | ||
| if (!value) return undefined | ||
| const raw = Array.isArray(value) ? value[0] : value | ||
| return raw.split(',')[0].trim() || undefined | ||
| } | ||
|
|
||
| const buildRequestRedirectUri = (req: Request): string => { | ||
| const forwardedProto = getForwardedHeader(req, 'x-forwarded-proto') | ||
| const forwardedHost = getForwardedHeader(req, 'x-forwarded-host') | ||
| const protocol = forwardedProto ?? req.protocol ?? 'http' | ||
| const host = | ||
| forwardedHost ?? | ||
| req.get('host') ?? | ||
| `localhost:${process.env.WEBAPP_PORT ?? '3000'}` | ||
|
|
||
| return `${protocol}://${host}/api/auth/callback` | ||
| } | ||
|
Comment on lines
+13
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if trust proxy is configured anywhere in the backend
rg -n "trust.?proxy" packages/backend/src/Repository: LucasSantana-Dev/Lucky Length of output: 48 🏁 Script executed: # First, let's read the actual file
cat -n packages/backend/src/utils/oauthRedirectUri.tsRepository: LucasSantana-Dev/Lucky Length of output: 1302 🏁 Script executed: # Check where and how getOAuthRedirectUri is used
rg -n "getOAuthRedirectUri\|buildRequestRedirectUri" packages/backend/src/ -B 2 -A 2Repository: LucasSantana-Dev/Lucky Length of output: 48 🏁 Script executed: # Look at server.ts to see if express app configuration includes trust proxy
cat -n packages/backend/src/server.ts | head -50Repository: LucasSantana-Dev/Lucky Length of output: 2101 🏁 Script executed: # Check how WEBAPP_FRONTEND_URL is used elsewhere
rg -n "WEBAPP_FRONTEND_URL" packages/ -B 2 -A 2Repository: LucasSantana-Dev/Lucky Length of output: 1924 🏁 Script executed: # Search for auth routes that might use this utility
fd "auth" packages/backend/src/routes/ --type fRepository: LucasSantana-Dev/Lucky Length of output: 145 🏁 Script executed: # Read the frontendOrigin.ts file to see the existing validation pattern
cat -n packages/backend/src/utils/frontendOrigin.tsRepository: LucasSantana-Dev/Lucky Length of output: 646 🏁 Script executed: # Search for any other forwarded header usage in the backend
rg -n "x-forwarded|req\.headers" packages/backend/src/ -t tsRepository: LucasSantana-Dev/Lucky Length of output: 484 🏁 Script executed: # Check the auth routes to see if and how getOAuthRedirectUri is used
cat -n packages/backend/src/routes/auth.ts | head -120Repository: LucasSantana-Dev/Lucky Length of output: 5135 🏁 Script executed: # Also check authCallback.ts
cat -n packages/backend/src/routes/authCallback.ts | head -80Repository: LucasSantana-Dev/Lucky Length of output: 3195 🏁 Script executed: # Search specifically for getOAuthRedirectUri import and usage
rg -n "getOAuthRedirectUri" packages/backend/src/Repository: LucasSantana-Dev/Lucky Length of output: 572 Add host validation to prevent header injection attacks. The utility reads 🤖 Prompt for AI Agents |
||
|
|
||
| export function getOAuthRedirectUri( | ||
| req: Request, | ||
| sessionRedirectUri?: string, | ||
| ): string { | ||
| return ( | ||
| sessionRedirectUri ?? | ||
| process.env.WEBAPP_REDIRECT_URI ?? | ||
| buildRequestRedirectUri(req) | ||
| ) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't swallow frontend test failures.
Line 48 makes this new test/coverage step non-blocking, so a broken frontend suite or bad coverage config can still leave the workflow green and Sonar running with incomplete data. Let the test step fail, and put
if: ${{ always() }}on the Sonar step if you still want the scan to execute.Suggested change
- name: Run frontend tests with coverage (lcov) run: npm run test --workspace=packages/frontend -- --coverage --coverage.reporter=lcov --coverage.reporter=text - continue-on-error: true - name: SonarCloud Scan + if: ${{ always() }} uses: SonarSource/sonarqube-scan-action@v6🤖 Prompt for AI Agents