import fs from 'fs' import path from 'path' type Clue = { number: number points: number song: string | null answer: string | null } type Category = { name: string clues: Clue[] } type Game = { name: string categories: Category[] } const projectRoot = process.cwd() const publicRoot = path.join(projectRoot, 'public') const dataRoot = path.join(publicRoot, 'Data') const outputPath = path.join(publicRoot, 'data.json') const isDirectory = (target: string) => { try { return fs.statSync(target).isDirectory() } catch { return false } } const listDirectories = (target: string) => { if (!isDirectory(target)) return [] return fs.readdirSync(target).filter((entry) => isDirectory(path.join(target, entry))) } const findSubdirCaseInsensitive = (baseDir: string, desiredName: string) => { if (!isDirectory(baseDir)) return null const entries = fs.readdirSync(baseDir) const match = entries.find( (entry) => entry.toLowerCase() === desiredName.toLowerCase() && isDirectory(path.join(baseDir, entry)) ) return match ? path.join(baseDir, match) : null } const findFileCaseInsensitive = (baseDir: string, fileName: string) => { if (!isDirectory(baseDir)) return null const entries = fs.readdirSync(baseDir) const match = entries.find((entry) => entry.toLowerCase() === fileName.toLowerCase()) return match ? path.join(baseDir, match) : null } const buildManifest = (): Game[] => { const games: Game[] = [] const gameNames = listDirectories(dataRoot) gameNames.forEach((gameName) => { const gamePath = path.join(dataRoot, gameName) const categories: Category[] = [] const categoryNames = listDirectories(gamePath) categoryNames.forEach((categoryName) => { const categoryPath = path.join(gamePath, categoryName) const songsDir = findSubdirCaseInsensitive(categoryPath, 'Songs') const answersDir = findSubdirCaseInsensitive(categoryPath, 'Answers') const clues: Clue[] = [] for (let i = 1; i <= 5; i += 1) { const songFile = songsDir ? findFileCaseInsensitive(songsDir, `${i}.mp3`) : null const answerFile = answersDir ? findFileCaseInsensitive(answersDir, `${i}.mp3`) : null const songRelPath = songFile ? `/${path.relative(publicRoot, songFile).replace(/\\/g, '/')}` : null const answerRelPath = answerFile ? `/${path.relative(publicRoot, answerFile).replace(/\\/g, '/')}` : null clues.push({ number: i, points: i * 100, song: songRelPath, answer: answerRelPath }) } categories.push({ name: categoryName, clues }) }) games.push({ name: gameName, categories }) }) return games } const main = () => { if (!isDirectory(dataRoot)) { fs.writeFileSync(outputPath, JSON.stringify([], null, 2)) return } const manifest = buildManifest() fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2)) } main()