
    J	j                         d Z ddlZddlZddlZddlZddlZddlmZ dZdZ	d Z
ddZddZd	 Zd
 Zedk(  r e        yy)uq  
silence_cutter.py — Remove silent parts from a video using FFmpeg silencedetect.

Usage:
    python3 silence_cutter.py <input_video> <output_video> [--threshold-db DB]
                                                [--min-duration SEC]
                                                [--padding SEC]

Requires: ffmpeg and ffprobe in /home/claw/.local/tools/ffmpeg/
    N)Pathz%/home/claw/.local/tools/ffmpeg/ffmpegz&/home/claw/.local/tools/ffmpeg/ffprobec           
          t         ddddddt        |       g}t        j                  |dd      }t	        j
                  |j                        }t        |d	   d
         S )z3Return total audio duration in seconds via ffprobe.z-verrorz-show_entrieszformat=durationz-ofjsonTcapture_outputtextformatduration)FFPROBEstr
subprocessrunr   loadsstdoutfloat)
video_pathcmdresultdatas       P/home/claw/.openclaw/workspace/skills/video-edit-local/scripts/silence_cutter.pyget_audio_durationr      s^     	w*vJ	C ^^C4@F::fmm$Dh
+,,    c                 2   t         dt        |       dd| d| dddg}t        j                  |dd	      }|j                  }g }g }g }|j                         D ]  }	|	j                         }	t        j                  d
|	      }
|
r)|j                  t        |
j                  d                   t        j                  d|	      }
|
sm|j                  t        |
j                  d                    t        ||      D ]  \  }}|j                  ||f        |S )z
    Run FFmpeg silencedetect and return list of (start, end) silence intervals.
    Threshold in dB (e.g. -30, -40). min_duration in seconds.
    -iz-afzsilencedetect=noise=zdB:d=-fnull-Tr   zsilence_start:\s*([\d.]+)   z;silence_end:\s*([\d.]+)\s*\|\s*silence_duration:\s*([\d.]+))FFMPEGr   r   r   stderr
splitlinesstripresearchappendr   groupzip)r   threshold_dbmin_durationr   r   r!   silencesstart_times	end_timeslinemses                r   detect_silencesr2   %   s    	c*o%l^5GfcC
 ^^C4@F]]FHKI!!# 	0zz|II2D9uQWWQZ01IITVZ[U1771:./	0 K+  1A  Or   c                     g }d}| D ]=  \  }}t        |||z
        }t        |||z         }||kD  r|j                  ||f       |}? ||k  r|j                  ||f       |S )z
    Given silence intervals, return the complement: the segments to KEEP.
    Adds small padding to avoid cutting too aggressively.
    g        )maxminr&   )r+   total_durationpaddingsegmentslast_endr0   r1   s          r   build_keep_segmentsr:   H   s}    
 HH 1!g+&G,x<OOXqM* . >23Or   c                    t        |      j                  dz  }|j                  d       |dz  }t        |d      5 }t	        |      D ]  \  }\  }}||z
  }	|d|ddz  }
t
        d	d
t        |      dt        |       dt        |	      ddddddddddt        |
      g}t        j                  |dd       |j                  d|
 d        	 ddd       t
        d	dddddt        |      ddddddddddt        |      g}t        j                  |dd      }|j                  d      D ]  }|j                           |j                          |j                          |j                  d k(  S # 1 sw Y   xY w)!z|
    Cut each keep-segment and stitch them together using FFmpeg concat.
    Re-encodes with libx264 for compatibility.
    z.concat_tmpT)exist_okzsegments.txtwseg_03dz.mp4z-yz-ssr   z-tz-c:vlibx264z-presetfastz-crf23z-c:aaacz-b:a128kr   zfile 'z'
Nr   concatz-safe0z	seg_*.mp4r   )r   parentmkdiropen	enumerater    r   r   r   writeglobunlinkrmdir
returncode)r   r8   output_pathtmp_dir	list_filefistartendr   segment_filer   
concat_cmdr   s                 r   concatenate_segmentsrY   ^   s   
 ;&&6GMM4M  .(I	i	 0(2 	0OA|sU{H"tAc7$%77Ls5zc*oc(m	9fvvL!	C NN3t$?GGf\N#./	00& 	hc)n	9ffdvvKJ ^^Jt$GF \\+& 	
MMO!!G0 0s   BE--E6c                  ^   t        j                  d      } | j                  dd       | j                  dd       | j                  dt        d	d
       | j                  dt        dd       | j                  dt        dd       | j	                         }t        |j                        }t        |j                        }|j                         s3t        d| t        j                         t        j                  d       t        d|j                   d|j                   d       t        ||j                  |j                        }t        dt!        |       d       t#        |      }t%        |||j&                        }t        dt!        |       d       t)        |      D ])  \  }\  }}	t        d|dz    d|dd|	dd |	|z
  dd!	       + t        d"       t+        |||      }
|
rt        d#|        y t        d$t        j                         t        j                  d       y )%Nz!Remove silent parts from a video.)descriptioninput_videozPath to input video file)helpoutput_videozPath to output video filez--threshold-dbz&Silence threshold in dB (default: -30))typedefaultr]   z--min-duration      ?z2Minimum silence duration in seconds (default: 0.5)z	--padding皙?z6Padding around kept segments in seconds (default: 0.1)z[ERROR] Input file not found: )filer   zDetecting silences (threshold=zdB, min_duration=zs)...zFound z silent segment(s)zKeeping z segment(s)z
  Segment z: z.2fu   s → zs (duration=zs)zCutting and concatenating...z[OK] Saved: z[ERROR] FFmpeg concat failed)argparseArgumentParseradd_argumentr   
parse_argsr   r\   r^   existsprintsysr!   exitr)   r*   r2   lenr   r:   r7   rJ   rY   )parserargs
input_pathrP   r+   r6   r8   rT   r0   r1   oks              r   mainrr      s   $$1TUF
,FG
-HI
(ucE  G
(ucQ  S
%U  W Dd&&'Jt(()K.zl;#**M	*4+<+<*==NtO`O`Naaf
ghz4+<+<d>O>OPH	F3x=/!3
45'
3N"8^T\\JH	HS]O;
/0x( O	6Aq
1Q3%r!Cqg\!A#c"MNO 
(*	j(K	@B	[M*+,3::>r   __main__)r_   rb   )rc   )__doc__re   r   r$   r   rk   pathlibr   r    r   r   r2   r:   rY   rr   __name__ r   r   <module>rx      sX   	   	  
 	0
2
- F,-"`%P zF r   