Skip to content

Instantly share code, notes, and snippets.

@ezr
Last active December 23, 2021 07:42
Show Gist options
  • Save ezr/40b29a9b14a895c0da0d436ebd77cb7f to your computer and use it in GitHub Desktop.
Save ezr/40b29a9b14a895c0da0d436ebd77cb7f to your computer and use it in GitHub Desktop.
ffmpeg wrapper for cutting files
#!/usr/bin/env python3
import argparse
import os
import random
from re import fullmatch
from shutil import copyfile
from string import ascii_letters
import subprocess
import sys
def get_length(f):
cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", f]
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output, err = pipe.communicate()
if err is not None:
print("error with the ffprobe command:", err)
exit(2)
try:
return float(output)
except ValueError:
print("error with the ffprobe command: ffprobe output could not be converted to a float.")
exit(2)
except Exception as e:
print("error with the ffprobe command:", e)
exit(2)
def calculate_ffmpeg_seconds(cut, file_length):
cut = cut.replace("[", "").replace("]", "")
start_second, _, end_second = cut.partition(":")
start_second = int(start_second) % file_length if start_second != '' else 0
end_second = int(end_second) % file_length if end_second != '' else file_length
plus_seconds = end_second - start_second
if plus_seconds < 0:
print("Error: start time was greater than the end time")
exit(3)
return str(start_second), str(plus_seconds)
def tempName(f):
extension = f.split('.')[-1]
basename = ''.join(random.choice(ascii_letters) for i in range(10))
return basename + "." + extension
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="cut an audio file using python slice syntax",
epilog=f"example: {sys.argv[0]} [30:] speech.m4a speech-cut.m4a")
parser.add_argument('-i', '--in-place', dest='in_place', action='store_true', help="overwrite the input")
parser.set_defaults(in_place=False)
parser.add_argument("slice", nargs=1, help="[start:end] (in seconds)")
parser.add_argument("in_file", nargs=1, help="input file")
parser.add_argument("out_file", nargs="?", help="output file", default="DEFAULT")
args = parser.parse_args()
cut_seconds = args.slice[0]
in_file = args.in_file[0]
out_file = tempName(in_file) if args.out_file == "DEFAULT" else args.out_file
if not fullmatch('^(\[(-?[0-9])+\:(-?[0-9])*\])|(\[(-?[0-9])*\:(-?[0-9])+\])$', cut_seconds):
print("error: invalid time/slice argument.")
exit(1)
file_length = get_length(in_file)
start_second, plus_seconds = calculate_ffmpeg_seconds(cut_seconds, file_length)
command = ["ffmpeg", "-i", in_file, "-acodec", "copy", "-vcodec", "copy",
"-async", "1", "-ss", start_second, "-t", plus_seconds, out_file]
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, err = p.communicate()
if err is not None:
print("Error running ffmpeg:")
print(err)
if args.in_place:
os.remove(in_file)
os.rename(out_file, in_file)
@ezr
Copy link
Author

ezr commented Apr 14, 2019

ffmpeg and python3 must be installed. On my system ffprobe came with ffmpeg.

The idea is to cut files using python's syntax for slicing arrays.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment