From f994ae1533bf9fcf95b9c7f3b90872e99f725cf2 Mon Sep 17 00:00:00 2001 From: Pedram Valiani Date: Fri, 28 Aug 2026 15:08:24 +0100 Subject: [PATCH] Use promo image for in-situ video playback --- .../Curation/HierarchicalGrid/index.test.tsx | 1 + .../Curation/HierarchicalGrid/index.tsx | 1 + .../MediaLoader/configs/aresMedia.ts | 23 +++++++++++-------- src/app/components/MediaLoader/index.test.tsx | 19 +++++++++++++++ src/app/components/MediaLoader/index.tsx | 3 +++ src/app/components/MediaLoader/types.ts | 2 ++ .../utils/buildSettings.client.test.ts | 18 +++++++++++++++ .../MediaLoader/utils/buildSettings.ts | 2 ++ 8 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/app/components/Curation/HierarchicalGrid/index.test.tsx b/src/app/components/Curation/HierarchicalGrid/index.test.tsx index 94690c2d736..9968d4d1f76 100644 --- a/src/app/components/Curation/HierarchicalGrid/index.test.tsx +++ b/src/app/components/Curation/HierarchicalGrid/index.test.tsx @@ -246,6 +246,7 @@ describe('Hierarchical Grid Curation', () => { blocks: aresMediaBlocks, uniqueId: `in-situ-${inSituPromo.id}`, loadPlayerOnInitialRender: true, + holdingImageURL: inSituPromo.imageUrl, }), undefined, ); diff --git a/src/app/components/Curation/HierarchicalGrid/index.tsx b/src/app/components/Curation/HierarchicalGrid/index.tsx index 9f9bbdcc6e5..8ec46e6b66e 100644 --- a/src/app/components/Curation/HierarchicalGrid/index.tsx +++ b/src/app/components/Curation/HierarchicalGrid/index.tsx @@ -205,6 +205,7 @@ const HiearchicalGrid = ({ blocks={inSituMediaBlocks} uniqueId={`in-situ-${promo.id || i}`} loadPlayerOnInitialRender + holdingImageURL={promo.imageUrl} />
{promoText}
diff --git a/src/app/components/MediaLoader/configs/aresMedia.ts b/src/app/components/MediaLoader/configs/aresMedia.ts index ca987c1e669..817ff21a427 100644 --- a/src/app/components/MediaLoader/configs/aresMedia.ts +++ b/src/app/components/MediaLoader/configs/aresMedia.ts @@ -29,6 +29,7 @@ export default ({ showAdsBasedOnLocation = false, embedded, lang, + holdingImageURL: holdingImageURLOverride, }: ConfigBuilderProps): ConfigBuilderReturnProps => { const { model: aresMedia }: AresMediaBlock = filterForBlockType(blocks, 'aresMedia') ?? {}; @@ -87,13 +88,15 @@ export default ({ // Referred to as 'clip PID', 'episode PID' or 'parent PID' const parentPID = aresMediaMetadata?.id; - const holdingImageURL = rawImage - ? buildIChefURL({ - originCode, - locator, - resolution: DEFAULT_WIDTH, - }) - : aresMediaMetadata?.imageUrl; + const holdingImageURL = + holdingImageURLOverride?.replace('{width}', String(DEFAULT_WIDTH)) || + (rawImage + ? buildIChefURL({ + originCode, + locator, + resolution: DEFAULT_WIDTH, + }) + : aresMediaMetadata?.imageUrl); const isLive = aresMediaMetadata?.live ?? false; @@ -116,8 +119,10 @@ export default ({ guidanceMessage, holdingImageURL, translations, - placeholderImageOriginCode: originCode, - placeholderImageLocator: locator, + placeholderImageOriginCode: holdingImageURLOverride + ? undefined + : originCode, + placeholderImageLocator: holdingImageURLOverride ? undefined : locator, }); const ampIframeUrl = getAmpIframeUrl({ id, parentPID, versionPID, lang }); diff --git a/src/app/components/MediaLoader/index.test.tsx b/src/app/components/MediaLoader/index.test.tsx index 44248660e4a..ca70bee5726 100644 --- a/src/app/components/MediaLoader/index.test.tsx +++ b/src/app/components/MediaLoader/index.test.tsx @@ -385,6 +385,25 @@ describe('MediaLoader', () => { ); }, ); + + it('passes a supplied holding image to the player configuration', async () => { + const buildConfigSpy = jest.spyOn(buildConfig, 'default'); + const holdingImageURL = + 'https://ichef.bbci.co.uk/ace/ws/{width}/cpsprodpb/promo-image.jpg.webp'; + + await act(async () => { + render( + , + ); + }); + + expect(buildConfigSpy).toHaveBeenCalledWith( + expect.objectContaining({ holdingImageURL }), + ); + }); }); describe('AMP', () => { diff --git a/src/app/components/MediaLoader/index.tsx b/src/app/components/MediaLoader/index.tsx index c4e73ac8897..074401dd228 100644 --- a/src/app/components/MediaLoader/index.tsx +++ b/src/app/components/MediaLoader/index.tsx @@ -218,6 +218,7 @@ type Props = { uniqueId?: string; eventMapping?: EventMapping; loadPlayerOnInitialRender?: boolean; + holdingImageURL?: string; }; const MediaLoader = ({ @@ -227,6 +228,7 @@ const MediaLoader = ({ uniqueId, eventMapping, loadPlayerOnInitialRender = false, + holdingImageURL, }: Props) => { const { lang, service, translations, defaultImage } = use(ServiceContext); const { pageIdentifier } = use(EventTrackingContext); @@ -268,6 +270,7 @@ const MediaLoader = ({ showAdsBasedOnLocation, embedded, defaultImage, + holdingImageURL, }); if (!config) return null; diff --git a/src/app/components/MediaLoader/types.ts b/src/app/components/MediaLoader/types.ts index 5bc45b5df8a..e7476d80396 100644 --- a/src/app/components/MediaLoader/types.ts +++ b/src/app/components/MediaLoader/types.ts @@ -124,6 +124,7 @@ export type ConfigBuilderProps = { embedded?: boolean; lang: string; defaultImage: string; + holdingImageURL?: string; }; export type Orientations = 'landscape' | 'portrait'; @@ -382,4 +383,5 @@ export type BuildConfigProps = { showAdsBasedOnLocation?: boolean; embedded?: boolean; defaultImage: string; + holdingImageURL?: string; }; diff --git a/src/app/components/MediaLoader/utils/buildSettings.client.test.ts b/src/app/components/MediaLoader/utils/buildSettings.client.test.ts index 32d1e33ccb5..778d57bd770 100644 --- a/src/app/components/MediaLoader/utils/buildSettings.client.test.ts +++ b/src/app/components/MediaLoader/utils/buildSettings.client.test.ts @@ -412,6 +412,24 @@ describe('buildSettings', () => { }); describe('AresMedia', () => { + it('uses a supplied holding image instead of the Ares media image', () => { + const holdingImageURL = + 'https://ichef.bbci.co.uk/ace/ws/{width}/cpsprodpb/promo-image.jpg.webp'; + const result = buildSettings({ + ...baseSettings, + blocks: aresMediaBlocks as MediaBlock[], + holdingImageURL, + }); + + expect(result?.playerConfig.playlistObject?.holdingImageURL).toBe( + holdingImageURL.replace('{width}', '512'), + ); + expect(result?.placeholderConfig).toMatchObject({ + placeholderSrc: holdingImageURL.replace('{width}', '512'), + placeholderSrcset: '', + }); + }); + it('Should process an AresMedia block into a valid playlist item for an "article" page.', () => { const result = buildSettings({ ...baseSettings, diff --git a/src/app/components/MediaLoader/utils/buildSettings.ts b/src/app/components/MediaLoader/utils/buildSettings.ts index b00f5475b57..f83e42ce6f9 100644 --- a/src/app/components/MediaLoader/utils/buildSettings.ts +++ b/src/app/components/MediaLoader/utils/buildSettings.ts @@ -40,6 +40,7 @@ const buildSettings = ({ showAdsBasedOnLocation = false, embedded, defaultImage, + holdingImageURL, }: BuildConfigProps) => { const { model: mediaOverrides } = filterForBlockType(blocks, 'mediaOverrides') || {}; @@ -86,6 +87,7 @@ const buildSettings = ({ embedded, lang, defaultImage, + holdingImageURL, }); if (!config) return null;