@playkit-js/kaltura-player-js
Version:
[](https://github.com/kaltura/kaltura-player-js/actions/workflows/run_canary.yaml) [ • 8.57 kB
text/typescript
import { PKSourcesConfigObject, PlayerStreamTypes, StreamType, Utils } from '@playkit-js/playkit-js';
import { getServerUIConf } from './setup-helpers';
import { KalturaPlayer } from '../../kaltura-player';
import { PartialKPOptionsObject } from '../../types';
import { SessionIdGenerator } from './session-id-generator';
const PLAY_MANIFEST = 'playmanifest/';
const PLAY_SESSION_ID = 'playSessionId=';
const DRM_SESSION_ID = 'sessionId=';
const REFERRER = 'referrer=';
const UICONF_ID = 'uiConfId=';
const CLIENT_TAG = 'clientTag=html5:v';
const UDRM_DOMAIN = 'kaltura.com';
const CUSTOM_DATA = 'custom_data=';
const SIGNATURE = 'signature=';
const SEEK_FROM = 'seekFrom=';
const CLIP_TO = 'clipTo=';
declare global {
interface Window {
originalRequestReferrer?: string;
}
}
/**
* @param {Player} player - player
* @param {PartialKPOptionsObject} playerConfig - player config
* @return {void}
* @private
*/
function handleSessionId(player: KalturaPlayer, playerConfig: PartialKPOptionsObject): void {
if (player.config.session && player.config.session.id) {
// on change media
updateSessionId(player, playerConfig);
} else {
// on first playback
addSessionId(playerConfig);
if (player?.playlist?.items?.length && playerConfig.sources?.id) {
player.sessionIdCache?.set(playerConfig.sources.id, playerConfig.session!.id as string);
}
}
}
/**
* @param {PartialKPOptionsObject} playerConfig - player config
* @return {void}
* @private
*/
function addSessionId(playerConfig: PartialKPOptionsObject): void {
setSessionId(playerConfig, SessionIdGenerator.next());
}
/**
* @param {Player} player - player
* @param {PartialKPOptionsObject} playerConfig - player config
* @return {void}
* @private
*/
function updateSessionId(player: KalturaPlayer, playerConfig: PartialKPOptionsObject): void {
const entryId = playerConfig.sources?.id;
if (!player?.playlist?.items?.length) {
setSessionId(playerConfig, SessionIdGenerator.next());
} else if (entryId) {
if (player.sessionIdCache?.get(entryId)) {
setSessionId(playerConfig, player.sessionIdCache?.get(entryId));
} else {
const sessionId = SessionIdGenerator.next();
player.sessionIdCache?.set(entryId, sessionId);
setSessionId(playerConfig, sessionId);
}
}
}
/**
* @param {PartialKPOptionsObject} playerConfig - player config
* @param {string} sessionId - the session id
* @return {void}
* @private
*/
function setSessionId(playerConfig: PartialKPOptionsObject, sessionId: string): void {
playerConfig.session = playerConfig.session || {};
playerConfig.session.id = sessionId;
}
/**
* @param {string} url - url
* @param {string} sessionId - session id
* @param {string} paramName - optional param name of the session id
* @return {string} - the url with the new sessionId
* @private
*/
function updateSessionIdInUrl(player: KalturaPlayer | null, url: string, sessionId?: string, paramName: string = PLAY_SESSION_ID): string {
if (sessionId) {
const sessionIdInUrlRegex = new RegExp(paramName + '((?:[a-z0-9]|-)*:(?:[a-z0-9]|-)*)', 'i');
const sessionIdInUrl = sessionIdInUrlRegex.exec(url);
// this url has session id (has already been played)
if (sessionIdInUrl && sessionIdInUrl[1]) {
// session id should be the same for the same entry
if (!player?.playlist?.items?.length) {
url = url.replace(sessionIdInUrl[1], sessionId);
}
} else {
url += getQueryStringParamDelimiter(url) + paramName + sessionId;
}
}
return url;
}
/**
* @return {string} - The referrer
* @private
*/
function getReferrer(): string {
let referrer;
try {
referrer = window.parent.document.URL;
//Ignore referrer from friendly iframe that contains kaltura.com
if (referrer.toLowerCase().includes('kaltura.com')) {
throw new Error('ignoring referrer:' + referrer);
}
} catch (e) {
// unfriendly iframe
// try to get it from originalReferrer supplied by backend
// or fallback to document referrer
referrer = window.originalRequestReferrer || document.referrer;
}
return referrer;
}
function getOriginalRequestReferrer(): string | undefined {
return window.originalRequestReferrer;
}
/**
* @param {string} url - url
* @return {string} - the url with the referrer appended in the query params
* @private
*/
function addReferrer(url: string): string {
if (url.indexOf(REFERRER) === -1) {
const referrer = btoa(getReferrer().substr(0, 1000));
url += getQueryStringParamDelimiter(url) + REFERRER + referrer;
}
return url;
}
/**
* @param {string} url - url
* @param {PartialKPOptionsObject} playerConfig - player config
* @return {string} - the url with the uiconf id appended in the query params
* @private
*/
function addUIConfId(url: string, playerConfig: PartialKPOptionsObject): string {
const uiConfId = Utils.Object.getPropertyPath(playerConfig, 'provider.uiConfId');
if (url.indexOf(UICONF_ID) === -1 && typeof uiConfId === 'number') {
url += getQueryStringParamDelimiter(url) + UICONF_ID + uiConfId;
}
return url;
}
/**
* @param {string} url - url
* @return {string} - returns the next param delimiter (? or &) according to the current url structure
* @private
*/
function getQueryStringParamDelimiter(url: string): string {
return url.indexOf('?') === -1 ? '?' : '&';
}
/**
* @param {string} url - url
* @param {string} productVersion - product version
* @return {string} - the url with the client tag appended in the query params
* @private
*/
function addClientTag(url: string, productVersion?: string): string {
if (url.indexOf(CLIENT_TAG) === -1) {
url += getQueryStringParamDelimiter(url) + CLIENT_TAG + (productVersion || __VERSION__);
}
return url;
}
/**
* @param {string} url - url
* @param {PKSourcesConfigObject} sources - sources
* @return {string} - the url with the seekFrom and clipTo appended in the query params
* @private
*/
function addStartAndEndTime(url: string, sources: PKSourcesConfigObject): string {
const seekFrom = Utils.Object.getPropertyPath(sources, 'seekFrom');
const clipTo = Utils.Object.getPropertyPath(sources, 'clipTo');
if (typeof seekFrom === 'number' && url.indexOf(SEEK_FROM) === -1) {
url += getQueryStringParamDelimiter(url) + SEEK_FROM + Math.floor(seekFrom * 1000);
}
if (typeof clipTo === 'number' && url.indexOf(CLIP_TO) === -1) {
url += getQueryStringParamDelimiter(url) + CLIP_TO + Math.floor(clipTo * 1000);
}
return url;
}
/**
* Adding Kaltura specific params to player config and player sources.
* @param {Player} player - player
* @param {PartialKPOptionsObject} playerConfig - player config
* @return {void}
* @private
*/
function addKalturaParams(player: KalturaPlayer, playerConfig: PartialKPOptionsObject): void {
handleSessionId(player, playerConfig);
const sources: PKSourcesConfigObject = playerConfig.sources!;
const sessionId = playerConfig.session && playerConfig.session.id;
const productVersion = getServerUIConf()?.productVersion;
Object.values(StreamType).forEach((key: PlayerStreamTypes) => {
if (sources[key]) {
sources[key].forEach((source) => {
if (
typeof source.url === 'string' &&
source.url.toLowerCase().indexOf(PLAY_MANIFEST) > -1 &&
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
!source.localSource
) {
source.url = updateSessionIdInUrl(player, source.url, sessionId);
source.url = addReferrer(source.url);
source.url = addClientTag(source.url, productVersion);
source.url = addStartAndEndTime(source.url, sources);
}
if (source['drmData'] && source['drmData'].length) {
source['drmData'].forEach((drmData) => {
if (typeof drmData.licenseUrl === 'string' && [UDRM_DOMAIN, CUSTOM_DATA, SIGNATURE].every((t) => drmData.licenseUrl.includes(t))) {
drmData.licenseUrl = updateSessionIdInUrl(player, drmData.licenseUrl, sessionId, DRM_SESSION_ID);
drmData.licenseUrl = addClientTag(drmData.licenseUrl, productVersion);
drmData.licenseUrl = addReferrer(drmData.licenseUrl);
drmData.licenseUrl = addUIConfId(drmData.licenseUrl, playerConfig);
}
});
}
});
}
});
}
export {
addKalturaParams,
handleSessionId,
updateSessionIdInUrl,
getReferrer,
addReferrer,
addClientTag,
addUIConfId,
getOriginalRequestReferrer,
addStartAndEndTime
};