diff --git a/src/features/MultiSourcePlayer/components/Chapters/index.tsx b/src/features/StreamPlayer/components/Chapters/index.tsx
similarity index 91%
rename from src/features/MultiSourcePlayer/components/Chapters/index.tsx
rename to src/features/StreamPlayer/components/Chapters/index.tsx
index bde90511..5ff72fa4 100644
--- a/src/features/MultiSourcePlayer/components/Chapters/index.tsx
+++ b/src/features/StreamPlayer/components/Chapters/index.tsx
@@ -1,14 +1,11 @@
import map from 'lodash/map'
-import {
- LoadedProgress,
- PlayedProgress,
-} from 'features/StreamPlayer/components/ProgressBar/styled'
-
import type { Chapter } from '../../types'
import {
ChapterList,
ChapterContainer,
+ LoadedProgress,
+ PlayedProgress,
} from './styled'
type ChapterWithStyles = Chapter & {
diff --git a/src/features/MultiSourcePlayer/components/Chapters/styled.tsx b/src/features/StreamPlayer/components/Chapters/styled.tsx
similarity index 55%
rename from src/features/MultiSourcePlayer/components/Chapters/styled.tsx
rename to src/features/StreamPlayer/components/Chapters/styled.tsx
index 54060a58..0caa93a3 100644
--- a/src/features/MultiSourcePlayer/components/Chapters/styled.tsx
+++ b/src/features/StreamPlayer/components/Chapters/styled.tsx
@@ -16,3 +16,17 @@ export const ChapterContainer = styled.div`
margin-right: 3px;
}
`
+
+export const LoadedProgress = styled.div`
+ position: absolute;
+ z-index: 1;
+ background-color: rgba(255, 255, 255, 0.6);
+ height: 100%;
+`
+
+export const PlayedProgress = styled.div`
+ position: absolute;
+ z-index: 2;
+ background-color: #CC0000;
+ height: 100%;
+`
diff --git a/src/features/MultiSourcePlayer/components/ProgressBar/helpers/calculateChapterStyles/__tests__/index.tsx b/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/__tests__/index.tsx
similarity index 100%
rename from src/features/MultiSourcePlayer/components/ProgressBar/helpers/calculateChapterStyles/__tests__/index.tsx
rename to src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/__tests__/index.tsx
diff --git a/src/features/MultiSourcePlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx b/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx
similarity index 94%
rename from src/features/MultiSourcePlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx
rename to src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx
index e0bc9fe7..9a257fb9 100644
--- a/src/features/MultiSourcePlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx
+++ b/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx
@@ -3,7 +3,7 @@ import pipe from 'lodash/fp/pipe'
import size from 'lodash/fp/size'
import slice from 'lodash/fp/slice'
-import type { Chapters, Chapter } from 'features/MultiSourcePlayer/types'
+import type { Chapters, Chapter } from 'features/StreamPlayer/types'
const calculateChapterProgress = (progress: number, chapter: Chapter) => (
Math.min(progress * 100 / chapter.duration, 100)
diff --git a/src/features/MultiSourcePlayer/components/ProgressBar/hooks.tsx b/src/features/StreamPlayer/components/ProgressBar/hooks.tsx
similarity index 92%
rename from src/features/MultiSourcePlayer/components/ProgressBar/hooks.tsx
rename to src/features/StreamPlayer/components/ProgressBar/hooks.tsx
index b080af87..fea576e8 100644
--- a/src/features/MultiSourcePlayer/components/ProgressBar/hooks.tsx
+++ b/src/features/StreamPlayer/components/ProgressBar/hooks.tsx
@@ -2,13 +2,13 @@ import { useMemo } from 'react'
import { secondsToHms } from 'helpers'
-import type { Chapters } from '../../types'
+import type { Chapters } from '../../../StreamPlayer/types'
import { calculateChapterStyles } from './helpers/calculateChapterStyles'
export type Props = {
activeChapterIndex: number,
allPlayedProgress: number,
- chapters?: Chapters,
+ chapters: Chapters,
duration: number,
loadedProgress: number,
onPlayedProgressChange: (progress: number, seeking: boolean) => void,
diff --git a/src/features/StreamPlayer/components/ProgressBar/index.tsx b/src/features/StreamPlayer/components/ProgressBar/index.tsx
index 2fc3f39c..741f09ea 100644
--- a/src/features/StreamPlayer/components/ProgressBar/index.tsx
+++ b/src/features/StreamPlayer/components/ProgressBar/index.tsx
@@ -1,43 +1,27 @@
-import { secondsToHms } from 'helpers'
-
import { useSlider } from 'features/StreamPlayer/hooks/useSlider'
import { TimeTooltip } from 'features/StreamPlayer/components/TimeTooltip'
+import { Scrubber } from 'features/StreamPlayer/components/ProgressBar/styled'
-import {
- ProgressBarList,
- LoadedProgress,
- PlayedProgress,
- Scrubber,
-} from './styled'
-
-type Props = {
- duration: number,
- isScrubberVisible?: boolean,
- loadedProgress: number,
- onPlayedProgressChange: (progress: number) => void,
- playedProgress: number,
-}
+import { Chapters } from '../Chapters'
+import type { Props } from './hooks'
+import { useProgressBar } from './hooks'
+import { ProgressBarList } from './styled'
-export const ProgressBar = ({
- duration,
- isScrubberVisible,
- loadedProgress,
- onPlayedProgressChange,
- playedProgress,
-}: Props) => {
+export const ProgressBar = (props: Props) => {
+ const { onPlayedProgressChange } = props
const progressBarRef = useSlider({ onChange: onPlayedProgressChange })
- const loadedFraction = Math.min(loadedProgress * 100 / duration, 100)
- const playedFraction = Math.min(playedProgress * 100 / duration, 100)
+ const {
+ calculatedChapters,
+ playedProgressInPercent,
+ time,
+ } = useProgressBar(props)
return (
-
-
- {isScrubberVisible === false ? null : (
-
-
-
- )}
+
+
+
+
)
}
diff --git a/src/features/StreamPlayer/components/ProgressBar/stories.tsx b/src/features/StreamPlayer/components/ProgressBar/stories.tsx
index d62dfce6..bd301b29 100644
--- a/src/features/StreamPlayer/components/ProgressBar/stories.tsx
+++ b/src/features/StreamPlayer/components/ProgressBar/stories.tsx
@@ -13,7 +13,7 @@ import { ProgressBar } from '.'
const Story = {
component: ProgressBar,
- title: 'ProgressBar',
+ title: 'ProgressBarWithChapters',
}
export default Story
@@ -47,9 +47,42 @@ const renderInControls = (progressBarElement: ReactElement) => (
const duration = 70000
+const chapters = [
+ {
+ duration: 30000,
+ endMs: 30000,
+ endOffsetMs: 0,
+ period: 0,
+ startMs: 0,
+ startOffsetMs: 0,
+ url: '',
+ },
+ {
+ duration: 30000,
+ endMs: 60000,
+ endOffsetMs: 0,
+ period: 0,
+ startMs: 30000,
+ startOffsetMs: 0,
+ url: '',
+ },
+ {
+ duration: 10000,
+ endMs: 70000,
+ endOffsetMs: 0,
+ period: 0,
+ startMs: 60000,
+ startOffsetMs: 0,
+ url: '',
+ },
+]
+
export const Empty = () => renderInControls(
renderInControls(
export const HalfLoaded = () => renderInControls(
renderInControls(
export const HalfPlayed = () => renderInControls(
renderInControls(
export const Loaded40AndPlayed20 = () => renderInControls(
= {
xhr.open('GET', url.toString())
},
}
+
+export const REWIND_SECONDS = 5
+
+export const HOUR_IN_MILLISECONDS = 60 * 60 * 1000
diff --git a/src/features/MultiSourcePlayer/helpers/index.tsx b/src/features/StreamPlayer/helpers/index.tsx
similarity index 82%
rename from src/features/MultiSourcePlayer/helpers/index.tsx
rename to src/features/StreamPlayer/helpers/index.tsx
index 41316ee0..062dd10c 100644
--- a/src/features/MultiSourcePlayer/helpers/index.tsx
+++ b/src/features/StreamPlayer/helpers/index.tsx
@@ -2,7 +2,7 @@ import { RefObject } from 'react'
import findIndex from 'lodash/findIndex'
-import type { Chapters, Players } from '../types'
+import type { Chapters } from '../types'
type Args = {
from?: number,
@@ -31,5 +31,3 @@ export const findChapterByProgress = (chapters: Chapters, progressMs: number) =>
startMs <= progressMs && progressMs <= endMs
))
)
-
-export const getNextPlayer = (player: Players): Players => (player + 1) % 2
diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx
index b2a90b8b..443889e8 100644
--- a/src/features/StreamPlayer/hooks/index.tsx
+++ b/src/features/StreamPlayer/hooks/index.tsx
@@ -2,71 +2,99 @@ import type { MouseEvent } from 'react'
import {
useCallback,
useEffect,
- useMemo,
useState,
} from 'react'
-import once from 'lodash/once'
+import size from 'lodash/size'
+import isNumber from 'lodash/isNumber'
-import { useVolume } from 'features/VideoPlayer/hooks/useVolume'
-import { REWIND_SECONDS } from 'features/MultiSourcePlayer/config'
-import { useNoNetworkPopupStore } from 'features/NoNetworkPopup'
+import { isIOS } from 'config/userAgent'
-import { useObjectState } from 'hooks'
+import { useObjectState } from 'hooks/useObjectState'
-import type { MatchInfo } from 'requests/getMatchInfo'
+import { useVolume } from 'features/VideoPlayer/hooks/useVolume'
+import { useNoNetworkPopupStore } from 'features/NoNetworkPopup'
-import { isIOS } from 'config/userAgent'
+import type { Chapters } from 'features/StreamPlayer/types'
+import { REWIND_SECONDS } from '../config'
import { useHlsPlayer } from './useHlsPlayer'
import { useFullscreen } from './useFullscreen'
import { useVideoQuality } from './useVideoQuality'
import { useControlsVisibility } from './useControlsVisibility'
+import { useProgressChangeHandler } from './useProgressChangeHandler'
+import { usePlayingHandlers } from './usePlayingHandlers'
+import { useDuration } from './useDuration'
+
+export type PlayerState = typeof initialState
const toMilliSeconds = (seconds: number) => seconds * 1000
const initialState = {
+ activeChapterIndex: 0,
+ buffering: true,
duration: 0,
loadedProgress: 0,
playedProgress: 0,
playing: false,
ready: false,
seek: 0,
+ seeking: false,
}
export type Props = {
+ chapters: Chapters,
+ isLive?: boolean,
+ onDurationChange?: (duration: number) => void,
onPlayingChange: (playing: boolean) => void,
onProgressChange: (seconds: number) => void,
- profile: MatchInfo,
resumeFrom?: number,
- url: string,
}
export const useVideoPlayer = ({
+ chapters,
+ isLive,
+ onDurationChange,
onPlayingChange,
onProgressChange: progressChangeCallback,
resumeFrom,
- url,
}: Props) => {
+ const { url } = chapters[0]
+ const numberOfChapters = size(chapters)
const { hls, videoRef } = useHlsPlayer(url, resumeFrom)
const [{
- duration,
+ activeChapterIndex,
+ buffering,
+ duration: fullMatchDuration,
loadedProgress,
playedProgress,
playing,
ready,
seek,
+ seeking,
}, setPlayerState] = useObjectState({
...initialState,
playedProgress: toMilliSeconds(resumeFrom || 0),
seek: resumeFrom || 0,
})
- const startPlaying = useMemo(() => once(() => {
- setPlayerState({ playing: true, ready: true })
- onPlayingChange(true)
- }), [onPlayingChange, setPlayerState])
+ const chaptersDuration = useDuration(chapters)
+
+ const duration = isLive ? fullMatchDuration : chaptersDuration
+
+ const {
+ onReady,
+ playNextChapter,
+ playPrevChapter,
+ stopPlaying,
+ togglePlaying,
+ } = usePlayingHandlers(setPlayerState, chapters)
+
+ const getActiveChapter = useCallback(
+ (index: number = activeChapterIndex) => chapters[index],
+ [chapters, activeChapterIndex],
+ )
const {
isFullscreen,
@@ -78,18 +106,39 @@ export const useVideoPlayer = ({
width: wrapperRef.current?.clientWidth,
})
- const togglePlaying = () => {
- if (ready) {
- setPlayerState({ playing: !playing })
- onPlayingChange(!playing)
+ const isFirstChapterPlaying = activeChapterIndex === 0
+ const isLastChapterPlaying = activeChapterIndex === numberOfChapters - 1
+ const seekTo = useCallback((progressMs: number) => {
+ if (!videoRef.current) return
+ videoRef.current.currentTime = progressMs / 1000
+ }, [videoRef])
+
+ const rewindForward = () => {
+ const chapter = getActiveChapter()
+ const newProgress = playedProgress + REWIND_SECONDS * 1000
+ if (newProgress <= chapter.duration) {
+ seekTo(chapter.startOffsetMs + newProgress)
+ } else if (isLastChapterPlaying) {
+ playNextChapter()
+ } else {
+ const nextChapter = getActiveChapter(activeChapterIndex + 1)
+ const fromMs = newProgress - chapter.duration
+ playNextChapter(fromMs, nextChapter.startOffsetMs)
}
}
- const rewind = (seconds: number) => () => {
- if (!videoRef.current) return
- const { currentTime } = videoRef.current
- const newProgress = currentTime + seconds
- videoRef.current.currentTime = newProgress
+ const rewindBackward = () => {
+ const chapter = getActiveChapter()
+ const newProgress = playedProgress - REWIND_SECONDS * 1000
+ if (newProgress >= 0) {
+ seekTo(chapter.startOffsetMs + newProgress)
+ } else if (isFirstChapterPlaying) {
+ seekTo(chapter.startOffsetMs)
+ } else {
+ const prevChapter = getActiveChapter(activeChapterIndex - 1)
+ const fromMs = prevChapter.duration + newProgress
+ playPrevChapter(fromMs, prevChapter.startOffsetMs)
+ }
}
const onError = useCallback(() => {
@@ -102,22 +151,45 @@ export const useVideoPlayer = ({
}
}
+ const onWaiting = () => {
+ setPlayerState({ buffering: true })
+ }
+
+ const onPlaying = () => {
+ setPlayerState({ buffering: false })
+ }
+
+ const onPause = () => {
+ setPlayerState({ playing: false })
+ }
+
+ const onPlay = () => {
+ setPlayerState({ playing: true })
+ }
+
const onDuration = (durationSeconds: number) => {
setPlayerState({ duration: toMilliSeconds(durationSeconds) })
+ onDurationChange?.(durationSeconds)
}
- const onProgressChange = useCallback((progress: number) => {
- const progressMs = progress * duration
- setPlayerState({ playedProgress: progressMs, seek: progressMs / 1000 })
- }, [duration, setPlayerState])
+ const onProgressChange = useProgressChangeHandler({
+ chapters,
+ duration,
+ setPlayerState,
+ })
const onLoadedProgress = (loadedMs: number) => {
- setPlayerState({ loadedProgress: loadedMs })
+ const chapter = getActiveChapter()
+ const value = loadedMs - chapter.startOffsetMs
+ setPlayerState({ loadedProgress: value })
}
const onPlayedProgress = (playedMs: number) => {
- setPlayerState({ playedProgress: playedMs })
- progressChangeCallback(playedMs / 1000)
+ const chapter = getActiveChapter()
+ const value = Math.max(playedMs - chapter.startOffsetMs, 0)
+ setPlayerState({ playedProgress: value })
+
+ progressChangeCallback(value / 1000)
}
const backToLive = useCallback(() => {
@@ -125,6 +197,36 @@ export const useVideoPlayer = ({
setPlayerState({ playedProgress: liveProgressMs, seek: liveProgressMs / 1000 })
}, [duration, setPlayerState])
+ useEffect(() => {
+ if (isNumber(seek)) {
+ setPlayerState({ seek: undefined })
+ }
+ }, [seek, setPlayerState])
+
+ useEffect(() => {
+ onPlayingChange(playing)
+ }, [playing, onPlayingChange])
+
+ useEffect(() => {
+ setPlayerState({
+ ...initialState,
+ playing: true,
+ seek: chapters[0].startOffsetMs / 1000,
+ })
+ }, [chapters, setPlayerState])
+
+ useEffect(() => {
+ const { duration: chapterDuration } = getActiveChapter()
+ if (playedProgress >= chapterDuration && !seeking) {
+ playNextChapter()
+ }
+ }, [
+ getActiveChapter,
+ playedProgress,
+ seeking,
+ playNextChapter,
+ ])
+
const { isOnline } = useNoNetworkPopupStore()
useEffect(() => {
@@ -138,13 +240,11 @@ export const useVideoPlayer = ({
useEffect(() => {
if (!isOnline) {
- setPlayerState({ playing: false })
- onPlayingChange(false)
+ stopPlaying()
}
}, [
isOnline,
- onPlayingChange,
- setPlayerState,
+ stopPlaying,
])
useEffect(() => {
@@ -160,26 +260,40 @@ export const useVideoPlayer = ({
}, [setPlayerState])
return {
+ activeChapterIndex,
+ allPlayedProgress: playedProgress + getActiveChapter().startMs,
backToLive,
+ buffering,
duration,
+ isFirstChapterPlaying,
isFullscreen,
+ isLastChapterPlaying,
loadedProgress,
+ numberOfChapters,
onDuration,
onError,
onFullscreenClick,
onLoadedProgress,
+ onPause,
+ onPlay,
onPlayedProgress,
onPlayerClick,
+ onPlaying,
onProgressChange,
+ onReady,
+ onWaiting,
+ playNextChapter,
+ playPrevChapter,
playedProgress,
playing,
ready,
- rewindBackward: rewind(-REWIND_SECONDS),
- rewindForward: rewind(REWIND_SECONDS),
+ rewindBackward,
+ rewindForward,
seek,
sizeOptions,
startPlaying,
togglePlaying,
+ url,
videoRef,
wrapperRef,
...useControlsVisibility(isFullscreen),
diff --git a/src/features/MultiSourcePlayer/hooks/useDuration.tsx b/src/features/StreamPlayer/hooks/useDuration.tsx
similarity index 100%
rename from src/features/MultiSourcePlayer/hooks/useDuration.tsx
rename to src/features/StreamPlayer/hooks/useDuration.tsx
diff --git a/src/features/StreamPlayer/hooks/useFullscreen.tsx b/src/features/StreamPlayer/hooks/useFullscreen.tsx
index ffbfb4a5..2a73e4f1 100644
--- a/src/features/StreamPlayer/hooks/useFullscreen.tsx
+++ b/src/features/StreamPlayer/hooks/useFullscreen.tsx
@@ -43,11 +43,8 @@ export const useFullscreen = () => {
}
}
- /**
- * В обертке могут быть 2 плеера, находим тот который играет сейчас, т.е. не скрыт
- */
const getPlayingVideoElement = () => (
- wrapperRef.current?.querySelector('video:not([hidden])') as HTMLVideoElement | null
+ wrapperRef.current?.querySelector('video') as HTMLVideoElement | null
)
const toggleIOSFullscreen = () => {
diff --git a/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx b/src/features/StreamPlayer/hooks/usePlayingHandlers.tsx
similarity index 63%
rename from src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx
rename to src/features/StreamPlayer/hooks/usePlayingHandlers.tsx
index edcc60cd..b223fbf2 100644
--- a/src/features/MultiSourcePlayer/hooks/usePlayingHandlers.tsx
+++ b/src/features/StreamPlayer/hooks/usePlayingHandlers.tsx
@@ -5,11 +5,11 @@ import isUndefined from 'lodash/isUndefined'
import type { SetPartialState } from 'hooks'
import type { PlayerState } from '.'
-import { getNextPlayer } from '../helpers'
+import type { Chapters } from '../types'
export const usePlayingHandlers = (
setPlayerState: SetPartialState,
- numberOfChapters: number,
+ chapters: Chapters,
) => {
const onReady = useCallback(() => {
setPlayerState((state) => (
@@ -43,53 +43,60 @@ export const usePlayingHandlers = (
setPlayerState((state) => {
if (!state.ready) return state
- const isLastChapter = state.activeChapterIndex + 1 === numberOfChapters
- if (isLastChapter || isUndefined(fromMs) || isUndefined(startOffsetMs)) {
+ const nextChapterIndex = state.activeChapterIndex + 1
+ const nextChapter = chapters[nextChapterIndex]
+ if (!nextChapter) {
return {
- activeChapterIndex: isLastChapter ? 0 : state.activeChapterIndex + 1,
- activePlayer: getNextPlayer(state.activePlayer),
+ activeChapterIndex: 0,
loadedProgress: 0,
playedProgress: 0,
- playing: isLastChapter ? false : state.playing,
+ playing: false,
+ seek: chapters[0].startOffsetMs / 1000,
+ seeking: false,
+ }
+ }
+ if (isUndefined(fromMs) || isUndefined(startOffsetMs)) {
+ return {
+ activeChapterIndex: nextChapterIndex,
+ loadedProgress: 0,
+ playedProgress: 0,
+ seek: nextChapter.startOffsetMs / 1000,
}
}
return {
- activeChapterIndex: state.activeChapterIndex + 1,
+ activeChapterIndex: nextChapterIndex,
loadedProgress: 0,
playedProgress: fromMs,
playing: state.playing,
- seek: {
- ...state.seek,
- [state.activePlayer]: (startOffsetMs + fromMs) / 1000,
- },
+ seek: (startOffsetMs + fromMs) / 1000,
}
})
- }, [numberOfChapters, setPlayerState])
+ }, [chapters, setPlayerState])
const playPrevChapter = useCallback((fromMs?: number, startOffsetMs?: number) => {
setPlayerState((state) => {
if (!state.ready || state.activeChapterIndex === 0) return state
+ const prevChapterIndex = state.activeChapterIndex - 1
+ const prevChapter = chapters[prevChapterIndex]
if (isUndefined(fromMs) || isUndefined(startOffsetMs)) {
return {
- activeChapterIndex: state.activeChapterIndex - 1,
+ activeChapterIndex: prevChapterIndex,
loadedProgress: 0,
playedProgress: 0,
+ seek: prevChapter.startOffsetMs / 1000,
}
}
return {
- activeChapterIndex: state.activeChapterIndex - 1,
+ activeChapterIndex: prevChapterIndex,
loadedProgress: 0,
playedProgress: fromMs,
- seek: {
- ...state.seek,
- [state.activePlayer]: (startOffsetMs + fromMs) / 1000,
- },
+ seek: (startOffsetMs + fromMs) / 1000,
}
})
- }, [setPlayerState])
+ }, [chapters, setPlayerState])
return {
onReady,
diff --git a/src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx b/src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx
similarity index 94%
rename from src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx
rename to src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx
index ed1883d3..6ec28782 100644
--- a/src/features/MultiSourcePlayer/hooks/useProgressChangeHandler.tsx
+++ b/src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx
@@ -38,10 +38,7 @@ export const useProgressChangeHandler = ({
return {
activeChapterIndex: nextChapter,
playedProgress: chapterProgressMs,
- seek: {
- ...state.seek,
- [state.activePlayer]: seekMs / 1000,
- },
+ seek: seekMs / 1000,
seeking,
}
})
diff --git a/src/features/StreamPlayer/index.tsx b/src/features/StreamPlayer/index.tsx
index d6f9bd8b..60e75fd9 100644
--- a/src/features/StreamPlayer/index.tsx
+++ b/src/features/StreamPlayer/index.tsx
@@ -1,34 +1,53 @@
+import { Fragment } from 'react'
+
+import { T9n } from 'features/T9n'
import { Loader } from 'features/Loader'
-import { REWIND_SECONDS } from 'features/MultiSourcePlayer/config'
import { VideoPlayer } from 'features/VideoPlayer'
-import { Name } from 'features/Name'
-import { isMobileDevice } from 'config/userAgent'
+import { secondsToHms } from 'helpers'
+
+import { HOUR_IN_MILLISECONDS, REWIND_SECONDS } from './config'
+import { VolumeBar } from './components/VolumeBar'
+import { Settings } from './components/Settings'
+import { ProgressBar } from './components/ProgressBar'
import {
PlayerWrapper,
- LoaderWrapper,
- ControlsGradient,
+ Controls,
+ ControlsRow,
+ ControlsGroup,
CenterControls,
- Backward,
PlayStop,
+ Fullscreen,
+ LoaderWrapper,
+ Backward,
Forward,
- TeamsDetailsWrapper,
+ PlaybackTime,
+ ControlsGradient,
+ LiveBtn,
+ ChaptersText,
+ Next,
+ Prev,
} from './styled'
import type { Props } from './hooks'
import { useVideoPlayer } from './hooks'
-import { Controls } from './components/Controls'
export const StreamPlayer = (props: Props) => {
- const { profile, url } = props
+ const { chapters, isLive } = props
const {
+ activeChapterIndex,
+ allPlayedProgress,
backToLive,
+ buffering,
controlsVisible,
duration,
+ isFirstChapterPlaying,
isFullscreen,
+ isLastChapterPlaying,
loadedProgress,
muted,
+ numberOfChapters,
onDuration,
onError,
onFullscreenClick,
@@ -36,23 +55,30 @@ export const StreamPlayer = (props: Props) => {
onMouseEnter,
onMouseLeave,
onMouseMove,
+ onPause,
+ onPlay,
onPlayedProgress,
onPlayerClick,
+ onPlaying,
onProgressChange,
onQualitySelect,
+ onReady,
onTouchEnd,
onTouchStart,
onVolumeChange,
onVolumeClick,
+ onWaiting,
playedProgress,
playing,
+ playNextChapter,
+ playPrevChapter,
ready,
rewindBackward,
rewindForward,
seek,
selectedQuality,
- startPlaying,
togglePlaying,
+ url,
videoQualities,
videoRef,
volume,
@@ -71,11 +97,9 @@ export const StreamPlayer = (props: Props) => {
onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd}
>
- {!ready && (
-
-
-
- )}
+
+
+
{
onPlayedProgress={onPlayedProgress}
onDurationChange={onDuration}
onEnded={togglePlaying}
- onReady={startPlaying}
+ onReady={onReady}
+ onPause={onPause}
+ onPlay={onPlay}
+ onPlaying={onPlaying}
+ onWaiting={onWaiting}
onError={onError}
crossOrigin='use-credentials'
/>
-
- {isMobileDevice && isFullscreen && controlsVisible && profile && (
-
-
- {` ${profile.team1.score}-${profile.team2.score} `}
-
-
- )}
-
{ready && (
@@ -120,34 +139,83 @@ export const StreamPlayer = (props: Props) => {
)}
-
-
+
+
+
+
+
+
+
+ {
+ numberOfChapters > 1 && (
+
+ playPrevChapter()}
+ />
+
+ {activeChapterIndex + 1} / {numberOfChapters}
+
+ playNextChapter()}
+ />
+
+ )
+ }
+
+ {
+ isLive
+ ? (
+
+ {secondsToHms(allPlayedProgress / 1000)}
+
+ )
+ : (
+ HOUR_IN_MILLISECONDS ? 150 : 130}>
+ {secondsToHms(allPlayedProgress / 1000)}
+ {' / '}
+ {secondsToHms(duration / 1000)}
+
+ )
+ }
+ {REWIND_SECONDS}
+ {REWIND_SECONDS}
+
+
+ {
+ isLive && (
+
+
+
+ )
+ }
+
+
+
+
+
+
)
}
diff --git a/src/features/StreamPlayer/styled.tsx b/src/features/StreamPlayer/styled.tsx
index 9b1b11e4..026438c7 100644
--- a/src/features/StreamPlayer/styled.tsx
+++ b/src/features/StreamPlayer/styled.tsx
@@ -128,15 +128,23 @@ export const PlayerWrapper = styled.div`
: ''};
`
-export const LoaderWrapper = styled.div`
+type LoaderWrapperProps = {
+ buffering: boolean,
+}
+
+export const LoaderWrapper = styled.div`
position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ z-index: 1;
+ transition: opacity 0.3s ease-in-out;
+
+ opacity: ${({ buffering }) => (
+ buffering
+ ? 1
+ : 0
+ )};
`
export const ButtonBase = styled.button`
@@ -324,3 +332,47 @@ export const TeamsDetailsWrapper = styled.div`
color: #FFFFFF;
z-index: 50;
`
+
+export const ChaptersText = styled.span`
+ margin: 0 14px;
+ font-weight: 500;
+ font-size: 16px;
+ color: #fff;
+ text-align: center;
+
+ ${isMobileDevice
+ ? css`
+ margin: 0 5px;
+ font-size: 12px;
+ width: 15%;
+ `
+ : ''};
+`
+
+type PrevProps = {
+ disabled?: boolean,
+}
+
+export const Prev = styled(ButtonBase)`
+ width: 29px;
+ height: 28px;
+ background-image: url(/images/player-prev.svg);
+
+ ${({ disabled }) => (
+ disabled
+ ? 'opacity: 0.5;'
+ : ''
+ )}
+
+ ${isMobileDevice
+ ? css`
+ width: 20px;
+ height: 20px;
+ `
+ : ''};
+`
+
+export const Next = styled(Prev)`
+ margin-right: 10px;
+ transform: rotate(180deg);
+`
diff --git a/src/features/MultiSourcePlayer/types.tsx b/src/features/StreamPlayer/types.tsx
similarity index 55%
rename from src/features/MultiSourcePlayer/types.tsx
rename to src/features/StreamPlayer/types.tsx
index 50c6ab29..088a62b0 100644
--- a/src/features/MultiSourcePlayer/types.tsx
+++ b/src/features/StreamPlayer/types.tsx
@@ -1,18 +1,11 @@
-export type Urls = { [quality: string]: string }
-
export type Chapter = {
duration: number,
endMs: number,
endOffsetMs: number,
- period: number,
+ index?: number,
startMs: number,
startOffsetMs: number,
- urls: Urls,
+ url: string,
}
export type Chapters = Array
-
-export enum Players {
- PLAYER1 = 0,
- PLAYER2 = 1,
-}
diff --git a/src/features/VideoPlayer/hooks/index.tsx b/src/features/VideoPlayer/hooks/index.tsx
index bff60797..d0484023 100644
--- a/src/features/VideoPlayer/hooks/index.tsx
+++ b/src/features/VideoPlayer/hooks/index.tsx
@@ -25,8 +25,11 @@ export type Props = {
onError?: (e?: SyntheticEvent) => void,
onLoadedProgress?: (loadedMs: number) => void,
onPause?: (e: SyntheticEvent) => void,
+ onPlay?: (e: SyntheticEvent) => void,
onPlayedProgress?: (playedMs: number) => void,
+ onPlaying?: () => void,
onReady?: () => void,
+ onWaiting?: () => void,
playing?: boolean,
ref?: Ref,
seek?: number | null,
diff --git a/src/features/VideoPlayer/index.tsx b/src/features/VideoPlayer/index.tsx
index 05dac725..42b51e90 100644
--- a/src/features/VideoPlayer/index.tsx
+++ b/src/features/VideoPlayer/index.tsx
@@ -15,6 +15,9 @@ export const VideoPlayer = forwardRef((props: Props, re
onEnded,
onError,
onPause,
+ onPlay,
+ onPlaying,
+ onWaiting,
src,
width,
} = props
@@ -40,8 +43,11 @@ export const VideoPlayer = forwardRef((props: Props, re
onProgress={handleLoadedChange}
onEnded={onEnded}
onDurationChange={handleDurationChange}
+ onPlay={onPlay}
onPause={onPause}
onError={onError}
+ onWaiting={onWaiting}
+ onPlaying={onPlaying}
crossOrigin={crossOrigin}
controls={controls}
/>