import React from 'react'; import PropTypes from 'prop-types'; import { VideoViewerActions } from '../../../utils/actions/'; import { SiteContext, SiteConsumer } from '../../../utils/contexts/'; import { PageStore, MediaPageStore, VideoViewerStore } from '../../../utils/stores/'; import { addClassname, removeClassname, formatInnerLink } from '../../../utils/helpers/'; import { BrowserCache, UpNextLoaderView, MediaDurationInfo, PlayerRecommendedMedia } from '../../../utils/classes/'; import { orderedSupportedVideoFormats, videoAvailableCodecsAndResolutions, extractDefaultVideoResolution, } from './functions'; import { VideoPlayer, VideoPlayerError } from '../../video-player/VideoPlayer'; import '../VideoViewer.scss'; function filterVideoEncoding(encoding_status) { switch (encoding_status) { case 'running': MediaPageStore.set('media-load-error-type', 'encodingRunning'); MediaPageStore.set('media-load-error-message', 'Media encoding is currently running. Try again in few minutes.'); break; case 'pending': MediaPageStore.set('media-load-error-type', 'encodingPending'); MediaPageStore.set('media-load-error-message', 'Media encoding is pending'); break; case 'fail': MediaPageStore.set('media-load-error-type', 'encodingFailed'); MediaPageStore.set('media-load-error-message', 'Media encoding failed'); break; } } export default class VideoViewer extends React.PureComponent { constructor(props) { super(props); this.state = { displayPlayer: false, }; this.videoSources = []; filterVideoEncoding(this.props.data.encoding_status); if (null !== MediaPageStore.get('media-load-error-type')) { this.state.displayPlayer = true; return; } if ('string' === typeof this.props.data.poster_url) { this.videoPoster = formatInnerLink(this.props.data.poster_url, this.props.siteUrl); } else if ('string' === typeof this.props.data.thumbnail_url) { this.videoPoster = formatInnerLink(this.props.data.thumbnail_url, this.props.siteUrl); } this.videoInfo = videoAvailableCodecsAndResolutions(this.props.data.encodings_info, this.props.data.hls_info); const resolutionsKeys = Object.keys(this.videoInfo); if (!resolutionsKeys.length) { this.videoInfo = null; } else { let defaultResolution = VideoViewerStore.get('video-quality'); if (null === defaultResolution || ('Auto' === defaultResolution && void 0 === this.videoInfo['Auto'])) { defaultResolution = 720; // Default resolution. } let defaultVideoResolution = extractDefaultVideoResolution(defaultResolution, this.videoInfo); if ('Auto' === defaultResolution && void 0 !== this.videoInfo['Auto']) { this.videoSources.push({ src: this.videoInfo['Auto'].url[0] }); } const supportedFormats = orderedSupportedVideoFormats(); let srcUrl, k; k = 0; while (k < this.videoInfo[defaultVideoResolution].format.length) { if ('hls' === this.videoInfo[defaultVideoResolution].format[k]) { this.videoSources.push({ src: this.videoInfo[defaultVideoResolution].url[k] }); break; } k += 1; } for (k in this.props.data.encodings_info[defaultVideoResolution]) { if (this.props.data.encodings_info[defaultVideoResolution].hasOwnProperty(k)) { if (supportedFormats.support[k]) { srcUrl = this.props.data.encodings_info[defaultVideoResolution][k].url; if (!!srcUrl) { srcUrl = formatInnerLink(srcUrl, this.props.siteUrl); this.videoSources.push({ src: srcUrl /*.replace("http://", "//").replace("https://", "//")*/, encodings_status: this.props.data.encodings_info[defaultVideoResolution][k].status, }); } } } } // console.log( supportedFormats ); // console.log( this.videoInfo ); // console.log( defaultVideoResolution ); // console.log( this.videoSources ); } if (this.videoSources.length) { if ( !this.props.inEmbed && 1 === this.videoSources.length && 'running' === this.videoSources[0].encodings_status ) { MediaPageStore.set('media-load-error-type', 'encodingRunning'); MediaPageStore.set( 'media-load-error-message', 'Media encoding is currently running. Try again in few minutes.' ); return; } } else { switch (MediaPageStore.get('media-load-error-type')) { case 'encodingRunning': case 'encodingPending': case 'encodingFailed': break; default: console.warn('VIDEO DEBUG:', "Video files don't exist"); } } PageStore.on('switched_media_auto_play', this.onUpdateMediaAutoPlay.bind(this)); this.browserCache = new BrowserCache(SiteContext._currentValue.id, 86400); // Keep cache data "fresh" for one day. const _MediaDurationInfo = new MediaDurationInfo(); _MediaDurationInfo.update(this.props.data.duration); this.durationISO8601 = _MediaDurationInfo.ISO8601(); this.playerElem = null; this.playerInstance = null; this.onPlayerInit = this.onPlayerInit.bind(this); this.onClickNext = this.onClickNext.bind(this); this.onClickPrevious = this.onClickPrevious.bind(this); this.onStateUpdate = this.onStateUpdate.bind(this); this.onVideoEnd = this.onVideoEnd.bind(this); this.onVideoRestart = this.onVideoRestart.bind(this); } componentDidMount() { if (this.videoSources.length) { this.recommendedMedia = this.props.data.related_media.length ? new PlayerRecommendedMedia( this.props.data.related_media, this.props.inEmbed, !PageStore.get('config-media-item').displayViews ) : null; this.upNextLoaderView = !this.props.inEmbed && this.props.data.related_media.length ? new UpNextLoaderView(this.props.data.related_media[0]) : null; let topLeftHtml = null; if (this.props.inEmbed) { let titleLink = document.createElement('a'); let userThumbLink = document.createElement('a'); topLeftHtml = document.createElement('div'); topLeftHtml.setAttribute('class', 'media-links-top-left'); if (titleLink) { titleLink.setAttribute('class', 'title-link'); titleLink.setAttribute('href', this.props.data.url); titleLink.setAttribute('title', this.props.data.title); titleLink.setAttribute('target', '_blank'); titleLink.innerHTML = this.props.data.title; } if (userThumbLink) { userThumbLink.setAttribute('class', 'user-thumb-link'); userThumbLink.setAttribute('href', formatInnerLink(this.props.data.author_profile, this.props.siteUrl)); userThumbLink.setAttribute('title', this.props.data.author_name); userThumbLink.setAttribute('target', '_blank'); userThumbLink.setAttribute( 'style', 'background-image:url(' + formatInnerLink(MediaPageStore.get('media-author-thumbnail-url'), this.props.siteUrl) + ')' ); } topLeftHtml.appendChild(userThumbLink); topLeftHtml.appendChild(titleLink); } const mediaUrl = MediaPageStore.get('media-url'); let bottomRightHTML = ''; bottomRightHTML += '
\
\ \
\
'; this.cornerLayers = { topLeft: topLeftHtml, topRight: this.upNextLoaderView ? this.upNextLoaderView.html() : null, bottomLeft: this.recommendedMedia ? this.recommendedMedia.html() : null, bottomRight: this.props.inEmbed ? bottomRightHTML : null, }; this.setState( { displayPlayer: true, }, function () { setTimeout(function () { const shareBtn = document.querySelector('.share-video-btn'); const shareWrap = document.querySelector('.share-options-wrapper'); const shareInner = document.querySelector('.share-options-inner'); if (shareBtn) { shareBtn.addEventListener('click', function (ev) { addClassname(document.querySelector('.video-js.vjs-mediacms'), 'vjs-visible-share-options'); }); } if (shareWrap) { shareWrap.addEventListener('click', function (ev) { if (ev.target === shareInner || ev.target === shareWrap) { removeClassname(document.querySelector('.video-js.vjs-mediacms'), 'vjs-visible-share-options'); } }); } }, 1000); } ); } } componentWillUnmount() { this.unsetRecommendedMedia(); } initRecommendedMedia() { if (null === this.recommendedMedia) { return; } if (!this.props.inEmbed) { this.recommendedMedia.init(); } this.playerInstance.player.on('fullscreenchange', this.recommendedMedia.onResize); PageStore.on('window_resize', this.recommendedMedia.onResize); VideoViewerStore.on('changed_viewer_mode', this.recommendedMedia.onResize); } unsetRecommendedMedia() { if (null === this.recommendedMedia) { return; } this.playerInstance.player.off('fullscreenchange', this.recommendedMedia.onResize); PageStore.removeListener('window_resize', this.recommendedMedia.onResize); VideoViewerStore.removeListener('changed_viewer_mode', this.recommendedMedia.onResize); this.recommendedMedia.destroy(); } onClickNext() { const playlistId = MediaPageStore.get('playlist-id'); let nextLink; if (playlistId) { nextLink = MediaPageStore.get('playlist-next-media-url'); if (null === nextLink) { nextLink = this.props.data.related_media[0].url; } } else if (!this.props.inEmbed) { nextLink = this.props.data.related_media[0].url; } window.location.href = nextLink; } onClickPrevious() { const playlistId = MediaPageStore.get('playlist-id'); let previousLink; if (playlistId) { previousLink = MediaPageStore.get('playlist-previous-media-url'); if (null === previousLink) { previousLink = this.props.data.related_media[0].url; } } else if (!this.props.inEmbed) { previousLink = this.props.data.related_media[0].url; } window.location.href = previousLink; } onStateUpdate(newState) { if (VideoViewerStore.get('in-theater-mode') !== newState.theaterMode) { VideoViewerActions.set_viewer_mode(newState.theaterMode); } if (VideoViewerStore.get('player-volume') !== newState.volume) { VideoViewerActions.set_player_volume(newState.volume); } if (VideoViewerStore.get('player-sound-muted') !== newState.soundMuted) { VideoViewerActions.set_player_sound_muted(newState.soundMuted); } if (VideoViewerStore.get('video-quality') !== newState.quality) { VideoViewerActions.set_video_quality(newState.quality); } if (VideoViewerStore.get('video-playback-speed') !== newState.playbackSpeed) { VideoViewerActions.set_video_playback_speed(newState.playbackSpeed); } } onPlayerInit(instance, elem) { this.playerElem = elem; this.playerInstance = instance; if (this.upNextLoaderView) { this.upNextLoaderView.setVideoJsPlayerElem(this.playerInstance.player.el_); this.onUpdateMediaAutoPlay(); } if (!this.props.inEmbed) { this.playerElem.parentNode.focus(); // Focus on player. } if (null !== this.recommendedMedia) { this.recommendedMedia.initWrappers(this.playerElem.parentNode); if (this.props.inEmbed) { this.playerInstance.player.one('pause', this.recommendedMedia.init); this.initRecommendedMedia(); } } this.playerInstance.player.one('ended', this.onVideoEnd); } onVideoRestart() { if (null !== this.recommendedMedia) { this.recommendedMedia.updateDisplayType('inline'); if (this.props.inEmbed) { this.playerInstance.player.one('pause', this.recommendedMedia.init); } this.playerInstance.player.one('ended', this.onVideoEnd); } } onVideoEnd() { if (null !== this.recommendedMedia) { if (!this.props.inEmbed) { this.initRecommendedMedia(); } this.recommendedMedia.updateDisplayType('full'); this.playerInstance.player.one('playing', this.onVideoRestart); } const playlistId = this.props.inEmbed ? null : MediaPageStore.get('playlist-id'); if (playlistId) { const moreMediaEl = document.querySelector('.video-player .more-media'); const actionsAnimEl = document.querySelector('.video-player .vjs-actions-anim'); this.upNextLoaderView.cancelTimer(); const nextMediaUrl = MediaPageStore.get('playlist-next-media-url'); if (nextMediaUrl) { if (moreMediaEl) { moreMediaEl.style.display = 'none'; } if (actionsAnimEl) { actionsAnimEl.style.display = 'none'; } window.location.href = nextMediaUrl; } this.upNextLoaderView.hideTimerView(); return; } if (this.upNextLoaderView) { if (PageStore.get('media-auto-play')) { this.upNextLoaderView.startTimer(); this.playerInstance.player.one( 'play', function () { this.upNextLoaderView.cancelTimer(); }.bind(this) ); } else { this.upNextLoaderView.cancelTimer(); } } } onUpdateMediaAutoPlay() { if (this.upNextLoaderView) { if (PageStore.get('media-auto-play')) { this.upNextLoaderView.showTimerView(this.playerInstance.isEnded()); } else { this.upNextLoaderView.hideTimerView(); } } } render() { let nextLink = null; let previousLink = null; const playlistId = this.props.inEmbed ? null : MediaPageStore.get('playlist-id'); if (playlistId) { nextLink = MediaPageStore.get('playlist-next-media-url'); previousLink = MediaPageStore.get('playlist-previous-media-url'); } else { nextLink = this.props.data.related_media.length && !this.props.inEmbed ? this.props.data.related_media[0].url : null; } const previewSprite = !!this.props.data.sprites_url ? { url: this.props.siteUrl + '/' + this.props.data.sprites_url.replace(/^\//g, ''), frame: { width: 160, height: 90, seconds: 10 }, } : null; return (
{this.state.displayPlayer && null !== MediaPageStore.get('media-load-error-type') ? ( ) : null} {this.state.displayPlayer && null == MediaPageStore.get('media-load-error-type') ? (
{(site) => ( )}
) : null}
); } } VideoViewer.defaultProps = { inEmbed: !0, siteUrl: PropTypes.string.isRequired, }; VideoViewer.propTypes = { inEmbed: PropTypes.bool, }; function findGetParameter(parameterName) { let result = null; let tmp = []; var items = location.search.substr(1).split('&'); for (let i = 0; i < items.length; i++) { tmp = items[i].split('='); if (tmp[0] === parameterName) { result = decodeURIComponent(tmp[1]); } } return result; } function handleCanvas(videoElem) { // Make sure it's a video element if (!videoElem || !videoElem.tagName || videoElem.tagName.toLowerCase() !== 'video') { console.error('Invalid video element:', videoElem); return; } const Player = videojs(videoElem); Player.playsinline(true); Player.on('loadedmetadata', function () { const muted = parseInt(findGetParameter('muted')); const autoplay = parseInt(findGetParameter('autoplay')); const timestamp = parseInt(findGetParameter('t')); if (muted == 1) { Player.muted(true); } if (timestamp >= 0 && timestamp < Player.duration()) { // Start the video from the given time Player.currentTime(timestamp); } else if (timestamp >= 0 && timestamp >= Player.duration()) { // Restart the video if the given time is greater than the duration Player.play(); } if (autoplay === 1) { Player.play(); } }); } const observer = new MutationObserver((mutations, me) => { const playerContainer = document.querySelector('.video-js.vjs-mediacms'); if (playerContainer) { const video = playerContainer.querySelector('video'); if (video) { handleCanvas(video); me.disconnect(); } } }); observer.observe(document, { childList: true, subtree: true, });