1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/components/pluginManager.js

171 lines
5.7 KiB
JavaScript
Raw Normal View History

2020-09-08 02:05:02 -04:00
import { Events } from 'jellyfin-apiclient';
2020-08-14 08:46:34 +02:00
import globalize from '../scripts/globalize';
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';
import { appRouter } from '../components/appRouter';
2021-04-14 18:59:51 -04:00
import * as inputManager from '../scripts/inputManager';
2020-10-18 20:00:39 +01:00
2020-08-01 03:01:32 +02:00
/* eslint-disable indent */
// TODO: replace with each plugin version
2020-10-07 21:12:14 +09:00
const cacheParam = new Date().getTime();
2018-10-23 01:05:09 +03:00
2020-08-01 03:01:32 +02:00
class PluginManager {
pluginsList = [];
2018-10-23 01:05:09 +03:00
2020-08-01 03:01:32 +02:00
get plugins() {
return this.pluginsList;
}
2020-08-01 03:01:32 +02:00
#loadStrings(plugin) {
2020-10-07 21:12:14 +09:00
const strings = plugin.getTranslations ? plugin.getTranslations() : [];
2020-08-01 03:01:32 +02:00
return globalize.loadStrings({
name: plugin.id || plugin.packageName,
strings: strings
});
}
2018-10-23 01:05:09 +03:00
2020-08-01 03:01:32 +02:00
#definePluginRoute(route, plugin) {
2020-08-12 15:21:56 +02:00
route.contentPath = this.mapPath(plugin, route.path);
route.path = this.#mapRoute(plugin, route);
2020-08-01 03:01:32 +02:00
Emby.App.defineRoute(route, plugin.id);
}
async #registerPlugin(plugin) {
2020-08-01 03:01:32 +02:00
this.#register(plugin);
if (plugin.getRoutes) {
2020-08-01 03:01:32 +02:00
plugin.getRoutes().forEach((route) => {
this.#definePluginRoute(route, plugin);
});
}
if (plugin.type === 'skin') {
// translations won't be loaded for skins until needed
return plugin;
} else {
return await this.#loadStrings(plugin);
}
}
async #preparePlugin(pluginSpec, plugin) {
2020-08-01 03:01:32 +02:00
if (typeof pluginSpec === 'string') {
// See if it's already installed
const existing = this.plugins.filter(function (p) {
return p.id === plugin.id;
})[0];
if (existing) {
return pluginSpec;
}
plugin.installUrl = pluginSpec;
const separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
}
return this.#registerPlugin(plugin);
}
async loadPlugin(pluginSpec) {
let plugin;
if (typeof pluginSpec === 'string') {
if (pluginSpec in window) {
console.log(`Loading plugin (via window): ${pluginSpec}`);
2020-11-29 14:46:18 +01:00
2020-12-09 11:53:00 +01: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-12-09 11:53:00 +01:00
}
const pluginClass = await pluginDefinition();
if (typeof pluginClass !== 'function') {
throw new TypeError(`Plugin definition doesn't return a class for '${pluginSpec}'`);
}
// init plugin and pass basic dependencies
2020-12-09 11:53:00 +01:00
plugin = new pluginClass({
events: Events,
loading,
appSettings,
2021-04-10 21:53:32 -04:00
playbackManager,
globalize,
appHost,
2021-04-14 18:59:51 -04:00
appRouter,
inputManager
});
} else {
console.debug(`Loading plugin (via dynamic import): ${pluginSpec}`);
2020-11-30 11:50:00 -05:00
const pluginResult = await import(/* webpackChunkName: "[request]" */ `../plugins/${pluginSpec}`);
plugin = new pluginResult.default;
}
2020-08-01 03:01:32 +02:00
} else if (pluginSpec.then) {
console.debug('Loading plugin (via promise/async function)');
const pluginResult = await pluginSpec;
plugin = new pluginResult.default;
2020-08-01 03:01:32 +02:00
} else {
throw new TypeError('Plugins have to be a Promise that resolves to a plugin builder function');
2020-08-01 03:01:32 +02:00
}
return this.#preparePlugin(pluginSpec, plugin);
}
2020-08-01 03:01:32 +02: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);
2020-09-08 02:05:02 -04:00
Events.trigger(this, 'registered', [obj]);
2020-08-01 03:01:32 +02:00
}
2020-08-01 03:01:32 +02:00
ofType(type) {
return this.pluginsList.filter((o) => {
return o.type === type;
});
}
2020-08-01 03:01:32 +02:00
#mapRoute(plugin, route) {
if (typeof plugin === 'string') {
plugin = this.pluginsList.filter((p) => {
return (p.id || p.packageName) === plugin;
})[0];
}
route = route.path || route;
if (route.toLowerCase().startsWith('http')) {
return route;
}
2020-08-01 03:01:32 +02:00
return '/plugins/' + plugin.id + '/' + route;
}
2020-08-12 15:21:56 +02:00
mapPath(plugin, path, addCacheParam) {
2020-08-01 03:01:32 +02:00
if (typeof plugin === 'string') {
plugin = this.pluginsList.filter((p) => {
return (p.id || p.packageName) === plugin;
})[0];
}
2020-10-07 21:12:14 +09:00
let url = plugin.baseUrl + '/' + path;
2020-08-01 03:01:32 +02:00
if (addCacheParam) {
url += url.includes('?') ? '&' : '?';
url += 'v=' + cacheParam;
}
return url;
}
2020-08-01 03:01:32 +02:00
}
2020-08-01 03:01:32 +02:00
/* eslint-enable indent */
2020-08-16 20:24:45 +02:00
export const pluginManager = new PluginManager();