A small shell script to grab audio from a CD and encode/compress it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

497 lines
14 KiB

#!/bin/bash
# === some global setting & configurations for the script ===
umask 000 # create files with all right for anyone
shopt -s nullglob # expand patterns which match no file to a null string
shopt -s extdebug
function atExit
{
echo -en "\033[?25h" # show cursor
}
trap atExit EXIT
# --------------------------------------------------------------
# das Verzeichnis in dem dieses script liegt herausfinden
scriptDir=${0%/*}
scriptDir="${scriptDir/#\./${PWD}}"
case "${scriptDir}" in /*);; *) scriptDir="${PWD}/${scriptDir}";; esac
# --------------------------------------------------------------
# include helpers
. ${scriptDir}/shellUtils.sh
# --------------------------------------------------------------
# string definitions
enhUsage=$"usage: $0 [-t(m|f|o|w)] [-p path] [-e encoder] [-c cddbitem] [-h]
[-I interface] [-D device] [-v[v|0]] [-q] [-s]
[--help] [--encoding=(m|f|o|w)] [--encoder=(lame|bladeenc)]
[--path=<string>] [--interface=(cooked_ioctl|generic_scsi)]
[--device=<string>]
options:
-h | --help: gives this help
-v: set verbosity level.
-v0 disable all output
-v be more verbose
-vv enables debug
-q: make the script silent. Equivalent to -v0
-t | --encoding: you can specify either m for encoding to mp3
using lame, or f for making lossless encoding using flac,
or o for making ogg/vorbis, or w for uncompressed wav.
Omitting this results in encoding to flac.
mp3s will be placed under a subfolder mp3 and flacs
under a subfolder flac
-p | --path: specifies the path to save the encoded data.
Defaults to the users home directory.
-e | --encoder: specifies the mp3 encoder to use.
valid encoders are actually: lame,bladeenc
Defaults to lame.
-c: specifies the CDDB-Entry to use.
sometimes there is more than 1 entry for a cd in cddb.
Then you can specify wich one to use by this option.
You can checkout all entries using cddb.pl.
-I | --interface: specifies cdda2wav interface to use.
Valid interfaces are generic_scsi and cooked_ioctl.
Please note that cooked_ioctl is not available on all
systems. Defaults to cooked_ioctl if device begins with
/dev else to generic_scsi
-D | --device: specifies device to use with cdda2wav. All values that
are valid for cdda2wav are valid here.
Defaults to /dev/cdrom
-s: if set indicates that this disk contains various artists
(is a sampler). In this case the artist is written in the
title information of cddb most likely. Giving this option
the script will show a title list and give the oppotunity
to enter a delimiting string so that title and artist
information can be split properly and fill the mp3id
or whatever correctly.
This script uses cdda2wav, cddb and can use various encoders to rip
an audio CD."
usage=$"usage: $0 [-t(m|f|o|w)] [-p path] [-e encoder] [-c cddbitem] [-h]
[-I interface] [-D device] [-v[v|0]] [-q] [-s]
options:
-h: this help
-v: set verbosity level.
-v0 disable all output
-v be more verbose
-vv enables debug
-q: make the script silent. Equivalent to -v0
-t: you can specify either m for encoding to mp3
using lame, or f for making lossless encoding using flac,
or o for making ogg/vorbis, or w for uncompressed wav.
Omitting this results in encoding to flac.
mp3s will be placed under a subfolder mp3 and flacs
under a subfolder flac
-p: specifies the path to save the encoded data.
Defaults to the users home directory.
-e: specifies the mp3 encoder to use.
valid encoders are actually: lame,bladeenc
Defaults to lame.
-c: specifies the CDDB-Entry to use.
sometimes there is more than 1 entry for a cd in cddb.
Then you can specify wich one to use by this option.
You can checkout all entries using cddb.pl.
-I: specifies cdda2wav interface to use.
Valid interfaces are generic_scsi and cooked_ioctl.
Please note that cooked_ioctl is not available on all
systems. Defaults to cooked_ioctl if device begins with
/dev else to generic_scsi
-D: specifies device to use with cdda2wav. All values that
are valid for cdda2wav are valid here.
Defaults to /dev/cdrom
-s: if set indicates that this disk contains various artists
(is a sampler). In this case the artist is written in the
title information of cddb most likely. Giving this option
the script will show a title list and give the oppotunity
to enter a delimiting string so that title and artist
information can be split properly and fill the mp3id
or whatever correctly.
This script uses cdda2wav, cddb and can use various encoders to rip
an audio CD."
ready=$"done"
# level 1 messages
getCDInfoMsg=$"getting cd info..."
outputDirMsg=$"output to: \$encodingDir"
createXmlMsg=$"create xml file..."
startRipMsg1=$"start ripping cd audio data..."
# level 2 messages
encodeMp3Msg=$"Encode to mp3"
encodeFlacMsg=$"Encode to flac"
encodeOggMsg=$"Encode to ogg"
encodeWavMsg=$"Encode to wav"
startRipMsg2=$"start ripping cd audio data:"
cdInfoMsg=$"DISK:
=====
Tracks: \$dTracks
Length: \$dLength
Index: \$dIndex
Artist: \$dArtist
Title: \$dTitle
Year: \$dYear
Genre: \$dGenre
CDDB: \$cddbId
Text: \$dText
Extra: \$dExtra
TRACKS:
======="
# --------------------------------------------------------------
# --------------------------------------------------------------
# Optionen auswerten (im Moment nur angabe einer alternativen
# Konfigurationsdatei, und vebose). Vorher default-werte setzen.
# Irgendwie hab ich noch Probleme mit -? das scheint nicht zu funzen.
$GETOPT -T >/dev/null 2>&1
if [ $? -eq 4 ]
then
# enhanced getopt
usage="${enhUsage}"
TEMP="`$GETOPT -o "?hsv::qt:p:e:c:I:D:" -l "help,encoding:,encoder:,path:,interface:,device:" -- "$@"`"
else
# old getopt
TEMP="`$GETOPT "?hsv::qt:p:e:c:I:D:" "$@"`"
fi
test $? -ne 0 && { echo -e "${usage}"; exit 1; } # on error
eval set -- "$TEMP" # set $1,$2,...
taOrder="t"
encodingDir=$HOME
encodingType="f"
encoder="lame"
cddbEntry=""
cddaIf=""
cddaDev="/dev/cdrom"
verbose=1
sampler="no"
while true
do
case "$1" in
--)
shift; break;;
-v)
# v has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
if [ -z "$2" ]
then
verbose=2
else
case "$2" in
v) verbose=3; shift 2;;
*) verbose="$2"; shift 2;;
esac
fi
shift 2
;;
-q)
verbose=0
shift
;;
-t|--encoding)
if [ "$2" != "m" -a "$2" != "f" -a \
"$2" != "o" -a "$2" != "w" ]
then
echo -e "$usage"
exit 1
fi
encodingType=$2
shift 2
;;
-p|--path)
if [ ! \( -d $2 \) ]
then
echo -e "$usage"
exit 1
fi
encodingDir=$2
shift 2
;;
-e|--encoder)
if [ -z $2 ]
then
echo -e "$usage"
exit 1
fi
encoder=$2
shift 2
;;
-c)
if [ "$2" -ge 1 ] 2>/dev/null
then
cddbEntry="$2"
cddbEntry=$((cddbEntry-1))
shift 2
else
echo -e "$usage"
exit 1
fi
;;
-I)
if [ "$2" != "generic_scsi" -a \
"$2" != "cooked_ioctl" ]
then
echo -e "$usage"
exit 1
fi
cddaIf=$2
shift 2
;;
-D)
if [ "x" == "x$2" ]
then
echo -e "$usage"
exit 1
fi
cddaDev=$2
shift 2
;;
-s)
sampler="yes"
shift
;;
-h|--help|*)
echo "${usage}"
exit 1
;;
esac
done
# --------------------------------------------------------------
if [ -z "${cddaIf}" ]
then
test "${cddaDev%/*}" = "/dev" &&\
cddaIf="cooked_ioctl" ||\
cddaIf="generic_scsi"
fi
# ----------------------------------------------------------------
# ----------------------------------------------------------------
# set encodingDir for used encodingType
case ${encodingType} in
m)
encodingDir="$encodingDir/mp3"
test ${verbose} -ge 2 && echo ${encodeMp3Msg}
;;
f)
encodingDir="$encodingDir/flac"
test ${verbose} -ge 2 && echo ${encodeFlacMsg}
;;
o)
encodingDir="$encodingDir/ogg"
test ${verbose} -ge 2 && echo ${encodeOggMsg}
;;
w)
encodingDir="$encodingDir/wav"
test ${verbose} -ge 2 && echo ${encodeWavMsg}
;;
esac
# ----------------------------------------------------------------
test ${verbose} -ge 1 && echo -n ${getCDInfoMsg}
# gets all info about the CD. Look in shellUtils for more info.
getCDInfo "$sampler" "$cddbEntry"
test ${verbose} -ge 1 && echo ${ready}
if [ ${verbose} -ge 2 ]
then
eval "cdInfo=\"$cdInfoMsg\""
cat <<-EOF
$cdInfo
EOF
i=0
while [ $i -lt ${#tTitle[@]} ]
do
echo -n "${tArtist[$i]} - ${tTitle[$i]} "
echo "([${tStartSec[$i]}-${tEndSec[$i]}] ${tLength[$i]})"
i=$((i+1))
done
fi
encodingDir="${encodingDir}/${dArtist}/${dTitle}"
mkdir -p "${encodingDir}"
test ${verbose} -ge 1 && eval "echo ${outputDirMsg}"
# ----------------------------------------------------------------
# fill xml file with data
test ${verbose} -ge 1 && echo -n "${createXmlMsg}"
xmlFile="${encodingDir}/cdinfo.xml"
xml_dText="`echo "${dText}" | recode utf8..h0`"
xml_dExtra="`echo "${dExtra}" | recode utf8..h0`"
xml_dArtist="`echo "${dArtist}" | recode utf8..h0`"
xml_dTitle="`echo "${dTitle}" | recode utf8..h0`"
cat >"${xmlFile}" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cdInfo SYSTEM \"cdInfo.dtd\">
<cdinfo>
<cdindex>${dIndex}</cdindex>
<cddb>${cddbId}</cddb>
<cd-text>${xml_dText}</cd-text>
<cd-extra>${xml_dExtra}</cd-extra>
<cd-artist>${xml_dArtist}</cd-artist>
<cd-title>${xml_dTitle}</cd-title>
<cd-year>${dYear}</cd-year>
<cd-genre>${dGenre}</cd-genre>
<cd-time>${dLength}</cd-time>
<cd-tracks>${dTracks}</cd-tracks>
<cd-comment></cd-comment>
EOF
i=0
while [ $i -lt ${#tTitle[@]} ]
do
trackNr="`printf %02d $((i+1))`"
xml_tTitle="`echo ${tTitle[$i]} | recode utf8..h0`"
xml_tArtist="`echo ${tArtist[$i]} | recode utf8..h0`"
trackEnd=${tEndSec[$i]}
trackStart=${tStartSec[$i]}
trackLen=$((trackEnd-$trackStart))
cat >>"${xmlFile}" <<EOF
<track>
<track-number>$trackNr</track-number>
<track-time>${tLength[$i]}</track-time>
<track-start-sector>${tStartSec[$i]}</track-start-sector>
<track-length>${trackLen}</track-length>
<track-artist>$xml_tArtist</track-artist>
<track-title>$xml_tTitle</track-title>
<track-comment></track-comment>
</track>
EOF
i=$((i+1))
done
echo "</cdinfo>" >>"${xmlFile}"
test ${verbose} -ge 1 && echo "${ready}"
# ----------------------------------------------------------------
# ----------------------------------------------------------------
# now do the ripping
test ${verbose} -eq 1 && echo -n "${startRipMsg1}"
test ${verbose} -ge 2 && { echo "${startRipMsg2}"; echo -en "\033[?25l"; }
i=0
while [ $i -lt ${#tTitle[@]} ]
do
trackNr=$((i+1))
# now that i don't forget it again. I use tr to translate \r to \n
# because sed does't recognise a line with only \r at its end as a line.
# Therefor sed reads until output of cdda2wav ends and does all the
# processing at once, so the percentage is not shown correctly
if [ ${verbose} -ge 2 ]
then
outStream="/dev/stdout"
else
outStream="/dev/null"
fi
case ${encodingType} in
f)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.flac"
outStr="track-$trackNr => ${outFile/\//-}: "
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
flac -c -f \
-T artist="${tArtist[$i]}" -T album="${dTitle}" \
-T genre="${dGenre}" -T title="${tTitle[$i]}" \
-T tracknumber="${trackNr}" -T tracknum="${trackNr}" \
-T date="${dYear}" -T comment="" \
-o "${encodingDir}/${outFile/\//-}" - #2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;/^ *[0-9]*\./d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
m)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.mp3"
outStr="track-$trackNr => ${outFile/\//-}: "
case ${encoder} in
lame)
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
lame -V2 \
--ta "${tArtist[$i]}" --tl "${dTitle}" \
--tg "${dGenre}" --tt "${tTitle[$i]}" \
--tn "${trackNr}" --ty "${dYear}" \
--tc "" \
- "${encodingDir}/${outFile/\//-}" 2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;/^ *[0-9]*\./d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
bladeenc)
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
bladeenc -progress=0 STDIN \
"${encodingDir}/${outFile/\//-}" 2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;/^ *[0-9]*\./d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
esac
;;
o)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.ogg"
outStr="track-$trackNr => ${outFile/\//-}: "
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - |\
oggenc -a "${tArtist[$i]}" -l "${dTitle}" \
-G "${dGenre}" -t "${tTitle[$i]}" \
-N "${trackNr}" -d "${dYear}" \
-c "" \
-o "${encodingDir}/${outFile/\//-}" - 2>/dev/null
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;/^ *[0-9]*\./d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
w)
outFile="`printf %02d ${trackNr}`-${tTitle[$i]}.wav"
outStr="track-$trackNr => ${outFile/\//-}: "
(
exec 2>&1
cdda2wav -H -D/dev/cdrom -I${cddaIf} -t${trackNr} - >\
"${encodingDir}/${outFile/\//-}"
) | tr '\r' '\n' |\
sed '/^ [0-9]/!d;/^ *[0-9]*\./d;s/^.* \([0-9]*%\).*$/\r'"${outStr}"'\1/' |\
tr -d '\n' >$outStream
;;
esac
test ${verbose} -ge 2 && echo # do a newline after each file
i=$((i+1))
done
test ${verbose} -ge 2 && echo -en "\033[?25h"
test ${verbose} -eq 1 && echo "${ready}"
# ----------------------------------------------------------------