Skip to content

Commit

Permalink
feat(videoJs): implement videoJs to story video (#1068)
Browse files Browse the repository at this point in the history
* feat(videoJs): implement videoJs to story video

* refactor(video): add poster
  • Loading branch information
KatvonRivia committed Mar 16, 2022
1 parent 4f97916 commit d698404
Show file tree
Hide file tree
Showing 16 changed files with 23,413 additions and 151 deletions.
22,722 changes: 22,618 additions & 104 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@types/react-dom": "^16.9.5",
"@types/react-redux": "^7.1.7",
"@types/redux-thunk": "^2.1.0",
"@types/video.js": "^7.3.31",
"@types/youtube-player": "^5.5.3",
"@typescript-eslint/eslint-plugin": "^2.19.2",
"@typescript-eslint/parser": "^2.19.2",
Expand Down Expand Up @@ -102,6 +103,7 @@
"terser-webpack-plugin": "^2.3.5",
"ts-loader": "^6.2.1",
"typescript": "^3.7.5",
"video.js": "^7.17.0",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0"
Expand Down
4 changes: 0 additions & 4 deletions src/scripts/components/stories/story-video/story-video.styl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,3 @@

.presentationVideo
padding-bottom: 15vh

.youtubePlayer
width: 100%
height: 100%
60 changes: 30 additions & 30 deletions src/scripts/components/stories/story-video/story-video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,57 @@
import React, {FunctionComponent} from 'react';
import {useSelector} from 'react-redux';
import cx from 'classnames';
import YouTube, {Options} from 'react-youtube';

import {languageSelector} from '../../../selectors/language';

import {StoryMode} from '../../../types/story-mode';
import {YouTubePlayer} from 'youtube-player/dist/types';
import VideoJS from '../video-js/video-js';
import YoutubePlayer from '../youtube-player/youtube-player';

import {Slide} from '../../../types/story';

import styles from './story-video.styl';

interface Props {
videoId: string;
mode: StoryMode | null;
storyId: string;
slide: Slide;
onPlay: (player: YouTubePlayer) => void;
}

const StoryVideo: FunctionComponent<Props> = ({mode, videoId, onPlay}) => {
const StoryVideo: FunctionComponent<Props> = ({
mode,
storyId,
slide,
onPlay
}) => {
const {videoSrc, videoId, videoCaptions, videoPoster} = slide;
const language = useSelector(languageSelector);
const isStoryMode = mode === StoryMode.Stories;
const classes = cx(
styles.storyVideo,
!isStoryMode && styles.presentationVideo
);

const opts: Options = {
height: '100%',
width: '100%',
playerVars: {
rel: 0,
cc_load_policy: 1,
hl: language,
// @ts-ignore
cc_lang_pref: language,
color: 'red',
controls: 2,
iv_load_policy: 3,
modestbranding: 1,
showinfo: 0,
allow:
'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture'
}
};

return (
<div className={classes}>
<YouTube
containerClassName={styles.youtubePlayer}
videoId={videoId}
opts={opts}
onReady={event => !isStoryMode && event.target.playVideo()}
onPlay={event => onPlay(event.target)}
/>
{videoSrc ? (
<VideoJS
storyId={storyId}
videoSrc={videoSrc}
language={language}
isStoryMode={isStoryMode}
videoCaptions={videoCaptions}
videoPoster={videoPoster}
/>
) : (
<YoutubePlayer
videoId={videoId}
language={language}
isStoryMode={isStoryMode}
onPlay={onPlay}
/>
)}
</div>
);
};
Expand Down
8 changes: 6 additions & 2 deletions src/scripts/components/stories/story/story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ const Story: FunctionComponent = () => {
storyId={story.id}
/>
);
} else if (slide.type === SlideType.Video && slide.videoId) {
} else if (
slide.type === SlideType.Video &&
(slide.videoSrc || slide.videoId)
) {
return (
<StoryVideo
mode={mode}
videoId={slide.videoId}
storyId={story.id}
slide={slide}
onPlay={(player: YouTubePlayer) => getVideoDuration(player)}
/>
);
Expand Down
98 changes: 98 additions & 0 deletions src/scripts/components/stories/video-js/video-js.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, {FunctionComponent, useEffect, useRef} from 'react';
import videojs, {VideoJsPlayerOptions} from 'video.js';
import {getStoryAssetUrl} from '../../../libs/get-story-asset-urls';

import {Language} from '../../../types/language';

import 'video.js/dist/video-js.css';

interface Props {
storyId: string;
videoSrc: string;
language: Language;
isStoryMode: boolean;
videoCaptions?: string;
videoPoster?: string;
}

const VideoJS: FunctionComponent<Props> = ({
storyId,
videoSrc,
language,
isStoryMode,
videoCaptions,
videoPoster
}) => {
const videoRef = useRef(null);
const playerRef = useRef<videojs.Player | null>();
const videoUrl = videoSrc && getStoryAssetUrl(storyId, videoSrc);
const captionsUrl = videoCaptions && getStoryAssetUrl(storyId, videoCaptions);
const posterUrl = videoPoster && getStoryAssetUrl(storyId, videoPoster);

const videoJsOptions: VideoJsPlayerOptions = {
autoplay: isStoryMode ? false : true,
controls: true,
responsive: true,
fluid: true,
aspectRatio: '4:3',
poster: posterUrl,
sources: [
{
src: videoUrl,
type: 'video/mp4'
}
],
tracks: [
{
srclang: language,
kind: 'captions',
src: captionsUrl,
default: true
}
]
};

const handlePlayerReady = (player: videojs.Player) => {
playerRef.current = player;
};

useEffect(() => {
// make sure Video.js player is only initialized once
if (!playerRef.current) {
const videoElement = videoRef.current;
if (!videoElement) {
return;
}

const player: videojs.Player = (playerRef.current = videojs(
videoElement,
videoJsOptions,
() => handlePlayerReady(player)
));
}
}, [videoJsOptions, videoRef]);

// Dispose the Video.js player when component unmounts
useEffect(() => {
const player = playerRef.current;

return () => {
if (player) {
player.dispose();
playerRef.current = null;
}
};
}, [playerRef]);

return (
<div data-vjs-player>
<video
ref={videoRef}
className="video-js vjs-big-play-centered"
style={{height: '100%'}}
/>
</div>
);
};

export default VideoJS;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.videoPlayer
width: 100%
height: 100%
54 changes: 54 additions & 0 deletions src/scripts/components/stories/youtube-player/youtube-player.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-disable camelcase */
/* eslint-disable @typescript-eslint/camelcase */
import React, {FunctionComponent} from 'react';
import YouTube, {Options} from 'react-youtube';
import {YouTubePlayer} from 'youtube-player/dist/types';

import {Language} from '../../../types/language';

import styles from './youtube-player.styl';

interface Props {
videoId?: string;
language: Language;
isStoryMode: boolean;
onPlay: (player: YouTubePlayer) => void;
}

const YoutubePlayer: FunctionComponent<Props> = ({
videoId,
language,
isStoryMode,
onPlay
}) => {
const options: Options = {
height: '100%',
width: '100%',
playerVars: {
rel: 0,
cc_load_policy: 1,
hl: language,
// @ts-ignore
cc_lang_pref: language,
color: 'red',
controls: 2,
iv_load_policy: 3,
modestbranding: 1,
showinfo: 0,
allow:
'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture'
}
};

return (
<YouTube
containerClassName={styles.videoPlayer}
videoId={videoId}
opts={options}
onReady={event => !isStoryMode && event.target.playVideo()}
onPlay={event => onPlay(event.target)}
/>
);
};

export default YoutubePlayer;
3 changes: 3 additions & 0 deletions src/scripts/types/story.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export interface Slide {
imageCaptions?: string[];
imageFits?: ImageFit[];
videoId?: string;
videoSrc?: string;
videoCaptions?: string;
videoPoster?: string;
layer?: StoryLayer[];
layerDescription?: string;
flyTo: GlobeView;
Expand Down
Loading

0 comments on commit d698404

Please sign in to comment.