修正切视频同步逻辑

This commit is contained in:
mtvpls
2025-12-08 00:53:28 +08:00
parent 7911e4cc5f
commit dfd5004a5e
2 changed files with 149 additions and 9 deletions

View File

@@ -1594,6 +1594,63 @@ function PlayPageClient() {
initSkipConfig();
}, []);
// 监听 URL 参数变化,处理换源和换视频(用于房员跟随房主操作)
useEffect(() => {
const urlSource = searchParams.get('source');
const urlId = searchParams.get('id');
// 只在URL参数存在且与当前状态不同时才处理
if (urlSource && urlId && (urlSource !== currentSource || urlId !== currentId)) {
console.log('[PlayPage] Detected source/id change from URL:', {
urlSource,
urlId,
currentSource,
currentId
});
// 检查新的source和id是否在可用源列表中
const targetSource = availableSources.find(
(source) => source.source === urlSource && source.id === urlId
);
if (targetSource) {
console.log('[PlayPage] Found matching source in available sources, updating...');
// 记录当前播放进度
const currentPlayTime = artPlayerRef.current?.currentTime || 0;
// 获取URL中的episode参数
const episodeParam = searchParams.get('episode');
const targetEpisode = episodeParam ? parseInt(episodeParam, 10) - 1 : 0;
// 更新视频源信息
setCurrentSource(urlSource);
setCurrentId(urlId);
setVideoTitle(targetSource.title);
setVideoYear(targetSource.year);
setVideoCover(targetSource.poster);
setVideoDoubanId(targetSource.douban_id || 0);
setDetail(targetSource);
// 更新集数
if (targetEpisode >= 0 && targetEpisode < targetSource.episodes.length) {
setCurrentEpisodeIndex(targetEpisode);
// 如果是同一集,保存播放进度以便恢复
if (targetEpisode === currentEpisodeIndex && currentPlayTime > 1) {
resumeTimeRef.current = currentPlayTime;
} else {
resumeTimeRef.current = null;
}
}
} else {
console.log('[PlayPage] Source not found in available sources, reloading page...');
// 如果新源不在可用列表中,强制刷新页面重新加载
window.location.reload();
}
}
}, [searchParams, currentSource, currentId, availableSources, currentEpisodeIndex]);
// 处理换源
const handleSourceChange = async (
newSource: string,

View File

@@ -248,8 +248,8 @@ export function usePlaySync({
const url = `/play?${params.toString()}`;
console.log('[PlaySync] Member redirecting to:', url);
// 使用 window.location.href 强制完整刷新页面,确保播放器重新加载
window.location.href = url;
// 使用 router.push 进行导航,支持在同一页面更新参数
router.push(url);
};
socket.on('play:update', handlePlayUpdate);
@@ -367,18 +367,45 @@ export function usePlaySync({
};
}, [socket, currentRoom, artPlayerRef, watchRoom, broadcastPlayState, isInRoom, playerReady]);
// 使用ref跟踪上一次的值用于检测真正的变化
const lastBroadcastRef = useRef<{
videoId: string;
source: string;
episode: number;
} | null>(null);
// 房主:监听视频/集数/源变化并广播
useEffect(() => {
if (!isOwner || !socket || !currentRoom || !isInRoom || !watchRoom) return;
if (!isOwner || !socket || !currentRoom || !isInRoom || !watchRoom) {
// 如果不是房主或不在房间,重置跟踪
lastBroadcastRef.current = null;
return;
}
if (!videoId || !videoUrl) return;
console.log('[PlaySync] Video params changed, will broadcast after delay:', {
const currentState = {
videoId,
currentSource,
currentEpisode
source: currentSource,
episode: currentEpisode || 1,
};
// 检查是否需要广播
const shouldBroadcast = !lastBroadcastRef.current ||
lastBroadcastRef.current.videoId !== currentState.videoId ||
lastBroadcastRef.current.source !== currentState.source ||
lastBroadcastRef.current.episode !== currentState.episode;
if (!shouldBroadcast) {
console.log('[PlaySync] No change detected, skipping broadcast');
return;
}
console.log('[PlaySync] Detected change, will broadcast:', {
from: lastBroadcastRef.current,
to: currentState
});
// 延迟广播,避免初始化时触发
// 延迟广播,确保页面已经稳定
const timer = setTimeout(() => {
const state: PlayState = {
type: 'play',
@@ -395,10 +422,66 @@ export function usePlaySync({
console.log('[PlaySync] Broadcasting play:change:', state);
watchRoom.changeVideo(state);
}, 1000); // 1秒延迟给页面足够时间初始化
// 更新跟踪值
lastBroadcastRef.current = currentState;
}, 500); // 减少延迟到500ms
return () => clearTimeout(timer);
}, [isOwner, socket, currentRoom, isInRoom, watchRoom, videoId, currentEpisode, currentSource]);
}, [isOwner, socket, currentRoom, isInRoom, watchRoom, videoId, currentEpisode, currentSource, videoUrl, videoName, videoYear, searchTitle, artPlayerRef]);
// 房主:加入房间时立即广播当前播放状态
const lastRoomStateRef = useRef<{ isOwner: boolean; roomId: string | null }>({ isOwner: false, roomId: null });
useEffect(() => {
const currentRoomId = currentRoom?.id || null;
const prevRoomState = lastRoomStateRef.current;
// 检测是否刚成为房主或刚加入房间
const justBecameOwner = !prevRoomState.isOwner && isOwner;
const justJoinedRoom = !prevRoomState.roomId && currentRoomId;
// 更新ref
lastRoomStateRef.current = { isOwner, roomId: currentRoomId };
if (!isOwner || !socket || !currentRoom || !isInRoom || !watchRoom) return;
if (!videoId || !videoUrl) return;
if (!justBecameOwner && !justJoinedRoom) return;
console.log('[PlaySync] Owner joined room, broadcasting current state immediately:', {
justBecameOwner,
justJoinedRoom
});
// 立即广播当前状态
const state: PlayState = {
type: 'play',
url: videoUrl,
currentTime: artPlayerRef.current?.currentTime || 0,
isPlaying: artPlayerRef.current?.playing || false,
videoId,
videoName,
videoYear,
searchTitle,
episode: currentEpisode,
source: currentSource,
};
// 短暂延迟确保房间连接已稳定
const timer = setTimeout(() => {
console.log('[PlaySync] Broadcasting play:change on room join:', state);
watchRoom.changeVideo(state);
// 同时更新跟踪值,避免立即重复广播
lastBroadcastRef.current = {
videoId,
source: currentSource,
episode: currentEpisode || 1,
};
}, 300);
return () => clearTimeout(timer);
}, [isOwner, currentRoom, socket, isInRoom, watchRoom, videoId, videoUrl, videoName, videoYear, searchTitle, currentEpisode, currentSource, artPlayerRef]);
return {
isInRoom,