Ott 1701 part 2 (#553)

* refactor(1725): video width 100%

* refactor(1701): building playlists and chapters
keep-around/fdb88b04b32b9392e76795099e2ec47c9856b38b
Mirlan 4 years ago committed by Andrei Dekterev
parent 95d0194c5b
commit 950a02c7ae
  1. 66
      src/features/MatchPage/components/LiveMatch/helpers.tsx
  2. 65
      src/features/MatchPage/components/LiveMatch/hooks/index.tsx
  3. 28
      src/features/MatchPage/components/LiveMatch/hooks/useChapters.tsx
  4. 2
      src/features/MatchPage/components/LiveMatch/hooks/usePlaylistLogger.tsx
  5. 23
      src/features/MatchPage/components/LiveMatch/hooks/useResumeUrlParam.tsx
  6. 6
      src/features/MatchPage/components/LiveMatch/index.tsx
  7. 2
      src/features/MatchPage/helpers/buildPlaylists.tsx
  8. 5
      src/features/MatchPage/store/hooks/usePlaylistLexics.tsx
  9. 2
      src/requests/getMatchEvents.tsx
  10. 32
      src/requests/getMatchPlaylists.tsx

@ -0,0 +1,66 @@
import last from 'lodash/last'
import reduce from 'lodash/reduce'
import concat from 'lodash/concat'
import type { Episodes } from 'requests/getMatchPlaylists'
import type { Chapters } from 'features/StreamPlayer/types'
import type { MatchPlaylistOption, PlaylistOption } from '../../types'
import { FULL_GAME_KEY } from '../../helpers/buildPlaylists'
const getFullMatchChapters = (url: string, playlist: MatchPlaylistOption) => {
const duration = (playlist.duration ?? 0) * 1000
return [
{
duration,
endMs: duration,
endOffsetMs: duration,
index: 0,
startMs: 0,
startOffsetMs: 0,
url,
},
]
}
const getPlaylistChapters = (url: string, episodes: Episodes) => reduce(
episodes,
(
acc: Chapters,
episode,
index,
) => {
if (episode.s >= episode.e) return acc
const episodeDuration = (episode.e - episode.s) * 1000
const prevVideoEndMs = last(acc)?.endMs || 0
const nextChapter = {
duration: episodeDuration,
endMs: prevVideoEndMs + episodeDuration,
endOffsetMs: episode.e * 1000,
index,
startMs: prevVideoEndMs,
startOffsetMs: episode.s * 1000,
url,
}
return concat(acc, nextChapter)
},
[],
)
type Args = {
selectedPlaylist?: PlaylistOption,
url: string,
}
export const buildChapters = ({
selectedPlaylist,
url,
}: Args): Chapters => {
if (!selectedPlaylist) return []
if (selectedPlaylist.id === FULL_GAME_KEY) {
return getFullMatchChapters(url, selectedPlaylist)
}
return getPlaylistChapters(url, selectedPlaylist.episodes)
}

@ -2,25 +2,24 @@ import { useMemo } from 'react'
import { API_ROOT } from 'config'
import type { MatchInfo } from 'requests/getMatchInfo'
import { usePageParams } from 'hooks/usePageParams'
import { useMatchPopupStore } from 'features/MatchPopup'
import { useMatchPageStore } from 'features/MatchPage/store'
import { usePlayerProgressReporter } from './usePlayerProgressReporter'
import { useLastPlayPosition } from './useLastPlayPosition'
import { useUrlParam } from './useUrlParam'
import { useResumeUrlParam } from './useResumeUrlParam'
import { useChapters } from './useChapters'
import { usePlaylistLogger } from './usePlaylistLogger'
export const useLiveMatch = (profile: MatchInfo) => {
export const useLiveMatch = () => {
const {
handlePlaylistClick,
matchPlaylists,
profile,
selectedPlaylist,
} = useMatchPopupStore()
setFullMatchPlaylistDuration,
} = useMatchPageStore()
const { profileId: matchId, sportType } = usePageParams()
const resume = useUrlParam()
const resume = useResumeUrlParam()
const fromStartIfStreamPaused = useMemo(
() => (profile && !profile.live ? 0 : undefined),
@ -30,13 +29,49 @@ export const useLiveMatch = (profile: MatchInfo) => {
[],
)
const { chapters } = useChapters({
selectedPlaylist,
url: `${API_ROOT}/video/stream/${sportType}/${matchId}.m3u8`,
})
const {
logPlaylistChange,
onPlayingChange: notifyPlaylistLogger,
} = usePlaylistLogger()
const {
onPlayerProgressChange,
onPlayingChange: notifyProgressLogger,
} = usePlayerProgressReporter()
const onDurationChange = (duration: number) => {
if (profile?.live) return
setFullMatchPlaylistDuration(duration)
}
const onPlayingChange = (playing: boolean) => {
notifyPlaylistLogger(playing)
notifyProgressLogger(playing)
}
const onPlaylistSelect: typeof handlePlaylistClick = (playlist, e) => {
if (selectedPlaylist) {
logPlaylistChange(selectedPlaylist)
}
handlePlaylistClick(playlist, e)
}
return {
matchPlaylists,
onPlaylistSelect: handlePlaylistClick,
chapters,
onDurationChange,
onPlayerProgressChange,
onPlayingChange,
onPlaylistSelect,
resume: resume ?? fromStartIfStreamPaused,
selectedPlaylist,
streamUrl: `${API_ROOT}/video/stream/${sportType}/${matchId}.m3u8`,
...usePlayerProgressReporter(),
...useLastPlayPosition(),
streamUrl: (
profile?.playbackUrl
|| `${API_ROOT}/video/stream/${sportType}/${matchId}.m3u8`
),
}
}

@ -0,0 +1,28 @@
import { useMemo } from 'react'
import type { PlaylistOption } from 'features/MatchPage/types'
import { buildChapters } from '../helpers'
type Args = {
selectedPlaylist?: PlaylistOption,
url: string,
}
export const useChapters = ({
selectedPlaylist,
url,
}: Args) => {
const chapters = useMemo(
() => buildChapters({
selectedPlaylist,
url,
}),
[
selectedPlaylist,
url,
],
)
return { chapters }
}

@ -21,7 +21,7 @@ const playlistTypeConfig = {
const getInitialData = () => ({ dateVisit: new Date().toISOString(), seconds: 0 })
export const usePlayerLogger = () => {
export const usePlaylistLogger = () => {
const location = useLocation()
const { profileId, sportType } = usePageParams()
const data = useRef(getInitialData())

@ -0,0 +1,23 @@
import { useMemo } from 'react'
import { useLocation } from 'react-router'
import isNumber from 'lodash/isNumber'
export const RESUME_KEY = 'resume'
const readResumeParam = (search: string) => {
const params = new URLSearchParams(search)
const rawValue = params.get(RESUME_KEY)
if (!rawValue) return undefined
const value = JSON.parse(rawValue)
return isNumber(value) ? value : 0
}
export const useResumeUrlParam = () => {
const { search } = useLocation()
const resume = useMemo(() => readResumeParam(search), [search])
return resume
}

@ -38,15 +38,13 @@ export const LiveMatch = ({
onPlaylistSelect,
resume,
streamUrl,
} = useLiveMatch(profile)
const Player = profile?.youtube_link ? YoutubePlayer : StreamPlayer
} = useLiveMatch()
return (
<Fragment>
<Container>
{profile?.youtube_link ? (
<Player
<YoutubePlayer
onPlayingChange={onPlayingChange}
onProgressChange={onPlayerProgressChange}
profile={profile}

@ -25,7 +25,7 @@ const getMatchPlaylists = (matchPlaylists: MatchPlaylists | null): MatchPlaylist
return map(MATCH_KEYS, (key) => {
const playlist = matchPlaylists[key]
const lexic = matchPlaylists.lexics[key]
const lexic = matchPlaylists.lexics[key] ?? ''
return {
duration: playlist?.dur,
episodes: sortBy(playlist?.data, ['h', 's']),

@ -1,6 +1,7 @@
import { useCallback } from 'react'
import isEmpty from 'lodash/isEmpty'
import compact from 'lodash/compact'
import values from 'lodash/values'
import type { MatchPlaylists } from 'requests'
@ -9,8 +10,8 @@ import { useLexicsStore } from 'features/LexicsStore'
export const usePlaylistLexics = () => {
const { addLexicsConfig } = useLexicsStore()
const fetchLexics = useCallback((playlist: MatchPlaylists | null) => {
const lexics = values(playlist?.lexics)
const fetchLexics = useCallback((playlist: MatchPlaylists) => {
const lexics = compact(values(playlist.lexics))
if (!isEmpty(lexics)) {
addLexicsConfig(lexics)
}

@ -76,5 +76,7 @@ export const getMatchEvents = async ({
url: `${DATA_URL}/${getSportLexic(sportType)}`,
})
if (!response?.data) return Promise.reject(response)
return response?.data || []
}

@ -49,12 +49,12 @@ type Player = {
export type Players = Array<Player>
export type Lexics = {
ball_in_play: number,
full_game: number,
goals: number,
highlights: number,
interview: number,
players: number,
ball_in_play?: number,
full_game?: number,
goals?: number,
highlights?: number,
interview?: number,
players?: number,
}
export type MatchPlaylists = {
@ -79,7 +79,7 @@ export const getMatchPlaylists = async ({
selectedActions,
sportType,
withFullMatchDuration,
}: Args) => {
}: Args): Promise<MatchPlaylists> => {
const actions = isEmpty(selectedActions) ? null : selectedActions
const config = {
@ -110,7 +110,19 @@ export const getMatchPlaylists = async ({
dur: fullMatchDuration,
}
return playlist.data
? { ...playlist.data, full_game }
: null
if (playlist.data) {
return { ...playlist.data, full_game }
}
return {
ball_in_play: {},
full_game,
goals: {},
highlights: {},
lexics: {},
players1: [],
players2: [],
score1: 0,
score2: 0,
}
}

Loading…
Cancel
Save