Last active
December 23, 2021 07:42
-
-
Save ezr/40b29a9b14a895c0da0d436ebd77cb7f to your computer and use it in GitHub Desktop.
ffmpeg wrapper for cutting files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.