mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
made some chanegs for xprime support
This commit is contained in:
parent
6547d38c0e
commit
a7e7c86f18
3 changed files with 279 additions and 3 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit d2eb5507001e031aaa5d258c390ec56ecfa8f9c8
|
||||
Subproject commit d129a1d2799397738c6e4848a6b80314a3326bd9
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { View, TouchableOpacity, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, Image, StyleSheet } from 'react-native';
|
||||
import { View, TouchableOpacity, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, Image, StyleSheet, Modal } from 'react-native';
|
||||
import Video, { VideoRef, SelectedTrack, SelectedTrackType, BufferingStrategyType } from 'react-native-video';
|
||||
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { RootStackParamList } from '../../navigation/AppNavigator';
|
||||
|
|
@ -162,6 +162,9 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
const isMounted = useRef(true);
|
||||
const controlsTimeout = useRef<NodeJS.Timeout | null>(null);
|
||||
const [isSyncingBeforeClose, setIsSyncingBeforeClose] = useState(false);
|
||||
const [showErrorModal, setShowErrorModal] = useState(false);
|
||||
const [errorDetails, setErrorDetails] = useState<string>('');
|
||||
const errorTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
// Get metadata to access logo (only if we have a valid id)
|
||||
const shouldLoadMetadata = Boolean(id && type);
|
||||
const metadataResult = useMetadata({
|
||||
|
|
@ -709,6 +712,44 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
|
||||
const handleError = (error: any) => {
|
||||
logger.error('AndroidVideoPlayer error: ', error);
|
||||
|
||||
// Format error details for user display
|
||||
let errorMessage = 'An unknown error occurred';
|
||||
if (error) {
|
||||
if (typeof error === 'string') {
|
||||
errorMessage = error;
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
} else if (error.error && error.error.message) {
|
||||
errorMessage = error.error.message;
|
||||
} else if (error.code) {
|
||||
errorMessage = `Error Code: ${error.code}`;
|
||||
} else {
|
||||
errorMessage = JSON.stringify(error, null, 2);
|
||||
}
|
||||
}
|
||||
|
||||
setErrorDetails(errorMessage);
|
||||
setShowErrorModal(true);
|
||||
|
||||
// Clear any existing timeout
|
||||
if (errorTimeoutRef.current) {
|
||||
clearTimeout(errorTimeoutRef.current);
|
||||
}
|
||||
|
||||
// Auto-exit after 5 seconds if user doesn't dismiss
|
||||
errorTimeoutRef.current = setTimeout(() => {
|
||||
handleErrorExit();
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const handleErrorExit = () => {
|
||||
if (errorTimeoutRef.current) {
|
||||
clearTimeout(errorTimeoutRef.current);
|
||||
errorTimeoutRef.current = null;
|
||||
}
|
||||
setShowErrorModal(false);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const onBuffer = (data: any) => {
|
||||
|
|
@ -851,6 +892,9 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
if (seekDebounceTimer.current) {
|
||||
clearTimeout(seekDebounceTimer.current);
|
||||
}
|
||||
if (errorTimeoutRef.current) {
|
||||
clearTimeout(errorTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
|
@ -1254,6 +1298,100 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
onSelectStream={handleSelectStream}
|
||||
isChangingSource={isChangingSource}
|
||||
/>
|
||||
|
||||
{/* Error Modal */}
|
||||
<Modal
|
||||
visible={showErrorModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={handleErrorExit}
|
||||
>
|
||||
<View style={{
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.8)'
|
||||
}}>
|
||||
<View style={{
|
||||
backgroundColor: '#1a1a1a',
|
||||
borderRadius: 14,
|
||||
width: '85%',
|
||||
maxHeight: '70%',
|
||||
padding: 20,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 6 },
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 8,
|
||||
elevation: 5,
|
||||
}}>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16
|
||||
}}>
|
||||
<MaterialIcons name="error" size={24} color="#ff4444" style={{ marginRight: 8 }} />
|
||||
<Text style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
color: '#ffffff',
|
||||
flex: 1
|
||||
}}>Playback Error</Text>
|
||||
<TouchableOpacity onPress={handleErrorExit}>
|
||||
<MaterialIcons name="close" size={24} color="#ffffff" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={{
|
||||
fontSize: 14,
|
||||
color: '#cccccc',
|
||||
marginBottom: 16,
|
||||
lineHeight: 20
|
||||
}}>The video player encountered an error and cannot continue playback:</Text>
|
||||
|
||||
<View style={{
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginBottom: 20,
|
||||
maxHeight: 200
|
||||
}}>
|
||||
<Text style={{
|
||||
fontSize: 12,
|
||||
color: '#ff8888',
|
||||
fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace'
|
||||
}}>{errorDetails}</Text>
|
||||
</View>
|
||||
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end'
|
||||
}}>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: '#ff4444',
|
||||
borderRadius: 8,
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 20
|
||||
}}
|
||||
onPress={handleErrorExit}
|
||||
>
|
||||
<Text style={{
|
||||
color: '#ffffff',
|
||||
fontWeight: '600',
|
||||
fontSize: 16
|
||||
}}>Exit Player</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={{
|
||||
fontSize: 12,
|
||||
color: '#888888',
|
||||
textAlign: 'center',
|
||||
marginTop: 12
|
||||
}}>This dialog will auto-close in 5 seconds</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { View, TouchableOpacity, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, Image, StyleSheet } from 'react-native';
|
||||
import { View, TouchableOpacity, Dimensions, Animated, ActivityIndicator, Platform, NativeModules, StatusBar, Text, Image, StyleSheet, Modal } from 'react-native';
|
||||
import { VLCPlayer } from 'react-native-vlc-media-player';
|
||||
import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { RootStackParamList, RootStackNavigationProp } from '../../navigation/AppNavigator';
|
||||
|
|
@ -167,6 +167,9 @@ const VideoPlayer: React.FC = () => {
|
|||
const [availableStreams, setAvailableStreams] = useState<{ [providerId: string]: { streams: any[]; addonName: string } }>(passedAvailableStreams || {});
|
||||
const [currentStreamUrl, setCurrentStreamUrl] = useState<string>(uri);
|
||||
const [isChangingSource, setIsChangingSource] = useState<boolean>(false);
|
||||
const [showErrorModal, setShowErrorModal] = useState(false);
|
||||
const [errorDetails, setErrorDetails] = useState<string>('');
|
||||
const errorTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const [pendingSeek, setPendingSeek] = useState<{ position: number; shouldPlay: boolean } | null>(null);
|
||||
const [currentQuality, setCurrentQuality] = useState<string | undefined>(quality);
|
||||
const [currentStreamProvider, setCurrentStreamProvider] = useState<string | undefined>(streamProvider);
|
||||
|
|
@ -794,6 +797,44 @@ const VideoPlayer: React.FC = () => {
|
|||
|
||||
const handleError = (error: any) => {
|
||||
logger.error('[VideoPlayer] Playback Error:', error);
|
||||
|
||||
// Format error details for user display
|
||||
let errorMessage = 'An unknown error occurred';
|
||||
if (error) {
|
||||
if (typeof error === 'string') {
|
||||
errorMessage = error;
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
} else if (error.error && error.error.message) {
|
||||
errorMessage = error.error.message;
|
||||
} else if (error.code) {
|
||||
errorMessage = `Error Code: ${error.code}`;
|
||||
} else {
|
||||
errorMessage = JSON.stringify(error, null, 2);
|
||||
}
|
||||
}
|
||||
|
||||
setErrorDetails(errorMessage);
|
||||
setShowErrorModal(true);
|
||||
|
||||
// Clear any existing timeout
|
||||
if (errorTimeoutRef.current) {
|
||||
clearTimeout(errorTimeoutRef.current);
|
||||
}
|
||||
|
||||
// Auto-exit after 5 seconds if user doesn't dismiss
|
||||
errorTimeoutRef.current = setTimeout(() => {
|
||||
handleErrorExit();
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const handleErrorExit = () => {
|
||||
if (errorTimeoutRef.current) {
|
||||
clearTimeout(errorTimeoutRef.current);
|
||||
errorTimeoutRef.current = null;
|
||||
}
|
||||
setShowErrorModal(false);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const onBuffering = (event: any) => {
|
||||
|
|
@ -929,6 +970,9 @@ const VideoPlayer: React.FC = () => {
|
|||
if (seekDebounceTimer.current) {
|
||||
clearTimeout(seekDebounceTimer.current);
|
||||
}
|
||||
if (errorTimeoutRef.current) {
|
||||
clearTimeout(errorTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
|
@ -1337,6 +1381,100 @@ const VideoPlayer: React.FC = () => {
|
|||
onSelectStream={handleSelectStream}
|
||||
isChangingSource={isChangingSource}
|
||||
/>
|
||||
|
||||
{/* Error Modal */}
|
||||
<Modal
|
||||
visible={showErrorModal}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={handleErrorExit}
|
||||
>
|
||||
<View style={{
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(0,0,0,0.8)'
|
||||
}}>
|
||||
<View style={{
|
||||
backgroundColor: '#1a1a1a',
|
||||
borderRadius: 14,
|
||||
width: '85%',
|
||||
maxHeight: '70%',
|
||||
padding: 20,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 6 },
|
||||
shadowOpacity: 0.25,
|
||||
shadowRadius: 8,
|
||||
elevation: 5,
|
||||
}}>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16
|
||||
}}>
|
||||
<MaterialIcons name="error" size={24} color="#ff4444" style={{ marginRight: 8 }} />
|
||||
<Text style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
color: '#ffffff',
|
||||
flex: 1
|
||||
}}>Playback Error</Text>
|
||||
<TouchableOpacity onPress={handleErrorExit}>
|
||||
<MaterialIcons name="close" size={24} color="#ffffff" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={{
|
||||
fontSize: 14,
|
||||
color: '#cccccc',
|
||||
marginBottom: 16,
|
||||
lineHeight: 20
|
||||
}}>The video player encountered an error and cannot continue playback:</Text>
|
||||
|
||||
<View style={{
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginBottom: 20,
|
||||
maxHeight: 200
|
||||
}}>
|
||||
<Text style={{
|
||||
fontSize: 12,
|
||||
color: '#ff8888',
|
||||
fontFamily: Platform.OS === 'ios' ? 'Courier' : 'monospace'
|
||||
}}>{errorDetails}</Text>
|
||||
</View>
|
||||
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end'
|
||||
}}>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
backgroundColor: '#ff4444',
|
||||
borderRadius: 8,
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 20
|
||||
}}
|
||||
onPress={handleErrorExit}
|
||||
>
|
||||
<Text style={{
|
||||
color: '#ffffff',
|
||||
fontWeight: '600',
|
||||
fontSize: 16
|
||||
}}>Exit Player</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={{
|
||||
fontSize: 12,
|
||||
color: '#888888',
|
||||
textAlign: 'center',
|
||||
marginTop: 12
|
||||
}}>This dialog will auto-close in 5 seconds</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue