mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2024-11-24 10:15:27 +08:00
Merge pull request #1818 from Revincx/revincx-pr
This commit is contained in:
commit
fd40a29180
BIN
public/img/icons/menu-dark@88.png
Normal file
BIN
public/img/icons/menu-dark@88.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -31,7 +31,8 @@ import { EventEmitter } from 'events';
|
|||
import express from 'express';
|
||||
import expressProxy from 'express-http-proxy';
|
||||
import Store from 'electron-store';
|
||||
import { createMpris } from '@/electron/mpris';
|
||||
import { createMpris, createDbus } from '@/electron/mpris';
|
||||
import { spawn } from 'child_process';
|
||||
const clc = require('cli-color');
|
||||
const log = text => {
|
||||
console.log(`${clc.blueBright('[background.js]')} ${text}`);
|
||||
|
@ -420,6 +421,21 @@ class Background {
|
|||
registerGlobalShortcut(this.window, this.store);
|
||||
}
|
||||
|
||||
// try to start osdlyrics process on start
|
||||
if (this.store.get('settings.enableOsdlyricsSupport')) {
|
||||
await createDbus(this.window);
|
||||
log('try to start osdlyrics process');
|
||||
const osdlyricsProcess = spawn('osdlyrics');
|
||||
|
||||
osdlyricsProcess.on('error', err => {
|
||||
log(`failed to start osdlyrics: ${err.message}`);
|
||||
});
|
||||
|
||||
osdlyricsProcess.on('exit', (code, signal) => {
|
||||
log(`osdlyrics process exited with code ${code}, signal ${signal}`);
|
||||
});
|
||||
}
|
||||
|
||||
// create mpris
|
||||
if (isCreateMpris) {
|
||||
createMpris(this.window);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import dbus from 'dbus-next';
|
||||
import { ipcMain, app } from 'electron';
|
||||
|
||||
export function createMpris(window) {
|
||||
|
@ -28,6 +29,8 @@ export function createMpris(window) {
|
|||
});
|
||||
|
||||
ipcMain.on('metadata', (e, metadata) => {
|
||||
// 更新 Mpris 状态前将位置设为0, 否则 OSDLyrics 获取到的进度是上首音乐切换时的进度
|
||||
player.getPosition = () => 0;
|
||||
player.metadata = {
|
||||
'mpris:trackid': player.objectPath('track/' + metadata.trackId),
|
||||
'mpris:artUrl': metadata.artwork[0].src,
|
||||
|
@ -41,6 +44,11 @@ export function createMpris(window) {
|
|||
|
||||
ipcMain.on('playerCurrentTrackTime', (e, position) => {
|
||||
player.getPosition = () => position * 1000 * 1000;
|
||||
player.seeked(position * 1000 * 1000);
|
||||
});
|
||||
|
||||
ipcMain.on('seeked', (e, position) => {
|
||||
player.seeked(position * 1000 * 1000);
|
||||
});
|
||||
|
||||
ipcMain.on('switchRepeatMode', (e, mode) => {
|
||||
|
@ -61,3 +69,26 @@ export function createMpris(window) {
|
|||
player.shuffle = shuffle;
|
||||
});
|
||||
}
|
||||
|
||||
export async function createDbus(window) {
|
||||
const bus = dbus.sessionBus();
|
||||
const Variant = dbus.Variant;
|
||||
|
||||
const osdService = await bus.getProxyObject(
|
||||
'org.osdlyrics.Daemon',
|
||||
'/org/osdlyrics/Lyrics'
|
||||
);
|
||||
|
||||
const osdInterface = osdService.getInterface('org.osdlyrics.Lyrics');
|
||||
|
||||
ipcMain.on('sendLyrics', async (e, { track, lyrics }) => {
|
||||
const metadata = {
|
||||
title: new Variant('s', track.name),
|
||||
artist: new Variant('s', track.ar.map(ar => ar.name).join(', ')),
|
||||
};
|
||||
|
||||
await osdInterface.SetLyricContent(metadata, Buffer.from(lyrics));
|
||||
|
||||
window.webContents.send('saveLyricFinished');
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* global __static */
|
||||
import path from 'path';
|
||||
import { app, nativeImage, Tray, Menu } from 'electron';
|
||||
import { app, nativeImage, Tray, Menu, nativeTheme } from 'electron';
|
||||
import { isLinux } from '@/utils/platform';
|
||||
|
||||
function createMenuTemplate(win) {
|
||||
|
@ -197,8 +197,11 @@ class YPMTrayWindowsImpl {
|
|||
}
|
||||
|
||||
export function createTray(win, eventEmitter) {
|
||||
// 感觉图标颜色应该不属于界面主题范畴,只需要跟随系统主题
|
||||
let iconTheme = nativeTheme.shouldUseDarkColors ? 'light' : 'dark';
|
||||
|
||||
let icon = nativeImage
|
||||
.createFromPath(path.join(__static, 'img/icons/menu@88.png'))
|
||||
.createFromPath(path.join(__static, `img/icons/menu-${iconTheme}@88.png`))
|
||||
.resize({
|
||||
height: 20,
|
||||
width: 20,
|
||||
|
|
|
@ -193,6 +193,13 @@ export default {
|
|||
exit: 'Exit',
|
||||
minimizeToTray: 'Minimize to tray',
|
||||
},
|
||||
enableOsdlyricsSupport: {
|
||||
title: 'desktop lyrics support',
|
||||
desc1:
|
||||
'Only takes effect under Linux. After enabled, it downloads the lyrics file to the local, and tries to launch OSDLyrics at startup.',
|
||||
desc2:
|
||||
'Please ensure that you have installed OSDLyrics before turning on this.',
|
||||
},
|
||||
unm: {
|
||||
enable: 'Enable',
|
||||
audioSource: {
|
||||
|
|
|
@ -194,6 +194,12 @@ export default {
|
|||
exit: '退出',
|
||||
minimizeToTray: '最小化到托盘',
|
||||
},
|
||||
enableOsdlyricsSupport: {
|
||||
title: '桌面歌词支持',
|
||||
desc1:
|
||||
'仅 Linux 下生效。启用后会将歌词文件下载到本地,并在开启播放器时尝试拉起 OSDLyrics。',
|
||||
desc2: '请在开启之前确保您已经正确安装了 OSDLyrics。',
|
||||
},
|
||||
unm: {
|
||||
enable: '启用',
|
||||
audioSource: {
|
||||
|
|
|
@ -191,6 +191,12 @@ export default {
|
|||
exit: '退出',
|
||||
minimizeToTray: '最小化到工作列角落',
|
||||
},
|
||||
enableOsdlyricsSupport: {
|
||||
title: '桌面歌詞支援',
|
||||
desc1:
|
||||
'只在 Linux 環境下生效。啟用後會將歌詞檔案下載至本機位置,並在開啟播放器時嘗試連帶啟動 OSDLyrics。',
|
||||
desc2: '請在開啟之前確保您已經正確安裝了 OSDLyrics。',
|
||||
},
|
||||
unm: {
|
||||
enable: '啟用',
|
||||
audioSource: {
|
||||
|
|
|
@ -23,6 +23,7 @@ let localStorage = {
|
|||
nyancatStyle: false,
|
||||
showLyricsTranslation: true,
|
||||
lyricsBackground: true,
|
||||
enableOsdlyricsSupport: false,
|
||||
closeAppOption: 'ask',
|
||||
enableDiscordRichPresence: false,
|
||||
enableGlobalShortcut: true,
|
||||
|
|
|
@ -3,7 +3,7 @@ import { getArtist } from '@/api/artist';
|
|||
import { trackScrobble, trackUpdateNowPlaying } from '@/api/lastfm';
|
||||
import { fmTrash, personalFM } from '@/api/others';
|
||||
import { getPlaylistDetail, intelligencePlaylist } from '@/api/playlist';
|
||||
import { getMP3, getTrackDetail, scrobble } from '@/api/track';
|
||||
import { getLyric, getMP3, getTrackDetail, scrobble } from '@/api/track';
|
||||
import store from '@/store';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
import { cacheTrackSource, getTrackSource } from '@/utils/db';
|
||||
|
@ -201,6 +201,9 @@ export default class {
|
|||
set progress(value) {
|
||||
if (this._howler) {
|
||||
this._howler.seek(value);
|
||||
if (isCreateMpris) {
|
||||
ipcRenderer?.send('seeked', this._howler.seek());
|
||||
}
|
||||
}
|
||||
}
|
||||
get isCurrentTrackLiked() {
|
||||
|
@ -622,9 +625,30 @@ export default class {
|
|||
|
||||
navigator.mediaSession.metadata = new window.MediaMetadata(metadata);
|
||||
if (isCreateMpris) {
|
||||
ipcRenderer?.send('metadata', metadata);
|
||||
this._updateMprisState(track, metadata);
|
||||
}
|
||||
}
|
||||
// OSDLyrics 会检测 Mpris 状态并寻找对应歌词文件,所以要在更新 Mpris 状态之前保证歌词下载完成
|
||||
async _updateMprisState(track, metadata) {
|
||||
if (!store.state.settings.enableOsdlyricsSupport) {
|
||||
return ipcRenderer?.send('metadata', metadata);
|
||||
}
|
||||
|
||||
let lyricContent = await getLyric(track.id);
|
||||
|
||||
if (!lyricContent.lrc || !lyricContent.lrc.lyric) {
|
||||
return ipcRenderer?.send('metadata', metadata);
|
||||
}
|
||||
|
||||
ipcRenderer.send('sendLyrics', {
|
||||
track,
|
||||
lyrics: lyricContent.lrc.lyric,
|
||||
});
|
||||
|
||||
ipcRenderer.on('saveLyricFinished', () => {
|
||||
ipcRenderer?.send('metadata', metadata);
|
||||
});
|
||||
}
|
||||
_updateMediaSessionPositionState() {
|
||||
if ('mediaSession' in navigator === false) {
|
||||
return;
|
||||
|
@ -822,11 +846,14 @@ export default class {
|
|||
this.play();
|
||||
}
|
||||
}
|
||||
seek(time = null) {
|
||||
seek(time = null, sendMpris = true) {
|
||||
if (isCreateMpris && sendMpris && time) {
|
||||
ipcRenderer?.send('seeked', time);
|
||||
}
|
||||
if (time !== null) {
|
||||
this._howler?.seek(time);
|
||||
if (this._playing)
|
||||
this._playDiscordPresence(this._currentTrack, this.seek());
|
||||
this._playDiscordPresence(this._currentTrack, this.seek(null, false));
|
||||
}
|
||||
return this._howler === null ? 0 : this._howler.seek();
|
||||
}
|
||||
|
|
|
@ -566,7 +566,7 @@ export default {
|
|||
},
|
||||
setLyricsInterval() {
|
||||
this.lyricsInterval = setInterval(() => {
|
||||
const progress = this.player.seek() ?? 0;
|
||||
const progress = this.player.seek(null, false) ?? 0;
|
||||
let oldHighlightLyricIndex = this.highlightLyricIndex;
|
||||
this.highlightLyricIndex = this.lyric.findIndex((l, index) => {
|
||||
const nextLyric = this.lyric[index + 1];
|
||||
|
|
|
@ -251,6 +251,33 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isElectron && isLinux" class="item">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{ $t('settings.unm.enable') }}
|
||||
<a target="_blank" href="https://github.com/osdlyrics/osdlyrics"
|
||||
>OSDLyrics</a
|
||||
>
|
||||
{{ $t('settings.enableOsdlyricsSupport.title') }}
|
||||
</div>
|
||||
<div class="description">
|
||||
{{ $t('settings.enableOsdlyricsSupport.desc1') }}
|
||||
<br />
|
||||
{{ $t('settings.enableOsdlyricsSupport.desc2') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="toggle">
|
||||
<input
|
||||
id="enable-osdlyrics-support"
|
||||
v-model="enableOsdlyricsSupport"
|
||||
type="checkbox"
|
||||
name="enable-osdlyrics-support"
|
||||
/>
|
||||
<label for="enable-osdlyrics-support"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section v-if="isElectron" class="unm-configuration">
|
||||
<h3>UnblockNeteaseMusic</h3>
|
||||
|
@ -975,6 +1002,17 @@ export default {
|
|||
});
|
||||
},
|
||||
},
|
||||
enableOsdlyricsSupport: {
|
||||
get() {
|
||||
return this.settings.enableOsdlyricsSupport;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'enableOsdlyricsSupport',
|
||||
value,
|
||||
});
|
||||
},
|
||||
},
|
||||
closeAppOption: {
|
||||
get() {
|
||||
return this.settings.closeAppOption;
|
||||
|
@ -1477,6 +1515,7 @@ h3 {
|
|||
|
||||
select {
|
||||
min-width: 192px;
|
||||
max-width: 600px;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
padding: 8px 12px 8px 12px;
|
||||
|
|
Loading…
Reference in New Issue
Block a user