mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-20 09:47:31 +00:00
230 lines
9 KiB
TypeScript
230 lines
9 KiB
TypeScript
import React, { useRef, useImperativeHandle, forwardRef, useEffect, useState } from 'react';
|
|
import { View, requireNativeComponent, UIManager, findNodeHandle, NativeModules } from 'react-native';
|
|
|
|
export interface KSPlayerSource {
|
|
uri: string;
|
|
headers?: Record<string, string>;
|
|
}
|
|
|
|
interface KSPlayerViewProps {
|
|
source?: KSPlayerSource;
|
|
paused?: boolean;
|
|
volume?: number;
|
|
rate?: number;
|
|
audioTrack?: number;
|
|
textTrack?: number;
|
|
allowsExternalPlayback?: boolean;
|
|
usesExternalPlaybackWhileExternalScreenIsActive?: boolean;
|
|
subtitleBottomOffset?: number;
|
|
subtitleFontSize?: number;
|
|
subtitleTextColor?: string;
|
|
subtitleBackgroundColor?: string;
|
|
subtitleOutlineEnabled?: boolean;
|
|
resizeMode?: 'contain' | 'cover' | 'stretch';
|
|
onLoad?: (data: any) => void;
|
|
onProgress?: (data: any) => void;
|
|
onBuffering?: (data: any) => void;
|
|
onEnd?: () => void;
|
|
onError?: (error: any) => void;
|
|
onBufferingProgress?: (data: any) => void;
|
|
style?: any;
|
|
}
|
|
|
|
const KSPlayerViewManager = requireNativeComponent<KSPlayerViewProps>('KSPlayerView');
|
|
const KSPlayerModule = NativeModules.KSPlayerModule;
|
|
|
|
export interface KSPlayerRef {
|
|
seek: (time: number) => void;
|
|
setSource: (source: KSPlayerSource) => void;
|
|
setPaused: (paused: boolean) => void;
|
|
setVolume: (volume: number) => void;
|
|
setPlaybackRate: (rate: number) => void;
|
|
setAudioTrack: (trackId: number) => void;
|
|
setTextTrack: (trackId: number) => void;
|
|
getTracks: () => Promise<{ audioTracks: any[]; textTracks: any[] }>;
|
|
setAllowsExternalPlayback: (allows: boolean) => void;
|
|
setUsesExternalPlaybackWhileExternalScreenIsActive: (uses: boolean) => void;
|
|
getAirPlayState: () => Promise<{ allowsExternalPlayback: boolean; usesExternalPlaybackWhileExternalScreenIsActive: boolean; isExternalPlaybackActive: boolean }>;
|
|
showAirPlayPicker: () => void;
|
|
}
|
|
|
|
export interface KSPlayerProps {
|
|
source?: KSPlayerSource;
|
|
paused?: boolean;
|
|
volume?: number;
|
|
rate?: number;
|
|
audioTrack?: number;
|
|
textTrack?: number;
|
|
allowsExternalPlayback?: boolean;
|
|
usesExternalPlaybackWhileExternalScreenIsActive?: boolean;
|
|
subtitleBottomOffset?: number;
|
|
subtitleFontSize?: number;
|
|
subtitleTextColor?: string;
|
|
subtitleBackgroundColor?: string;
|
|
subtitleOutlineEnabled?: boolean;
|
|
resizeMode?: 'contain' | 'cover' | 'stretch';
|
|
onLoad?: (data: any) => void;
|
|
onProgress?: (data: any) => void;
|
|
onBuffering?: (data: any) => void;
|
|
onEnd?: () => void;
|
|
onError?: (error: any) => void;
|
|
onBufferingProgress?: (data: any) => void;
|
|
style?: any;
|
|
}
|
|
|
|
const KSPlayer = forwardRef<KSPlayerRef, KSPlayerProps>((props, ref) => {
|
|
const nativeRef = useRef<any>(null);
|
|
const [key, setKey] = useState(0); // Force re-render when source changes
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
seek: (time: number) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.seek;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [time]);
|
|
}
|
|
},
|
|
setSource: (source: KSPlayerSource) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setSource;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [source]);
|
|
}
|
|
},
|
|
setPaused: (paused: boolean) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setPaused;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [paused]);
|
|
}
|
|
},
|
|
setVolume: (volume: number) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setVolume;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [volume]);
|
|
}
|
|
},
|
|
setPlaybackRate: (rate: number) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setPlaybackRate;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [rate]);
|
|
}
|
|
},
|
|
setAudioTrack: (trackId: number) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setAudioTrack;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [trackId]);
|
|
}
|
|
},
|
|
setTextTrack: (trackId: number) => {
|
|
console.log('[KSPlayerComponent] setTextTrack called with trackId:', trackId);
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
console.log('[KSPlayerComponent] setTextTrack dispatching command to node:', node);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setTextTrack;
|
|
console.log('[KSPlayerComponent] setTextTrack commandId:', commandId);
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [trackId]);
|
|
} else {
|
|
console.warn('[KSPlayerComponent] setTextTrack: nativeRef.current is null');
|
|
}
|
|
},
|
|
getTracks: async () => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
if (node) {
|
|
return await KSPlayerModule.getTracks(node);
|
|
}
|
|
}
|
|
return { audioTracks: [], textTracks: [] };
|
|
},
|
|
setAllowsExternalPlayback: (allows: boolean) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setAllowsExternalPlayback;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [allows]);
|
|
}
|
|
},
|
|
setUsesExternalPlaybackWhileExternalScreenIsActive: (uses: boolean) => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
// @ts-ignore legacy UIManager commands path for Paper
|
|
const commandId = UIManager.getViewManagerConfig('KSPlayerView').Commands.setUsesExternalPlaybackWhileExternalScreenIsActive;
|
|
UIManager.dispatchViewManagerCommand(node, commandId, [uses]);
|
|
}
|
|
},
|
|
getAirPlayState: async () => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
if (node) {
|
|
return await KSPlayerModule.getAirPlayState(node);
|
|
}
|
|
}
|
|
return { allowsExternalPlayback: false, usesExternalPlaybackWhileExternalScreenIsActive: false, isExternalPlaybackActive: false };
|
|
},
|
|
showAirPlayPicker: () => {
|
|
if (nativeRef.current) {
|
|
const node = findNodeHandle(nativeRef.current);
|
|
if (node) {
|
|
console.log('[KSPlayerComponent] Calling showAirPlayPicker with node:', node);
|
|
KSPlayerModule.showAirPlayPicker(node);
|
|
} else {
|
|
console.warn('[KSPlayerComponent] Cannot call showAirPlayPicker: node is null');
|
|
}
|
|
} else {
|
|
console.log('[KSPlayerComponent] nativeRef.current is null');
|
|
}
|
|
},
|
|
}));
|
|
|
|
// No need for event listeners - events are handled through props
|
|
|
|
// Force re-render when source changes to ensure proper reloading
|
|
useEffect(() => {
|
|
if (props.source) {
|
|
setKey(prev => prev + 1);
|
|
}
|
|
}, [props.source?.uri]);
|
|
|
|
return (
|
|
<KSPlayerViewManager
|
|
key={key}
|
|
ref={nativeRef}
|
|
source={props.source}
|
|
paused={props.paused}
|
|
volume={props.volume}
|
|
rate={props.rate}
|
|
audioTrack={props.audioTrack}
|
|
textTrack={props.textTrack}
|
|
allowsExternalPlayback={props.allowsExternalPlayback}
|
|
usesExternalPlaybackWhileExternalScreenIsActive={props.usesExternalPlaybackWhileExternalScreenIsActive}
|
|
subtitleBottomOffset={props.subtitleBottomOffset}
|
|
subtitleFontSize={props.subtitleFontSize}
|
|
subtitleTextColor={props.subtitleTextColor}
|
|
subtitleBackgroundColor={props.subtitleBackgroundColor}
|
|
subtitleOutlineEnabled={props.subtitleOutlineEnabled}
|
|
resizeMode={props.resizeMode}
|
|
onLoad={(e: any) => props.onLoad?.(e?.nativeEvent ?? e)}
|
|
onProgress={(e: any) => props.onProgress?.(e?.nativeEvent ?? e)}
|
|
onBuffering={(e: any) => props.onBuffering?.(e?.nativeEvent ?? e)}
|
|
onEnd={() => props.onEnd?.()}
|
|
onError={(e: any) => props.onError?.(e?.nativeEvent ?? e)}
|
|
onBufferingProgress={(e: any) => props.onBufferingProgress?.(e?.nativeEvent ?? e)}
|
|
style={props.style}
|
|
/>
|
|
);
|
|
});
|
|
|
|
KSPlayer.displayName = 'KSPlayer';
|
|
|
|
export default KSPlayer;
|