mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-03 14:20:50 +08:00
feat: 添加歌词矫正功能,支持增加和减少矫正时间
This commit is contained in:
@@ -11,6 +11,8 @@ export default {
|
||||
mute: 'Mute',
|
||||
unmute: 'Unmute',
|
||||
songNum: 'Song Number: {num}',
|
||||
addCorrection: 'Add {num} seconds',
|
||||
subtractCorrection: 'Subtract {num} seconds',
|
||||
playFailed: 'Play Failed, Play Next Song',
|
||||
playMode: {
|
||||
sequence: 'Sequence',
|
||||
|
||||
@@ -11,6 +11,8 @@ export default {
|
||||
mute: '静音',
|
||||
unmute: '取消静音',
|
||||
songNum: '歌曲总数:{num}',
|
||||
addCorrection: '提前 {num} 秒',
|
||||
subtractCorrection: '延迟 {num} 秒',
|
||||
playFailed: '当前歌曲播放失败,播放下一首',
|
||||
playMode: {
|
||||
sequence: '顺序播放',
|
||||
|
||||
53
src/renderer/components/lyric/LyricCorrectionControl.vue
Normal file
53
src/renderer/components/lyric/LyricCorrectionControl.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const props = defineProps<{
|
||||
correctionTime: number
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'adjust', delta: number): void
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="lyric-correction-btns-mac absolute right-0 bottom-4 flex flex-col items-center space-y-1 z-50 select-none transition-opacity duration-200 opacity-0 pointer-events-none"
|
||||
>
|
||||
<n-tooltip placement="right">
|
||||
<template #trigger>
|
||||
<div
|
||||
class="lyric-correction-btn"
|
||||
@click="emit('adjust', -0.2)"
|
||||
:title="t('player.subtractCorrection', { num: 0.2 })"
|
||||
>
|
||||
<i class="ri-subtract-line text-base"></i>
|
||||
</div>
|
||||
</template>
|
||||
<span>{{ t('player.subtractCorrection', { num: 0.2 }) }}</span>
|
||||
</n-tooltip>
|
||||
<span class="text-xs py-0.5 px-1 rounded bg-white/70 dark:bg-neutral-800/70 shadow font-mono tracking-wider text-gray-700 dark:text-gray-200 bg-opacity-40 backdrop-blur-2xl">
|
||||
{{ props.correctionTime > 0 ? '+' : '' }}{{ props.correctionTime.toFixed(1) }}s
|
||||
</span>
|
||||
<n-tooltip placement="right">
|
||||
<template #trigger>
|
||||
<div
|
||||
class="lyric-correction-btn"
|
||||
@click="emit('adjust', 0.2)"
|
||||
:title="t('player.addCorrection', { num: 0.2 })"
|
||||
>
|
||||
<i class="ri-add-line text-base"></i>
|
||||
</div>
|
||||
</template>
|
||||
<span>{{ t('player.addCorrection', { num: 0.2 }) }}</span>
|
||||
</n-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.lyric-correction-btn {
|
||||
@apply w-7 h-7 flex items-center justify-center rounded-lg bg-white dark:bg-neutral-800 border border-white/20 dark:border-neutral-700/40 shadow-md backdrop-blur-2xl cursor-pointer transition-all duration-150 text-gray-700 dark:text-gray-200 hover:bg-green-500/80 hover:text-white hover:border-green-400/60 active:scale-95 bg-opacity-40 dark:hover:bg-green-500/80 dark:hover:text-white dark:hover:border-green-400/60 dark:hover:bg-opacity-40;
|
||||
}
|
||||
</style>
|
||||
@@ -19,7 +19,6 @@ export const lrcTimeArray = ref<number[]>([]); // 歌词时间数组
|
||||
export const nowTime = ref(0); // 当前播放时间
|
||||
export const allTime = ref(0); // 总播放时间
|
||||
export const nowIndex = ref(0); // 当前播放歌词
|
||||
export const correctionTime = ref(0.4); // 歌词矫正时间Correction time
|
||||
export const currentLrcProgress = ref(0); // 来存储当前歌词的进度
|
||||
export const playMusic = computed(() => playerStore.playMusic as SongResult); // 当前播放歌曲
|
||||
export const sound = ref<Howl | null>(audioService.getCurrentSound());
|
||||
@@ -482,25 +481,64 @@ export const pause = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 增加矫正时间
|
||||
export const addCorrectionTime = (time: number) => (correctionTime.value += time);
|
||||
// 歌词矫正时间映射(每首歌独立)
|
||||
const CORRECTION_KEY = 'lyric-correction-map';
|
||||
const correctionTimeMap = ref<Record<string, number>>({});
|
||||
|
||||
// 减少矫正时间
|
||||
export const reduceCorrectionTime = (time: number) => (correctionTime.value -= time);
|
||||
// 初始化 correctionTimeMap
|
||||
const loadCorrectionMap = () => {
|
||||
try {
|
||||
const raw = localStorage.getItem(CORRECTION_KEY);
|
||||
correctionTimeMap.value = raw ? JSON.parse(raw) : {};
|
||||
} catch {
|
||||
correctionTimeMap.value = {};
|
||||
}
|
||||
};
|
||||
const saveCorrectionMap = () => {
|
||||
localStorage.setItem(CORRECTION_KEY, JSON.stringify(correctionTimeMap.value));
|
||||
};
|
||||
|
||||
loadCorrectionMap();
|
||||
|
||||
// 歌词矫正时间,当前歌曲
|
||||
export const correctionTime = ref(0);
|
||||
|
||||
// 切歌时自动读取矫正时间
|
||||
watch(
|
||||
() => playMusic.value?.id,
|
||||
(id) => {
|
||||
if (!id) return;
|
||||
correctionTime.value = correctionTimeMap.value[id] ?? 0;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* 调整歌词矫正时间(每首歌独立)
|
||||
* @param delta 增加/减少的秒数(正为加,负为减)
|
||||
*/
|
||||
export const adjustCorrectionTime = (delta: number) => {
|
||||
const id = playMusic.value?.id;
|
||||
if (!id) return;
|
||||
const newVal = Math.max(-10, Math.min(10, (correctionTime.value ?? 0) + delta));
|
||||
correctionTime.value = newVal;
|
||||
correctionTimeMap.value[id] = newVal;
|
||||
saveCorrectionMap();
|
||||
};
|
||||
|
||||
// 获取当前播放歌词
|
||||
export const isCurrentLrc = (index: number, time: number): boolean => {
|
||||
const currentTime = lrcTimeArray.value[index];
|
||||
const nextTime = lrcTimeArray.value[index + 1];
|
||||
const nowTime = time + correctionTime.value;
|
||||
const isTrue = nowTime > currentTime && nowTime < nextTime;
|
||||
return isTrue;
|
||||
const correctedTime = time + correctionTime.value;
|
||||
return correctedTime > currentTime && correctedTime < nextTime;
|
||||
};
|
||||
|
||||
// 获取当前播放歌词INDEX
|
||||
export const getLrcIndex = (time: number): number => {
|
||||
const correctedTime = time + correctionTime.value;
|
||||
for (let i = 0; i < lrcTimeArray.value.length; i++) {
|
||||
if (isCurrentLrc(i, time)) {
|
||||
if (isCurrentLrc(i, correctedTime - correctionTime.value)) {
|
||||
nowIndex.value = i;
|
||||
return i;
|
||||
}
|
||||
@@ -517,15 +555,22 @@ const currentLrcTiming = computed(() => {
|
||||
|
||||
// 获取歌词样式
|
||||
export const getLrcStyle = (index: number) => {
|
||||
if (index === nowIndex.value) {
|
||||
const currentTime = nowTime.value + correctionTime.value;
|
||||
const start = lrcTimeArray.value[index];
|
||||
const end = lrcTimeArray.value[index + 1] ?? (start + 1);
|
||||
|
||||
if (currentTime >= start && currentTime < end) {
|
||||
// 当前句,显示进度
|
||||
const progress = ((currentTime - start) / (end - start)) * 100;
|
||||
return {
|
||||
backgroundImage: `linear-gradient(to right, #ffffff ${currentLrcProgress.value}%, #ffffff8a ${currentLrcProgress.value}%)`,
|
||||
backgroundImage: `linear-gradient(to right, #ffffff ${progress}%, #ffffff8a ${progress}%)`,
|
||||
backgroundClip: 'text',
|
||||
WebkitBackgroundClip: 'text',
|
||||
color: 'transparent',
|
||||
transition: 'background-image 0.1s linear'
|
||||
};
|
||||
}
|
||||
// 其它句
|
||||
return {};
|
||||
};
|
||||
|
||||
|
||||
@@ -135,12 +135,13 @@
|
||||
<span>{{ t('player.lrc.noLrc') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 歌词右下角矫正按钮组件 -->
|
||||
<LyricCorrectionControl
|
||||
v-if="!isMobile"
|
||||
:correction-time="correctionTime"
|
||||
@adjust="adjustCorrectionTime"
|
||||
/>
|
||||
</n-layout>
|
||||
<!-- 时间矫正 -->
|
||||
<!-- <div class="music-content-time">
|
||||
<n-button @click="reduceCorrectionTime(0.2)">-</n-button>
|
||||
<n-button @click="addCorrectionTime(0.2)">+</n-button>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</n-drawer>
|
||||
@@ -153,6 +154,7 @@ import { useI18n } from 'vue-i18n';
|
||||
|
||||
import LyricSettings from '@/components/lyric/LyricSettings.vue';
|
||||
import MiniPlayBar from '@/components/player/MiniPlayBar.vue';
|
||||
import LyricCorrectionControl from '@/components/lyric/LyricCorrectionControl.vue';
|
||||
import {
|
||||
artistList,
|
||||
lrcArray,
|
||||
@@ -160,7 +162,9 @@ import {
|
||||
playMusic,
|
||||
setAudioTime,
|
||||
textColors,
|
||||
useLyricProgress
|
||||
useLyricProgress,
|
||||
correctionTime,
|
||||
adjustCorrectionTime
|
||||
} from '@/hooks/MusicHook';
|
||||
import { useArtist } from '@/hooks/useArtist';
|
||||
import { usePlayerStore } from '@/store/modules/player';
|
||||
@@ -797,4 +801,12 @@ defineExpose({
|
||||
color: white;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.lyric-correction-btns-mac {
|
||||
/* 仅在 hover 歌词区域时显示 */
|
||||
.music-lrc:hover & {
|
||||
opacity: 1 !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user