You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.5 KiB
97 lines
2.5 KiB
import {
|
|
useState,
|
|
useEffect,
|
|
useCallback,
|
|
} from 'react'
|
|
|
|
import Hls, { Level } from 'hls.js'
|
|
|
|
import map from 'lodash/map'
|
|
import find from 'lodash/find'
|
|
import uniqBy from 'lodash/uniqBy'
|
|
import isEmpty from 'lodash/isEmpty'
|
|
import orderBy from 'lodash/orderBy'
|
|
import isString from 'lodash/isString'
|
|
import filter from 'lodash/fp/filter'
|
|
|
|
import { useLocalStore } from 'hooks'
|
|
|
|
const autoQuality = {
|
|
label: 'Auto',
|
|
level: -1,
|
|
}
|
|
|
|
/**
|
|
* Убирает из списка качества без height
|
|
*
|
|
* Когда в манифесте нет данных о качествах стрима hls.levels содержит
|
|
* непонятное качество без свойств height, width и тд для определения
|
|
* какое это качество
|
|
*/
|
|
const filterOutUnknownQualities = filter(({ height }: Level) => Boolean(height))
|
|
|
|
const getVideoQualities = (levels: Array<Level>) => {
|
|
if (isEmpty(levels)) return []
|
|
|
|
const filteredQualities = filterOutUnknownQualities(levels)
|
|
const qualities = map(filteredQualities, (level, i) => ({
|
|
label: String(level.height),
|
|
level: i,
|
|
}))
|
|
const sorted = orderBy(
|
|
qualities,
|
|
Number,
|
|
'desc',
|
|
)
|
|
return uniqBy([...sorted], 'label')
|
|
}
|
|
|
|
export const useVideoQuality = (hls: Hls | null) => {
|
|
const [videoQualities, setVideoQualities] = useState([autoQuality])
|
|
const [selectedQuality, setSelectedQuality] = useLocalStore({
|
|
defaultValue: autoQuality.label,
|
|
key: 'player_quality',
|
|
validator: isString,
|
|
})
|
|
|
|
const onQualitySelect = useCallback((label: string) => {
|
|
if (!hls) return
|
|
|
|
const quality = find(videoQualities, { label })
|
|
if (!quality || quality.level === hls.currentLevel) return
|
|
// eslint-disable-next-line no-param-reassign
|
|
hls.currentLevel = quality.level
|
|
setSelectedQuality(quality.label)
|
|
}, [
|
|
setSelectedQuality,
|
|
videoQualities,
|
|
hls,
|
|
])
|
|
|
|
useEffect(() => {
|
|
if (!hls) return undefined
|
|
|
|
const listener = () => {
|
|
const qualities = getVideoQualities(hls.levels)
|
|
const quality = find(qualities, { label: selectedQuality }) || qualities[0]
|
|
// eslint-disable-next-line no-param-reassign
|
|
hls.currentLevel = quality.level
|
|
setSelectedQuality(quality.label)
|
|
setVideoQualities(qualities)
|
|
}
|
|
hls.on(Hls.Events.MANIFEST_PARSED, listener)
|
|
return () => {
|
|
hls.off(Hls.Events.MANIFEST_PARSED, listener)
|
|
}
|
|
}, [
|
|
selectedQuality,
|
|
setSelectedQuality,
|
|
hls,
|
|
])
|
|
|
|
return {
|
|
onQualitySelect,
|
|
selectedQuality,
|
|
videoQualities: map(videoQualities, 'label'),
|
|
}
|
|
}
|
|
|