From 694ef941bf88907ba96b6d3c73d0ff0c54c53358 Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Thu, 23 Oct 2025 16:41:39 +0300 Subject: [PATCH 1/8] feat: fetch video-specific config --- src/index.js | 10 +++++++-- src/player.js | 41 ++++++++++++++++++++--------------- test/unit/videoSource.test.js | 30 +++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/index.js b/src/index.js index 252c105e6..8d1378a13 100644 --- a/src/index.js +++ b/src/index.js @@ -14,13 +14,19 @@ const getConfig = (playerOptions = {}, cloudinaryConfig) => { }); }; -const getVideoPlayer = config => (id, playerOptions, ready) => - new VideoPlayer(id, getConfig(playerOptions, config), ready); +const getVideoPlayer = config => (id, playerOptions, ready) => { + const options = getConfig(playerOptions, config); + if (options.profile) { + return createPlayer(id, options, ready); + } + return new VideoPlayer(id, options, ready); +}; const getVideoPlayers = config => (selector, playerOptions, ready) => VideoPlayer.all(selector, getConfig(playerOptions, config), ready); const getPlayer = config => (id, playerOptions, ready) => createPlayer(id, getConfig(playerOptions, config), ready); + const getPlayers = config => (selector, playerOptions, ready) => { const nodeList = document.querySelectorAll(selector); const playerConfig = getConfig(playerOptions, config); diff --git a/src/player.js b/src/player.js index a8d018bb5..a05f759b8 100644 --- a/src/player.js +++ b/src/player.js @@ -3,6 +3,7 @@ import { defaultProfiles } from 'cloudinary-video-player-profiles'; import { isRawUrl, getCloudinaryUrlPrefix } from './plugins/cloudinary/common'; const isDefaultProfile = (profileName) => !!defaultProfiles.find(({ name }) => profileName === name); + const getDefaultProfileConfig = (profileName) => { const profile = defaultProfiles.find(({ name }) => profileName === name); @@ -13,38 +14,42 @@ const getDefaultProfileConfig = (profileName) => { return profile.config; }; -export const getProfile = async (profile, initOptions) => { - if (isDefaultProfile(profile)) { - return getDefaultProfileConfig(profile); +export const fetchConfig = async (initOptions) => { + const profileName = initOptions.profile; + + if (profileName && isDefaultProfile(profileName)) { + return getDefaultProfileConfig(profileName); } const urlPrefix = getCloudinaryUrlPrefix(initOptions.cloudinaryConfig); - const profileUrl = isRawUrl(profile) ? profile : `${urlPrefix}/_applet_/video_service/video_player_profiles/${profile.replaceAll(' ', '+')}.json`; + let profileUrl; + // if (!profileName && initOptions.publicId) { + // profileUrl = `${urlPrefix}/${initOptions.publicId}/config.json`; + // } else + if (isRawUrl(profileName)) { + profileUrl = profileName; + } else if (profileName) { + profileUrl = `${urlPrefix}/_applet_/video_service/video_player_profiles/${profileName.replaceAll(' ', '+')}.json`; + } else { + return {}; + } + return fetch(profileUrl, { method: 'GET' }).then(res => res.json()); }; const player = async (elem, initOptions, ready) => { - const { profile, ...otherInitOptions } = initOptions; try { - const profileOptions = profile ? await getProfile(profile, otherInitOptions) : {}; - const options = Object.assign({}, profileOptions.playerOptions, profileOptions.sourceOptions, otherInitOptions, { + const profileOptions = await fetchConfig(initOptions); + const options = Object.assign({}, profileOptions.playerOptions, profileOptions.sourceOptions, initOptions, { _internalAnalyticsMetadata: { newPlayerMethod: true, - profile: isDefaultProfile(profile) ? profile : !!profile, + profile: isDefaultProfile(initOptions.profile) ? initOptions.profile : !!initOptions.profile, }, }); - const videoPlayer = new VideoPlayer(elem, options, ready); - - const nativeVideoPlayerSourceMethod = videoPlayer.source; - videoPlayer.source = (id, options) => { - const extendedOptions = Object.assign({}, profileOptions.sourceOptions, options); - return nativeVideoPlayerSourceMethod.call(videoPlayer, id, extendedOptions); - }; - - return videoPlayer; + return new VideoPlayer(elem, options, ready); } catch (e) { - const videoPlayer = new VideoPlayer(elem, otherInitOptions); + const videoPlayer = new VideoPlayer(elem, initOptions); videoPlayer.videojs.error('Invalid profile'); throw e; } diff --git a/test/unit/videoSource.test.js b/test/unit/videoSource.test.js index a078aa3b7..bc8204e0f 100644 --- a/test/unit/videoSource.test.js +++ b/test/unit/videoSource.test.js @@ -1,7 +1,9 @@ import VideoSource from '../../src/plugins/cloudinary/models/video-source/video-source.js'; import { hasCodec } from '../../src/plugins/cloudinary/models/video-source/video-source.utils'; import { SOURCE_TYPE } from '../../src/utils/consts'; +import { extractOptions } from '../../src/video-player.utils'; import '../../src/'; + const cld = { cloud_name: 'demo' }; describe('video source tests', () => { @@ -558,3 +560,31 @@ describe('test hasCodec method', () => { }); }); }); + +describe('sourceOptions extraction and inheritance', () => { + it('should extract SOURCE_PARAMS into playerOptions.sourceOptions', () => { + let elem = document.createElement('video'); + let options = { + cloudName: 'demo', + transformation: { width: 640, crop: 'scale' }, + allowUsageReport: true + }; + let { playerOptions } = extractOptions(elem, options); + + expect(playerOptions.sourceOptions.transformation).toEqual({ width: 640, crop: 'scale' }); + expect(playerOptions.sourceOptions.allowUsageReport).toBe(true); + }); + + it('should separate SOURCE_PARAMS from PLAYER_PARAMS', () => { + let elem = document.createElement('video'); + let options = { + cloudName: 'demo', + transformation: { width: 640 }, + colors: { base: '#FF0000' } + }; + let { playerOptions } = extractOptions(elem, options); + + expect(playerOptions.sourceOptions.transformation).toEqual({ width: 640 }); + expect(playerOptions.colors).toEqual({ base: '#FF0000' }); + }); +}); From cdda3a242af772f6cdffb80d1c4f7dec10a2490a Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Sun, 26 Oct 2025 16:33:31 +0200 Subject: [PATCH 2/8] feat(VIDEO-20073): video-specific config --- docs/es-modules/profiles.html | 76 ++++++++++--- docs/profiles.html | 202 +++++++++++++++++++--------------- src/index.js | 38 +++++-- src/player.js | 46 ++++---- src/video-player.const.js | 1 + src/video-player.js | 11 +- src/video-player.utils.js | 19 ++-- 7 files changed, 239 insertions(+), 154 deletions(-) diff --git a/docs/es-modules/profiles.html b/docs/es-modules/profiles.html index a987d6a0e..b3b0dcbdc 100644 --- a/docs/es-modules/profiles.html +++ b/docs/es-modules/profiles.html @@ -19,7 +19,13 @@

Cloudinary Video Player

Profiles

-
Player with default profile
+

+ Player profiles provide a mechanism to define and save your video player configuration + to your Cloudinary account and then reference this profile as part of your video player setup. + For details, see the player profiles documentation. +

+ +

Default profile - applies predefined player configuration

-
Player with custom profile
+

Custom profile - loads player and source config from profile

-
Player with custom profile and overrides
+

Override player config - profile config overridden by JS player options

+ + +

Override source config - profile transformation overridden by JS source options

+ +

No profile - fetches asset-specific config from publicId/config.json

+