Search code examples
bashaudioffmpegflacalbumart

Bash: FFmpeg: Automate Album Art Tagging


Every one of my music folders are set up like Artist > Year Album >

Track 01.flac
Track 02.flac
Track 03.flac
folder.jpg, jpeg, png, etc

And what I need to do is if folder.* is available.

if [ -f folder.* ]; then

Run this command to set smaller size without replacing the original photo.

for small in folder.*
convert $small -resize 1000x1000 temp$small

Then run these commands on every file to automatically add the smaller sized cover to each audio file's tagging.

ffmpeg -i TRACK.flac -i SMALLFOLDER.* -map a -map 1:v -disposition:v attached_pic -metadata:s:v comment="Cover (Front)" -codec copy TRACKWITHART.flac
&& rm TRACK.flac
&& mv TRACKWITHART.flac TRACK.flac
&& rm temp$small

Last little bit there is me cleaning up. I'm having trouble piping commands into one another with this and not the most experienced with that sort of thing.

And also, if it's not available like above, will need to extract it from the first audio file by finding it.

else
find . -name "*.flac" -print -quit 

And extracting it with this command.

ffmpeg -i TRACK.flac -vf scale=1000:1000 -an FOLDER.png

Then run the other commands above.

Now I don't know if anyone is familiar with FFmpeg but it's actually kind of nightmare because it's not necessarily for audio tagging but I don't know anything else to handle this kind of automated album art task in the terminal. If anyone can point me more in the right direction with a better CLI utility, that'd be awesome or just help with this bash scripting. You can see I'm fairly familiar with the terminal and getting some things done by searching the web but putting them altogether in a bash script is very difficult for me to understand, if anyone has some links for specifically this, that would be much appreciated.


Solution

  • You have the general right idea of how to do it.

    The wooledge BashGuide is pretty much the best place to start when learning bash scripting. It's very accessible, and it directly addresses a lot of the pitfalls that beginners are susceptible to when writing scripts.

    ALWAYS quote your variables when you are using them to store filenames/paths. You need to write your script as if every path/filename will have spaces, newlines, special characters, etc. Quoting your variables will go a long way towards preventing any chaos when your script runs.

    Here is your code fixed up and thrown together into a working script:

    #!/bin/bash
    
        # check for album art file, 
        # if none, extract from first flac w/ ffmpeg
        # exit script if ffmpeg fails
    [[ -f folder.* ]] || 
      { tracks=(*.flac)
        ffmpeg -i "${tracks[0]}" -vf scale=1000:1000 -an folder.png \
          || exit 1 ; }
    
        # define an array of all folder.* files
    albumart=(folder.*)
    
    ffmpeg -i "${albumart[0]}" -vf scale=1000:1000 "tmp_${albumart[0]}" \
      || exit 1
        # use the first element of the array, 
        # in case there are multiple folder.* files.
        # exit if ffmpeg gives error code
    
    for track in *.flac; do
      ffmpeg -i "$track" -i "tmp_${albumart[0]}" -map a -map 1:v -disposition:v attached_pic -metadata:s:v comment="Cover (Front)" -codec copy "tmp_${track}" \
        && rm "$track" \
        && mv "tmp_${track}" "$track"
    done
    
    rm "tmp_${albumart[0]}"
    

    I took the liberty of changing your convert line of image-resizing code so that it is instead handled by ffmpeg, since I am unfamiliar with "convert". If it is a script or binary you use, you will want to edit this line (keeping the new input & output variables intact).

    This script does not need any arguments, and it will loop through and add the album art & metadata to all .flac files in your current directory. It is not designed to work recursively; you will need to cd into & run the script in each directory.