Skip to content

Commit 71c0e7e

Browse files
ralyodioqwencoder
andcommitted
fix: Amazon Silk fullscreen fallback + touch handling for IPTV player
Add vendor-prefixed fullscreen API fallback chain (requestFullscreen -> webkitRequestFullscreen -> webkitEnterFullscreen) for Amazon Silk and other Chromium-based TV browsers. Add onTouchEnd handlers with preventDefault and pointer-events-none on SVG icons to fix button click issues in Silk's modal context. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
1 parent db28dc7 commit 71c0e7e

1 file changed

Lines changed: 79 additions & 13 deletions

File tree

src/components/live-tv/hls-player-modal.tsx

Lines changed: 79 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,58 @@ export function HlsPlayerModal({
150150
const handleVideoPlay = useCallback((): void => {
151151
const video = videoRef.current;
152152
if (!video) return;
153-
154-
// Only request fullscreen if not already in fullscreen
155-
if (!document.fullscreenElement && video.requestFullscreen) {
156-
video.requestFullscreen().catch((err: unknown) => {
157-
console.warn('[HLS Player] Could not enter fullscreen:', err);
158-
});
159-
}
153+
154+
// Check if already in fullscreen (supports vendor-prefixed variants)
155+
const isInFullscreen = !!(
156+
document.fullscreenElement ||
157+
(document as Document & { webkitFullscreenElement?: Element }).webkitFullscreenElement ||
158+
(document as Document & { mozFullScreenElement?: Element }).mozFullScreenElement
159+
);
160+
161+
if (isInFullscreen) return;
162+
163+
// Try multiple fullscreen methods for maximum browser compatibility
164+
// Amazon Silk and other Chromium-based TV browsers need vendor-prefixed methods
165+
const tryFullscreen = (): void => {
166+
// Method 1: Standard API
167+
if (video.requestFullscreen) {
168+
video.requestFullscreen().catch((err: unknown) => {
169+
console.warn('[HLS Player] requestFullscreen failed, trying webkit:', err);
170+
tryWebkitFullscreen();
171+
});
172+
return;
173+
}
174+
tryWebkitFullscreen();
175+
};
176+
177+
const tryWebkitFullscreen = (): void => {
178+
// Method 2: webkit prefix (Silk, older Chrome/Safari)
179+
const videoWithWebkit = video as HTMLVideoElement & { webkitRequestFullscreen?: () => Promise<void> };
180+
if (videoWithWebkit.webkitRequestFullscreen) {
181+
videoWithWebkit.webkitRequestFullscreen().catch((err: unknown) => {
182+
console.warn('[HLS Player] webkitRequestFullscreen failed, trying webkitEnterFullscreen:', err);
183+
tryWebkitEnterFullscreen();
184+
});
185+
return;
186+
}
187+
tryWebkitEnterFullscreen();
188+
};
189+
190+
const tryWebkitEnterFullscreen = (): void => {
191+
// Method 3: webkitEnterFullscreen (iOS Safari, some Android browsers)
192+
const videoWithWebkitEnter = video as HTMLVideoElement & { webkitEnterFullscreen?: () => void };
193+
if (videoWithWebkitEnter.webkitEnterFullscreen) {
194+
try {
195+
videoWithWebkitEnter.webkitEnterFullscreen();
196+
} catch (err: unknown) {
197+
console.warn('[HLS Player] webkitEnterFullscreen failed:', err);
198+
}
199+
return;
200+
}
201+
console.warn('[HLS Player] No fullscreen method available');
202+
};
203+
204+
tryFullscreen();
160205
}, []);
161206

162207
// Handle refresh button click to reload the stream
@@ -606,11 +651,22 @@ export function HlsPlayerModal({
606651
video.requestPictureInPicture().catch(() => {});
607652
}
608653
}}
609-
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
654+
onTouchEnd={(e) => {
655+
// Silk browser touch handling
656+
e.preventDefault();
657+
const video = videoRef.current;
658+
if (!video) return;
659+
if (document.pictureInPictureElement) {
660+
document.exitPictureInPicture().catch(() => {});
661+
} else {
662+
video.requestPictureInPicture().catch(() => {});
663+
}
664+
}}
665+
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors cursor-pointer touch-manipulation"
610666
aria-label="Picture-in-Picture"
611667
title="Picture-in-Picture (mini player)"
612668
>
613-
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
669+
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5 pointer-events-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
614670
<rect x="2" y="3" width="20" height="14" rx="2" />
615671
<rect x="12" y="9" width="8" height="6" rx="1" />
616672
</svg>
@@ -620,11 +676,16 @@ export function HlsPlayerModal({
620676
<button
621677
type="button"
622678
onClick={handleRefresh}
623-
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
679+
onTouchEnd={(e) => {
680+
// Silk browser touch handling
681+
e.preventDefault();
682+
handleRefresh();
683+
}}
684+
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors cursor-pointer touch-manipulation"
624685
aria-label="Refresh stream"
625686
title="Refresh stream"
626687
>
627-
<RefreshIcon className="w-5 h-5" />
688+
<RefreshIcon className="w-5 h-5 pointer-events-none" />
628689
</button>
629690
</div>
630691

@@ -633,10 +694,15 @@ export function HlsPlayerModal({
633694
ref={closeButtonRef}
634695
type="button"
635696
onClick={onClose}
636-
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
697+
onTouchEnd={(e) => {
698+
// Silk browser touch handling
699+
e.preventDefault();
700+
onClose();
701+
}}
702+
className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors cursor-pointer touch-manipulation"
637703
aria-label="Close"
638704
>
639-
<CloseIcon className="w-5 h-5" />
705+
<CloseIcon className="w-5 h-5 pointer-events-none" />
640706
</button>
641707
</div>
642708

0 commit comments

Comments
 (0)