Skip to content

Instantly share code, notes, and snippets.

@danstowell
Last active August 6, 2024 10:18
Show Gist options
  • Save danstowell/84eff5456ce6b3c4d1c82f29de374790 to your computer and use it in GitHub Desktop.
Save danstowell/84eff5456ce6b3c4d1c82f29de374790 to your computer and use it in GitHub Desktop.
Python script to enforce a maximum duration on a set of audio files. Long files are trimmed, without altering the sample data. The script can either convert all to FLAC, or preserve exact container type for each file.
#!/bin/env python
# Script to enforce a maximum duration on a set of audio files.
# Long files are trimmed, without altering their file format.
# Uses ffmpeg. (So, that needs to be installed on your system).
# Tested in Ubuntu Linux v22.04.
# Written by Dan Stowell 2024.
# CC0: This work has been marked as dedicated to the public domain.
import os, glob, subprocess
###################################################
# User config variables:
indir = "wavs_original"
outdir = "wavs_trimmed"
maxdur = 120 # measured in seconds
verbose = True
convert_format = True # whether to convert all to FLAC (should achieve smaller filesize without data loss)
###################################################
totalin = 0
totalout = 0
for inpath in sorted(glob.glob(os.path.join(indir, "*.*"))):
filename = os.path.basename(inpath)
outpath = os.path.join(outdir, filename)
if convert_format:
acodec = 'flac'
outpath = os.path.splitext(outpath)[0] + ".flac"
else:
acodec = 'copy'
totalin += 1
if verbose:
print("======================")
print(f"File {filename}:")
# First calculate the duration
cmd = ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", inpath]
try:
result = subprocess.run(cmd, capture_output=True, check=True, text=True)
#print(result)
filedur = float(result.stdout)
except Exception:
print(f"WARNING: Unable to read duration of input file: {filename}")
if verbose:
print(result.stdout)
print(result.stderr)
continue
# This is the main command. We will add more arguments.
cmd = ["ffmpeg", "-loglevel", "quiet", "-y",
"-i", inpath, "-acodec", acodec]
if filedur <= maxdur:
# Note that despite "no trim needed", we still use ffmpeg to copy it,
# to ensure the file's container is readable,
# i.e. all output files will surely be readable at least by ffmpeg.
if verbose:
print(f"File will be kept full length: {filename}, full dur {filedur}")
pass
else:
if filedur <= maxdur * 3:
# choosing the middle segment
starttime = (filedur - maxdur) / 2
else:
# choosing the segment [maxdur, maxdur * 2]
starttime = maxdur
if verbose:
print(f"File will be trimmed: {filename}, full dur {filedur}, start will be {starttime}")
cmd += ["-ss", str(starttime), "-t", str(maxdur)]
cmd += [outpath] # the command is finally completed, with the output path
if verbose:
print(cmd)
print(" ".join(cmd))
try:
result = subprocess.run(cmd, capture_output=True, check=True, text=True)
except Exception:
print(f"WARNING: Error creating edited file for: '{filename}'")
if verbose:
print(result.stdout)
print(result.stderr)
continue
totalout += 1
print(f"Finished. Converted {totalout} out of {totalin} files.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment