diff --git a/src/bigscreenplayer.js b/src/bigscreenplayer.js index 72333dc2..71f8ad18 100644 --- a/src/bigscreenplayer.js +++ b/src/bigscreenplayer.js @@ -307,6 +307,8 @@ function BigscreenPlayer() { callbacks.onError(reason) } }) + + Plugins.updateContext((context) => ({ ...context, mediaSources })) }, /** @@ -737,7 +739,7 @@ function BigscreenPlayer() { }, /** - * Register a plugin for extended events. + * Register a plugin for extended events & custom functionality. * @function * @param {*} plugin */ diff --git a/src/playercomponent.js b/src/playercomponent.js index 5abf94cb..5148f1d8 100644 --- a/src/playercomponent.js +++ b/src/playercomponent.js @@ -335,6 +335,9 @@ function PlayerComponent( }) } + // Not an ideal place for this, but I've been warned of a possible playercomponent rewrite + Plugins.updateContext((context) => ({ ...context, attemptCdnFailover })) + function clearFatalErrorTimeout() { if (fatalErrorTimeout !== null) { clearTimeout(fatalErrorTimeout) diff --git a/src/plugins.js b/src/plugins.js index b4715135..75808fda 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -2,6 +2,7 @@ import PlaybackUtils from "./utils/playbackutils" import CallCallbacks from "./utils/callcallbacks" let plugins = [] +const pluginContext = {} function callOnAllPlugins(funcKey, evt) { const clonedEvent = PlaybackUtils.deepClone(evt) @@ -13,8 +14,37 @@ function callOnAllPlugins(funcKey, evt) { } export default { + /** + * @param {function (*): *} updater - a function which accepts the current context, and returns a new context + */ + updateContext: (updater) => { + const newContext = updater(PlaybackUtils.deepClone(pluginContext)) + + if (typeof newContext !== "object") { + throw new TypeError("context must be an object") + } + + // update object (preserving reference) + for (const prop of Object.keys(pluginContext)) { + delete pluginContext[prop] + } + + Object.assign(pluginContext, newContext) + + // call context update handlers + for (const plugin of plugins) { + plugin.onContextUpdated?.(pluginContext) + } + }, + + /** + * @param {*} plugin - an object + */ registerPlugin: (plugin) => { plugins.push(plugin) + + // provide initial context + plugin.onContextUpdated?.(pluginContext) }, unregisterPlugin: (plugin) => { diff --git a/src/subtitles/imscsubtitles.test.js b/src/subtitles/imscsubtitles.test.js index dee02a37..57848492 100644 --- a/src/subtitles/imscsubtitles.test.js +++ b/src/subtitles/imscsubtitles.test.js @@ -7,6 +7,7 @@ import Plugins from "../plugins" jest.mock("smp-imsc") jest.mock("../utils/loadurl") jest.mock("../plugins", () => ({ + updateContext: jest.fn(), interface: { onSubtitlesTimeout: jest.fn(), onSubtitlesXMLError: jest.fn(), diff --git a/src/subtitles/legacysubtitles.test.js b/src/subtitles/legacysubtitles.test.js index f99bd65e..15d62cdc 100644 --- a/src/subtitles/legacysubtitles.test.js +++ b/src/subtitles/legacysubtitles.test.js @@ -6,6 +6,7 @@ import Renderer from "./renderer" jest.mock("../utils/loadurl") jest.mock("../plugins", () => ({ + updateContext: jest.fn(), interface: { onSubtitlesTimeout: jest.fn(), onSubtitlesXMLError: jest.fn(), diff --git a/src/subtitles/subtitles.js b/src/subtitles/subtitles.js index 8536edfd..4ba99342 100644 --- a/src/subtitles/subtitles.js +++ b/src/subtitles/subtitles.js @@ -133,6 +133,16 @@ function Subtitles( subtitlesContainer?.tearDown() } + function attemptSubtitleCdnFailover(opts) { + hide() + mediaSources + .failoverSubtitles(opts) + .then(() => show()) + .catch(() => DebugTool.info("No more CDNs available for subtitle failover")) + } + + Plugins.updateContext((context) => ({ ...context, attemptSubtitleCdnFailover })) + return { enable, disable,