Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How can I create quality controls option for my project if it's HLS, or else just attach mp4 video and play? #734

Answered by realamirhe
huy232 asked this question in Q&A
Discussion options

Hello, can I ask for more detail about my project, I'm trying to use Plyr-react to implement video into my project. I'm using React + Javascript, not Typescript so there's some example written in Typescript and I can't exactly do the following like that.

I have the mp4 URL or m3u8 URL for HLS, it depends on the Anime I watched.

How can I:

  1. Only attach the mp4 URL into Plyr and play. No quality control is needed.
  2. If it's m3u8 I want to add quality controls to it, because my m3u8 does support [480, 720, 1080] resolution (I've loaded Hls.Events.MANIFEST_PARSED to see it and it does exist, but I really don't know how to implement it into Plyr)

I have read a few documents but I'm still confused about how to implement them into my project.

From this code: I've succeeded to play the m3u8 URL video, but I can't change quality control because I really don't know how to implement them. And I don't know how to implement the video if it's the mp4 URL...

I need a few more examples, it doesn't have to be exactly solved my problem but I need some guidance. I'm really stuck, thanks for reading my post. (In the useEffect I have 2 responses, feel free to skip the first response, it just to get information and loaded the ID to implement it into second request, the main code started from the second response, it's where I create the This is mp4 and This is m3u8)

Here's my code:

import { useState, useEffect, useRef } from "react"
import { useParams } from "react-router-dom"
import axios from "axios"
import Plyr from "plyr-react"
import Hls from "hls.js"
import "plyr-react/dist/plyr.css"
function AnimeWatch({ instance }) {
	const videoPlayer = useRef(null)
	const { anime } = useParams()
	const queryParams = new URLSearchParams(window.location.search)
	const index = queryParams.get("index")
	const [info, setInfo] = useState([])
	const [titleAnime, setTitleAnime] = useState("")
	const [currentEpisodeName, setCurrentEpisodeName] = useState("")
	useEffect(() => {
		const CancelToken = axios.CancelToken
		const source = CancelToken.source()
		const getList = async () => {
			await instance
				.get(`/watch/${anime}`, {
					cancelToken: source.token,
				})
				.then(async (response) => {
					const mainId = response.data.data.id
					const numIndex = Number(index)
					setTitleAnime(response.data.data.name)
					setInfo(response.data.data.episodes)
					await instance
						.get(`/anime/${mainId}/episodes/${numIndex}`, {
							cancelToken: source.token,
						})
						.then((res) => {
							// VIDEO URL IS HERE, it's can be mp4 or m3u8
							const videoUrl = res.data.data.videoSource
							
							let xhttp = new XMLHttpRequest()
							xhttp.open("HEAD", videoUrl)
							xhttp.onreadystatechange = function () {
								if (this.readyState == this.DONE) {
									if (this.getResponseHeader("Content-Type") === "video/mp4") {
										console.log("This is mp4")
									} else {
										console.log("This is m3u8")
										const defaultOptions = {}
										const videoElement = videoPlayer.current.plyr.media
										const hls = new Hls()
										hls.loadSource(videoUrl)
										hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
											const availableQualities = hls.levels.map((l) => l.height)
											defaultOptions.quality = {
												default: availableQualities[0],
												options: availableQualities,
												forced: true,
											}
										})
										hls.attachMedia(videoElement)
									}
								}
							}
							xhttp.send()
 setCurrentEpisodeName(res.data.data.full_name)
						})
				})
				.catch((thrown) => {
					if (axios.isCancel(thrown)) return
				})
		}
		getList()
		return () => {
			source.cancel()
		}
	}, [])
	return (
		<>
				<div>
					<Plyr ref={videoPlayer} />
				</div>
		</>
	)
}
export default AnimeWatch
You must be logged in to vote
  • The usePlyr hook is from our alpha release 4.0.0-alpha.1
  • In case you don't want to use forwardRef just pass the ref with a different name simply as props e.g. plyrRef, that should completely work :).

Here is the same component we have in our readme + new alpha release integration + type removed
https://codesandbox.io/s/silent-hooks-tpsbe?file=/src/HLS-javascript.jsx

Replies: 2 comments 7 replies

Comment options

Hi @huy232

We are working on a stand-alone integration, ready to use and bug-free in the future, so your feedback is always welcomed.

For the issue you mentioned
The first one has been solved I guess and these #656 #654 #652 can help you.

For the second one, I guess we got an issue which was with the plyr package itself. I will test that out soon.

It would be helpful if you can make a runnable code on the code sandbox to make it possible to solve your exact concern.

