updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / flac2mp3-bash / flac2mp3.sh
blobea6261b87eb51a0ab3b98e4d7ea828240586c836
1 #! /bin/bash
3 # Identification of the script
4 name="flac2mp3"
5 author="Rechosen"
6 version="1.0"
8 # The help variables
9 shorthelp='Usage: '"$(basename "${0}")"' [-b bitrate] [-d dirstoretain] [-l lameopts]
10 [-o outputdirectory] [-r] FILES'
11 longhelp='This script uses the tools flac, metaflac and lame to convert flac files to
12 mp3s. Accepts both individual files and directories (the latter when using the
13 -r option).
15 Explanation of the options:
16 -b bitrate Specifies the bitrate of the converted mp3. Defaults to
17 128. Specify a bitrate of "none" to stop the -b option
18 from being passed to lame.
19 -d dirstoretain Specifies how many directory names to retain when using
20 both -r and -o. Works from right to left. See the -r
21 option for an example.
22 -l lameopts Allows to give custom options to lame. Make sure to
23 surround them with quotes (e.g. -l "-V 6")!
24 -o outputdirectory Specifies the directory to write the mp3s to. If not
25 specified, the mp3s will be written to the directory
26 where the flac files are located.
27 -r Makes the script look for flac files recursively. If
28 this option is specified together with an alternative
29 output directory, the mp3s will be written to the
30 specified output directory plus the current relative
31 path of the flac file. Example:
32 "After Edmund/Hello/01_Thank_God.flac"
33 will be converted to
34 "<outputdirectory>/After Edmund/Hello/01_Thank_God.mp3."
36 ATTENTION: When using full paths (like
37 /home/user/music/After Edmund/Hello/01_Thank_God.flac),
38 you can determine how many directories the script will
39 retain using the -d option. With -d 2, the full path
40 file just above will be converted to:
41 "<outputdirectory>/After Edmund/Hello/01_Thank_God.mp3."
43 -s Do not use this option unless you know what you are
44 doing! It is used internally to self-execute the
45 script for conversion.
46 -v Be verbose; makes the script tell what it is doing.
48 For more information see http://www.linuxtutorialblog.com/.
49 No warranty included with this script ;-) Rechosen'
51 # Is the user asking for extensive help?
52 if [[ "$*" == *--help* ]]; then
53 echo -e "$shorthelp""\n""$longhelp"
54 exit
57 # Specify the default variable values
58 bitrate="128"
59 dirstoretain=""
60 lameopts=""
61 outputdir=""
62 recursive="-maxdepth 0"
63 selfexecute="false"
64 optionstopass=( )
65 lameoptsarray=( )
66 verbose=""
68 # Functions for input validation
69 function IsNum() {
70 if [[ "$1" == *[^0-9]* && "$1" != "none" ]]; then
71 echo -e "-$options has to be numeric!\n""$shorthelp"
72 exit 1
76 # Get the passed options
77 i=0
78 while getopts ":b:d:l:o:rsv" options; do
79 optionstopass[$i]=-"$options"
80 (( i++ ))
81 if [ "$OPTARG" ]; then
82 optionstopass[$i]="$OPTARG"
83 (( i++ ))
85 case $options in
86 b) IsNum "$OPTARG" && bitrate="$OPTARG";;
87 d) IsNum "$OPTARG" && dirstoretain="$OPTARG";;
88 l) lameopts="$OPTARG";;
89 o) outputdir="$OPTARG";;
90 r) recursive="";;
91 s) selfexecute="true";;
92 v) verbose="true";;
93 ?) echo $shorthelp; exit 2;;
94 esac
95 done
97 # Remove parsed options
98 shift $(($OPTIND - 1))
100 [ "$verbose" ] && echo "Options parsed. Left on the command-line: ""$*"
102 # Do we have any files to convert? If not, show usage.
103 if [ -z "$*" ]; then
104 echo -e "No files to convert!\n""$shorthelp"; exit 2
107 # For drag&drop support: we haven't accidentally got a non-supported URL, do we?
108 [ "$verbose" ] && echo "Checking for unsupported URLs..."
109 cmdline=( "$@" )
110 # Attention: from now on, only ${cmdline[@]} is safe to use to get the files!
111 for (( i=0; i<${#cmdline[@]}; i++ )); do
112 [ "$verbose" ] && echo "Removing any \"file://\" prefixes..."
113 cmdline[$i]=${cmdline[$i]#"file://"}
114 if [[ "${cmdline[@]}" =~ "^.{1,7}\://" ]]; then
115 echo "Sorry, $(basename "$0") only supports local files."
116 exit 1
118 done
120 # Make sure $outputdir has an ending "/"
121 if [ -n "$outputdir" -a "${outputdir:(-1)}" != "/" ]; then
122 outputdir=$outputdir"/"
123 [ "$verbose" ] && echo "Added a trailing \"/\" to \$outputdir."
127 # Are we user-called or self-executing?
128 if [ "$selfexecute" == "false" ]; then
129 # Introduce ourselves
130 echo "Thanks for using $name $version! This script by $author."
132 # Find all flac files and re-execute the script once for every file to
133 # convert them.
134 [ "$verbose" ] && echo "Using find to get the flac files and re-executing the script for each of them."
135 find "${cmdline[@]}" $recursive -print0 | grep -zZ -i -E .+\.flac$ |\
136 xargs -i -0 "$0" "${optionstopass[@]}" -s {}
137 else
138 # Start an actual conversion; get the file to convert
139 [ "$verbose" ] && echo "Getting file to convert..."
140 file="$@" # "$@" is safe to use again because of self-execution
141 [ "$verbose" ] && echo "File: ""$file"
142 # Remove any lame-looking "./" in front of the filename
143 if [ "${file:0:2}" == "./" ]; then
144 file="${file:2}"
145 [ "$verbose" ] && echo "Removed \"./\" from the filename."
148 # Get the tags
149 [ "$verbose" ] && echo "Getting the tags..."
151 for tag in {"title","artist","album","tracknumber","date","genre","comment"}; do
152 info[$i]=$(metaflac --show-tag=$tag "$file")
153 info[$i]=${info[$i]#*=}
154 [ "$verbose" ] && echo "Got $tag tag: ""${info[$i]}"
155 (( i++ ))
156 done
158 # Convert the tags to options for lame
159 [ "$verbose" ] && echo "Converting tags to lame options..."
161 for option in {"t","a","l","n","y","g","c"}; do
162 if [ "${info[$((i/2))]}" ]; then
163 command[$i]=--t$option
164 command[$((i+1))]="${info[$((i/2))]}"
165 if [ "$option" == "c" ]; then
166 command[$((i+1))]=${command[$((i+1))]:0:30}
167 elif [ "$option" == "y" ]; then
168 command[$((i+1))]=${command[$((i+1))]:0:4}
169 elif [ "$option" == "g" ]; then
170 if ! lame --genre-list 2>&1 | grep "${command[$((i+1))]}" >/dev/null; then
171 command[$((i+1))]=""
172 [ "$verbose" ] && echo "Nullified the genre tag as the specified genre does not exist."
176 i=$(($i+2))
177 done
178 [ "$verbose" ] && echo "Lame options: ""${command[@]}"
180 # Prepare the outputfile variable
181 [ "$verbose" ] && echo "Preparing \$outputfile..."
182 basefile=$(basename "$file")
183 if [ -z "$outputdir" -o -z "$recursive" ]; then
184 # We're going to extend the outputdir using the source dir(s)
185 # Checking if we need to limit the amount of source dirs retained...
186 if [ -n "$dirstoretain" ]; then
187 retaineddirs=""
188 filedir=$(dirname "$file")
190 while [ $i -lt $dirstoretain -a -n "$filedir" ]; do
191 dirtoretain=`expr "$filedir" : '.*\(/[^/]\+\)'`
192 filedir=${filedir%$dirtoretain}
193 dirtoretain=${dirtoretain:1}"/"
194 retaineddirs="$dirtoretain""$retaineddirs"
195 (( i++ ))
196 done
197 outputfile="$outputdir""$retaineddirs""${basefile/.[fF][lL][aA][cC]/.mp3}"
198 else
199 # Just throw in all dirs
200 outputfile="$outputdir""${file/.[fF][lL][aA][cC]/.mp3}"
202 else
203 outputfile="$outputdir""${basefile/.[fF][lL][aA][cC]/.mp3}"
205 [ "$verbose" ] && echo "\$outputfile is ""$outputfile"". Creating directories if needed..."
206 mkdir -p "$(dirname "$outputfile")"
208 # Prepare the bitrate
209 [ "$verbose" ] && echo "Preparing bitrate..."
210 if [ -n "$bitrate" -a "$bitrate" != "none" ]; then
211 bitratearray=( "-b" "$bitrate" )
214 # Make the lameopts usable
215 [ "$verbose" ] && echo "Making \$lameopts usable."
217 for l in $lameopts; do
218 lameoptsarray[$i]="$l"
219 (( i++ ))
220 done
222 # Actual conversion coming up...
223 [ "$verbose" ] && echo "Preparing progress indicator..."
224 # Now for the great trick... a progress indicator!
225 flacsize=$(stat -c %s "$file")
226 blocksize=$(( flacsize / 100 ))
227 if [ $blocksize -le 0 ]; then
228 blocksize=1
230 ddcount=$(( $blocksize / 512 ))
231 if [ $blocksize -le 0 ]; then
232 ddcount=1
234 donesofar=0
235 percent=0
236 start=$(date +%s)
237 echo -n "Converting $file to $outputfile..."
238 printf "%4s%%" 0
239 printf " Time left: %02d:%02d" 0 0
240 cat "$file" | (
241 while [ $donesofar -lt $flacsize ]; do
242 dd bs=512 count=$ddcount 2>/dev/null
243 (( donesofar += $blocksize ))
245 percent=$(( 100 * $donesofar / $flacsize ))
246 echo -n -e "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" 1>&2
247 printf "%4s%%" $percent 1>&2
249 # Calculate the estimated time left
250 timeelapsed=$(( $(date +%s) - $start ))
251 if [ $timeelapsed -gt 0 ]; then
252 bytespersec=$(( $donesofar / $timeelapsed ))
253 totaltimeest=$(( $flacsize / $bytespersec + 2 )) # "+ 2" is a correction because flac and lame need to finish up
254 timeleft=$(( $totaltimeest - $timeelapsed ))
255 timeleftmin=$(( $timeleft / 60 ))
256 timeleftsec=$(( $timeleft % 60 ))
257 printf " Time left: %02d:%02d" $timeleftmin $timeleftsec 1>&2
258 else
259 printf " Time left: %02d:%02d" 0 0 1>&2
261 done
262 ) | flac -cds - |\
263 lame -hS "${bitratearray[@]}" "${lameoptsarray[@]}" "${command[@]}" - "$outputfile"
264 echo -e "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b Done. "