2022-10-14 10:53:16 -04:00
|
|
|
import Events from '../utils/events.ts';
|
2024-08-15 02:33:50 -04:00
|
|
|
import globalize from '../lib/globalize';
|
2020-11-18 23:13:56 +00:00
|
|
|
import loading from './loading/loading';
|
|
|
|
import appSettings from '../scripts/settings/appSettings';
|
|
|
|
import { playbackManager } from './playback/playbackmanager';
|
2021-04-10 21:53:32 -04:00
|
|
|
import { appHost } from '../components/apphost';
|
2023-05-01 10:04:13 -04:00
|
|
|
import { appRouter } from './router/appRouter';
|
2021-04-14 18:59:51 -04:00
|
|
|
import * as inputManager from '../scripts/inputManager';
|
2021-04-19 18:37:22 -04:00
|
|
|
import toast from '../components/toast/toast';
|
|
|
|
import confirm from '../components/confirm/confirm';
|
2023-02-23 23:05:48 -05:00
|
|
|
import * as dashboard from '../utils/dashboard';
|
2023-02-23 23:07:55 -05:00
|
|
|
import ServerConnections from '../components/ServerConnections';
|
2020-10-18 20:00:39 +01:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
// TODO: replace with each plugin version
|
|
|
|
const cacheParam = new Date().getTime();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
class PluginManager {
|
|
|
|
pluginsList = [];
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
get plugins() {
|
|
|
|
return this.pluginsList;
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
#loadStrings(plugin) {
|
|
|
|
const strings = plugin.getTranslations ? plugin.getTranslations() : [];
|
|
|
|
return globalize.loadStrings({
|
|
|
|
name: plugin.id || plugin.packageName,
|
|
|
|
strings: strings
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async #registerPlugin(plugin) {
|
|
|
|
this.#register(plugin);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
if (plugin.type === 'skin') {
|
|
|
|
// translations won't be loaded for skins until needed
|
|
|
|
return plugin;
|
|
|
|
} else {
|
2022-08-09 14:53:43 +03:00
|
|
|
return this.#loadStrings(plugin);
|
2020-08-01 03:01:32 +02:00
|
|
|
}
|
2022-03-31 09:57:21 -04:00
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
async #preparePlugin(pluginSpec, plugin) {
|
|
|
|
if (typeof pluginSpec === 'string') {
|
|
|
|
// See if it's already installed
|
|
|
|
const existing = this.plugins.filter(function (p) {
|
|
|
|
return p.id === plugin.id;
|
|
|
|
})[0];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
if (existing) {
|
|
|
|
return pluginSpec;
|
2020-04-27 13:02:25 +02:00
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
plugin.installUrl = pluginSpec;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
const separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
|
|
|
|
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
return this.#registerPlugin(plugin);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
async loadPlugin(pluginSpec) {
|
|
|
|
let plugin;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
if (typeof pluginSpec === 'string') {
|
|
|
|
if (pluginSpec in window) {
|
|
|
|
console.log(`Loading plugin (via window): ${pluginSpec}`);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
const pluginDefinition = await window[pluginSpec];
|
|
|
|
if (typeof pluginDefinition !== 'function') {
|
|
|
|
throw new TypeError('Plugin definitions in window have to be an (async) function returning the plugin class');
|
2020-11-18 23:13:56 +00:00
|
|
|
}
|
|
|
|
|
2023-07-06 11:49:55 -04:00
|
|
|
const PluginClass = await pluginDefinition();
|
|
|
|
if (typeof PluginClass !== 'function') {
|
2022-03-31 09:57:21 -04:00
|
|
|
throw new TypeError(`Plugin definition doesn't return a class for '${pluginSpec}'`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// init plugin and pass basic dependencies
|
2023-07-06 11:49:55 -04:00
|
|
|
plugin = new PluginClass({
|
2022-03-31 09:57:21 -04:00
|
|
|
events: Events,
|
|
|
|
loading,
|
|
|
|
appSettings,
|
|
|
|
playbackManager,
|
|
|
|
globalize,
|
|
|
|
appHost,
|
|
|
|
appRouter,
|
|
|
|
inputManager,
|
|
|
|
toast,
|
2023-02-23 23:05:48 -05:00
|
|
|
confirm,
|
2023-02-23 23:07:55 -05:00
|
|
|
dashboard,
|
|
|
|
ServerConnections
|
2022-03-31 09:57:21 -04:00
|
|
|
});
|
2020-08-01 03:01:32 +02:00
|
|
|
} else {
|
2022-03-31 09:57:21 -04:00
|
|
|
console.debug(`Loading plugin (via dynamic import): ${pluginSpec}`);
|
|
|
|
const pluginResult = await import(/* webpackChunkName: "[request]" */ `../plugins/${pluginSpec}`);
|
|
|
|
plugin = new pluginResult.default;
|
2020-08-01 03:01:32 +02:00
|
|
|
}
|
2022-03-31 09:57:21 -04:00
|
|
|
} else if (pluginSpec.then) {
|
|
|
|
console.debug('Loading plugin (via promise/async function)');
|
2020-11-18 23:13:56 +00:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
const pluginResult = await pluginSpec;
|
|
|
|
plugin = new pluginResult.default;
|
|
|
|
} else {
|
|
|
|
throw new TypeError('Plugins have to be a Promise that resolves to a plugin builder function');
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
return this.#preparePlugin(pluginSpec, plugin);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
// In lieu of automatic discovery, plugins will register dynamic objects
|
|
|
|
// Each object will have the following properties:
|
|
|
|
// name
|
|
|
|
// type (skin, screensaver, etc)
|
|
|
|
#register(obj) {
|
|
|
|
this.pluginsList.push(obj);
|
|
|
|
Events.trigger(this, 'registered', [obj]);
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
ofType(type) {
|
2023-03-08 17:47:40 -05:00
|
|
|
return this.pluginsList.filter(plugin => plugin.type === type);
|
|
|
|
}
|
|
|
|
|
|
|
|
firstOfType(type) {
|
|
|
|
// Get all plugins of the specified type
|
|
|
|
return this.ofType(type)
|
|
|
|
// Return the plugin with the "highest" (lowest numeric value) priority
|
|
|
|
.sort((p1, p2) => (p1.priority || 0) - (p2.priority || 0))[0];
|
2022-03-31 09:57:21 -04:00
|
|
|
}
|
2020-08-01 03:01:32 +02:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
mapPath(plugin, path, addCacheParam) {
|
|
|
|
if (typeof plugin === 'string') {
|
|
|
|
plugin = this.pluginsList.filter((p) => {
|
|
|
|
return (p.id || p.packageName) === plugin;
|
|
|
|
})[0];
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
let url = plugin.baseUrl + '/' + path;
|
2020-08-01 03:01:32 +02:00
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
if (addCacheParam) {
|
|
|
|
url += url.includes('?') ? '&' : '?';
|
|
|
|
url += 'v=' + cacheParam;
|
2019-01-10 15:39:37 +03:00
|
|
|
}
|
|
|
|
|
2022-03-31 09:57:21 -04:00
|
|
|
return url;
|
|
|
|
}
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
2020-08-16 20:24:45 +02:00
|
|
|
export const pluginManager = new PluginManager();
|