@playkit-js/kaltura-player-js
Version:
[](https://github.com/kaltura/kaltura-player-js/actions/workflows/run_canary.yaml) [ • 33.6 kB
text/typescript
import {
Env,
TextStyle,
Utils,
setCapabilities,
EngineType,
DrmScheme,
getLogger,
LogLevel,
setLogHandler,
setLogLevel as _setLogLevel,
ILogLevel,
ILogHandler,
PKSourcesConfigObject
} from '@playkit-js/playkit-js';
import { ProviderOptionsObject } from '@playkit-js/playkit-js-providers/types';
import { ValidationErrorType } from './validation-error';
import LocalStorageManager from '../storage/local-storage-manager';
import { KalturaPlayer } from '../../kaltura-player';
import { addClientTag, addReferrer, updateSessionIdInUrl } from './kaltura-params';
import { DEFAULT_OBSERVED_THRESHOLDS, DEFAULT_PLAYER_THRESHOLD } from './viewability-manager';
import SessionStorageManager from '../storage/session-storage-manager';
import { BaseStorageManager } from '../storage/base-storage-manager';
import { BasePlugin } from '../plugins';
import { KalturaPlayerConfig, LegacyPartialKPOptionsObject, PartialKPOptionsObject, PluginsConfig, PlaybackConfig } from '../../types';
import { SessionIdGenerator } from './session-id-generator';
import { UiConfIdSingleton } from './ui-conf-id-singleton';
const setupMessages: Array<any> = [];
const CONTAINER_CLASS_NAME: string = 'kaltura-player-container';
const KALTURA_PLAYER_DEBUG_QS: string = 'debugKalturaPlayer';
const KALTURA_PLAYER_START_TIME_QS: string = 'kalturaStartTime';
const KALTURA_PLAYER_END_TIME_QS: string = 'kalturaEndTime';
const KALTURA_PLAYER_CLIP_START_TIME_QS: string = 'kalturaSeekFrom';
const KALTURA_PLAYER_CLIP_END_TIME_QS: string = 'kalturaClipTo';
const KAVA_DEFAULT_PARTNER = 2504201;
// eslint-disable-next-line max-len
const KAVA_DEFAULT_IMPRESSION = `https://analytics.kaltura.com/api_v3/index.php?service=analytics&action=trackEvent&apiVersion=3.3.0&format=1&eventType=1&partnerId=${KAVA_DEFAULT_PARTNER}&entryId=1_3bwzbc9o&&eventIndex=1&position=0`;
declare let __CONFIG_DOCS_URL__: string;
const logHandlers: Array<(messages: any[], context: object) => void> = [];
const LOG_BUFFER_SIZE = 1000;
const logBuffer: string[] = [];
const logHandler = (messages: any[], ctx: { name: string }): void => {
logHandlers.forEach((handler: ILogHandler): void => {
handler(messages, { ...ctx, level: LogLevel.INFO });
});
};
/**
* Validate the initial user config.
* @private
* @param {PartialKPOptionsObject} options - partial kaltura player options.
* @returns {void}
*/
function validateConfig(options: PartialKPOptionsObject): void {
if (!options) {
throw new Error(ValidationErrorType.INITIAL_CONFIG_REQUIRED);
}
validateTargetId(options.targetId);
}
/**
* Validate the user input for target id.
* @private
* @param {string} targetId - The DOM element id which the player will be append to.
* @returns {void}
*/
function validateTargetId(targetId: string): void {
if (!targetId) {
throw new Error(ValidationErrorType.TARGET_ID_REQUIRED);
}
const targetIdElement = document.getElementById(targetId);
if (!targetIdElement) {
throw new Error(ValidationErrorType.DOM_ELEMENT_WITH_TARGET_ID_REQUIRED + targetId);
}
if (targetIdElement.getElementsByClassName(CONTAINER_CLASS_NAME).length > 0) {
throw new Error(ValidationErrorType.TARGET_ID_ALREADY_USED + targetId);
}
}
/**
* @param {string} url - url
* @param {string} productVersion - product version
* @return {string} - the url with the product version appended in the query params
* @private
*/
function addProductVersion(url: string, productVersion?: string): string {
if (productVersion) {
url += `&clientVer=${productVersion}`;
}
return url;
}
/**
* Validate the initial user input for the provider options.
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function validateProviderConfig(options: KalturaPlayerConfig): void {
const { provider: providerOptions }: { provider: ProviderOptionsObject } = options;
const productVersion: string = getServerUIConf()?.productVersion;
if (!providerOptions.partnerId || providerOptions.partnerId === KAVA_DEFAULT_PARTNER) {
//create source object as a 'hack' to be able to use utility functions on url
const source = {
url: KAVA_DEFAULT_IMPRESSION,
mimetype: ''
};
source.url = addProductVersion(source.url, productVersion);
source.url = addReferrer(source.url);
source.url = addClientTag(source.url, productVersion);
source.url = updateSessionIdInUrl(null, source.url, SessionIdGenerator.next());
navigator.sendBeacon && navigator.sendBeacon(source.url);
}
}
/**
* Creates the player container dom element.
* @private
* @param {string} targetId - The div id which the player will append to.
* @returns {string} - The player container id.
*/
function createKalturaPlayerContainer(targetId: string): string {
const el = document.createElement('div');
el.id = Utils.Generator.uniqueId(5);
el.className = CONTAINER_CLASS_NAME;
el.setAttribute('tabindex', '-1');
const parentNode = document.getElementById(targetId);
if (parentNode && el) {
parentNode.appendChild(el);
}
return el.id;
}
/**
* Initializes the storage managers.
* @private
* @returns {void}
*/
function initializeStorageManagers(): void {
LocalStorageManager.initialize();
SessionStorageManager.initialize();
}
/**
* Sets the storage config on the player config if certain conditions are met.
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function setStorageConfig(options: KalturaPlayerConfig): void {
if (!options.disableUserCache) {
BaseStorageManager.setStorageConfig(options);
}
}
/**
* Applies cache support if it's supported by the environment.
* @private
* @param {KalturaPlayer} player - The Kaltura player.
* @returns {void}
*/
function applyStorageSupport(player: KalturaPlayer): void {
BaseStorageManager.attachAll(player);
}
/**
* Loads the registered remote players.
* @private
* @param {KalturaPlayerConfig} defaultOptions - The kaltura player options.
* @param {KalturaPlayer} player - The Kaltura player.
* @returns {void}
*/
function applyCastSupport(defaultOptions: KalturaPlayerConfig, player: KalturaPlayer): void {
if (defaultOptions.cast) {
player.remotePlayerManager.load(defaultOptions.cast, player);
}
}
/**
* Sets the player text style from storage.
* @private
* @param {KalturaPlayer} player - The Kaltura player.
* @returns {void}
*/
function setStorageTextStyle(player: KalturaPlayer): void {
if (!player.config.disableUserCache && LocalStorageManager.isStorageAvailable()) {
const textStyleObj = LocalStorageManager.getPlayerTextStyle();
if (textStyleObj) {
player.textStyle = Utils.Object.mergeDeep(new TextStyle(), textStyleObj);
}
}
}
/**
* Call to setCapabilities on the first UI_CLICKED event
* @private
* @param {Player} player - The Kaltura player.
* @returns {void}
*/
function attachToFirstClick(player: KalturaPlayer): void {
if (Env.isIOS || Env.isIPadOS) {
const onUIClicked = (): void => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
player.removeEventListener(player.Event.UI.UI_CLICKED, onUIClicked);
setCapabilities(EngineType.HTML5, { autoplay: true });
};
const onSourceSelected = (): void => {
player.removeEventListener(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
player.Event.SOURCE_SELECTED,
onSourceSelected
);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
player.addEventListener(player.Event.UI.UI_CLICKED, onUIClicked);
};
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
player.addEventListener(player.Event.SOURCE_SELECTED, onSourceSelected);
}
}
/**
* check the player debug mode according to config or URL query string params
* @private
* @returns {boolean} - if to set debug mode or not
*/
function isDebugMode(): boolean {
let isDebugMode = false;
if (window.DEBUG_KALTURA_PLAYER === true) {
isDebugMode = true;
} else {
isDebugMode = getUrlParameter(KALTURA_PLAYER_DEBUG_QS) === '';
}
return isDebugMode;
}
/**
* get the parameter for start time
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function maybeApplyStartTimeQueryParam(options: KalturaPlayerConfig): void {
const startTime = parseFloat(<string>getUrlParameter(KALTURA_PLAYER_START_TIME_QS));
if (!isNaN(startTime)) {
Utils.Object.createPropertyPath(options, 'sources.startTime', startTime);
}
}
/**
* get the parameter for end time
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function maybeApplyEndTimeQueryParam(options: KalturaPlayerConfig): void {
const endTime = parseFloat(<string>getUrlParameter(KALTURA_PLAYER_END_TIME_QS));
if (!isNaN(endTime)) {
Utils.Object.createPropertyPath(options, 'sources.endTime', endTime);
}
}
/**
* get the parameters for seekFrom and clipTo
* @private
* @param {KPOptionsObject} options - kaltura player options
* @returns {void}
*/
function maybeApplyClipQueryParams(options: KalturaPlayerConfig): void {
const seekFrom = parseFloat(getUrlParameter(KALTURA_PLAYER_CLIP_START_TIME_QS)!);
if (!isNaN(seekFrom)) {
Utils.Object.createPropertyPath(options, 'sources.seekFrom', seekFrom);
}
const clipTo = parseFloat(getUrlParameter(KALTURA_PLAYER_CLIP_END_TIME_QS)!);
if (!isNaN(clipTo)) {
Utils.Object.createPropertyPath(options, 'sources.clipTo', clipTo);
}
}
/**
* set the logger
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function setLogOptions(options: KalturaPlayerConfig): void {
if (!Utils.Object.getPropertyPath(options, 'ui.log')) {
Utils.Object.createPropertyPath(options, 'ui.log', {});
}
if (!Utils.Object.getPropertyPath(options, 'provider.log')) {
Utils.Object.createPropertyPath(options, 'provider.log', {});
}
if (!Utils.Object.getPropertyPath(options, 'log')) {
Utils.Object.createPropertyPath(options, 'log', {});
}
if (Utils.Object.getPropertyPath(options, 'log.useDebugInfo') === undefined) {
options.log!.useDebugInfo = true;
}
setLogHandlers(options);
let logLevelObj: ILogLevel = LogLevel.ERROR;
if (options.log && isDebugMode()) {
logLevelObj = LogLevel.DEBUG;
options.log.level = LogLevel.DEBUG.name;
} else if (options.log && options.log.level && LogLevel[options.log.level]) {
logLevelObj = LogLevel[options.log.level];
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
options.ui.log.level = options.provider.log.level = logLevelObj.name;
_setLogLevel(logLevelObj);
}
function setLogHandlers(options: KalturaPlayerConfig): void {
if (options.log && !options.log.handler && !options.log.useDebugInfo) return;
function getFormattedMessage(messages: any[], ctx: any): string {
const messagesStr = [...messages]
.map((msg) => {
try {
// stringify objects, but protect against errors (e.g. circular references)
return typeof msg === 'string' ? msg : JSON.stringify(msg);
} catch (e) {
return msg;
}
})
.join(' ');
return `[${(ctx as { name: string }).name}] ${messagesStr}`;
}
logHandlers.push((messages, ctx) => {
// when we use a handler, we have to explicitly print the message to console
// eslint-disable-next-line no-console
console.log(getFormattedMessage(messages, ctx));
});
if (options.log && (options.log as any).useDebugInfo) {
logHandlers.push((messages, ctx) => {
const message = getFormattedMessage(messages, ctx);
if (logBuffer.length === LOG_BUFFER_SIZE) {
logBuffer.shift();
}
logBuffer.push(`${new Date().toLocaleString()} ${message} \n`);
});
}
// add custom log handlers
if (options.log && typeof options.log.handler === 'function') {
logHandlers.push(options.log.handler);
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
setLogHandler(logHandler);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
options.ui.log.handler = options.provider.log.handler = logHandler;
}
/**
* gets the url query string parameter
* @private
* @param {string} name - name of query string param
* @returns {?string} - value of the query string param or null if doesn't exist
*/
function getUrlParameter(name: string): string | null {
const getUrlParamPolyfill = (name: string): string | null => {
name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]');
const regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
const results = regex.exec(location.search);
const isExist = location.search.indexOf(name) > -1;
return results === null ? (isExist ? '' : null) : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
let value;
if (window.URLSearchParams) {
const urlParams = new URLSearchParams(window.location.search);
value = urlParams.get(name);
} else {
value = getUrlParamPolyfill(name);
}
return value;
}
/**
* get the server UIConf
* @private
* @returns {Object} - The server UIConf
*/
function getServerUIConf(): any {
const uiConfId = UiConfIdSingleton.getInstance().getUiConfId();
if (uiConfId !== '' && window.KalturaPlayers && window.KalturaPlayers[uiConfId]?.config) {
return window.KalturaPlayers[uiConfId].config;
}
return window.__kalturaplayerdata || {};
}
/**
* set the UIConfId if exists
* @private
* @param {PartialKPOptionsObject} options - partial user kaltura player options.
* @returns {void}
*/
function setUIConfId(options: PartialKPOptionsObject): void {
// Store uiConfId if it exists in options
if (options.provider && options.provider.uiConfId) {
UiConfIdSingleton.getInstance().setUiConfId(options.provider.uiConfId.toString());
}
}
/**
* Gets the default options after merging the user options with the uiConf options and the default internal options.
* @private
* @param {PartialKPOptionsObject} options - partial user kaltura player options.
* @returns {KalturaPlayerConfig} - default kaltura player options.
*/
function getDefaultOptions(options: PartialKPOptionsObject): KalturaPlayerConfig {
const targetId = createKalturaPlayerContainer(options.targetId);
// TODO - fix all KalturaPlayerConfig and Partial relationships
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
let defaultOptions: KalturaPlayerConfig = {
targetId: options.targetId,
provider: {
partnerId: options.provider.partnerId
},
ui: {
targetId: targetId
},
plugins: {},
advertising: {
adBreaks: []
},
viewability: {
observedThresholds: DEFAULT_OBSERVED_THRESHOLDS,
playerThreshold: DEFAULT_PLAYER_THRESHOLD
}
};
Utils.Object.mergeDeep(defaultOptions, options);
if (!options.provider.ignoreServerConfig) {
const serverUIConf = Utils.Object.copyDeep(getServerUIConf());
delete serverUIConf.productVersion;
defaultOptions = Utils.Object.mergeDeep({}, supportLegacyOptions(serverUIConf), defaultOptions);
}
checkNativeHlsSupport(defaultOptions);
checkNativeTextTracksSupport(defaultOptions);
configureSmartTVDefaultOptions(defaultOptions);
configureEdgeDRMDefaultOptions(defaultOptions);
configureIMADefaultOptions(defaultOptions);
configureDAIDefaultOptions(defaultOptions);
configureBumperDefaultOptions(defaultOptions);
maybeSetFullScreenConfig(defaultOptions);
maybeSetCapabilitiesForIos(defaultOptions);
return defaultOptions;
}
/**
* Sets config option for native HLS playback
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function checkNativeHlsSupport(options: KalturaPlayerConfig): void {
if ((Env.isMacOS && Env.isSafari) || Env.isIOS) {
const preferNativeHlsValue = Utils.Object.getPropertyPath(options, 'playback.preferNative.hls');
if (typeof preferNativeHlsValue !== 'boolean') {
Utils.Object.mergeDeep(options, {
playback: {
preferNative: {
hls: true
}
}
});
}
}
}
/**
* Sets config option for native text track support
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function checkNativeTextTracksSupport(options: KalturaPlayerConfig): void {
if ((Env.isMacOS && Env.isSafari) || Env.isIOS) {
const useNativeTextTrack = Utils.Object.getPropertyPath(options, 'text.useNativeTextTrack');
if (typeof useNativeTextTrack !== 'boolean') {
Utils.Object.mergeDeep(options, {
text: {
useNativeTextTrack: true
}
});
}
}
}
/**
* Sets config option for Ads with MSE
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function _configureAdsWithMSE(options: KalturaPlayerConfig): void {
const playAdsWithMSE = Utils.Object.getPropertyPath(options, 'playback.playAdsWithMSE');
if (typeof playAdsWithMSE !== 'boolean') {
options = Utils.Object.createPropertyPath(options, 'playback.playAdsWithMSE', true);
}
const disableMediaPreloadIma = Utils.Object.getPropertyPath(options, 'plugins.ima.disableMediaPreload');
const disableMediaPreloadBumper = Utils.Object.getPropertyPath(options, 'plugins.bumper.disableMediaPreload');
if (options.plugins && options.plugins.ima && typeof disableMediaPreloadIma !== 'boolean') {
options = Utils.Object.createPropertyPath(options, 'plugins.ima.disableMediaPreload', true);
}
if (options.plugins && options.plugins.bumper && typeof disableMediaPreloadBumper !== 'boolean') {
options = Utils.Object.createPropertyPath(options, 'plugins.bumper.disableMediaPreload', true);
}
}
/**
* Sets config option for LG TV SDK 2 live which has problem with long duration buffer
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function _configureLGSDK2HlsLiveConfig(options: KalturaPlayerConfig): void {
const hlsLiveConfig = Utils.Object.getPropertyPath(options, 'playback.options.html5.hls.liveSyncDurationCount');
//webos SDK 2 and less detect as safari browser greater version is chrome
if (typeof hlsLiveConfig !== 'boolean' && Env.isSafari) {
options = Utils.Object.createPropertyPath(options, 'playback.options.html5.hls.liveSyncDurationCount', 2);
}
}
/**
* Sets config option for smart TV
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function configureSmartTVDefaultOptions(options: KalturaPlayerConfig): void {
if (Env.isSmartTV) {
//relevant for LG SDK 4 and HISENSE which doesn't support our check for autoplay with base64 source
setCapabilities(EngineType.HTML5, { autoplay: true });
_configureAdsWithMSE(options);
_configureLGSDK2HlsLiveConfig(options);
if (options.plugins && options.plugins.ima) {
const imaForceReload = Utils.Object.getPropertyPath(options, 'plugins.ima.forceReloadMediaAfterAds');
const delayUntilSourceSelected = Utils.Object.getPropertyPath(options, 'plugins.ima.delayInitUntilSourceSelected');
if (typeof imaForceReload !== 'boolean') {
options = Utils.Object.createPropertyPath(options, 'plugins.ima.forceReloadMediaAfterAds', true);
}
if (typeof delayUntilSourceSelected !== 'boolean') {
options = Utils.Object.createPropertyPath(options, 'plugins.ima.delayInitUntilSourceSelected', true);
}
}
if (options.plugins && options.plugins.youbora) {
const playheadMonitorInterval = Utils.Object.getPropertyPath(options, 'plugins.youbora.playheadMonitorInterval');
if (typeof playheadMonitorInterval !== 'number') {
options = Utils.Object.createPropertyPath(options, 'plugins.youbora.playheadMonitorInterval', 2000);
}
}
const lowLatencyMode = Utils.Object.getPropertyPath(options, 'streaming.lowLatencyMode');
if (typeof lowLatencyMode !== 'boolean') {
options = Utils.Object.createPropertyPath(options, 'streaming.lowLatencyMode', false);
}
}
}
/**
* prefer Playready in edge - from chromium version of edge Widevine is option as well
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function configureEdgeDRMDefaultOptions(options: KalturaPlayerConfig): void {
if (Env.browser.name === 'Edge') {
const keySystem = Utils.Object.getPropertyPath(options, 'drm.keySystem');
if (!keySystem) {
if (Env.os.name === 'Windows') {
options = Utils.Object.createPropertyPath(options, 'drm.keySystem', DrmScheme.PLAYREADY);
} else {
options = Utils.Object.createPropertyPath(options, 'drm.keySystem', DrmScheme.WIDEVINE);
}
}
}
}
/**
* Sets default config option for ima plugin
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function configureIMADefaultOptions(options: KalturaPlayerConfig): void {
if (Env.isIOS && options.plugins && options.plugins.ima && !options.plugins.ima['disable']) {
const playsinline = Utils.Object.getPropertyPath(options, 'playback.playsinline');
const disableMediaPreloadIma = Utils.Object.getPropertyPath(options, 'plugins.ima.disableMediaPreload');
if (playsinline === false && typeof disableMediaPreloadIma !== 'boolean') {
Utils.Object.createPropertyPath(options, 'plugins.ima.disableMediaPreload', true);
}
}
}
/**
* Sets default config option for dai plugin
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function configureDAIDefaultOptions(options: KalturaPlayerConfig): void {
if (options.plugins && options.plugins.imadai && !options.plugins.imadai['disable']) {
const autoStartLoadConfig = Utils.Object.getPropertyPath(options, 'playback.options.html5.hls.autoStartLoad');
if (typeof autoStartLoadConfig !== 'boolean') {
Utils.Object.mergeDeep(options, {
playback: {
options: {
html5: {
hls: {
autoStartLoad: false
}
}
}
}
});
}
}
}
/**
* Sets default config option for bumper plugin when ima-dai enabled
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function configureBumperDefaultOptions(options: KalturaPlayerConfig): void {
const bumperConfig = Utils.Object.getPropertyPath(options, 'plugins.bumper');
const daiConfig = Utils.Object.getPropertyPath(options, 'plugins.imadai');
if (bumperConfig) {
const newBumperConfig: any = {};
if (
typeof bumperConfig.playOnMainVideoTag !== 'boolean' &&
(Env.isSmartTV || (Env.isIOS && options.playback && options.playback.playsinline === false))
) {
newBumperConfig['playOnMainVideoTag'] = true;
}
if (daiConfig && !daiConfig.disable) {
if (!Array.isArray(bumperConfig.position)) {
newBumperConfig['position'] = [0];
}
if (typeof bumperConfig.disableMediaPreload !== 'boolean') {
newBumperConfig['disableMediaPreload'] = true;
}
}
Utils.Object.mergeDeep(options, {
plugins: {
bumper: newBumperConfig
}
});
}
}
/**
* print kaltura version to log by configuration
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function printKalturaPlayerVersionToLog(options: PartialKPOptionsObject | LegacyPartialKPOptionsObject): void {
const playerVersion = Utils.Object.getPropertyPath(options, 'log.playerVersion');
if (playerVersion !== false) {
_setLogLevel(LogLevel.INFO);
getLogger().log(`%c ${__NAME__} ${__VERSION__}`, 'color: #ff98f9; font-size: large');
getLogger().log(`%c For more details see ${__PACKAGE_URL__}`, 'color: #ff98f9;');
}
}
/**
* Transform options structure from legacy structure to new structure.
* @private
* @param {Object} options - The options with the legacy structure.
* @return {PartialKPOptionsObject} - Partial options with the expected structure.
*/
function supportLegacyOptions(options: LegacyPartialKPOptionsObject): PartialKPOptionsObject {
const removePlayerEntry = (): void => {
if (options.player) {
setupMessages.push({
level: 'warn',
msg: `Path config.player will be deprecated soon. Please update your config structure as describe here: ${__CONFIG_DOCS_URL__}`
});
const playerOptions = Utils.Object.copyDeep(options.player);
delete options.player;
Utils.Object.mergeDeep(options, playerOptions);
}
};
const moveProp = (propPath: string, targetPath: string): void => {
if (Utils.Object.hasPropertyPath(options, propPath)) {
setupMessages.push({
level: 'warn',
msg: `Path config.player.${propPath} will be deprecated soon. Please update your config structure as describe here: ${__CONFIG_DOCS_URL__}`
});
if (!Utils.Object.hasPropertyPath(options, targetPath)) {
const propValue = Utils.Object.getPropertyPath(options, propPath);
const propObj = Utils.Object.createPropertyPath({}, targetPath, propValue);
Utils.Object.mergeDeep(options, propObj);
Utils.Object.deletePropertyPath(options, propPath);
} else {
Utils.Object.deletePropertyPath(options, propPath);
}
}
};
const moves = [
['duration', 'sources.duration'],
['type', 'sources.type'],
['dvr', 'sources.dvr'],
['id', 'sources.id'],
['name', 'metadata.name'],
['metadata.poster', 'sources.poster'],
['metadata', 'sources.metadata'],
['logLevel', 'log.level'],
['ui.components.fullscreen.inBrowserFullscreenForIOS', 'playback.inBrowserFullscreen'],
['playback.enableCEA708Captions', 'text.enableCEA708Captions'],
['playback.useNativeTextTrack', 'text.useNativeTextTrack'],
['playback.options.html5.dash.useShakaTextTrackDisplay', 'text.useShakaTextTrackDisplay'],
['playback.captionsTextTrack1Label', 'text.captionsTextTrack1Label'],
['playback.captionsTextTrack1LanguageCode', 'text.captionsTextTrack1LanguageCode'],
['playback.captionsTextTrack2Label', 'text.captionsTextTrack2Label'],
['playback.captionsTextTrack2LanguageCode', 'text.captionsTextTrack2LanguageCode'],
['plugins.visibility.threshold', 'viewability.playerThreshold'],
['plugins.visibility.floating', 'plugins.floating'],
['playback.startTime', 'sources.startTime']
];
removePlayerEntry();
moves.forEach((move) => moveProp(move[0], move[1]));
return <PartialKPOptionsObject>options;
}
/**
* Prints early setup messages.
* @private
* @returns {void}
*/
function printSetupMessages(): void {
setupMessages.forEach((msgObj) => getLogger('KalturaPlayer:Setup')[msgObj.level](msgObj.msg));
}
/**
* Prints early setup messages.
* @private
* @param {Player} player - The player.
* @param {string} engine - The player engine name.
* @param {string} format - The player engine format.
* @returns {PKPlaybackConfigObject} - The playback config.
*/
function addEngineToStreamPriority(player: KalturaPlayer, engine: string, format: string): PlaybackConfig {
const playbackConfig = player.config.playback;
let hasYoutube = false;
playbackConfig.streamPriority.forEach((sp) => {
if (sp.engine === engine) {
hasYoutube = true;
}
});
if (!hasYoutube) {
playbackConfig.streamPriority.push({
engine: engine,
format: format
});
}
return playbackConfig;
}
/**
* set stream priority according to playerConfig
* @param {Player} player - player
* @param {PKSourcesConfigObject} sources - sources
* @return {void}
*/
function maybeSetStreamPriority(player: KalturaPlayer, sources: PKSourcesConfigObject): PlaybackConfig | null {
if (sources && hasYoutubeSource(sources)) {
return addEngineToStreamPriority(player, 'youtube', 'progressive');
}
if (sources && hasImageSource(sources)) {
return addEngineToStreamPriority(player, 'image', 'image');
}
if (sources && hasDocumentSource(sources)) {
return addEngineToStreamPriority(player, 'document', 'document');
}
return null;
}
/**
* returns true if sources contain youtube video source
* @param {PKSourcesConfigObject} sources - thr sources object
* @returns {boolean} - true if sources contain youtube source
*/
function hasYoutubeSource(sources: PKSourcesConfigObject): boolean {
const source = sources && sources.progressive;
return !!(source && source[0] && source[0].mimetype === 'video/youtube');
}
/**
* returns true if sources contain image source
* @param {PKSourcesConfigObject} sources - thr sources object
* @returns {boolean} - true if sources contain image source
*/
function hasImageSource(sources: PKSourcesConfigObject): boolean {
// const IMAGE_MIME_TYPES = /(^image)(\/)[a-zA-Z0-9_]*/;
const source = sources && sources.image;
// return !!(source && source[0] && source[0].mimetype.match(IMAGE_MIME_TYPES));
return !!(source && source[0]);
}
/**
* returns true if sources contain document source
* @param {PKSourcesConfigObject} sources - thr sources object
* @returns {boolean} - true if sources contain document source
*/
function hasDocumentSource(sources: PKSourcesConfigObject): boolean {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const source = sources && sources.document;
return !!(source && source[0]);
}
/**
* Maybe set inBrowserFullscreen config based on the plugins.
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function maybeSetFullScreenConfig(options: KalturaPlayerConfig): void {
const vrPlugin = Utils.Object.getPropertyPath(options, 'plugins.vr');
if (vrPlugin && !vrPlugin.disable) {
const fullscreenConfig = Utils.Object.getPropertyPath(options, 'playback.inBrowserFullscreen');
if (typeof fullscreenConfig !== 'boolean') {
Utils.Object.mergeDeep(options, {
playback: {
inBrowserFullscreen: true
}
});
}
}
}
/**
* Set the autoplay capability to false for native Ios player.
* @private
* @param {KalturaPlayerConfig} options - kaltura player options
* @returns {void}
*/
function maybeSetCapabilitiesForIos(options: KalturaPlayerConfig): void {
if (Env.isIOS) {
const playsinline = Utils.Object.getPropertyPath(options, 'playback.playsinline');
const isAirPlayConfigured = Utils.Object.hasPropertyPath(options, 'plugins.airplay');
const isPlaysinline = playsinline !== false;
if (isAirPlayConfigured) {
setCapabilities(EngineType.HTML5, {
autoplay: false,
mutedAutoPlay: isPlaysinline
});
} else if (Env.device.model === 'iPhone' && !isPlaysinline) {
setCapabilities(EngineType.HTML5, {
autoplay: false,
mutedAutoPlay: false
});
}
}
}
/**
* Merge the provider plugins config (e.g. bumper) into the app config and returns it and the respective app config to restore in change media
* @param {PluginsConfig} providerPluginsConfig - the provider plugins config
* @param {KalturaPlayerConfig} appPluginsConfig - the entire app plugins config
* @returns {Array<PluginsConfig>} - the merged plugins config and the partial respective app plugins config
*/
function mergeProviderPluginsConfig(providerPluginsConfig: PluginsConfig, appPluginsConfig: PluginsConfig): Array<PluginsConfig> {
const mergePluginConfig: PluginsConfig = {};
const respectiveAppPluginsConfig: PluginsConfig = {};
Utils.Object.isObject(providerPluginsConfig) &&
Object.entries(providerPluginsConfig).forEach(([pluginName, pluginConfig]: [string, any]) => {
mergePluginConfig[pluginName] = {} as BasePlugin;
respectiveAppPluginsConfig[pluginName] = {} as BasePlugin;
Object.entries(pluginConfig).forEach(([key, providerValue]) => {
const appValue = Utils.Object.getPropertyPath(appPluginsConfig[pluginName], key);
mergePluginConfig[pluginName][key] = appValue || providerValue;
respectiveAppPluginsConfig[pluginName][key] = appValue;
});
});
return [mergePluginConfig, respectiveAppPluginsConfig];
}
function maybeLoadInitialServerResponse(player: KalturaPlayer): void {
const { serviceUrl, initCallToServer } = player.provider.env;
if (initCallToServer) {
const url = serviceUrl + initCallToServer + '/format/1';
fetch(url).then((response) => {
response.json().then((data) => {
getLogger().log(`Initial server response: ${data}`);
});
});
}
return;
}
function getLogBuffer(): string {
return logBuffer.join('');
}
export {
printSetupMessages,
supportLegacyOptions,
printKalturaPlayerVersionToLog,
setStorageConfig,
applyStorageSupport,
applyCastSupport,
setStorageTextStyle,
attachToFirstClick,
validateConfig,
validateProviderConfig,
setLogOptions,
maybeApplyStartTimeQueryParam,
maybeApplyEndTimeQueryParam,
maybeApplyClipQueryParams,
createKalturaPlayerContainer,
checkNativeHlsSupport,
getDefaultOptions,
maybeSetStreamPriority,
hasYoutubeSource,
hasImageSource,
hasDocumentSource,
mergeProviderPluginsConfig,
getServerUIConf,
initializeStorageManagers,
maybeLoadInitialServerResponse,
KALTURA_PLAYER_START_TIME_QS,
getLogBuffer,
setUIConfId
};