'use strict'; import { app, protocol, BrowserWindow, shell, dialog, globalShortcut, nativeTheme, } from 'electron'; import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'; import { startNeteaseMusicApi } from './electron/services'; import { initIpcMain } from './electron/ipcMain.js'; import { createMenu } from './electron/menu'; import { createTray } from '@/electron/tray'; import { createTouchBar } from './electron/touchBar'; import { createDockMenu } from './electron/dockMenu'; import { registerGlobalShortcut } from './electron/globalShortcut'; import { autoUpdater } from 'electron-updater'; import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'; import express from 'express'; import expressProxy from 'express-http-proxy'; import Store from 'electron-store'; class Background { constructor() { this.window = null; this.tray = null; this.store = new Store({ windowWidth: { width: { type: 'number', default: 1440 }, height: { type: 'number', default: 840 }, }, }); this.neteaseMusicAPI = null; this.expressApp = null; this.willQuitApp = process.platform === 'darwin' ? false : true; this.init(); } init() { console.log('initializing'); // Make sure the app is singleton. if (!app.requestSingleInstanceLock()) return app.quit(); // start netease music api this.neteaseMusicAPI = startNeteaseMusicApi(); // create Express app this.createExpressApp(); // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([ { scheme: 'app', privileges: { secure: true, standard: true } }, ]); // handle app events this.handleAppEvents(); } async initDevtools() { // Install Vue Devtools extension try { await installExtension(VUEJS_DEVTOOLS); } catch (e) { console.error('Vue Devtools failed to install:', e.toString()); } // Exit cleanly on request from parent process in development mode. if (process.platform === 'win32') { process.on('message', data => { if (data === 'graceful-exit') { app.quit(); } }); } else { process.on('SIGTERM', () => { app.quit(); }); } } createExpressApp() { console.log('creating express app'); const expressApp = express(); expressApp.use('/', express.static(__dirname + '/')); expressApp.use('/api', expressProxy('http://127.0.0.1:10754')); this.expressApp = expressApp.listen(27232); } createWindow() { console.log('creating app window'); const appearance = this.store.get('settings.appearance'); this.window = new BrowserWindow({ width: this.store.get('window.width') || 1440, height: this.store.get('window.height') || 840, minWidth: 1080, minHeight: 720, titleBarStyle: 'hiddenInset', frame: process.platform !== 'win32', title: 'YesPlayMusic', webPreferences: { webSecurity: false, nodeIntegration: true, enableRemoteModule: true, contextIsolation: false, }, backgroundColor: ((appearance === undefined || appearance === 'auto') && nativeTheme.shouldUseDarkColors) || appearance === 'dark' ? '#222' : '#fff', }); // hide menu bar on Microsoft Windows and Linux this.window.setMenuBarVisibility(false); if (process.env.WEBPACK_DEV_SERVER_URL) { // Load the url of the dev server if in development mode this.window.loadURL(process.env.WEBPACK_DEV_SERVER_URL); if (!process.env.IS_TEST) this.window.webContents.openDevTools(); } else { createProtocol('app'); this.window.loadURL('http://localhost:27232'); } } checkForUpdates() { autoUpdater.checkForUpdatesAndNotify(); const showNewVersionMessage = info => { dialog .showMessageBox({ title: '发现新版本 v' + info.version, message: '发现新版本 v' + info.version, detail: '是否前往 GitHub 下载新版本安装包?', buttons: ['下载', '取消'], type: 'question', noLink: true, }) .then(result => { if (result.response === 0) { shell.openExternal( 'https://github.com/qier222/YesPlayMusic/releases' ); } }); }; autoUpdater.on('update-available', info => { showNewVersionMessage(info); }); } handleWindowEvents() { this.window.once('ready-to-show', () => { console.log('windows ready-to-show event'); this.window.show(); }); this.window.on('close', e => { console.log('windows close event'); if (this.willQuitApp) { /* the user tried to quit the app */ this.window = null; app.quit(); } else { /* the user only tried to close the window */ e.preventDefault(); this.window.hide(); } }); this.window.on('resize', () => { let { height, width } = this.window.getBounds(); this.store.set('window', { height, width }); }); this.window.on('minimize', () => { if ( ['win32', 'linux'].includes(process.platform) && this.store.get('settings.minimizeToTray') ) { this.window.hide(); } }); this.window.webContents.on('new-window', function (e, url) { e.preventDefault(); console.log('open url'); const excludeHosts = ['www.last.fm']; const exclude = excludeHosts.find(host => url.includes(host)); if (exclude) { const newWindow = new BrowserWindow({ width: 800, height: 600, titleBarStyle: 'default', title: 'YesPlayMusic', webPreferences: { webSecurity: false, nodeIntegration: true, enableRemoteModule: true, contextIsolation: false, }, }); newWindow.loadURL(url); return; } shell.openExternal(url); }); } handleAppEvents() { app.on('ready', async () => { // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. console.log('app ready event'); // for development if (process.env.NODE_ENV !== 'production') { this.initDevtools(); } // create window this.createWindow(); this.handleWindowEvents(); // init ipcMain initIpcMain(this.window, this.store); // check for updates this.checkForUpdates(); // create menu createMenu(this.window); // create tray if (['win32', 'linux'].includes(process.platform)) { this.tray = createTray(this.window); } // create dock menu for macOS app.dock.setMenu(createDockMenu(this.window)); // create touch bar this.window.setTouchBar(createTouchBar(this.window)); // register global shortcuts if (this.store.get('settings.enableGlobalShortcut')) { registerGlobalShortcut(this.window); } }); app.on('activate', () => { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. console.log('app activate event'); if (this.window === null) { this.createWindow(); } else { this.window.show(); } }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('before-quit', () => { this.willQuitApp = true; }); app.on('quit', () => { this.expressApp.close(); }); app.on('will-quit', () => { // unregister all global shortcuts globalShortcut.unregisterAll(); }); } } new Background();