@@ -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