Refactor ChannelPlayer component: remove play/pause functionality and related state management, update comments for clarity, and streamline audio control features for a live streaming experience.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import Hls from 'hls.js'
|
import Hls from 'hls.js'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Maximize, Pause, Play, Volume2, VolumeX } from 'lucide-react'
|
import { Maximize, Volume2, VolumeX } from 'lucide-react'
|
||||||
|
|
||||||
const STORAGE_KEY = 'tw:player'
|
const STORAGE_KEY = 'tw:player'
|
||||||
|
|
||||||
@@ -23,8 +23,8 @@ function readStoredAudio(): { volume: number; muted: boolean } {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HLS-плеер линейного канала. Перемотка невозможна: своя минимальная панель без таймлайна, а на
|
* HLS-плеер линейного канала. Это живой эфир: ни перемотки, ни паузы — только звук, громкость и
|
||||||
* play/после ошибки плеер прыгает к живому краю. Cookie tw_stream уже выдана к монтированию.
|
* полноэкранный режим. Cookie tw_stream уже выдана к монтированию.
|
||||||
*/
|
*/
|
||||||
export function ChannelPlayer({
|
export function ChannelPlayer({
|
||||||
slug,
|
slug,
|
||||||
@@ -37,7 +37,6 @@ export function ChannelPlayer({
|
|||||||
const containerRef = useRef<HTMLDivElement>(null)
|
const containerRef = useRef<HTMLDivElement>(null)
|
||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
const videoRef = useRef<HTMLVideoElement>(null)
|
||||||
const hlsRef = useRef<Hls | null>(null)
|
const hlsRef = useRef<Hls | null>(null)
|
||||||
const [playing, setPlaying] = useState(false)
|
|
||||||
const [muted, setMuted] = useState(() => readStoredAudio().muted)
|
const [muted, setMuted] = useState(() => readStoredAudio().muted)
|
||||||
const [volume, setVolume] = useState(() => readStoredAudio().volume)
|
const [volume, setVolume] = useState(() => readStoredAudio().volume)
|
||||||
|
|
||||||
@@ -79,17 +78,6 @@ export function ChannelPlayer({
|
|||||||
|
|
||||||
useEffect(() => clearHideTimer, [clearHideTimer])
|
useEffect(() => clearHideTimer, [clearHideTimer])
|
||||||
|
|
||||||
const seekToLiveEdge = useCallback(() => {
|
|
||||||
const video = videoRef.current
|
|
||||||
if (!video) return
|
|
||||||
const live = hlsRef.current?.liveSyncPosition
|
|
||||||
if (typeof live === 'number' && Number.isFinite(live)) {
|
|
||||||
video.currentTime = live
|
|
||||||
} else if (video.seekable.length > 0) {
|
|
||||||
video.currentTime = video.seekable.end(video.seekable.length - 1)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const video = videoRef.current
|
const video = videoRef.current
|
||||||
if (!video) return
|
if (!video) return
|
||||||
@@ -137,17 +125,6 @@ export function ChannelPlayer({
|
|||||||
}
|
}
|
||||||
}, [slug, onUnavailable])
|
}, [slug, onUnavailable])
|
||||||
|
|
||||||
const togglePlay = () => {
|
|
||||||
const video = videoRef.current
|
|
||||||
if (!video) return
|
|
||||||
if (video.paused) {
|
|
||||||
seekToLiveEdge()
|
|
||||||
void video.play().catch(() => undefined)
|
|
||||||
} else {
|
|
||||||
video.pause()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Установить громкость (0..1); 0 = mute, >0 запоминаем как последний уровень для «размьютить».
|
// Установить громкость (0..1); 0 = mute, >0 запоминаем как последний уровень для «размьютить».
|
||||||
const applyVolume = (value: number) => {
|
const applyVolume = (value: number) => {
|
||||||
const video = videoRef.current
|
const video = videoRef.current
|
||||||
@@ -194,14 +171,9 @@ export function ChannelPlayer({
|
|||||||
playsInline
|
playsInline
|
||||||
muted
|
muted
|
||||||
className="h-full w-full"
|
className="h-full w-full"
|
||||||
onClick={togglePlay}
|
|
||||||
onDoubleClick={toggleFullscreen}
|
onDoubleClick={toggleFullscreen}
|
||||||
onPlay={() => {
|
onPlay={scheduleHide}
|
||||||
setPlaying(true)
|
|
||||||
scheduleHide()
|
|
||||||
}}
|
|
||||||
onPause={() => {
|
onPause={() => {
|
||||||
setPlaying(false)
|
|
||||||
clearHideTimer()
|
clearHideTimer()
|
||||||
setControlsVisible(true)
|
setControlsVisible(true)
|
||||||
}}
|
}}
|
||||||
@@ -221,9 +193,6 @@ export function ChannelPlayer({
|
|||||||
controlsVisible ? 'opacity-100' : 'pointer-events-none opacity-0'
|
controlsVisible ? 'opacity-100' : 'pointer-events-none opacity-0'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<button type="button" onClick={togglePlay} aria-label="play/pause">
|
|
||||||
{playing ? <Pause className="h-5 w-5" /> : <Play className="h-5 w-5" />}
|
|
||||||
</button>
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<button type="button" onClick={toggleMute} aria-label="mute">
|
<button type="button" onClick={toggleMute} aria-label="mute">
|
||||||
{muted ? <VolumeX className="h-5 w-5" /> : <Volume2 className="h-5 w-5" />}
|
{muted ? <VolumeX className="h-5 w-5" /> : <Volume2 className="h-5 w-5" />}
|
||||||
|
|||||||
Reference in New Issue
Block a user