Skip to content

Commit fc82df7

Browse files
abeddow91domlander
andauthored
Reintroduce subtitles file and use in looping video #14624 (#14786)
* Use subtitles file and use in looping video * WIP - Trying to change the line cues are rendered on * Update hardcoded assets for testing m3u8, mp4 and vtt. This needs to be removed before merge * Remove background colour as this does not affect the existing cue box drawn by the browser. It instead draws another box around the cue box which is not desired. * Require CORS without credentials using "anonymous". This ensure the subtitles are available to JS on all browsers. * Measure the height of the video and set the absolute positioning of the cues by % off of that. * Remove background colour palette for subtitles as the background colour cannot currently be modified whilst we only support the browser subtitle implementation. * Remove hardcoded testing properties * Reduce space from bottom to 12px on browser cues * Alias vidRef.current to video for easier parsing * Remove height protection as we should always be able to retrieve getBoundingClientRect * Add comment to support future development of the loop video player * Temporarily remove looping video stories to unblock PR. * fix linting --------- Co-authored-by: Dominik Lander <[email protected]>
1 parent acb0b78 commit fc82df7

File tree

13 files changed

+121
-4
lines changed

13 files changed

+121
-4
lines changed

dotcom-rendering/src/components/Card/Card.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { CardPicture } from '../CardPicture';
4242
import { Island } from '../Island';
4343
import { LatestLinks } from '../LatestLinks.importable';
4444
import { LoopVideo } from '../LoopVideo.importable';
45+
import type { SubtitleSize } from '../LoopVideoPlayer';
4546
import { Pill } from '../Pill';
4647
import { SlideshowCarousel } from '../SlideshowCarousel.importable';
4748
import { Snap } from '../Snap';
@@ -156,6 +157,7 @@ export type Props = {
156157
trailTextSize?: TrailTextSize;
157158
/** A kicker image is seperate to the main media and renders as part of the kicker */
158159
showKickerImage?: boolean;
160+
subtitleSize?: SubtitleSize;
159161
/** Determines if the headline should be positioned within the content or outside the content */
160162
headlinePosition?: 'inner' | 'outer';
161163
/** Feature flag for the labs redesign work */
@@ -403,6 +405,7 @@ export const Card = ({
403405
showKickerImage = false,
404406
headlinePosition = 'inner',
405407
showLabsRedesign = false,
408+
subtitleSize = 'small',
406409
}: Props) => {
407410
const hasSublinks = supportingContent && supportingContent.length > 0;
408411
const sublinkPosition = decideSublinkPosition(
@@ -950,6 +953,10 @@ export const Card = ({
950953
fallbackImageAlt={media.imageAltText}
951954
fallbackImageAspectRatio="5:4"
952955
linkTo={linkTo}
956+
subtitleSource={
957+
media.mainMedia.subtitleSource
958+
}
959+
subtitleSize={subtitleSize}
953960
/>
954961
</Island>
955962
)}

dotcom-rendering/src/components/FlexibleGeneral.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ export const SplashBoostLevels: Story = {
323323

324324
return (
325325
<>
326+
<Section title="Default" boostLevel="default" />
326327
<Section title="Boosted" boostLevel="boost" />
327328
<Section title="Mega boosted" boostLevel="megaboost" />
328329
<Section title="Giga boosted" boostLevel="gigaboost" />

dotcom-rendering/src/components/FlexibleGeneral.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type { ResponsiveFontSize } from './CardHeadline';
2121
import type { Loading } from './CardPicture';
2222
import { FeatureCard } from './FeatureCard';
2323
import { FrontCard } from './FrontCard';
24+
import type { SubtitleSize } from './LoopVideoPlayer';
2425
import type { Alignment } from './SupportingContent';
2526

2627
type Props = {
@@ -155,6 +156,7 @@ type BoostedSplashProperties = {
155156
supportingContentAlignment: Alignment;
156157
liveUpdatesAlignment: Alignment;
157158
trailTextSize: TrailTextSize;
159+
subtitleSize: SubtitleSize;
158160
avatarUrl?: string;
159161
};
160162

@@ -185,6 +187,7 @@ const decideSplashCardProperties = (
185187
supportingContentLength >= 4 ? 'horizontal' : 'vertical',
186188
liveUpdatesAlignment: 'vertical',
187189
trailTextSize: 'regular',
190+
subtitleSize: 'medium',
188191
};
189192
case 'boost':
190193
return {
@@ -200,6 +203,7 @@ const decideSplashCardProperties = (
200203
supportingContentLength >= 4 ? 'horizontal' : 'vertical',
201204
liveUpdatesAlignment: 'vertical',
202205
trailTextSize: 'regular',
206+
subtitleSize: 'medium',
203207
};
204208
case 'megaboost':
205209
return {
@@ -216,6 +220,7 @@ const decideSplashCardProperties = (
216220
supportingContentAlignment: 'horizontal',
217221
liveUpdatesAlignment: 'horizontal',
218222
trailTextSize: 'large',
223+
subtitleSize: 'large',
219224
};
220225
case 'gigaboost':
221226
return {
@@ -232,6 +237,7 @@ const decideSplashCardProperties = (
232237
supportingContentAlignment: 'horizontal',
233238
liveUpdatesAlignment: 'horizontal',
234239
trailTextSize: 'large',
240+
subtitleSize: 'large',
235241
};
236242
}
237243
};
@@ -293,6 +299,7 @@ const SplashCardLayout = ({
293299
supportingContentAlignment,
294300
liveUpdatesAlignment,
295301
trailTextSize,
302+
subtitleSize,
296303
} = decideSplashCardProperties(
297304
card.boostLevel ?? 'default',
298305
card.supportingContent?.length ?? 0,
@@ -342,6 +349,7 @@ const SplashCardLayout = ({
342349
trailTextSize={trailTextSize}
343350
canPlayInline={true}
344351
showKickerImage={card.format.design === ArticleDesign.Audio}
352+
subtitleSize={subtitleSize}
345353
headlinePosition={card.showLivePlayable ? 'outer' : 'inner'}
346354
showLabsRedesign={showLabsRedesign}
347355
/>
@@ -355,6 +363,7 @@ type BoostedCardProperties = {
355363
mediaSize: MediaSizeType;
356364
liveUpdatesPosition: Position;
357365
supportingContentAlignment: Alignment;
366+
subtitleSize: SubtitleSize;
358367
};
359368

360369
/**
@@ -378,6 +387,7 @@ const decideCardProperties = (
378387
liveUpdatesPosition: 'outer',
379388
supportingContentAlignment:
380389
supportingContentLength >= 2 ? 'horizontal' : 'vertical',
390+
subtitleSize: 'medium',
381391
};
382392
case 'boost':
383393
default:
@@ -391,6 +401,7 @@ const decideCardProperties = (
391401
liveUpdatesPosition: 'inner',
392402
supportingContentAlignment:
393403
supportingContentLength >= 2 ? 'horizontal' : 'vertical',
404+
subtitleSize: 'small',
394405
};
395406
}
396407
};
@@ -431,6 +442,7 @@ const FullWidthCardLayout = ({
431442
mediaSize,
432443
supportingContentAlignment,
433444
liveUpdatesPosition,
445+
subtitleSize,
434446
} = decideCardProperties(
435447
card.supportingContent?.length ?? 0,
436448
card.boostLevel,
@@ -496,6 +508,7 @@ const FullWidthCardLayout = ({
496508
canPlayInline={true}
497509
showKickerImage={card.format.design === ArticleDesign.Audio}
498510
showLabsRedesign={showLabsRedesign}
511+
subtitleSize={subtitleSize}
499512
/>
500513
</LI>
501514
</UL>

dotcom-rendering/src/components/FlexibleSpecial.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { UL } from './Card/components/UL';
1919
import type { ResponsiveFontSize } from './CardHeadline';
2020
import type { Loading } from './CardPicture';
2121
import { FrontCard } from './FrontCard';
22+
import type { SubtitleSize } from './LoopVideoPlayer';
2223
import type { Alignment } from './SupportingContent';
2324

2425
type Props = {
@@ -41,6 +42,7 @@ type BoostProperties = {
4142
supportingContentAlignment: Alignment;
4243
liveUpdatesAlignment: Alignment;
4344
trailTextSize: TrailTextSize;
45+
subtitleSize: SubtitleSize;
4446
};
4547

4648
/**
@@ -69,6 +71,7 @@ const determineCardProperties = (
6971
supportingContentLength >= 3 ? 'horizontal' : 'vertical',
7072
liveUpdatesAlignment: 'vertical',
7173
trailTextSize: 'regular',
74+
subtitleSize: 'medium',
7275
};
7376
case 'boost':
7477
return {
@@ -84,6 +87,7 @@ const determineCardProperties = (
8487
supportingContentLength >= 3 ? 'horizontal' : 'vertical',
8588
liveUpdatesAlignment: 'vertical',
8689
trailTextSize: 'regular',
90+
subtitleSize: 'medium',
8791
};
8892
case 'megaboost':
8993
return {
@@ -98,6 +102,7 @@ const determineCardProperties = (
98102
supportingContentAlignment: 'horizontal',
99103
liveUpdatesAlignment: 'horizontal',
100104
trailTextSize: 'large',
105+
subtitleSize: 'large',
101106
};
102107
case 'gigaboost':
103108
return {
@@ -112,6 +117,7 @@ const determineCardProperties = (
112117
supportingContentAlignment: 'horizontal',
113118
liveUpdatesAlignment: 'horizontal',
114119
trailTextSize: 'large',
120+
subtitleSize: 'large',
115121
};
116122
}
117123
};
@@ -154,6 +160,7 @@ export const OneCardLayout = ({
154160
supportingContentAlignment,
155161
liveUpdatesAlignment,
156162
trailTextSize,
163+
subtitleSize,
157164
} = determineCardProperties(
158165
card.boostLevel ?? 'default',
159166
card.supportingContent?.length ?? 0,
@@ -194,6 +201,7 @@ export const OneCardLayout = ({
194201
showKickerImage={card.format.design === ArticleDesign.Audio}
195202
headlinePosition={isSplashCard ? 'outer' : 'inner'}
196203
showLabsRedesign={showLabsRedesign}
204+
subtitleSize={subtitleSize}
197205
/>
198206
</LI>
199207
</UL>

dotcom-rendering/src/components/LoopVideo.importable.tsx

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { css } from '@emotion/react';
22
import { log, storage } from '@guardian/libs';
3+
import { space } from '@guardian/source/foundations';
34
import { SvgAudio, SvgAudioMute } from '@guardian/source/react-components';
45
import { useCallback, useEffect, useRef, useState } from 'react';
56
import {
@@ -18,8 +19,12 @@ import {
1819
} from '../lib/video';
1920
import { CardPicture, type Props as CardPictureProps } from './CardPicture';
2021
import { useConfig } from './ConfigContext';
22+
import type {
23+
PLAYER_STATES,
24+
PlayerStates,
25+
SubtitleSize,
26+
} from './LoopVideoPlayer';
2127
import { LoopVideoPlayer } from './LoopVideoPlayer';
22-
import type { PLAYER_STATES, PlayerStates } from './LoopVideoPlayer';
2328
import { ophanTrackerWeb } from './YoutubeAtom/eventEmitters';
2429

2530
const videoContainerStyles = css`
@@ -117,6 +122,8 @@ type Props = {
117122
fallbackImageAlt: CardPictureProps['alt'];
118123
fallbackImageAspectRatio: CardPictureProps['aspectRatio'];
119124
linkTo: string;
125+
subtitleSource?: string;
126+
subtitleSize: SubtitleSize;
120127
};
121128

122129
export const LoopVideo = ({
@@ -132,6 +139,8 @@ export const LoopVideo = ({
132139
fallbackImageAlt,
133140
fallbackImageAspectRatio,
134141
linkTo,
142+
subtitleSource,
143+
subtitleSize,
135144
}: Props) => {
136145
const adapted = useShouldAdapt();
137146
const { renderingTarget } = useConfig();
@@ -486,6 +495,25 @@ export const LoopVideo = ({
486495
return FallbackImageComponent;
487496
}
488497

498+
const handleLoadedMetadata = () => {
499+
const video = vidRef.current;
500+
if (!video) return;
501+
502+
const track = video.textTracks[0];
503+
if (!track?.cues) return;
504+
const pxFromBottom = space[3];
505+
const videoHeight = video.getBoundingClientRect().height;
506+
const percentFromTop =
507+
((videoHeight - pxFromBottom) / videoHeight) * 100;
508+
509+
for (const cue of Array.from(track.cues)) {
510+
if (cue instanceof VTTCue) {
511+
cue.snapToLines = false;
512+
cue.line = percentFromTop;
513+
}
514+
}
515+
};
516+
489517
const handleLoadedData = () => {
490518
if (vidRef.current) {
491519
setHasAudio(doesVideoHaveAudio(vidRef.current));
@@ -625,6 +653,7 @@ export const LoopVideo = ({
625653
isPlayable={isPlayable}
626654
playerState={playerState}
627655
isMuted={isMuted}
656+
handleLoadedMetadata={handleLoadedMetadata}
628657
handleLoadedData={handleLoadedData}
629658
handleCanPlay={handleCanPlay}
630659
handlePlayPauseClick={handlePlayPauseClick}
@@ -635,6 +664,8 @@ export const LoopVideo = ({
635664
AudioIcon={hasAudio ? AudioIcon : null}
636665
preloadPartialData={preloadPartialData}
637666
showPlayIcon={showPlayIcon}
667+
subtitleSource={subtitleSource}
668+
subtitleSize={subtitleSize}
638669
/>
639670
</figure>
640671
);

dotcom-rendering/src/components/LoopVideo.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const meta = {
1212
parameters: {
1313
chromatic: {
1414
viewports: [breakpoints.mobile, breakpoints.wide],
15+
disableSnapshot: true,
1516
},
1617
},
1718
} satisfies Meta<typeof LoopVideo>;

0 commit comments

Comments
 (0)