1. 实现linux下的mpris和gnome状态栏歌词功能

This commit is contained in:
alger
2026-03-29 13:30:36 +08:00
committed by stark81
parent 8e3e4e610c
commit 33fc4f768c
5 changed files with 354 additions and 0 deletions
+53
View File
@@ -52,6 +52,8 @@ export const textColors = ref<any>(getTextColors());
export let playMusic: ComputedRef<SongResult>;
export let artistList: ComputedRef<Artist[]>;
let lastIndex = -1;
export const musicDB = await useIndexedDB(
'musicDB',
[
@@ -329,6 +331,12 @@ const setupAudioListeners = () => {
sendLyricToWin();
}
}
if (isElectron && lrcArray.value[nowIndex.value]) {
if (lastIndex !== nowIndex.value) {
sendTrayLyric(nowIndex.value);
lastIndex = nowIndex.value;
}
}
// === 逐字歌词行内进度 ===
const { start, end } = currentLrcTiming.value;
@@ -372,6 +380,15 @@ const setupAudioListeners = () => {
);
}
}
// === MPRIS 进度更新(每 ~1 秒)===
if (isElectron && lyricThrottleCounter % 20 === 0) {
try {
window.electron.ipcRenderer.send('mpris-position-update', currentTime);
} catch {
// 忽略发送失败
}
}
} catch (error) {
console.error('进度更新 interval 出错:', error);
// 出错时不清除 interval,让下一次 tick 继续尝试
@@ -420,6 +437,11 @@ const setupAudioListeners = () => {
if (typeof currentTime === 'number' && !Number.isNaN(currentTime)) {
nowTime.value = currentTime;
// === MPRIS seek 时同步进度 ===
if (isElectron) {
window.electron.ipcRenderer.send('mpris-position-update', currentTime);
}
// 检查是否需要更新歌词
const newIndex = getLrcIndex(nowTime.value);
if (newIndex !== nowIndex.value) {
@@ -807,6 +829,37 @@ export const sendLyricToWin = () => {
}
};
// 发送歌词到系统托盘歌词(TrayLyric)
const sendTrayLyric = (index: number) => {
const platformValue = window.electron.ipcRenderer.sendSync('get-platform');
console.log(
'[TrayLyric] sendTrayLyric called, isElectron:',
isElectron,
'platform:',
platformValue
);
if (!isElectron || platformValue !== 'linux') return;
try {
const lyric = lrcArray.value[index];
if (!lyric) return;
const currentTime = lrcTimeArray.value[index] || 0;
const nextTime = lrcTimeArray.value[index + 1] || currentTime + 3;
const duration = nextTime - currentTime;
const lrcObj = JSON.stringify({
content: lyric.text || '',
time: duration.toFixed(1),
sender: 'AlgerMusicPlayer'
});
window.electron.ipcRenderer.send('tray-lyric-update', lrcObj);
} catch (error) {
console.error('[TrayLyric] Failed to send:', error);
}
};
// 歌词同步定时器
let lyricSyncInterval: any = null;
+15
View File
@@ -1,6 +1,7 @@
import { onMounted, onUnmounted } from 'vue';
import i18n from '@/../i18n/renderer';
import { audioService } from '@/services/audioService';
import { usePlayerStore, useSettingsStore } from '@/store';
import {
@@ -37,6 +38,18 @@ const onUpdateAppShortcuts = (_event: unknown, shortcuts: unknown) => {
updateAppShortcuts(shortcuts);
};
const onMprisSeek = (_event: unknown, position: number) => {
if (audioService) {
audioService.seek(position);
}
};
const onMprisSetPosition = (_event: unknown, position: number) => {
if (audioService) {
audioService.seek(position);
}
};
function shouldSkipAction(action: ShortcutAction): boolean {
const now = Date.now();
const lastTimestamp = actionTimestamps.get(action) ?? 0;
@@ -192,6 +205,8 @@ export function initAppShortcuts() {
window.electron.ipcRenderer.on('global-shortcut', onGlobalShortcut);
window.electron.ipcRenderer.on('update-app-shortcuts', onUpdateAppShortcuts);
window.electron.ipcRenderer.on('mpris-seek', onMprisSeek);
window.electron.ipcRenderer.on('mpris-set-position', onMprisSetPosition);
const storedShortcuts = window.electron.ipcRenderer.sendSync('get-store-value', 'shortcuts');
updateAppShortcuts(storedShortcuts);