Bash script or function to rename mp3 files

168 views Asked by At

Want to batch rename mp3 files to following scheme my-artist_my-title.mp3

E.g.: Let's suppose that I have the mp3 file: of the song Underground‐Čoček, by Goran Bregović. But the file is named s3 24)3ü6 Dț67 .mp3 (for exaple, because it was lost on a drive and recovered with testdisk. Supposing the mp3 metadata is correct, the script should change the filename to: goran-bregovic_underground‐cocek.mp3

Ideally I would prefer to have a bash script which I would trigger with:

$ rename-mp3 directory-with-subdirectories-with-mp3-files

Searching for similar solutions I found this function. I modified it and it works, partially! The regex modifications, marked with #? are not working.

  function rename-mp3() {       # input is an mp3 file: i.e. find -name 's3  24)3ü6   Dț67  .mp3' -exec bash -c 'rename-mp3 "$@"' bash {} \;
                                # extract metadata from file
  artist=`ffprobe -loglevel error -show_entries format_tags=artist -of default=noprint_wrappers=1:nokey=1 "$1"`
  title=`ffprobe -loglevel error -show_entries format_tags=title -of default=noprint_wrappers=1:nokey=1 "$1"`
  artist="${artist/\&/}"        #? delete all non-numeral, non-latin, and non-space characters (&, %, !, ', ä, ö, ü, ă, ț, etc.)
  title="${title/\&/}"          #? delete all non-numeral, non-latin, and non-space characters (&, %, !, ', ä, ö, ü, ă, ț, etc.)
  artist="${artist// +/\-}"     #? replace all spaces with "-", if more then one in sequence substitute only one "-"
  title="${artist// +/\-}"      #? replace all spaces with "-", if more then one in sequence substitute only one "-"
  filename="$artist_$title.mp3" # paste artist and title together
  filename="${name,,}"          # lowercase everything
  echo "$filename"              # display new filename
  cp "$1" "renamed/$name"       # copy renamed file to the renamed folder
}
1

There are 1 answers

0
Arnaud Valmary On

I'm using a similar script (but really more complicated) to sort all my audio files.

Based on your script:

#! /usr/bin/env bash

declare -r input_filename="$1"
declare -r output_dirname="$2"

function rationalize() {
    local s="$1"
    # extglob option is necessary for pattern matching in bash expansions
    shopt -s extglob
    # delete all non-ascii characters
    s="${s//[^[:ascii:]]/}"
    # keep only all alpha, numeral and space characters
    s="${s//[^[:alnum:]|[:space:]]/}"
    # replace all spaces with "-", if more then one in sequence substitute only one "-"
    s="${s//+([[:space:]])/-}"
    shopt -u extglob
    printf "%s" "$s"
}

function get_tag() {
    local -r tag="$1"
    local -r filename="$2"
    local value=$(ffprobe -loglevel error -show_entries format_tags="$tag" -of default=noprint_wrappers=1:nokey=1 "$filename")
    value=$(rationalize "$value")
    printf "%s" "$value"
}

function copy_audiofile() {
    local -r from_filname="$1"
    local -r to_dir="$2"
    # get filename extension
    local -r ext="${from_filname##*.}"
    # get artist for file
    local artist=$(get_tag "artist" "$from_filname")
    # get title for file
    local title=$( get_tag "title" "$from_filname")
    # paste artist and title together
    local filename_to="${artist}_$title.$ext"
    # lowercase everything
    filename_to="${filename_to,,}"
    # display new from_filname
    echo "Rename '$from_filname' to '$filename_to'"
    # copy renamed file to the renamed folder
    cp "$1" "$to_dir/$filename_to"
}

copy_audiofile "$input_filename" "$output_dirname"