172 lines
4.7 KiB
TypeScript
172 lines
4.7 KiB
TypeScript
import { useEffect, useRef } from "react";
|
|
import type { RefObject } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import type { LoopMode, Neighbors } from "../types";
|
|
|
|
interface UseVideoPlayerProps {
|
|
awemeId: string;
|
|
videoRef: RefObject<HTMLVideoElement | null>;
|
|
volume: number;
|
|
rate: number;
|
|
loopMode: LoopMode;
|
|
neighbors: Neighbors;
|
|
progressRestored: boolean;
|
|
setIsPlaying: (playing: boolean) => void;
|
|
setProgress: (progress: number) => void;
|
|
setProgressRestored: (restored: boolean) => void;
|
|
}
|
|
|
|
export function useVideoPlayer({
|
|
awemeId,
|
|
videoRef,
|
|
volume,
|
|
rate,
|
|
loopMode,
|
|
neighbors,
|
|
progressRestored,
|
|
setIsPlaying,
|
|
setProgress,
|
|
setProgressRestored,
|
|
}: UseVideoPlayerProps) {
|
|
const router = useRouter();
|
|
|
|
// 恢复播放进度
|
|
useEffect(() => {
|
|
if (progressRestored) return;
|
|
const v = videoRef.current;
|
|
if (!v) return;
|
|
|
|
const onLoadedMetadata = () => {
|
|
if (progressRestored) return;
|
|
|
|
try {
|
|
const key = `aweme_progress_${awemeId}`;
|
|
const saved = localStorage.getItem(key);
|
|
if (!saved) {
|
|
setProgressRestored(true);
|
|
return;
|
|
}
|
|
|
|
const { time, timestamp } = JSON.parse(saved);
|
|
const now = Date.now();
|
|
const fiveMinutes = 5 * 60 * 1000;
|
|
|
|
if (now - timestamp < fiveMinutes && time > 1 && time < v.duration - 1) {
|
|
v.currentTime = time;
|
|
console.log(`恢复播放进度: ${Math.round(time)}s`);
|
|
} else if (now - timestamp >= fiveMinutes) {
|
|
localStorage.removeItem(key);
|
|
}
|
|
} catch (e) {
|
|
console.error("恢复播放进度失败", e);
|
|
}
|
|
|
|
setProgressRestored(true);
|
|
};
|
|
|
|
if (v.readyState >= 1) {
|
|
onLoadedMetadata();
|
|
} else {
|
|
v.addEventListener("loadedmetadata", onLoadedMetadata, { once: true });
|
|
return () => v.removeEventListener("loadedmetadata", onLoadedMetadata);
|
|
}
|
|
}, [awemeId, progressRestored, videoRef, setProgressRestored]);
|
|
|
|
// 保存播放进度
|
|
useEffect(() => {
|
|
const v = videoRef.current;
|
|
if (!v) return;
|
|
|
|
const saveProgress = () => {
|
|
if (!v.duration || Number.isNaN(v.duration) || v.currentTime < 1) return;
|
|
|
|
try {
|
|
const key = `aweme_progress_${awemeId}`;
|
|
const value = JSON.stringify({
|
|
time: v.currentTime,
|
|
timestamp: Date.now(),
|
|
});
|
|
localStorage.setItem(key, value);
|
|
} catch (e) {
|
|
console.error("保存播放进度失败", e);
|
|
}
|
|
};
|
|
|
|
const interval = setInterval(saveProgress, 2000);
|
|
const onBeforeUnload = () => saveProgress();
|
|
window.addEventListener("beforeunload", onBeforeUnload);
|
|
|
|
return () => {
|
|
clearInterval(interval);
|
|
window.removeEventListener("beforeunload", onBeforeUnload);
|
|
saveProgress();
|
|
};
|
|
}, [awemeId, videoRef]);
|
|
|
|
// 监听播放状态和进度
|
|
useEffect(() => {
|
|
const v = videoRef.current;
|
|
if (!v) return;
|
|
|
|
const onTime = () => {
|
|
if (!v.duration || Number.isNaN(v.duration)) return;
|
|
setProgress(v.currentTime / v.duration);
|
|
};
|
|
const onPlay = () => setIsPlaying(true);
|
|
const onPause = () => setIsPlaying(false);
|
|
const onEnded = () => {
|
|
if (loopMode === "sequential" && neighbors?.next) {
|
|
router.push(`/aweme/${neighbors.next.aweme_id}`);
|
|
}
|
|
};
|
|
|
|
v.addEventListener("timeupdate", onTime);
|
|
v.addEventListener("loadedmetadata", onTime);
|
|
v.addEventListener("play", onPlay);
|
|
v.addEventListener("pause", onPause);
|
|
v.addEventListener("ended", onEnded);
|
|
|
|
return () => {
|
|
v.removeEventListener("timeupdate", onTime);
|
|
v.removeEventListener("loadedmetadata", onTime);
|
|
v.removeEventListener("play", onPlay);
|
|
v.removeEventListener("pause", onPause);
|
|
v.removeEventListener("ended", onEnded);
|
|
};
|
|
}, [loopMode, neighbors?.next, router, videoRef, setIsPlaying, setProgress]);
|
|
|
|
// 自动播放检测
|
|
useEffect(() => {
|
|
const v = videoRef.current;
|
|
if (!v) return;
|
|
|
|
const checkAutoplay = async () => {
|
|
try {
|
|
await v.play();
|
|
setIsPlaying(true);
|
|
} catch (error) {
|
|
console.log("自动播放被阻止,需要用户交互");
|
|
setIsPlaying(false);
|
|
}
|
|
};
|
|
|
|
if (v.readyState >= 1) {
|
|
checkAutoplay();
|
|
} else {
|
|
v.addEventListener("loadedmetadata", checkAutoplay, { once: true });
|
|
return () => v.removeEventListener("loadedmetadata", checkAutoplay);
|
|
}
|
|
}, [awemeId, videoRef, setIsPlaying]);
|
|
|
|
// 更新音量和倍速
|
|
useEffect(() => {
|
|
const v = videoRef.current;
|
|
if (v) v.volume = volume;
|
|
}, [volume, videoRef]);
|
|
|
|
useEffect(() => {
|
|
const v = videoRef.current;
|
|
if (v) v.playbackRate = rate;
|
|
}, [rate, videoRef]);
|
|
}
|