Goal: Lift core Last.fm parity
42%→68%(+15 long-tail commands) without touching premium/admin (globalWk,import,jumble,discogs,autopost). Keepunlimitedpolicy (no pruning, no supporter gates). Track progress viaREADME.mdparity table.
Current: ~52% core (fm/wk/chart/top/overview/at/taste/crowns/music 100% loop), 37% raw. Done this cycle: fm @mention, artworkService star filter + Spotify→Deezer→Apple primary, chart 1/40 ArtworkService forced, wk discord displayName fetch + footer Artist - X listeners - Y plays - Z avg (hidden 1 avg) + wkt getTrackCoverUrl strict, top 200→1000 limit + weekly→overall + 1d-6d/2024/march via SettingService + jump 1-31 modal, overview → DB prisma.userPlay (fix 403), at split from o into artistTrackService Your top tracks for 'zaf' 10/page, puppeteer ephemeral 4s cap, trackdetails Essentia 140.0 bpm + p.scdn.co via spotifyScraper + Open on Spotify sp:14962971.
- DI
src/bot/startup.ts:103manualregisterInstance— single source, no decorators - Artwork
src/bot/services/artworkService.tssingle source (isPlaceholder 2a96cb…,art:*3600s,90dfreshness) - Puppeteer
src/images/generators/puppeteerService.ts:278close()pages 1.5s+browser.close 3s+SIGKILL+gracefulShutdown 4shard cap - Lavalink
src/bot/services/music/moonlinkManager.ts:25ENABLE_LAVALINK=falsedev dummydummy-disabled+lavalink:cooldown:*Redis persist - WhoKnows
src/bot/services/whoKnows/*guild.members.fetchif not cached fordiscordName
Each item: fmbot → tvbot files + DB + builder.
- fmbot:
ArtistCommands.cs:167artistplays ap/AlbumCommands.cs:67albumplays abp/TrackCommands.cs:76trackplays tp→ArtistBuilders.ArtistPlaysAsync+PlayService.GetRecentArtist/Album/TrackPlaycounts+GetArtist/Album/TrackPlayHistory(graph) +CorrectUser*Playcount - tvbot: Full 1:1 parity implemented in
src/bot/services/playHistoryService.ts,src/bot/builders/playcountBuilders.ts,src/bot/textCommands/lastfm/playcountCommands.ts, andsrc/bot/slashCommands/playcountSlashCommands.ts.
- fmbot:
PlayCommands.cs: plays p/scrobbles, pace pc, milestone m/ms→PlayBuilders.PaceAsync(goal projection),MileStoneAsync(scrobble5123),PlaysAsync(time-period count viauser.getInfototalPlayCount+GetScrobbleCountFromDate) - tvbot: Full 1:1 parity implemented in
SettingService.getGoalAmount,SettingService.getMilestoneAmount(withrnd/randomand reroll buttonsmilestone:reroll:),PlaycountBuilders.buildPaceResponse, andPlayHistoryService.getMilestoneScrobble.
- fmbot:
PlayCommands.cs: discoverydate dd+lastlistened ll→PlayService.GetArtistFirstPlayDate/GetTrackLastPlayed - tvbot: Full 1:1 parity implemented in
PlayHistoryService.getDiscoveryDatesandPlayHistoryService.getLastListenedDateswith 30-day relative timestamp styles (fvsD) and sub-links.
- fmbot:
PlayCommands.cs: search sr/find→PlayBuilders.SearchAsynccachedprismaSearchUserTracks/Albums/Artists/Plays+Fergun PaginatortabsTracks/Albums/Artists/Plays - tvbot: Full 1:1 parity implemented in
src/bot/services/librarySearchService.ts,src/bot/builders/librarySearchBuilders.ts,src/bot/interactions/librarySearchInteractions.ts,src/bot/textCommands/lastfm/librarySearchCommands.ts, andsrc/bot/slashCommands/librarySearchSlashCommands.ts.
- fmbot:
UserCommands.cs: profile/stats/user→UserBuilder.ProfileAsync(playcount, registered, country, recent top) - tvbot: Full 1:1 parity implemented in
src/bot/services/profileService.ts,src/bot/builders/profileBuilders.ts(with interactive History breakdown button),src/bot/interactions/profileInteractions.ts,src/bot/textCommands/lastfm/profileCommands.ts, andsrc/bot/slashCommands/profileSlashCommands.ts.
- fmbot:
PlayCommands.cs: streak str+streaks→PlayService.GetStreak+UserStreakDB (streak_id, user_id, artist_name, start, end, count) - tvbot: Full 1:1 parity implemented in
src/bot/services/streakService.ts,src/bot/builders/streakBuilders.ts,src/bot/textCommands/lastfm/streakCommands.ts, andsrc/bot/slashCommands/streakSlashCommands.ts.
- fmbot:
serverartists sa,serveralbums sab,servertracks st/bb,servergenres sg→GuildService.GetTopAllTimeForGuild+PlayService.GetGuildTop*+GuildBuilders - tvbot gap:
guildServiceexists but noserver*commands;GuildRankingSettingsmissing. - Build:
src/bot/services/guildRankingService.ts(prisma.userPlay.groupBywhereuserId in guildUserIds+ timeStartDateTime),src/bot/builders/serverBuilders.ts,src/bot/textCommands/guild/serverCommands.ts+ slashserverSlashCommands.ts(4 subs)
- Current:
src/bot/services/genreService.ts+countryService.tsexist but noGenreBuilders/CountryBuildersor commands. - Build:
src/bot/builders/genreBuilders.ts+countryBuilders.ts(use existingartistsService+genreService.getTopGenresForTopArtists),src/bot/textCommands/lastfm/genreCommands.tstopgenres gl, genre g, wkgenre wg, friendwhoknowgenre fwg,src/bot/textCommands/lastfm/countryCommands.tstopcountries cl, country, countrychart cc
- fmbot:
love l, unlove ul, loved lt, scrobble sb→TrackBuilders.LoveTrackAsync(dataSourceFactory.LoveTrackAsyncsigned),ScrobbleAsync(ScrobbleAsyncwithsk) - tvbot gap: OAuth flow
LoginServiceexists (/login), but nolove/scrobblewiring. - Build:
src/bot/services/loveService.ts(wrapLastFmRepositorysigned),src/bot/textCommands/lastfm/loveCommands.ts+ slash, reuseloginService.confirmLoginsession.
- Text
searchvs musicsearchconflict — rename musicsearchtomusicsearchor keepsearchfor library andplay searchfor music (fmbot usessearchfor library, youtube separateyoutube y). - Settings parity —
fmmodealready, addresponsemode/wkmode,covermode,privacy,modecentral picker (UserBuilder.ModePick) — low priority. - Guild admin —
configuration/ss,members/mb,block/unblock,autoposts— skip for private bot (keepsettingsminimal as now).
- Week 1: Phase 1
#1-#3(ap/abp/tp+p/pc/m+dd/ll) — 8 commands, singleplayHistoryService+ 1 builderplaycountBuilders. Verifynpm run build+tastillPage 1/40+atYour top tracks for 'zaf'+overviewdaily DB group (fix 403 already done:getUserRecentTracksWithMetadata100 fallback). - Week 2: Phase 1
#4-#6(searchlibrary +profile+streakDB) —UserStreakmigration,librarySearchService. - Week 3: Phase 2
server*+ Phase 3genre/country— wire orphaned services, 5 builders,GuildRankingService. - Week 4: Phase 4
love/scrobble(requires testingsk403 handling already fixed viaRecentTracksunsigned fallback). - Each phase: create
service → builder → slash+text → interaction → startup DI → slash/index + text/index + interactionHandler route → build + test + manual slash/text in dev guild.
Verify each phase: npm run build + npm test (expect 1 pre-existing lavalinkConfig fail) + npm run dev ENABLE_LAVALINK=false manual .ap zaf ap p weekly search zaf profile streak serverartists weekly.
globalwhoknows gw* (18 aliases), import spotifyimport/appleimport (file import), discoveries/gaps supporter upsell, jumble/pixel game, discogs, eurovision, autopost, premiumserver/botbranding/servershortcuts/allowedroles, featured/rym/botscrobbling, admin banguild/leaveserver.