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.
 
 
 
 
spa_instat_tv/src/features/StreamPlayer/hooks/useVideoQuality.tsx

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'),
}
}