From 537a38a79a35840951602ab359fb19a8ee6f01cd Mon Sep 17 00:00:00 2001 From: Mirlan Date: Wed, 27 Jan 2021 14:25:21 +0600 Subject: [PATCH] feat(703): preloading next episode (#277) --- .../MultiSourcePlayer/hooks/index.tsx | 39 ++++++++++----- .../hooks/usePlayingHandlers.tsx | 7 ++- .../hooks/useProgressChangeHandler.tsx | 49 ++++++++++--------- src/features/MultiSourcePlayer/index.tsx | 37 +++++++++++--- src/features/MultiSourcePlayer/types.tsx | 5 ++ src/features/VideoPlayer/hooks/index.tsx | 3 +- src/features/VideoPlayer/index.tsx | 2 + 7 files changed, 98 insertions(+), 44 deletions(-) diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx index 85ddeae2..f4c57d24 100644 --- a/src/features/MultiSourcePlayer/hooks/index.tsx +++ b/src/features/MultiSourcePlayer/hooks/index.tsx @@ -19,24 +19,30 @@ import { usePlayingHandlers } from './usePlayingHandlers' import { useVideoQuality } from './useVideoQuality' import { useDuration } from './useDuration' import type { Chapters } from '../types' +import { Players } from '../types' export type PlayerState = { activeChapterIndex: number, + activePlayer: Players, loadedProgress: number, playedProgress: number, playing: boolean, ready: boolean, - seek: number, + seek: Record, seeking: boolean, } const initialState: PlayerState = { activeChapterIndex: 0, + activePlayer: 0, loadedProgress: 0, playedProgress: 0, playing: false, ready: false, - seek: 0, + seek: { + [Players.PLAYER1]: 0, + [Players.PLAYER2]: 0, + }, seeking: false, } @@ -59,6 +65,7 @@ export const useMultiSourcePlayer = ({ const [ { activeChapterIndex, + activePlayer, loadedProgress, playedProgress, playing, @@ -68,7 +75,8 @@ export const useMultiSourcePlayer = ({ }, setPlayerState, ] = useObjectState({ ...initialState, activeChapterIndex: resumeFrom.half }) - const videoRef = useRef(null) + const video1Ref = useRef(null) + const video2Ref = useRef(null) const { onReady, playNextChapter, @@ -92,20 +100,24 @@ export const useMultiSourcePlayer = ({ }, [onError, stopPlaying]) const onProgressChange = useProgressChangeHandler({ - activeChapterIndex, chapters, duration, setPlayerState, }) - const getActiveChapterUrl = useCallback((quality: string = selectedQuality) => ( - chapters[activeChapterIndex].urls[quality] - ), [selectedQuality, chapters, activeChapterIndex]) + const getChapterUrl = useCallback((index: number, quality: string = selectedQuality) => ( + chapters[index]?.urls[quality] + ), [selectedQuality, chapters]) + + const videoRef = [video1Ref, video2Ref][activePlayer] const onQualitySelect = (quality: string) => { - setPlayerState({ - seek: videoRef.current?.currentTime ?? 0, - }) + setPlayerState((state) => ({ + seek: { + ...state.seek, + [state.activePlayer]: videoRef.current?.currentTime ?? 0, + }, + })) setSelectedQuality(quality) } @@ -159,12 +171,14 @@ export const useMultiSourcePlayer = ({ return { activeChapterIndex, - activeSrc: getActiveChapterUrl(), + activePlayer, + activeSrc: getChapterUrl(activeChapterIndex), chapters, duration, isFirstChapterPlaying: activeChapterIndex === 0, isLastChapterPlaying: activeChapterIndex === numberOfChapters - 1, loadedProgress, + nextSrc: getChapterUrl(activeChapterIndex + 1), onError: handleError, onLoadedProgress, onPlayedProgress, @@ -181,8 +195,9 @@ export const useMultiSourcePlayer = ({ selectedQuality, startPlaying, togglePlaying, + video1Ref, + video2Ref, videoQualities, - videoRef, ...useFullscreen(), ...useVolume(), } diff --git a/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx b/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx index 642f7094..ef5cf692 100644 --- a/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx +++ b/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx @@ -2,7 +2,10 @@ import { useCallback } from 'react' import { SetPartialState } from 'hooks' -import { PlayerState } from '.' +import type { PlayerState } from '.' +import { Players } from '../types' + +const getNextPlayer = (player: Players): Players => (player + 1) % 2 export const usePlayingHandlers = ( setPlayerState: SetPartialState, @@ -43,6 +46,7 @@ export const usePlayingHandlers = ( const isLastChapter = state.activeChapterIndex + 1 === numberOfChapters return { activeChapterIndex: isLastChapter ? 0 : state.activeChapterIndex + 1, + activePlayer: getNextPlayer(state.activeChapterIndex), loadedProgress: 0, playedProgress: 0, playing: isLastChapter ? false : state.playing, @@ -55,6 +59,7 @@ export const usePlayingHandlers = ( if (!state.ready || state.activeChapterIndex === 0) return state return { activeChapterIndex: state.activeChapterIndex - 1, + activePlayer: getNextPlayer(state.activeChapterIndex), loadedProgress: 0, playedProgress: 0, } diff --git a/src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx b/src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx index 7e55f160..ed1883d3 100644 --- a/src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx +++ b/src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx @@ -7,42 +7,45 @@ import type { PlayerState } from '.' import { findChapterByProgress } from '../helpers' type Args = { - activeChapterIndex: number, chapters: Chapters, duration: number, setPlayerState: SetPartialState, } export const useProgressChangeHandler = ({ - activeChapterIndex, chapters, duration, setPlayerState, }: Args) => { const onProgressChange = useCallback((progress: number, seeking: boolean) => { - // значение новой позиции ползунка в миллисекундах - const progressMs = progress * duration - const chapterIndex = findChapterByProgress(chapters, progressMs) - const chapter = chapters[chapterIndex] - const isProgressOnDifferentChapter = ( - chapterIndex !== -1 - && chapterIndex !== activeChapterIndex - ) - const nextChapter = isProgressOnDifferentChapter - ? chapterIndex - : activeChapterIndex + setPlayerState((state) => { + // значение новой позиции ползунка в миллисекундах + const progressMs = progress * duration + const chapterIndex = findChapterByProgress(chapters, progressMs) + const chapter = chapters[chapterIndex] + const isProgressOnDifferentChapter = ( + chapterIndex !== -1 + && chapterIndex !== state.activeChapterIndex + ) + const nextChapter = isProgressOnDifferentChapter + ? chapterIndex + : state.activeChapterIndex - // отнимаем начало главы на котором остановились от общего прогресса - // чтобы получить прогресс текущей главы - const chapterProgressMs = (progressMs - chapter.startMs) - const seekMs = chapterProgressMs + chapter.startOffsetMs - setPlayerState({ - activeChapterIndex: nextChapter, - playedProgress: chapterProgressMs, - seek: seekMs / 1000, - seeking, + // отнимаем начало главы на котором остановились от общего прогресса + // чтобы получить прогресс текущей главы + const chapterProgressMs = (progressMs - chapter.startMs) + const seekMs = chapterProgressMs + chapter.startOffsetMs + return { + activeChapterIndex: nextChapter, + playedProgress: chapterProgressMs, + seek: { + ...state.seek, + [state.activePlayer]: seekMs / 1000, + }, + seeking, + } }) - }, [duration, chapters, activeChapterIndex, setPlayerState]) + }, [duration, chapters, setPlayerState]) return onProgressChange } diff --git a/src/features/MultiSourcePlayer/index.tsx b/src/features/MultiSourcePlayer/index.tsx index 93c0294d..433b1dbe 100644 --- a/src/features/MultiSourcePlayer/index.tsx +++ b/src/features/MultiSourcePlayer/index.tsx @@ -15,10 +15,12 @@ import { ProgressBar } from './components/ProgressBar' import { Settings } from './components/Settings' import type { Props } from './hooks' import { useMultiSourcePlayer } from './hooks' +import { Players } from './types' export const MultiSourcePlayer = (props: Props) => { const { activeChapterIndex, + activePlayer, activeSrc, chapters, duration, @@ -27,6 +29,7 @@ export const MultiSourcePlayer = (props: Props) => { isLastChapterPlaying, loadedProgress, muted, + nextSrc, onError, onFullscreenClick, onLoadedProgress, @@ -45,12 +48,16 @@ export const MultiSourcePlayer = (props: Props) => { seek, selectedQuality, togglePlaying, + video1Ref, + video2Ref, videoQualities, - videoRef, volume, volumeInPercent, wrapperRef, } = useMultiSourcePlayer(props) + + const firstPlayerActive = activePlayer === Players.PLAYER1 + return ( { ) }