
    <j/C                     d   d Z ddlZddlZddlZddlmZ ddlmZ dZdZ	dZ
dZd	Zd-d
ededej                  fdZdedefdZdefdZefdedefdZdedededefdZdedefdZ	 	 d.dedededededefdZd-dededefd Zdefd!Zdefd"Z	 	 d/d#ed$ed%ed&ed'ededed(ed)efd*Zd+edefd,Zy)0u.   Utilitários de montagem de vídeo via FFmpeg.    N)Path)gerar_karaoke_drawtext_filters   i8  i  128k48000cmdcheckreturnc                     t        j                  | dd      }|r*|j                  dk7  rt        d|j                  dd        |S )z0Executa um comando FFmpeg e retorna o resultado.Tcapture_outputtextr   zFFmpeg falhou: iN)
subprocessrun
returncodeRuntimeErrorstderr)r   r	   results      7/opt/mia/workspace/video_editor/backend/ffmpeg_utils.pyr   r      sG    ^^C4@F""a'_V]]45-A,BCDDM    pathc           	          t        j                  dddddd| gdd      }|j                  d	k7  ry
t        j                  |j
                        }t        |d   j                  dd	            S )u)   Retorna duração do arquivo em segundos.ffprobez-vquietz-print_formatjsonz-show_formatTr   r           formatduration)r   r   r   r   loadsstdoutfloatget)r   r   datas      r   get_duracaor$      sh    ^^	D'?FNDQ$F A::fmm$Dh##J233r   c            	      @    dt          dt         dt          dt         d	S )z3Filtro de scale+pad para 1080x1920 com SAR correto.zscale=:z*:force_original_aspect_ratio=decrease,pad=z#:(ow-iw)/2:(oh-ih)/2:black,setsar=1)TARGET_WTARGET_H r   r   _vf_9_16r*   (   s0     
