From 86a9ed498d2b5818ad85232cc4f886656c4b8366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D1=82=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B5=D0=B2=20=D0=9C=D0=B8=D1=80=D0=BB=D0=B0=D0=BD?= Date: Wed, 1 Dec 2021 10:50:54 +0300 Subject: [PATCH] Ott 1701 part 5 --- package.json | 3 +- .../components/LiveMatch/helpers.tsx | 15 ++++++-- .../store/hooks/useMatchPlaylists.tsx | 5 +++ .../helpers/calculateChapterStyles/index.tsx | 6 ++-- src/features/StreamPlayer/config.tsx | 4 +-- src/features/StreamPlayer/helpers/index.tsx | 36 +++++-------------- src/features/StreamPlayer/hooks/index.tsx | 6 +--- .../hooks/useProgressChangeHandler.tsx | 4 +-- .../StreamPlayer/hooks/useVideoQuality.tsx | 6 ++-- src/features/StreamPlayer/index.tsx | 3 ++ src/features/StreamPlayer/types.tsx | 22 ++++++++++++ src/features/VideoPlayer/index.tsx | 10 ++++++ 12 files changed, 73 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 2436e172..1a69883f 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "babel-polyfill": "^6.26.0", "date-fns": "^2.14.0", "history": "^4.10.1", - "hls.js": "^0.14.15", + "hls.js": "^1.1.1", "lodash": "^4.17.15", "m3u8-parser": "^4.7.0", "oidc-client": "^1.11.5", @@ -56,7 +56,6 @@ "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^7.1.2", "@types/history": "^4.7.6", - "@types/hls.js": "^0.13.2", "@types/jest": "^26.0.15", "@types/lodash": "^4.14.154", "@types/node": "^12.0.0", diff --git a/src/features/MatchPage/components/LiveMatch/helpers.tsx b/src/features/MatchPage/components/LiveMatch/helpers.tsx index 01793814..5bb69240 100644 --- a/src/features/MatchPage/components/LiveMatch/helpers.tsx +++ b/src/features/MatchPage/components/LiveMatch/helpers.tsx @@ -4,11 +4,15 @@ import concat from 'lodash/concat' import type { Episodes } from 'requests/getMatchPlaylists' -import type { Chapters } from 'features/StreamPlayer/types' +import type { Chapters, Chapter } from 'features/StreamPlayer/types' import type { MatchPlaylistOption, PlaylistOption } from '../../types' import { FULL_GAME_KEY } from '../../helpers/buildPlaylists' +/** + * Формирует эпизоды плейлиста Полный матч + * API не выдает полный матч как плейлист, формируем на фронте + * */ const getFullMatchChapters = (url: string, playlist: MatchPlaylistOption) => { const duration = (playlist.duration ?? 0) * 1000 return [ @@ -17,6 +21,7 @@ const getFullMatchChapters = (url: string, playlist: MatchPlaylistOption) => { endMs: duration, endOffsetMs: duration, index: 0, + isFullMatchChapter: true, startMs: 0, startOffsetMs: 0, url, @@ -24,6 +29,9 @@ const getFullMatchChapters = (url: string, playlist: MatchPlaylistOption) => { ] } +/** + * Формирует эпизоды плейлистов матча и игроков + * */ const getPlaylistChapters = (url: string, episodes: Episodes) => reduce( episodes, ( @@ -35,7 +43,7 @@ const getPlaylistChapters = (url: string, episodes: Episodes) => reduce( const episodeDuration = (episode.e - episode.s) * 1000 const prevVideoEndMs = last(acc)?.endMs || 0 - const nextChapter = { + const nextChapter: Chapter = { duration: episodeDuration, endMs: prevVideoEndMs + episodeDuration, endOffsetMs: episode.e * 1000, @@ -54,6 +62,9 @@ type Args = { url: string, } +/** + * Формирует список эпизодов из выбранного плейлиста для плеера + */ export const buildChapters = ({ selectedPlaylist, url, diff --git a/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx b/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx index 70feee6b..a8773b69 100644 --- a/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx +++ b/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx @@ -56,6 +56,11 @@ export const useMatchPlaylists = () => { .then(setMatchPlaylists) }, [fetchLexics, setInitialSeletedPlaylist]) + /** + * API не выдает длительность Полного матча + * Здесь получаем его из самого видео + * и обновляем длительность плейлиста Полный матч + */ const setFullMatchPlaylistDuration = (duration: number) => { const playlists = [...matchPlaylists.match] if (!playlists[0]) return diff --git a/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx b/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx index 498aac56..8bf4bde5 100644 --- a/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx +++ b/src/features/StreamPlayer/components/ProgressBar/helpers/calculateChapterStyles/index.tsx @@ -49,9 +49,9 @@ export const calculateChapterStyles = ({ ...chapter, loaded: calculateChapterProgress(loadedProgress, chapter), played: calculateChapterProgress(playedProgress, chapter), - width: chapter.duration - ? chapter.duration * 100 / videoDuration - : 100, + width: chapter.isFullMatchChapter + ? 100 + : chapter.duration * 100 / videoDuration, } return [ ...playedChapters, diff --git a/src/features/StreamPlayer/config.tsx b/src/features/StreamPlayer/config.tsx index b32ff717..77418095 100644 --- a/src/features/StreamPlayer/config.tsx +++ b/src/features/StreamPlayer/config.tsx @@ -1,8 +1,8 @@ -import Hls from 'hls.js' +import type { HlsConfig } from 'hls.js' import { readToken } from 'helpers/token' -export const streamConfig: Partial = { +export const streamConfig: Partial = { liveSyncDuration: 30, maxBufferLength: 30, xhrSetup: (xhr, urlString) => { diff --git a/src/features/StreamPlayer/helpers/index.tsx b/src/features/StreamPlayer/helpers/index.tsx index 062dd10c..854ce2c3 100644 --- a/src/features/StreamPlayer/helpers/index.tsx +++ b/src/features/StreamPlayer/helpers/index.tsx @@ -1,33 +1,13 @@ -import { RefObject } from 'react' - import findIndex from 'lodash/findIndex' +import size from 'lodash/size' import type { Chapters } from '../types' -type Args = { - from?: number, - url: string, - videoRef: RefObject, +export const findChapterByProgress = (chapters: Chapters, progressMs: number) => { + if (size(chapters) === 1 && chapters[0].isFullMatchChapter) return 0 + return ( + findIndex(chapters, ({ endMs, startMs }) => ( + startMs <= progressMs && progressMs <= endMs + )) + ) } - -export const preparePlayer = ({ - from = 0, - url, - videoRef, -}: Args) => { - const video = videoRef?.current - if (!video) return - - // eslint-disable-next-line no-param-reassign - video.src = url - if (from) { - video.currentTime = from - } - video.load() -} - -export const findChapterByProgress = (chapters: Chapters, progressMs: number) => ( - findIndex(chapters, ({ endMs, startMs }) => ( - startMs <= progressMs && progressMs <= endMs - )) -) diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index f0cab226..70adf164 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -75,11 +75,7 @@ export const useVideoPlayer = ({ ready, seek, seeking, - }, setPlayerState] = useObjectState({ - ...initialState, - playedProgress: toMilliSeconds(resumeFrom || 0), - seek: resumeFrom || 0, - }) + }, setPlayerState] = useObjectState(initialState) const chaptersDuration = useDuration(chapters) diff --git a/src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx b/src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx index 6ec28782..17788fe8 100644 --- a/src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx +++ b/src/features/StreamPlayer/hooks/useProgressChangeHandler.tsx @@ -31,8 +31,8 @@ export const useProgressChangeHandler = ({ ? chapterIndex : state.activeChapterIndex - // отнимаем начало главы на котором остановились от общего прогресса - // чтобы получить прогресс текущей главы + // отнимаем начало эпизода на котором остановились от общего прогресса + // чтобы получить прогресс текущего эпизода const chapterProgressMs = (progressMs - chapter.startMs) const seekMs = chapterProgressMs + chapter.startOffsetMs return { diff --git a/src/features/StreamPlayer/hooks/useVideoQuality.tsx b/src/features/StreamPlayer/hooks/useVideoQuality.tsx index c8617513..43b968c1 100644 --- a/src/features/StreamPlayer/hooks/useVideoQuality.tsx +++ b/src/features/StreamPlayer/hooks/useVideoQuality.tsx @@ -4,7 +4,7 @@ import { useCallback, } from 'react' -import Hls from 'hls.js' +import Hls, { Level } from 'hls.js' import map from 'lodash/map' import find from 'lodash/find' @@ -28,9 +28,9 @@ const autoQuality = { * непонятное качество без свойств height, width и тд для определения * какое это качество */ -const filterOutUnknownQualities = filter(({ height }: Hls.Level) => Boolean(height)) +const filterOutUnknownQualities = filter(({ height }: Level) => Boolean(height)) -const getVideoQualities = (levels: Array) => { +const getVideoQualities = (levels: Array) => { if (isEmpty(levels)) return [] const filteredQualities = filterOutUnknownQualities(levels) diff --git a/src/features/StreamPlayer/index.tsx b/src/features/StreamPlayer/index.tsx index 60e75fd9..f5e9dcfb 100644 --- a/src/features/StreamPlayer/index.tsx +++ b/src/features/StreamPlayer/index.tsx @@ -32,6 +32,9 @@ import { import type { Props } from './hooks' import { useVideoPlayer } from './hooks' +/** + * HLS плеер, применяется на лайв и завершенных матчах + */ export const StreamPlayer = (props: Props) => { const { chapters, isLive } = props diff --git a/src/features/StreamPlayer/types.tsx b/src/features/StreamPlayer/types.tsx index 088a62b0..e90a6fb1 100644 --- a/src/features/StreamPlayer/types.tsx +++ b/src/features/StreamPlayer/types.tsx @@ -1,9 +1,31 @@ +/** + * для примера матч с двумя эпизодами в плейлисте Голы, время в мс: + * [{start: 0, end: 20000}, {start: 60000, end: 80000}] +*/ + export type Chapter = { duration: number, + + /** + * конец эпизода в плейлисте + * в первом эпизоде - 20000, во втором - 40000 + */ endMs: number, + + /** конец эпизода как отмечено в матче */ endOffsetMs: number, + + /** индекс эпизода для дебага */ index?: number, + isFullMatchChapter?: boolean, + + /** + * начало эпизода в плейлисте + * в первом эпизоде - 0, во втором - 20000 + */ startMs: number, + + /** начало эпизода как отмечено в матче */ startOffsetMs: number, url: string, } diff --git a/src/features/VideoPlayer/index.tsx b/src/features/VideoPlayer/index.tsx index 42b51e90..bc56c661 100644 --- a/src/features/VideoPlayer/index.tsx +++ b/src/features/VideoPlayer/index.tsx @@ -4,6 +4,16 @@ import type { Props } from './hooks' import { useVideoPlayer } from './hooks' import { Video } from './styled' +/** + * Низкоуровневый компонент для декларативной работы с HTMLVideoElement + * ```ts + * например старт и пауза плеера вместо + * video.play() | video.pause() + * + * контролируем через пропс playing + * + * ``` + */ export const VideoPlayer = forwardRef((props: Props, ref) => { const { className,