Search code examples
linuxbashfile-renamebatch-rename

Bash script to mass rename mp3s?


I have a music library of mp3s (with correct metadata) organized like so: Music/{artists}/{album}/{title}

For example: Music/Green Day/American Idiot/<songs in the album>

Each mp3 is named like so: {title} {artists} {album}.mp3

For example: Jesus of Suburbia Green Day American Idiot.mp3

Keeping the same directory structure, I would like to rename each file so that it is titled like so: {title} - {artists} - {album}.mp3

For example Jesus of Suburbia Green Day American Idiot.mp3 --> Jesus of Suburbia - Green Day - American Idiot.mp3

I was hoping someone would know of a script that could do this?

Thanks for the help.

P.S.

Songs that have multiple artists are organized somewhat differently

For example, in the music library we have both

Music/Fall Out Boy/Save Rock And Roll/<most of the songs in the album>

and

Music/Fall Out Boy,Elton John/Save Rock And Roll/Save Rock And Roll Fall Out Boy,Elton John Save Rock And Roll.mp3

This one isn't the best example, as it may be confusing because that song shares the same name as the album, which is why it appears twice in the mp3's name.

EDIT: Based on your search suggestions, I was able to find a command:

ffprobe -loglevel error -show_entries format_tags=title,artist,album -of default=noprint_wrappers=1:nokey=1 file.mp3

Which can extract the metadata attributes that I need. I'm not sure how to apply this to be able to rename files though...


Solution

  • Based on your research, you can get title/artist/album from mp3 file by executing: ffprobe -loglevel error -show_entries format_tags=title -of default=noprint_wrappers=1:nokey=1 mymp3.mp3

    So we just need to make a function to build mp3 name by concatenating those strings:

    function mp3name() {
      local title="$(ffprobe -loglevel error -show_entries format_tags=title -of default=noprint_wrappers=1:nokey=1 "$1")"
      local artist="$(ffprobe -loglevel error -show_entries format_tags=artist -of default=noprint_wrappers=1:nokey=1 "$1")"
      local album="$(ffprobe -loglevel error -show_entries format_tags=album -of default=noprint_wrappers=1:nokey=1 "$1")"
      mkdir -p "$artist/$album"
      local name="$artist/$album/$title - $artist - $album.mp3"
      echo "$name"
      mv "$1" "$name"
    }
    

    Then we can use find and it's exec argument to execute above function on mp3's

    export -f mp3name
    find -name '*.mp3' -exec bash -c 'mp3name "$@"' bash {} \;
    

    Example mp3 file can be taken from: https://file-examples.com/index.php/sample-audio-files/sample-mp3-download/

    Result:

    $ ls
    'Impact Moderato - Kevin MacLeod - YouTube Audio Library.mp3'