@@ -95,6 +95,7 @@ export const StreamPanel = memo(function StreamPanel({
9595 const [ isSeeking , setIsSeeking ] = useState ( false ) ;
9696 const [ willWrap , setWillWrap ] = useState ( false ) ;
9797 const [ animatedDisplayVolume , setAnimatedDisplayVolume ] = useState ( stream . volume ) ;
98+ const [ containerWidth , setContainerWidth ] = useState < number > ( 999 ) ; // Inicializa com valor alto para mostrar controles até calcular
9899 const containerRef = useRef < HTMLDivElement > ( null ) ;
99100 const iframeRef = useRef < HTMLIFrameElement > ( null ) ;
100101 const twitchEmbedRef = useRef < HTMLDivElement > ( null ) ;
@@ -121,7 +122,13 @@ export const StreamPanel = memo(function StreamPanel({
121122 setCurrentTime ( 0 ) ;
122123 lastDurationRef . current = 0 ;
123124 durationIncreaseCountRef . current = 0 ;
124- } , [ stream . id , stream . channelId ] ) ;
125+
126+ // Se for um canal do YouTube (isChannel), assume que é live por padrão
127+ // A URL nesse caso usa /live_stream que sempre aponta para live ativa
128+ if ( stream . platform === 'youtube' && stream . isChannel ) {
129+ setIsLive ( true ) ;
130+ }
131+ } , [ stream . id , stream . channelId , stream . platform , stream . isChannel ] ) ;
125132
126133 // Fecha chat automaticamente se for YouTube e não for live
127134 useEffect ( ( ) => {
@@ -245,6 +252,27 @@ export const StreamPanel = memo(function StreamPanel({
245252 } ;
246253 } , [ ] ) ;
247254
255+ // Monitora a largura do container baseado na porcentagem
256+ useEffect ( ( ) => {
257+ const updateWidth = ( ) => {
258+ // Calcula largura real em pixels baseado na porcentagem do stream
259+ const viewportWidth = window . innerWidth ;
260+ const calculatedWidth = ( viewportWidth * stream . width ) / 100 ;
261+ console . log ( 'Container width:' , calculatedWidth , 'Stream:' , stream . title , 'Percentage:' , stream . width ) ;
262+ setContainerWidth ( calculatedWidth ) ;
263+ } ;
264+
265+ // Atualiza largura inicial
266+ updateWidth ( ) ;
267+
268+ // Atualiza na mudança de tamanho da janela
269+ window . addEventListener ( 'resize' , updateWidth ) ;
270+
271+ return ( ) => {
272+ window . removeEventListener ( 'resize' , updateWidth ) ;
273+ } ;
274+ } , [ stream . width , stream . title ] ) ;
275+
248276 // Inicializa Twitch Embed quando plataforma for Twitch
249277 useEffect ( ( ) => {
250278 if ( stream . platform !== 'twitch' || ! twitchEmbedRef . current ) return ;
@@ -466,19 +494,26 @@ export const StreamPanel = memo(function StreamPanel({
466494
467495 // Detecta se é uma transmissão ao vivo
468496 // Lives do YouTube têm duração que aumenta continuamente
469- if ( newDuration > lastDurationRef . current && newDuration > 60 ) {
497+ if ( newDuration > lastDurationRef . current && newDuration > 0 ) {
470498 // Incrementa contador de aumentos consecutivos
471499 durationIncreaseCountRef . current += 1 ;
472500
473- // Só considera live se a duração aumentou múltiplas vezes (3+)
474- // Isso evita falsos positivos com vídeos carregando
475- if ( durationIncreaseCountRef . current >= 3 ) {
501+ // Detecção mais agressiva de live:
502+ // 1. Se a duração aumentou pelo menos 2 vezes (mais rápido que antes)
503+ // 2. OU se a diferença entre currentTime e duration é pequena (indica live)
504+ // 3. OU se a duração é muito alta (>= 12h pode indicar live longa ou VOD de live)
505+ const timeDiff = newDuration - ( data . info . currentTime || 0 ) ;
506+ const isProbablyLive = durationIncreaseCountRef . current >= 2 ||
507+ ( timeDiff > 0 && timeDiff < 30 && newDuration > 60 ) ||
508+ newDuration >= 43200 ; // 12 horas
509+
510+ if ( isProbablyLive ) {
476511 setIsLive ( true ) ;
477512 }
478- } else if ( newDuration === lastDurationRef . current ) {
479- // Duração parou de crescer - provavelmente não é live
480- // Ou a live acabou
481- if ( durationIncreaseCountRef . current < 3 ) {
513+ } else if ( newDuration === lastDurationRef . current && newDuration > 0 ) {
514+ // Duração parou de crescer
515+ // Só marca como não- live se teve poucas aumentos E não é uma duração muito alta
516+ if ( durationIncreaseCountRef . current < 2 && newDuration < 43200 ) {
482517 setIsLive ( false ) ;
483518 }
484519 }
@@ -498,6 +533,14 @@ export const StreamPanel = memo(function StreamPanel({
498533 }
499534 }
500535
536+ // Resposta de getVideoData para detectar live
537+ if ( typeof data === 'object' && data . method === 'getVideoData' && data . value ) {
538+ // YouTube retorna isLive no videoData quando disponível
539+ if ( data . value . isLive !== undefined ) {
540+ setIsLive ( data . value . isLive ) ;
541+ }
542+ }
543+
501544 // Resposta direta de getCurrentTime - só atualiza se não estiver fazendo seek e se o valor for maior ou igual ao atual
502545 if ( typeof data === 'object' && data . method === 'getCurrentTime' && ! isSeeking && ( data . value || 0 ) >= currentTime ) {
503546 setCurrentTime ( data . value || 0 ) ;
@@ -558,6 +601,14 @@ export const StreamPanel = memo(function StreamPanel({
558601 args : [ ]
559602 } ;
560603 iframeRef . current . contentWindow ?. postMessage ( JSON . stringify ( durationMessage ) , '*' ) ;
604+
605+ // Requisita videoData para detectar live de forma mais precisa
606+ const videoDataMessage = {
607+ event : 'command' ,
608+ func : 'getVideoData' ,
609+ args : [ ]
610+ } ;
611+ iframeRef . current . contentWindow ?. postMessage ( JSON . stringify ( videoDataMessage ) , '*' ) ;
561612 }
562613 } , 500 ) ; // Atualiza a cada 500ms para resposta mais rápida
563614
@@ -1141,15 +1192,18 @@ export const StreamPanel = memo(function StreamPanel({
11411192 { /* Controles de reprodução (apenas para YouTube) */ }
11421193 { stream . platform === 'youtube' && (
11431194 < >
1144- < Button
1145- variant = "ghost"
1146- size = "icon"
1147- className = "h-8 w-8"
1148- onClick = { skipBackward }
1149- title = "Retroceder 10s (←)"
1150- >
1151- < SkipBack className = "h-4 w-4" />
1152- </ Button >
1195+ { /* Botões de skip - ocultos em largura < 300px */ }
1196+ { containerWidth >= 400 && (
1197+ < Button
1198+ variant = "ghost"
1199+ size = "icon"
1200+ className = "h-8 w-8"
1201+ onClick = { skipBackward }
1202+ title = "Retroceder 10s (←)"
1203+ >
1204+ < SkipBack className = "h-4 w-4" />
1205+ </ Button >
1206+ ) }
11531207 < Button
11541208 variant = "ghost"
11551209 size = "icon"
@@ -1163,27 +1217,35 @@ export const StreamPanel = memo(function StreamPanel({
11631217 < Play className = "h-4 w-4" />
11641218 ) }
11651219 </ Button >
1166- < Button
1167- variant = "ghost"
1168- size = "icon"
1169- className = "h-8 w-8"
1170- onClick = { skipForward }
1171- title = "Avançar 10s (→)"
1172- >
1173- < SkipForward className = "h-4 w-4" />
1174- </ Button >
1220+ { /* Botões de skip - ocultos em largura < 400px */ }
1221+ { containerWidth >= 400 && (
1222+ < Button
1223+ variant = "ghost"
1224+ size = "icon"
1225+ className = "h-8 w-8"
1226+ onClick = { skipForward }
1227+ title = "Avançar 10s (→)"
1228+ >
1229+ < SkipForward className = "h-4 w-4" />
1230+ </ Button >
1231+ ) }
11751232
11761233 { /* Botão "Ao Vivo" quando estiver atrasado */ }
11771234 { isLive && isBehindLive && (
11781235 < Button
11791236 variant = "default"
1180- size = "sm"
1181- className = "h-7 px-2 ml-1 bg-red-600 hover:bg-red-700 text-white"
1237+ size = { containerWidth < 400 ? "icon" : "sm" }
1238+ className = { cn (
1239+ "ml-1 bg-red-600 hover:bg-red-700 text-white" ,
1240+ containerWidth < 400 ? "h-7 w-7 px-0" : "h-7 px-2"
1241+ ) }
11821242 onClick = { goToLive }
11831243 title = "Voltar ao ao vivo"
11841244 >
1185- < Radio className = "h-3 w-3 mr-1" />
1186- < span className = "text-xs font-bold" > AO VIVO</ span >
1245+ < Radio className = { containerWidth < 400 ? "h-3 w-3" : "h-3 w-3 mr-1" } />
1246+ { containerWidth >= 400 && (
1247+ < span className = "text-xs font-bold" > AO VIVO</ span >
1248+ ) }
11871249 </ Button >
11881250 ) }
11891251 </ >
0 commit comments