fix: lyrics sync offset tag + 200ms lookahead
- Parse [offset:N] metadata from LRC files (was silently ignored, caused ~1s drift) - Apply 200ms lookahead so active line highlights slightly before it's sung Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
af03061f75
commit
9f68deea94
1 file changed
+9
-1
@@ -474,12 +474,19 @@ export function switchNpTab(tab) {
|
|||||||
let _lyricsLines = [];
|
let _lyricsLines = [];
|
||||||
let _lyricsSongId = null;
|
let _lyricsSongId = null;
|
||||||
|
|
||||||
|
const LYRICS_LOOKAHEAD_MS = 200; // highlight line this many ms before its timestamp
|
||||||
|
|
||||||
function _parseLrc(text) {
|
function _parseLrc(text) {
|
||||||
|
let offsetMs = 0;
|
||||||
const lines = [];
|
const lines = [];
|
||||||
for(const raw of text.split('\n')) {
|
for(const raw of text.split('\n')) {
|
||||||
|
const offM = raw.match(/^\[offset:\s*([+-]?\d+)\s*\]/i);
|
||||||
|
if(offM) { offsetMs = parseInt(offM[1]); continue; }
|
||||||
const m = raw.match(/^\[(\d+):(\d+(?:\.\d+)?)\](.*)/);
|
const m = raw.match(/^\[(\d+):(\d+(?:\.\d+)?)\](.*)/);
|
||||||
if(m) lines.push({ start: Math.round((parseInt(m[1])*60 + parseFloat(m[2]))*1000), value: m[3].trim() });
|
if(m) lines.push({ start: Math.round((parseInt(m[1])*60 + parseFloat(m[2]))*1000), value: m[3].trim() });
|
||||||
}
|
}
|
||||||
|
// [offset:N] shifts all timestamps by N ms (positive = lines appear later)
|
||||||
|
if(offsetMs) lines.forEach(l => l.start = Math.max(0, l.start + offsetMs));
|
||||||
return lines.sort((a,b) => a.start - b.start).filter(l => l.value);
|
return lines.sort((a,b) => a.start - b.start).filter(l => l.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,9 +566,10 @@ async function _loadNpLyrics(songId) {
|
|||||||
|
|
||||||
export function updateLyricsHighlight(currentMs) {
|
export function updateLyricsHighlight(currentMs) {
|
||||||
if(!_lyricsLines.length || !S.npLyricsMode) return;
|
if(!_lyricsLines.length || !S.npLyricsMode) return;
|
||||||
|
const adjusted = currentMs + LYRICS_LOOKAHEAD_MS;
|
||||||
let activeIdx = -1;
|
let activeIdx = -1;
|
||||||
for(let i = 0; i < _lyricsLines.length; i++) {
|
for(let i = 0; i < _lyricsLines.length; i++) {
|
||||||
if(_lyricsLines[i].start <= currentMs) activeIdx = i;
|
if(_lyricsLines[i].start <= adjusted) activeIdx = i;
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
_lyricsLines.forEach((line, i) => {
|
_lyricsLines.forEach((line, i) => {
|
||||||
|
|||||||
Reference in new issue
Block a user