You must be logged in to vote
0 replies
Comment options

Hi @amirHossein-Ebrahimi
Yesterday, I was able to implement the mp4 into my video using setState, I think that's correct, right now I just want to have quality controls over HLS but I still really don't know-how.

This is the code sandbox that is runnable, I've made a few changes for more simplicity, but it serves the same as my situation. Please help me as the part of console.log ('This is m3u8').

Code Sandbox

And by the way, is there anyways I can implement a custom button into this Plyr, I mean it's stick together with the Plyr, like Play, Fast-forward, Rewind button, etc? I want to create a Go back button to the previous page and Go next button to go to the next episode, I've made a hand-made video player before but it didn't work out so well, that's why I'm trying to switch to Plyr because some of my friends said it better.

If you can have some simple examples, please provide me, I can base on that and try to make my own feature.

Thanks for answering my question.

You must be logged in to vote
7 replies
Comment options

Thanks for writing it @amirHossein-Ebrahimi , I'm not learned Typescript yet so there's some unfamiliar way of writing that I can't understand, but I'll try. And I'm new to HLS, too, I've searched for a few days but this topic is rather rare or somehow. I'm just trying to make my video work as it should've😃

Is the Commented code below is working as React + javascript only or it's just a note 😃 .

Comment options

Sorry, I forgot the ts part. Here is js alternative

import * as React from 'react'
import Hls from 'hls.js'
import { usePlyr, APITypes, PlyrProps } from 'plyr-react'
import 'plyr-react/dist/plyr.css'
import { useEffect, useRef, useState } from 'react'
// Self-prepare mp4 and m3u8 url
const videoUrls = {
 hsl: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
 mp4:
 'https://static.videezy.com/system/resources/previews/000/052/817/original/Rainbow_colorful_stars_random_color_flying_and_faded.mp4',
}
const source = { type: 'video' }
// TODO: videoSrc and options
const CustomPlyrInstance = React.forwardRef(
 (props, ref) => {
 const hlsRef = useRef(new Hls())
 const [options, setOptions] = useState({
 quality: {
 default: 480,
 forced: true,
 options: [],
 onChange: (_quality) => {},
 },
 })
 const videoPlayer = usePlyr(ref, { options, source })
 useEffect(() => {
 const { current: hls } = hlsRef
 const video = videoPlayer.current && videoPlayer.current.plyr.media
 hls.loadSource(videoUrls.hsl)
 hls.attachMedia(video)
 hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) {
 const qualityOptions = hls.levels.map((l) => l.height)
 setOptions({
 quality: {
 default: qualityOptions[qualityOptions.length - 1],
 options: qualityOptions,
 forced: true,
 // Manage quality changes
 onChange: (quality) => {
 hls.levels.forEach((level, levelIndex) => {
 if (level.height === quality) {
 hls.currentLevel = levelIndex
 }
 })
 },
 },
 })
 })
 })
 return (
 <video
 ref={videoPlayer}
 className="plyr-react plyr"
 id="plyr"
 />
 )
 }
)
const PlyrComponent = () => {
 const ref = React.useRef(null)
 const hslIsSupported = Hls.isSupported()
 return (
 <div className="wrapper">
 {hslIsSupported && <CustomPlyrInstance ref={ref} />}
 </div>
 )
}
export default PlyrComponent

as a rule of thumb, remove the following and you can convert ts to js on your own.

  • base types : someType
  • casting types as someType
  • generic type <someType>
Comment options

I'm sorry to ask a newbie question, but this is a separate component from the one I posted at first right? Then I passed the props, refs from my AnimeWatch component down to PlyrComponent?

I've never used forwardRef before so pardon me, but I've read it and it's said that it used to pass the props + refs from the parent component down.

UPDATE:

I tried a bit but it's said that

export 'usePlyr' (imported as 'usePlyr') was not found in 'plyr-react'

UPDATE:

I tried switching back to Plyr, not Plyr-react, it accepted usePlyr

But I get

Uncaught TypeError: (0 , plyr__WEBPACK_IMPORTED_MODULE_2__.usePlyr) is not a function

from

const videoPlayer = usePlyr(ref, { options, source })

I don't know if I implement it right or not.

Comment options

  • The usePlyr hook is from our alpha release 4.0.0-alpha.1
  • In case you don't want to use forwardRef just pass the ref with a different name simply as props e.g. plyrRef, that should completely work :).

Here is the same component we have in our readme + new alpha release integration + type removed
https://codesandbox.io/s/silent-hooks-tpsbe?file=/src/HLS-javascript.jsx

Answer selected by chintan9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /