diff --git a/client/src/app/core/plugins/plugin.service.ts b/client/src/app/core/plugins/plugin.service.ts index 525740a01..af330c2eb 100644 --- a/client/src/app/core/plugins/plugin.service.ts +++ b/client/src/app/core/plugins/plugin.service.ts @@ -125,8 +125,15 @@ export class PluginService { for (const hook of this.hooks[hookName]) { try { - if (wait) result = await hook.handler(param) - else result = hook.handler() + const p = hook.handler(param) + + if (wait) { + result = await p + } else if (p.catch) { + p.catch((err: Error) => { + console.error('Cannot run hook %s of script %s of plugin %s.', hookName, hook.plugin, hook.clientScript, err) + }) + } } catch (err) { console.error('Cannot run hook %s of script %s of plugin %s.', hookName, hook.plugin, hook.clientScript, err) } diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 93ccb7da8..1111fd97f 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -19,7 +19,7 @@ const LAST_MIGRATION_VERSION = 400 // --------------------------------------------------------------------------- const API_VERSION = 'v1' -const PEERTUBE_VERSION = process.env.npm_package_version || 'unknown' +const PEERTUBE_VERSION = require(join(root(), 'package.json')).version const PAGINATION = { COUNT: { diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts index 9e4ec5adf..570b56193 100644 --- a/server/lib/plugins/plugin-manager.ts +++ b/server/lib/plugins/plugin-manager.ts @@ -104,10 +104,12 @@ export class PluginManager { for (const hook of this.hooks[hookName]) { try { + const p = hook.handler(param) + if (wait) { - result = await hook.handler(param) - } else { - result = hook.handler() + result = await p + } else if (p.catch) { + p.catch(err => logger.warn('Hook %s of plugin %s thrown an error.', hookName, hook.pluginName, { err })) } } catch (err) { logger.error('Cannot run hook %s of plugin %s.', hookName, hook.pluginName, { err }) @@ -329,7 +331,7 @@ export class PluginManager { registerSetting, settingsManager, storageManager - }) + }).catch(err => logger.error('Cannot register plugin %s.', npmName, { err })) logger.info('Add plugin %s CSS to global file.', npmName) @@ -365,7 +367,7 @@ export class PluginManager { private async regeneratePluginGlobalCSS () { await this.resetCSSGlobalFile() - for (const key of Object.keys(this.registeredPlugins)) { + for (const key of Object.keys(this.getRegisteredPlugins())) { const plugin = this.registeredPlugins[key] await this.addCSSToGlobalFile(plugin.path, plugin.css) diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index 50963ba57..f39b97ef0 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts @@ -156,6 +156,15 @@ export class PluginModel extends Model { return PluginModel.findOne(query) .then((c: any) => { if (!c) return undefined + const value = c.value + + if (typeof value === 'string' && value.startsWith('{')) { + try { + return JSON.parse(value) + } catch { + return value + } + } return c.value }) diff --git a/shared/models/plugins/plugin-library.model.ts b/shared/models/plugins/plugin-library.model.ts index df6499b6b..fd90a3b46 100644 --- a/shared/models/plugins/plugin-library.model.ts +++ b/shared/models/plugins/plugin-library.model.ts @@ -1,7 +1,7 @@ import { RegisterOptions } from './register-options.model' export interface PluginLibrary { - register: (options: RegisterOptions) => void + register: (options: RegisterOptions) => Promise unregister: () => Promise } diff --git a/support/doc/plugins/quickstart.md b/support/doc/plugins/quickstart.md index a018aa50a..0e125e707 100644 --- a/support/doc/plugins/quickstart.md +++ b/support/doc/plugins/quickstart.md @@ -18,10 +18,13 @@ A plugin registers functions in JavaScript to execute when PeerTube (server and Example: ```js -registerHook({ - target: 'action:application.listening', - handler: () => displayHelloWorld() -}) +// This register function is called by PeerTube, and **must** return a promise +async function register ({ registerHook }) { + registerHook({ + target: 'action:application.listening', + handler: () => displayHelloWorld() + }) +} ``` On server side, these hooks are registered by the `library` file defined in `package.json`. @@ -65,9 +68,7 @@ or `/themes/{theme-name}/{theme-version}/static/` routes. Plugins can declare CSS files that PeerTube will automatically inject in the client. -### Server helpers - -**Only for plugins** +### Server helpers (only for plugins) #### Settings @@ -94,7 +95,7 @@ Example: ```js const value = await storageManager.getData('mykey') -await storageManager.storeData('mykey', 'myvalue') +await storageManager.storeData('mykey', { subkey: 'value' }) ``` ### Publishing @@ -169,12 +170,13 @@ If you don't need static directories, use an empty `object`: } ``` -And if you don't need CSS files, use an empty `array`: +And if you don't need CSS or client script files, use an empty `array`: ```json { ..., "css": [], + "clientScripts": [], ... } ``` @@ -197,8 +199,14 @@ You'll need to have a local PeerTube instance: ``` $ npm run build -- --light ``` + + * Build the CLI: - * Run it (you can access to your instance on http://localhost:9000): +``` +$ npm run setup:cli +``` + + * Run PeerTube (you can access to your instance on http://localhost:9000): ``` $ NODE_ENV=test npm start