@mpxjs/webpack-plugin
Version:
mpx compile core
254 lines (253 loc) • 8.92 kB
JSX
/**
* ✔ src
* ✘ duration
* ✔ controls
* ✘ danmu-list
* ✘ danmu-btn
* ✘ enable-danmu
* ✔ autoplay
* ✔ loop
* ✔ muted
* ✔ initial-time
* ✘ page-gesture
* ✘ direction
* ✘ show-progress
* ✘ show-fullscreen-btn
* ✘ show-play-btn
* ✘ show-center-play-btn
* ✘ enable-progress-gesture
* ✔ object-fit
* ✔ poster
* ✘ show-mute-btn
* ✘ title
* ✘ play-btn-position
* ✘ enable-play-gesture
* ✘ auto-pause-if-navigate
* ✘ auto-pause-if-open-native
* ✘ vslide-gesture
* ✘ vslide-gesture-in-fullscreen
* ✘ show-bottom-progress(use show-progress)
* ✘ ad-unit-id
* ✘ poster-for-crawler
* ✘ show-casting-button
* ✘ picture-in-picture-mode
* ✘ picture-in-picture-show-progress
* ✘ picture-in-picture-init-position
* ✔ enable-auto-rotation (only ios)
* ✘ show-screen-lock-button
* ✘ show-snapshot-button
* ✘ show-background-playback-button
* ✘ background-poster
* ✘ referrer-policy
* ✔ is-drm
* ✘ is-live
* ✔ provision-url(android)
* ✔ certificate-url(ios)
* ✔ license-url
* ✔ preferred-peak-bit-rate
* ✔ bindplay
* ✔ bindpause
* ✔ bindended
* ✘ bindtimeupdate
* ✔ bindfullscreenchange
* ✔ bindwaiting
* ✔ binderror
* ✘ bindprogress
* ✔ bindloadedmetadata
* ✔ bindcontrolstoggle(only android)
* ✘ bindenterpictureinpicture
* ✘ bindleavepictureinpicture
* ✔ bindseekcomplete
* ✘ bindcastinguserselect
* ✘ bindcastingstatechange
* ✘ bindcastinginterrupt
*/
import { useRef, forwardRef, createElement } from 'react';
import Video, { DRMType } from 'react-native-video';
import { StyleSheet, View } from 'react-native';
import { splitProps, useTransformStyle, useLayout, extendObject } from './utils';
import useInnerProps, { getCustomEvent } from './getInnerListeners';
import useNodesRef from './useNodesRef';
import Portal from './mpx-portal';
const styles = StyleSheet.create({
container: {
width: 300,
height: 225
},
video: {
flex: 1
}
});
const MpxVideo = forwardRef((videoProps, ref) => {
const { innerProps: props = {} } = splitProps(videoProps);
const { src, autoplay = false, loop = false, muted = false, controls = true, poster = '', bindplay, bindpause, bindended, bindtimeupdate, bindfullscreenchange, bindwaiting, binderror, bindloadedmetadata, bindcontrolstoggle, bindseekcomplete, style, 'initial-time': initialTime = 0, 'object-fit': objectFit = 'contain', 'is-drm': isDrm = false, 'provision-url': provisionUrl, 'certificate-url': certificateUrl, 'license-url': licenseUrl, 'preferred-peak-bit-rate': preferredPeakBitRate = 0, 'enable-auto-rotation': enableAutoRotation = false, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
const videoRef = useRef(null);
const viewRef = useRef(null);
const videoInfoRef = useRef({});
const propsRef = useRef({});
propsRef.current = props;
const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(extendObject({}, styles.container, style), {
enableVar,
externalVarContext,
parentFontSize,
parentWidth,
parentHeight
});
const { layoutRef, layoutStyle, layoutProps } = useLayout({
props,
hasSelfPercent,
setWidth,
setHeight,
nodeRef: viewRef
});
useNodesRef(props, ref, viewRef, {
style: normalStyle,
node: {
play,
pause,
stop,
seek,
requestFullScreen,
exitFullScreen
}
});
function handleProgress(data) {
const { currentTime } = data;
bindtimeupdate && bindtimeupdate(getCustomEvent('timeupdate', {}, {
detail: {
currentTime,
duration: videoInfoRef.current.duration
},
layoutRef
}, propsRef.current));
}
function handleEnd() {
bindended(getCustomEvent('end', {}, { layoutRef }, propsRef.current));
}
function handleWaiting({ isBuffering }) {
if (isBuffering) {
bindwaiting(getCustomEvent('waiting', {}, { layoutRef }, propsRef.current));
}
}
function handleSeekcomplete({ seekTime }) {
// 手动拖拽进度条场景,android 可以触发,ios 不可以
bindseekcomplete(getCustomEvent('seekcomplete', {}, {
detail: {
position: __mpx_mode__ !== 'ios' ? seekTime * 1000 : seekTime
},
layoutRef
}, propsRef.current));
}
function handleEnterFullScreen() {
bindfullscreenchange && bindfullscreenchange(getCustomEvent('fullscreenchange', {}, { detail: { fullScreen: 1 }, layoutRef }, propsRef.current));
}
function handleExitFullScreen() {
bindfullscreenchange && bindfullscreenchange(getCustomEvent('fullscreenchange', {}, { detail: { fullScreen: 0 }, layoutRef }, propsRef.current));
}
function handlePlaybackRateChange({ playbackRate }) {
if (playbackRate === 0) {
bindpause && bindpause(getCustomEvent('pause', {}, { layoutRef }, propsRef.current));
}
else {
bindplay && bindplay(getCustomEvent('play', {}, { layoutRef }, propsRef.current));
}
}
function handleAndroidControlsVisibilityChange({ isVisible }) {
bindcontrolstoggle(getCustomEvent('progress', {}, {
detail: {
show: isVisible
},
layoutRef
}, propsRef.current));
}
function handleVideoLoad(data) {
const { naturalSize, duration } = data;
if (initialTime) {
videoRef.current && videoRef.current.seek(initialTime);
}
videoInfoRef.current = data;
bindloadedmetadata && bindloadedmetadata(getCustomEvent('loadedmetadata', {}, {
detail: {
width: naturalSize.width,
height: naturalSize.height,
duration
},
layoutRef
}, propsRef.current));
}
function handleError({ error }) {
binderror && binderror(getCustomEvent('play', {}, { detail: { errMsg: error.localizedFailureReason }, layoutRef }, propsRef.current));
}
function play() {
videoRef.current && videoRef.current.resume();
}
function pause() {
videoRef.current && videoRef.current.pause();
}
function seek(position) {
videoRef.current && videoRef.current.seek(position);
}
function stop() {
videoRef.current && videoRef.current.pause();
seek(0);
}
function exitFullScreen() {
videoRef.current && videoRef.current.setFullScreen(false);
}
function requestFullScreen() {
videoRef.current && videoRef.current.setFullScreen(true);
}
const source = {
uri: src
};
if (isDrm) {
source.drm = {
type: DRMType.FAIRPLAY,
certificateUrl: __mpx_mode__ !== 'ios' ? provisionUrl : certificateUrl,
licenseServer: licenseUrl
};
}
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
style: styles.video,
ref: videoRef,
source,
paused: !autoplay,
repeat: loop,
muted,
controls,
maxBitRate: preferredPeakBitRate,
fullscreenAutorotate: enableAutoRotation,
resizeMode: objectFit === 'fill' ? 'stretch' : objectFit,
poster: controls ? poster : '',
onProgress: bindtimeupdate && handleProgress,
onEnd: bindended && handleEnd,
onError: binderror && handleError,
onBuffer: bindwaiting && handleWaiting,
onSeek: bindseekcomplete && handleSeekcomplete,
onPlaybackRateChange: (bindpause || bindplay) && handlePlaybackRateChange,
onFullscreenPlayerDidPresent: bindfullscreenchange && handleEnterFullScreen,
onFullscreenPlayerWillDismiss: bindfullscreenchange && handleExitFullScreen,
onControlsVisibilityChange: bindcontrolstoggle && handleAndroidControlsVisibilityChange,
onLoad: handleVideoLoad
}), [
'src',
'autoplay',
'loop',
'bindplay',
'bindpause',
'bindended',
'bindtimeupdate',
'bindfullscreenchange',
'bindwaiting',
'binderror',
'bindloadedmetadata',
'bindcontrolstoggle',
'bindseekcomplete'
], { layoutRef });
let videoComponent = createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
if (hasPositionFixed) {
videoComponent = createElement(Portal, null, videoComponent);
}
return videoComponent;
});
export default MpxVideo;