YesPlayMusic/src/electron/ipcMain.js
memorydream d716bb8cde
feat: refactor tray (#1227)
* feat: support set tray icon tooltip info

* fix: name

* refactor tray impl and add tray playing state change

* fix: linux impl

* add pause icon

* add tray like state

* fix

* fix: linux impl

* better pause icon
2022-01-17 23:23:21 +08:00

289 lines
8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { app, dialog, globalShortcut, ipcMain } from 'electron';
import match from '@unblockneteasemusic/server';
import { registerGlobalShortcut } from '@/electron/globalShortcut';
import cloneDeep from 'lodash/cloneDeep';
import shortcuts from '@/utils/shortcuts';
import { createMenu } from './menu';
import { isCreateTray, isMac } from '@/utils/platform';
const clc = require('cli-color');
const log = text => {
console.log(`${clc.blueBright('[ipcMain.js]')} ${text}`);
};
const exitAsk = (e, win) => {
e.preventDefault(); //阻止默认行为
dialog
.showMessageBox({
type: 'info',
title: 'Information',
cancelId: 2,
defaultId: 0,
message: '确定要关闭吗?',
buttons: ['最小化', '直接退出'],
})
.then(result => {
if (result.response == 0) {
e.preventDefault(); //阻止默认行为
win.minimize(); //调用 最小化实例方法
} else if (result.response == 1) {
win = null;
//app.quit();
app.exit(); //exit()直接关闭客户端不会执行quit();
}
})
.catch(err => {
log(err);
});
};
const exitAskWithoutMac = (e, win) => {
e.preventDefault(); //阻止默认行为
dialog
.showMessageBox({
type: 'info',
title: 'Information',
cancelId: 2,
defaultId: 0,
message: '确定要关闭吗?',
buttons: ['最小化到托盘', '直接退出'],
checkboxLabel: '记住我的选择',
})
.then(result => {
if (result.checkboxChecked && result.response !== 2) {
win.webContents.send(
'rememberCloseAppOption',
result.response === 0 ? 'minimizeToTray' : 'exit'
);
}
if (result.response === 0) {
e.preventDefault(); //阻止默认行为
win.hide(); //调用 最小化实例方法
} else if (result.response === 1) {
win = null;
//app.quit();
app.exit(); //exit()直接关闭客户端不会执行quit();
}
})
.catch(err => {
log(err);
});
};
const client = require('discord-rich-presence')('818936529484906596');
/**
* Make data a Buffer.
*
* @param {?} data The data to convert.
* @returns {import("buffer").Buffer} The converted data.
*/
function toBuffer(data) {
if (data instanceof Buffer) {
return data;
} else {
return Buffer.from(data);
}
}
/**
* Get the file URI from bilivideo.
*
* @param {string} url The URL to fetch.
* @returns {Promise<string>} The file URI.
*/
async function getBiliVideoFile(url) {
const axios = await import('axios').then(m => m.default);
const response = await axios.get(url, {
headers: {
Referer: 'https://www.bilibili.com/',
'User-Agent': 'okhttp/3.4.1',
},
responseType: 'arraybuffer',
});
const buffer = toBuffer(response.data);
const encodedData = buffer.toString('base64');
return `data:application/octet-stream;base64,${encodedData}`;
}
/**
* Parse the source string (`a, b`) to source list `['a', 'b']`.
*
* @param {string} sourceString The source string.
* @returns {string[]} The source list.
*/
function parseSourceStringToList(sourceString) {
return sourceString.split(',').map(s => s.trim());
}
export function initIpcMain(win, store, trayEventEmitter) {
ipcMain.handle('unblock-music', async (_, track, source) => {
// 兼容 unblockneteasemusic 所使用的 api 字段
track.alias = track.alia || [];
track.duration = track.dt || 0;
track.album = track.al || [];
track.artists = track.ar || [];
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject('timeout');
}, 5000);
});
const sourceList =
typeof source === 'string' ? parseSourceStringToList(source) : null;
log(`[UNM] using source: ${sourceList || '<default>'}`);
try {
const matchedAudio = await Promise.race([
// TODO: tell users to install yt-dlp.
// we passed "null" to source, to let UNM choose the default source.
match(track.id, sourceList, track),
timeoutPromise,
]);
if (!matchedAudio || !matchedAudio.url) {
throw new Error('no such a song found');
}
// bilibili's audio file needs some special treatment
if (matchedAudio.url.includes('bilivideo.com')) {
matchedAudio.url = await getBiliVideoFile(matchedAudio.url);
}
return matchedAudio;
} catch (err) {
const errorMessage = err instanceof Error ? `${err.message}` : `${err}`;
log(`UnblockNeteaseMusic failed: ${errorMessage}`);
return null;
}
});
ipcMain.on('close', e => {
if (isMac) {
win.hide();
exitAsk(e, win);
} else {
let closeOpt = store.get('settings.closeAppOption');
if (closeOpt === 'exit') {
win = null;
//app.quit();
app.exit(); //exit()直接关闭客户端不会执行quit();
} else if (closeOpt === 'minimizeToTray') {
e.preventDefault();
win.hide();
} else {
exitAskWithoutMac(e, win);
}
}
});
ipcMain.on('minimize', () => {
win.minimize();
});
ipcMain.on('maximizeOrUnmaximize', () => {
const isMaximized = win.isMaximized();
isMaximized ? win.unmaximize() : win.maximize();
win.webContents.send('isMaximized', isMaximized);
});
ipcMain.on('settings', (event, options) => {
store.set('settings', options);
if (options.enableGlobalShortcut) {
registerGlobalShortcut(win, store);
} else {
log('unregister global shortcut');
globalShortcut.unregisterAll();
}
});
ipcMain.on('playDiscordPresence', (event, track) => {
client.updatePresence({
details: track.name + ' - ' + track.ar.map(ar => ar.name).join(','),
state: track.al.name,
endTimestamp: Date.now() + track.dt,
largeImageKey: 'logo',
largeImageText: 'Listening ' + track.name,
smallImageKey: 'play',
smallImageText: 'Playing',
instance: true,
});
});
ipcMain.on('pauseDiscordPresence', (event, track) => {
client.updatePresence({
details: track.name + ' - ' + track.ar.map(ar => ar.name).join(','),
state: track.al.name,
largeImageKey: 'logo',
largeImageText: 'YesPlayMusic',
smallImageKey: 'pause',
smallImageText: 'Pause',
instance: true,
});
});
ipcMain.on('setProxy', (event, config) => {
const proxyRules = `${config.protocol}://${config.server}:${config.port}`;
store.set('proxy', proxyRules);
win.webContents.session.setProxy(
{
proxyRules,
},
() => {
log('finished setProxy');
}
);
});
ipcMain.on('removeProxy', (event, arg) => {
log('removeProxy');
win.webContents.session.setProxy({});
store.set('proxy', '');
});
ipcMain.on('switchGlobalShortcutStatusTemporary', (e, status) => {
log('switchGlobalShortcutStatusTemporary');
if (status === 'disable') {
globalShortcut.unregisterAll();
} else {
registerGlobalShortcut(win, store);
}
});
ipcMain.on('updateShortcut', (e, { id, type, shortcut }) => {
log('updateShortcut');
let shortcuts = store.get('settings.shortcuts');
let newShortcut = shortcuts.find(s => s.id === id);
newShortcut[type] = shortcut;
store.set('settings.shortcuts', shortcuts);
createMenu(win, store);
globalShortcut.unregisterAll();
registerGlobalShortcut(win, store);
});
ipcMain.on('restoreDefaultShortcuts', () => {
log('restoreDefaultShortcuts');
store.set('settings.shortcuts', cloneDeep(shortcuts));
createMenu(win, store);
globalShortcut.unregisterAll();
registerGlobalShortcut(win, store);
});
if (isCreateTray) {
ipcMain.on('updateTrayTooltip', (_, title) => {
trayEventEmitter.emit('updateTooltip', title);
});
ipcMain.on('updateTrayPlayState', (_, isPlaying) => {
trayEventEmitter.emit('updatePlayState', isPlaying);
});
ipcMain.on('updateTrayLikeState', (_, isLiked) => {
trayEventEmitter.emit('updateLikeState', isLiked);
});
}
}