!H: &j( $	r   fpsc                 `    dddddddt        |       dd	d
t        | dz        dt               ddgS )u/   Argumentos padronizados de re-encode de vídeo.-c:vlibx264-presetfast-crf23-r-pix_fmtyuv420pz-g   -vfz	-movflagsz
+faststart)strr*   )r+   s    r   _encode_args_videor9   1   sD     		6c#hIc#'lxz\	 	r   
video_path	segmentosjob_idc                    t        |       j                  }g }t        |      D ]  \  }}t        || d| dz        }ddd| dt        |d         dt        |d	         gt	               z   d
ddt
        dt        |gz   }t        |       t        |      j                         s~|j                  |        |s| S t        |      dk(  r|d   S t        || dz        }	t        |	d      5 }
|D ]  }|
j                  d| d        	 ddd       t        || dz        }t        ddddddd|	dd|gd       |S # 1 sw Y   4xY w)uS   Corta e une segmentos selecionados em um único arquivo, com re-encode normalizado._seg_.mp4ffmpeg-y-i-ssinicio-tofim-c:aaac-b:a-ar   r   z_lista_segs.txtwfile ''
Nz_cortado.mp4-fconcat-safe0-ccopyTr	   )r   parent	enumerater8   r9   AUDIO_BITRATEAUDIO_SRr   existsappendlenopenwrite)r:   r;   r<   temp_dirclipsisegclipr   listafcoutputs                r   cortar_segmentosrh   ?   s   J&&HEI& 38aS556dD*3s8}%3s5z?
  	!
 E6=%$
	
 	C:LL 
5zQQxfX_556E	eS	 %Q 	%AGGfQCsO$	%% vhl334F$heT66	  M% %s   (D99Esrt_pathc           
      <   dt         dt        fd}t        |dd      5 }t        | d      D ]Y  \  }}|j	                  | d       |j	                   ||d	          d
 ||d          d       |j	                  |d    d       [ 	 ddd       y# 1 sw Y   yxY w)z4Gera arquivo .srt a partir dos segmentos do Whisper.sr
   c                     t        | dz        }t        | dz  dz        }| dz  }|dd|dd|dj                  dd      S )Ni  <   02dr&   z06.3f.,)intreplace)rk   hmsss       r   fmtzgerar_legenda_srt.<locals>.fmth   sU    T	NTb !VC!C"U,44S#>>r   rL   zutf-8)encodingrK   
rD   z --> rF   textoz

N)r!   r8   r]   rW   r^   )r;   ri   rv   re   ra   rb   s         r   gerar_legenda_srtrz   f   s    ?u ? ? 
hg	. +!	1- 	+FAsGGqcHGGs3x=)*%CJ/@CDGGs7|nD)*	++ + +s   A)BB
input_pathoutput_path	sem_audioduracao_maxru   toc                    ddg}||dt        |      gz  }||dt        |      gz  }|d| gz  }||dt        |      gz  }|t               z  }|r|dgz  }n|d	d
dt        dt        gz  }|j	                  |       t        |d       y)u   
    Re-encoda um clip para o padrão 1080x1920 / 30fps / yuv420p / GOP 60 / AAC 48kHz.
    Garante que clips do Pexels e cortes do principal fiquem 100% compatíveis pra concat.
    r@   rA   NrC   rE   rB   z-tz-anrG   rH   rI   rJ   TrU   )r8   r9   rX   rY   r[   r   )r{   r|   r}   r~   ru   r   r   s          r   normalizar_clipr   u   s     T
C	~s2w	~s2wD*Cc+&''Cwv}eXFFJJ{4r   c                      t        | ||       y)uV   Converte vídeo inteiro para 9:16 (1080x1920) com letterbox e padronização completa.r}   N)r   )r{   r|   r}   s      r   converter_9_16r      s    JyAr   c                     t        | t              r| S t        | t              r	 t        |       S y# t        $ r Y nw xY wddddd}|j	                  | j                         j                         d      S )zCConverte 'pequeno'/'medio'/'grande' (ou int) em FontSize do libass.         pequenomediou   médiogrande
isinstancerq   r8   
ValueErrorr"   lowerstriptamanho_legendamapas     r   _resolver_tamanho_legendar      sv    /3'/3'	''
 	  		bBGxx--/557<<   
0 	<<c                     t        | t              r| S t        | t              r	 t        |       S y# t        $ r Y nw xY wddddd}|j	                  | j                         j                         d      S )u   
    Resolve fontsize em PX absoluto pro Karaokê IG (drawtext, não libass).
    Vídeo 1080x1920. ~3.6% da altura = 70px é o tamanho médio (ref do IG).
    :   H   Z   r   r   r   s     r   _resolver_fontsize_karaoker      sx    
 /3'/3'	''
 	  		bBGxx--/557<<r   video_principalclips_brolltranscricaomusica_pathestilo_legendar   volume_musicac	                    t        |       j                  }	t        |	| dz        }
t        | |
d       t	        |
      }|xr) t        |      j                         j                         dv}d}d}|rt        |      j                         j                         }|dv r2	 t        |      }t        |t        t        |      }|st        d       d}nt        |	| d
z        }|j                  dd      j                  dd      }t        |j                  dg       |       t!        |      }|dk(  rd| d}n|dk(  rd| d}nd| d}d| dt         dt         d| d	}t#        ||      }|r|D ]  }t        |d         j%                         sd|d<   %t        |	| d|d    dz        }	 t'        d |d!   |d"   z
        }t)        |d   |d#|$       t        |      j%                         r|nd|d<    |D cg c]  }|j                  d      s| }}|j+                  d' (       g }d }|D ]F  }t'        |d"   |d)z         }t-        |d!   |      }||z
  d*k  r-|j/                  i |||d+       |}H |rt        |	| d,z        } t1        d-d.d/|
d0d1d2d3t2        d4t4        | gd#5       g }!d }"|D ]  }|d"   |"d6z   kD  r[t        |	| d7t7        |!      d8d9z        }#t)        |
|#d#|"|d"   :       t        |#      j%                         r|!j/                  |#       |!j/                  |d          |d!   }" |"|d6z
  k  rXt        |	| d7t7        |!      d8d9z        }#t)        |
|#d#|"|:       t        |#      j%                         r|!j/                  |#       t        |	| d;z        }$t9        |$d<      5 }%|!D ]  }&|%j;                  d=|& d>        	 ddd       t        |	| d?z        }'t1        d-d.d@dAdBdCd/|$dDdE|'g      }(|(j<                  dFk7  st        |'      j%                         st        dG|(j>                  dHd         g })|!D ]	  }&|)d/|&gz  }) t7        |!      }*dIjA                  dJ tC        |*      D              dK|* dLz   }+t1        d-d.g|)dM|+dNdOdPdQdRdSdTdUdVt        tD              dWdX|'x},d#5       t        |	| dYz        }-t1        d-d.d/|'d/| dPdEd1d2d3t2        d4t4        dZ|-gd#5       |-}.n|
}.n|
}.|r|s|rt        |	| d[z        }/|r|}0d\}1n|}0d]}1t        d^|1        t1        d-d.d/|.d_|0dPdQdRdSdTdUdVt        tD              dWdXd1dE|/g      }2|2j<                  dFk7  st        |/      j%                         s!t        d`|2j>                  dad  db       |.}/n|.}/|rt        |      j%                         r	 tG        |      }3t'        dFt-        dd|3            }3|3dez  }4|3dFk(  rtM        jN                  |/|       yt        df|4dgdh|3 di       t1        d-d.d/|/d/|dMdj|4dkdldNdmdNdndPdEd1d2d3t2        d4t4        dZ|gd#5       ytM        jN                  |/|       y# t        $ r}t        d| d	       d}Y d}~"d}~ww xY w# t        $ r$}t        d%|d    d&|        d|d<   Y d}~Ad}~ww xY wc c}w # 1 sw Y   xY w# tH        tJ        f$ r dc}3Y w xY w)ou  
    Pipeline de montagem:
    1. Normaliza principal pra 9:16/30fps/yuv420p
    2. Gera SRT
    3. Intercala B-rolls alinhados com a fala (cada item tem inicio/fim)
    4. Queima legendas com tamanho ajustável
    5. Adiciona música de fundo (volume controlado por `volume_musica`, 0..50)

    `clips_broll` aceita 2 formatos:
        - lista de strings (paths) - modo legado (intercala em intervalos fixos)
        - lista de dicts {"path": str, "inicio": float, "fim": float} - modo alinhado
    z_main_9_16.mp4Fr   >    semnonefalsenenhumN>   
