fix(1701): playing stream in between time boundaries

keep-around/fdb88b04b32b9392e76795099e2ec47c9856b38b
Mirlan 4 years ago committed by Andrei Dekterev
parent 8cf1637f14
commit 6ed39e2570
  1. 41
      src/features/MatchPage/components/LiveMatch/helpers.tsx
  2. 2
      src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx
  3. 22
      src/features/StreamPlayer/hooks/index.tsx
  4. 3
      src/features/StreamPlayer/index.tsx
  5. 6
      src/requests/getMatchInfo.tsx

@ -1,30 +1,38 @@
import last from 'lodash/last' import last from 'lodash/last'
import find from 'lodash/find'
import reduce from 'lodash/reduce' import reduce from 'lodash/reduce'
import concat from 'lodash/concat' import concat from 'lodash/concat'
import type { Episodes } from 'requests/getMatchPlaylists' import type { Episodes } from 'requests/getMatchPlaylists'
import type { MatchInfo } from 'requests/getMatchInfo'
import type { Chapters, Chapter } from 'features/StreamPlayer/types' import type { Chapters, Chapter } from 'features/StreamPlayer/types'
import type { MatchInfo, VideoBound } from 'requests/getMatchInfo'
import type { MatchPlaylistOption, PlaylistOption } from '../../types' import type { MatchPlaylistOption, PlaylistOption } from '../../types'
import { FULL_GAME_KEY } from '../../helpers/buildPlaylists' import { FULL_GAME_KEY } from '../../helpers/buildPlaylists'
export const FULL_MATCH_BOUNDARY = '0'
/** /**
* Формирует эпизоды плейлиста Полный матч * Формирует эпизоды плейлиста Полный матч
* API не выдает полный матч как плейлист, формируем на фронте * API не выдает полный матч как плейлист, формируем на фронте
* */ * */
const getFullMatchChapters = (url: string, playlist: MatchPlaylistOption) => { const getFullMatchChapters = (
const duration = (playlist.duration ?? 0) * 1000 profile: MatchInfo,
url: string,
playlist: MatchPlaylistOption,
) => {
const bound = find(profile?.video_bounds, { h: FULL_MATCH_BOUNDARY })
const durationMs = (playlist.duration ?? 0) * 1000
return [ return [
{ {
duration, duration: durationMs,
endMs: duration, endMs: durationMs,
endOffsetMs: duration, endOffsetMs: bound ? Number(bound.e) * 1000 : durationMs,
index: 0, index: 0,
isFullMatchChapter: true, isFullMatchChapter: true,
startMs: 0, startMs: 0,
startOffsetMs: 0, startOffsetMs: bound ? Number(bound.s) * 1000 : 0,
url, url,
}, },
] ]
@ -46,20 +54,19 @@ const getPlaylistChapters = (
) => { ) => {
if (episode.s >= episode.e) return acc if (episode.s >= episode.e) return acc
const bound = profile!.video_bounds!.filter( const bound = find(profile?.video_bounds, { h: String(episode.h) })
(ep: VideoBound) => Number(ep.h) === Number(episode.h), const boundStart = bound ? Number(bound.s) : 0
)
const episodeDuration = (episode.e - episode.s) * 1000 const episodeDuration = (episode.e - episode.s) * 1000
const prevVideoEndMs = (last(acc)?.endMs ?? bound[0].s * 1000) || 0 const prevVideoEndMs = last(acc)?.endMs ?? 0
const nextChapter: Chapter = { const nextChapter: Chapter = {
duration: episodeDuration, duration: episodeDuration,
endMs: prevVideoEndMs + episodeDuration, endMs: prevVideoEndMs + episodeDuration,
endOffsetMs: prevVideoEndMs + episode.e * 1000, endOffsetMs: (boundStart + episode.e) * 1000,
index, index,
startMs: 0, startMs: prevVideoEndMs,
startOffsetMs: prevVideoEndMs + episode.s * 1000, startOffsetMs: (boundStart + episode.s) * 1000,
url, url,
} }
return concat(acc, nextChapter) return concat(acc, nextChapter)
@ -83,7 +90,11 @@ export const buildChapters = ({
}: Args): Chapters => { }: Args): Chapters => {
if (!selectedPlaylist) return [] if (!selectedPlaylist) return []
if (selectedPlaylist.id === FULL_GAME_KEY) { if (selectedPlaylist.id === FULL_GAME_KEY) {
return getFullMatchChapters(url, selectedPlaylist) return getFullMatchChapters(
profile,
url,
selectedPlaylist,
)
} }
return getPlaylistChapters( return getPlaylistChapters(
profile, profile,

@ -44,7 +44,7 @@ export const calculateChapterStyles = ({
})), })),
)(chapters) )(chapters)
const chapter = chapters[activeChapterIndex] ?? chapters[0] const chapter = chapters[activeChapterIndex]
const activeChapter = { const activeChapter = {
...chapter, ...chapter,

@ -35,6 +35,7 @@ const toMilliSeconds = (seconds: number) => seconds * 1000
const initialState = { const initialState = {
activeChapterIndex: 0, activeChapterIndex: 0,
buffering: true, buffering: true,
chapters: [] as Chapters,
duration: 0, duration: 0,
loadedProgress: 0, loadedProgress: 0,
playedProgress: 0, playedProgress: 0,
@ -54,20 +55,17 @@ export type Props = {
} }
export const useVideoPlayer = ({ export const useVideoPlayer = ({
chapters, chapters: chaptersProps,
isLive, isLive,
onDurationChange, onDurationChange,
onPlayingChange, onPlayingChange,
onProgressChange: progressChangeCallback, onProgressChange: progressChangeCallback,
resumeFrom, resumeFrom,
}: Props) => { }: Props) => {
const { url } = chapters[0]
const numberOfChapters = size(chapters)
const { hls, videoRef } = useHlsPlayer(url, resumeFrom)
const [{ const [{
activeChapterIndex, activeChapterIndex,
buffering, buffering,
chapters,
duration: fullMatchDuration, duration: fullMatchDuration,
loadedProgress, loadedProgress,
playedProgress, playedProgress,
@ -75,7 +73,11 @@ export const useVideoPlayer = ({
ready, ready,
seek, seek,
seeking, seeking,
}, setPlayerState] = useObjectState(initialState) }, setPlayerState] = useObjectState({ ...initialState, chapters: chaptersProps })
const { url } = chapters[0] ?? { url: '' }
const numberOfChapters = size(chapters)
const { hls, videoRef } = useHlsPlayer(url, resumeFrom)
const chaptersDuration = useDuration(chapters) const chaptersDuration = useDuration(chapters)
@ -90,7 +92,7 @@ export const useVideoPlayer = ({
} = usePlayingHandlers(setPlayerState, chapters) } = usePlayingHandlers(setPlayerState, chapters)
const getActiveChapter = useCallback( const getActiveChapter = useCallback(
(index: number = activeChapterIndex) => chapters[index] ?? chapters[0], (index: number = activeChapterIndex) => chapters[index],
[chapters, activeChapterIndex], [chapters, activeChapterIndex],
) )
@ -219,10 +221,11 @@ export const useVideoPlayer = ({
useEffect(() => { useEffect(() => {
setPlayerState({ setPlayerState({
...initialState, ...initialState,
chapters: chaptersProps,
playing: true, playing: true,
seek: chapters[0].startOffsetMs / 1000, seek: chaptersProps[0].startOffsetMs / 1000,
}) })
}, [chapters, setPlayerState]) }, [chaptersProps, setPlayerState])
useEffect(() => { useEffect(() => {
if (isLive || isEmpty(chapters)) return if (isLive || isEmpty(chapters)) return
@ -277,6 +280,7 @@ export const useVideoPlayer = ({
allPlayedProgress: playedProgress + getActiveChapter().startMs, allPlayedProgress: playedProgress + getActiveChapter().startMs,
backToLive, backToLive,
buffering, buffering,
chapters,
duration, duration,
isFirstChapterPlaying, isFirstChapterPlaying,
isFullscreen, isFullscreen,

@ -36,13 +36,14 @@ import { useVideoPlayer } from './hooks'
* HLS плеер, применяется на лайв и завершенных матчах * HLS плеер, применяется на лайв и завершенных матчах
*/ */
export const StreamPlayer = (props: Props) => { export const StreamPlayer = (props: Props) => {
const { chapters, isLive } = props const { isLive } = props
const { const {
activeChapterIndex, activeChapterIndex,
allPlayedProgress, allPlayedProgress,
backToLive, backToLive,
buffering, buffering,
chapters,
controlsVisible, controlsVisible,
duration, duration,
isFirstChapterPlaying, isFirstChapterPlaying,

@ -17,9 +17,9 @@ export type Team = {
} }
export type VideoBound = { export type VideoBound = {
e: number, e: string,
h: number, h: string,
s: number, s: string,
} }
type VideoBounds = Array<VideoBound> type VideoBounds = Array<VideoBound>

Loading…
Cancel
Save