A majority of my music collection is in ogg/vorbis format and although my iPod has been modified to make use of the open RockBox firmware which can play oggs, there are time when I need a particular set of ogg files in mp3 format for one purpose or another. I looked at using tools such as gStreamer, however its id3mux plug-in writes ID3 tags in the 2.4 format which is not widely supported.

I decided to write a custom bash script which recursively transverses a directory structure, recreates the directory structure in a new location and converts all the ogg files it finds along the way into mp3s using the ffmpeg encoder and the id3tag command from the id3lib library.

The convert() and copyTag() functions can be modified to support different encoders (e.g. lame) and tagging programs.

#!/bin/bash
#
#  oggfolder2mp3.sh - Script to convert Ogg folders to Mp3
#
#   Requires: ffmpeg, id3lib
#
#   Sumit Khanna - http://penguindreams.org
#
#   Free for noncomercial use
#
#

usage() {
  echo -e "\nmp3folder2ogg.sh - recursively converts a folder of oggs to mp3s\n"
  echo -e "\tmp3folder2ogg.sh <ogg folder to convert> <destination> <mp3 bitrate in kbps>\n"
  echo -e "\t\tThe name of the source folder and its directory structure"
  echo -e "\t\tare recreated in the destination\n"
  exit 1
}

# -Copies tags from an ogg to an mp3
#  $1 - Ogg file to read tags from
#  $2 - mp3 file to copy tags to
copyTags() {

  while read line; do
    value=${line#*=}
    key=${line%=*}
    a="tag_${key,,}"
    read $a <<< $value;
  done < <(vorbiscomment -l "$1")

  id3tag "--artist=$tag_artist" "--album=$tag_album" "--song=$tag_title" \
         "--year=$tag_date" "--track=$tag_tracknumber" \
         "--comment=$tag_comment" "--genre=$tag_genre" "$2"
}

# -Converts ogg to mp3 using ffmpeg
#  $1 - source ogg
#  $2 - destination mp3
#  $3 - bitrate in k/bps (e.g. 128, 256, etc)
convert() {
  #convert k/bps to bps for ffmpeg
  bitrate=$(($3 * 1000));
  ffmpeg -i "$1" -ab "$bitrate" "$2"
}

# -Recursively scans a directory, replicates the
#  structure and converts all oggs to mp3s
#  $1 - Full path of current directory to scan
#  $2 - Construction of new mp3 absolute path
#  $3 - Basename of current directory (for path construction)
#  $4 - bitrate in kbps
scanDir() {
  mkdir "$2/$3";
  for a in "$1"/*; do
    if [ -d "$a" ]; then
      scanDir "$a" "$2/$3" "$(basename "$a")" "$4"
    else
        case ${a##*.} in ogg|OGG)
         newfile="$(basename "$a")"
         newfile="${newfile%.*}.mp3"
         echo "converting $(basename "$a")"
         ogg="$a"
         mp3="$2/$3/$newfile"
         convert "$ogg" "$mp3" "$4"
         copyTags "$ogg" "$mp3"
        esac
    fi
  done
}

# -Entry Point
if [[ -d "$1" && -d "$2" && "$3" -gt 0 ]]; then
  base=$(basename "$1")
  scanDir "$1" "$2" "$base" "$3"
else
  usage
fi