mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
fix: plugin load
This commit is contained in:
@ -50,6 +50,7 @@ export default defineConfig({
|
||||
const commonConfig: UserConfig = {
|
||||
plugins: [
|
||||
viteResolve({
|
||||
'virtual:PluginBuilders': pluginVirtualModuleGenerator('index'),
|
||||
'virtual:PreloadPlugins': pluginVirtualModuleGenerator('preload'),
|
||||
}),
|
||||
],
|
||||
@ -86,6 +87,7 @@ export default defineConfig({
|
||||
const commonConfig: UserConfig = {
|
||||
plugins: [
|
||||
viteResolve({
|
||||
'virtual:PluginBuilders': pluginVirtualModuleGenerator('index'),
|
||||
'virtual:RendererPlugins': pluginVirtualModuleGenerator('renderer'),
|
||||
}),
|
||||
],
|
||||
|
||||
@ -1,27 +1,16 @@
|
||||
import { deepmerge } from '@fastify/deepmerge';
|
||||
|
||||
import store from './store';
|
||||
import defaultConfig from './defaults';
|
||||
|
||||
import { restart } from '../providers/app-controls';
|
||||
import { Entries } from '../utils/type-utils';
|
||||
|
||||
interface Plugin {
|
||||
enabled: boolean;
|
||||
}
|
||||
import type { PluginBaseConfig } from '../plugins/utils/builder';
|
||||
|
||||
type DefaultPluginsConfig = typeof defaultConfig.plugins;
|
||||
const deepmergeFn = deepmerge();
|
||||
|
||||
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 getPlugins() {
|
||||
return store.get('plugins') as Record<string, PluginBaseConfig>;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -69,7 +58,7 @@ export function disable(plugin: string) {
|
||||
|
||||
export default {
|
||||
isEnabled,
|
||||
getEnabled,
|
||||
getPlugins,
|
||||
enable,
|
||||
disable,
|
||||
setOptions,
|
||||
|
||||
59
src/index.ts
59
src/index.ts
@ -10,6 +10,8 @@ import { autoUpdater } from 'electron-updater';
|
||||
import electronDebug from 'electron-debug';
|
||||
import { parse } from 'node-html-parser';
|
||||
|
||||
import { deepmerge as createDeepmerge } from '@fastify/deepmerge';
|
||||
|
||||
import config from './config';
|
||||
|
||||
import { refreshMenu, setApplicationMenu } from './menu';
|
||||
@ -26,7 +28,10 @@ import { pluginBuilders } from 'virtual:PluginBuilders';
|
||||
/* eslint-enable import/order */
|
||||
|
||||
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
|
||||
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()) {
|
||||
const builder = pluginBuilders[pluginId as keyof PluginBuilderList];
|
||||
const factory = (mainPlugins as Record<string, MainPluginFactory<PluginBaseConfig>>)[pluginId];
|
||||
if (config?.enabled) {
|
||||
builder.styles?.forEach((style) => {
|
||||
injectCSS(win.webContents, style);
|
||||
console.log('[YTMusic]', `"${pluginId}" plugin meta data is loaded`);
|
||||
});
|
||||
|
||||
if (builder) {
|
||||
builder.styles?.forEach((style) => {
|
||||
injectCSS(win.webContents, style);
|
||||
console.log('[YTMusic]', `"${pluginId}" plugin meta data is loaded`);
|
||||
});
|
||||
}
|
||||
|
||||
if (factory) {
|
||||
try {
|
||||
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 {
|
||||
const context = createContext(pluginId as keyof PluginBuilderList);
|
||||
const plugin = await (factory as MainPluginFactory<PluginBaseConfig>)(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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@ export default builder.createRenderer(async ({ getConfig }) => {
|
||||
if (!video) return null;
|
||||
if (!wrapper) return null;
|
||||
|
||||
console.log('injectBlurVideo', songVideo, video, wrapper);
|
||||
const blurCanvas = document.createElement('canvas');
|
||||
blurCanvas.classList.add('html5-blur-canvas');
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ export default builder.createMain(({ handle, send }) => {
|
||||
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);
|
||||
|
||||
return JSON.parse(JSON.stringify(
|
||||
@ -67,7 +67,7 @@ export default builder.createMain(({ handle, send }) => {
|
||||
handle('window-unmaximize', () => win.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);
|
||||
return nativeImageIcon?.toDataURL();
|
||||
});
|
||||
|
||||
@ -20,7 +20,7 @@ export default builder.createMain(({ handle, getConfig }) =>{
|
||||
revRomanized = true;
|
||||
}
|
||||
|
||||
handle('search-genius-lyrics', async (_, extractedSongInfo: SongInfo) => {
|
||||
handle('search-genius-lyrics', async (extractedSongInfo: SongInfo) => {
|
||||
const metadata = extractedSongInfo;
|
||||
return await fetchFromGenius(metadata);
|
||||
});
|
||||
|
||||
@ -24,7 +24,7 @@ export default builder.createRenderer(({ on, invoke }) => ({
|
||||
|
||||
let unregister: (() => void) | null = null;
|
||||
|
||||
on('update-song-info', (_, extractedSongInfo: SongInfo) => {
|
||||
on('update-song-info', (extractedSongInfo: SongInfo) => {
|
||||
unregister?.();
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
@ -261,8 +261,8 @@ export default builder.createRenderer(async ({ on, getConfig, setConfig }) => {
|
||||
|
||||
document.addEventListener('apiLoaded', (e) => {
|
||||
api = e.detail;
|
||||
on('changeVolume', (_, toIncrease: boolean) => changeVolume(toIncrease));
|
||||
on('setVolume', (_, value: number) => setVolume(value));
|
||||
on('changeVolume', (toIncrease: boolean) => changeVolume(toIncrease));
|
||||
on('setVolume', (value: number) => setVolume(value));
|
||||
firstRun();
|
||||
}, { once: true, passive: true });
|
||||
},
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
|
||||
import is from 'electron-is';
|
||||
|
||||
import { pluginBuilders } from 'virtual:PluginBuilders';
|
||||
|
||||
import { deepmerge as createDeepmerge } from '@fastify/deepmerge';
|
||||
|
||||
import config from './config';
|
||||
|
||||
// eslint-disable-next-line import/order
|
||||
import { preloadPlugins } from 'virtual:PreloadPlugins';
|
||||
import { PluginBaseConfig, PluginContext, PreloadPluginFactory } from './plugins/utils/builder';
|
||||
|
||||
const enabledPluginNameAndOptions = config.plugins.getEnabled();
|
||||
const deepmerge = createDeepmerge();
|
||||
|
||||
const createContext = <
|
||||
Key extends keyof PluginBuilderList,
|
||||
@ -22,12 +26,15 @@ const createContext = <
|
||||
|
||||
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)) {
|
||||
const factory = (preloadPlugins as Record<string, PreloadPluginFactory<PluginBaseConfig>>)[id];
|
||||
|
||||
try {
|
||||
const context = createContext(id);
|
||||
const context = createContext(id as keyof PluginBuilderList);
|
||||
const plugin = await factory(context);
|
||||
plugin.onLoad?.();
|
||||
preloadedPluginList.push(plugin);
|
||||
|
||||
@ -2,13 +2,17 @@
|
||||
// eslint-disable-next-line import/order
|
||||
import { rendererPlugins } from 'virtual:RendererPlugins';
|
||||
|
||||
import { deepmerge as createDeepmerge } from '@fastify/deepmerge';
|
||||
|
||||
import { PluginBaseConfig, RendererPluginContext, RendererPluginFactory } from './plugins/utils/builder';
|
||||
|
||||
import { startingPages } from './providers/extracted-data';
|
||||
import { setupSongControls } from './providers/song-controls-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;
|
||||
|
||||
@ -116,55 +120,31 @@ const createContext = <
|
||||
});
|
||||
|
||||
(async () => {
|
||||
// enabledPluginNameAndOptions.forEach(async ([pluginName, options]) => {
|
||||
// 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 pluginConfig = window.mainConfig.plugins.getPlugins();
|
||||
|
||||
const rendererPluginList = Object.entries(rendererPlugins);
|
||||
const rendererPluginResult = await Promise.allSettled(
|
||||
enabledPluginNameAndOptions.map(async ([id]) => {
|
||||
// HACK: eslint has a bug detects the type of rendererPlugins as "any"
|
||||
const builder = (rendererPlugins as Record<string, RendererPluginFactory<PluginBaseConfig>>)[id];
|
||||
|
||||
const context = createContext(id as keyof PluginBuilderList);
|
||||
return [id, await builder(context)] as const;
|
||||
}),
|
||||
rendererPluginList
|
||||
.filter(([id]) => deepmerge(pluginBuilders[id as keyof PluginBuilderList].config, pluginConfig[id as keyof PluginBuilderList])?.enabled)
|
||||
.map(async ([id, builder]) => {
|
||||
const context = createContext(id as keyof PluginBuilderList);
|
||||
return [id, await (builder as RendererPluginFactory<PluginBaseConfig>)(context)] as const;
|
||||
}),
|
||||
);
|
||||
|
||||
const rendererPluginList = rendererPluginResult
|
||||
.map((it) => it.status === 'fulfilled' ? it.value : null)
|
||||
.filter(Boolean);
|
||||
|
||||
rendererPluginResult.forEach((it, index) => {
|
||||
if (it.status === 'rejected') {
|
||||
const id = enabledPluginNameAndOptions[index][0];
|
||||
const id = rendererPluginList[index][0];
|
||||
console.error('[YTMusic]', `Cannot load plugin "${id}"`);
|
||||
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 {
|
||||
plugin.onLoad?.();
|
||||
console.log('[YTMusic]', `"${id}" plugin is loaded`);
|
||||
@ -175,7 +155,7 @@ const createContext = <
|
||||
});
|
||||
|
||||
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) {
|
||||
plugin[1].onConfigChange?.(newConfig);
|
||||
|
||||
Reference in New Issue
Block a user