import { readFile, writeFile } from 'node:fs/promises'; import path from 'node:path'; import process from 'node:process'; const sourcePath = process.argv[2]; if (!sourcePath) { throw new Error('사용법: npm run data:import-songs -- <기존 계산기 HTML 경로>'); } const source = await readFile(sourcePath, 'utf8'); function parseConstant(name) { const prefix = `const ${name} = `; const start = source.indexOf(prefix); if (start < 0) throw new Error(`${name} 데이터를 찾을 수 없습니다.`); const valueStart = start + prefix.length; const valueEnd = source.indexOf(';\n', valueStart); if (valueEnd < 0) throw new Error(`${name} 데이터의 끝을 찾을 수 없습니다.`); return JSON.parse(source.slice(valueStart, valueEnd)); } const songs = parseConstant('SONGS'); const specials = parseConstant('SONG_SPECIAL'); const noteHistograms = parseConstant('SONG_NOTE_HIST'); const difficultyNames = ['hard', 'expert']; function parseNotes(value) { if (typeof value !== 'string' || value.length === 0) return []; return value.split(',').map((noteCount) => Number(noteCount)); } function specialStarts(songId, difficultyIndex) { const starts = Array(5).fill(null); for (const entry of specials[songId]?.[difficultyIndex] ?? []) { const [slot, startSeconds] = entry; if (Number.isInteger(slot) && slot >= 0 && slot < starts.length && Number.isFinite(startSeconds)) { starts[slot] = startSeconds; } } return starts; } const normalizedSongs = songs.flatMap(([id, title, durationSeconds]) => { const histograms = noteHistograms[id]; if (!histograms) return []; const difficulties = Object.fromEntries( difficultyNames.flatMap((difficulty, difficultyIndex) => { const notesPerSecond = parseNotes(histograms[difficultyIndex]); if (notesPerSecond.length === 0) return []; return [[difficulty, { notesPerSecond, specialStartSeconds: specialStarts(id, difficultyIndex), totalNotes: notesPerSecond.reduce((sum, noteCount) => sum + noteCount, 0) }]]; }) ); if (Object.keys(difficulties).length === 0) return []; return [{ id, title, durationSeconds, difficulties }]; }); const output = { schemaVersion: 1, source: path.basename(sourcePath), songs: normalizedSongs }; const outputPath = path.resolve('src/lib/data/song-charts.json'); await writeFile(outputPath, `${JSON.stringify(output, null, 2)}\n`, 'utf8'); console.log(`${normalizedSongs.length}곡의 채보 밀도 데이터를 ${outputPath}에 저장했습니다.`);