I need some help trying to figure how to use hls.js in react.
Let me explain the situation I have to fetch the m3u8 from an api I'm able to make it work from a basic html with the <script>
tag but when i try to implement it on react it doesn't work any help is appreciated. This is what I've got so far:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
import Grid from "@material-ui/core/Grid";
import ButtonBase from "@material-ui/core/ButtonBase";
import CircularProgress from "@material-ui/core/CircularProgress";
import Hls from "hls.js";
const styles = theme => ({
root: {
flexGrow: 1,
paddingTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 2,
marginBottom: 24,
marginLeft: 24,
marginRight: 60
},
image: {
marginLeft: 24,
width: 200,
height: 200
},
img: {
display: "block",
width: 200,
height: 200,
maxWidth: "100%",
maxHeight: "100%"
},
detail: {
marginLeft: 16
},
progress: {
display: "flex",
justifyContent: "center",
alignItems: "center"
}
});
class Video extends Component {
constructor(props) {
super(props);
}
componentWillReceiveProps(props) {
if (props.episode && this.player) {
var hlsUrl = props.episode.assets.hls;
var video = this.player;
if (video.canPlayType("application/vnd.apple.mpegurl")) {
// If HLS is natively supported, let the browser do the work!
video.src = "hlsUrl";
video.addEventListener("loadedmetadata", function() {
video.play();
});
} else if (Hls.isSupported()) {
// If the browser supports MSE, use hls.js to play the video
var hls = new Hls({
// This configuration is required to insure that only the
// viewer can access the content by sending a session cookie
// to api.video service
xhrSetup: function(xhr, url) {
xhr.withCredentials = true;
}
});
hls.loadSource(hlsUrl);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function() {
video.play();
});
} else {
alert("Please use a modern browser to play the video");
}
}
}
handleSerieClick = () => {
this.props.history.push("/" + this.props.serie.apiName);
};
_onTouchInsidePlayer() {
if (this.player.paused) {
this.player.play();
} else {
this.player.pause();
}
}
render() {
const { classes, theme } = this.props;
if (this.props.episode) {
const { assets, title, description, videoId } = this.props.episode;
return (
<Grid className={classes.root} item xs={12}>
<video
controls
onClick={this._onTouchInsidePlayer}
ref={player => (this.player = player)}
autoPlay={true}
/>
</Grid>
);
} else {
return (
<Grid className={classes.progress} item xs={12}>
<CircularProgress size={100} />
</Grid>
);
}
}
}
export default withStyles(styles, { withTheme: true })(Video);
This is the code that works with <script>
tag
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="video"></video>
<script>
var hlsUrl = 'https://cdn.libcast.net/stream/3de8ff01-18f7-4262-a1f2-abeeb9bb962b/hls/manifest.hls';
var video = document.getElementById('video');
if (video.canPlayType('application/vnd.apple.mpegurl')) {
// If HLS is natively supported, let the browser do the work!
video.src = 'hlsUrl';
video.addEventListener('loadedmetadata',function() {
video.play();
});
} else if (Hls.isSupported()) {
// If the browser supports MSE, use hls.js to play the video
var hls = new Hls({
// This configuration is required to insure that only the
// viewer can access the content by sending a session cookie
// to api.video service
xhrSetup: function(xhr, url) { xhr.withCredentials = true; }
});
hls.loadSource(hlsUrl);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED,function() {
video.play();
});
} else {
alert('Please use a modern browser to play the video');
}
</script>
I pass the hls source from a parent component in the props and in componentWillRecieveProps i try to use the source to run the player
EDIT
THe problem seems to be that <video>
tag is undefined when I try to apply the source.
Initing hls in componentWillReceiveProps
is probably "too early". Refs are created during the render execution so your this.video
is probably null
at that time.
Try moving your logic into componentDidMount
(if you pass proper props from the beginnig) or at least componentDidUpdate
.