mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-09 06:46:37 +08:00
bug处理
This commit is contained in:
@@ -100,6 +100,7 @@ export function PlayerControls({
|
|||||||
const subtitleMenuOpenRef = useRef(false)
|
const subtitleMenuOpenRef = useRef(false)
|
||||||
const danmakuOpenRef = useRef(false)
|
const danmakuOpenRef = useRef(false)
|
||||||
const playlistOpenRef = useRef(false)
|
const playlistOpenRef = useRef(false)
|
||||||
|
const pendingSeekRef = useRef<number | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
controlsHoveredRef.current = controlsHovered
|
controlsHoveredRef.current = controlsHovered
|
||||||
@@ -184,16 +185,28 @@ export function PlayerControls({
|
|||||||
onMove()
|
onMove()
|
||||||
}
|
}
|
||||||
const syncTime = () => {
|
const syncTime = () => {
|
||||||
if (!isScrubbingRef.current) {
|
if (isScrubbingRef.current) return
|
||||||
setCurrentTime(streamOffset + el.currentTime)
|
if (pendingSeekRef.current !== null) {
|
||||||
|
const curAbs = streamOffset + el.currentTime
|
||||||
|
if (Math.abs(curAbs - pendingSeekRef.current) < 3 && el.currentTime > 0.1) {
|
||||||
|
pendingSeekRef.current = null
|
||||||
|
setCurrentTime(curAbs)
|
||||||
|
} else {
|
||||||
|
setCurrentTime(pendingSeekRef.current)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
setCurrentTime(streamOffset + el.currentTime)
|
||||||
}
|
}
|
||||||
const syncMeta = () => {
|
const syncMeta = () => {
|
||||||
const streamDur = Number.isFinite(el.duration) ? el.duration : 0
|
const streamDur = Number.isFinite(el.duration) ? el.duration : 0
|
||||||
setDuration(Math.max(knownDuration || 0, streamOffset + streamDur))
|
setDuration(Math.max(knownDuration || 0, streamOffset + streamDur))
|
||||||
if (!isScrubbingRef.current) {
|
if (isScrubbingRef.current) return
|
||||||
setCurrentTime(streamOffset + el.currentTime)
|
if (pendingSeekRef.current !== null) {
|
||||||
|
setCurrentTime(pendingSeekRef.current)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
setCurrentTime(streamOffset + el.currentTime)
|
||||||
}
|
}
|
||||||
const syncVolume = () => {
|
const syncVolume = () => {
|
||||||
setVolume(el.volume)
|
setVolume(el.volume)
|
||||||
@@ -269,6 +282,7 @@ export function PlayerControls({
|
|||||||
const el = video()
|
const el = video()
|
||||||
if (!el) return
|
if (!el) return
|
||||||
if (onSeekAbsolute?.(absolute)) {
|
if (onSeekAbsolute?.(absolute)) {
|
||||||
|
pendingSeekRef.current = absolute
|
||||||
setCurrentTime(absolute)
|
setCurrentTime(absolute)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,9 +259,15 @@ export function PlayerPage() {
|
|||||||
if (cancelled || !ref.current) return
|
if (cancelled || !ref.current) return
|
||||||
if (HlsCtor.isSupported()) {
|
if (HlsCtor.isSupported()) {
|
||||||
const hls = new HlsCtor({ enableWorker: true, lowLatencyMode: false })
|
const hls = new HlsCtor({ enableWorker: true, lowLatencyMode: false })
|
||||||
|
try {
|
||||||
|
video.currentTime = 0
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
hls.loadSource(url)
|
hls.loadSource(url)
|
||||||
hls.attachMedia(video)
|
hls.attachMedia(video)
|
||||||
hls.on(HlsCtor.Events.MANIFEST_PARSED, () => {
|
hls.on(HlsCtor.Events.MANIFEST_PARSED, () => {
|
||||||
|
void video.play().catch(() => undefined)
|
||||||
// .strm 入库时常缺 duration;转码启动时会补探测,这里刷新一次给进度条总时长。
|
// .strm 入库时常缺 duration;转码启动时会补探测,这里刷新一次给进度条总时长。
|
||||||
if (durationSec > 0) return
|
if (durationSec > 0) return
|
||||||
mediaAPI
|
mediaAPI
|
||||||
@@ -287,14 +293,19 @@ export function PlayerPage() {
|
|||||||
}
|
}
|
||||||
hlsRef.current = hls
|
hlsRef.current = hls
|
||||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
|
try {
|
||||||
|
video.currentTime = 0
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
video.src = url
|
video.src = url
|
||||||
|
void video.play().catch(() => undefined)
|
||||||
} else {
|
} else {
|
||||||
setHlsUnavailable(true)
|
setHlsUnavailable(true)
|
||||||
setPlayerError('当前浏览器不支持 HLS,正在尝试直接播放。')
|
setPlayerError('当前浏览器不支持 HLS,正在尝试直接播放。')
|
||||||
toast.error('当前浏览器不支持 HLS,降级到直接播放')
|
toast.error('当前浏览器不支持 HLS,降级到直接播放')
|
||||||
setMode('direct')
|
setMode('direct')
|
||||||
}
|
}
|
||||||
void video.play().catch(() => undefined)
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
if (cancelled) return
|
if (cancelled) return
|
||||||
setHlsUnavailable(true)
|
setHlsUnavailable(true)
|
||||||
@@ -381,22 +392,33 @@ export function PlayerPage() {
|
|||||||
}
|
}
|
||||||
}, [resumePosition, initialSeekDone, mode, hlsStartSec])
|
}, [resumePosition, initialSeekDone, mode, hlsStartSec])
|
||||||
|
|
||||||
|
// 使用 ref 实时同步进度计算所需的状态,避免每次 hlsStartSec 改变都触发 cleanup 并误上报旧进度
|
||||||
|
const hlsStartSecRef = useRef(hlsStartSec)
|
||||||
|
hlsStartSecRef.current = hlsStartSec
|
||||||
|
const modeRef = useRef(mode)
|
||||||
|
modeRef.current = mode
|
||||||
|
|
||||||
// Persist resume position every 10 seconds while playing, and immediately upon pause/unmount.
|
// Persist resume position every 10 seconds while playing, and immediately upon pause/unmount.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!media || !ref.current) return
|
if (!id || !ref.current) return
|
||||||
const video = ref.current
|
const video = ref.current
|
||||||
const absolutePositionMs = () =>
|
const absolutePositionMs = () => {
|
||||||
Math.floor(((mode === 'hls' ? hlsStartSec : 0) + video.currentTime) * 1000)
|
const currentStartSec = modeRef.current === 'hls' ? hlsStartSecRef.current : 0
|
||||||
const absoluteDurationMs = () =>
|
return Math.floor((currentStartSec + (video.currentTime || 0)) * 1000)
|
||||||
Math.floor(Math.max(media.duration_sec || 0, (mode === 'hls' ? hlsStartSec : 0) + (video.duration || 0)) * 1000)
|
}
|
||||||
|
const absoluteDurationMs = () => {
|
||||||
|
const currentStartSec = modeRef.current === 'hls' ? hlsStartSecRef.current : 0
|
||||||
|
const mediaDur = mediaRef.current?.duration_sec || 0
|
||||||
|
return Math.floor(Math.max(mediaDur, currentStartSec + (video.duration || 0)) * 1000)
|
||||||
|
}
|
||||||
const handler = () => {
|
const handler = () => {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
if (now - lastSentRef.current < 10_000) return
|
if (now - lastSentRef.current < 10_000) return
|
||||||
lastSentRef.current = now
|
lastSentRef.current = now
|
||||||
const positionMs = absolutePositionMs()
|
const positionMs = absolutePositionMs()
|
||||||
const durationMs = absoluteDurationMs()
|
const durationMs = absoluteDurationMs()
|
||||||
if (positionMs > 0) {
|
if (positionMs > 0 && mediaRef.current) {
|
||||||
playbackAPI.recordProgress(media.id, positionMs, durationMs).catch(() => undefined)
|
playbackAPI.recordProgress(mediaRef.current.id, positionMs, durationMs).catch(() => undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
video.addEventListener('timeupdate', handler)
|
video.addEventListener('timeupdate', handler)
|
||||||
@@ -406,11 +428,11 @@ export function PlayerPage() {
|
|||||||
video.removeEventListener('pause', handler)
|
video.removeEventListener('pause', handler)
|
||||||
const positionMs = absolutePositionMs()
|
const positionMs = absolutePositionMs()
|
||||||
const durationMs = absoluteDurationMs()
|
const durationMs = absoluteDurationMs()
|
||||||
if (positionMs > 0 && media) {
|
if (positionMs > 0 && mediaRef.current) {
|
||||||
playbackAPI.recordProgress(media.id, positionMs, durationMs).catch(() => undefined)
|
playbackAPI.recordProgress(mediaRef.current.id, positionMs, durationMs).catch(() => undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [media, mode, hlsStartSec])
|
}, [id])
|
||||||
|
|
||||||
// 加载剧集/播放列表
|
// 加载剧集/播放列表
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user