fix: destroy MediaPlayer when source changing on webkit

This commit is contained in:
shinya
2025-06-26 02:15:29 +08:00
parent 1eb266e379
commit a45e16d3ef

View File

@@ -130,6 +130,12 @@ function PlayPageClient() {
const currentIdRef = useRef(currentId); const currentIdRef = useRef(currentId);
const videoTitleRef = useRef(videoTitle); const videoTitleRef = useRef(videoTitle);
// 标记是否已触发过一次 sourcechange首次不重建播放器
const hasSourceChangedRef = useRef(false);
// 当播放器因重建而触发一次额外的 sourcechange 时,用于忽略那一次
const ignoreSourceChangeRef = useRef(false);
// 同步最新值到 refs // 同步最新值到 refs
useEffect(() => { useEffect(() => {
currentSourceRef.current = currentSource; currentSourceRef.current = currentSource;
@@ -415,6 +421,7 @@ function PlayPageClient() {
if (playerRef.current && !playerRef.current.paused) { if (playerRef.current && !playerRef.current.paused) {
saveCurrentPlayProgress(); saveCurrentPlayProgress();
} }
playerRef.current;
setCurrentEpisodeIndex(episodeIndex); setCurrentEpisodeIndex(episodeIndex);
setShowEpisodePanel(false); setShowEpisodePanel(false);
} }
@@ -1041,6 +1048,9 @@ function PlayPageClient() {
}; };
}, []); }, []);
// Safari(WebKit) 专用:用于强制重新挂载 <MediaPlayer>,实现"销毁并重建"效果
const [playerReloadKey, setPlayerReloadKey] = useState(0);
if (loading) { if (loading) {
return ( return (
<div className='min-h-[100dvh] bg-black flex items-center justify-center overflow-hidden overscroll-contain'> <div className='min-h-[100dvh] bg-black flex items-center justify-center overflow-hidden overscroll-contain'>
@@ -1194,6 +1204,32 @@ function PlayPageClient() {
} }
}; };
const onSourceChange = () => {
// 仅在 WebKitSafari环境下重建播放器解决部分资源切换后黑屏或无法播放的问题
const isWebkit =
typeof window !== 'undefined' &&
typeof (window as any).webkitConvertPointFromNodeToPage === 'function';
if (ignoreSourceChangeRef.current) {
// 这一次是由我们手动重建引起的,直接忽略
ignoreSourceChangeRef.current = false;
return;
}
if (isWebkit) {
// 第一次真实的 sourcechange仅设置标记不重建
if (!hasSourceChangedRef.current) {
hasSourceChangedRef.current = true;
return;
}
// 第二次(用户真正切换源)开始重建播放器
// 设置标志,下一次由重建带来的 sourcechange 忽略
ignoreSourceChangeRef.current = true;
setPlayerReloadKey((k) => k + 1);
}
};
return ( return (
<div <div
ref={playerContainerRef} ref={playerContainerRef}
@@ -1263,13 +1299,14 @@ function PlayPageClient() {
autoPlay autoPlay
crossOrigin='anonymous' crossOrigin='anonymous'
controlsDelay={3000} controlsDelay={3000}
keyDisabled key={playerReloadKey}
onCanPlay={onCanPlay} onCanPlay={onCanPlay}
onEnded={onEnded} onEnded={onEnded}
onTimeUpdate={onTimeUpdate} onTimeUpdate={onTimeUpdate}
onPause={saveCurrentPlayProgress} onPause={saveCurrentPlayProgress}
onError={handlePlayerError} onError={handlePlayerError}
onProviderChange={onProviderChange} onProviderChange={onProviderChange}
onSourceChange={onSourceChange}
> >
<MediaProvider /> <MediaProvider />
<PlayerUITopbar <PlayerUITopbar