diff --git a/.github/workflows/e2e_pr.yml b/.github/workflows/e2e_pr.yml
index 0ad95782..21fe50ce 100644
--- a/.github/workflows/e2e_pr.yml
+++ b/.github/workflows/e2e_pr.yml
@@ -26,8 +26,17 @@ jobs:
- name: NPM Install
run: npm install
+ - name: Extract PR Number
+ id: extract_pr_number
+ run: echo "PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
+
+ - name: Set Deploy Preview URL
+ run: echo "PREVIEW_URL=https://deploy-preview-${{ env.PR_NUMBER }}--cld-vp-esm-pages.netlify.app" >> $GITHUB_ENV
+
- name: E2E tests
run: npm run test:e2e
+ env:
+ PREVIEW_URL: ${{ env.PREVIEW_URL }}
- name: Upload report to artifact
uses: actions/upload-artifact@v4
diff --git a/CHANGELOG-edge.md b/CHANGELOG-edge.md
index c29a7a40..1dab850f 100644
--- a/CHANGELOG-edge.md
+++ b/CHANGELOG-edge.md
@@ -1,5 +1,31 @@
# Changelog
+## [2.1.1-edge.2](https://github.com/cloudinary/cloudinary-video-player/compare/v2.1.1-edge.1...v2.1.1-edge.2) (2024-10-27)
+
+
+### Bug Fixes
+
+* use cld player profiles package for default profiles ([#701](https://github.com/cloudinary/cloudinary-video-player/issues/701)) ([1083b94](https://github.com/cloudinary/cloudinary-video-player/commit/1083b94ac96f4e075d8d820a894703eb644bec7a))
+
+## [2.1.1-edge.1](https://github.com/cloudinary/cloudinary-video-player/compare/v2.1.1-edge.0...v2.1.1-edge.1) (2024-10-18)
+
+
+### Features
+
+* add internal analytics about new method & profiles ([#699](https://github.com/cloudinary/cloudinary-video-player/issues/699)) ([a1c8c1e](https://github.com/cloudinary/cloudinary-video-player/commit/a1c8c1eb4ffd8362ce4cc7ab5ed47276cc5651ee))
+
+## [2.1.1-edge.0](https://github.com/cloudinary/cloudinary-video-player/compare/v2.0.6-edge.0...v2.1.1-edge.0) (2024-10-07)
+
+
+### Features
+
+* add url template for video player profiles ([#696](https://github.com/cloudinary/cloudinary-video-player/issues/696)) ([d60cb4f](https://github.com/cloudinary/cloudinary-video-player/commit/d60cb4f4fc9d8b0ff2a6f0e21621c6c84063c898))
+
+
+### Bug Fixes
+
+* default secure option for new method ([#698](https://github.com/cloudinary/cloudinary-video-player/issues/698)) ([0d95b76](https://github.com/cloudinary/cloudinary-video-player/commit/0d95b76381b2130a01755feab87bb2766ead9d59))
+
## [2.0.6-edge.0](https://github.com/cloudinary/cloudinary-video-player/compare/v2.0.5-edge.2...v2.0.6-edge.0) (2024-08-08)
diff --git a/docs/es-modules/profiles.html b/docs/es-modules/profiles.html
index f2481395..9cebf908 100644
--- a/docs/es-modules/profiles.html
+++ b/docs/es-modules/profiles.html
@@ -30,9 +30,31 @@
Player with default profile
muted
>
+ Player with custom profile
+
+
+ Player with custom profile and overrides
+
+
Full documentationFull documentation
@@ -44,11 +66,34 @@ Player with default profile
(async () => {
const playerWithDefaultProfile = await player('player-default-profile', {
cloudName: 'demo',
- profile: 'cldDefault'
+ profile: 'cld-default'
});
playerWithDefaultProfile.source('sea_turtle');
})();
+
+ (async () => {
+ const playerWithCustomProfile = await player('player-custom-profile', {
+ cloudName: 'prod',
+ profile: 'myCustomProfile'
+ });
+
+ playerWithCustomProfile.source('samples/cld-sample-video');
+ })();
+
+ (async () => {
+ const playerWithCustomProfileAndOverrides = await cloudinary.player('player-custom-profile-overrides', {
+ cloudName: 'prod',
+ profile: 'myCustomProfile',
+ colors: {
+ base: "#1532a8"
+ },
+ seekThumbnails: false,
+ aiHighlightsGraph: true,
+ });
+
+ playerWithCustomProfileAndOverrides.source('samples/cld-sample-video');
+ })();
diff --git a/docs/es-modules/raw-url.html b/docs/es-modules/raw-url.html
index 915a9ddb..617fe7e2 100644
--- a/docs/es-modules/raw-url.html
+++ b/docs/es-modules/raw-url.html
@@ -63,7 +63,7 @@ Video with raw URL - ABR
const player = videoPlayer('player', config);
- player.source('https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_10mb.mp4');
+ player.source('https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
const abrPlayer = videoPlayer('abrPlayer', config);
diff --git a/docs/profiles.html b/docs/profiles.html
index 00b09f7c..e2b2b88a 100644
--- a/docs/profiles.html
+++ b/docs/profiles.html
@@ -26,11 +26,34 @@
window.addEventListener('load', async () => {
const playerWithDefaultProfile = await cloudinary.player('player-default-profile', {
cloudName: 'demo',
- profile: 'cldDefault',
+ profile: 'cld-default',
});
playerWithDefaultProfile.source('sea_turtle');
}, false);
+
+ window.addEventListener('load', async function() {
+ const playerWithCustomProfile = await cloudinary.player('player-custom-profile', {
+ cloudName: 'prod',
+ profile: 'myCustomProfile',
+ });
+
+ playerWithCustomProfile.source('samples/cld-sample-video');
+ }, false);
+
+ window.addEventListener('load', async function() {
+ const playerWithCustomProfileAndOverrides = await cloudinary.player('player-custom-profile-overrides', {
+ cloudName: 'prod',
+ profile: 'myCustomProfile',
+ colors: {
+ base: "#1532a8"
+ },
+ seekThumbnails: false,
+ aiHighlightsGraph: true,
+ });
+
+ playerWithCustomProfileAndOverrides.source('samples/cld-sample-video');
+ }, false);
@@ -71,13 +94,94 @@ Example Code:
window.addEventListener('load', async function() {
const playerWithDefaultProfile = await cloudinary.player('player-default-profile', {
cloudName: 'demo',
- profile: 'cldDefault',
+ profile: 'cld-default',
});
playerWithDefaultProfile.source('sea_turtle');
}, false);
+
+ Player with custom profile
+
+
+ Example Code:
+
+
+
+
+ <video
+ id="player-custom-profile"
+ controls
+ autoplay
+ muted
+ class="cld-video-player"
+ width="500">
+ </video>
+
+
+
+ window.addEventListener('load', async function() {
+ const playerWithCustomProfile = await cloudinary.player('player-custom-profile', {
+ cloudName: 'prod',
+ profile: 'myCustomProfile',
+ });
+
+ playerWithCustomProfile.source('samples/cld-sample-video');
+ }, false);
+
+
+
+ Player with custom profile and overrides
+
+
+ Example Code:
+
+
+
+
+ <video
+ id="player-custom-profile-overrides"
+ controls
+ autoplay
+ muted
+ class="cld-video-player"
+ width="500">
+ </video>
+
+
+
+ window.addEventListener('load', async function() {
+ const playerWithCustomProfileAndOverrides = await cloudinary.player('player-custom-profile-overrides', {
+ cloudName: 'prod',
+ profile: 'myCustomProfile',
+ colors: {
+ base: "#1532a8"
+ },
+ seekThumbnails: false,
+ aiHighlightsGraph: true,
+ });
+
+ playerWithCustomProfileAndOverrides.source('samples/cld-sample-video');
+ }, false);
+
+
diff --git a/docs/raw-url.html b/docs/raw-url.html
index 43dcaa5d..dcc5cd5c 100644
--- a/docs/raw-url.html
+++ b/docs/raw-url.html
@@ -35,7 +35,7 @@
player = cloudinary.videoPlayer('player', config);
- player.source('https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_10mb.mp4');
+ player.source('https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
adpPlayer = cloudinary.videoPlayer('adpPlayer',config);
@@ -106,7 +106,7 @@ Example Code:
player = cloudinary.videoPlayer('player', config);
- player.source('https://res.cloudinary.com/demo/video/upload/sea_turtle.mp4');
+ player.source('https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
adpPlayer = cloudinary.videoPlayer('adpPlayer',config);
diff --git a/package-lock.json b/package-lock.json
index 257234a5..e26978cf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"@cloudinary/url-gen": "^1.20.0",
"cloudinary-video-analytics": "1.7.1",
+ "cloudinary-video-player-profiles": "1.1.0",
"lodash": "^4.17.21",
"uuid": "^10.0.0",
"video.js": "^8.17.1",
@@ -6538,6 +6539,11 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/cloudinary-video-player-profiles": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/cloudinary-video-player-profiles/-/cloudinary-video-player-profiles-1.1.0.tgz",
+ "integrity": "sha512-vBpoDmDEq6+iViASIrsbRPNhiykwnnbfW4kdiYyrbdU6FFzogTun+6jmlbw/FR6XG2FEn4s69OOFRlu/qsl01Q=="
+ },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
diff --git a/package.json b/package.json
index 1db08edc..51766b2b 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,7 @@
},
{
"path": "./dist/cld-video-player.light.min.js",
- "maxSize": "130kb"
+ "maxSize": "131kb"
},
{
"path": "./lib/cld-video-player.js",
@@ -80,6 +80,7 @@
"dependencies": {
"@cloudinary/url-gen": "^1.20.0",
"cloudinary-video-analytics": "1.7.1",
+ "cloudinary-video-player-profiles": "1.1.0",
"lodash": "^4.17.21",
"uuid": "^10.0.0",
"video.js": "^8.17.1",
diff --git a/src/config/profiles/cldAdaptiveStream.json b/src/config/profiles/cldAdaptiveStream.json
deleted file mode 100644
index 3f20af1c..00000000
--- a/src/config/profiles/cldAdaptiveStream.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "playerOptions": {
- "fluid": true,
- "controls": true,
- "controlBar": {
- "fullscreenToggle": false
- },
- "showJumpControls": true,
- "hideContextMenu": false,
- "floatingWhenNotVisible": "none"
- },
- "sourceOptions": {
- "chapters": true,
- "sourceTypes": ["hls"],
- "transformation": [
- {
- "effect": ["volume:auto"]
- }
- ]
- }
-}
diff --git a/src/config/profiles/cldDefault.json b/src/config/profiles/cldDefault.json
deleted file mode 100644
index c8c24b97..00000000
--- a/src/config/profiles/cldDefault.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "playerOptions": {},
- "sourceOptions": {}
-}
diff --git a/src/config/profiles/cldLooping.json b/src/config/profiles/cldLooping.json
deleted file mode 100644
index ab33fe5c..00000000
--- a/src/config/profiles/cldLooping.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "playerOptions": {
- "fluid": true,
- "controls": false,
- "muted": true,
- "floatingWhenNotVisible": "none",
- "hideContextMenu": false,
- "autoplay": true,
- "loop": true
- },
- "sourceOptions": {}
-}
diff --git a/src/config/profiles/index.js b/src/config/profiles/index.js
deleted file mode 100644
index 32df3c8e..00000000
--- a/src/config/profiles/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import cldDefault from './cldDefault.json';
-import cldLooping from './cldLooping.json';
-import cldAdaptiveStream from './cldAdaptiveStream.json';
-
-export const defaultProfiles = {
- cldDefault,
- cldLooping,
- cldAdaptiveStream
-};
diff --git a/src/index.es.js b/src/index.es.js
index da6e2826..f19be260 100644
--- a/src/index.es.js
+++ b/src/index.es.js
@@ -13,7 +13,6 @@ import cloudinary from './index.js';
export const videoPlayer = cloudinary.videoPlayer;
export const videoPlayers = cloudinary.videoPlayers;
-export const videoPlayerWithProfile = cloudinary.videoPlayerWithProfile;
export const player = cloudinary.player;
diff --git a/src/index.js b/src/index.js
index 9a0cf729..252c105e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -29,10 +29,6 @@ const getPlayers = config => (selector, playerOptions, ready) => {
export const videoPlayer = getVideoPlayer();
export const videoPlayers = getVideoPlayers();
-export const videoPlayerWithProfile = (id, playerOptions, ready) => {
- console.warn('videoPlayerWithProfile method is DEPRECATED and will be removed soon, please use new `player` method instead');
- return getPlayer()(id, playerOptions, ready);
-};
export const player = getPlayer();
export const players = getPlayers();
@@ -51,7 +47,6 @@ const cloudinary = {
...(window.cloudinary || {}),
videoPlayer,
videoPlayers,
- videoPlayerWithProfile,
player,
players,
Cloudinary: {
diff --git a/src/index.videoPlayerWithProfile.js b/src/index.videoPlayerWithProfile.js
deleted file mode 100644
index e739ba95..00000000
--- a/src/index.videoPlayerWithProfile.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// This file is bundled as `videoPlayerWithProfile.js` to be imported as a tree-shaken module.
-
-// Usage:
-// import videoPlayerWithProfile from 'cloudinary-video-player/videoPlayerWithProfile';
-
-export { videoPlayerWithProfile as default } from './index.js';
diff --git a/src/player.js b/src/player.js
index 0c6250bb..04d9b6da 100644
--- a/src/player.js
+++ b/src/player.js
@@ -1,24 +1,49 @@
import VideoPlayer from './video-player';
-import { defaultProfiles } from './config/profiles';
+import { defaultProfiles } from 'cloudinary-video-player-profiles';
import { isRawUrl } from './plugins/cloudinary/common';
+import { unsigned_url_prefix } from '@cloudinary/url-gen/backwards/utils/unsigned_url_prefix';
-export const getProfile = async (cloudName, profile) => {
- if (Object.keys(defaultProfiles).includes(profile)) {
- return defaultProfiles[profile];
+const isDefaultProfile = (profileName) => !!defaultProfiles.find(({ name }) => profileName === name);
+const getDefaultProfileConfig = (profileName) => {
+ const profile = defaultProfiles.find(({ name }) => profileName === name);
+
+ if (!profile) {
+ throw new Error(`Default profile with name ${profileName} does not exist`);
}
- if (isRawUrl(profile)) {
- return await fetch(profile, { method: 'GET' }).then(res => res.json());
+ return profile.config;
+};
+
+export const getProfile = async (profile, initOptions) => {
+ if (isDefaultProfile(profile)) {
+ return getDefaultProfileConfig(profile);
}
- throw new Error('Custom profiles will be supported soon, please use one of default profiles: "cldDefault", "cldLooping" or "cldAdaptiveStream"');
+ const urlPrefix = unsigned_url_prefix(
+ null,
+ initOptions.cloudName ?? initOptions.cloud_name,
+ initOptions.private_cdn,
+ initOptions.cdn_subdomain,
+ initOptions.secure_cdn_subdomain,
+ initOptions.cname,
+ initOptions.secure ?? true,
+ initOptions.secure_distribution,
+ );
+
+ const profileUrl = isRawUrl(profile) ? profile : `${urlPrefix}/_applet_/video_service/video_player_profiles/${profile.replaceAll(' ', '+')}.json`;
+ 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(otherInitOptions.cloud_name, profile) : {};
- const options = Object.assign({}, profileOptions.playerOptions, otherInitOptions);
+ const profileOptions = profile ? await getProfile(profile, otherInitOptions) : {};
+ const options = Object.assign({}, profileOptions.playerOptions, otherInitOptions, {
+ _internalAnalyticsMetadata: {
+ newPlayerMethod: true,
+ profile: isDefaultProfile(profile) ? profile : !!profile,
+ },
+ });
const videoPlayer = new VideoPlayer(elem, options, ready);
const nativeVideoPlayerSourceMethod = videoPlayer.source;
diff --git a/src/video-player.const.js b/src/video-player.const.js
index afad6d0d..c35c3292 100644
--- a/src/video-player.const.js
+++ b/src/video-player.const.js
@@ -12,6 +12,7 @@ export const CLOUDINARY_PARAMS = [
];
export const PLAYER_PARAMS = CLOUDINARY_PARAMS.concat([
+ '_internalAnalyticsMetadata',
'debug',
'publicId',
'source',
diff --git a/src/video-player.js b/src/video-player.js
index f3db2d7a..c1597415 100644
--- a/src/video-player.js
+++ b/src/video-player.js
@@ -112,6 +112,7 @@ class VideoPlayer extends Utils.mixin(Eventable) {
return;
}
try {
+ const internalAnalyticsMetadata = options._internalAnalyticsMetadata ?? {};
const analyticsData = getAnalyticsFromPlayerOptions(options);
const analyticsParams = new URLSearchParams(analyticsData).toString();
const baseParams = new URLSearchParams({
@@ -120,7 +121,8 @@ class VideoPlayer extends Utils.mixin(Eventable) {
// #if (process.env.WEBPACK_BUILD_LIGHT)
vpLightBuild: true,
// #endif
- cloudName: options.cloudinary.cloudinaryConfig.cloud_name
+ cloudName: options.cloudinary.cloudinaryConfig.cloud_name,
+ ...internalAnalyticsMetadata,
}).toString();
fetch(`${INTERNAL_ANALYTICS_URL}/video_player_source?${analyticsParams}&${baseParams}`);
} catch (e) {
diff --git a/test/e2e/playwright.config.ts b/test/e2e/playwright.config.ts
index c5a555fe..cbb78353 100644
--- a/test/e2e/playwright.config.ts
+++ b/test/e2e/playwright.config.ts
@@ -6,7 +6,7 @@ import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testMatch: /test\/e2e\/specs\/.*(\.spec.ts)/,
- timeout: 45000,
+ timeout: 150000,
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
diff --git a/test/e2e/specs/linksConsoleErrorsEsmPage.spec.ts b/test/e2e/specs/linksConsoleErrorsEsmPage.spec.ts
index d1c7a36c..5652d157 100644
--- a/test/e2e/specs/linksConsoleErrorsEsmPage.spec.ts
+++ b/test/e2e/specs/linksConsoleErrorsEsmPage.spec.ts
@@ -1,19 +1,26 @@
-import { ConsoleMessage, expect } from '@playwright/test';
+import { ConsoleMessage, expect, Page } from '@playwright/test';
import { vpTest } from '../fixtures/vpTest';
import { ESM_LINKS } from '../testData/esmPageLinksData';
import { waitForPageToLoadWithTimeout } from '../src/helpers/waitForPageToLoadWithTimeout';
import { validatePageErrors } from '../src/helpers/validatePageErrors';
+import { ExampleLinkType } from '../types/exampleLinkType';
+
+const EDGE_ESM_URL = 'https://cld-vp-esm-pages.netlify.app/';
+// On PR level it will use the preview deploy URL and locally it will use the latest EDGE.
+const ESM_URL = process.env.PREVIEW_URL ?? EDGE_ESM_URL;
+// Flag to indicate if the deploy preview URL is ready
+let isPreviewUrlLoaded = false;
-const ESM_URL = 'https://cld-vp-esm-pages.netlify.app/';
/**
* Console error test generated by LINKS object array data.
*/
for (const link of ESM_LINKS) {
vpTest(`Test console errors on link ${link.name}`, async ({ page, consoleErrors, vpExamples }) => {
vpTest.skip(link.name === 'Adaptive Streaming', 'Flaky on CI');
- /**
- * Navigate to ESM Imports examples page
- */
+ //Wait for deploy URL to be available if PREVIEW_URL is set, and it is not available yet
+ if (process.env.PREVIEW_URL && !isPreviewUrlLoaded) {
+ await waitForDeployPreviewUrl(link, page);
+ }
await page.goto(ESM_URL);
await vpExamples.clickLinkByName(link.name);
await waitForPageToLoadWithTimeout(page, 5000);
@@ -44,9 +51,21 @@ function handleCommonEsmBrowsersErrors(linkName: string, consoleErrors: ConsoleM
);
break;
case 'VAST & VPAID Support':
- validatePageErrors(consoleErrors, [], ["Blocked script execution in 'about:blank' because the document's frame is sandboxed and the 'allow-scripts' permission is not set"]);
+ validatePageErrors(consoleErrors, [], ["Blocked script execution in 'about:blank' because the document's frame is sandboxed and the 'allow-scripts' permission is not set", 'the server responded with a status of 404']);
break;
default:
- expect(consoleErrors, `The following unexpected console errors were found: ${JSON.stringify(consoleErrors)}`).toHaveLength(0);
+ validatePageErrors(consoleErrors, [], ['the server responded with a status of 404']);
}
}
+
+/**
+ * Waits for a deploy preview URL to become available by making repeated requests and check that link is visible.
+ */
+async function waitForDeployPreviewUrl(link: ExampleLinkType, page: Page): Promise {
+ await expect(async () => {
+ await page.goto(process.env.PREVIEW_URL);
+ const linkLocator = page.getByRole('link', { name: link.name, exact: true });
+ await expect(linkLocator).toBeVisible({ timeout: 10000 });
+ isPreviewUrlLoaded = true;
+ }).toPass({ intervals: [1_000], timeout: 120000 });
+}
diff --git a/webpack/es6.config.js b/webpack/es6.config.js
index 1e82ee76..d6194f66 100644
--- a/webpack/es6.config.js
+++ b/webpack/es6.config.js
@@ -1,7 +1,6 @@
const { merge } = require('webpack-merge');
const webpackCommon = require('./common.config');
const path = require('path');
-const CopyWebpackPlugin = require('copy-webpack-plugin');
delete webpackCommon.output; // overwrite
@@ -13,7 +12,6 @@ module.exports = merge(webpackCommon, {
entry: {
'cld-video-player': './index.es.js', // default
'videoPlayer': './index.videoPlayer.js',
- 'videoPlayerWithProfile': './index.videoPlayerWithProfile.js',
'player': './index.player.js',
'all': './index.all.js'
},
@@ -29,15 +27,6 @@ module.exports = merge(webpackCommon, {
chunkLoadingGlobal: 'cloudinaryVideoPlayerChunkLoading'
},
- plugins: [
- new CopyWebpackPlugin({
- patterns: [{
- from: path.resolve(__dirname, '../src/config/profiles'),
- to: `${outputPath}/profiles`
- }]
- })
- ],
-
experiments: {
outputModule: true
}