From 54cdfc279f75ebf367332232886fa5719c02b5a4 Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Sun, 2 Nov 2025 17:25:13 +0200 Subject: [PATCH 1/6] feat(VIDEO-20110): video-elements - add support for poster --- docs/es-modules/poster.html | 12 +++++++ docs/poster.html | 31 +++++++++++++++++++ src/plugins/cloudinary/index.js | 10 ++++-- .../models/video-source/video-source.js | 27 +++++++++++++--- 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/docs/es-modules/poster.html b/docs/es-modules/poster.html index ac4b6a3ce..fc2614038 100644 --- a/docs/es-modules/poster.html +++ b/docs/es-modules/poster.html @@ -53,6 +53,12 @@

Raw URL - default with no poster image

+
+

Applet poster (poster: true)

+
Uses applet service URL for poster
+ +
+

Full documentationRaw URL - default with no poster image cloudName: 'demo', publicId: 'https://res.cloudinary.com/demo/video/upload/sp_auto/sea_turtle.m3u8' }); + + const playerAppletPoster = videoPlayer('player-applet-poster', { + cloudName: 'demo', + publicId: 'snow_horses', + poster: true + }); diff --git a/docs/poster.html b/docs/poster.html index da11778d9..951cfcb59 100644 --- a/docs/poster.html +++ b/docs/poster.html @@ -56,6 +56,13 @@ publicId: 'https://res.cloudinary.com/demo/video/upload/sp_auto/sea_turtle.m3u8' }); + player5 = cloudinary.videoPlayer('player-applet-poster', { + cloud_name: 'demo', + publicId: 'snow_horses', + poster: true + // poster: 'https://images.unsplash.com/photo-1559551538-96c62c56b256?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&q=80&w=3540' + }); + }, false); @@ -113,6 +120,17 @@

Raw URL - default with no poster image

> +
+

Applet poster (poster: true)

+
Uses applet service URL for poster
+ +
+

Full documentation

@@ -151,6 +169,13 @@

Example Code:

class="cld-video-player cld-fluid" </video> + <video + id="player-applet-poster" + playsinline + controls + class="cld-video-player cld-fluid" + </video> + @@ -179,6 +204,12 @@

Example Code:

publicId: 'https://res.cloudinary.com/demo/video/upload/sp_auto/sea_turtle.m3u8' }); + player5 = cloudinary.videoPlayer('player-applet-poster', { + cloud_name: 'demo', + publicId: 'snow_horses', + poster: true + }); +
diff --git a/src/plugins/cloudinary/index.js b/src/plugins/cloudinary/index.js index e0c303a26..5ca000b63 100644 --- a/src/plugins/cloudinary/index.js +++ b/src/plugins/cloudinary/index.js @@ -122,8 +122,14 @@ class CloudinaryContext { options.cloudinaryConfig = extendCloudinaryConfig(this.cloudinaryConfig(), options.cloudinaryConfig || {}); options.transformation = mergeTransformations(this.transformation(), options.transformation || {}); options.sourceTransformation = options.sourceTransformation || this.sourceTransformation(); - options.sourceTypes = options.sourceTypes || this.sourceTypes(); - options.poster = options.poster || posterOptionsForCurrent(); + options.sourceTypes = options.sourceTypes || this.sourceTypes(); + + + const defaultPosterOptions = posterOptionsForCurrent(); + const userPosterOptions = options.posterOptions || {}; + options.poster = options.poster || defaultPosterOptions; + options.posterOptions = Object.assign({}, defaultPosterOptions, userPosterOptions); + options.queryParams = Object.assign(options.queryParams || {}, options.allowUsageReport ? { _s: `vp-${VERSION}` } : {}); if (options.sourceTypes.indexOf('audio') > -1) { diff --git a/src/plugins/cloudinary/models/video-source/video-source.js b/src/plugins/cloudinary/models/video-source/video-source.js index 08cbe7698..ee26da072 100644 --- a/src/plugins/cloudinary/models/video-source/video-source.js +++ b/src/plugins/cloudinary/models/video-source/video-source.js @@ -14,7 +14,9 @@ import { hasCodec, normalizeFormat } from './video-source.utils'; -import { normalizeOptions, isSrcEqual, isRawUrl, mergeTransformations } from '../../common'; +import { normalizeOptions, isSrcEqual, isRawUrl, mergeTransformations, getCloudinaryUrlPrefix } from '../../common'; +import { utf8ToBase64 } from 'utils/utf8Base64'; +import Transformation from '@cloudinary/url-gen/backwards/transformation'; import BaseSource from '../base-source'; import ImageSource from '../image-source'; @@ -127,9 +129,26 @@ class VideoSource extends BaseSource { } options.cloudinaryConfig = options.cloudinaryConfig || this.cloudinaryConfig(); - - options.resource_type = this.resourceType() || options.resource_type; - + + if (publicId === true) { + const urlPrefix = getCloudinaryUrlPrefix(options.cloudinaryConfig); + const deliveryType = this.getInitOptions().type || 'upload'; + const base64PublicId = utf8ToBase64(this.publicId()); + let appletUrl = `${urlPrefix}/_applet_/video_service/elements/${deliveryType}/${base64PublicId}/poster`; + + const transformation = this.getInitOptions().posterOptions?.transformation; + if (transformation) { + const transformationString = new Transformation(transformation).toString(); + appletUrl += `?${transformationString}`; + } + + this._poster = new ImageSource(appletUrl, { + cloudinaryConfig: options.cloudinaryConfig + }); + + return this; + } + this._poster = new ImageSource(publicId, options); return this; From d4cd0569397fb6c109c734b6a641224f2b524e4e Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Sun, 2 Nov 2025 17:32:06 +0200 Subject: [PATCH 2/6] chore: bundlewatch --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b68b1a9e..f5149b1c9 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "files": [ { "path": "./dist/cld-video-player.min.js", - "maxSize": "135kb" + "maxSize": "136kb" }, { "path": "./lib/cld-video-player.js", From d8a1d2469664db924d1f7806fbdec9c757163ad4 Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Sun, 2 Nov 2025 17:41:59 +0200 Subject: [PATCH 3/6] chore: fix options.resource_type --- src/plugins/cloudinary/models/video-source/video-source.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/cloudinary/models/video-source/video-source.js b/src/plugins/cloudinary/models/video-source/video-source.js index ee26da072..3e0982ef9 100644 --- a/src/plugins/cloudinary/models/video-source/video-source.js +++ b/src/plugins/cloudinary/models/video-source/video-source.js @@ -130,6 +130,8 @@ class VideoSource extends BaseSource { options.cloudinaryConfig = options.cloudinaryConfig || this.cloudinaryConfig(); + options.resource_type = this.resourceType() || options.resource_type; + if (publicId === true) { const urlPrefix = getCloudinaryUrlPrefix(options.cloudinaryConfig); const deliveryType = this.getInitOptions().type || 'upload'; From c8f67b70aee703e67a6ffa2ae060d108408d488d Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Tue, 4 Nov 2025 14:55:41 +0200 Subject: [PATCH 4/6] chore: tx query string --- src/plugins/cloudinary/models/video-source/video-source.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cloudinary/models/video-source/video-source.js b/src/plugins/cloudinary/models/video-source/video-source.js index 3e0982ef9..a4fab60ad 100644 --- a/src/plugins/cloudinary/models/video-source/video-source.js +++ b/src/plugins/cloudinary/models/video-source/video-source.js @@ -141,7 +141,7 @@ class VideoSource extends BaseSource { const transformation = this.getInitOptions().posterOptions?.transformation; if (transformation) { const transformationString = new Transformation(transformation).toString(); - appletUrl += `?${transformationString}`; + appletUrl += `?tx=${transformationString}`; } this._poster = new ImageSource(appletUrl, { From 2c01f8ef8fe57cdc0ef560f19575341216e8114f Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Wed, 26 Nov 2025 11:35:25 +0200 Subject: [PATCH 5/6] chore: e2e example page --- docs/poster.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/poster.html b/docs/poster.html index 951cfcb59..63cd55332 100644 --- a/docs/poster.html +++ b/docs/poster.html @@ -57,10 +57,9 @@ }); player5 = cloudinary.videoPlayer('player-applet-poster', { - cloud_name: 'demo', - publicId: 'snow_horses', + cloud_name: 'dux0ev1nu', + publicId: 'applets_demo', poster: true - // poster: 'https://images.unsplash.com/photo-1559551538-96c62c56b256?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&q=80&w=3540' }); }, false); From 8603e131646cfc99da1c1ca33a1aec098cf75320 Mon Sep 17 00:00:00 2001 From: Tsachi Shlidor Date: Wed, 26 Nov 2025 11:57:17 +0200 Subject: [PATCH 6/6] chore: poster analytics and E2e --- docs/poster.html | 4 ++-- src/utils/get-analytics-player-options.js | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/poster.html b/docs/poster.html index 63cd55332..6ed9ded6c 100644 --- a/docs/poster.html +++ b/docs/poster.html @@ -57,8 +57,8 @@ }); player5 = cloudinary.videoPlayer('player-applet-poster', { - cloud_name: 'dux0ev1nu', - publicId: 'applets_demo', + cloud_name: 'demo', + publicId: 'snow_horses', poster: true }); diff --git a/src/utils/get-analytics-player-options.js b/src/utils/get-analytics-player-options.js index 1b59d01f6..6b7e04178 100644 --- a/src/utils/get-analytics-player-options.js +++ b/src/utils/get-analytics-player-options.js @@ -12,6 +12,11 @@ const filterDefaultsAndNulls = (obj) => Object.entries(obj).reduce((filtered, [k }, {}); const getSourceOptions = (sourceOptions = {}) => ({ + poster: (() => { + if (sourceOptions.poster === true) return 'auto'; + if (typeof sourceOptions.poster === 'string') return 'url'; + return undefined; + })(), posterOptions: hasConfig(sourceOptions.posterOptions), posterOptionsPublicId: sourceOptions.posterOptions && hasConfig(sourceOptions.posterOptions.publicId), autoShowRecommendations: sourceOptions.autoShowRecommendations,