From f2299c51b196e41eb06b69a3b46ad10f3e25bd30 Mon Sep 17 00:00:00 2001 From: sm18lr88 <64564447+sm18lr88@users.noreply.github.com> Date: Mon, 27 Nov 2023 21:32:38 -0500 Subject: [PATCH 1/3] Add files via upload --- silence_cutter_GUI.py | 175 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 silence_cutter_GUI.py diff --git a/silence_cutter_GUI.py b/silence_cutter_GUI.py new file mode 100644 index 0000000..6bcbd46 --- /dev/null +++ b/silence_cutter_GUI.py @@ -0,0 +1,175 @@ +import subprocess +import tempfile +import os +import tkinter as tk +from tkinter import filedialog, messagebox +import webbrowser + +def findSilences(filename, dB=-35): + try: + command = ["ffmpeg", "-i", filename, "-af", "silencedetect=n=" + str(dB) + "dB:d=0.5", "-f", "null", "-"] + output = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) + except subprocess.CalledProcessError as e: + messagebox.showerror("Error", f"An error occurred while finding silences: {e}") + return [] + + s = str(output) + lines = s.split("\\r") + time_list = [] + for line in lines: + if "silencedetect" in line: + words = line.split(" ") + for i in range(len(words)): + if "silence_start" in words[i]: + time_list.append(float(words[i + 1])) + if "silence_end" in words[i]: + time_list.append(float(words[i + 1])) + return time_list + +def getVideoDuration(filename): + try: + command = ["ffprobe", "-i", filename, "-v", "quiet", "-show_entries", "format=duration", "-hide_banner", "-of", "default=noprint_wrappers=1:nokey=1"] + output = subprocess.run(command, stdout=subprocess.PIPE, check=True) + except subprocess.CalledProcessError as e: + messagebox.showerror("Error", f"An error occurred while getting video duration: {e}") + return 0 + + s = str(output.stdout, "UTF-8") + return float(s) + +def getSectionsOfNewVideo(silences, duration): + return [0.0] + silences + [duration] + +def ffmpeg_filter_getSegmentFilter(videoSectionTimings): + ret = "" + for i in range(int(len(videoSectionTimings) / 2)): + start = videoSectionTimings[2 * i] + end = videoSectionTimings[2 * i + 1] + ret += "between(t," + str(start) + "," + str(end) + ")+" + ret = ret[:-1] + return ret + +def getFileContent_videoFilter(videoSectionTimings): + ret = "select='" + ret += ffmpeg_filter_getSegmentFilter(videoSectionTimings) + ret += "', setpts=N/FRAME_RATE/TB" + return ret + +def getFileContent_audioFilter(videoSectionTimings): + ret = "aselect='" + ret += ffmpeg_filter_getSegmentFilter(videoSectionTimings) + ret += "', asetpts=N/SR/TB" + return ret + +def writeFile(filename, content): + with open(filename, "w") as file: + file.write(str(content)) + +def ffmpeg_run(file, videoFilter, audioFilter, outfile): + try: + with tempfile.NamedTemporaryFile(mode="w", encoding="UTF-8", prefix="silence_video", delete=False) as vFile, \ + tempfile.NamedTemporaryFile(mode="w", encoding="UTF-8", prefix="silence_audio", delete=False) as aFile: + writeFile(vFile.name, videoFilter) + writeFile(aFile.name, audioFilter) + + command = ["ffmpeg", "-hwaccel", "cuda", "-i", file, + "-filter_script:v", vFile.name, + "-filter_script:a", aFile.name, + "-c:v", "h264_nvenc", outfile] + + subprocess.run(command, check=True) + except subprocess.CalledProcessError as e: + messagebox.showerror("Error", f"An error occurred while processing the file: {e}") + +def cut_silences(infile, outfile, dB=-35): + silences = findSilences(infile, dB) + if not silences: + return + duration = getVideoDuration(infile) + if duration == 0: + return + videoSegments = getSectionsOfNewVideo(silences, duration) + videoFilter = getFileContent_videoFilter(videoSegments) + audioFilter = getFileContent_audioFilter(videoSegments) + ffmpeg_run(infile, videoFilter, audioFilter, outfile) + +class SilenceCutterApp(tk.Tk): + def __init__(self): + super().__init__() + self.title("Silence Cutter") + self.geometry("400x300") + + self.infile_label = tk.Label(self, text="Input File:") + self.infile_label.pack() + self.infile_entry = tk.Entry(self, width=50) + self.infile_entry.pack() + self.browse_button = tk.Button(self, text="Browse", command=self.browse_file) + self.browse_button.pack() + + self.outfile_label = tk.Label(self, text="Output File: (file conversion possible)") + self.outfile_label.pack() + self.outfile_entry = tk.Entry(self, width=50) + self.outfile_entry.pack() + self.save_as_button = tk.Button(self, text="Save As", command=self.save_as) + self.save_as_button.pack() + + self.db_label = tk.Label(self, text="Decibel Level for silence threshold detection (default -30 dB):") + self.db_label.pack() + self.db_entry = tk.Entry(self, width=50) + self.db_entry.insert(0, "-30") + self.db_entry.pack() + + self.process_button = tk.Button(self, text="Process", command=self.process_file) + self.process_button.pack() + + self.help_button = tk.Button(self, text="Help", command=self.show_help) + self.help_button.pack() + + def browse_file(self): + filename = filedialog.askopenfilename(title="Select a file", filetypes=[("Media files", "*.*")]) + self.infile_entry.delete(0, tk.END) + self.infile_entry.insert(0, filename) + + def save_as(self): + infile = self.infile_entry.get() + default_ext = os.path.splitext(infile)[1] if infile else '' + outfile = filedialog.asksaveasfilename( + title="Save As", + filetypes=[("Media files", f"*{default_ext}"), ("All files", "*.*")], + defaultextension=default_ext + ) + self.outfile_entry.delete(0, tk.END) + self.outfile_entry.insert(0, outfile) + + def process_file(self): + infile = self.infile_entry.get() + outfile = self.outfile_entry.get() + db = self.db_entry.get() + + if not infile or not outfile: + messagebox.showerror("Error", "Please specify both input and output files.") + return + + try: + db_value = float(db) + cut_silences(infile, outfile, db_value) + messagebox.showinfo("Success", "Processing completed.") + except ValueError: + messagebox.showerror("Error", "Invalid decibel level for silence threshold.") + + def show_help(self): + help_text = """ + Usage: Select an input file and an output file. Optionally, set the dB level. + Default dB level is -30. + -30 dB: Cuts mouse clicks and movement; cuts are very recognizable. + -35 dB: Cuts inhaling breath before speaking; cuts are quite recognizable. + -40 dB: Cuts are almost not recognizable. + -50 dB: Cuts are almost not recognizable and nothing if there's background noise. + Dependencies: ffmpeg, ffprobe + For more information on supported formats, visit: https://ffmpeg.org/ffmpeg-formats.html + """ + messagebox.showinfo("Help", help_text) + +if __name__ == "__main__": + app = SilenceCutterApp() + app.mainloop() From d0e3afd31236402318738f788b925635eeca4f54 Mon Sep 17 00:00:00 2001 From: sm18lr88 <64564447+sm18lr88@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:23:51 -0400 Subject: [PATCH 2/3] Update readme.md --- readme.md | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/readme.md b/readme.md index 9a18f11..0fa0c7d 100644 --- a/readme.md +++ b/readme.md @@ -1,42 +1,37 @@ # A tool for removing silences from a video -**This tool is made to just work!** - -However, at the moment, it's a quick-write. Please report bugs, if you found some. +GUI to remove silence in videos. ## Dependencies -- python3 -- ffmpeg -- ffprobe +- [python](https://www.python.org/downloads/) +- [ffmpeg](https://ffmpeg.org/download.html) +- [ffprobe](https://ffmpeg.org/download.html) -You need to have all of those installed. +Download and install them first. -**@Windows users**: -Make sure, that the path to `ffmpeg` and `ffprobe` are inside the "path variable". I.e. you can run both commands from the command line like `C:> ffmpeg`. +**Windows users**: +Make sure ffmpeg and ffprobe are in your environment path variables. The links above should have information on how to do that. ## How to use -- Easiest command:
-`python3 silence_cutter.py [your video]` +- Graphical user interface: `python silence_cutter_gui.py` + +## For command-line interface: -- Show **help** and suggestions:
-`python3 silence_cutter.py --help` +`python3` is typed in Linux; Windows users should use `python` instead. -- More Options:
-`python3 silence_cutter.py [your video] [outfile] [silence dB border]` +- Easiest command: `python3 silence_cutter.py [your video]` +- Show **help** and suggestions: `python3 silence_cutter.py --help` -## Bugs +- More Options: `python3 silence_cutter.py [your video] [outfile] [silence dB border]` -File them directly here on Github. I'll try to fix them as soon as possible. -## Comparison to other tools -As far as my reseach goes, all other tools suck: -- They don't work -- They have huge dependencies -- They have complex dependencies -- Their dependencies don't work +## Most other tools are: +- Unreliable +- Too complex +- Huge in size - They store each frame of the video as bitmap file
(how can you even think about something like that) From b3e9834a0ea512c15cf1343771b40f5d5b692743 Mon Sep 17 00:00:00 2001 From: sm18lr88 <64564447+sm18lr88@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:24:35 -0400 Subject: [PATCH 3/3] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0fa0c7d..4ea5d67 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,7 @@ GUI to remove silence in videos. Download and install them first. **Windows users**: -Make sure ffmpeg and ffprobe are in your environment path variables. The links above should have information on how to do that. +Make sure ffmpeg and ffprobe are in your environment path variables. The links above should have information on how to do that. You can also ask any AI agent to help you with that. ## How to use