import type { db as Db } from "../db"; import type { Question, QuizRound } from "../party-types"; import { buildOptionsWithCorrect, buildOrderedOptions, buildQuestionWindow, getMostSharedGenreNames, getTopClusterArtists, getTopClusterTracks, isUsableText, type PartyAnalytics, pickQuestionCandidate, pickRandom, type QuestionCandidate, resolveQuestionSong, } from "./question-utils"; export async function buildAudioMetadataQuestion( dbClient: typeof Db, analytics: PartyAnalytics, index: number, history: QuizRound[], ): Promise { type ChoiceQuestion = Extract; const questions: Array< QuestionCandidate> > = []; const topSong = await resolveQuestionSong(dbClient, analytics); const topSongName = topSong?.name; const topTracks = getTopClusterTracks(analytics); const topTrackNames = topTracks.map((track) => track.name); if (isUsableText(topSongName)) { const currentSongOptions = buildOptionsWithCorrect( topSongName, topTrackNames, 4, ); if (currentSongOptions) { questions.push({ key: `audio:current-song:${topSongName}`, subjectKey: `track:${topSongName}`, question: { type: "choice", text: "What song is currently playing?", options: currentSongOptions, correct: 0, points: 10, song: topSong ?? undefined, hideSongTitle: true, }, }); } } const genreOptions = buildOrderedOptions( getMostSharedGenreNames(analytics), 4, ); if (genreOptions) { const topGenre = genreOptions[0]; if (topGenre) { questions.push({ key: `audio:genre:${topGenre}`, subjectKey: `genre:${topGenre}`, question: { type: "choice", text: "Which genre appears most in the party analytics?", options: genreOptions, correct: 0, points: 10, song: topSong ?? undefined, }, }); } } const topArtists = getTopClusterArtists(analytics); const topArtist = topArtists[0]; if (topArtist) { const artistOptions = buildOptionsWithCorrect(topArtist, topArtists, 4); if (artistOptions) { questions.push({ key: `audio:artist:${topArtist}`, subjectKey: `artist:${topArtist}`, question: { type: "choice", text: "Which artist shows up most often in the shared audio data?", options: artistOptions, correct: 0, points: 10, song: topSong ?? undefined, }, }); } } if (topTracks.length > 0) { const topTrackName = topTrackNames[0]; const trackOptions = topTrackName ? buildOptionsWithCorrect(topTrackName, topTrackNames, 4) : null; if (trackOptions) { questions.push({ key: `audio:track:${topTrackName}`, subjectKey: `track:${topTrackName}`, question: { type: "choice", text: "Which track looks most shared across the party?", options: trackOptions, correct: 0, points: 10, song: topSong ?? undefined, }, }); } } const randomTopTrack = pickRandom(topTracks); if (randomTopTrack) { const randomTrackSong = await resolveQuestionSong(dbClient, analytics, { trackName: randomTopTrack.name, artistNames: randomTopTrack.artists?.map((artist) => artist.name), albumName: randomTopTrack.albumName, }); const trackArtists = randomTopTrack.artists?.map((artist) => artist.name) ?? []; const allArtists = topArtists.length > 0 ? topArtists : trackArtists; const correctArtist = trackArtists[0] ?? allArtists[0]; if (correctArtist) { const artistOptions = buildOptionsWithCorrect( correctArtist, allArtists, 4, ); if (artistOptions) { questions.push({ key: `audio:performer:${randomTopTrack.name}`, subjectKey: `track:${randomTopTrack.name}`, question: { type: "choice", text: `Who performs "${randomTopTrack.name}"?`, options: artistOptions, correct: 0, points: 10, song: randomTrackSong ?? topSong ?? undefined, }, }); } const trackNames = topTracks.map((t) => t.name); const trackNameOptions = buildOptionsWithCorrect( randomTopTrack.name, trackNames, 4, ); if (trackNameOptions) { questions.push({ key: `audio:title:${randomTopTrack.name}`, subjectKey: `track:${randomTopTrack.name}`, question: { type: "choice", text: `What is the name of this track by ${correctArtist}?`, options: trackNameOptions, correct: 0, points: 10, song: randomTrackSong ?? topSong ?? undefined, }, }); } if (isUsableText(topSongName) && topSongName !== randomTopTrack.name) { const alternateSongOptions = buildOptionsWithCorrect( topSongName, trackNames, 4, ); if (alternateSongOptions) { questions.push({ key: `audio:current-song:${topSongName}`, subjectKey: `track:${topSongName}`, question: { type: "choice", text: "Which song is this audio clip from?", options: alternateSongOptions, correct: 0, points: 10, song: topSong ?? undefined, hideSongTitle: true, }, }); } } } if (randomTopTrack.albumName) { const albumNames = topTracks .map((track) => track.albumName) .filter((name): name is string => Boolean(name)); const albumOptions = buildOptionsWithCorrect( randomTopTrack.albumName, albumNames, 4, ); if (albumOptions) { questions.push({ key: `audio:album:${randomTopTrack.albumName}`, subjectKey: `track:${randomTopTrack.name}`, question: { type: "choice", text: `"${randomTopTrack.name}" appears on which album?`, options: albumOptions, correct: 0, points: 10, song: randomTrackSong ?? topSong ?? undefined, }, }); } } } if (questions.length === 0) { return null; } const question = pickQuestionCandidate(questions, history, index); if (!question) return null; return buildQuestionWindow(question); }