From 69f82a94273473efb3a0255cf6c2a0b3911c856e Mon Sep 17 00:00:00 2001 From: jeffvli Date: Mon, 12 Feb 2024 13:58:50 -0800 Subject: [PATCH] Add logger functions and move player functions to feature --- src/main/features/core/player/index.ts | 161 +++++++++++++++++++++++- src/main/main.ts | 162 ++++--------------------- src/main/utils.ts | 17 +++ 3 files changed, 197 insertions(+), 143 deletions(-) diff --git a/src/main/features/core/player/index.ts b/src/main/features/core/player/index.ts index facd1b1a..b1843acc 100644 --- a/src/main/features/core/player/index.ts +++ b/src/main/features/core/player/index.ts @@ -1,7 +1,11 @@ import console from 'console'; -import { ipcMain } from 'electron'; -import { getMpvInstance } from '../../../main'; +import { app, ipcMain } from 'electron'; +import uniq from 'lodash/uniq'; +import MpvAPI from 'node-mpv'; +import { getMainWindow, sendToastToRenderer } from '../../../main'; import { PlayerData } from '/@/renderer/store'; +import { isWindows } from '../../../utils'; +import { store } from '../settings'; declare module 'node-mpv'; @@ -13,6 +17,150 @@ declare module 'node-mpv'; // }); // } +let mpvInstance: MpvAPI | null = null; + +const MPV_BINARY_PATH = store.get('mpv_path') as string | undefined; +const isDevelopment = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; + +const prefetchPlaylistParams = [ + '--prefetch-playlist=no', + '--prefetch-playlist=yes', + '--prefetch-playlist', +]; + +const DEFAULT_MPV_PARAMETERS = (extraParameters?: string[]) => { + const parameters = ['--idle=yes', '--no-config', '--load-scripts=no']; + + if (!extraParameters?.some((param) => prefetchPlaylistParams.includes(param))) { + parameters.push('--prefetch-playlist=yes'); + } + + return parameters; +}; + +const createMpv = async (data: { + extraParameters?: string[]; + properties?: Record; +}): Promise => { + const { extraParameters, properties } = data; + + const params = uniq([...DEFAULT_MPV_PARAMETERS(extraParameters), ...(extraParameters || [])]); + console.log('Setting mpv params: ', params); + + const extra = isDevelopment ? '-dev' : ''; + + const mpv = new MpvAPI( + { + audio_only: true, + auto_restart: false, + binary: MPV_BINARY_PATH || undefined, + socket: isWindows() ? `\\\\.\\pipe\\mpvserver${extra}` : `/tmp/node-mpv${extra}.sock`, + time_update: 1, + }, + params, + ); + + try { + await mpv.start(); + } catch (error: { message: string; stack: any } | any) { + console.log('MPV failed to start', error); + } finally { + console.log('Setting MPV properties: ', properties); + await mpv.setMultipleProperties(properties || {}); + } + + mpv.on('status', (status, ...rest) => { + console.log('MPV Event: status', status.property, status.value, rest); + if (status.property === 'playlist-pos') { + if (status.value === -1) { + mpv?.stop(); + } + + if (status.value !== 0) { + getMainWindow()?.webContents.send('renderer-player-auto-next'); + } + } + }); + + // Automatically updates the play button when the player is playing + mpv.on('resumed', () => { + console.log('MPV Event: resumed'); + getMainWindow()?.webContents.send('renderer-player-play'); + }); + + // Automatically updates the play button when the player is stopped + mpv.on('stopped', () => { + console.log('MPV Event: stopped'); + getMainWindow()?.webContents.send('renderer-player-stop'); + }); + + // Automatically updates the play button when the player is paused + mpv.on('paused', () => { + console.log('MPV Event: paused'); + getMainWindow()?.webContents.send('renderer-player-pause'); + }); + + // Event output every interval set by time_update, used to update the current time + mpv.on('timeposition', (time: number) => { + getMainWindow()?.webContents.send('renderer-player-current-time', time); + }); + + mpv.on('quit', () => { + console.log('MPV Event: quit'); + }); + + return mpv; +}; + +export const getMpvInstance = () => { + return mpvInstance; +}; + +ipcMain.on('player-set-properties', async (_event, data: Record) => { + if (data.length === 0) { + return; + } + + if (data.length === 1) { + getMpvInstance()?.setProperty(Object.keys(data)[0], Object.values(data)[0]); + } else { + getMpvInstance()?.setMultipleProperties(data); + } +}); + +ipcMain.on( + 'player-restart', + async (_event, data: { extraParameters?: string[]; properties?: Record }) => { + console.log('Initializing MPV with data: ', data); + mpvInstance?.quit(); + try { + mpvInstance = await createMpv(data); + } catch (err) { + console.log('init error', err); + sendToastToRenderer({ message: 'Initialization error', type: 'error' }); + } + }, +); + +ipcMain.handle( + 'player-initialize', + async (_event, data: { extraParameters?: string[]; properties?: Record }) => { + console.log('Initializing MPV with data: ', data); + try { + mpvInstance = await createMpv(data); + } catch (err) { + console.log('init error', err); + sendToastToRenderer({ message: 'Initialization error', type: 'error' }); + } + }, +); + +ipcMain.on('player-quit', async () => { + mpvInstance?.stop(); + mpvInstance?.quit(); + mpvInstance = null; +}); + ipcMain.handle('player-is-running', async () => { return getMpvInstance()?.isRunning(); }); @@ -203,3 +351,12 @@ ipcMain.on('player-mute', async (_event, mute: boolean) => { ipcMain.handle('player-get-time', async (): Promise => { return getMpvInstance()?.getTimePosition(); }); + +app.on('before-quit', () => { + getMpvInstance()?.stop(); + getMpvInstance()?.quit(); +}); + +app.on('window-all-closed', () => { + getMpvInstance()?.quit(); +}); diff --git a/src/main/main.ts b/src/main/main.ts index 235cf345..fd124e47 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -26,14 +26,19 @@ import { net, } from 'electron'; import electronLocalShortcut from 'electron-localshortcut'; -import log from 'electron-log'; +import log from 'electron-log/main'; import { autoUpdater } from 'electron-updater'; -import uniq from 'lodash/uniq'; -import MpvAPI from 'node-mpv'; import { disableMediaKeys, enableMediaKeys } from './features/core/player/media-keys'; import { store } from './features/core/settings/index'; import MenuBuilder from './menu'; -import { hotkeyToElectronAccelerator, isLinux, isMacOS, isWindows, resolveHtmlPath } from './utils'; +import { + hotkeyToElectronAccelerator, + isLinux, + isMacOS, + isWindows, + resolveHtmlPath, + createLog, +} from './utils'; import './features'; import type { TitleTheme } from '/@/renderer/types'; @@ -433,138 +438,6 @@ const createWindow = async () => { app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling,MediaSessionService'); -const MPV_BINARY_PATH = store.get('mpv_path') as string | undefined; - -const prefetchPlaylistParams = [ - '--prefetch-playlist=no', - '--prefetch-playlist=yes', - '--prefetch-playlist', -]; - -const DEFAULT_MPV_PARAMETERS = (extraParameters?: string[]) => { - const parameters = ['--idle=yes', '--no-config', '--load-scripts=no']; - - if (!extraParameters?.some((param) => prefetchPlaylistParams.includes(param))) { - parameters.push('--prefetch-playlist=yes'); - } - - return parameters; -}; - -let mpvInstance: MpvAPI | null = null; - -const createMpv = async (data: { - extraParameters?: string[]; - properties?: Record; -}): Promise => { - const { extraParameters, properties } = data; - - const params = uniq([...DEFAULT_MPV_PARAMETERS(extraParameters), ...(extraParameters || [])]); - console.log('Setting mpv params: ', params); - - const extra = isDevelopment ? '-dev' : ''; - - const mpv = new MpvAPI( - { - audio_only: true, - auto_restart: false, - binary: MPV_BINARY_PATH || '', - socket: isWindows() ? `\\\\.\\pipe\\mpvserver${extra}` : `/tmp/node-mpv${extra}.sock`, - time_update: 1, - }, - params, - ); - - try { - await mpv.start(); - } catch (error) { - console.log('MPV failed to start', error); - } finally { - console.log('Setting MPV properties: ', properties); - await mpv.setMultipleProperties(properties || {}); - } - - mpv.on('status', (status, ...rest) => { - console.log('MPV Event: status', status.property, status.value, rest); - if (status.property === 'playlist-pos') { - if (status.value === -1) { - mpv?.stop(); - } - - if (status.value !== 0) { - getMainWindow()?.webContents.send('renderer-player-auto-next'); - } - } - }); - - // Automatically updates the play button when the player is playing - mpv.on('resumed', () => { - console.log('MPV Event: resumed'); - getMainWindow()?.webContents.send('renderer-player-play'); - }); - - // Automatically updates the play button when the player is stopped - mpv.on('stopped', () => { - console.log('MPV Event: stopped'); - getMainWindow()?.webContents.send('renderer-player-stop'); - }); - - // Automatically updates the play button when the player is paused - mpv.on('paused', () => { - console.log('MPV Event: paused'); - getMainWindow()?.webContents.send('renderer-player-pause'); - }); - - // Event output every interval set by time_update, used to update the current time - mpv.on('timeposition', (time: number) => { - getMainWindow()?.webContents.send('renderer-player-current-time', time); - }); - - mpv.on('quit', () => { - console.log('MPV Event: quit'); - }); - - return mpv; -}; - -export const getMpvInstance = () => { - return mpvInstance; -}; - -ipcMain.on('player-set-properties', async (_event, data: Record) => { - if (data.length === 0) { - return; - } - - if (data.length === 1) { - getMpvInstance()?.setProperty(Object.keys(data)[0], Object.values(data)[0]); - } else { - getMpvInstance()?.setMultipleProperties(data); - } -}); - -ipcMain.on( - 'player-restart', - async (_event, data: { extraParameters?: string[]; properties?: Record }) => { - mpvInstance?.quit(); - mpvInstance = await createMpv(data); - }, -); - -ipcMain.handle( - 'player-initialize', - async (_event, data: { extraParameters?: string[]; properties?: Record }) => { - console.log('Initializing MPV with data: ', data); - mpvInstance = await createMpv(data); - }, -); - -ipcMain.on('player-quit', async () => { - mpvInstance?.stop(); - mpvInstance?.quit(); - mpvInstance = null; -}); - // Must duplicate with the one in renderer process settings.store.ts enum BindingActions { GLOBAL_SEARCH = 'globalSearch', @@ -647,14 +520,21 @@ ipcMain.on( }, ); -app.on('before-quit', () => { - getMpvInstance()?.stop(); - getMpvInstance()?.quit(); -}); +ipcMain.on( + 'logger', + ( + _event, + data: { + message: string; + type: 'debug' | 'verbose' | 'success' | 'error' | 'warning' | 'info'; + }, + ) => { + createLog(data); + }, +); app.on('window-all-closed', () => { globalShortcut.unregisterAll(); - getMpvInstance()?.quit(); // Respect the OSX convention of having the application in memory even // after all windows have been closed if (isMacOS()) { diff --git a/src/main/utils.ts b/src/main/utils.ts index 5ca169b3..ab49f2a1 100644 --- a/src/main/utils.ts +++ b/src/main/utils.ts @@ -2,6 +2,7 @@ import path from 'path'; import process from 'process'; import { URL } from 'url'; +import log from 'electron-log/main'; export let resolveHtmlPath: (htmlFileName: string) => string; @@ -50,3 +51,19 @@ export const hotkeyToElectronAccelerator = (hotkey: string) => { return accelerator; }; + +const logInstance = { + debug: log.debug, + error: log.error, + info: log.info, + success: log.info, + verbose: log.verbose, + warning: log.warn, +}; + +export const createLog = (data: { + message: string; + type: 'debug' | 'verbose' | 'success' | 'error' | 'warning' | 'info'; +}) => { + logInstance[data.type](data.message); +};