2024-10-18 18:37:53 +08:00
|
|
|
|
import { computed, ref } from 'vue';
|
|
|
|
|
|
|
2024-12-12 22:18:52 +08:00
|
|
|
|
import { audioService } from '@/services/audioService';
|
2024-10-18 18:37:53 +08:00
|
|
|
|
import store from '@/store';
|
|
|
|
|
|
import type { ILyricText, SongResult } from '@/type/music';
|
2023-12-17 14:48:21 +08:00
|
|
|
|
|
2024-09-12 16:44:42 +08:00
|
|
|
|
const windowData = window as any;
|
|
|
|
|
|
|
2024-10-18 18:37:53 +08:00
|
|
|
|
export const isElectron = computed(() => !!windowData.electronAPI);
|
|
|
|
|
|
|
|
|
|
|
|
export const lrcArray = ref<ILyricText[]>([]); // 歌词数组
|
|
|
|
|
|
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(() => store.state.playMusic as SongResult); // 当前播放歌曲
|
2024-12-12 22:18:52 +08:00
|
|
|
|
export const sound = ref<Howl | null>(audioService.getCurrentSound());
|
2024-12-16 22:12:28 +08:00
|
|
|
|
export const isLyricWindowOpen = ref(false); // 新增状态
|
2024-12-12 22:18:52 +08:00
|
|
|
|
|
|
|
|
|
|
document.onkeyup = (e) => {
|
2024-12-14 13:00:06 +08:00
|
|
|
|
// 检查事件目标是否是输入框元素
|
|
|
|
|
|
const target = e.target as HTMLElement;
|
|
|
|
|
|
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-12 22:18:52 +08:00
|
|
|
|
switch (e.code) {
|
|
|
|
|
|
case 'Space':
|
|
|
|
|
|
if (store.state.play) {
|
|
|
|
|
|
store.commit('setPlayMusic', false);
|
|
|
|
|
|
audioService.getCurrentSound()?.pause();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
store.commit('setPlayMusic', true);
|
|
|
|
|
|
audioService.getCurrentSound()?.play();
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => store.state.playMusicUrl,
|
|
|
|
|
|
(newVal) => {
|
|
|
|
|
|
if (newVal) {
|
|
|
|
|
|
audioService.play(newVal);
|
|
|
|
|
|
sound.value = audioService.getCurrentSound();
|
|
|
|
|
|
audioServiceOn(audioService);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
2024-10-18 18:37:53 +08:00
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => store.state.playMusic,
|
|
|
|
|
|
() => {
|
2024-12-16 22:12:28 +08:00
|
|
|
|
nextTick(async () => {
|
2024-10-18 18:37:53 +08:00
|
|
|
|
lrcArray.value = playMusic.value.lyric?.lrcArray || [];
|
|
|
|
|
|
lrcTimeArray.value = playMusic.value.lyric?.lrcTimeArray || [];
|
2024-12-16 22:12:28 +08:00
|
|
|
|
// 当歌词数据更新时,如果歌词窗口打开,则发送数据
|
|
|
|
|
|
if (isElectron.value && isLyricWindowOpen.value && lrcArray.value.length > 0) {
|
|
|
|
|
|
sendLyricToWin();
|
|
|
|
|
|
}
|
2024-10-18 18:37:53 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
deep: true,
|
2024-12-16 22:12:28 +08:00
|
|
|
|
immediate: true,
|
2024-10-18 18:37:53 +08:00
|
|
|
|
},
|
|
|
|
|
|
);
|
2024-12-12 22:18:52 +08:00
|
|
|
|
|
|
|
|
|
|
export const audioServiceOn = (audio: typeof audioService) => {
|
|
|
|
|
|
let interval: any = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 监听播放
|
|
|
|
|
|
audio.onPlay(() => {
|
|
|
|
|
|
store.commit('setPlayMusic', true);
|
|
|
|
|
|
interval = setInterval(() => {
|
|
|
|
|
|
nowTime.value = sound.value?.seek() as number;
|
|
|
|
|
|
allTime.value = sound.value?.duration() as number;
|
|
|
|
|
|
const newIndex = getLrcIndex(nowTime.value);
|
|
|
|
|
|
if (newIndex !== nowIndex.value) {
|
|
|
|
|
|
nowIndex.value = newIndex;
|
|
|
|
|
|
currentLrcProgress.value = 0;
|
2024-12-16 22:12:28 +08:00
|
|
|
|
// 当歌词索引更新时,发送歌词数据
|
|
|
|
|
|
if (isElectron.value && isLyricWindowOpen.value) {
|
|
|
|
|
|
sendLyricToWin();
|
|
|
|
|
|
}
|
2024-12-12 22:18:52 +08:00
|
|
|
|
}
|
2024-12-16 22:12:28 +08:00
|
|
|
|
// 定期发送歌词数据更新
|
|
|
|
|
|
if (isElectron.value && isLyricWindowOpen.value) {
|
2024-12-12 22:18:52 +08:00
|
|
|
|
sendLyricToWin();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 50);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 监听暂停
|
|
|
|
|
|
audio.onPause(() => {
|
|
|
|
|
|
store.commit('setPlayMusic', false);
|
|
|
|
|
|
clearInterval(interval);
|
2024-12-16 22:12:28 +08:00
|
|
|
|
// 暂停时也发送一次状态更新
|
|
|
|
|
|
if (isElectron.value && isLyricWindowOpen.value) {
|
|
|
|
|
|
sendLyricToWin();
|
|
|
|
|
|
}
|
2024-12-12 22:18:52 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 监听结束
|
|
|
|
|
|
audio.onEnd(() => {
|
2024-12-15 01:40:13 +08:00
|
|
|
|
if (store.state.playMode === 1) {
|
|
|
|
|
|
// 单曲循环模式
|
|
|
|
|
|
audio.getCurrentSound()?.play();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 列表循环模式
|
|
|
|
|
|
store.commit('nextPlay');
|
|
|
|
|
|
}
|
2024-12-12 22:18:52 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const play = () => {
|
|
|
|
|
|
audioService.getCurrentSound()?.play();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const pause = () => {
|
|
|
|
|
|
audioService.getCurrentSound()?.pause();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-10-18 18:37:53 +08:00
|
|
|
|
const isPlaying = computed(() => store.state.play as boolean);
|
2023-12-17 14:48:21 +08:00
|
|
|
|
|
|
|
|
|
|
// 增加矫正时间
|
2024-10-18 18:37:53 +08:00
|
|
|
|
export const addCorrectionTime = (time: number) => (correctionTime.value += time);
|
2023-12-17 14:48:21 +08:00
|
|
|
|
|
|
|
|
|
|
// 减少矫正时间
|
2024-10-18 18:37:53 +08:00
|
|
|
|
export const reduceCorrectionTime = (time: number) => (correctionTime.value -= time);
|
2023-12-17 14:48:21 +08:00
|
|
|
|
|
2024-10-18 18:37:53 +08:00
|
|
|
|
// 获取当前播放歌词
|
|
|
|
|
|
export const isCurrentLrc = (index: number, time: number): boolean => {
|
|
|
|
|
|
const currentTime = lrcTimeArray.value[index];
|
|
|
|
|
|
const nextTime = lrcTimeArray.value[index + 1];
|
2024-05-16 18:54:30 +08:00
|
|
|
|
const nowTime = time + correctionTime.value;
|
|
|
|
|
|
const isTrue = nowTime > currentTime && nowTime < nextTime;
|
|
|
|
|
|
return isTrue;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-10-18 18:37:53 +08:00
|
|
|
|
// 获取当前播放歌词INDEX
|
|
|
|
|
|
export const getLrcIndex = (time: number): number => {
|
2024-05-16 18:54:30 +08:00
|
|
|
|
for (let i = 0; i < lrcTimeArray.value.length; i++) {
|
|
|
|
|
|
if (isCurrentLrc(i, time)) {
|
2024-10-18 18:37:53 +08:00
|
|
|
|
nowIndex.value = i;
|
2024-05-16 18:54:30 +08:00
|
|
|
|
return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nowIndex.value;
|
|
|
|
|
|
};
|
2023-12-17 14:48:21 +08:00
|
|
|
|
|
2024-12-14 13:15:59 +08:00
|
|
|
|
// 获取当前播放歌词进度
|
2024-10-18 18:37:53 +08:00
|
|
|
|
const currentLrcTiming = computed(() => {
|
|
|
|
|
|
const start = lrcTimeArray.value[nowIndex.value] || 0;
|
|
|
|
|
|
const end = lrcTimeArray.value[nowIndex.value + 1] || start + 1;
|
|
|
|
|
|
return { start, end };
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 获取歌词样式
|
|
|
|
|
|
export const getLrcStyle = (index: number) => {
|
|
|
|
|
|
if (index === nowIndex.value) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
backgroundImage: `linear-gradient(to right, #ffffff ${currentLrcProgress.value}%, #ffffff8a ${currentLrcProgress.value}%)`,
|
|
|
|
|
|
backgroundClip: 'text',
|
|
|
|
|
|
WebkitBackgroundClip: 'text',
|
|
|
|
|
|
color: 'transparent',
|
|
|
|
|
|
transition: 'background-image 0.1s linear',
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return {};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 播放进度
|
|
|
|
|
|
export const useLyricProgress = () => {
|
|
|
|
|
|
let animationFrameId: number | null = null;
|
|
|
|
|
|
|
|
|
|
|
|
const updateProgress = () => {
|
|
|
|
|
|
if (!isPlaying.value) return;
|
2024-12-12 22:18:52 +08:00
|
|
|
|
const currentSound = sound.value;
|
|
|
|
|
|
if (!currentSound) return;
|
|
|
|
|
|
|
2024-10-18 18:37:53 +08:00
|
|
|
|
const { start, end } = currentLrcTiming.value;
|
|
|
|
|
|
const duration = end - start;
|
2024-12-12 22:18:52 +08:00
|
|
|
|
const elapsed = (currentSound.seek() as number) - start;
|
2024-10-18 18:37:53 +08:00
|
|
|
|
currentLrcProgress.value = Math.min(Math.max((elapsed / duration) * 100, 0), 100);
|
|
|
|
|
|
|
|
|
|
|
|
animationFrameId = requestAnimationFrame(updateProgress);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const startProgressAnimation = () => {
|
|
|
|
|
|
if (!animationFrameId && isPlaying.value) {
|
|
|
|
|
|
updateProgress();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const stopProgressAnimation = () => {
|
|
|
|
|
|
if (animationFrameId) {
|
|
|
|
|
|
cancelAnimationFrame(animationFrameId);
|
|
|
|
|
|
animationFrameId = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
watch(isPlaying, (newIsPlaying) => {
|
|
|
|
|
|
if (newIsPlaying) {
|
|
|
|
|
|
startProgressAnimation();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
stopProgressAnimation();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
if (isPlaying.value) {
|
|
|
|
|
|
startProgressAnimation();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
stopProgressAnimation();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
currentLrcProgress,
|
|
|
|
|
|
getLrcStyle,
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-12-16 22:12:28 +08:00
|
|
|
|
// 设置<E8AEBE><E7BDAE><EFBFBD>前播放时间
|
2024-12-12 22:18:52 +08:00
|
|
|
|
export const setAudioTime = (index: number) => {
|
|
|
|
|
|
const currentSound = sound.value;
|
|
|
|
|
|
if (!currentSound) return;
|
|
|
|
|
|
|
|
|
|
|
|
currentSound.seek(lrcTimeArray.value[index]);
|
|
|
|
|
|
currentSound.play();
|
2024-05-16 18:54:30 +08:00
|
|
|
|
};
|
2023-12-17 14:48:21 +08:00
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
|
// 获取当前播放的歌词
|
|
|
|
|
|
export const getCurrentLrc = () => {
|
|
|
|
|
|
const index = getLrcIndex(nowTime.value);
|
2024-10-18 18:37:53 +08:00
|
|
|
|
return {
|
|
|
|
|
|
currentLrc: lrcArray.value[index],
|
|
|
|
|
|
nextLrc: lrcArray.value[index + 1],
|
|
|
|
|
|
};
|
2024-05-16 18:54:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2024-12-12 22:18:52 +08:00
|
|
|
|
// 获取一句歌词播放时间几秒到几秒
|
2024-10-18 18:37:53 +08:00
|
|
|
|
export const getLrcTimeRange = (index: number) => ({
|
|
|
|
|
|
currentTime: lrcTimeArray.value[index],
|
|
|
|
|
|
nextTime: lrcTimeArray.value[index + 1],
|
|
|
|
|
|
});
|
2024-05-16 18:54:30 +08:00
|
|
|
|
|
2024-12-06 23:50:44 +08:00
|
|
|
|
// 监听歌词数组变化,当切换歌曲时重新初始化歌词窗口
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => lrcArray.value,
|
|
|
|
|
|
(newLrcArray) => {
|
2024-12-16 22:12:28 +08:00
|
|
|
|
if (newLrcArray.length > 0 && isElectron.value && isLyricWindowOpen.value) {
|
2024-12-06 23:50:44 +08:00
|
|
|
|
sendLyricToWin();
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 发送歌词更新数据
|
2024-12-16 22:12:28 +08:00
|
|
|
|
export const sendLyricToWin = () => {
|
|
|
|
|
|
if (!isElectron.value || !isLyricWindowOpen.value) {
|
|
|
|
|
|
console.log('Cannot send lyric: electron or lyric window not available');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-10-18 18:37:53 +08:00
|
|
|
|
|
2024-05-16 18:54:30 +08:00
|
|
|
|
try {
|
|
|
|
|
|
if (lrcArray.value.length > 0) {
|
|
|
|
|
|
const nowIndex = getLrcIndex(nowTime.value);
|
2024-12-06 23:50:44 +08:00
|
|
|
|
const updateData = {
|
2024-12-16 22:12:28 +08:00
|
|
|
|
type: 'full',
|
2024-05-16 18:54:30 +08:00
|
|
|
|
nowIndex,
|
|
|
|
|
|
nowTime: nowTime.value,
|
2024-10-18 18:37:53 +08:00
|
|
|
|
startCurrentTime: lrcTimeArray.value[nowIndex],
|
2024-12-06 23:50:44 +08:00
|
|
|
|
nextTime: lrcTimeArray.value[nowIndex + 1],
|
2024-12-16 22:12:28 +08:00
|
|
|
|
isPlay: isPlaying.value,
|
|
|
|
|
|
lrcArray: lrcArray.value,
|
|
|
|
|
|
lrcTimeArray: lrcTimeArray.value,
|
|
|
|
|
|
allTime: allTime.value,
|
|
|
|
|
|
playMusic: playMusic.value,
|
2024-05-16 18:54:30 +08:00
|
|
|
|
};
|
2024-12-06 23:50:44 +08:00
|
|
|
|
windowData.electronAPI.sendLyric(JSON.stringify(updateData));
|
2024-05-16 18:54:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
2024-12-06 23:50:44 +08:00
|
|
|
|
console.error('Error sending lyric update:', error);
|
2024-05-16 18:54:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const openLyric = () => {
|
2024-10-18 18:37:53 +08:00
|
|
|
|
if (!isElectron.value) return;
|
2024-12-16 22:12:28 +08:00
|
|
|
|
console.log('Opening lyric window with current song:', playMusic.value?.name);
|
2024-12-16 22:25:38 +08:00
|
|
|
|
|
|
|
|
|
|
isLyricWindowOpen.value = !isLyricWindowOpen.value;
|
|
|
|
|
|
if (isLyricWindowOpen.value) {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
windowData.electronAPI.openLyric();
|
2024-12-16 22:12:28 +08:00
|
|
|
|
sendLyricToWin();
|
2024-12-16 22:25:38 +08:00
|
|
|
|
}, 500);
|
|
|
|
|
|
sendLyricToWin();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
closeLyric();
|
|
|
|
|
|
}
|
2024-05-16 18:54:30 +08:00
|
|
|
|
};
|
2024-12-16 22:12:28 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加关闭歌词窗口的方法
|
|
|
|
|
|
export const closeLyric = () => {
|
|
|
|
|
|
if (!isElectron.value) return;
|
|
|
|
|
|
windowData.electron.ipcRenderer.send('close-lyric');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 添加播放控制命令监听
|
|
|
|
|
|
if (isElectron.value) {
|
|
|
|
|
|
windowData.electron.ipcRenderer.on('lyric-control-back', (command: string) => {
|
|
|
|
|
|
console.log('Received playback control command:', command);
|
|
|
|
|
|
switch (command) {
|
|
|
|
|
|
case 'playpause':
|
|
|
|
|
|
if (store.state.play) {
|
|
|
|
|
|
store.commit('setPlayMusic', false);
|
|
|
|
|
|
audioService.getCurrentSound()?.pause();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
store.commit('setPlayMusic', true);
|
|
|
|
|
|
audioService.getCurrentSound()?.play();
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'prev':
|
|
|
|
|
|
store.commit('prevPlay');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'next':
|
|
|
|
|
|
store.commit('nextPlay');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'close':
|
|
|
|
|
|
closeLyric();
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
console.log('Unknown command:', command);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|