Here's a Python script I quickly hacked together to solve the original problem: keep a compressed copy of a music library. The script will convert .m4a files (assumed to be ALAC) to AAC format, unless the AAC file already exists and is newer than the ALAC file. MP3 files in the library will be linked, since they are already compressed.
Just beware that aborting the script (ctrl-c) will leave behind a half-converted file.
I originally also wanted to write a Makefile to handle this, but since it cannot handle spaces in filenames (see the accepted answer) and because writing a bash script is guaranteed to put in me in a world of pain, Python it is. It's fairly straightforward and short, and thus should be easy to tweak to your needs.
from __future__ import print_function
import glob
import os
import subprocess
UNCOMPRESSED_DIR = 'Music'
COMPRESSED = 'compressed_'
UNCOMPRESSED_EXTS = ('m4a', ) # files to convert to lossy format
LINK_EXTS = ('mp3', ) # files to link instead of convert
for root, dirs, files in os.walk(UNCOMPRESSED_DIR):
out_root = COMPRESSED + root
if not os.path.exists(out_root):
os.mkdir(out_root)
for file in files:
file_path = os.path.join(root, file)
file_root, ext = os.path.splitext(file_path)
if ext[1:] in LINK_EXTS:
if not os.path.exists(COMPRESSED + file_path):
print('Linking {}'.format(file_path))
link_source = os.path.relpath(file_path, out_root)
os.symlink(link_source, COMPRESSED + file_path)
continue
if ext[1:] not in UNCOMPRESSED_EXTS:
print('Skipping {}'.format(file_path))
continue
out_file_path = COMPRESSED + file_path
if (os.path.exists(out_file_path)
and os.path.getctime(out_file_path) > os.path.getctime(file_path)):
print('Up to date: {}'.format(file_path))
continue
print('Converting {}'.format(file_path))
subprocess.call(['ffmpeg', '-y', '-i', file_path,
'-c:a', 'libfdk_aac', '-vbr', '4',
out_file_path])
Of course, this can be enhanced to perform the encoding in parallel. That is left as an exercise to the reader ;-)
make
is closer to implementing it than barebash
. – Orthochromaticsh
script that walks through the list of flac files (find | while read flacname
), makes amp3name
from that, runs "mkdir -p" on thedirname "$mp3name"
, and then,if [ "$flacfile" -nt "$mp3file"]
converts"$flacname"
into"$mp3name"
is not really magic. The only feature you are actually losing compared to amake
based solution is the possibility to runN
file conversions processes in parallel withmake -jN
. – Crosshatchmake
's declarative approach is nicer than any imperative language could ever offer. – Crosshatchmake
and having spaces in file names are contradictory requirements. Use a tool appropriate for the problem domain. – Jaan