Add logger functions and move player functions to feature
This commit is contained in:
parent
adf5fc348a
commit
69f82a9427
3 changed files with 197 additions and 143 deletions
|
@ -1,7 +1,11 @@
|
||||||
import console from 'console';
|
import console from 'console';
|
||||||
import { ipcMain } from 'electron';
|
import { app, ipcMain } from 'electron';
|
||||||
import { getMpvInstance } from '../../../main';
|
import uniq from 'lodash/uniq';
|
||||||
|
import MpvAPI from 'node-mpv';
|
||||||
|
import { getMainWindow, sendToastToRenderer } from '../../../main';
|
||||||
import { PlayerData } from '/@/renderer/store';
|
import { PlayerData } from '/@/renderer/store';
|
||||||
|
import { isWindows } from '../../../utils';
|
||||||
|
import { store } from '../settings';
|
||||||
|
|
||||||
declare module 'node-mpv';
|
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<string, any>;
|
||||||
|
}): Promise<MpvAPI> => {
|
||||||
|
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<string, any>) => {
|
||||||
|
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<string, any> }) => {
|
||||||
|
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<string, any> }) => {
|
||||||
|
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 () => {
|
ipcMain.handle('player-is-running', async () => {
|
||||||
return getMpvInstance()?.isRunning();
|
return getMpvInstance()?.isRunning();
|
||||||
});
|
});
|
||||||
|
@ -203,3 +351,12 @@ ipcMain.on('player-mute', async (_event, mute: boolean) => {
|
||||||
ipcMain.handle('player-get-time', async (): Promise<number | undefined> => {
|
ipcMain.handle('player-get-time', async (): Promise<number | undefined> => {
|
||||||
return getMpvInstance()?.getTimePosition();
|
return getMpvInstance()?.getTimePosition();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.on('before-quit', () => {
|
||||||
|
getMpvInstance()?.stop();
|
||||||
|
getMpvInstance()?.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
getMpvInstance()?.quit();
|
||||||
|
});
|
||||||
|
|
162
src/main/main.ts
162
src/main/main.ts
|
@ -26,14 +26,19 @@ import {
|
||||||
net,
|
net,
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import electronLocalShortcut from 'electron-localshortcut';
|
import electronLocalShortcut from 'electron-localshortcut';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log/main';
|
||||||
import { autoUpdater } from 'electron-updater';
|
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 { disableMediaKeys, enableMediaKeys } from './features/core/player/media-keys';
|
||||||
import { store } from './features/core/settings/index';
|
import { store } from './features/core/settings/index';
|
||||||
import MenuBuilder from './menu';
|
import MenuBuilder from './menu';
|
||||||
import { hotkeyToElectronAccelerator, isLinux, isMacOS, isWindows, resolveHtmlPath } from './utils';
|
import {
|
||||||
|
hotkeyToElectronAccelerator,
|
||||||
|
isLinux,
|
||||||
|
isMacOS,
|
||||||
|
isWindows,
|
||||||
|
resolveHtmlPath,
|
||||||
|
createLog,
|
||||||
|
} from './utils';
|
||||||
import './features';
|
import './features';
|
||||||
import type { TitleTheme } from '/@/renderer/types';
|
import type { TitleTheme } from '/@/renderer/types';
|
||||||
|
|
||||||
|
@ -433,138 +438,6 @@ const createWindow = async () => {
|
||||||
|
|
||||||
app.commandLine.appendSwitch('disable-features', 'HardwareMediaKeyHandling,MediaSessionService');
|
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<string, any>;
|
|
||||||
}): Promise<MpvAPI> => {
|
|
||||||
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<string, any>) => {
|
|
||||||
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<string, any> }) => {
|
|
||||||
mpvInstance?.quit();
|
|
||||||
mpvInstance = await createMpv(data);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
ipcMain.handle(
|
|
||||||
'player-initialize',
|
|
||||||
async (_event, data: { extraParameters?: string[]; properties?: Record<string, any> }) => {
|
|
||||||
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
|
// Must duplicate with the one in renderer process settings.store.ts
|
||||||
enum BindingActions {
|
enum BindingActions {
|
||||||
GLOBAL_SEARCH = 'globalSearch',
|
GLOBAL_SEARCH = 'globalSearch',
|
||||||
|
@ -647,14 +520,21 @@ ipcMain.on(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
app.on('before-quit', () => {
|
ipcMain.on(
|
||||||
getMpvInstance()?.stop();
|
'logger',
|
||||||
getMpvInstance()?.quit();
|
(
|
||||||
});
|
_event,
|
||||||
|
data: {
|
||||||
|
message: string;
|
||||||
|
type: 'debug' | 'verbose' | 'success' | 'error' | 'warning' | 'info';
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
createLog(data);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
globalShortcut.unregisterAll();
|
globalShortcut.unregisterAll();
|
||||||
getMpvInstance()?.quit();
|
|
||||||
// Respect the OSX convention of having the application in memory even
|
// Respect the OSX convention of having the application in memory even
|
||||||
// after all windows have been closed
|
// after all windows have been closed
|
||||||
if (isMacOS()) {
|
if (isMacOS()) {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import process from 'process';
|
import process from 'process';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
|
import log from 'electron-log/main';
|
||||||
|
|
||||||
export let resolveHtmlPath: (htmlFileName: string) => string;
|
export let resolveHtmlPath: (htmlFileName: string) => string;
|
||||||
|
|
||||||
|
@ -50,3 +51,19 @@ export const hotkeyToElectronAccelerator = (hotkey: string) => {
|
||||||
|
|
||||||
return accelerator;
|
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);
|
||||||
|
};
|
||||||
|
|
Reference in a new issue