72 lines
2.5 KiB
JavaScript
72 lines
2.5 KiB
JavaScript
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}에 저장했습니다.`);
|