mirror of
https://gh-proxy.org/https://github.com/tiajinsha/JKVideo
synced 2026-07-07 23:18:38 +08:00
1
This commit is contained in:
@@ -62,7 +62,6 @@ const LIVE_AREAS = [
|
||||
{ id: 9, name: "虚拟主播" },
|
||||
{ id: 10, name: "生活" },
|
||||
{ id: 11, name: "知识" },
|
||||
{ id: 13, name: "赛事" },
|
||||
];
|
||||
|
||||
export default function HomeScreen() {
|
||||
|
||||
@@ -30,6 +30,7 @@ export default function LiveDetailScreen() {
|
||||
|
||||
const isLive = room?.live_status === 1;
|
||||
const hlsUrl = stream?.hlsUrl ?? "";
|
||||
const flvUrl = stream?.flvUrl ?? "";
|
||||
const qualities = stream?.qualities ?? [];
|
||||
const currentQn = stream?.qn ?? 0;
|
||||
|
||||
@@ -51,6 +52,7 @@ export default function LiveDetailScreen() {
|
||||
{/* Player */}
|
||||
<LivePlayer
|
||||
hlsUrl={hlsUrl}
|
||||
flvUrl={flvUrl}
|
||||
isLive={isLive}
|
||||
qualities={qualities}
|
||||
currentQn={currentQn}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Ionicons } from '@expo/vector-icons';
|
||||
|
||||
interface Props {
|
||||
hlsUrl: string;
|
||||
flvUrl?: string;
|
||||
isLive: boolean;
|
||||
qualities?: { qn: number; desc: string }[];
|
||||
currentQn?: number;
|
||||
@@ -27,7 +28,7 @@ const HEADERS = {
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
};
|
||||
|
||||
export function LivePlayer({ hlsUrl, isLive, qualities = [], currentQn = 0, onQualityChange }: Props) {
|
||||
export function LivePlayer({ hlsUrl, flvUrl, isLive, qualities = [], currentQn = 0, onQualityChange }: Props) {
|
||||
const { width: SCREEN_W, height: SCREEN_H } = useWindowDimensions();
|
||||
const VIDEO_H = SCREEN_W * 0.5625;
|
||||
|
||||
@@ -179,12 +180,6 @@ function NativeLivePlayer({
|
||||
|
||||
{showControls && (
|
||||
<>
|
||||
{/* LIVE badge top-left */}
|
||||
<View style={styles.liveBadge} pointerEvents="none">
|
||||
<View style={styles.liveDot} />
|
||||
<Text style={styles.liveText}>live</Text>
|
||||
</View>
|
||||
|
||||
{/* Center play/pause */}
|
||||
<TouchableOpacity
|
||||
style={styles.centerBtn}
|
||||
|
||||
@@ -123,6 +123,8 @@ export function useLiveDanmaku(roomId: number): DanmakuItem[] {
|
||||
const info = await getLiveDanmakuInfo(roomId);
|
||||
token = info.token;
|
||||
host = info.host;
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.warn('[danmaku] getDanmuInfo failed:', e);
|
||||
}
|
||||
@@ -144,19 +146,18 @@ export function useLiveDanmaku(roomId: number): DanmakuItem[] {
|
||||
wsRef.current = ws;
|
||||
|
||||
ws.onopen = () => {
|
||||
|
||||
const authBody = JSON.stringify({
|
||||
uid: 0,
|
||||
roomid: roomId,
|
||||
protover: 2,
|
||||
platform: 'h5', // must match platform param used in getConf API call
|
||||
platform: 'h5',
|
||||
type: 2,
|
||||
key: token,
|
||||
});
|
||||
const authPkt = buildPacket(authBody, 7);
|
||||
const hdr = Array.from(authPkt.slice(0, 16))
|
||||
.map(b => b.toString(16).padStart(2, '0')).join(' ');
|
||||
// Send as ArrayBuffer (more reliable than Uint8Array in some RN/Hermes versions)
|
||||
const t0 = Date.now();
|
||||
|
||||
|
||||
ws.send(authPkt.buffer as ArrayBuffer);
|
||||
|
||||
heartbeatRef.current = setInterval(() => {
|
||||
@@ -171,10 +172,8 @@ export function useLiveDanmaku(roomId: number): DanmakuItem[] {
|
||||
if (items.length > 0) setDanmakus(prev => [...prev, ...items]);
|
||||
};
|
||||
|
||||
ws.onerror = (e: Event) => {
|
||||
const ws2 = (e as any).currentTarget as WebSocket;
|
||||
};
|
||||
ws.onclose = (e: CloseEvent) => {
|
||||
ws.onerror = () => {};
|
||||
ws.onclose = () => {
|
||||
if (heartbeatRef.current) clearInterval(heartbeatRef.current);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ export async function getLiveAnchorInfo(roomId: number): Promise<LiveAnchorInfo>
|
||||
export async function getLiveStreamUrl(roomId: number, qn = 10000): Promise<LiveStreamInfo> {
|
||||
try {
|
||||
const res = await api.get(`${LIVE_BASE}/xlive/web-room/v2/index/getRoomPlayInfo`, {
|
||||
params: { room_id: roomId, protocol: '0,1', format: '0,1,2', codec: '0', qn },
|
||||
params: { room_id: roomId, protocol: '0,1', format: '0,1,2', codec: '0', qn, platform: 'android' },
|
||||
});
|
||||
const playurl = res.data?.data?.playurl_info?.playurl;
|
||||
const streams: any[] = playurl?.stream ?? [];
|
||||
@@ -338,11 +338,14 @@ export async function searchVideos(keyword: string, page = 1): Promise<VideoItem
|
||||
}
|
||||
|
||||
export async function getLiveDanmakuInfo(roomId: number): Promise<{ token: string; host: string }> {
|
||||
const res = await api.get(`${LIVE_BASE}/room/v1/Danmu/getConf`, {
|
||||
params: { room_id: roomId, platform: 'h5' },
|
||||
const { imgKey, subKey } = await getWbiKeys();
|
||||
const signed = signWbi({ id: roomId, type: 0 }, imgKey, subKey);
|
||||
const res = await api.get(`${LIVE_BASE}/xlive/web-room/v1/index/getDanmuInfo`, {
|
||||
params: signed,
|
||||
});
|
||||
const data = res.data.data;
|
||||
const hostInfo = data?.host_server_list?.[0];
|
||||
const hostList: any[] = data?.host_list ?? [];
|
||||
const hostInfo = hostList.find(h => h.wss_port === 443) ?? hostList[0];
|
||||
const host = hostInfo
|
||||
? `wss://${hostInfo.host}:${hostInfo.wss_port}/sub`
|
||||
: 'wss://broadcastlv.chat.bilibili.com/sub';
|
||||
|
||||
Reference in New Issue
Block a user