karaoke-igkig	karaokeig
karaoke_igz2[ffmpeg] karaoke_ig sem palavras, pulando legenda.z#[ffmpeg] erro ao gerar karaoke_ig: z. Pulando legenda.z.srt\z\\r&   z\:r;   amarelaz	FontSize=zW,PrimaryColour=&H00FFFF,OutlineColour=&H000000,Outline=2,Bold=1,Alignment=2,MarginV=120karaokezp,PrimaryColour=&HFFFFFF,SecondaryColour=&H00FFFF,OutlineColour=&H000000,Outline=2,Bold=1,Alignment=2,MarginV=120zW,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,Outline=2,Bold=1,Alignment=2,MarginV=120z
subtitles=z:original_size=xz:force_style=''r   	path_norm_broll_norm_idxr?   r   rF   rD   T)r}   r~   z#[ffmpeg] Falha ao normalizar broll z: c                     | d   S )NrD   r)   )r   s    r   <lambda>z$montar_video_final.<locals>.<lambda>  s
    1X; r   )keyg      ?      ?)rD   rF   z
_audio.aacr@   rA   rB   z-vnrG   rH   rI   rJ   rU   g333333?_tl_rn   z	_main.mp4)r}   ru   r   z_lista_v.txtrL   rM   rN   z_sem_audio.mp4rO   rP   rQ   rR   rS   rT   r   z7[ffmpeg] concat copy falhou, usando concat filter. err=i8r   c              3   (   K   | ]
  }d | d  yw)[z:v]Nr)   ).0ra   s     r   	<genexpr>z%montar_video_final.<locals>.<genexpr>W  s     (F1QCs(Fs   z	concat=n=z:v=1:a=0[v]z-filter_complexz-mapz[v]r-   r.   r/   r0   r1   r2   r3   r4   r5   z_com_audio.mp4z	-shortestz_legendado.mp4z karaoke_ig (drawtext word-level)zsubtitles (libass)z$[ffmpeg] Queimando legenda no modo: r7   z*[ffmpeg] Aviso: falha ao gravar legendas (iz). Continuando sem elas.   2   g      Y@u$   [ffmpeg] Mixando música com volume=z.2fz (z%)z[1:a]volume=z.3fz6[music];[0:a][music]amix=inputs=2:duration=first[aout]z0:vz[aout])(r   rV   r8   r   r$   r   r   r   r   r'   r(   print	Exceptionrr   rz   r"   r   _normalizar_broll_inputrZ   maxr   sortminr[   r   rX   rY   r\   r]   r^   r   r   joinrange
TARGET_FPSrq   	TypeErrorr   shutilrT   )5r   r   r   r   r   r<   r|   r   r   r_   principal_9_16duracao_totallegenda_ativasubtitles_filterkaraoke_ig_filterestilo_lfontsize_pxeri   srt_escapedfontsizestylebroll_itemsitem	broll_outjanelabvalidos	ajustadoscursorinirF   
audio_pathclips_vt	clip_mainlista_vre   rf   video_sem_audior_concatinputsnfilter_complexinputs_to_cmdvideo_com_audiovideo_para_legendavideo_legendadovf_argmodo_logrvol_int	vol_floats5                                                        r   montar_video_finalr      s   . O$++H vhn$==>N?NeD/M #xs>':'@'@'B'H'H'JRx'xM~&,,.446GG
&8I$B8[%! )NO$)M 8o56H"**48@@eLKkook2>I0AH9$#H:  .E  FY&#H:  .^  _#H:  .E  F [M
!H:^\a[bbcd 
 *+}EK 	)DV%,,.$([!H&d5k]$'OOPI
)S$u+X">?L)t & 26i1G1G1IIt[!	)$ *@QUU;-?1@@./ 	 	Aak6C<0Cah.CSy3==S=>F	 X6(*(==>J$nev}eX 	 GA X;S( #H&c'l3=Oy/Y$Y ZI#&	T8 I--/y1 q~.eH  =3&&fXT#g,s9K9+U UV	"I] 	?))+NN9- (x|%<<=Ggs# -q  -AGGfQCsO,-- "(x~-F"FGO$hgtV_ H ""a'tO/D/K/K/MOPXP_P_`d`ePfOghi  (AtQi'F(L!#(FU1X(F!F9UVTWWbIc!cd&%+&%&'5& & "& 	& &	& (1	& 39	& ;A	& CG	&
 &
 j/&
 ,6&
 8A& $& M  "(x~-F"FGO$otZv}eX_  "1!/+ *.?hF8>)BBC&F9H%F+H4XJ?@dD"46Iy&&$#j/:yFO
  <<1D$9$@$@$B>qxx>OOghi0O - tK(//1	-(G aR)*eO	a<KK583r'RTUV$ot[!yo-cdvxv}eX[	 	 	O[1E  &;A3>PQR %&P  );DL>A3OP$([!)
 Al- -T :& 	G	s[   0Y! -AZ	:Z9Z95Z>[ !	Z*ZZ		Z6Z11Z6>[[ [ r   c           
         | sg S | d   }t        |t              rg }t        |       D ]r  \  }}|j                  d      }t	        |j                  dd            }t	        |j                  dt        |dz   |                  }|s]|j                  ||||d       t |S d}	d}
