Skip to content

Instantly share code, notes, and snippets.

@bobbicodes
Last active July 12, 2022 18:40
Show Gist options
  • Save bobbicodes/8261d999e62f9e06b0813f7d520b7111 to your computer and use it in GitHub Desktop.
Save bobbicodes/8261d999e62f9e06b0813f7d520b7111 to your computer and use it in GitHub Desktop.
Babashka script to trim silence from video with ffmpeg and moviepy
(ns silence
(:require [clojure.string :as str]
[clojure.java.shell :as shell]
[babashka.process :as p]))
(defn silences-output [file]
(:err
(shell/sh
"ffmpeg" "-hide_banner" "-vn" "-i"
file "-af" "silencedetect=n=-50dB:d=1" "-f" "null" "-")))
(defn lines [s]
(filter #(str/includes? % "silence_end")
(str/split (silences-output s) #"\r?\n|\r")))
(defn silences [line]
(str (nth line 4) " " (nth line 7)))
(defn generate-timestamps [file]
(let [base-name (apply str (take-while #(not= \. %) file))]
(->>
(map silences (map #(str/split % #"\s+") (lines file)))
(interpose \newline)
(apply str)
(spit (str base-name "-timestamps.txt")))))
(defn trim-video [file]
(let [base-name (apply str (take-while #(not= \. %) file))
cmd ["python3" "trim-silence.py" file
(str base-name "-trimmed.mp4")
(str base-name "-timestamps.txt")]
proc (p/process cmd {:inherit true
:shutdown p/destroy-tree})]
proc))
(def file (first *command-line-args*))
(generate-timestamps file)
@(trim-video file)
(comment
(def file "JavaScript-3-Poetry-club.mp4")
(generate-timestamps file)
(trim-video file)
)
#!/usr/bin/env python
import sys
import subprocess
import os
import shutil
from moviepy.editor import VideoFileClip, concatenate_videoclips
# Input file path
file_in = sys.argv[1]
# Output file path
file_out = sys.argv[2]
# Silence timestamps
silence_file = sys.argv[3]
minimum_duration = 1
def main():
# number of clips generated
count = 0
# start of next clip
last = 0
in_handle = open(silence_file, "r", errors='replace')
video = VideoFileClip(file_in)
full_duration = video.duration
clips = []
while True:
line = in_handle.readline()
if not line:
break
end,duration = line.strip().split()
to = float(end) - float(duration)
start = float(last)
clip_duration = float(to) - start
# Clips less than one seconds don't seem to work
print("Clip Duration: {} seconds".format(clip_duration))
print("Clip {} (Start: {}, End: {})".format(count, start, to))
clip = video.subclip(start, to)
clips.append(clip)
last = end
count += 1
if full_duration - float(last) > minimum_duration:
print("Clip {} (Start: {}, End: {})".format(count, last, 'EOF'))
clips.append(video.subclip(float(last)))
processed_video = concatenate_videoclips(clips)
processed_video.write_videofile(
file_out,
fps=30,
preset='ultrafast',
codec='libx264'
)
in_handle.close()
video.close()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment