From 93aa63cecf7538fbcb1bf7bb45c83a53ff0158a9 Mon Sep 17 00:00:00 2001 From: Dominik Lander Date: Wed, 26 Nov 2025 17:47:27 +0000 Subject: [PATCH 1/4] Make video crossOrigin undefined if no subtitles --- dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx index 0ed3bea3a29..56277647292 100644 --- a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx @@ -194,7 +194,7 @@ export const SelfHostedVideoPlayer = forwardRef( videoStyles(width, height), showSubtitles && subtitleStyles(subtitleSize), ]} - crossOrigin="anonymous" + crossOrigin={showSubtitles ? 'anonymous' : undefined} ref={ref} tabIndex={0} data-testid="self-hosted-video-player" From f5b54147f1a44426b6249699ed5f4e6e26d5c806 Mon Sep 17 00:00:00 2001 From: Dominik Lander Date: Mon, 1 Dec 2025 10:28:42 +0000 Subject: [PATCH 2/4] Always send CORS header on video requests in prod --- .../src/components/SelfHostedVideoPlayer.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx index 56277647292..868c219769f 100644 --- a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx @@ -131,12 +131,10 @@ type Props = { /** * Note that in React 19, forwardRef is no longer necessary: * https://react.dev/reference/react/forwardRef - */ -/** + * * NB: To develop the video player locally, use `https://r.thegulocal.com/` instead of `localhost`. * This is required because CORS restrictions prevent accessing the subtitles and video file from localhost. */ - export const SelfHostedVideoPlayer = forwardRef( ( { @@ -185,6 +183,16 @@ export const SelfHostedVideoPlayer = forwardRef( showPlayIcon ? 'play' : 'pause' }-${atomId}`; + /** + * We need CORS enabled to show subtitles on a video as it allows access to the VTT file. + * + * We don't want a client to not request CORS headers on a video request, then to request + * the same video with CORS headers, as the response could be cached without the headers, which + * will result in the video failing to load. Therefore, we always request CORS headers in production. + */ + const requestCORS = + showSubtitles || process.env.NODE_ENV === 'production'; + return ( <> {/* eslint-disable-next-line jsx-a11y/media-has-caption -- Not all videos require captions. */} @@ -194,7 +202,7 @@ export const SelfHostedVideoPlayer = forwardRef( videoStyles(width, height), showSubtitles && subtitleStyles(subtitleSize), ]} - crossOrigin={showSubtitles ? 'anonymous' : undefined} + crossOrigin={requestCORS ? 'anonymous' : undefined} ref={ref} tabIndex={0} data-testid="self-hosted-video-player" From 7f6e13f93a0bb0f763fb2af1ab81c9394c1d1e40 Mon Sep 17 00:00:00 2001 From: Dominik Lander Date: Tue, 2 Dec 2025 15:37:53 +0000 Subject: [PATCH 3/4] Add comment --- dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx | 8 ++++---- dotcom-rendering/src/layouts/FrontLayout.tsx | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx index 868c219769f..42e5b4c95a8 100644 --- a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx @@ -184,11 +184,11 @@ export const SelfHostedVideoPlayer = forwardRef( }-${atomId}`; /** - * We need CORS enabled to show subtitles on a video as it allows access to the VTT file. + * To show subtitles, CORS must be enabled as it allows access to the VTT file. * - * We don't want a client to not request CORS headers on a video request, then to request - * the same video with CORS headers, as the response could be cached without the headers, which - * will result in the video failing to load. Therefore, we always request CORS headers in production. + * CORS should be enabled in production so that requests are consistent with respect to CORS. + * If a client requests a video without CORS, then later made a request to the same video with + * CORS, then this request could fail as the response could be cached without the headers. */ const requestCORS = showSubtitles || process.env.NODE_ENV === 'production'; diff --git a/dotcom-rendering/src/layouts/FrontLayout.tsx b/dotcom-rendering/src/layouts/FrontLayout.tsx index 97a212e9f08..311d3ae58d9 100644 --- a/dotcom-rendering/src/layouts/FrontLayout.tsx +++ b/dotcom-rendering/src/layouts/FrontLayout.tsx @@ -139,7 +139,8 @@ export const FrontLayout = ({ front, NAV }: Props) => { const contributionsServiceUrl = getContributionsServiceUrl(front); - /** We allow the labs redesign to be shown if: + /** + * We allow the labs redesign to be shown if: * - the feature switch is ON * OR * - the user is opted into the 0% server side test From 1359febdfc1d9a0b086e6ea0cedb31073969fef2 Mon Sep 17 00:00:00 2001 From: Dominik Lander Date: Wed, 3 Dec 2025 09:38:38 +0000 Subject: [PATCH 4/4] Use CORS if not in stories only --- .../src/components/SelfHostedVideo.importable.tsx | 6 ++++++ .../src/components/SelfHostedVideo.stories.tsx | 1 + .../src/components/SelfHostedVideoPlayer.tsx | 14 +++----------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dotcom-rendering/src/components/SelfHostedVideo.importable.tsx b/dotcom-rendering/src/components/SelfHostedVideo.importable.tsx index 5507e398d86..255b8b8d1f6 100644 --- a/dotcom-rendering/src/components/SelfHostedVideo.importable.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideo.importable.tsx @@ -140,6 +140,10 @@ type Props = { fallbackImageAlt: CardPictureProps['alt']; fallbackImageAspectRatio: CardPictureProps['aspectRatio']; linkTo: string; + /** + * If CORS are enabled, the video request will include CORS headers. + */ + enableCors?: boolean; subtitleSource?: string; subtitleSize: SubtitleSize; }; @@ -158,6 +162,7 @@ export const SelfHostedVideo = ({ fallbackImageAlt, fallbackImageAspectRatio, linkTo, + enableCors = true, subtitleSource, subtitleSize, }: Props) => { @@ -706,6 +711,7 @@ export const SelfHostedVideo = ({ AudioIcon={hasAudio ? AudioIcon : null} preloadPartialData={preloadPartialData} showPlayIcon={showPlayIcon} + enableCors={enableCors} subtitleSource={subtitleSource} subtitleSize={subtitleSize} activeCue={activeCue} diff --git a/dotcom-rendering/src/components/SelfHostedVideo.stories.tsx b/dotcom-rendering/src/components/SelfHostedVideo.stories.tsx index 1a993222bf5..5053e1fb8bd 100644 --- a/dotcom-rendering/src/components/SelfHostedVideo.stories.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideo.stories.tsx @@ -32,6 +32,7 @@ export const Loop5to4: Story = { uniqueId: 'test-video-1', atomId: 'test-atom-1', videoStyle: 'Loop', + enableCors: false, height: 720, width: 900, posterImage: diff --git a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx index 42e5b4c95a8..0b0d29aec3e 100644 --- a/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx +++ b/dotcom-rendering/src/components/SelfHostedVideoPlayer.tsx @@ -122,6 +122,7 @@ type Props = { posterImage?: string; preloadPartialData: boolean; showPlayIcon: boolean; + enableCors?: boolean; subtitleSource?: string; subtitleSize?: SubtitleSize; /* used in custom subtitle overlays */ @@ -162,6 +163,7 @@ export const SelfHostedVideoPlayer = forwardRef( AudioIcon, preloadPartialData, showPlayIcon, + enableCors = true, subtitleSource, subtitleSize, activeCue, @@ -183,16 +185,6 @@ export const SelfHostedVideoPlayer = forwardRef( showPlayIcon ? 'play' : 'pause' }-${atomId}`; - /** - * To show subtitles, CORS must be enabled as it allows access to the VTT file. - * - * CORS should be enabled in production so that requests are consistent with respect to CORS. - * If a client requests a video without CORS, then later made a request to the same video with - * CORS, then this request could fail as the response could be cached without the headers. - */ - const requestCORS = - showSubtitles || process.env.NODE_ENV === 'production'; - return ( <> {/* eslint-disable-next-line jsx-a11y/media-has-caption -- Not all videos require captions. */} @@ -202,7 +194,7 @@ export const SelfHostedVideoPlayer = forwardRef( videoStyles(width, height), showSubtitles && subtitleStyles(subtitleSize), ]} - crossOrigin={requestCORS ? 'anonymous' : undefined} + crossOrigin={enableCors ? 'anonymous' : undefined} ref={ref} tabIndex={0} data-testid="self-hosted-video-player"