// utils/normalizeQuestionMedia.ts // Shared helper for normalizing media URLs in quiz questions. // Call before saving to KV/SQL to ensure consistent data format. import { hashText } from "../services/stateMiddleware.ts"; /** * Question structure with media fields */ export interface QuizQuestion { id: string; text_1: string; text_2: string; background_file: string; background_image_data: string; audio_file_1: string; audio_file_2: string; } /** * Normalizes media URLs in a question to the expected local format. * Call this BEFORE saving to KV/SQL to ensure consistent data. * * Expected output formats: * - background_image_data: "/api/ai-images/file/{filename}" or "/api/image-blob/{hashName}" or base64 * (legacy http URLs are left unchanged - they'll be handled by the serving layer) * - audio_file_1/2: "{hashName}" or "{hashName}.webm" (just the hash, not a URL) * * Note: background_file stores the user's description (not a filename). * The actual filename is embedded in the background_image_data URL path. * * @param question - The question object to normalize (mutated in place) * @returns true if any field was modified */ export async function normalizeQuestionMedia( question: QuizQuestion | null | undefined, ): Promise { let changed = false; if (!question) { return false; } // Note: We no longer try to derive background_image_data from background_file // because background_file now stores the user's description, not a filename. // Legacy http URLs in background_image_data are left as-is. // New images should already have correct /api/... URLs when saved. // Normalize audio_file_1 if (question.text_1 && question.audio_file_1) { if (question.audio_file_1.startsWith("http")) { // Convert to hash-based local reference const hash = await hashText(question.id + ":" + question.text_1); question.audio_file_1 = hash + ""; changed = true; } } // Normalize audio_file_2 if (question.text_2 && question.audio_file_2) { if (question.audio_file_2.startsWith("http")) { const hash = await hashText(question.id + ":" + question.text_2); question.audio_file_2 = hash + ""; changed = true; } } return changed; } /** * Normalizes all questions in a quiz config. * @param questions - Array of questions to normalize (mutated in place) * @returns true if any question was modified */ export async function normalizeQuizMedia( questions: Array, ): Promise { let anyChanged = false; for (const question of questions) { if (!question) continue; const changed = await normalizeQuestionMedia(question); anyChanged = anyChanged || changed; } return anyChanged; }