mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-06 15:38:53 -05:00
feat: Keep a backup from old videojs files
This commit is contained in:
parent
3be86f91f7
commit
660f76ecfe
@ -0,0 +1,257 @@
|
|||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import urlParse from 'url-parse';
|
||||||
|
|
||||||
|
import MediaPlayer from 'mediacms-player/dist/mediacms-player.js';
|
||||||
|
import 'mediacms-player/dist/mediacms-player.css';
|
||||||
|
|
||||||
|
import './VideoPlayer.scss';
|
||||||
|
|
||||||
|
export function formatInnerLink(url, baseUrl) {
|
||||||
|
let link = urlParse(url, {});
|
||||||
|
|
||||||
|
if ('' === link.origin || 'null' === link.origin || !link.origin) {
|
||||||
|
link = urlParse(baseUrl + '/' + url.replace(/^\//g, ''), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
return link.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VideoPlayerError(props) {
|
||||||
|
return (
|
||||||
|
<div className="error-container">
|
||||||
|
<div className="error-container-inner">
|
||||||
|
<span className="icon-wrap">
|
||||||
|
<i className="material-icons">error_outline</i>
|
||||||
|
</span>
|
||||||
|
<span className="msg-wrap">{props.errorMessage}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoPlayerError.propTypes = {
|
||||||
|
errorMessage: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function VideoPlayer(props) {
|
||||||
|
const videoElemRef = useRef(null);
|
||||||
|
|
||||||
|
let player = null;
|
||||||
|
|
||||||
|
const playerStates = {
|
||||||
|
playerVolume: props.playerVolume,
|
||||||
|
playerSoundMuted: props.playerSoundMuted,
|
||||||
|
videoQuality: props.videoQuality,
|
||||||
|
videoPlaybackSpeed: props.videoPlaybackSpeed,
|
||||||
|
inTheaterMode: props.inTheaterMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
playerStates.playerVolume =
|
||||||
|
null === playerStates.playerVolume ? 1 : Math.max(Math.min(Number(playerStates.playerVolume), 1), 0);
|
||||||
|
playerStates.playerSoundMuted = null !== playerStates.playerSoundMuted ? playerStates.playerSoundMuted : !1;
|
||||||
|
playerStates.videoQuality = null !== playerStates.videoQuality ? playerStates.videoQuality : 'Auto';
|
||||||
|
playerStates.videoPlaybackSpeed = null !== playerStates.videoPlaybackSpeed ? playerStates.videoPlaybackSpeed : !1;
|
||||||
|
playerStates.inTheaterMode = null !== playerStates.inTheaterMode ? playerStates.inTheaterMode : !1;
|
||||||
|
|
||||||
|
function onClickNext() {
|
||||||
|
if (void 0 !== props.onClickNextCallback) {
|
||||||
|
props.onClickNextCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClickPrevious() {
|
||||||
|
if (void 0 !== props.onClickPreviousCallback) {
|
||||||
|
props.onClickPreviousCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPlayerStateUpdate(newState) {
|
||||||
|
if (playerStates.playerVolume !== newState.volume) {
|
||||||
|
playerStates.playerVolume = newState.volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerStates.playerSoundMuted !== newState.soundMuted) {
|
||||||
|
playerStates.playerSoundMuted = newState.soundMuted;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerStates.videoQuality !== newState.quality) {
|
||||||
|
playerStates.videoQuality = newState.quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerStates.videoPlaybackSpeed !== newState.playbackSpeed) {
|
||||||
|
playerStates.videoPlaybackSpeed = newState.playbackSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerStates.inTheaterMode !== newState.theaterMode) {
|
||||||
|
playerStates.inTheaterMode = newState.theaterMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (void 0 !== props.onStateUpdateCallback) {
|
||||||
|
props.onStateUpdateCallback(newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initPlayer() {
|
||||||
|
if (null !== player || null !== props.errorMessage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.inEmbed) {
|
||||||
|
window.removeEventListener('focus', initPlayer);
|
||||||
|
document.removeEventListener('visibilitychange', initPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!videoElemRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.inEmbed) {
|
||||||
|
videoElemRef.current.focus(); // Focus on player before instance init.
|
||||||
|
}
|
||||||
|
|
||||||
|
const subtitles = {
|
||||||
|
on: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (void 0 !== props.subtitlesInfo && null !== props.subtitlesInfo && props.subtitlesInfo.length) {
|
||||||
|
subtitles.languages = [];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
while (i < props.subtitlesInfo.length) {
|
||||||
|
if (
|
||||||
|
void 0 !== props.subtitlesInfo[i].src &&
|
||||||
|
void 0 !== props.subtitlesInfo[i].srclang &&
|
||||||
|
void 0 !== props.subtitlesInfo[i].label
|
||||||
|
) {
|
||||||
|
subtitles.languages.push({
|
||||||
|
src: formatInnerLink(props.subtitlesInfo[i].src, props.siteUrl),
|
||||||
|
srclang: props.subtitlesInfo[i].srclang,
|
||||||
|
label: props.subtitlesInfo[i].label,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subtitles.languages.length) {
|
||||||
|
subtitles.on = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player = new MediaPlayer(
|
||||||
|
videoElemRef.current,
|
||||||
|
{
|
||||||
|
enabledTouchControls: true,
|
||||||
|
sources: props.sources,
|
||||||
|
poster: props.poster,
|
||||||
|
autoplay: props.enableAutoplay,
|
||||||
|
bigPlayButton: true,
|
||||||
|
controlBar: {
|
||||||
|
theaterMode: props.hasTheaterMode,
|
||||||
|
pictureInPicture: false,
|
||||||
|
next: props.hasNextLink ? true : false,
|
||||||
|
previous: props.hasPreviousLink ? true : false,
|
||||||
|
},
|
||||||
|
subtitles: subtitles,
|
||||||
|
cornerLayers: props.cornerLayers,
|
||||||
|
videoPreviewThumb: props.previewSprite,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
volume: playerStates.playerVolume,
|
||||||
|
soundMuted: playerStates.playerSoundMuted,
|
||||||
|
theaterMode: playerStates.inTheaterMode,
|
||||||
|
theSelectedQuality: void 0, // @note: Allow auto resolution selection by sources order.
|
||||||
|
theSelectedPlaybackSpeed: playerStates.videoPlaybackSpeed || 1,
|
||||||
|
},
|
||||||
|
props.info,
|
||||||
|
[0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],
|
||||||
|
onPlayerStateUpdate,
|
||||||
|
onClickNext,
|
||||||
|
onClickPrevious
|
||||||
|
);
|
||||||
|
|
||||||
|
if (void 0 !== props.onPlayerInitCallback) {
|
||||||
|
props.onPlayerInitCallback(player, videoElemRef.current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsetPlayer() {
|
||||||
|
if (null === player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
videojs(videoElemRef.current).dispose();
|
||||||
|
player = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.inEmbed || document.hasFocus() || 'visible' === document.visibilityState) {
|
||||||
|
initPlayer();
|
||||||
|
} else {
|
||||||
|
window.addEventListener('focus', initPlayer);
|
||||||
|
document.addEventListener('visibilitychange', initPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// We don't need this because we have a custom function in frontend/src/static/js/components/media-viewer/VideoViewer/index.js:617
|
||||||
|
player && player.player.one('loadedmetadata', () => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const paramT = Number(urlParams.get('t'));
|
||||||
|
const timestamp = !isNaN(paramT) ? paramT : 0;
|
||||||
|
player.player.currentTime(timestamp);
|
||||||
|
}); */
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsetPlayer();
|
||||||
|
|
||||||
|
if (void 0 !== props.onUnmountCallback) {
|
||||||
|
props.onUnmountCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return null === props.errorMessage ? (
|
||||||
|
<video ref={videoElemRef} className="video-js vjs-mediacms native-dimensions"></video>
|
||||||
|
) : (
|
||||||
|
<div className="error-container">
|
||||||
|
<div className="error-container-inner">
|
||||||
|
<span className="icon-wrap">
|
||||||
|
<i className="material-icons">error_outline</i>
|
||||||
|
</span>
|
||||||
|
<span className="msg-wrap">{props.errorMessage}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoPlayer.propTypes = {
|
||||||
|
playerVolume: PropTypes.string,
|
||||||
|
playerSoundMuted: PropTypes.bool,
|
||||||
|
videoQuality: PropTypes.string,
|
||||||
|
videoPlaybackSpeed: PropTypes.number,
|
||||||
|
inTheaterMode: PropTypes.bool,
|
||||||
|
siteId: PropTypes.string.isRequired,
|
||||||
|
siteUrl: PropTypes.string.isRequired,
|
||||||
|
errorMessage: PropTypes.string,
|
||||||
|
cornerLayers: PropTypes.object,
|
||||||
|
subtitlesInfo: PropTypes.array.isRequired,
|
||||||
|
inEmbed: PropTypes.bool.isRequired,
|
||||||
|
sources: PropTypes.array.isRequired,
|
||||||
|
info: PropTypes.object.isRequired,
|
||||||
|
enableAutoplay: PropTypes.bool.isRequired,
|
||||||
|
hasTheaterMode: PropTypes.bool.isRequired,
|
||||||
|
hasNextLink: PropTypes.bool.isRequired,
|
||||||
|
hasPreviousLink: PropTypes.bool.isRequired,
|
||||||
|
poster: PropTypes.string,
|
||||||
|
previewSprite: PropTypes.object,
|
||||||
|
onClickPreviousCallback: PropTypes.func,
|
||||||
|
onClickNextCallback: PropTypes.func,
|
||||||
|
onPlayerInitCallback: PropTypes.func,
|
||||||
|
onStateUpdateCallback: PropTypes.func,
|
||||||
|
onUnmountCallback: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoPlayer.defaultProps = {
|
||||||
|
errorMessage: null,
|
||||||
|
cornerLayers: {},
|
||||||
|
};
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { format } from 'timeago.js';
|
import { format } from 'timeago.js';
|
||||||
import { formatViewsNumber, imageExtension } from '../../../../utils/helpers/';
|
import { formatViewsNumber, imageExtension } from '../../../../utils/helpers/';
|
||||||
import { VideoPlayerByPageLink } from '../../../video-player/VideoPlayerByPageLink';
|
// import { VideoPlayerByPageLink } from '../../../video-player/VideoPlayerByPageLink';
|
||||||
import { translateString } from '../../../../utils/helpers/';
|
import { translateString } from '../../../../utils/helpers/';
|
||||||
|
|
||||||
export function ItemDescription(props) {
|
export function ItemDescription(props) {
|
||||||
@ -74,8 +74,8 @@ export function MediaItemEditLink(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return !link ? null : (
|
return !link ? null : (
|
||||||
<a href={link} title={translateString("Edit media")} className="item-edit-link">
|
<a href={link} title={translateString('Edit media')} className="item-edit-link">
|
||||||
{translateString("EDIT MEDIA")}
|
{translateString('EDIT MEDIA')}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -136,7 +136,11 @@ export function MediaItemAuthorLink(props) {
|
|||||||
|
|
||||||
export function MediaItemMetaViews(props) {
|
export function MediaItemMetaViews(props) {
|
||||||
return (
|
return (
|
||||||
<span className="item-views">{formatViewsNumber(props.views) + ' ' + (1 >= props.views ? translateString('view') : translateString('views'))}</span>
|
<span className="item-views">
|
||||||
|
{formatViewsNumber(props.views) +
|
||||||
|
' ' +
|
||||||
|
(1 >= props.views ? translateString('view') : translateString('views'))}
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +179,8 @@ export function MediaItemVideoPlayer(props) {
|
|||||||
return (
|
return (
|
||||||
<div className="item-player-wrapper">
|
<div className="item-player-wrapper">
|
||||||
<div className="item-player-wrapper-inner">
|
<div className="item-player-wrapper-inner">
|
||||||
<VideoPlayerByPageLink pageLink={props.mediaPageLink} />
|
stop component tou VideoPlayerByPageLink
|
||||||
|
{/* <VideoPlayerByPageLink pageLink={props.mediaPageLink} /> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,7 +10,8 @@ import {
|
|||||||
videoAvailableCodecsAndResolutions,
|
videoAvailableCodecsAndResolutions,
|
||||||
extractDefaultVideoResolution,
|
extractDefaultVideoResolution,
|
||||||
} from './functions';
|
} from './functions';
|
||||||
import { VideoPlayer, VideoPlayerError } from '../../video-player/VideoPlayer';
|
// import { VideoPlayer, VideoPlayerError } from '../../video-player/VideoPlayer';
|
||||||
|
import VideoJSEmbed from '../../VideoJS/VideoJSEmbed';
|
||||||
|
|
||||||
import '../VideoViewer.scss';
|
import '../VideoViewer.scss';
|
||||||
|
|
||||||
@ -18,7 +19,10 @@ function filterVideoEncoding(encoding_status) {
|
|||||||
switch (encoding_status) {
|
switch (encoding_status) {
|
||||||
case 'running_X':
|
case 'running_X':
|
||||||
MediaPageStore.set('media-load-error-type', 'encodingRunning');
|
MediaPageStore.set('media-load-error-type', 'encodingRunning');
|
||||||
MediaPageStore.set('media-load-error-message', 'Media encoding is currently running. Try again in few minutes.');
|
MediaPageStore.set(
|
||||||
|
'media-load-error-message',
|
||||||
|
'Media encoding is currently running. Try again in few minutes.'
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'pending_X':
|
case 'pending_X':
|
||||||
MediaPageStore.set('media-load-error-type', 'encodingPending');
|
MediaPageStore.set('media-load-error-type', 'encodingPending');
|
||||||
@ -80,7 +84,9 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
k = 0;
|
k = 0;
|
||||||
while (k < this.videoInfo[defaultVideoResolution].format.length) {
|
while (k < this.videoInfo[defaultVideoResolution].format.length) {
|
||||||
if ('hls' === this.videoInfo[defaultVideoResolution].format[k]) {
|
if ('hls' === this.videoInfo[defaultVideoResolution].format[k]) {
|
||||||
this.videoSources.push({ src: this.videoInfo[defaultVideoResolution].url[k] });
|
this.videoSources.push({
|
||||||
|
src: this.videoInfo[defaultVideoResolution].url[k],
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
k += 1;
|
k += 1;
|
||||||
@ -191,7 +197,10 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
|
|
||||||
if (userThumbLink) {
|
if (userThumbLink) {
|
||||||
userThumbLink.setAttribute('class', 'user-thumb-link');
|
userThumbLink.setAttribute('class', 'user-thumb-link');
|
||||||
userThumbLink.setAttribute('href', formatInnerLink(this.props.data.author_profile, this.props.siteUrl));
|
userThumbLink.setAttribute(
|
||||||
|
'href',
|
||||||
|
formatInnerLink(this.props.data.author_profile, this.props.siteUrl)
|
||||||
|
);
|
||||||
userThumbLink.setAttribute('title', this.props.data.author_name);
|
userThumbLink.setAttribute('title', this.props.data.author_name);
|
||||||
userThumbLink.setAttribute('target', '_blank');
|
userThumbLink.setAttribute('target', '_blank');
|
||||||
userThumbLink.setAttribute(
|
userThumbLink.setAttribute(
|
||||||
@ -292,13 +301,19 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
const shareInner = document.querySelector('.share-options-inner');
|
const shareInner = document.querySelector('.share-options-inner');
|
||||||
if (shareBtn) {
|
if (shareBtn) {
|
||||||
shareBtn.addEventListener('click', function (ev) {
|
shareBtn.addEventListener('click', function (ev) {
|
||||||
addClassname(document.querySelector('.video-js.vjs-mediacms'), 'vjs-visible-share-options');
|
addClassname(
|
||||||
|
document.querySelector('.video-js.vjs-mediacms'),
|
||||||
|
'vjs-visible-share-options'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (shareWrap) {
|
if (shareWrap) {
|
||||||
shareWrap.addEventListener('click', function (ev) {
|
shareWrap.addEventListener('click', function (ev) {
|
||||||
if (ev.target === shareInner || ev.target === shareWrap) {
|
if (ev.target === shareInner || ev.target === shareWrap) {
|
||||||
removeClassname(document.querySelector('.video-js.vjs-mediacms'), 'vjs-visible-share-options');
|
removeClassname(
|
||||||
|
document.querySelector('.video-js.vjs-mediacms'),
|
||||||
|
'vjs-visible-share-options'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -506,7 +521,9 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
previousLink = MediaPageStore.get('playlist-previous-media-url');
|
previousLink = MediaPageStore.get('playlist-previous-media-url');
|
||||||
} else {
|
} else {
|
||||||
nextLink =
|
nextLink =
|
||||||
this.props.data.related_media.length && !this.props.inEmbed ? this.props.data.related_media[0].url : null;
|
this.props.data.related_media.length && !this.props.inEmbed
|
||||||
|
? this.props.data.related_media[0].url
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const previewSprite = !!this.props.data.sprites_url
|
const previewSprite = !!this.props.data.sprites_url
|
||||||
@ -517,13 +534,76 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{/* {React.createElement(VideoJSEmbed, {
|
||||||
|
data: this.props.data,
|
||||||
|
siteUrl: window.MediaCMS.site.url,
|
||||||
|
onLoad: () => console.log('Video js loaded in VideoViewer'),
|
||||||
|
onError: (error) => console.error('Video js error in VideoViewer:', error),
|
||||||
|
})} */}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
key={(this.props.inEmbed ? 'embed-' : '') + 'player-container'}
|
key={(this.props.inEmbed ? 'embed-' : '') + 'player-container'}
|
||||||
className={'player-container' + (this.videoSources.length ? '' : ' player-container-error')}
|
className={'player-container' + (this.videoSources.length ? '' : ' player-container-error')}
|
||||||
style={this.props.containerStyles}
|
style={this.props.containerStyles}
|
||||||
ref="playerContainer"
|
ref="playerContainer"
|
||||||
>
|
>
|
||||||
<div className="player-container-inner" ref="playerContainerInner" style={this.props.containerStyles}>
|
<div
|
||||||
|
className="player-container-inner"
|
||||||
|
ref="playerContainerInner"
|
||||||
|
style={this.props.containerStyles}
|
||||||
|
>
|
||||||
|
{this.state.displayPlayer && null == MediaPageStore.get('media-load-error-type') ? (
|
||||||
|
<div className="video-player" ref="videoJSPlayerWrapper" key="videoJSPlayerWrapper">
|
||||||
|
<SiteConsumer>
|
||||||
|
{(site) => {
|
||||||
|
return React.createElement(VideoJSEmbed, {
|
||||||
|
data: this.props.data,
|
||||||
|
playerVolume: this.browserCache.get('player-volume'),
|
||||||
|
playerSoundMuted: this.browserCache.get('player-sound-muted'),
|
||||||
|
videoQuality: this.browserCache.get('video-quality'),
|
||||||
|
videoPlaybackSpeed: parseInt(
|
||||||
|
this.browserCache.get('video-playback-speed'),
|
||||||
|
10
|
||||||
|
),
|
||||||
|
inTheaterMode: this.browserCache.get('in-theater-mode'),
|
||||||
|
siteId: site.id,
|
||||||
|
siteUrl: site.url,
|
||||||
|
info: this.videoInfo,
|
||||||
|
cornerLayers: this.cornerLayers,
|
||||||
|
sources: this.videoSources,
|
||||||
|
poster: this.videoPoster,
|
||||||
|
previewSprite: previewSprite,
|
||||||
|
subtitlesInfo: this.props.data.subtitles_info,
|
||||||
|
enableAutoplay: !this.props.inEmbed,
|
||||||
|
inEmbed: this.props.inEmbed,
|
||||||
|
hasTheaterMode: !this.props.inEmbed,
|
||||||
|
hasNextLink: !!nextLink,
|
||||||
|
hasPreviousLink: !!previousLink,
|
||||||
|
errorMessage: MediaPageStore.get('media-load-error-message'),
|
||||||
|
onClickNextCallback: this.onClickNext,
|
||||||
|
onClickPreviousCallback: this.onClickPrevious,
|
||||||
|
onStateUpdateCallback: this.onStateUpdate,
|
||||||
|
onPlayerInitCallback: this.onPlayerInit,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
</SiteConsumer>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <div
|
||||||
|
key={(this.props.inEmbed ? 'embed-' : '') + 'player-container'}
|
||||||
|
className={'player-container' + (this.videoSources.length ? '' : ' player-container-error')}
|
||||||
|
style={this.props.containerStyles}
|
||||||
|
ref="playerContainer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="player-container-inner"
|
||||||
|
ref="playerContainerInner"
|
||||||
|
style={this.props.containerStyles}
|
||||||
|
>
|
||||||
{this.state.displayPlayer && null !== MediaPageStore.get('media-load-error-type') ? (
|
{this.state.displayPlayer && null !== MediaPageStore.get('media-load-error-type') ? (
|
||||||
<VideoPlayerError errorMessage={MediaPageStore.get('media-load-error-message')} />
|
<VideoPlayerError errorMessage={MediaPageStore.get('media-load-error-message')} />
|
||||||
) : null}
|
) : null}
|
||||||
@ -536,7 +616,10 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
playerVolume={this.browserCache.get('player-volume')}
|
playerVolume={this.browserCache.get('player-volume')}
|
||||||
playerSoundMuted={this.browserCache.get('player-sound-muted')}
|
playerSoundMuted={this.browserCache.get('player-sound-muted')}
|
||||||
videoQuality={this.browserCache.get('video-quality')}
|
videoQuality={this.browserCache.get('video-quality')}
|
||||||
videoPlaybackSpeed={parseInt(this.browserCache.get('video-playback-speed'), 10)}
|
videoPlaybackSpeed={parseInt(
|
||||||
|
this.browserCache.get('video-playback-speed'),
|
||||||
|
10
|
||||||
|
)}
|
||||||
inTheaterMode={this.browserCache.get('in-theater-mode')}
|
inTheaterMode={this.browserCache.get('in-theater-mode')}
|
||||||
siteId={site.id}
|
siteId={site.id}
|
||||||
siteUrl={site.url}
|
siteUrl={site.url}
|
||||||
@ -562,7 +645,8 @@ export default class VideoViewer extends React.PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> */}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +673,8 @@ function findGetParameter(parameterName) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCanvas(videoElem) { // Make sure it's a video element
|
function handleCanvas(videoElem) {
|
||||||
|
// Make sure it's a video element
|
||||||
|
|
||||||
if (!videoElem || !videoElem.tagName || videoElem.tagName.toLowerCase() !== 'video') {
|
if (!videoElem || !videoElem.tagName || videoElem.tagName.toLowerCase() !== 'video') {
|
||||||
console.error('Invalid video element:', videoElem);
|
console.error('Invalid video element:', videoElem);
|
||||||
|
|||||||
@ -1,257 +0,0 @@
|
|||||||
import React, { useRef, useEffect } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import urlParse from 'url-parse';
|
|
||||||
|
|
||||||
import MediaPlayer from 'mediacms-player/dist/mediacms-player.js';
|
|
||||||
import 'mediacms-player/dist/mediacms-player.css';
|
|
||||||
|
|
||||||
import './VideoPlayer.scss';
|
|
||||||
|
|
||||||
export function formatInnerLink(url, baseUrl) {
|
|
||||||
let link = urlParse(url, {});
|
|
||||||
|
|
||||||
if ('' === link.origin || 'null' === link.origin || !link.origin) {
|
|
||||||
link = urlParse(baseUrl + '/' + url.replace(/^\//g, ''), {});
|
|
||||||
}
|
|
||||||
|
|
||||||
return link.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function VideoPlayerError(props) {
|
|
||||||
return (
|
|
||||||
<div className="error-container">
|
|
||||||
<div className="error-container-inner">
|
|
||||||
<span className="icon-wrap">
|
|
||||||
<i className="material-icons">error_outline</i>
|
|
||||||
</span>
|
|
||||||
<span className="msg-wrap">{props.errorMessage}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoPlayerError.propTypes = {
|
|
||||||
errorMessage: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function VideoPlayer(props) {
|
|
||||||
const videoElemRef = useRef(null);
|
|
||||||
|
|
||||||
let player = null;
|
|
||||||
|
|
||||||
const playerStates = {
|
|
||||||
playerVolume: props.playerVolume,
|
|
||||||
playerSoundMuted: props.playerSoundMuted,
|
|
||||||
videoQuality: props.videoQuality,
|
|
||||||
videoPlaybackSpeed: props.videoPlaybackSpeed,
|
|
||||||
inTheaterMode: props.inTheaterMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
playerStates.playerVolume =
|
|
||||||
null === playerStates.playerVolume ? 1 : Math.max(Math.min(Number(playerStates.playerVolume), 1), 0);
|
|
||||||
playerStates.playerSoundMuted = null !== playerStates.playerSoundMuted ? playerStates.playerSoundMuted : !1;
|
|
||||||
playerStates.videoQuality = null !== playerStates.videoQuality ? playerStates.videoQuality : 'Auto';
|
|
||||||
playerStates.videoPlaybackSpeed = null !== playerStates.videoPlaybackSpeed ? playerStates.videoPlaybackSpeed : !1;
|
|
||||||
playerStates.inTheaterMode = null !== playerStates.inTheaterMode ? playerStates.inTheaterMode : !1;
|
|
||||||
|
|
||||||
function onClickNext() {
|
|
||||||
if (void 0 !== props.onClickNextCallback) {
|
|
||||||
props.onClickNextCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClickPrevious() {
|
|
||||||
if (void 0 !== props.onClickPreviousCallback) {
|
|
||||||
props.onClickPreviousCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPlayerStateUpdate(newState) {
|
|
||||||
if (playerStates.playerVolume !== newState.volume) {
|
|
||||||
playerStates.playerVolume = newState.volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerStates.playerSoundMuted !== newState.soundMuted) {
|
|
||||||
playerStates.playerSoundMuted = newState.soundMuted;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerStates.videoQuality !== newState.quality) {
|
|
||||||
playerStates.videoQuality = newState.quality;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerStates.videoPlaybackSpeed !== newState.playbackSpeed) {
|
|
||||||
playerStates.videoPlaybackSpeed = newState.playbackSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerStates.inTheaterMode !== newState.theaterMode) {
|
|
||||||
playerStates.inTheaterMode = newState.theaterMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== props.onStateUpdateCallback) {
|
|
||||||
props.onStateUpdateCallback(newState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initPlayer() {
|
|
||||||
if (null !== player || null !== props.errorMessage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!props.inEmbed) {
|
|
||||||
window.removeEventListener('focus', initPlayer);
|
|
||||||
document.removeEventListener('visibilitychange', initPlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!videoElemRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!props.inEmbed) {
|
|
||||||
videoElemRef.current.focus(); // Focus on player before instance init.
|
|
||||||
}
|
|
||||||
|
|
||||||
const subtitles = {
|
|
||||||
on: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== props.subtitlesInfo && null !== props.subtitlesInfo && props.subtitlesInfo.length) {
|
|
||||||
subtitles.languages = [];
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
while (i < props.subtitlesInfo.length) {
|
|
||||||
if (
|
|
||||||
void 0 !== props.subtitlesInfo[i].src &&
|
|
||||||
void 0 !== props.subtitlesInfo[i].srclang &&
|
|
||||||
void 0 !== props.subtitlesInfo[i].label
|
|
||||||
) {
|
|
||||||
subtitles.languages.push({
|
|
||||||
src: formatInnerLink(props.subtitlesInfo[i].src, props.siteUrl),
|
|
||||||
srclang: props.subtitlesInfo[i].srclang,
|
|
||||||
label: props.subtitlesInfo[i].label,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subtitles.languages.length) {
|
|
||||||
subtitles.on = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player = new MediaPlayer(
|
|
||||||
videoElemRef.current,
|
|
||||||
{
|
|
||||||
enabledTouchControls: true,
|
|
||||||
sources: props.sources,
|
|
||||||
poster: props.poster,
|
|
||||||
autoplay: props.enableAutoplay,
|
|
||||||
bigPlayButton: true,
|
|
||||||
controlBar: {
|
|
||||||
theaterMode: props.hasTheaterMode,
|
|
||||||
pictureInPicture: false,
|
|
||||||
next: props.hasNextLink ? true : false,
|
|
||||||
previous: props.hasPreviousLink ? true : false,
|
|
||||||
},
|
|
||||||
subtitles: subtitles,
|
|
||||||
cornerLayers: props.cornerLayers,
|
|
||||||
videoPreviewThumb: props.previewSprite,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
volume: playerStates.playerVolume,
|
|
||||||
soundMuted: playerStates.playerSoundMuted,
|
|
||||||
theaterMode: playerStates.inTheaterMode,
|
|
||||||
theSelectedQuality: void 0, // @note: Allow auto resolution selection by sources order.
|
|
||||||
theSelectedPlaybackSpeed: playerStates.videoPlaybackSpeed || 1,
|
|
||||||
},
|
|
||||||
props.info,
|
|
||||||
[0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],
|
|
||||||
onPlayerStateUpdate,
|
|
||||||
onClickNext,
|
|
||||||
onClickPrevious
|
|
||||||
);
|
|
||||||
|
|
||||||
if (void 0 !== props.onPlayerInitCallback) {
|
|
||||||
props.onPlayerInitCallback(player, videoElemRef.current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function unsetPlayer() {
|
|
||||||
if (null === player) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
videojs(videoElemRef.current).dispose();
|
|
||||||
player = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.inEmbed || document.hasFocus() || 'visible' === document.visibilityState) {
|
|
||||||
initPlayer();
|
|
||||||
} else {
|
|
||||||
window.addEventListener('focus', initPlayer);
|
|
||||||
document.addEventListener('visibilitychange', initPlayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// We don't need this because we have a custom function in frontend/src/static/js/components/media-viewer/VideoViewer/index.js:617
|
|
||||||
player && player.player.one('loadedmetadata', () => {
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
const paramT = Number(urlParams.get('t'));
|
|
||||||
const timestamp = !isNaN(paramT) ? paramT : 0;
|
|
||||||
player.player.currentTime(timestamp);
|
|
||||||
}); */
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
unsetPlayer();
|
|
||||||
|
|
||||||
if (void 0 !== props.onUnmountCallback) {
|
|
||||||
props.onUnmountCallback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return null === props.errorMessage ? (
|
|
||||||
<video ref={videoElemRef} className="video-js vjs-mediacms native-dimensions"></video>
|
|
||||||
) : (
|
|
||||||
<div className="error-container">
|
|
||||||
<div className="error-container-inner">
|
|
||||||
<span className="icon-wrap">
|
|
||||||
<i className="material-icons">error_outline</i>
|
|
||||||
</span>
|
|
||||||
<span className="msg-wrap">{props.errorMessage}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoPlayer.propTypes = {
|
|
||||||
playerVolume: PropTypes.string,
|
|
||||||
playerSoundMuted: PropTypes.bool,
|
|
||||||
videoQuality: PropTypes.string,
|
|
||||||
videoPlaybackSpeed: PropTypes.number,
|
|
||||||
inTheaterMode: PropTypes.bool,
|
|
||||||
siteId: PropTypes.string.isRequired,
|
|
||||||
siteUrl: PropTypes.string.isRequired,
|
|
||||||
errorMessage: PropTypes.string,
|
|
||||||
cornerLayers: PropTypes.object,
|
|
||||||
subtitlesInfo: PropTypes.array.isRequired,
|
|
||||||
inEmbed: PropTypes.bool.isRequired,
|
|
||||||
sources: PropTypes.array.isRequired,
|
|
||||||
info: PropTypes.object.isRequired,
|
|
||||||
enableAutoplay: PropTypes.bool.isRequired,
|
|
||||||
hasTheaterMode: PropTypes.bool.isRequired,
|
|
||||||
hasNextLink: PropTypes.bool.isRequired,
|
|
||||||
hasPreviousLink: PropTypes.bool.isRequired,
|
|
||||||
poster: PropTypes.string,
|
|
||||||
previewSprite: PropTypes.object,
|
|
||||||
onClickPreviousCallback: PropTypes.func,
|
|
||||||
onClickNextCallback: PropTypes.func,
|
|
||||||
onPlayerInitCallback: PropTypes.func,
|
|
||||||
onStateUpdateCallback: PropTypes.func,
|
|
||||||
onUnmountCallback: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
VideoPlayer.defaultProps = {
|
|
||||||
errorMessage: null,
|
|
||||||
cornerLayers: {},
|
|
||||||
};
|
|
||||||
Loading…
x
Reference in New Issue
Block a user