feat(#489): saving player quality and sound settings in local storage (#187)

keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Mirlan 5 years ago committed by GitHub
parent 563219b741
commit 46f44189ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/features/MultiSourcePlayer/hooks/index.tsx
  2. 14
      src/features/MultiSourcePlayer/hooks/usePlayingState.tsx
  3. 16
      src/features/MultiSourcePlayer/hooks/useVideoQuality.tsx
  4. 45
      src/features/MultiSourcePlayer/hooks/useVolume.tsx
  5. 10
      src/features/StreamPlayer/hooks/index.tsx
  6. 32
      src/features/StreamPlayer/hooks/useVideoQuality.tsx
  7. 34
      src/features/StreamPlayer/hooks/useVolume.tsx
  8. 4
      src/features/StreamPlayer/styled.tsx

@ -43,7 +43,6 @@ export const useMultiSourcePlayer = ({
const [playedProgress, setPlayedProgress] = useState(0)
const {
continuePlaying,
firstTimeStart,
playing,
startPlaying,
stopPlaying,
@ -114,11 +113,10 @@ export const useMultiSourcePlayer = ({
const url = getActiveChapterUrl()
const chapterStartMs = getActiveChapterStart()
const from = resumeFrom.second - (chapterStartMs / 1000)
if (url && firstTimeStart) {
if (url) {
startPlaying(url, from)
}
}, [
firstTimeStart,
resumeFrom,
getActiveChapterUrl,
getActiveChapterStart,

@ -4,13 +4,12 @@ import { useState, useCallback } from 'react'
import { preparePlayer } from '../helpers'
export const usePlayingState = (videoRef: RefObject<HTMLVideoElement>) => {
const [firstTimeStart, setFirstTimeStart] = useState(true)
const [playing, setPlaying] = useState(false)
const togglePlaying = useCallback(() => {
setPlaying((isPlaying) => {
const video = videoRef.current
if (!video || firstTimeStart) return false
if (!video) return false
const nextIsPlaying = !isPlaying
if (nextIsPlaying) {
@ -20,7 +19,7 @@ export const usePlayingState = (videoRef: RefObject<HTMLVideoElement>) => {
}
return nextIsPlaying
})
}, [firstTimeStart, videoRef])
}, [videoRef])
const stopPlaying = useCallback((nextUrl: string = '') => {
preparePlayer({ url: nextUrl, videoRef })
@ -33,9 +32,11 @@ export const usePlayingState = (videoRef: RefObject<HTMLVideoElement>) => {
url,
videoRef,
})
videoRef.current?.play()
setFirstTimeStart(false)
setPlaying(true)
// автовоспроизведение со звуком иногда может не сработать
// https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#new-behaviors
videoRef.current?.play().then(() => {
setPlaying(true)
})
}, [videoRef])
const continuePlaying = useCallback((
@ -58,7 +59,6 @@ export const usePlayingState = (videoRef: RefObject<HTMLVideoElement>) => {
return {
continuePlaying,
firstTimeStart,
playing,
startPlaying,
stopPlaying,

@ -1,10 +1,10 @@
import { useState } from 'react'
import map from 'lodash/map'
import uniq from 'lodash/uniq'
import orderBy from 'lodash/orderBy'
import includes from 'lodash/includes'
import type { Videos } from 'requests'
import { useLocalStore } from 'hooks'
const getVideoQualities = (videos: Videos) => {
const qualities = uniq(map(videos, 'quality'))
@ -17,7 +17,17 @@ const getVideoQualities = (videos: Videos) => {
export const useVideoQuality = (videos: Videos) => {
const videoQualities = getVideoQualities(videos)
const [selectedQuality, setSelectedQuality] = useState(videoQualities[0])
const qualityValidator = (localStorageQuality: string) => (
includes(videoQualities, localStorageQuality)
)
const [selectedQuality, setSelectedQuality] = useLocalStore({
// по умолчанию наилучшее качество
defaultValue: videoQualities[0],
key: 'player_quality',
validator: qualityValidator,
})
return {
selectedQuality,

@ -1,47 +1,44 @@
import type { RefObject } from 'react'
import { useState, useCallback } from 'react'
import { useEffect, useRef } from 'react'
import { useToggle } from 'hooks'
import isNumber from 'lodash/isNumber'
import { useLocalStore } from 'hooks'
const defaultVolume = 1
const useVolumeState = (videoRef: RefObject<HTMLVideoElement>) => {
const [volume, setVolume] = useState(0.5)
const setVideoVolume = useCallback((value: number) => {
const [volume, setVolume] = useLocalStore({
defaultValue: defaultVolume,
key: 'player_volume',
validator: isNumber,
})
useEffect(() => {
if (videoRef.current) {
// eslint-disable-next-line no-param-reassign
videoRef.current.volume = value
videoRef.current.volume = volume
}
setVolume(value)
}, [videoRef])
return [volume, setVideoVolume] as const
}, [volume, videoRef])
return [volume, setVolume] as const
}
export const useVolume = (videoRef: RefObject<HTMLVideoElement>) => {
const {
close: unmute,
isOpen: muted,
open: mute,
toggle: toggleMuted,
} = useToggle(true)
const prevVolumeRef = useRef(defaultVolume)
const [volume, setVolume] = useVolumeState(videoRef)
const onVolumeChange = (value: number) => {
if (value === 0) {
mute()
} else {
unmute()
}
setVolume(value)
}
const onVolumeClick = () => {
if (muted && volume === 0) {
setVolume(0.1)
}
toggleMuted()
setVolume(volume === 0 ? prevVolumeRef.current : 0)
prevVolumeRef.current = volume || defaultVolume
}
return {
muted,
muted: volume === 0,
onVolumeChange,
onVolumeClick,
volume,

@ -44,8 +44,14 @@ export const useVideoPlayer = ({
const startPlaying = useCallback(once(() => {
setReady(true)
setPlaying(true)
onPlayingChange(true)
// автовоспроизведение со звуком иногда может не сработать
// https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#new-behaviors
const video = playerRef.current?.getInternalPlayer() as HTMLVideoElement | undefined
video?.play().then(() => {
setPlaying(true)
onPlayingChange(true)
})
}), [])
const togglePlaying = () => {

@ -1,7 +1,6 @@
import type { RefObject } from 'react'
import {
useMemo,
useState,
useEffect,
useCallback,
} from 'react'
@ -14,6 +13,9 @@ 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 { useLocalStore } from 'hooks'
const autoQuality = {
label: 'Auto',
@ -38,7 +40,11 @@ const getVideoQualities = (hls: Hls | null) => {
export const useVideoQuality = (ref: RefObject<ReactPlayer>) => {
const hls = ref.current?.getInternalPlayer('hls') as Hls | null
const videoQualities = useMemo(() => getVideoQualities(hls), [hls])
const [selectedQuality, setSelectedQuality] = useState('')
const [selectedQuality, setSelectedQuality] = useLocalStore({
defaultValue: autoQuality.label,
key: 'player_quality',
validator: isString,
})
const onQualitySelect = useCallback((label: string) => {
const item = find(videoQualities, { label })
@ -46,11 +52,27 @@ export const useVideoQuality = (ref: RefObject<ReactPlayer>) => {
hls.currentLevel = item.level
setSelectedQuality(item.label)
}
}, [hls, videoQualities])
}, [
setSelectedQuality,
hls,
videoQualities,
])
useEffect(() => {
onQualitySelect(autoQuality.label)
}, [onQualitySelect])
if (!hls) return
const quality = find(videoQualities, { label: selectedQuality }) || autoQuality
if (quality.level === hls.currentLevel) return
hls.currentLevel = quality.level
setSelectedQuality(quality.label)
}, [
selectedQuality,
setSelectedQuality,
videoQualities,
hls,
])
return {
onQualitySelect,

@ -1,34 +1,30 @@
import { useState } from 'react'
import { useRef } from 'react'
import { useToggle } from 'hooks'
import isNumber from 'lodash/isNumber'
import { useLocalStore } from 'hooks'
const defaultVolume = 1
export const useVolume = () => {
const {
close: unmute,
isOpen: muted,
open: mute,
toggle: toggleMuted,
} = useToggle(true)
const [volume, setVolume] = useState(0.5)
const prevVolumeRef = useRef(defaultVolume)
const [volume, setVolume] = useLocalStore({
defaultValue: defaultVolume,
key: 'player_volume',
validator: isNumber,
})
const onVolumeChange = (value: number) => {
if (value === 0) {
mute()
} else {
unmute()
}
setVolume(value)
}
const onVolumeClick = () => {
if (muted && volume === 0) {
setVolume(0.1)
}
toggleMuted()
setVolume(volume === 0 ? prevVolumeRef.current : 0)
prevVolumeRef.current = volume || defaultVolume
}
return {
muted,
muted: volume === 0,
onVolumeChange,
onVolumeClick,
volume,

@ -25,6 +25,10 @@ export const PlayerWrapper = styled.div<PlayStopProps>`
padding-top: 56.25%;
background-color: #000;
:fullscreen {
padding-top: 0;
}
:hover ${Controls} {
opacity: 1;
}

Loading…
Cancel
Save