mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
android Trailer Fix
This commit is contained in:
parent
de5dc55ce0
commit
76fde372ff
4 changed files with 162 additions and 11 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -48,3 +48,4 @@ sliderreadme.md
|
|||
local-scrapers-repo
|
||||
worki.json
|
||||
VERSION_UPDATE_README.md
|
||||
hackintosh-emulator-fix.sh
|
||||
|
|
|
|||
126
index.html
126
index.html
|
|
@ -911,6 +911,132 @@
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Mobile Responsive Styles for iOS Modal */
|
||||
@media (max-width: 768px) {
|
||||
.ios-modal-content {
|
||||
padding: 1.5rem;
|
||||
margin: 1rem;
|
||||
max-width: calc(100% - 2rem);
|
||||
width: calc(100% - 2rem);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.ios-modal-title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.ios-modal-subtitle {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.ios-modal-header {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.ios-install-option {
|
||||
padding: 1rem;
|
||||
gap: 0.75rem;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.ios-option-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.ios-option-icon img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.ios-option-title {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.ios-option-description {
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.ios-modal-close {
|
||||
top: 0.75rem;
|
||||
right: 0.75rem;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.copy-feedback {
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-size: 0.85rem;
|
||||
border-radius: 10px;
|
||||
margin: 0 1rem;
|
||||
max-width: calc(100% - 2rem);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.ios-modal-content {
|
||||
padding: 1.25rem;
|
||||
margin: 0.75rem;
|
||||
max-width: calc(100% - 1.5rem);
|
||||
width: calc(100% - 1.5rem);
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.ios-modal-title {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.ios-modal-subtitle {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.ios-install-option {
|
||||
padding: 0.875rem;
|
||||
gap: 0.625rem;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.ios-option-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.ios-option-icon img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.ios-option-title {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.ios-option-description {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.ios-modal-close {
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.copy-feedback {
|
||||
padding: 0.625rem 1.25rem;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.screenshot h4 {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
|
|
|
|||
|
|
@ -746,7 +746,6 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
|||
setTrailerPreloaded(true);
|
||||
}
|
||||
setTrailerReady(true);
|
||||
setTrailerPlaying(true);
|
||||
|
||||
// Smooth transition: fade out thumbnail, fade in trailer
|
||||
thumbnailOpacity.value = withTiming(0, { duration: 500 });
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ const TrailerPlayer = React.forwardRef<any, TrailerPlayerProps>(({
|
|||
const [showControls, setShowControls] = useState(false);
|
||||
const [duration, setDuration] = useState(0);
|
||||
const [position, setPosition] = useState(0);
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
|
||||
// Animated values
|
||||
const controlsOpacity = useSharedValue(0);
|
||||
|
|
@ -139,12 +140,13 @@ const TrailerPlayer = React.forwardRef<any, TrailerPlayerProps>(({
|
|||
logger.info('TrailerPlayer', 'Video loaded successfully');
|
||||
}, [loadingOpacity, onLoad]);
|
||||
|
||||
const handleError = useCallback((error: string) => {
|
||||
const handleError = useCallback((error: any) => {
|
||||
setIsLoading(false);
|
||||
setHasError(true);
|
||||
loadingOpacity.value = withTiming(0, { duration: 300 });
|
||||
onError?.(error);
|
||||
logger.error('TrailerPlayer', 'Video error:', error);
|
||||
const message = typeof error === 'string' ? error : (error?.errorString || error?.error?.string || error?.error?.message || JSON.stringify(error));
|
||||
onError?.(message);
|
||||
logger.error('TrailerPlayer', 'Video error details:', error);
|
||||
}, [loadingOpacity, onError]);
|
||||
|
||||
const handleProgress = useCallback((data: OnProgressData) => {
|
||||
|
|
@ -216,24 +218,47 @@ const TrailerPlayer = React.forwardRef<any, TrailerPlayerProps>(({
|
|||
<View style={[styles.container, style]}>
|
||||
<Video
|
||||
ref={videoRef}
|
||||
source={{ uri: trailerUrl }}
|
||||
source={(() => {
|
||||
const androidHeaders = Platform.OS === 'android' ? { 'User-Agent': 'Nuvio/1.0 (Android)' } : {} as any;
|
||||
// Help ExoPlayer select proper MediaSource
|
||||
const lower = (trailerUrl || '').toLowerCase();
|
||||
const looksLikeHls = /\.m3u8(\b|$)/.test(lower) || /hls|applehlsencryption|playlist|m3u/.test(lower);
|
||||
const looksLikeDash = /\.mpd(\b|$)/.test(lower) || /dash|manifest/.test(lower);
|
||||
if (Platform.OS === 'android') {
|
||||
if (looksLikeHls) {
|
||||
return { uri: trailerUrl, type: 'm3u8', headers: androidHeaders } as any;
|
||||
}
|
||||
if (looksLikeDash) {
|
||||
return { uri: trailerUrl, type: 'mpd', headers: androidHeaders } as any;
|
||||
}
|
||||
return { uri: trailerUrl, headers: androidHeaders } as any;
|
||||
}
|
||||
return { uri: trailerUrl } as any;
|
||||
})()}
|
||||
style={styles.video}
|
||||
resizeMode="cover"
|
||||
resizeMode={isFullscreen ? 'contain' : 'cover'}
|
||||
paused={!isPlaying}
|
||||
repeat={true}
|
||||
repeat={isPlaying}
|
||||
muted={isMuted}
|
||||
volume={isMuted ? 0 : 1}
|
||||
mixWithOthers="duck"
|
||||
ignoreSilentSwitch="ignore"
|
||||
/* TextureView can cause rendering issues with complex overlays on Android */
|
||||
useTextureView={Platform.OS === 'android' ? false : undefined}
|
||||
playInBackground={false}
|
||||
playWhenInactive={false}
|
||||
onFullscreenPlayerWillPresent={() => setIsFullscreen(true)}
|
||||
onFullscreenPlayerDidDismiss={() => setIsFullscreen(false)}
|
||||
onLoadStart={handleLoadStart}
|
||||
onLoad={handleLoad}
|
||||
onError={(error: any) => handleError(error?.error?.message || 'Unknown error')}
|
||||
onError={(error: any) => handleError(error)}
|
||||
onProgress={handleProgress}
|
||||
controls={false}
|
||||
onEnd={() => {
|
||||
// Auto-restart when video ends
|
||||
videoRef.current?.seek(0);
|
||||
setIsPlaying(true);
|
||||
// Only loop if still considered playing
|
||||
if (isPlaying) {
|
||||
videoRef.current?.seek(0);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue