Skip to content

feat(autoplay): preferred artists shape VC playback + drop dead Spotify endpoints - #719

Closed
LucasSantana-Dev wants to merge 1 commit into
mainfrom
feat/preferred-artists-vc-playback-and-spotify-cleanup
Closed

LucasSantana-Dev wants to merge 1 commit into
mainfrom
feat/preferred-artists-vc-playback-and-spotify-cleanup

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented Apr 19, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR completes two coordinated improvements to the autoplay system:

  1. Removes dead Spotify endpoints that have been silently failing since Spotify deprecated them for new apps in November 2024:

    • /v1/recommendations with audio-feature constraining
    • /v1/audio-features and /v1/audio-features/* batch endpoint
    • Audio-feature mood matching and reranking infrastructure
    • Net effect: eliminates latency overhead from endpoints that were no longer functional
  2. Introduces preferred-artist seeding to wire the user's Preferred Artists list (saved on the Musical Taste page) directly into the autoplay queue:

    • New collectPreferredArtistCandidates() fetches top tracks from each preferred artist via Last.fm
    • Scores candidates with a +0.5 boost (0.3 base score + 0.2 extra) to ensure preferred-artist tracks reliably land
    • Runs immediately after collectLastFmCandidates in the replenisher
    • Aggregates preferred artist names across all VC members

Test plan

  • Run: npm run test --workspace=packages/bot -- spotifyApi spotifyRecommender candidateCollector replenisher preferredArtistSeeder feedbackService queueManipulation candidateScorer
  • Run: npm run type:check --workspace=packages/bot
  • Run: npm run lint --workspace=packages/bot
  • Verify no regressions in queueReplenishment, seedCandidateSelection, and candidateScoring
  • Verify preferred artists appear in autoplay output when set on Musical Taste page

Files changed

Deleted functions:

  • spotifyApi.ts: getSpotifyRecommendations, SpotifyRecommendationTrack, SpotifyAudioFeatureConstraints, getAudioFeatures, getBatchAudioFeatures, SpotifyAudioFeatures
  • spotifyRecommender.ts: collectSpotifyRecommendationCandidates
  • queueManipulation.ts: getTrackAudioFeatures, enrichWithAudioFeatures, audioFeatureCache

New functions:

  • lastFmApi.ts: getArtistTopTracks(artist, limit = 10)
  • feedbackService.ts: getPreferredArtistNames(guildId, userId)
  • preferredArtistSeeder.ts: collectPreferredArtistCandidates(...)

Modified call sites:

  • replenisher.ts: aggregates preferred artist names, calls new seeder after Last.fm seeder
  • candidateCollector.ts: removed currentFeatures parameter, removed Spotify recs collector call

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Last.fm artist top tracks support for autoplay recommendations
    • Introduced user-preferred artist selection for personalized autoplay candidate discovery
    • Added preference tracking for artist recommendations
  • Removed Features

    • Removed Spotify audio-feature-based recommendations
    • Removed Spotify recommendation API integration
  • Tests

    • Updated test coverage for feature changes

…cs/audio-features

This commit completes two major improvements to the autoplay system:

1. Removes dead Spotify endpoints that have been silently failing since November 2024:
   - Deleted: /v1/recommendations with audio-feature constraining
   - Deleted: /v1/audio-features and /v1/audio-features/* endpoints
   - Removed: SpotifyAudioFeatures type and audio-feature cache infrastructure
   - Rationale: Spotify deprecated these for new apps; the feature was adding latency without benefit

2. Introduces preferred-artist-seeder to make the user's Preferred Artists list (saved on the Musical Taste page) directly seed the autoplay queue:
   - Added: getArtistTopTracks() to lastFmApi to fetch an artist's top tracks from Last.fm
   - Added: collectPreferredArtistCandidates() in new preferredArtistSeeder.ts, which:
     - Fetches top tracks for each preferred artist (cap 5 per call, 6 tracks each)
     - Resolves each via searchLastFmQuery (existing pattern)
     - Scores with calculateRecommendationScore + 0.5 boost (0.3 base + 0.2 extra)
     - Adds to candidate pool immediately after collectLastFmCandidates in replenisher
   - Added: getPreferredArtistNames() to feedbackService to read artist names from DB
   - Replenisher now aggregates preferred artist names across all VC members

Removes audio-feature mood matching infrastructure entirely (out of scope for reimplement via another provider). The Preferred Artists feature now ensures at least some preferred-artist tracks always reach the queue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 19, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lucky Ready Ready Preview, Comment Apr 19, 2026 2:46pm

Request Review

@coderabbitai

coderabbitai Bot commented Apr 19, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This pull request replaces Spotify audio-feature-based recommendation enrichment with a Last.fm-powered preferred artist candidate collection system. It removes audio feature fetching, enrichment logic, and Spotify recommendation candidate collection, while adding Last.fm artist top track fetching and a new preferred artist seeder module that queries user-preferred artists from the database.

Changes

Cohort / File(s) Summary
Last.fm API Expansion
packages/bot/src/lastfm/lastFmApi.ts, packages/bot/src/lastfm/index.ts
Added new getArtistTopTracks function to fetch top tracks for an artist from Last.fm API and re-exported it from the module's public interface.
Spotify API Removal
packages/bot/src/spotify/spotifyApi.ts, packages/bot/src/spotify/spotifyApi.spec.ts
Removed getSpotifyRecommendations, getAudioFeatures, getBatchAudioFeatures functions and their associated types (SpotifyRecommendationTrack, SpotifyAudioFeatures, SpotifyAudioFeatureConstraints) along with 396 lines of test coverage.
Feedback Service Enhancement
packages/bot/src/services/musicRecommendation/feedbackService.ts
Added getPreferredArtistNames method to query database for user-preferred artist names within a guild, returning a set of trimmed artist names with error fallback.
Autoplay Candidate Collection Removal
packages/bot/src/utils/music/autoplay/candidateCollector.ts, packages/bot/src/utils/music/autoplay/candidateCollector.spec.ts
Removed currentFeatures parameter and Spotify recommendations candidate collection call; updated documentation to reflect Last.fm-only orchestration.
Autoplay Audio Feature Enrichment Removal
packages/bot/src/utils/music/autoplay/candidateScorer.ts, packages/bot/src/utils/music/autoplay/candidateScorer.spec.ts
Deleted enrichWithAudioFeatures export, audio feature caching, and 257 lines of enrichment test coverage; retained genre-family scoring infrastructure.
Spotify Recommendation Candidate Removal
packages/bot/src/utils/music/autoplay/spotifyRecommender.ts
Removed collectSpotifyRecommendationCandidates export and all Spotify token resolution, recommendations fetching, and feature-based scoring logic; retained searchSeedCandidates.
Preferred Artist Candidate Collection
packages/bot/src/utils/music/autoplay/preferredArtistSeeder.ts, packages/bot/src/utils/music/autoplay/preferredArtistSeeder.spec.ts
Added new module with collectPreferredArtistCandidates function that fetches preferred artist top tracks via Last.fm, performs player searches, and populates autoplay candidate map with scoring; includes comprehensive test coverage for nominal and edge cases.
Autoplay Replenishment Logic
packages/bot/src/utils/music/autoplay/replenisher.ts
Added preferred artist name fetching via feedback service; replaced audio feature enrichment with direct candidate usage; updated candidate collection orchestration to exclude audio features parameter.
Queue Manipulation Audio Feature Removal
packages/bot/src/utils/music/queueManipulation.ts
Removed getTrackAudioFeatures and enrichWithAudioFeatures implementations including Spotify token lookup, feature caching, and genre-based scoring adjustments.

Sequence Diagram(s)

sequenceDiagram
    participant Replenisher as Replenisher
    participant FeedbackService as Feedback Service
    participant Database as Prisma Database
    participant LastFM as Last.fm API
    participant Queue as Guild Queue
    participant Scorer as Candidate Scorer
    participant Candidates as Candidates Map

    Replenisher->>FeedbackService: getPreferredArtistNames(guildId, userId)
    FeedbackService->>Database: Query userArtistPreference<br/>(preference='prefer')
    Database-->>FeedbackService: Return artist names
    FeedbackService-->>Replenisher: Set<artistNames>
    
    Replenisher->>Replenisher: collectPreferredArtistCandidates(...)
    loop For each preferred artist
        Replenisher->>LastFM: getArtistTopTracks(artist, limit=6)
        LastFM-->>Replenisher: Track array
        loop For each top track
            Replenisher->>Queue: Search queue by track
            Queue-->>Replenisher: Search results
            Replenisher->>Scorer: calculateRecommendationScore(track)
            Scorer-->>Replenisher: Score
            Replenisher->>Candidates: upsertScoredCandidate(reason='preferred artist')
        end
    end
    Candidates-->>Replenisher: Populated candidates map
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

bot, enhancement, size/xl

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the two main changes: introducing preferred-artist-based autoplay seeding and removing deprecated Spotify endpoints.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/preferred-artists-vc-playback-and-spotify-cleanup

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/bot/src/utils/music/autoplay/replenisher.ts (2)

217-247: ⚠️ Potential issue | 🟠 Major

Actually invoke the preferred-artist seeder after Last.fm collection.

allPreferredNames is fetched and collectPreferredArtistCandidates is imported, but the seeder is never called, so the new preferred-artist feature is currently inert.

Wire preferred artists into replenishment
         const preferredArtistKeys = new Set(
             allPreferredSets.flatMap((s) => [...s]),
         )
         const blockedArtistKeys = new Set(allBlockedSets.flatMap((s) => [...s]))
+        const preferredArtistNames = new Set(
+            allPreferredNames.flatMap((s) => [...s]),
+        )
             debugLog({
                 message: 'Autoplay: last.fm candidates',
                 data: {
                     guildId,
                     added: candidates.size - beforeLastFm,
                     total: candidates.size,
                     source: 'lastfm',
                 },
             })
+
+            if (preferredArtistNames.size > 0) {
+                const beforePreferredArtists = candidates.size
+                await collectPreferredArtistCandidates(
+                    queue,
+                    requestedBy,
+                    preferredArtistNames,
+                    excludedUrls,
+                    excludedKeys,
+                    dislikedWeights,
+                    likedWeights,
+                    preferredArtistKeys,
+                    blockedArtistKeys,
+                    currentTrack,
+                    recentArtists,
+                    candidates,
+                    autoplayMode,
+                    artistFrequency,
+                    implicitDislikeKeys,
+                    implicitLikeKeys,
+                    sessionMood,
+                )
+                debugLog({
+                    message: 'Autoplay: preferred artist candidates',
+                    data: {
+                        guildId,
+                        added: candidates.size - beforePreferredArtists,
+                        total: candidates.size,
+                        source: 'preferred_artists',
+                    },
+                })
+            }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/music/autoplay/replenisher.ts` around lines 217 - 247,
The preferred-artist seeder is fetched but never executed; after the call to
collectLastFmCandidates (inside the requestedBy?.id block) invoke
collectPreferredArtistCandidates using the same queue/context variables and the
fetched allPreferredNames so it can add to the candidates Set (e.g., call
collectPreferredArtistCandidates(queue, requestedBy, excludedUrls, excludedKeys,
dislikedWeights, likedWeights, preferredArtistKeys, blockedArtistKeys,
currentTrack, recentArtists, candidates, autoplayMode, artistFrequency,
implicitDislikeKeys, implicitLikeKeys, sessionMood, contributionWeights,
allPreferredNames) or otherwise match the existing parameter order), then update
or log the delta (like the existing debugLog that reports candidates.size
change) so preferred-artist additions are visible.

97-147: ⚠️ Potential issue | 🔴 Critical

Fix the malformed Promise.all argument list.

The getPreferredArtistNames promise (lines 145-150) is positioned outside the array passed to Promise.all due to a closing bracket and comma at line 144, causing a TypeScript compilation error. Move the closing bracket to line 150 so that getPreferredArtistNames becomes the ninth array element.

Compile fix
-            ),
-        ],
-            Promise.all(
+            ),
+            Promise.all(
                 allMemberIds.map((id) =>
                     recommendationFeedbackService.getPreferredArtistNames(
                         queue.guild.id,
                         id,
                     ),
                 ),
             ),
         ])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/music/autoplay/replenisher.ts` around lines 97 - 147,
The Promise.all call that populates [likedWeights, ..., allPreferredNames] is
malformed: the Promise for
recommendationFeedbackService.getPreferredArtistNames(queue.guild.id, id) is
placed outside the array due to an early closing bracket, causing a TS compile
error; fix it by moving the closing bracket/comma so that the Promise.all([...])
wrapper includes the Promise.all(allMemberIds.map(id =>
recommendationFeedbackService.getPreferredArtistNames(queue.guild.id, id))) as
the ninth element, ensuring the destructured variable allPreferredNames receives
that result and the outer await Promise.all([...]) contains exactly nine items.
🤖 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/services/musicRecommendation/feedbackService.ts`:
- Around line 474-500: The export for recommendationFeedbackService is currently
placed inside the RecommendationFeedbackService class body causing a syntax
error; move the class closing brace so that the class ends immediately after the
getPreferredArtistNames method (i.e., close the RecommendationFeedbackService
class right after getPreferredArtistNames) and then keep the export const
recommendationFeedbackService = new RecommendationFeedbackService(...) at module
scope; verify the class name RecommendationFeedbackService and the exported
identifier recommendationFeedbackService match after the change.

In `@packages/bot/src/utils/music/autoplay/candidateCollector.ts`:
- Around line 56-60: Update the header comment in candidateCollector.ts (the
aggregator that orchestrates Last.fm + YouTube candidate collection) to remove
the stale "Spotify" / "seed track similar searches (Spotify)" mention and ensure
it only references the actual sources (YouTube and
Last.fm/collectLastFmCandidates). Edit the top comment block near the
collect/replenish logic (the candidate collector/collectCandidates function) so
wording matches current behavior: "Seed track similar searches (YouTube)" and
"Last.fm + YouTube" without any Spotify references.

---

Outside diff comments:
In `@packages/bot/src/utils/music/autoplay/replenisher.ts`:
- Around line 217-247: The preferred-artist seeder is fetched but never
executed; after the call to collectLastFmCandidates (inside the requestedBy?.id
block) invoke collectPreferredArtistCandidates using the same queue/context
variables and the fetched allPreferredNames so it can add to the candidates Set
(e.g., call collectPreferredArtistCandidates(queue, requestedBy, excludedUrls,
excludedKeys, dislikedWeights, likedWeights, preferredArtistKeys,
blockedArtistKeys, currentTrack, recentArtists, candidates, autoplayMode,
artistFrequency, implicitDislikeKeys, implicitLikeKeys, sessionMood,
contributionWeights, allPreferredNames) or otherwise match the existing
parameter order), then update or log the delta (like the existing debugLog that
reports candidates.size change) so preferred-artist additions are visible.
- Around line 97-147: The Promise.all call that populates [likedWeights, ...,
allPreferredNames] is malformed: the Promise for
recommendationFeedbackService.getPreferredArtistNames(queue.guild.id, id) is
placed outside the array due to an early closing bracket, causing a TS compile
error; fix it by moving the closing bracket/comma so that the Promise.all([...])
wrapper includes the Promise.all(allMemberIds.map(id =>
recommendationFeedbackService.getPreferredArtistNames(queue.guild.id, id))) as
the ninth element, ensuring the destructured variable allPreferredNames receives
that result and the outer await Promise.all([...]) contains exactly nine items.
🪄 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: 671c135d-2bef-4c4d-bb49-c82fd7471258

📥 Commits

Reviewing files that changed from the base of the PR and between 923fe82 and 09252b2.

📒 Files selected for processing (14)
  • packages/bot/src/lastfm/index.ts
  • packages/bot/src/lastfm/lastFmApi.ts
  • packages/bot/src/services/musicRecommendation/feedbackService.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
  • packages/bot/src/spotify/spotifyApi.ts
  • packages/bot/src/utils/music/autoplay/candidateCollector.spec.ts
  • packages/bot/src/utils/music/autoplay/candidateCollector.ts
  • packages/bot/src/utils/music/autoplay/candidateScorer.spec.ts
  • packages/bot/src/utils/music/autoplay/candidateScorer.ts
  • packages/bot/src/utils/music/autoplay/preferredArtistSeeder.spec.ts
  • packages/bot/src/utils/music/autoplay/preferredArtistSeeder.ts
  • packages/bot/src/utils/music/autoplay/replenisher.ts
  • packages/bot/src/utils/music/autoplay/spotifyRecommender.ts
  • packages/bot/src/utils/music/queueManipulation.ts
💤 Files with no reviewable changes (6)
  • packages/bot/src/utils/music/autoplay/candidateCollector.spec.ts
  • packages/bot/src/spotify/spotifyApi.spec.ts
  • packages/bot/src/utils/music/queueManipulation.ts
  • packages/bot/src/utils/music/autoplay/candidateScorer.spec.ts
  • packages/bot/src/spotify/spotifyApi.ts
  • packages/bot/src/utils/music/autoplay/spotifyRecommender.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). (1)
  • GitHub Check: SonarCloud Scan
🧰 Additional context used
🪛 Biome (2.4.11)
packages/bot/src/services/musicRecommendation/feedbackService.ts

[error] 496-496: expected a semicolon to end the class property, but found none

(parse)


[error] 496-496: expected a semicolon to end the class property, but found none

(parse)

🪛 GitHub Actions: CI/CD Pipeline
packages/bot/src/utils/music/autoplay/replenisher.ts

[error] 147-147: TypeScript compilation failed (tsc) with TS1135: Argument expression expected.

🔇 Additional comments (5)
packages/bot/src/lastfm/index.ts (1)

9-9: LGTM — export is wired correctly.

getArtistTopTracks is exposed through the Last.fm barrel module for the preferred-artist seeder.

packages/bot/src/lastfm/lastFmApi.ts (1)

324-350: LGTM — helper follows the existing Last.fm wrapper pattern.

The config guard, response mapping, and swallowed failure behavior are consistent with the other Last.fm read helpers.

packages/bot/src/utils/music/autoplay/candidateScorer.ts (1)

34-61: LGTM — genre family mapping remains straightforward.

No concerns with the moved constant itself.

packages/bot/src/utils/music/autoplay/preferredArtistSeeder.spec.ts (1)

23-130: Good coverage for the new seeder behavior.

The suite covers candidate creation, empty preferred-artist input, and duration-based rejection.

packages/bot/src/utils/music/autoplay/preferredArtistSeeder.ts (1)

11-15: No changes needed—imports are correct.

The functions shouldIncludeCandidate and upsertScoredCandidate are re-exported from queueManipulation for backward compatibility (lines 86–91), and normalizeTrackKey is defined and exported directly in that module. The import statement in preferredArtistSeeder.ts is correct as written.

Comment on lines +474 to +500
async getPreferredArtistNames(
guildId: string,
userId: string | undefined,
): Promise<Set<string>> {
if (!userId) return new Set<string>()

try {
const db = getPrismaClient()
const prefs = await db.userArtistPreference.findMany({
where: { discordUserId: userId, guildId, preference: 'prefer' },
select: { artistName: true },
})
return new Set(
prefs
.map((p) => p.artistName.trim())
.filter((name) => name.length > 0),
)
} catch {
return new Set<string>()
}
}

export const recommendationFeedbackService = new RecommendationFeedbackService(
parseInt(process.env.AUTOPLAY_FEEDBACK_TTL_DAYS ?? '30', 10),
)

} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect the class/export boundary around the parse error.
sed -n '470,502p' packages/bot/src/services/musicRecommendation/feedbackService.ts

Repository: LucasSantana-Dev/Lucky

Length of output: 1042


🏁 Script executed:

#!/bin/bash
# Get the class definition and structure around the reported lines
cat -n packages/bot/src/services/musicRecommendation/feedbackService.ts | sed -n '450,510p'

Repository: LucasSantana-Dev/Lucky

Length of output: 1971


🏁 Script executed:

#!/bin/bash
# Find the class declaration to confirm the structure
rg -n "class RecommendationFeedbackService" packages/bot/src/services/musicRecommendation/feedbackService.ts

Repository: LucasSantana-Dev/Lucky

Length of output: 113


Move the service export outside the class body.

The class closing brace is placed on line 500, after the export statement on line 496. This causes a syntax error since the export declaration cannot exist at module scope while still nested inside the class body. The closing brace must move to line 495, immediately after the getPreferredArtistNames method ends.

Compile fix
     async getPreferredArtistNames(
         guildId: string,
         userId: string | undefined,
     ): Promise<Set<string>> {
         if (!userId) return new Set<string>()
 
         try {
             const db = getPrismaClient()
             const prefs = await db.userArtistPreference.findMany({
                 where: { discordUserId: userId, guildId, preference: 'prefer' },
                 select: { artistName: true },
             })
             return new Set(
                 prefs
                     .map((p) => p.artistName.trim())
                     .filter((name) => name.length > 0),
             )
         } catch {
             return new Set<string>()
         }
     }
+}
 
 export const recommendationFeedbackService = new RecommendationFeedbackService(
     parseInt(process.env.AUTOPLAY_FEEDBACK_TTL_DAYS ?? '30', 10),
 )
-
-}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getPreferredArtistNames(
guildId: string,
userId: string | undefined,
): Promise<Set<string>> {
if (!userId) return new Set<string>()
try {
const db = getPrismaClient()
const prefs = await db.userArtistPreference.findMany({
where: { discordUserId: userId, guildId, preference: 'prefer' },
select: { artistName: true },
})
return new Set(
prefs
.map((p) => p.artistName.trim())
.filter((name) => name.length > 0),
)
} catch {
return new Set<string>()
}
}
export const recommendationFeedbackService = new RecommendationFeedbackService(
parseInt(process.env.AUTOPLAY_FEEDBACK_TTL_DAYS ?? '30', 10),
)
}
async getPreferredArtistNames(
guildId: string,
userId: string | undefined,
): Promise<Set<string>> {
if (!userId) return new Set<string>()
try {
const db = getPrismaClient()
const prefs = await db.userArtistPreference.findMany({
where: { discordUserId: userId, guildId, preference: 'prefer' },
select: { artistName: true },
})
return new Set(
prefs
.map((p) => p.artistName.trim())
.filter((name) => name.length > 0),
)
} catch {
return new Set<string>()
}
}
}
export const recommendationFeedbackService = new RecommendationFeedbackService(
parseInt(process.env.AUTOPLAY_FEEDBACK_TTL_DAYS ?? '30', 10),
)
🧰 Tools
🪛 Biome (2.4.11)

[error] 496-496: expected a semicolon to end the class property, but found none

(parse)


[error] 496-496: expected a semicolon to end the class property, but found none

(parse)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/services/musicRecommendation/feedbackService.ts` around
lines 474 - 500, The export for recommendationFeedbackService is currently
placed inside the RecommendationFeedbackService class body causing a syntax
error; move the class closing brace so that the class ends immediately after the
getPreferredArtistNames method (i.e., close the RecommendationFeedbackService
class right after getPreferredArtistNames) and then keep the export const
recommendationFeedbackService = new RecommendationFeedbackService(...) at module
scope; verify the class name RecommendationFeedbackService and the exported
identifier recommendationFeedbackService match after the change.

Comment on lines 56 to 60
* Collect recommendation candidates from multiple sources:
* - Spotify Recommendations API (based on seed tracks)
* - Seed track similar searches (YouTube, Spotify)
*
* This is the main aggregator that orchestrates Spotify + LastFm + YouTube sourcing.
* This is the main aggregator that orchestrates LastFm + YouTube sourcing.
* Last.fm is handled separately by collectLastFmCandidates in _replenishQueue.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove the stale Spotify mention from this collector comment.

Line 57 still says seed searches include Spotify, but this PR removes Spotify recommendation collection and Line 59 now says Last.fm + YouTube.

Suggested cleanup
- * - Seed track similar searches (YouTube, Spotify)
+ * - Seed track similar searches (YouTube)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* Collect recommendation candidates from multiple sources:
* - Spotify Recommendations API (based on seed tracks)
* - Seed track similar searches (YouTube, Spotify)
*
* This is the main aggregator that orchestrates Spotify + LastFm + YouTube sourcing.
* This is the main aggregator that orchestrates LastFm + YouTube sourcing.
* Last.fm is handled separately by collectLastFmCandidates in _replenishQueue.
* Collect recommendation candidates from multiple sources:
* - Seed track similar searches (YouTube)
*
* This is the main aggregator that orchestrates LastFm + YouTube sourcing.
* Last.fm is handled separately by collectLastFmCandidates in _replenishQueue.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bot/src/utils/music/autoplay/candidateCollector.ts` around lines 56
- 60, Update the header comment in candidateCollector.ts (the aggregator that
orchestrates Last.fm + YouTube candidate collection) to remove the stale
"Spotify" / "seed track similar searches (Spotify)" mention and ensure it only
references the actual sources (YouTube and Last.fm/collectLastFmCandidates).
Edit the top comment block near the collect/replenish logic (the candidate
collector/collectCandidates function) so wording matches current behavior: "Seed
track similar searches (YouTube)" and "Last.fm + YouTube" without any Spotify
references.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
4.3% Coverage on New Code (required ≥ 80%)
5.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@LucasSantana-Dev

Copy link
Copy Markdown
Owner Author

Closing — same scope as #720 which broke 6+ replenisher test files (0 candidates produced where >=1 expected). The dead /v1/recommendations + /v1/audio-features endpoints aren't actively harmful (they fail silently). Re-attempt should include proper test mock updates for the new candidate-source pipeline order. Live UX bugs (#721) take priority.

This branch was successfully deployed

1 active deployment
Preview — 09252b2e Deployed Apr 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot enhancement New feature or request size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant