native-lyrics-tools
Version:
A JavaScript library for parsing and generating various lyric formats.
95 lines (81 loc) • 2.52 kB
JavaScript
function parseTime(str) {
const match = str.match(/^\[(\d+):(\d+)[.:](\d{1,3})]/);
if (!match) throw new Error(`Invalid timestamp: ${str}`);
const minutes = parseInt(match[1], 10);
const seconds = parseInt(match[2], 10);
let milliseconds = match[3].padEnd(3, '0'); // Normalize to 3 digits
milliseconds = parseInt(milliseconds, 10);
const totalMs = minutes * 60000 + seconds * 1000 + milliseconds;
const remaining = str.slice(match[0].length);
return { remaining, time: totalMs };
}
function parseLine(line) {
const timeRegex = /\[\d+:\d+[.:]\d{1,3}]/g;
const matches = [...line.matchAll(timeRegex)];
if (matches.length === 0) return [];
const times = matches.map(match => parseTime(match[0]).time);
const textStart = matches[matches.length - 1].index + matches[matches.length - 1][0].length;
const lyricText = line.slice(textStart).trim();
if (!lyricText) return [];
return times.map(t => ({
start_time: t,
end_time: 0,
words: [{
start_time: t,
end_time: 0,
word: lyricText
}]
}));
}
function parseLRC(src) {
const result = [];
const lines = src.split(/\r?\n/);
for (const line of lines) {
try {
const parsed = parseLine(line);
if (parsed.length > 0) {
result.push(...parsed);
}
} catch (e) {
continue;
}
}
result.sort((a, b) => a.start_time - b.start_time);
let lastEndTime = Number.MAX_SAFE_INTEGER;
for (let i = result.length - 1; i >= 0; i--) {
const line = result[i];
line.end_time = lastEndTime;
if (line.words.length > 0) {
line.words[0].end_time = lastEndTime;
}
lastEndTime = line.start_time;
}
// Optional: insert timing adjustments with a separate `processLyrics()` if needed
return result;
}
function writeTimestamp(time) {
const ms = time % 1000;
const sec = Math.floor(time / 1000) % 60;
const min = Math.floor(time / 60000);
return `[${String(min).padStart(2, '0')}:${String(sec).padStart(2, '0')}.${String(ms).padStart(3, '0')}]`;
}
function stringifyLRC(lines) {
let result = '';
for (const line of lines) {
if (!line.words.length) continue;
result += writeTimestamp(line.words[0].start_time);
for (const word of line.words) {
result += word.word;
}
result += '\n';
}
return result;
}
// Exported ES module API
export {
parseTime,
parseLine,
parseLRC,
stringifyLRC,
writeTimestamp
};