fix(music-player): 修复歌词解析和显示问题
- 更新歌词解析正则,支持更广泛的歌词格式 - 修复歌词时间计算,精确到毫秒 -优化无歌词时的处理逻辑,显示每行文本 - 改进歌词滚动逻辑,确保正确显示当前行 - 增加对 currentTime 的监听,实时更新歌词显示
This commit is contained in:
@@ -386,22 +386,29 @@ const parsedLyric = computed(() => {
|
||||
const lyric = currentMusic.value.lyric;
|
||||
const lines = lyric.split('\n');
|
||||
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) {
|
||||
const text = line.replace(timeRegExp, '').trim();
|
||||
if (text) {
|
||||
timeRegExp.lastIndex = 0;
|
||||
let match;
|
||||
while ((match = timeRegExp.exec(line)) !== null) {
|
||||
const min = parseInt(match, 10);
|
||||
const sec = parseInt(match, 10);
|
||||
const msStr = match;
|
||||
const time = min * 60 + sec + parseFloat('0.' + msStr);
|
||||
const min = parseInt(match[1], 10);
|
||||
const sec = parseInt(match[2], 10);
|
||||
const msPart = match[3];
|
||||
const msStr = msPart.padEnd(3, '0');
|
||||
const ms = parseInt(msStr, 10);
|
||||
const time = min * 60 + sec + ms / 1000;
|
||||
if (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);
|
||||
})
|
||||
|
||||
@@ -523,18 +530,28 @@ const formatSliderTooltip = (val) => formatTime(val)
|
||||
// 监听 Pinia store 的时间更新
|
||||
watch(currentTime, (newVal) => {
|
||||
if (!isUserSeeking.value) {
|
||||
sliderTime.value = newVal
|
||||
sliderTime.value = newVal;
|
||||
}
|
||||
// 更新歌词
|
||||
if (parsedLyric.value.length > 0) {
|
||||
let newIndex = parsedLyric.value.findIndex(line => line.time > newVal) - 1
|
||||
if (newIndex < 0) newIndex = parsedLyric.value.length - 1
|
||||
if (parsedLyric.value && parsedLyric.value.length > 0) {
|
||||
let newIndex = parsedLyric.value.findIndex(l => l.time > newVal);
|
||||
|
||||
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) {
|
||||
currentLyricIndex.value = newIndex
|
||||
if (isExpanded.value) scrollToActiveLyric()
|
||||
currentLyricIndex.value = newIndex;
|
||||
if (isExpanded.value && newIndex >= 0) {
|
||||
scrollToActiveLyric();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// 滚动到当前歌词
|
||||
const scrollToActiveLyric = async () => {
|
||||
@@ -577,6 +594,34 @@ watch(() => currentMusic.value?.id, (newId) => {
|
||||
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>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user