native-lyrics-tools
Version:
A JavaScript library for parsing and generating various lyric formats.
140 lines (124 loc) • 3.08 kB
JavaScript
function parseProperty(str) {
const match = str.match(/^\[(\d+)]/);
if (!match) throw new Error("Invalid property format");
const code = parseInt(match[1], 10);
const remaining = str.slice(match[0].length);
const map = {
0: [false, false],
1: [false, false],
2: [false, true],
3: [false, false],
4: [false, false],
5: [false, true],
6: [true, false],
7: [true, false],
8: [true, true],
};
return {
remaining,
is_bg: map[code]?.[0] ?? false,
is_duet: map[code]?.[1] ?? false,
};
}
function parseWordTime(segment) {
const match = segment.match(/^\((\d+),(\d+)\)/);
if (!match) throw new Error("Invalid word time format");
const start_time = parseInt(match[1], 10);
const duration = parseInt(match[2], 10);
const remaining = segment.slice(match[0].length);
return {
remaining,
start_time,
end_time: start_time + duration,
};
}
function parseWord(str) {
for (let i = 0; i < str.length; i++) {
if (str[i] === '(') {
const before = str.slice(0, i);
try {
const { remaining, start_time, end_time } = parseWordTime(str.slice(i));
return {
remaining,
word: {
word: before,
start_time,
end_time,
}
};
} catch {
continue;
}
}
}
throw new Error("Failed to parse word");
}
function parseWords(str) {
const words = [];
while (str.length > 0) {
try {
const { word, remaining } = parseWord(str);
words.push(word);
str = remaining.trimStart();
} catch {
break;
}
}
return words;
}
function parseLine(line) {
const { remaining, is_bg, is_duet } = parseProperty(line);
const words = parseWords(remaining);
return {
is_bg,
is_duet,
words,
start_time: words[0]?.start_time ?? 0,
end_time: words.at(-1)?.end_time ?? 0,
};
}
function parseLys(src) {
const lines = [];
for (const rawLine of src.split(/\r?\n/)) {
if (!rawLine.trim()) continue;
try {
const line = parseLine(rawLine);
if (line.words && line.words.length > 0) {
lines.push(line);
}
} catch {
continue;
}
}
// You can call a processLyrics() function here if needed
return lines;
}
function stringifyLys(lines) {
let result = '';
for (const line of lines) {
if (!line.words.length) continue;
const prop = (() => {
if (line.is_bg && line.is_duet) return '[8]';
if (line.is_bg) return '[6]';
if (line.is_duet) return '[2]';
return '[0]';
})();
result += prop;
for (const word of line.words) {
result += word.word;
result += `(${word.start_time},${word.end_time - word.start_time})`;
}
result += '\n';
}
return result;
}
// Export for ES Module usage
export {
parseProperty,
parseWordTime,
parseWord,
parseWords,
parseLine,
parseLys,
stringifyLys
};