Preserve and display bilingual and phonetic lyric cues

This commit is contained in:
Jonathan Sykes
2026-10-03 15:20:52 +08:00
parent c8ab741d72
commit d4354d220e
13 changed files with 78 additions and 11 deletions

View File

@@ -56,6 +56,11 @@
return String(s).split(/[,|·]/).map((x) => x.trim()).filter(Boolean);
}
function display(line) {
const text = String(line?.text || ''), divider = text.indexOf(' / ');
return { text: divider < 0 ? text : text.slice(0, divider).trim(), secondary: line?.secondary || (divider < 0 ? '' : text.slice(divider + 3).trim()), phonetic: line?.phonetic || '' };
}
// Editor text → { lines, tags, offset }.
function fromText(text) {
const lines = [];
@@ -65,8 +70,14 @@
for (const rawLine of String(text || '').replace(/\r/g, '').split('\n')) {
let rest = rawLine.trim();
if (!rest) continue;
if (/^!pinyin:\s*/i.test(rest) && group.some(l => l.kind === 'line')) {
const value = rest.replace(/^!pinyin:\s*/i, '').trim();
for (const line of group) if (value) line.phonetic = line.phonetic ? line.phonetic + '\n' + value : value;
continue;
}
if (rest.startsWith('| ') && group.length) {
for (const line of group) line.text += '\n' + rest.slice(2).trim();
const extra = display({ text: rest.slice(2).trim() });
for (const line of group) { line.text += '\n' + extra.text; if (extra.secondary) line.secondary = line.secondary ? line.secondary + '\n' + extra.secondary : extra.secondary; }
continue;
}
group = [];
@@ -92,6 +103,7 @@
if (!rest) continue;
group = stamps.length ? stamps.map(t => ({ t: Math.round(t * 100) / 100, text: rest, kind }))
: [{ t: null, text: rest, kind }];
if (kind === 'line') for (const line of group) { const parts = display(line); line.text = parts.text; if (parts.secondary) line.secondary = parts.secondary; }
lines.push(...group);
}
// A fully timed sheet (typical .lrc with repeated-chorus stamps) is put in
@@ -108,8 +120,11 @@
for (const l of (doc && doc.lines) || []) {
const stamp = l.t === null || l.t === undefined ? '' : `[${fmtStamp(l.t)}] `;
const mark = l.kind === 'section' ? '# ' : l.kind === 'cue' ? '! ' : '';
const parts = String(l.text || '').split('\n');
out.push(stamp + mark + parts[0], ...parts.slice(1).map(part => '| ' + part));
const parts = (l.kind === 'line' ? display(l) : { text: l.text || '', secondary: '' });
const primary = parts.text.split('\n'), secondary = parts.secondary.split('\n');
const combined = primary.map((part, i) => part + (secondary[i] ? ' / ' + secondary[i] : ''));
out.push(stamp + mark + combined[0], ...combined.slice(1).map(part => '| ' + part));
if (l.phonetic) out.push(...String(l.phonetic).split('\n').map(part => '!pinyin: ' + part));
}
return out.join('\n');
}
@@ -162,7 +177,7 @@
}
const LyricsCore = {
parseStamp, fmtStamp, fmtClock, fromText, toText,
parseStamp, fmtStamp, fmtClock, fromText, toText, display,
activeIndex, activeSection, timedCount, activeMarker, toYouTubeTimestamps,
};