g }|	}t        | dd	       D ]<  \  }}||d
z
  k\  r |S |}t        ||
z   |      }|j                  ||||d       ||	z   }> |S )a  
    Normaliza o argumento clips_broll pros dois formatos suportados:
    - lista de strings (paths): cria janelas fixas
    - lista de dicts {"path","inicio","fim"}: passa adiante adicionando idx
    Retorna lista de dicts {"idx", "path", "inicio", "fim"}.
    r   r   rD   rF   g      @)r   r   rD   rF   g       @N   r   )r   dictrW   r"   r!   r   r[   )r   r   primeirooutra   r   r   r   rF   INTERVAL_MAININTERVAL_BROLLr   s               r   r   r     s.    	 1~H(D! - 	LGAt88F#D1-.CC#I}(EFGCJJq$#cJK	L 
 MN
CA[!_-  4##
 J	 !n$m4

1dc#FG-  Jr   )F)FNNN)r   r   ) __doc__r   r   r   pathlibr   karaoke_legendar   r   r'   r(   rX   rY   listboolCompletedProcessr   r8   r!   r$   r*   rq   r9   rh   rz   r   r   r   r   r   r   r   r)   r   r   <module>r      s   4     : 
T $ :+F+F 	4c 	4e 	4#  #- C  $ $ $s $s $N+ + + JONR # $ "'49FK.Bs B B B
# 3 4 #t2t2t2 t2 	t2
 t2 t2 t2 t2 t2n# #$ #r   