fix: plugin load

This commit is contained in:
JellyBrick
2023-11-11 19:23:17 +09:00
parent de0b228ae8
commit 1f96b6b44d
10 changed files with 69 additions and 99 deletions

View File

@ -50,6 +50,7 @@ export default defineConfig({
const commonConfig: UserConfig = { const commonConfig: UserConfig = {
plugins: [ plugins: [
viteResolve({ viteResolve({
'virtual:PluginBuilders': pluginVirtualModuleGenerator('index'),
'virtual:PreloadPlugins': pluginVirtualModuleGenerator('preload'), 'virtual:PreloadPlugins': pluginVirtualModuleGenerator('preload'),
}), }),
], ],
@ -86,6 +87,7 @@ export default defineConfig({
const commonConfig: UserConfig = { const commonConfig: UserConfig = {
plugins: [ plugins: [
viteResolve({ viteResolve({
'virtual:PluginBuilders': pluginVirtualModuleGenerator('index'),
'virtual:RendererPlugins': pluginVirtualModuleGenerator('renderer'), 'virtual:RendererPlugins': pluginVirtualModuleGenerator('renderer'),
}), }),
], ],

View File

@ -1,27 +1,16 @@
import { deepmerge } from '@fastify/deepmerge';
import store from './store'; import store from './store';
import defaultConfig from './defaults';
import { restart } from '../providers/app-controls'; import { restart } from '../providers/app-controls';
import { Entries } from '../utils/type-utils';
interface Plugin { import type { PluginBaseConfig } from '../plugins/utils/builder';
enabled: boolean;
}
type DefaultPluginsConfig = typeof defaultConfig.plugins; export function getPlugins() {
const deepmergeFn = deepmerge(); return store.get('plugins') as Record<string, PluginBaseConfig>;
export function getEnabled() {
const plugins = deepmergeFn(defaultConfig.plugins, (store.get('plugins') as DefaultPluginsConfig));
return (Object.entries(plugins) as Entries<DefaultPluginsConfig>).filter(([, options]) =>
(options as Plugin).enabled,
);
} }
export function isEnabled(plugin: string) { export function isEnabled(plugin: string) {
const pluginConfig = (store.get('plugins') as Record<string, Plugin>)[plugin]; const pluginConfig = (store.get('plugins') as Record<string, PluginBaseConfig>)[plugin];
return pluginConfig !== undefined && pluginConfig.enabled; return pluginConfig !== undefined && pluginConfig.enabled;
} }
@ -69,7 +58,7 @@ export function disable(plugin: string) {
export default { export default {
isEnabled, isEnabled,
getEnabled, getPlugins,
enable, enable,
disable, disable,
setOptions, setOptions,

View File

@ -10,6 +10,8 @@ import { autoUpdater } from 'electron-updater';
import electronDebug from 'electron-debug'; import electronDebug from 'electron-debug';
import { parse } from 'node-html-parser'; import { parse } from 'node-html-parser';
import { deepmerge as createDeepmerge } from '@fastify/deepmerge';
import config from './config'; import config from './config';
import { refreshMenu, setApplicationMenu } from './menu'; import { refreshMenu, setApplicationMenu } from './menu';
@ -26,7 +28,10 @@ import { pluginBuilders } from 'virtual:PluginBuilders';
/* eslint-enable import/order */ /* eslint-enable import/order */
import youtubeMusicCSS from './youtube-music.css?inline'; import youtubeMusicCSS from './youtube-music.css?inline';
import { MainPlugin, PluginBaseConfig, MainPluginContext, MainPluginFactory } from './plugins/utils/builder';
import type { MainPlugin, PluginBaseConfig, MainPluginContext, MainPluginFactory } from './plugins/utils/builder';
const deepmerge = createDeepmerge();
// Catch errors and log them // Catch errors and log them
unhandled({ unhandled({
@ -159,42 +164,30 @@ async function loadPlugins(win: BrowserWindow) {
}, },
}); });
const pluginConfigs = config.plugins.getPlugins();
for (const [pluginId, factory] of Object.entries(mainPlugins)) {
if (Object.hasOwn(pluginBuilders, pluginId)) {
const builder = pluginBuilders[pluginId as keyof PluginBuilderList];
const config = deepmerge(builder.config, pluginConfigs[pluginId as keyof PluginBuilderList]);
for (const [pluginId, options] of config.plugins.getEnabled()) { if (config?.enabled) {
const builder = pluginBuilders[pluginId as keyof PluginBuilderList]; builder.styles?.forEach((style) => {
const factory = (mainPlugins as Record<string, MainPluginFactory<PluginBaseConfig>>)[pluginId]; injectCSS(win.webContents, style);
console.log('[YTMusic]', `"${pluginId}" plugin meta data is loaded`);
});
if (builder) { try {
builder.styles?.forEach((style) => { const context = createContext(pluginId as keyof PluginBuilderList);
injectCSS(win.webContents, style); const plugin = await (factory as MainPluginFactory<PluginBaseConfig>)(context);
console.log('[YTMusic]', `"${pluginId}" plugin meta data is loaded`); loadedPluginList.push([pluginId, plugin]);
}); plugin.onLoad?.(win);
} console.log('[YTMusic]', `"${pluginId}" plugin is loaded`);
} catch (error) {
if (factory) { console.error('[YTMusic]', `Cannot load plugin "${pluginId}"`);
try { console.trace(error);
const context = createContext(pluginId as keyof PluginBuilderList); }
const plugin = await factory(context);
loadedPluginList.push([pluginId, plugin]);
plugin.onLoad?.(win);
console.log('[YTMusic]', `"${pluginId}" plugin is loaded`);
} catch (error) {
console.error('[YTMusic]', `Cannot load plugin "${pluginId}"`);
console.trace(error);
} }
} }
// try {
// if (Object.hasOwn(mainPlugins, plugin)) {
// console.log('Loaded plugin - ' + plugin);
// const handler = mainPlugins[plugin as keyof typeof mainPlugins];
// if (handler) {
// await handler(win, options as never);
// }
// }
// } catch (e) {
// console.error(`Failed to load plugin "${plugin}"`, e);
// }
} }
} }

View File

@ -26,7 +26,6 @@ export default builder.createRenderer(async ({ getConfig }) => {
if (!video) return null; if (!video) return null;
if (!wrapper) return null; if (!wrapper) return null;
console.log('injectBlurVideo', songVideo, video, wrapper);
const blurCanvas = document.createElement('canvas'); const blurCanvas = document.createElement('canvas');
blurCanvas.classList.add('html5-blur-canvas'); blurCanvas.classList.add('html5-blur-canvas');

View File

@ -49,7 +49,7 @@ export default builder.createMain(({ handle, send }) => {
if (target) target.click(undefined, BrowserWindow.fromWebContents(event.sender), event.sender); if (target) target.click(undefined, BrowserWindow.fromWebContents(event.sender), event.sender);
}); });
handle('get-menu-by-id', (_, commandId: number) => { handle('get-menu-by-id', (commandId: number) => {
const result = getMenuItemById(commandId); const result = getMenuItemById(commandId);
return JSON.parse(JSON.stringify( return JSON.parse(JSON.stringify(
@ -67,7 +67,7 @@ export default builder.createMain(({ handle, send }) => {
handle('window-unmaximize', () => win.unmaximize()); handle('window-unmaximize', () => win.unmaximize());
win.on('unmaximize', () => send('window-unmaximize')); win.on('unmaximize', () => send('window-unmaximize'));
handle('image-path-to-data-url', (_, imagePath: string) => { handle('image-path-to-data-url', (imagePath: string) => {
const nativeImageIcon = nativeImage.createFromPath(imagePath); const nativeImageIcon = nativeImage.createFromPath(imagePath);
return nativeImageIcon?.toDataURL(); return nativeImageIcon?.toDataURL();
}); });

View File

@ -20,7 +20,7 @@ export default builder.createMain(({ handle, getConfig }) =>{
revRomanized = true; revRomanized = true;
} }
handle('search-genius-lyrics', async (_, extractedSongInfo: SongInfo) => { handle('search-genius-lyrics', async (extractedSongInfo: SongInfo) => {
const metadata = extractedSongInfo; const metadata = extractedSongInfo;
return await fetchFromGenius(metadata); return await fetchFromGenius(metadata);
}); });

View File

@ -24,7 +24,7 @@ export default builder.createRenderer(({ on, invoke }) => ({
let unregister: (() => void) | null = null; let unregister: (() => void) | null = null;
on('update-song-info', (_, extractedSongInfo: SongInfo) => { on('update-song-info', (extractedSongInfo: SongInfo) => {
unregister?.(); unregister?.();
setTimeout(async () => { setTimeout(async () => {

View File

@ -261,8 +261,8 @@ export default builder.createRenderer(async ({ on, getConfig, setConfig }) => {
document.addEventListener('apiLoaded', (e) => { document.addEventListener('apiLoaded', (e) => {
api = e.detail; api = e.detail;
on('changeVolume', (_, toIncrease: boolean) => changeVolume(toIncrease)); on('changeVolume', (toIncrease: boolean) => changeVolume(toIncrease));
on('setVolume', (_, value: number) => setVolume(value)); on('setVolume', (value: number) => setVolume(value));
firstRun(); firstRun();
}, { once: true, passive: true }); }, { once: true, passive: true });
}, },

View File

@ -1,13 +1,17 @@
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
import is from 'electron-is'; import is from 'electron-is';
import { pluginBuilders } from 'virtual:PluginBuilders';
import { deepmerge as createDeepmerge } from '@fastify/deepmerge';
import config from './config'; import config from './config';
// eslint-disable-next-line import/order // eslint-disable-next-line import/order
import { preloadPlugins } from 'virtual:PreloadPlugins'; import { preloadPlugins } from 'virtual:PreloadPlugins';
import { PluginBaseConfig, PluginContext, PreloadPluginFactory } from './plugins/utils/builder'; import { PluginBaseConfig, PluginContext, PreloadPluginFactory } from './plugins/utils/builder';
const enabledPluginNameAndOptions = config.plugins.getEnabled(); const deepmerge = createDeepmerge();
const createContext = < const createContext = <
Key extends keyof PluginBuilderList, Key extends keyof PluginBuilderList,
@ -22,12 +26,15 @@ const createContext = <
const preloadedPluginList = []; const preloadedPluginList = [];
enabledPluginNameAndOptions.forEach(async ([id]) => { const pluginConfig = config.plugins.getPlugins();
Object.entries(preloadPlugins)
.filter(([id]) => deepmerge(pluginBuilders[id as keyof PluginBuilderList].config, pluginConfig[id as keyof PluginBuilderList])?.enabled)
.forEach(async ([id]) => {
if (Object.hasOwn(preloadPlugins, id)) { if (Object.hasOwn(preloadPlugins, id)) {
const factory = (preloadPlugins as Record<string, PreloadPluginFactory<PluginBaseConfig>>)[id]; const factory = (preloadPlugins as Record<string, PreloadPluginFactory<PluginBaseConfig>>)[id];
try { try {
const context = createContext(id); const context = createContext(id as keyof PluginBuilderList);
const plugin = await factory(context); const plugin = await factory(context);
plugin.onLoad?.(); plugin.onLoad?.();
preloadedPluginList.push(plugin); preloadedPluginList.push(plugin);

View File

@ -2,13 +2,17 @@
// eslint-disable-next-line import/order // eslint-disable-next-line import/order
import { rendererPlugins } from 'virtual:RendererPlugins'; import { rendererPlugins } from 'virtual:RendererPlugins';
import { deepmerge as createDeepmerge } from '@fastify/deepmerge';
import { PluginBaseConfig, RendererPluginContext, RendererPluginFactory } from './plugins/utils/builder'; import { PluginBaseConfig, RendererPluginContext, RendererPluginFactory } from './plugins/utils/builder';
import { startingPages } from './providers/extracted-data'; import { startingPages } from './providers/extracted-data';
import { setupSongControls } from './providers/song-controls-front'; import { setupSongControls } from './providers/song-controls-front';
import setupSongInfo from './providers/song-info-front'; import setupSongInfo from './providers/song-info-front';
import {mainPlugins} from "virtual:MainPlugins";
import {pluginBuilders} from "virtual:PluginBuilders";
const enabledPluginNameAndOptions = window.mainConfig.plugins.getEnabled(); const deepmerge = createDeepmerge();
let api: Element | null = null; let api: Element | null = null;
@ -116,55 +120,31 @@ const createContext = <
}); });
(async () => { (async () => {
// enabledPluginNameAndOptions.forEach(async ([pluginName, options]) => { const pluginConfig = window.mainConfig.plugins.getPlugins();
// if (pluginName === 'ambient-mode') {
// const builder = rendererPlugins[pluginName];
// try {
// const context = createContext(pluginName);
// const plugin = await builder?.(context);
// console.log(plugin);
// plugin.onLoad?.();
// } catch (error) {
// console.error(`Error in plugin "${pluginName}"`);
// console.trace(error);
// }
// }
// if (Object.hasOwn(rendererPlugins, pluginName)) {
// const handler = rendererPlugins[pluginName];
// try {
// await handler?.(options as never);
// } catch (error) {
// console.error(`Error in plugin "${pluginName}"`);
// console.trace(error);
// }
// }
// });
const rendererPluginList = Object.entries(rendererPlugins);
const rendererPluginResult = await Promise.allSettled( const rendererPluginResult = await Promise.allSettled(
enabledPluginNameAndOptions.map(async ([id]) => { rendererPluginList
// HACK: eslint has a bug detects the type of rendererPlugins as "any" .filter(([id]) => deepmerge(pluginBuilders[id as keyof PluginBuilderList].config, pluginConfig[id as keyof PluginBuilderList])?.enabled)
const builder = (rendererPlugins as Record<string, RendererPluginFactory<PluginBaseConfig>>)[id]; .map(async ([id, builder]) => {
const context = createContext(id as keyof PluginBuilderList);
const context = createContext(id as keyof PluginBuilderList); return [id, await (builder as RendererPluginFactory<PluginBaseConfig>)(context)] as const;
return [id, await builder(context)] as const; }),
}),
); );
const rendererPluginList = rendererPluginResult
.map((it) => it.status === 'fulfilled' ? it.value : null)
.filter(Boolean);
rendererPluginResult.forEach((it, index) => { rendererPluginResult.forEach((it, index) => {
if (it.status === 'rejected') { if (it.status === 'rejected') {
const id = enabledPluginNameAndOptions[index][0]; const id = rendererPluginList[index][0];
console.error('[YTMusic]', `Cannot load plugin "${id}"`); console.error('[YTMusic]', `Cannot load plugin "${id}"`);
console.trace(it.reason); console.trace(it.reason);
} }
}); });
rendererPluginList.forEach(([id, plugin]) => { const loadedRendererPluginList = rendererPluginResult
.map((it) => it.status === 'fulfilled' ? it.value : null)
.filter(Boolean);
loadedRendererPluginList.forEach(([id, plugin]) => {
try { try {
plugin.onLoad?.(); plugin.onLoad?.();
console.log('[YTMusic]', `"${id}" plugin is loaded`); console.log('[YTMusic]', `"${id}" plugin is loaded`);
@ -175,7 +155,7 @@ const createContext = <
}); });
window.ipcRenderer.on('config-changed', (_event, id: string, newConfig: PluginBaseConfig) => { window.ipcRenderer.on('config-changed', (_event, id: string, newConfig: PluginBaseConfig) => {
const plugin = rendererPluginList.find(([pluginId]) => pluginId === id); const plugin = loadedRendererPluginList.find(([pluginId]) => pluginId === id);
if (plugin) { if (plugin) {
plugin[1].onConfigChange?.(newConfig); plugin[1].onConfigChange?.(newConfig);