mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-14 14:50:50 +08:00
✨ feat: 优化桌面歌词添加歌曲控制 上一首下一首 播放暂停
This commit is contained in:
2
app.js
2
app.js
@@ -66,7 +66,7 @@ function createWindow() {
|
||||
store.set('set', setJson);
|
||||
}
|
||||
|
||||
loadLyricWindow(ipcMain);
|
||||
loadLyricWindow(ipcMain, mainWin);
|
||||
}
|
||||
|
||||
// 限制只能启动一个应用
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const { BrowserWindow, screen } = require('electron');
|
||||
const { BrowserWindow, screen, ipcRenderer } = require('electron');
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
|
||||
let lyricWindow = null;
|
||||
let isDragging = false;
|
||||
|
||||
const createWin = () => {
|
||||
console.log('Creating lyric window');
|
||||
lyricWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 200,
|
||||
@@ -21,16 +21,26 @@ const createWin = () => {
|
||||
webSecurity: false,
|
||||
},
|
||||
});
|
||||
|
||||
// 监听窗口关闭事件
|
||||
lyricWindow.on('closed', () => {
|
||||
console.log('Lyric window closed');
|
||||
lyricWindow = null;
|
||||
});
|
||||
};
|
||||
|
||||
const loadLyricWindow = (ipcMain) => {
|
||||
const loadLyricWindow = (ipcMain, mainWin) => {
|
||||
ipcMain.on('open-lyric', () => {
|
||||
console.log('Received open-lyric request');
|
||||
if (lyricWindow) {
|
||||
console.log('Lyric window exists, focusing');
|
||||
if (lyricWindow.isMinimized()) lyricWindow.restore();
|
||||
lyricWindow.focus();
|
||||
lyricWindow.show();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Creating new lyric window');
|
||||
createWin();
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
lyricWindow.webContents.openDevTools({ mode: 'detach' });
|
||||
@@ -41,26 +51,39 @@ const loadLyricWindow = (ipcMain) => {
|
||||
}
|
||||
|
||||
lyricWindow.setMinimumSize(600, 200);
|
||||
|
||||
// 隐藏任务栏
|
||||
lyricWindow.setSkipTaskbar(true);
|
||||
|
||||
lyricWindow.show();
|
||||
lyricWindow.once('ready-to-show', () => {
|
||||
console.log('Lyric window ready to show');
|
||||
lyricWindow.show();
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on('send-lyric', (e, data) => {
|
||||
if (lyricWindow) {
|
||||
lyricWindow.webContents.send('receive-lyric', data);
|
||||
if (lyricWindow && !lyricWindow.isDestroyed()) {
|
||||
try {
|
||||
lyricWindow.webContents.send('receive-lyric', data);
|
||||
} catch (error) {
|
||||
console.error('Error processing lyric data:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('Cannot send lyric: window not available or destroyed');
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('top-lyric', (e, data) => {
|
||||
lyricWindow.setAlwaysOnTop(data);
|
||||
if (lyricWindow && !lyricWindow.isDestroyed()) {
|
||||
lyricWindow.setAlwaysOnTop(data);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('close-lyric', () => {
|
||||
lyricWindow.close();
|
||||
lyricWindow = null;
|
||||
if (lyricWindow && !lyricWindow.isDestroyed()) {
|
||||
lyricWindow.webContents.send('lyric-window-close');
|
||||
mainWin.webContents.send('lyric-control-back', 'close');
|
||||
lyricWindow.close();
|
||||
lyricWindow = null;
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('mouseenter-lyric', () => {
|
||||
@@ -71,11 +94,6 @@ const loadLyricWindow = (ipcMain) => {
|
||||
lyricWindow.setIgnoreMouseEvents(false);
|
||||
});
|
||||
|
||||
// 开始拖动
|
||||
ipcMain.on('lyric-drag-start', () => {
|
||||
isDragging = true;
|
||||
});
|
||||
|
||||
// 处理拖动移动
|
||||
ipcMain.on('lyric-drag-move', (e, { deltaX, deltaY }) => {
|
||||
if (!lyricWindow) return;
|
||||
@@ -91,11 +109,6 @@ const loadLyricWindow = (ipcMain) => {
|
||||
lyricWindow.setPosition(newX, newY);
|
||||
});
|
||||
|
||||
// 结束拖动
|
||||
ipcMain.on('lyric-drag-end', () => {
|
||||
isDragging = false;
|
||||
});
|
||||
|
||||
// 添加鼠标穿透事件处理
|
||||
ipcMain.on('set-ignore-mouse', (e, shouldIgnore) => {
|
||||
if (!lyricWindow) return;
|
||||
@@ -108,6 +121,12 @@ const loadLyricWindow = (ipcMain) => {
|
||||
lyricWindow.setIgnoreMouseEvents(false);
|
||||
}
|
||||
});
|
||||
|
||||
// 添加播放控制处理
|
||||
ipcMain.on('control-back', (e, command) => {
|
||||
console.log('Received control-back request:', command);
|
||||
mainWin.webContents.send('lyric-control-back', command);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -17,6 +17,7 @@ export const correctionTime = ref(0.4); // 歌词矫正时间Correction time
|
||||
export const currentLrcProgress = ref(0); // 来存储当前歌词的进度
|
||||
export const playMusic = computed(() => store.state.playMusic as SongResult); // 当前播放歌曲
|
||||
export const sound = ref<Howl | null>(audioService.getCurrentSound());
|
||||
export const isLyricWindowOpen = ref(false); // 新增状态
|
||||
|
||||
document.onkeyup = (e) => {
|
||||
// 检查事件目标是否是输入框元素
|
||||
@@ -53,13 +54,18 @@ watch(
|
||||
watch(
|
||||
() => store.state.playMusic,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
nextTick(async () => {
|
||||
lrcArray.value = playMusic.value.lyric?.lrcArray || [];
|
||||
lrcTimeArray.value = playMusic.value.lyric?.lrcTimeArray || [];
|
||||
// 当歌词数据更新时,如果歌词窗口打开,则发送数据
|
||||
if (isElectron.value && isLyricWindowOpen.value && lrcArray.value.length > 0) {
|
||||
sendLyricToWin();
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -76,8 +82,13 @@ export const audioServiceOn = (audio: typeof audioService) => {
|
||||
if (newIndex !== nowIndex.value) {
|
||||
nowIndex.value = newIndex;
|
||||
currentLrcProgress.value = 0;
|
||||
// 当歌词索引更新时,发送歌词数据
|
||||
if (isElectron.value && isLyricWindowOpen.value) {
|
||||
sendLyricToWin();
|
||||
}
|
||||
}
|
||||
if (isElectron.value) {
|
||||
// 定期发送歌词数据更新
|
||||
if (isElectron.value && isLyricWindowOpen.value) {
|
||||
sendLyricToWin();
|
||||
}
|
||||
}, 50);
|
||||
@@ -87,11 +98,14 @@ export const audioServiceOn = (audio: typeof audioService) => {
|
||||
audio.onPause(() => {
|
||||
store.commit('setPlayMusic', false);
|
||||
clearInterval(interval);
|
||||
// 暂停时也发送一次状态更新
|
||||
if (isElectron.value && isLyricWindowOpen.value) {
|
||||
sendLyricToWin();
|
||||
}
|
||||
});
|
||||
|
||||
// 监听结束
|
||||
audio.onEnd(() => {
|
||||
handleEnded();
|
||||
if (store.state.playMode === 1) {
|
||||
// 单曲循环模式
|
||||
audio.getCurrentSound()?.play();
|
||||
@@ -213,7 +227,7 @@ export const useLyricProgress = () => {
|
||||
};
|
||||
};
|
||||
|
||||
// 设置当前播放时间
|
||||
// 设置<EFBFBD><EFBFBD><EFBFBD>前播放时间
|
||||
export const setAudioTime = (index: number) => {
|
||||
const currentSound = sound.value;
|
||||
if (!currentSound) return;
|
||||
@@ -241,72 +255,33 @@ export const getLrcTimeRange = (index: number) => ({
|
||||
watch(
|
||||
() => lrcArray.value,
|
||||
(newLrcArray) => {
|
||||
if (newLrcArray.length > 0 && isElectron.value) {
|
||||
// 重新初始化歌词数据
|
||||
initLyricWindow();
|
||||
// 发送当前状态
|
||||
if (newLrcArray.length > 0 && isElectron.value && isLyricWindowOpen.value) {
|
||||
sendLyricToWin();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// 监听播放状态变化
|
||||
watch(isPlaying, (newIsPlaying) => {
|
||||
if (isElectron.value) {
|
||||
sendLyricToWin(newIsPlaying);
|
||||
}
|
||||
});
|
||||
|
||||
// 处理歌曲结束
|
||||
export const handleEnded = () => {
|
||||
if (isElectron.value) {
|
||||
setTimeout(() => {
|
||||
initLyricWindow();
|
||||
sendLyricToWin();
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化歌词数据
|
||||
export const initLyricWindow = () => {
|
||||
if (!isElectron.value) return;
|
||||
try {
|
||||
if (lrcArray.value.length > 0) {
|
||||
console.log('Initializing lyric window with data:', {
|
||||
lrcArray: lrcArray.value,
|
||||
lrcTimeArray: lrcTimeArray.value,
|
||||
allTime: allTime.value,
|
||||
});
|
||||
|
||||
const staticData = {
|
||||
type: 'init',
|
||||
lrcArray: lrcArray.value,
|
||||
lrcTimeArray: lrcTimeArray.value,
|
||||
allTime: allTime.value,
|
||||
};
|
||||
windowData.electronAPI.sendLyric(JSON.stringify(staticData));
|
||||
} else {
|
||||
console.log('No lyrics available for initialization');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing lyric window:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 发送歌词更新数据
|
||||
export const sendLyricToWin = (isPlay: boolean = true) => {
|
||||
if (!isElectron.value) return;
|
||||
export const sendLyricToWin = () => {
|
||||
if (!isElectron.value || !isLyricWindowOpen.value) {
|
||||
console.log('Cannot send lyric: electron or lyric window not available');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (lrcArray.value.length > 0) {
|
||||
const nowIndex = getLrcIndex(nowTime.value);
|
||||
const updateData = {
|
||||
type: 'update',
|
||||
type: 'full',
|
||||
nowIndex,
|
||||
nowTime: nowTime.value,
|
||||
startCurrentTime: lrcTimeArray.value[nowIndex],
|
||||
nextTime: lrcTimeArray.value[nowIndex + 1],
|
||||
isPlay,
|
||||
isPlay: isPlaying.value,
|
||||
lrcArray: lrcArray.value,
|
||||
lrcTimeArray: lrcTimeArray.value,
|
||||
allTime: allTime.value,
|
||||
playMusic: playMusic.value,
|
||||
};
|
||||
windowData.electronAPI.sendLyric(JSON.stringify(updateData));
|
||||
}
|
||||
@@ -317,13 +292,55 @@ export const sendLyricToWin = (isPlay: boolean = true) => {
|
||||
|
||||
export const openLyric = () => {
|
||||
if (!isElectron.value) return;
|
||||
console.log('Opening lyric window');
|
||||
console.log('Opening lyric window with current song:', playMusic.value?.name);
|
||||
windowData.electronAPI.openLyric();
|
||||
isLyricWindowOpen.value = true;
|
||||
|
||||
// 延迟一下初始化,确保窗口已经创建
|
||||
setTimeout(() => {
|
||||
console.log('Initializing lyric window after delay');
|
||||
initLyricWindow();
|
||||
sendLyricToWin();
|
||||
if (isLyricWindowOpen.value) {
|
||||
console.log('Initializing lyric window with data:', {
|
||||
hasLyrics: lrcArray.value.length > 0,
|
||||
songName: playMusic.value?.name,
|
||||
});
|
||||
sendLyricToWin();
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 添加关闭歌词窗口的方法
|
||||
export const closeLyric = () => {
|
||||
if (!isElectron.value) return;
|
||||
isLyricWindowOpen.value = false;
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -69,7 +69,11 @@
|
||||
</n-tooltip>
|
||||
<n-tooltip v-if="isElectron" class="music-lyric" trigger="hover" :z-index="9999999">
|
||||
<template #trigger>
|
||||
<i class="iconfont ri-netease-cloud-music-line" @click="openLyric"></i>
|
||||
<i
|
||||
class="iconfont ri-netease-cloud-music-line"
|
||||
:class="{ 'text-green-500': isLyricWindowOpen }"
|
||||
@click="openLyricWindow"
|
||||
></i>
|
||||
</template>
|
||||
歌词
|
||||
</n-tooltip>
|
||||
@@ -113,7 +117,7 @@ import { useTemplateRef } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
import SongItem from '@/components/common/SongItem.vue';
|
||||
import { allTime, isElectron, nowTime, openLyric, sound } from '@/hooks/MusicHook';
|
||||
import { allTime, isElectron, isLyricWindowOpen, nowTime, openLyric, sound } from '@/hooks/MusicHook';
|
||||
import type { SongResult } from '@/type/music';
|
||||
import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils';
|
||||
|
||||
@@ -253,6 +257,10 @@ const toggleFavorite = async (e: Event) => {
|
||||
store.commit('addToFavorite', playMusic.value.id);
|
||||
}
|
||||
};
|
||||
|
||||
const openLyricWindow = () => {
|
||||
openLyric();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -18,15 +18,28 @@
|
||||
<i class="ri-add-line"></i>
|
||||
</n-button>
|
||||
</n-button-group>
|
||||
<div>{{ staticData.playMusic.name }}</div>
|
||||
</div>
|
||||
<!-- 添加播放控制按钮 -->
|
||||
<div class="play-controls">
|
||||
<div class="control-button" @click="handlePrev">
|
||||
<i class="ri-skip-back-fill"></i>
|
||||
</div>
|
||||
<div class="control-button play-button" @click="handlePlayPause">
|
||||
<i :class="dynamicData.isPlay ? 'ri-pause-fill' : 'ri-play-fill'"></i>
|
||||
</div>
|
||||
<div class="control-button" @click="handleNext">
|
||||
<i class="ri-skip-forward-fill"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-buttons">
|
||||
<div class="control-button" @click="checkTheme">
|
||||
<i v-if="lyricSetting.theme === 'light'" class="ri-sun-line"></i>
|
||||
<i v-else class="ri-moon-line"></i>
|
||||
</div>
|
||||
<div class="control-button" @click="handleTop">
|
||||
<!-- <div class="control-button" @click="handleTop">
|
||||
<i class="ri-pushpin-line" :class="{ active: lyricSetting.isTop }"></i>
|
||||
</div>
|
||||
</div> -->
|
||||
<div id="lyric-lock" class="control-button" @click="handleLock">
|
||||
<i v-if="lyricSetting.isLock" class="ri-lock-line"></i>
|
||||
<i v-else class="ri-lock-unlock-line"></i>
|
||||
@@ -46,7 +59,10 @@
|
||||
v-for="(line, index) in staticData.lrcArray"
|
||||
:key="index"
|
||||
class="lyric-line"
|
||||
:style="lyricLineStyle"
|
||||
:style="{
|
||||
...lyricLineStyle,
|
||||
display: line.text ? 'flex' : 'none',
|
||||
}"
|
||||
:class="{
|
||||
'lyric-line-current': index === currentIndex,
|
||||
'lyric-line-passed': index < currentIndex,
|
||||
@@ -71,18 +87,18 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
|
||||
import { SongResult } from '@/type/music';
|
||||
|
||||
defineOptions({
|
||||
name: 'Lyric',
|
||||
});
|
||||
|
||||
const windowData = window as any;
|
||||
const containerRef = ref<HTMLElement | null>(null);
|
||||
const containerHeight = ref(0);
|
||||
const lineHeight = ref(60);
|
||||
const currentIndex = ref(0);
|
||||
const isInitialized = ref(false);
|
||||
// 字体大小控制
|
||||
const fontSize = ref(24); // 默认字体大小
|
||||
const fontSizeStep = 2; // 每次整的步长
|
||||
@@ -94,10 +110,12 @@ const staticData = ref<{
|
||||
lrcArray: Array<{ text: string; trText: string }>;
|
||||
lrcTimeArray: number[];
|
||||
allTime: number;
|
||||
playMusic: SongResult;
|
||||
}>({
|
||||
lrcArray: [],
|
||||
lrcTimeArray: [],
|
||||
allTime: 0,
|
||||
playMusic: {} as SongResult,
|
||||
});
|
||||
|
||||
// 动态数据
|
||||
@@ -140,7 +158,6 @@ const clearHideTimer = () => {
|
||||
|
||||
// 处理鼠标进入窗口
|
||||
const handleMouseEnter = () => {
|
||||
console.log('handleMouseEnter');
|
||||
if (lyricSetting.value.isLock) {
|
||||
isHovering.value = true;
|
||||
windowData.electron.ipcRenderer.send('set-ignore-mouse', true);
|
||||
@@ -151,7 +168,6 @@ const handleMouseEnter = () => {
|
||||
|
||||
// 处理鼠标离开窗口
|
||||
const handleMouseLeave = () => {
|
||||
console.log('handleMouseLeave');
|
||||
if (!lyricSetting.value.isLock) return;
|
||||
isHovering.value = false;
|
||||
windowData.electron.ipcRenderer.send('set-ignore-mouse', false);
|
||||
@@ -180,7 +196,7 @@ onUnmounted(() => {
|
||||
|
||||
// 计算歌词滚动位置
|
||||
const wrapperStyle = computed(() => {
|
||||
if (!isInitialized.value || !containerHeight.value) {
|
||||
if (!containerHeight.value) {
|
||||
return {
|
||||
transform: 'translateY(0)',
|
||||
transition: 'none',
|
||||
@@ -208,7 +224,7 @@ const wrapperStyle = computed(() => {
|
||||
|
||||
return {
|
||||
transform: `translateY(${finalOffset}px)`,
|
||||
transition: isInitialized.value ? 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)' : 'none',
|
||||
transition: 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -281,8 +297,8 @@ const actualTime = ref(0);
|
||||
|
||||
// 计算当前行的进度
|
||||
const currentProgress = computed(() => {
|
||||
const { startCurrentTime, nextTime, isPlay } = dynamicData.value;
|
||||
if (!startCurrentTime || !nextTime || !isPlay) return 0;
|
||||
const { startCurrentTime, nextTime } = dynamicData.value;
|
||||
if (!startCurrentTime || !nextTime) return 0;
|
||||
|
||||
const duration = nextTime - startCurrentTime;
|
||||
const elapsed = actualTime.value - startCurrentTime;
|
||||
@@ -364,22 +380,34 @@ const handleDataUpdate = (parsedData: {
|
||||
nextTime: number;
|
||||
isPlay: boolean;
|
||||
nowIndex: number;
|
||||
lrcArray: Array<{ text: string; trText: string }>;
|
||||
lrcTimeArray: number[];
|
||||
allTime: number;
|
||||
playMusic: SongResult;
|
||||
}) => {
|
||||
// 确保数据存在且格式正确
|
||||
if (!parsedData || typeof parsedData.nowTime !== 'number') {
|
||||
if (!parsedData) {
|
||||
console.error('Invalid update data received:', parsedData);
|
||||
return;
|
||||
}
|
||||
// 更新静态数据
|
||||
staticData.value = {
|
||||
lrcArray: parsedData.lrcArray || [],
|
||||
lrcTimeArray: parsedData.lrcTimeArray || [],
|
||||
allTime: parsedData.allTime || 0,
|
||||
playMusic: parsedData.playMusic || {},
|
||||
};
|
||||
|
||||
// 更新动态数据
|
||||
dynamicData.value = {
|
||||
nowTime: parsedData.nowTime,
|
||||
startCurrentTime: parsedData.startCurrentTime,
|
||||
nextTime: parsedData.nextTime,
|
||||
nowTime: parsedData.nowTime || 0,
|
||||
startCurrentTime: parsedData.startCurrentTime || 0,
|
||||
nextTime: parsedData.nextTime || 0,
|
||||
isPlay: parsedData.isPlay,
|
||||
};
|
||||
|
||||
// 更新索引
|
||||
if (typeof parsedData.nowIndex === 'number' && parsedData.nowIndex !== currentIndex.value) {
|
||||
if (typeof parsedData.nowIndex === 'number') {
|
||||
currentIndex.value = parsedData.nowIndex;
|
||||
}
|
||||
};
|
||||
@@ -400,33 +428,7 @@ onMounted(() => {
|
||||
windowData.electron.ipcRenderer.on('receive-lyric', (data: string) => {
|
||||
try {
|
||||
const parsedData = JSON.parse(data);
|
||||
if (parsedData.type === 'init') {
|
||||
// 初始化重置状态
|
||||
currentIndex.value = 0;
|
||||
isInitialized.value = false;
|
||||
|
||||
// 清理可能存在的动画
|
||||
if (animationFrameId.value) {
|
||||
cancelAnimationFrame(animationFrameId.value);
|
||||
animationFrameId.value = null;
|
||||
}
|
||||
|
||||
// 确保数据格式正确
|
||||
if (Array.isArray(parsedData.lrcArray)) {
|
||||
staticData.value = {
|
||||
lrcArray: parsedData.lrcArray,
|
||||
lrcTimeArray: parsedData.lrcTimeArray || [],
|
||||
allTime: parsedData.allTime || 0,
|
||||
};
|
||||
} else {
|
||||
console.error('Invalid lyric array format:', parsedData);
|
||||
}
|
||||
nextTick(() => {
|
||||
isInitialized.value = true;
|
||||
});
|
||||
} else if (parsedData.type === 'update') {
|
||||
handleDataUpdate(parsedData);
|
||||
}
|
||||
handleDataUpdate(parsedData);
|
||||
} catch (error) {
|
||||
console.error('Error parsing lyric data:', error);
|
||||
}
|
||||
@@ -467,7 +469,7 @@ watch(
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// 添加拖动相关变量
|
||||
// 添<EFBFBD><EFBFBD>拖动相关变量
|
||||
const isDragging = ref(false);
|
||||
const startPosition = ref({ x: 0, y: 0 });
|
||||
|
||||
@@ -534,6 +536,19 @@ onMounted(() => {
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 添加播放控制相关的函数
|
||||
const handlePlayPause = () => {
|
||||
windowData.electron.ipcRenderer.send('control-back', 'playpause');
|
||||
};
|
||||
|
||||
const handlePrev = () => {
|
||||
windowData.electron.ipcRenderer.send('control-back', 'prev');
|
||||
};
|
||||
|
||||
const handleNext = () => {
|
||||
windowData.electron.ipcRenderer.send('control-back', 'next');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -554,7 +569,7 @@ body {
|
||||
cursor: default;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
.control-bar {
|
||||
&-show {
|
||||
opacity: 1;
|
||||
@@ -571,7 +586,7 @@ body {
|
||||
--text-color: #ffffff;
|
||||
--text-secondary: rgba(255, 255, 255, 0.6);
|
||||
--highlight-color: #1db954;
|
||||
--control-bg: rgba(0, 0, 0, 0.3);
|
||||
--control-bg: rgba(124, 124, 124, 0.3);
|
||||
}
|
||||
|
||||
&.light {
|
||||
@@ -584,13 +599,13 @@ body {
|
||||
|
||||
.control-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 40px;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
align-items: start;
|
||||
padding: 0 20px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
@@ -600,13 +615,28 @@ body {
|
||||
z-index: 100;
|
||||
|
||||
.font-size-controls {
|
||||
margin-right: auto; // 将字体控制放在侧
|
||||
padding-right: 20px;
|
||||
-webkit-app-region: no-drag;
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.play-controls {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
.n-button {
|
||||
.play-button {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
i {
|
||||
font-size: 16px;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -623,23 +653,21 @@ body {
|
||||
}
|
||||
|
||||
.control-button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
border-radius: 8px;
|
||||
color: var(--text-color);
|
||||
transition: all 0.2s ease;
|
||||
backdrop-filter: blur(4px);
|
||||
|
||||
&:hover {
|
||||
background: var(--control-bg);
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
text-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
|
||||
&.active {
|
||||
@@ -650,7 +678,7 @@ body {
|
||||
|
||||
.lyric-container {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
@@ -689,8 +717,7 @@ body {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.lyric-line-passed,
|
||||
&.lyric-line-next {
|
||||
&.lyric-line-passed {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
@@ -751,6 +778,10 @@ body {
|
||||
.lyric_lock & .font-size-controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lyric_lock & .play-controls {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.lyric_lock {
|
||||
@@ -758,5 +789,12 @@ body {
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#lyric-lock {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 72px;
|
||||
background: var(--control-bg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user