2026-03-25 15:03:49 +08:00
|
|
|
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
2026-03-16 16:20:59 +08:00
|
|
|
|
import { getLiveRoomDetail, getLiveAnchorInfo, getLiveStreamUrl } from '../services/bilibili';
|
|
|
|
|
|
import type { LiveRoomDetail, LiveAnchorInfo, LiveStreamInfo } from '../services/types';
|
|
|
|
|
|
|
|
|
|
|
|
interface LiveDetailState {
|
|
|
|
|
|
room: LiveRoomDetail | null;
|
|
|
|
|
|
anchor: LiveAnchorInfo | null;
|
|
|
|
|
|
stream: LiveStreamInfo | null;
|
|
|
|
|
|
loading: boolean;
|
|
|
|
|
|
error: string | null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function useLiveDetail(roomId: number) {
|
|
|
|
|
|
const [state, setState] = useState<LiveDetailState>({
|
|
|
|
|
|
room: null,
|
|
|
|
|
|
anchor: null,
|
|
|
|
|
|
stream: null,
|
|
|
|
|
|
loading: true,
|
|
|
|
|
|
error: null,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-03-25 15:03:49 +08:00
|
|
|
|
// 用 ref 追踪最新的 roomId,避免 cancelled 闭包问题
|
|
|
|
|
|
const latestRoomId = useRef(roomId);
|
|
|
|
|
|
latestRoomId.current = roomId;
|
|
|
|
|
|
|
2026-03-16 16:20:59 +08:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!roomId) return;
|
2026-03-25 15:03:49 +08:00
|
|
|
|
|
2026-03-16 16:20:59 +08:00
|
|
|
|
setState({ room: null, anchor: null, stream: null, loading: true, error: null });
|
|
|
|
|
|
|
2026-03-25 15:03:49 +08:00
|
|
|
|
const fetchId = roomId; // 捕获当前 roomId
|
|
|
|
|
|
|
|
|
|
|
|
async function doFetch() {
|
2026-03-16 16:20:59 +08:00
|
|
|
|
try {
|
|
|
|
|
|
const [room, anchor] = await Promise.all([
|
2026-03-25 15:03:49 +08:00
|
|
|
|
getLiveRoomDetail(fetchId),
|
|
|
|
|
|
getLiveAnchorInfo(fetchId),
|
2026-03-16 16:20:59 +08:00
|
|
|
|
]);
|
2026-03-25 15:03:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 仅在 roomId 未变化时更新状态(替代 cancelled 模式)
|
|
|
|
|
|
if (latestRoomId.current !== fetchId) return;
|
2026-03-16 16:20:59 +08:00
|
|
|
|
|
2026-03-16 21:13:26 +08:00
|
|
|
|
let stream: LiveStreamInfo = { hlsUrl: '', flvUrl: '', qn: 0, qualities: [] };
|
2026-03-25 15:03:49 +08:00
|
|
|
|
if (room?.live_status === 1) {
|
|
|
|
|
|
stream = await getLiveStreamUrl(fetchId);
|
2026-03-16 16:20:59 +08:00
|
|
|
|
}
|
2026-03-25 15:03:49 +08:00
|
|
|
|
|
|
|
|
|
|
if (latestRoomId.current !== fetchId) return;
|
2026-03-16 16:20:59 +08:00
|
|
|
|
|
|
|
|
|
|
setState({ room, anchor, stream, loading: false, error: null });
|
|
|
|
|
|
} catch (e: any) {
|
2026-03-25 15:03:49 +08:00
|
|
|
|
if (latestRoomId.current !== fetchId) return;
|
2026-03-16 16:20:59 +08:00
|
|
|
|
setState(prev => ({ ...prev, loading: false, error: e?.message ?? '加载失败' }));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-25 15:03:49 +08:00
|
|
|
|
doFetch();
|
2026-03-16 16:20:59 +08:00
|
|
|
|
}, [roomId]);
|
|
|
|
|
|
|
2026-03-16 21:13:26 +08:00
|
|
|
|
const changeQuality = useCallback(async (qn: number) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const stream = await getLiveStreamUrl(roomId, qn);
|
2026-03-25 12:03:28 +08:00
|
|
|
|
setState(prev => ({ ...prev, stream: { ...stream, qn } }));
|
2026-03-16 21:13:26 +08:00
|
|
|
|
} catch { /* ignore */ }
|
|
|
|
|
|
}, [roomId]);
|
|
|
|
|
|
|
|
|
|
|
|
return { ...state, changeQuality };
|
2026-03-16 16:20:59 +08:00
|
|
|
|
}
|