fix(music-player): 修复歌词解析和显示问题

- 更新歌词解析正则,支持更广泛的歌词格式
- 修复歌词时间计算,精确到毫秒
-优化无歌词时的处理逻辑,显示每行文本
- 改进歌词滚动逻辑,确保正确显示当前行
- 增加对 currentTime 的监听,实时更新歌词显示
This commit is contained in:
ikmkj
2025-07-26 02:06:13 +08:00
parent 0fbed14ea7
commit fa41955eb7

View File

@@ -386,22 +386,29 @@ const parsedLyric = computed(() => {
const lyric = currentMusic.value.lyric; const lyric = currentMusic.value.lyric;
const lines = lyric.split('\n'); const lines = lyric.split('\n');
const result = []; const result = [];
const timeRegExp = /\[(\d{2}):(\d{2})\.(\d+)\]/g; const timeRegExp = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/g;
for (const line of lines) { for (const line of lines) {
const text = line.replace(timeRegExp, '').trim(); const text = line.replace(timeRegExp, '').trim();
if (text) {
timeRegExp.lastIndex = 0; timeRegExp.lastIndex = 0;
let match; let match;
while ((match = timeRegExp.exec(line)) !== null) { while ((match = timeRegExp.exec(line)) !== null) {
const min = parseInt(match, 10); const min = parseInt(match[1], 10);
const sec = parseInt(match, 10); const sec = parseInt(match[2], 10);
const msStr = match; const msPart = match[3];
const time = min * 60 + sec + parseFloat('0.' + msStr); const msStr = msPart.padEnd(3, '0');
const ms = parseInt(msStr, 10);
const time = min * 60 + sec + ms / 1000;
if (text) {
result.push({ time, text }); result.push({ time, text });
} }
} }
} }
if (result.length === 0) {
return lines.map(line => ({ time: 0, text: line.trim() }));
}
return result.sort((a, b) => a.time - b.time); return result.sort((a, b) => a.time - b.time);
}) })
@@ -523,18 +530,28 @@ const formatSliderTooltip = (val) => formatTime(val)
// 监听 Pinia store 的时间更新 // 监听 Pinia store 的时间更新
watch(currentTime, (newVal) => { watch(currentTime, (newVal) => {
if (!isUserSeeking.value) { if (!isUserSeeking.value) {
sliderTime.value = newVal sliderTime.value = newVal;
} }
// 更新歌词 // 更新歌词
if (parsedLyric.value.length > 0) { if (parsedLyric.value && parsedLyric.value.length > 0) {
let newIndex = parsedLyric.value.findIndex(line => line.time > newVal) - 1 let newIndex = parsedLyric.value.findIndex(l => l.time > newVal);
if (newIndex < 0) newIndex = parsedLyric.value.length - 1
if (newIndex === -1) {
// We are at or after the last lyric line
newIndex = parsedLyric.value.length - 1;
} else {
// The active line is the one before the next line
newIndex = newIndex - 1;
}
if (currentLyricIndex.value !== newIndex) { if (currentLyricIndex.value !== newIndex) {
currentLyricIndex.value = newIndex currentLyricIndex.value = newIndex;
if (isExpanded.value) scrollToActiveLyric() if (isExpanded.value && newIndex >= 0) {
scrollToActiveLyric();
} }
} }
}) }
});
// 滚动到当前歌词 // 滚动到当前歌词
const scrollToActiveLyric = async () => { const scrollToActiveLyric = async () => {
@@ -577,6 +594,34 @@ watch(() => currentMusic.value?.id, (newId) => {
if (isExpanded.value) expandedActiveTab.value = 'lyric' if (isExpanded.value) expandedActiveTab.value = 'lyric'
} }
}) })
// 监听当前播放时间,更新歌词
watch(currentTime, (newTime) => {
if (!parsedLyric.value || parsedLyric.value.length === 0) return
let newIndex = -1
for (let i = 0; i < parsedLyric.value.length; i++) {
if (newTime >= parsedLyric.value[i].time) {
newIndex = i
} else {
break
}
}
if (newIndex !== currentLyricIndex.value) {
currentLyricIndex.value = newIndex
if (newIndex > -1 && lyricScrollbar.value && lyricLines.value[newIndex]) {
const lineEl = lyricLines.value[newIndex]
const scrollbarEl = lyricScrollbar.value.wrapRef
if (scrollbarEl) {
const offsetTop = lineEl.offsetTop
const scrollbarHeight = scrollbarEl.clientHeight
const targetScrollTop = offsetTop - scrollbarHeight / 2 + lineEl.clientHeight / 2
lyricScrollbar.value.setScrollTop(targetScrollTop)
}
}
}
})
</script> </script>
<style scoped> <style scoped>