rn-yt-player
Version:
A package for React Native to embed YouTube video in React Native app without pain. It customizable, so that you can embed secure videos with it.
158 lines (155 loc) • 7.27 kB
JavaScript
import React, { useRef, useState, memo } from 'react';
import WebView from 'react-native-webview';
import { View, ActivityIndicator, StyleSheet } from 'react-native';
const YouTubePlayer = memo(
({
accentColor,
hideCards,
videoSource,
startVideoFrom,
innerPlayButtonColor,
playButtonColor,
hideYTLogo,
hideTopBar,
hideSettingButton,
hideCaptionButton,
hideControls,
width,
height,
children,
loaderContainerStyle,
autoPlay,
onError
}) => {
const [videoLoaded, setVideoLoaded] = useState(false);
const themeColor = accentColor || '#FFFFFF';
const webRef = useRef(null);
const startDuration = String(startVideoFrom || 0);
width = width || '100%';
height = height || 200;
const PLAYER_DIMMENSIONS = { width: width, height: height };
const LOADER_OVERLAYER_STYLE = { marginTop: -1 * height };
videoSource = videoSource || '_CuSlwOmDOo';
let vidId = '';
if (videoSource.indexOf('youtu.be') !== -1) {
vidId = videoSource.split('.be/')[1];
} else if (videoSource.indexOf('/embed/') !== -1) {
vidId = videoSource.split('/embed/')[1];
} else if (videoSource.indexOf('?v=') !== -1) {
vidId = videoSource.split('&')[0];
vidId = vidId.split('?v=')[1];
} else {
vidId = videoSource;
}
const YT_URL = `https://www.youtube.com/embed/${vidId}?start=${startDuration}${autoPlay === true ? '&autoplay=1' : ''}`;
function removeBranding() {
const JAVASCRIPT_TO_BE_EXECUTED = `
const removeThisElementBuddy = (selector) =>{
document.querySelectorAll(selector).forEach(e=>e.remove());
};
${hideCards === true ? `removeThisElementBuddy(".ytp-cards-teaser");` : ''}
${hideTopBar === true
? `removeThisElementBuddy(".ytp-chrome-top");`
: ``
}
document.querySelector(".ytp-gradient-top").remove();
${hideYTLogo === true
? `removeThisElementBuddy("a");`
: ``
}
${hideControls
? `removeThisElementBuddy(".ytp-chrome-bottom");removeThisElementBuddy(".ytp-gradient-bottom");`
: ``
}
removeThisElementBuddy("watch-again-on-youtube-endscreen");
const style = document.createElement('style');
style.innerHTML = \`.ytp-endscreen-previous, .ytp-endscreen-next{display:none!important;}.watch-again-on-youtube-endscreen{display:none!important;}
${hideCards === true ? `.ytp-cards-teaser{display:none!important;}` : ''}${hideControls
? `.ytp-chrome-bottom, .ytp-gradient-bottom{display:none!important;}`
: ``
}${hideCaptionButton
? `.ytp-subtitles-button{display:none!important;}`
: ``
}${hideSettingButton ? `.ytp-settings-button{display:none!important;}` : ``
}${hideTopBar === true
? `.ytp-show-cards-title{display:none!important;}`
: ``
}.ytp-gradient-bottom{background-color: #1e1e1e!important;background-image:unset!important;height:35px!important;opacity:0.9!important;}.ytp-gradient-top, .ytp-gradient-bottom{background-image:unset!important;}.ytp-progress-linear-live-buffer, .ytp-swatch-background-color{background:${themeColor}!important;}.iv-branding{display:none!important}.ytp-menuitem:nth-child(1),.ytp-menuitem:nth-child(4){display:none!important;}.ytp-pause-overlay-container{display:none!important;}.ytp-ce-element{display:none!important}.ytp-videowall-still{display:none!important;}\`;
document.querySelector("body").appendChild(style);
document.querySelector(".ytp-large-play-button").innerHTML = \`<svg width="99" height="99" viewBox="0 0 99 99" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="30" y="26" width="39" height="48" fill="${innerPlayButtonColor || '#FFFFFF'
}"/><path d="M49.5 8.25C26.73 8.25 8.25 26.73 8.25 49.5C8.25 72.27 26.73 90.75 49.5 90.75C72.27 90.75 90.75 72.27 90.75 49.5C90.75 26.73 72.27 8.25 49.5 8.25ZM41.25 63.9375V35.0625C41.25 33.3713 43.1888 32.3813 44.55 33.4125L63.8138 47.85C64.9275 48.675 64.9275 50.325 63.8138 51.15L44.55 65.5875C43.1888 66.6187 41.25 65.6287 41.25 63.9375Z" fill="${playButtonColor || accentColor || '#000000'
}"/></svg>\`;
window.ReactNativeWebView.postMessage(200);
`;
webRef.current.injectJavaScript(JAVASCRIPT_TO_BE_EXECUTED);
}
function handleMessage(event) {
const response = parseInt(event.nativeEvent.data);
if (response === 200) {
setVideoLoaded(true);
}
}
function checkProgress(r) {
if (videoLoaded === true) {
setVideoLoaded(false);
}
let nextUrl = r.nativeEvent.url.replaceAll('https://', '');
nextUrl = nextUrl.replaceAll('http://', '');
nextUrl = nextUrl.split('?')[0];
nextUrl = nextUrl.split('/')[1];
if (nextUrl !== 'embed') {
webRef.current.stopLoading();
webRef.current.goBack();
}
}
function onErrorMethod() {
onError();
}
return (
<View style={PLAYER_DIMMENSIONS}>
<WebView
ref={webRef}
source={{ uri: YT_URL }}
style={PLAYER_DIMMENSIONS}
onLoadEnd={removeBranding}
onLoadStart={checkProgress}
onMessage={handleMessage}
allowsFullscreenVideo={true}
onError={onErrorMethod}
setBuiltInZoomControls={false}
scrollEnabled={false}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
/>
{!videoLoaded ? (
children ? (
<View
style={[
PLAYER_DIMMENSIONS,
LOADER_OVERLAYER_STYLE,
loaderContainerStyle,
]}>
{children}
</View>
) : (
<View
style={[
style.overLayer,
PLAYER_DIMMENSIONS,
LOADER_OVERLAYER_STYLE,
]}>
<ActivityIndicator size="large" color={accentColor || 'orange'} />
</View>
)
) : null}
</View>
);
},
);
export default YouTubePlayer;
const style = StyleSheet.create({
overLayer: {
backgroundColor: '#404040',
justifyContent: 'center',
},
});