#!/usr/bin/python3 import subprocess as sp from shlex import quote import re import argparse import sys, os FFMPEG_SILENCEDETECT_COMMAND = "ffmpeg -y -hide_banner -nostats -i {filename} -af silencedetect=d=0.3 -map 0 -map -0:v -f wav /dev/null" SILENCE_START_RE = re.compile("^\[silencedetect @ 0x[0-9a-f]+\] silence_start: ([\d\.]+)$") SILENCE_END_RE = re.compile("^\[silencedetect @ 0x[0-9a-f]+\] silence_end: ([\d\.]+) \| silence_duration: ([\d\.]+)$") def cut(in_file, out_file="out_file.mkv", silences=[]): betweens = "" for silence in silences: betweens += f"between(t,{silence[0]},{silence[1]})+" betweens = betweens[:-1] if betweens else betweens video_filter = f"select='{betweens}',setpts=N/FRAME_RATE/TB" audio_filter = f"aselect='{betweens}',asetpts=N/SR/TB" command = ["ffmpeg", "-i", in_file, "-vf", video_filter, "-af", audio_filter, out_file] sp.run(command) def detect_silence(filename): output = sp.run(FFMPEG_SILENCEDETECT_COMMAND.format(filename=quote(filename)), shell=True, stderr=sp.PIPE).stderr total_silence = 0 talking = [] current_silence = ["0", None] for line in output.split(b"\n"): line = line.strip() line = line.decode("utf8") if not "silencedetect" in line: continue if match := SILENCE_START_RE.match(line): print("Silence start at", match[1]) current_silence[1] = match[1] talking.append(tuple(current_silence)) elif match := SILENCE_END_RE.match(line): print("Silence end at", match[1]) current_silence[0] = match[1] total_silence += float(match.group(2)) print("Total:", total_silence) return talking if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--output-format", "-f") parser.add_argument("infiles", nargs="+") args = parser.parse_args() for f in args.infiles: if not os.path.isfile(f): print(f"{f} not found, skipping...", file=sys.stderr) continue new_filename = os.path.splitext(f)[0]+".mkv" talking = detect_silence(f) cut(f, new_filename, talking)