11"use client" ;
22import React , { useRef , useEffect , useState } from "react" ;
3- import { Play , Radio , Signal , Zap , Users , Clipboard , X } from "lucide-react" ;
3+ import { Play , Radio , Signal , Zap , Users , Clipboard , X , RotateCcw } from "lucide-react" ;
44import videojs from "video.js" ;
55import "video.js/dist/video-js.css" ;
6+ import { usePathname } from "next/navigation" ;
7+
8+
9+ const streamKey = process . env . NEXT_PUBLIC_STREAM_KEY || "fallback-key" ;
10+
11+ const dashStream = `https://live.bitmutex.com/dash/${ streamKey } _src.mpd` ;
12+ const hlsStream = `https://live.bitmutex.com/hls/${ streamKey } .m3u8` ;
13+ console . log ( "DASH Stream URL:" , dashStream ) ;
14+ console . log ( "HLS Stream URL:" , hlsStream ) ;
615
7- const dashStream = "https://live.bitmutex.com/dash/test_src.mpd" ;
8- const hlsStream = "https://live.bitmutex.com/hls/test.m3u8" ;
916const genericHlsUrl = "https://live.bitmutex.com/dash/<key>_src.mpd" ;
1017const genericDashUrl = "https://live.bitmutex.com/hls/<key>.m3u8" ;
1118const rtmpServerUrl = "rtmp://152.67.172.75/live/<key>" ;
@@ -36,12 +43,21 @@ const StreamInfoPopover = ({ hlsUrl, dashUrl, rtmpServer }: { hlsUrl: string, da
3643
3744 return (
3845 < div className = "relative" ref = { popoverRef } >
39- < button
40- onClick = { ( ) => setIsOpen ( ! isOpen ) }
41- className = "p-2 rounded-full bg-gray-200/50 backdrop-blur-lg border border-gray-300 hover:bg-gray-300 dark:bg-gray-800/50 dark:border-gray-700 dark:hover:bg-gray-700 transition-colors"
42- >
43- < Signal size = { 20 } className = "text-gray-600 dark:text-gray-400" />
44- </ button >
46+ < div className = "flex items-center gap-3 p-2 bg-gray-100/50 dark:bg-gray-900/50 rounded-xl backdrop-blur-lg border border-gray-300 dark:border-gray-700" >
47+ < button
48+ onClick = { ( ) => setIsOpen ( ! isOpen ) }
49+ className = "p-2 rounded-full bg-gray-200/50 backdrop-blur-lg border border-gray-300 hover:bg-gray-300 dark:bg-gray-800/50 dark:border-gray-700 dark:hover:bg-gray-700 transition-colors"
50+ >
51+ < Signal size = { 20 } className = "text-gray-600 dark:text-gray-400" />
52+ </ button >
53+
54+ < button
55+ onClick = { ( ) => window . location . reload ( ) }
56+ className = "p-2 rounded-full bg-gray-200/50 backdrop-blur-lg border border-gray-300 hover:bg-gray-300 dark:bg-gray-800/50 dark:border-gray-700 dark:hover:bg-gray-700 transition-colors"
57+ >
58+ < RotateCcw size = { 20 } className = "text-gray-600 dark:text-gray-400" />
59+ </ button >
60+ </ div >
4561
4662 { isOpen && (
4763 < div className = "absolute left-1/2 -translate-x-1/2 mt-3 w-96 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg z-50 p-4 transition-all duration-300 ease-out transform scale-100 opacity-100" >
@@ -121,6 +137,8 @@ function VideoPlayer({
121137 const videoRef = useRef < HTMLVideoElement > ( null ) ;
122138 const playerRef = useRef < any > ( null ) ;
123139 const [ isLoading , setIsLoading ] = useState ( true ) ;
140+ const [ hasError , setHasError ] = useState ( false ) ;
141+
124142
125143 useEffect ( ( ) => {
126144 if ( videoRef . current ) {
@@ -133,16 +151,36 @@ function VideoPlayer({
133151 playerRef . current = videojs ( videoRef . current , {
134152 controls : true ,
135153 autoplay : false ,
154+ pip : true ,
136155 preload : "auto" ,
137156 fluid : true ,
138157 responsive : true ,
158+ userActions : {
159+ hotkeys : true
160+ } ,
139161 sources : [ { src, type } ] ,
140162 playbackRates : [ 0.5 , 1 , 1.25 , 1.5 , 2 ] ,
163+ poster : "https://i.ibb.co/PzxzqC7R/streamsoon.jpg" , // thumbnail before playback
164+ aspectRatio : "16:9" , // keep consistent aspect ratio
165+ html5 : {
166+ hls : { overrideNative : true } , // HLS options
167+ nativeAudioTracks : false ,
168+ nativeVideoTracks : false
169+ } ,
141170 plugins : { } ,
142171 } ) ;
143172
173+ videojs . addLanguage ( 'en' , {
174+ "Play" : "▶ Play" ,
175+ "Pause" : "⏸ Pause" ,
176+ "Video Not Supported" : "Video cannot be played." ,
177+ "The media could not be loaded, either because the server or network failed or because the format is not supported." :
178+ "Oops! Something went wrong or we are not live yet, check back later! 🤖" ,
179+ } ) ;
180+
144181 playerRef . current . ready ( ( ) => {
145182 setIsLoading ( false ) ;
183+ setHasError ( false ) ;
146184 } ) ;
147185
148186 playerRef . current . on ( 'loadstart' , ( ) => {
@@ -151,10 +189,13 @@ function VideoPlayer({
151189
152190 playerRef . current . on ( 'canplay' , ( ) => {
153191 setIsLoading ( false ) ;
192+ setHasError ( false ) ;
154193 } ) ;
155194
156- playerRef . current . on ( 'error' , ( ) => {
195+ playerRef . current . on ( "error" , ( ) => {
196+ console . error ( "Video.js player error:" , playerRef . current . error ( ) ) ;
157197 setIsLoading ( false ) ;
198+ setHasError ( true ) ; // Mark as error
158199 } ) ;
159200 }
160201
@@ -182,16 +223,27 @@ function VideoPlayer({
182223 style = { { display : hidden ? "none" : "block" } }
183224 >
184225 < div className = "relative overflow-hidden rounded-2xl bg-gradient-to-br from-gray-900 via-gray-800 to-black shadow-2xl dark:from-gray-950 dark:via-gray-900 dark:to-gray-800" >
185- { /* Stream info overlay */ }
186- < div className = "absolute top-4 left-4 z-20 flex items-center gap-3" >
187- < div className = "flex items-center gap-2 px-3 py-1.5 rounded-full bg-red-500/90 backdrop-blur-sm" >
188- < div className = "w-2 h-2 bg-emerald-400 rounded-full animate-pulse" > </ div >
189- < span className = "text-emerald text-sm font-medium" > LIVE</ span >
190- </ div >
191- < div className = "flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-black/40 backdrop-blur-sm text-white/90 dark:bg-white/10 dark:text-gray-200" >
192- < Users size = { 14 } />
193- </ div >
226+ { /* Stream info overlay */ }
227+ < div className = "absolute top-4 left-4 z-20 flex items-center gap-3" >
228+ < div
229+ className = { `flex items-center gap-2 px-3 py-1.5 rounded-full backdrop-blur-sm ${
230+ hasError ? "bg-gray-500/80" : "bg-red-500/90"
231+ } `}
232+ >
233+ < div
234+ className = { `w-2 h-2 rounded-full ${
235+ hasError ? "bg-red-600 animate-none" : "bg-emerald-400 animate-pulse"
236+ } `}
237+ > </ div >
238+ < span className = { `text-sm font-medium ${ hasError ? "text-white" : "text-emerald" } ` } >
239+ { hasError ? "OFFLINE" : "LIVE" }
240+ </ span >
241+ </ div >
242+
243+ < div className = "flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-black/40 backdrop-blur-sm text-white/90 dark:bg-white/10 dark:text-gray-200" >
244+ < Users size = { 14 } />
194245 </ div >
246+ </ div >
195247
196248 { /* Stream quality badge */ }
197249 < div className = "absolute top-4 right-4 z-20" >
@@ -351,6 +403,7 @@ export default function LivePage() {
351403 </ div >
352404
353405 </ div >
406+
354407 </ div >
355408 ) ;
356409}
0 commit comments