mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-16 12:42:06 +00:00
feat: plugin load await
This commit is contained in:
@ -49,35 +49,33 @@ export const forceUnloadMainPlugin = async (
|
|||||||
const plugin = loadedPluginMap[id];
|
const plugin = loadedPluginMap[id];
|
||||||
if (!plugin) return;
|
if (!plugin) return;
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
try {
|
||||||
try {
|
const hasStopped = await stopPlugin(id, plugin, {
|
||||||
const hasStopped = stopPlugin(id, plugin, {
|
ctx: 'backend',
|
||||||
ctx: 'backend',
|
context: createContext(id, win),
|
||||||
context: createContext(id, win),
|
});
|
||||||
});
|
if (
|
||||||
if (
|
hasStopped ||
|
||||||
hasStopped ||
|
(
|
||||||
(
|
hasStopped === null &&
|
||||||
hasStopped === null &&
|
typeof plugin.backend !== 'function' && plugin.backend
|
||||||
typeof plugin.backend !== 'function' && plugin.backend
|
)
|
||||||
)
|
) {
|
||||||
) {
|
delete loadedPluginMap[id];
|
||||||
delete loadedPluginMap[id];
|
console.log(LoggerPrefix, `"${id}" plugin is unloaded`);
|
||||||
console.log(LoggerPrefix, `"${id}" plugin is unloaded`);
|
return;
|
||||||
resolve();
|
} else {
|
||||||
} else {
|
console.log(
|
||||||
console.log(
|
LoggerPrefix,
|
||||||
LoggerPrefix,
|
`Cannot unload "${id}" plugin`,
|
||||||
`Cannot unload "${id}" plugin`,
|
);
|
||||||
);
|
return Promise.reject();
|
||||||
reject();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(LoggerPrefix, `Cannot unload "${id}" plugin: ${String(err)}`);
|
|
||||||
reject(err);
|
|
||||||
}
|
}
|
||||||
});
|
} catch (err) {
|
||||||
|
console.error(LoggerPrefix, `Cannot unload "${id}" plugin`);
|
||||||
|
console.trace(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const forceLoadMainPlugin = async (
|
export const forceLoadMainPlugin = async (
|
||||||
@ -87,34 +85,31 @@ export const forceLoadMainPlugin = async (
|
|||||||
const plugin = mainPlugins[id];
|
const plugin = mainPlugins[id];
|
||||||
if (!plugin) return;
|
if (!plugin) return;
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
try {
|
||||||
try {
|
const hasStarted = await startPlugin(id, plugin, {
|
||||||
const hasStarted = startPlugin(id, plugin, {
|
ctx: 'backend',
|
||||||
ctx: 'backend',
|
context: createContext(id, win),
|
||||||
context: createContext(id, win),
|
});
|
||||||
});
|
if (
|
||||||
if (
|
hasStarted ||
|
||||||
hasStarted ||
|
(
|
||||||
(
|
hasStarted === null &&
|
||||||
hasStarted === null &&
|
typeof plugin.backend !== 'function' && plugin.backend
|
||||||
typeof plugin.backend !== 'function' && plugin.backend
|
)
|
||||||
)
|
) {
|
||||||
) {
|
loadedPluginMap[id] = plugin;
|
||||||
loadedPluginMap[id] = plugin;
|
} else {
|
||||||
resolve();
|
console.log(LoggerPrefix, `Cannot load "${id}" plugin`);
|
||||||
} else {
|
return Promise.reject();
|
||||||
console.log(LoggerPrefix, `Cannot load "${id}" plugin`);
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(
|
|
||||||
LoggerPrefix,
|
|
||||||
`Cannot initialize "${id}" plugin: `,
|
|
||||||
);
|
|
||||||
console.trace(err);
|
|
||||||
reject(err);
|
|
||||||
}
|
}
|
||||||
});
|
} catch (err) {
|
||||||
|
console.error(
|
||||||
|
LoggerPrefix,
|
||||||
|
`Cannot initialize "${id}" plugin: `,
|
||||||
|
);
|
||||||
|
console.trace(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadAllMainPlugins = async (win: BrowserWindow) => {
|
export const loadAllMainPlugins = async (win: BrowserWindow) => {
|
||||||
@ -134,9 +129,9 @@ export const loadAllMainPlugins = async (win: BrowserWindow) => {
|
|||||||
await Promise.allSettled(queue);
|
await Promise.allSettled(queue);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const unloadAllMainPlugins = (win: BrowserWindow) => {
|
export const unloadAllMainPlugins = async (win: BrowserWindow) => {
|
||||||
for (const id of Object.keys(loadedPluginMap)) {
|
for (const id of Object.keys(loadedPluginMap)) {
|
||||||
forceUnloadMainPlugin(id, win);
|
await forceUnloadMainPlugin(id, win);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -20,10 +20,10 @@ const createContext = (id: string): PreloadContext<PluginConfig> => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const forceUnloadPreloadPlugin = (id: string) => {
|
export const forceUnloadPreloadPlugin = async (id: string) => {
|
||||||
if (!loadedPluginMap[id]) return;
|
if (!loadedPluginMap[id]) return;
|
||||||
|
|
||||||
const hasStopped = stopPlugin(id, loadedPluginMap[id], {
|
const hasStopped = await stopPlugin(id, loadedPluginMap[id], {
|
||||||
ctx: 'preload',
|
ctx: 'preload',
|
||||||
context: createContext(id),
|
context: createContext(id),
|
||||||
});
|
});
|
||||||
@ -41,12 +41,12 @@ export const forceUnloadPreloadPlugin = (id: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const forceLoadPreloadPlugin = (id: string) => {
|
export const forceLoadPreloadPlugin = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const plugin = preloadPlugins[id];
|
const plugin = preloadPlugins[id];
|
||||||
if (!plugin) return;
|
if (!plugin) return;
|
||||||
|
|
||||||
const hasStarted = startPlugin(id, plugin, {
|
const hasStarted = await startPlugin(id, plugin, {
|
||||||
ctx: 'preload',
|
ctx: 'preload',
|
||||||
context: createContext(id),
|
context: createContext(id),
|
||||||
});
|
});
|
||||||
@ -71,25 +71,25 @@ export const forceLoadPreloadPlugin = (id: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadAllPreloadPlugins = () => {
|
export const loadAllPreloadPlugins = async () => {
|
||||||
const pluginConfigs = config.plugins.getPlugins();
|
const pluginConfigs = config.plugins.getPlugins();
|
||||||
|
|
||||||
for (const [pluginId, pluginDef] of Object.entries(preloadPlugins)) {
|
for (const [pluginId, pluginDef] of Object.entries(preloadPlugins)) {
|
||||||
const config = deepmerge(pluginDef.config ?? { enable: false }, pluginConfigs[pluginId] ?? {}) ;
|
const config = deepmerge(pluginDef.config ?? { enable: false }, pluginConfigs[pluginId] ?? {});
|
||||||
|
|
||||||
if (config.enabled) {
|
if (config.enabled) {
|
||||||
forceLoadPreloadPlugin(pluginId);
|
await forceLoadPreloadPlugin(pluginId);
|
||||||
} else {
|
} else {
|
||||||
if (loadedPluginMap[pluginId]) {
|
if (loadedPluginMap[pluginId]) {
|
||||||
forceUnloadPreloadPlugin(pluginId);
|
await forceUnloadPreloadPlugin(pluginId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const unloadAllPreloadPlugins = () => {
|
export const unloadAllPreloadPlugins = async () => {
|
||||||
for (const id of Object.keys(loadedPluginMap)) {
|
for (const id of Object.keys(loadedPluginMap)) {
|
||||||
forceUnloadPreloadPlugin(id);
|
await forceUnloadPreloadPlugin(id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ export const createContext = <Config extends PluginConfig>(id: string): Renderer
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const forceUnloadRendererPlugin = (id: string) => {
|
export const forceUnloadRendererPlugin = async (id: string) => {
|
||||||
unregisterStyleMap[id]?.forEach((unregister) => unregister());
|
unregisterStyleMap[id]?.forEach((unregister) => unregister());
|
||||||
|
|
||||||
delete unregisterStyleMap[id];
|
delete unregisterStyleMap[id];
|
||||||
@ -40,7 +40,7 @@ export const forceUnloadRendererPlugin = (id: string) => {
|
|||||||
const plugin = rendererPlugins[id];
|
const plugin = rendererPlugins[id];
|
||||||
if (!plugin) return;
|
if (!plugin) return;
|
||||||
|
|
||||||
const hasStopped = stopPlugin(id, plugin, { ctx: 'renderer', context: createContext(id) });
|
const hasStopped = await stopPlugin(id, plugin, { ctx: 'renderer', context: createContext(id) });
|
||||||
if (plugin?.stylesheets) {
|
if (plugin?.stylesheets) {
|
||||||
document.querySelector(`style#plugin-${id}`)?.remove();
|
document.querySelector(`style#plugin-${id}`)?.remove();
|
||||||
}
|
}
|
||||||
@ -57,11 +57,11 @@ export const forceUnloadRendererPlugin = (id: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const forceLoadRendererPlugin = (id: string) => {
|
export const forceLoadRendererPlugin = async (id: string) => {
|
||||||
const plugin = rendererPlugins[id];
|
const plugin = rendererPlugins[id];
|
||||||
if (!plugin) return;
|
if (!plugin) return;
|
||||||
|
|
||||||
const hasEvaled = startPlugin(id, plugin, {
|
const hasEvaled = await startPlugin(id, plugin, {
|
||||||
ctx: 'renderer',
|
ctx: 'renderer',
|
||||||
context: createContext(id),
|
context: createContext(id),
|
||||||
});
|
});
|
||||||
@ -93,25 +93,25 @@ export const forceLoadRendererPlugin = (id: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loadAllRendererPlugins = () => {
|
export const loadAllRendererPlugins = async () => {
|
||||||
const pluginConfigs = window.mainConfig.plugins.getPlugins();
|
const pluginConfigs = window.mainConfig.plugins.getPlugins();
|
||||||
|
|
||||||
for (const [pluginId, pluginDef] of Object.entries(rendererPlugins)) {
|
for (const [pluginId, pluginDef] of Object.entries(rendererPlugins)) {
|
||||||
const config = deepmerge(pluginDef.config, pluginConfigs[pluginId] ?? {}) ;
|
const config = deepmerge(pluginDef.config, pluginConfigs[pluginId] ?? {}) ;
|
||||||
|
|
||||||
if (config.enabled) {
|
if (config.enabled) {
|
||||||
forceLoadRendererPlugin(pluginId);
|
await forceLoadRendererPlugin(pluginId);
|
||||||
} else {
|
} else {
|
||||||
if (loadedPluginMap[pluginId]) {
|
if (loadedPluginMap[pluginId]) {
|
||||||
forceUnloadRendererPlugin(pluginId);
|
await forceUnloadRendererPlugin(pluginId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const unloadAllRendererPlugins = () => {
|
export const unloadAllRendererPlugins = async () => {
|
||||||
for (const id of Object.keys(loadedPluginMap)) {
|
for (const id of Object.keys(loadedPluginMap)) {
|
||||||
forceUnloadRendererPlugin(id);
|
await forceUnloadRendererPlugin(id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,11 @@ import {
|
|||||||
|
|
||||||
loadAllPreloadPlugins();
|
loadAllPreloadPlugins();
|
||||||
|
|
||||||
ipcRenderer.on('plugin:unload', (_, id: string) => {
|
ipcRenderer.on('plugin:unload', async (_, id: string) => {
|
||||||
forceUnloadPreloadPlugin(id);
|
await forceUnloadPreloadPlugin(id);
|
||||||
});
|
});
|
||||||
ipcRenderer.on('plugin:enable', (_, id: string) => {
|
ipcRenderer.on('plugin:enable', async (_, id: string) => {
|
||||||
forceLoadPreloadPlugin(id);
|
await forceLoadPreloadPlugin(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('mainConfig', config);
|
contextBridge.exposeInMainWorld('mainConfig', config);
|
||||||
|
|||||||
@ -14,10 +14,10 @@ import type { YoutubePlayer } from '@/types/youtube-player';
|
|||||||
|
|
||||||
let api: (Element & YoutubePlayer) | null = null;
|
let api: (Element & YoutubePlayer) | null = null;
|
||||||
|
|
||||||
function listenForApiLoad() {
|
async function listenForApiLoad() {
|
||||||
api = document.querySelector('#movie_player');
|
api = document.querySelector('#movie_player');
|
||||||
if (api) {
|
if (api) {
|
||||||
onApiLoaded();
|
await onApiLoaded();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ async function onApiLoaded() {
|
|||||||
const audioSource = audioContext.createMediaElementSource(video);
|
const audioSource = audioContext.createMediaElementSource(video);
|
||||||
audioSource.connect(audioContext.destination);
|
audioSource.connect(audioContext.destination);
|
||||||
|
|
||||||
for (const [id, plugin] of Object.entries(getAllLoadedRendererPlugins())) {
|
for await (const [id, plugin] of Object.entries(getAllLoadedRendererPlugins())) {
|
||||||
if (typeof plugin.renderer !== 'function') {
|
if (typeof plugin.renderer !== 'function') {
|
||||||
await plugin.renderer?.onPlayerApiReady?.call(plugin.renderer, api!, createContext(id));
|
await plugin.renderer?.onPlayerApiReady?.call(plugin.renderer, api!, createContext(id));
|
||||||
}
|
}
|
||||||
@ -126,23 +126,23 @@ async function onApiLoaded() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(() => {
|
(async () => {
|
||||||
loadAllRendererPlugins();
|
await loadAllRendererPlugins();
|
||||||
|
|
||||||
window.ipcRenderer.on(
|
window.ipcRenderer.on(
|
||||||
'plugin:unload',
|
'plugin:unload',
|
||||||
(_event, id: string) => {
|
async (_event, id: string) => {
|
||||||
forceUnloadRendererPlugin(id);
|
await forceUnloadRendererPlugin(id);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
window.ipcRenderer.on(
|
window.ipcRenderer.on(
|
||||||
'plugin:enable',
|
'plugin:enable',
|
||||||
(_event, id: string) => {
|
async (_event, id: string) => {
|
||||||
forceLoadRendererPlugin(id);
|
await forceLoadRendererPlugin(id);
|
||||||
if (api) {
|
if (api) {
|
||||||
const plugin = getLoadedRendererPlugin(id);
|
const plugin = getLoadedRendererPlugin(id);
|
||||||
if (plugin && typeof plugin.renderer !== 'function') {
|
if (plugin && typeof plugin.renderer !== 'function') {
|
||||||
plugin.renderer?.onPlayerApiReady?.call(plugin.renderer, api, createContext(id));
|
await plugin.renderer?.onPlayerApiReady?.call(plugin.renderer, api, createContext(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -159,7 +159,7 @@ async function onApiLoaded() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Wait for complete load of YouTube api
|
// Wait for complete load of YouTube api
|
||||||
listenForApiLoad();
|
await listenForApiLoad();
|
||||||
|
|
||||||
// Blocks the "Are You Still There?" popup by setting the last active time to Date.now every 15min
|
// Blocks the "Are You Still There?" popup by setting the last active time to Date.now every 15min
|
||||||
setInterval(() => (window._lact = Date.now()), 900_000);
|
setInterval(() => (window._lact = Date.now()), 900_000);
|
||||||
|
|||||||
@ -69,7 +69,7 @@ type Options<Config extends PluginConfig> =
|
|||||||
| { ctx: 'preload'; context: PreloadContext<Config> }
|
| { ctx: 'preload'; context: PreloadContext<Config> }
|
||||||
| { ctx: 'renderer'; context: RendererContext<Config> };
|
| { ctx: 'renderer'; context: RendererContext<Config> };
|
||||||
|
|
||||||
export const startPlugin = <Config extends PluginConfig>(
|
export const startPlugin = async <Config extends PluginConfig>(
|
||||||
id: string,
|
id: string,
|
||||||
def: PluginDef<unknown, unknown, unknown, Config>,
|
def: PluginDef<unknown, unknown, unknown, Config>,
|
||||||
options: Options<Config>,
|
options: Options<Config>,
|
||||||
@ -99,7 +99,7 @@ export const startPlugin = <Config extends PluginConfig>(
|
|||||||
|
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|
||||||
lifecycle?.call(
|
await lifecycle?.call(
|
||||||
defContext,
|
defContext,
|
||||||
options.context as Config & typeof options.context,
|
options.context as Config & typeof options.context,
|
||||||
);
|
);
|
||||||
@ -118,7 +118,7 @@ export const startPlugin = <Config extends PluginConfig>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const stopPlugin = <Config extends PluginConfig>(
|
export const stopPlugin = async <Config extends PluginConfig>(
|
||||||
id: string,
|
id: string,
|
||||||
def: PluginDef<unknown, unknown, unknown, Config>,
|
def: PluginDef<unknown, unknown, unknown, Config>,
|
||||||
options: Options<Config>,
|
options: Options<Config>,
|
||||||
@ -132,7 +132,7 @@ export const stopPlugin = <Config extends PluginConfig>(
|
|||||||
try {
|
try {
|
||||||
const stop = defCtx.stop;
|
const stop = defCtx.stop;
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
stop.call(
|
await stop.call(
|
||||||
def[options.ctx],
|
def[options.ctx],
|
||||||
options.context as Config & typeof options.context,
|
options.context as Config & typeof options.context,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user