--- /dev/null
+#!/bin/zsh
+
+## Copyright (C) 2006 - 2008 Steve Youngs
+
+## Author: Steve Youngs <steve@sxemacs.org>
+## Maintainer: Steve Youngs <steve@sxemacs.org>
+## Created: <2006-08-08>
+## Time-stamp: <Thursday Jun 12, 2008 12:29:31 steve>
+
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+##
+## 1. Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## 2. Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the distribution.
+##
+## 3. Neither the name of the author nor the names of any contributors
+## may be used to endorse or promote products derived from this
+## software without specific prior written permission.
+##
+## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+## SUBSTITUTE GOODS OR SERVICES# LOSS OF USE, DATA, OR PROFITS# OR
+## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+### Commentary:
+##
+## Ease the process of ripping audio CDs to .mp3 or .ogg. See
+## help (zcdrip -h) for full details.
+##
+
+### Todo:
+##
+## o Partial album ripping. Specify track numbers or a range of
+## track numbers to only rip/encode those tracks.
+##
+## o Ripping from music DVDs
+##
+
+### Bugs:
+##
+## Bugs? What bugs? Seriously though, if you find any, let me
+## know.
+##
+
+# Debug
+[[ -n $DEBUG ]] && set -x; zdebug=${TMPPREFIX}/zdebug
+
+### Code:
+ourname=${0##*/}
+
+# Version info.
+VERSION=@VERSION@
+COPYRIGHT="Copyright (C) 2006 - 2008 Steve Youngs <steve@sxemacs.org>"
+
+version_str="${ourname}: ${VERSION}
+${COPYRIGHT}"
+
+_version () { echo $version_str }
+
+# Help
+usage ()
+{
+ # If you use eshell you will have a problem displaying this help.
+ # This is the only part of the script that eshell has a problem
+ # with, but if you really want to be able to view this help in
+ # eshell, create a symlink and call it `ecdrip'.
+
+ [[ ${LINES} -lt 70 && $TERM != dumb ]] && _doc=${PAGER:-less} || _doc=cat
+ [[ $ourname == ecdrip ]] && _doc=cat
+ $_doc<<EOF
+
+ $ourname
+ ${VERSION}
+
+
+Synopsis:
+--------
+
+ $ourname
+ [ -moi ] [ --mp3 | --ogg ] [ -r FILE ] [ --interactive | --rcfile=FILE ]
+ [ -a ALBUM ] [ --album=ALBUM ] [ -s ARTIST ] [ --sameartist=ARTIST ]
+ [ -t ENCODING_TYPE ] [ --type=ENCODING_TYPE ] [ -f | --flac_copy ]
+ [ -e FILE | --edit_rcfile=FILE ] [ -O | --online ] [ -d DIR | --dir=DIR ]
+ $ourname
+ [ -h | --help ]
+ $ourname
+ [ -V | --version ]
+
+Description:
+-----------
+
+ $ourname is a "frontend" to the process of ripping audio (cdda) CDs
+ to a hard disk and encoding the audio tracks to either MP3 format or
+ Ogg Vorbis format.
+
+ File names are auto-generated from track titles, with illegal
+ characters removed and spaces converted to underscores.
+
+ Track title, artist, and album names are added to the ID3 tags or
+ Vorbis comments header.
+
+Options:
+-------
+
+ -a ALBUM
+ --album=ALBUM
+ Specify the ALBUM name. Argument ALBUM is _NOT_ optional.
+ Whitespace and punctuation is permitted, but you must protect
+ them from the shell. If this option is omitted, the album
+ name will be prompted for.
+
+ -d DIR
+ --dir=DIR
+ Save encoded files to the directory, DIR. If flac encoding
+ is also requested, see '--flac_copy' option below, the flac
+ files will be saved to DIR/flac. If this option is omitted,
+ it defaults to 'PWD/ARTIST/ALBUM' the album name is first
+ converted to a sane filename.
+
+ -e FILE
+ --edit_rcfile=FILE
+ Edit/create rcfile, FILE, in an editor. If the environment
+ variable EDITOR is not set, vi is used. This implicitly sets
+ rcfile, see '--rcfile' option below.
+
+ -f
+ --flac_copy
+ In addition to encoding the CD audio tracks to MP3 or Ogg
+ Vorbis, create a FLAC audio file for archival purposes.
+
+ -h
+ --help
+ Display this help text and exit.
+
+ -i
+ --interactive
+ Prompt for track titles and artist names.
+
+ -m
+ --mp3
+ Specify MP3 encoding.
+
+ -o
+ --ogg
+ Specify Ogg Vorbis encoding.
+
+ -O
+ --online
+ Attempt to grab the track info from freedb.freedb.org.
+
+ -r FILE
+ --rcfile=FILE
+ Get track titles and artist names from FILE. Argument FILE
+ is _NOT_ optional. The format of FILE is:
+
+ Artist Name|Track Title
+
+ One "record" per line. Whitespace and punctuation is permitted,
+ blank lines are not. And there is no "comment" lines.
+
+ -s ARTIST
+ --sameartist=ARTIST
+ All tracks on the album are by the same ARTIST. Argument
+ ARTIST is _NOT_ optional.
+
+ -t ENCODING_TYPE
+ --type=ENCODING_TYPE
+ This is an alternative to using the -m or -o options.
+ Use ENCODING_TYPE to encode the audio. Valid values for
+ ENCODING_TYPE are "mp3", "ogg".
+
+ -V
+ --version
+ Display version info and exit.
+
+Requirements:
+------------
+
+ zsh http://www.zsh.org/ (mandatory)
+
+ cdparanoia http://www.xiph.org/paranoia/
+ For ripping the audio tracks from CD. (mandatory)
+
+ lame http://www.mp3dev.org/
+ For encoding to MP3 format. (optional if encoding to
+ Ogg Vorbis)
+
+ oggenc http://www.xiph.org/
+ For encoding to Ogg Vorbis format (optional if encoding
+ to MP3)
+
+ flac http://flac.sourceforge.net/
+ For additionally storing audio tracks in FLAC format.
+ (optional)
+
+Files:
+-----
+
+ ${TMPPREFIX}/$ourname.log
+ A log of the incoming TCP traffic from the CDDB server.
+ This will be kept if debugging is turned on, otherwise
+ it is deleted upon successful exit.
+
+ $zdebug
+ Some extra debugging info is logged here.
+
+ rcfile
+ Where $ourname gets track info from. It can be
+ specified on the command line (see -r above) when
+ not using an online CDDB server, otherwise it is
+ created automatically by $ourname.
+
+Environment Variables:
+---------------------
+
+ Some aspects of $ourname can be tweaked by setting the following
+ environment variables.
+
+ DEBUG Set to a non-nil string to turn on debugging.
+
+ zcddb CDDB server to use (default: freedb.freedb.org).
+
+ zuser Name used to log into CDDB server (default: $USER).
+
+ zhost Host used to log into CDDB server (default: $HOST).
+
+ zedit Set to a non-nil string to force $ourname to invoke an
+ editor to create a rcfile.
+
+ zcomment Extra comment field/value to add to ID3 tags/Vorbis
+ comments (default: "Encoded with $ourname").
+
+ Occasionally, the CDDB entries for a given CD are either wrong or
+ have not been formatted correctly. In an attempt to compensate for
+ these types of quirks you can set the following environment variables
+ with $ourname invocation to override the madness...
+
+ ARTIST Override the artist field.
+
+ ALBUM Override the album name.
+
+ YEAR Override year.
+
+ GENRE Override genre.
+
+Example Usage:
+-------------
+
+ Probably the most common usage would be to encode to Ogg/Vorbis
+ format using track info obtained from freedb.freedb.org. Like
+ this...
+
+ \$ $ourname -oO
+
+ Encode to MP3 format, prompting for album name, year, genre, artist,
+ and track titles...
+
+ \$ $ourname -mi
+
+ Encode to Ogg/Vorbis, set album name on the command line, taking
+ track title info from a file, and make a FLAC format backup copy of
+ each track...
+
+ \$ $ourname -a "The Album Name" -o -f -r /path/to/rcfile
+
+ Encode to Ogg/Vorbis, taking track info from a online CDDB server,
+ and override the genre for the album...
+
+ \$ GENRE=alternate $ourname -oO
+
+Exit Status:
+-----------
+
+ $ourname will return the following status codes on exit:
+
+ 0 -- Clean exit (no errors)
+ 2 -- Command line option error
+ 3 -- Missing external command
+ 4 -- CDDB error
+
+Debugging:
+---------
+
+ If you call $ourname with the environment variable DEBUG set to a
+ non nil value, for example: DEBUG=yes $ourname <opts>, $ourname will
+ be called with "set -x".
+
+ "set -x" spams your stdout with a _LOT_ of messages, it would most
+ likely pay you to redirect stdout/stderr to a file.
+
+${COPYRIGHT}
+
+EOF
+}
+
+# Convert song title to something resembling a sane filename... no
+# whitespace, no punctuation, etc. Also adds .ogg/.mp3 extension.
+fnamefix ()
+{
+ local psub="[[:cntrl:],\*\?\`';/\\\\\"]"
+ local prep=""
+ local wsub="[[:space:][:blank:]]"
+ local wrep="_"
+
+ setopt extendedglob
+
+ for (( i=1; i<=$tracks; ++i )); do
+ tf=$filename[$i]
+ tf=${tf//\\t/ }
+ tf=${tf//${~psub}/$prep}
+ tf=${tf//[ ]##/ }
+ tf=${tf//${~wsub}/$wrep}
+ filename[$i]=$tf.$prepargs[1]
+ done
+}
+
+### freedb magic
+_freedb_login ()
+{
+ local args
+ if [[ -z $1 ]]; then
+ print invalid args >&2
+ return 1
+ fi
+
+ args="$@"
+ # login
+ tcp_send "cddb hello $args"
+ tcp_expect -T 10 -s $ourname "*Hello and welcome*"
+ if [[ $? -eq 2 ]]; then
+ print Timeout waiting for cddb server >&2
+ exit 4
+ fi
+ # set protocol level
+ tcp_send "proto 6"
+ tcp_expect -T 10 -s $ourname "*CDDB protocol*"
+ if [[ $? -eq 2 ]]; then
+ print Timeout waiting for cddb server >&2
+ exit 4
+ fi
+ return 0
+}
+
+_parse_cddb ()
+{
+ local various=yes
+ art=$(grep DTITLE $zlog|cut -d= -f2|cut -d/ -f1|sed '1!d')
+ art=${art/%[[:space:]]/}
+ art=${art//'&'/'\&'}
+
+ # Possibly override.
+ art=${ARTIST:-$art}
+
+ # Artist
+ if [[ "$art" != "Various Artists" && "$art" != "Various" ]]; then
+ various=no
+ fi
+
+ # Album, year, genre, number or tracks
+ album=$(grep DTITLE $zlog|cut -d= -f2|cut -d/ -f2)
+ album=${album/#[[:space:]]/}
+ album=${album//[[:cntrl:]]/}
+ year=$(grep DYEAR $zlog|cut -d= -f2)
+ year=${year//[[:cntrl:]]/}
+ genre=$(grep DGENRE $zlog|cut -d= -f2)
+ genre=${genre//[[:cntrl:]]/}
+ tracks=$zid[2]
+
+ # Possibly override album, year, genre
+ album=${ALBUM:-$album}
+ year=${YEAR:-$year}
+ genre=${GENRE:-$genre}
+
+ # print what we got when we're debugging
+ if [[ -n $DEBUG ]]; then
+ printf "Artist: %s\nAlbum: %s\nYear: %s\nGenre: %s\nNum Tracks: %s\n" \
+ $art $album $year $genre $tracks > $zdebug
+ printf "Various: %s\n" $various >> $zdebug
+ echo --- Titles --- >> $zdebug
+ grep TTITLE $zlog >> $zdebug
+ fi
+
+ # create an rcfile
+ if [[ $various == yes || -n $(grep TTITLE $zlog|grep $art) ]]; then
+ grep TTITLE $zlog|cut -d= -f2|sed 's@ [-/] @|@' > $rcfile
+ else
+ grep TTITLE $zlog|cut -d= -f2 > $rcfile
+ sed -i "s@^@${art}|@g" $rcfile
+ fi
+
+}
+
+_freedb_read ()
+{
+ if [[ -z $1 ]]; then
+ print invalid args >&2
+ return 1
+ fi
+
+ tcp_send "cddb read $1 $2"
+ tcp_expect -T 25 -s $ourname "*PLAYORDER*"
+ if [[ $? -eq 2 ]]; then
+ print Timeout waiting for cddb server >&2
+ exit 4
+ fi
+
+ _parse_cddb
+
+}
+
+_freedb_query ()
+{
+ if [[ -z $1 ]]; then
+ print invalid args >&2
+ return 1
+ fi
+
+ tcp_send "cddb query $zid"
+ tcp_expect -T 10 -p idx -s $ourname "*No match for disc ID*" \
+ "<-\[$ourname\] 200*" "<-\[$ourname\] .*"
+ if [[ $? -eq 2 ]]; then
+ print Timeout waiting for cddb server >&2
+ exit 4
+ fi
+ case $idx in
+ (1)
+ print No entry listed for disc: $zid[1] >&2
+ print You will have to do this disc manually >&2
+ exit 4
+ ;;
+ (2)
+ category=$TCP_LINE
+ category=${category/*200 /}
+ category=${category/ $zid[1]*/}
+ _freedb_read $category $zid[1]
+ ;;
+ (3)
+ echo Multiple entries found...
+ echo
+ tmulti=(${(ps:\r:)${tcp_expect_lines}})
+ [[ $tmulti[1] == *inexact* ]] && exact=no
+ tmulti[1]=${tmulti[1]:#${tmulti[1]}}
+ multi=($tmulti)
+ for (( i=1; i<${#multi}; ++i )); do
+ multi[$i]=${multi[$i]/<-\[$ourname\] /}
+ printf "\t[%s]%s\n" $i $multi[$i]
+ done
+ echo
+ echo -n "Which CDDB entry (q to quit): "
+ read choice
+ case $choice in
+ ([qQ]) do_offline; exit 0 ;;
+ ([^[:digit:]])
+ print Invalid response >&2
+ do_offline
+ exit 2
+ ;;
+ ([[:digit:]])
+ category=$multi[$choice]
+ if [[ $exact == no ]]; then
+ tcategory=(${(ps: :)category})
+ _freedb_read $tcategory[1,2]
+ else
+ category=${category/ $zid[1]*/}
+ _freedb_read $category $zid[1]
+ fi
+ ;;
+ (*)
+ print Unknown error >&2
+ do_offline
+ exit 2
+ ;;
+ esac
+ ;;
+ (*) print Unknown error >&2 ;;
+ esac
+}
+
+do_online ()
+{
+ autoload -U tcp_open
+ autoload -U tcp_log
+ [[ -n $DEBUG ]] || TCP_SILENT=nodebugging
+
+ zcddb=${zcddb:-freedb.freedb.org}
+ port=8880
+ zuser=${zuser:-$USER}
+ zhost=${zhost:-$HOST}
+ proto=6
+ zlog=${TMPPREFIX}/zcdrip.log
+
+ # open the log and connect
+ tcp_log $zlog
+ tcp_open $zcddb $port $ourname
+ tcp_expect -T 10 -s $ourname "<-\[$ourname\] 201*ready*"
+ if [[ $? -eq 2 ]]; then
+ print Timeout waiting for cddb server >&2
+ exit 4
+ else
+ _freedb_login $zuser $zhost $ourname $VERSION
+ fi
+
+ # query cddb server to find out if the CD is listed
+ _freedb_query $zid
+
+}
+
+# Close tcp connection
+do_offline ()
+{
+ tcp_close $ourname
+ tcp_log -c
+}
+
+# Tidy up if not debugging
+cleanup ()
+{
+ rm -f $zlog $rcfile $zdebug
+ unset ARTIST ALBUM YEAR GENRE
+}
+
+# convert album/artist name into a sane filename for output dir
+_album_to_dir ()
+{
+ local talbum=$album
+ local tart=$art
+ local psub="[[:cntrl:],\`';/\\\\\"]"
+ local prep=""
+ local wsub="[[:space:][:blank:]]"
+ local wrep="_"
+
+ setopt extendedglob
+
+ talbum=${talbum//\\t/ }
+ talbum=${talbum//${~psub}/$prep}
+ talbum=${talbum//[ ]##/ }
+ talbum=${talbum//${~wsub}/$wrep}
+
+ tart=${tart//\\t/ }
+ tart=${tart//${~psub}/$prep}
+ tart=${tart//[ ]##/ }
+ tart=${tart//${~wsub}/$wrep}
+
+ # Various Artists is sometimes "Various" and other times "Various
+ # Artists", we'll call them all "Various_Artists".
+ if [[ "${tart}" == "Various" ]]; then
+ tart=Various_Artists
+ fi
+
+ dir=$(pwd)/${tart}/${talbum}
+ [[ -d ${dir} ]] || mkdir -p ${dir}
+ [[ $keep_flac == yes ]] && fdir=${dir}/flac; mkdir -p ${fdir}
+}
+
+
+# Store song titles, artist, and album names.
+prep ()
+{
+ zid=($(zdiscid))
+ tracks=$zid[2]
+
+ [[ -d ${TMPPREFIX} ]] || mkdir -p ${TMPPREFIX}
+
+ if [[ $online == yes ]]; then
+ do_online
+ do_offline
+ fi
+
+ typeset -A artist
+ typeset -A song
+ typeset -A filename
+
+ if [[ $zedit == yes && -n $rcfile ]]; then
+ _zedit=${EDITOR:-vi}
+ cat>$rcfile<<EOF
+The format of this file is...
+ Artist Name|Track Title
+One "record" per line. Punctuation and whitespace is OK.
+You MUST delete these instructions before saving.
+EOF
+ $_zedit $rcfile
+ fi
+
+ if [[ -z $album ]]; then
+ echo -n "Please enter the name of this album: "
+ read album
+ echo
+ fi
+
+ [[ -n $dir ]] || _album_to_dir
+
+ if [[ ! -d ${dir} ]]; then
+ mkdir -p ${dir}
+ if [[ $keep_flac == yes && ! -d ${fdir} ]]; then
+ mkdir -p ${fdir}
+ fi
+ fi
+
+ if [[ -z $year ]]; then
+ echo -n "Please enter the year this album was released: "
+ read year
+ echo
+ fi
+
+ if [[ -z $genre ]]; then
+ echo -n "Please enter the genre of this album: "
+ read genre
+ echo
+ fi
+
+ zcomment=${zcomment:-"Encoded with $ourname"}
+
+ if [[ $prepargs[2] == yes ]]; then
+ for (( i=1; i<=$tracks; ++i )); do
+ if [[ -n $art ]]; then
+ artist[$i]=$art
+ else
+ echo -n "Track $i artist: "
+ read art
+ artist[$i]=$art
+ unset art
+ fi
+ echo -n "Track $i title: "
+ read sg
+ song[$i]=$sg
+ filename[$i]=$sg
+ done
+ else
+ IFS="|"
+ i=0
+ while read art sg; do
+ (( ++i ))
+ artist[$i]=$art
+ sg=${sg/#[[:space:]]/}
+ sg=${sg//[[:cntrl:]]/}
+ song[$i]=${sg}
+ filename[$i]=${sg}
+ done < $prepargs[3]
+ fi
+
+ fnamefix $prepargs[1]
+ wavfile=dumpaudio.wav
+ ${prepargs[1]}rip
+
+ [[ -n $DEBUG ]] || cleanup
+}
+
+# Flac
+flacenc ()
+{
+ file=$1
+ shift # pop off $1 (flacfile)
+ flac -8 --delete-input-file -o ${fdir}/${file} ${1}
+ shift # pop off next arg (wavfile)
+ for tag in title artist album year genre tracknumber comment; do
+ metaflac --set-tag="$tag=${1}" ${fdir}/${file}
+ shift
+ done
+}
+
+flactomp3 ()
+{
+ flac=$1
+ mp3=$2
+
+ # tags
+ title=$(metaflac --show-tag=title|cut -d= -f2)
+ artist=$(metaflac --show-tag=artist|cut -d= -f2)
+ album=$(metaflac --show-tag=album|cut -d= -f2)
+ year=$(metaflac --show-tag=year|cut -d= -f2)
+ genre=$(metaflac --show-tag=genre|cut -d= -f2)
+ track=$(metaflac --show-tag=tracknumber|cut -d= -f2)
+ comment=$(metaflac --show-tag=comment|cut -d= -f2)
+
+ flac -c -d $flac|lame -h --tt ${title} --ta ${artist} --tl ${album} \
+ --ty $year --tg $genre --tn $track --tc ${comment} - $mp3
+}
+
+# Encode to MP3
+mp3rip ()
+{
+ # Work around lame being too anal about genre
+ lame --genre-list|grep ${genre} 1>/dev/null || genre=Other
+
+ for (( i=1; i<=$tracks; ++i )); do
+ echo MP3-Ripping: $song[$i], by: $artist[$i], to: $filename[$i]
+ cdparanoia -X $i $wavfile
+ if [[ -f $wavfile ]]; then
+ if [[ $keep_flac == yes ]]; then
+ flacfile=${filename[$i]/%mp3/flac}
+ flacenc ${flacfile} ${wavfile} $song[$i] $artist[$i] $album \
+ $year $genre $i $zcomment
+ flactomp3 ${flacfile} ${dir}/$filename[$i]
+ else
+ lame -h --tt $song[$i] --ta $artist[$i] --tl $album \
+ --ty $year --tg $genre --tc $zcomment $wavfile \
+ --tn $i ${dir}/$filename[$i]
+ fi
+ fi
+ [[ -f $wavfile ]] && rm -f $wavfile
+ done
+}
+
+# Encode to OGG Vorbis
+oggrip ()
+{
+ for (( i=1; i<=$tracks; ++i )); do
+ echo OGG-Ripping: $song[$i], by: $artist[$i], to: $filename[$i]
+ cdparanoia -X $i $wavfile
+ if [[ -f $wavfile ]]; then
+ if [[ $keep_flac == yes ]]; then
+ flacfile=${filename[$i]/%ogg/flac}
+ flacenc ${flacfile} ${wavfile} $song[$i] $artist[$i] $album \
+ $year $genre $i $zcomment
+ oggenc -q3 -o ${dir}/$filename[$i] ${fdir}/$flacfile
+ else
+ oggenc -q3 -o ${dir}/$filename[$i] -t $song[$i] -a $artist[$i] \
+ -l $album -d $year -G $genre -c "comment=$zcomment" \
+ -N $i $wavfile
+ rm $wavfile
+ fi
+ fi
+ done
+}
+
+# Make sure we have everything we need.
+# This might be a little over the top, but I don't see any point in
+# checking for `oggenc' if you are encoding to MP3, likewise, there's
+# no point in checking for `lame' if you are encoding to Ogg Vorbis.
+chkreqs ()
+{
+ reqs=(cdparanoia lame oggenc flac)
+ whence -w $reqs[1] 1>/dev/null
+ if [[ $? -gt 0 ]]; then
+ echo $ourname: error: Missing $reqs[1] >&2
+ rv=3
+ fi
+ case $atype in
+ (mp3)
+ whence -w $reqs[2] 1>/dev/null
+ if [[ $? -gt 0 ]]; then
+ echo $ourname: error: Missing $reqs[2] >&2
+ rv=3
+ fi
+ ;;
+ (ogg)
+ whence -w $reqs[3] 1>/dev/null
+ if [[ $? -gt 0 ]]; then
+ echo $ourname: error: Missing $reqs[3] >&2
+ rv=3
+ fi
+ ;;
+ esac
+ if [[ $keep_flac == yes ]]; then
+ whence -w $reqs[4] 1>/dev/null
+ if [[ $? -gt 0 ]]; then
+ echo $ourname: error: Missing $reqs[4] >&2
+ rv=3
+ fi
+ fi
+ if [[ $rv -eq 3 ]]; then
+ exit $rv
+ else
+ return 0
+ fi
+}
+
+
+# Command line parsing
+args=mofihVO-:r:a:s:t:e:d:
+flavour=0
+rc=0
+interactive=no
+rcfile=" "
+zedit=" "
+
+while getopts $args opts; do
+ case $opts in
+ (-)
+ case $OPTARG in
+ (mp3) atype=mp3; (( ++flavour )) ;;
+ (ogg) atype=ogg; (( ++flavour )) ;;
+ (edit_rcfile?*)
+ rcfile=${OPTARG/edit_rcfile=/}
+ (( ++rc ))
+ zedit=yes
+ ;;
+ (flac_copy) keep_flac=yes ;;
+ (type?*) atype=${OPTARG/type=/}; (( ++flavour )) ;;
+ (interactive) interactive=yes; (( ++rc )) ;;
+ (online) online=yes; (( ++rc )); rcfile=${TMPPREFIX}/zrcfile ;;
+ (rcfile?*) rcfile=${OPTARG/rcfile=/}; (( ++rc )) ;;
+ (album?*) album=${OPTARG/album=/} ;;
+ (sameartist?*) art=${OPTARG/sameartist=/} ;;
+ (dir?*) dir=${OPTARG/dir=/} ;;
+ (version) _version; exit 0 ;;
+ (help) cmd=usage; rv=0 ;;
+ (*)
+ echo $ourname: error: bad option: --$OPTARG >&2
+ exit 2
+ ;;
+ esac
+ ;;
+ (i) interactive=yes; (( ++rc )) ;;
+ (O) online=yes; (( ++rc )); rcfile=${TMPPREFIX}/zrcfile ;;
+ (m) atype=mp3; (( ++flavour )) ;;
+ (o) atype=ogg; (( ++flavour )) ;;
+ (e) rcfile=$OPTARG; (( ++rc )); zedit=yes ;;
+ (f) keep_flac=yes ;;
+ (r) rcfile=$OPTARG; (( ++rc )) ;;
+ (a) album=$OPTARG ;;
+ (s) art=$OPTARG ;;
+ (t) atype=$OPTARG; (( ++flavour )) ;;
+ (d) dir=$OPTARG ;;
+ (V) _version; exit 0 ;;
+ (h) cmd=usage; rv=0 ;;
+ (*) rv=2 ;;
+ esac
+done
+shift $(( $OPTIND - 1 ))
+
+if [[ $cmd != usage ]]; then
+ case $flavour in
+ (0)
+ echo $ourname: error: no audio format specified >&2
+ if [[ $rc -ne 1 ]]; then
+ echo $ourname: error: improper use of interactice/rcfile option >&2
+ fi
+ rv=2
+ ;;
+ (1)
+ if [[ $rc -ne 1 ]]; then
+ echo $ourname: error: improper use of interactive/rcfile option >&2
+ rv=2
+ else
+ typeset -A prepargs
+ prepargs=(1 $atype 2 $interactive 3 $rcfile 4 $zedit)
+ chkreqs
+ prep $prepargs
+ fi
+ ;;
+ (*)
+ echo $ourname: error: multiple or invalid audio formats specified >&2
+ if [[ $rc -ne 1 ]]; then
+ echo $ourname: error: improper use of interactice/rcfile option >&2
+ fi
+ rv=2
+ ;;
+ esac
+else
+ usage
+fi
+
+exit $rv
+
+### zcdrip ends here
--- /dev/null
+/* zdiscid.c -- Print the CDDB disc ID for an audio CD */
+
+/*
+ * Copyright (C) 2006, 2007 Steve Youngs
+ */
+
+/*
+ * Author: Steve Youngs <steve@sxemacs.org>
+ * Maintainer: Steve Youngs <steve@sxemacs.org>
+ * Created: <2006-08-13>
+ */
+
+/*
+ * This file is part of zcdrip.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+
+ * 3. Neither the name of the author nor the names of any contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Commentary:
+ *
+ * Print the CDDB disc ID for an audio CD.
+ */
+
+/* Code: */
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+
+#define FAILURE_NOCD -1
+
+struct toc {
+ int min, sec, frame;
+} cdtoc[100];
+
+int read_toc();
+int cddb_sum(int);
+unsigned long get_cddb_id(int);
+
+int
+read_toc()
+{
+ int drive = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
+ struct cdrom_tochdr tochdr;
+ struct cdrom_tocentry tocentry;
+ int i;
+
+ if (ioctl(drive, CDROMREADTOCHDR, &tochdr) != 0) {
+ fprintf(stderr, "No disc in drive\n");
+ close(drive);
+ return FAILURE_NOCD;
+ }
+
+ for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
+ tocentry.cdte_track = i;
+ tocentry.cdte_format = CDROM_MSF;
+ ioctl(drive, CDROMREADTOCENTRY, &tocentry);
+ cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
+ cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
+ cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
+ cdtoc[i-1].frame += cdtoc[i-1].min * 60 * 75;
+ cdtoc[i-1].frame += cdtoc[i-1].sec * 75;
+ }
+ tocentry.cdte_track = 0xAA;
+ tocentry.cdte_format = CDROM_MSF;
+ ioctl(drive, CDROMREADTOCENTRY, &tocentry);
+ cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
+ cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
+ cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
+ cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min * 60 * 75;
+ cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec * 75;
+ close(drive);
+ return tochdr.cdth_trk1;
+}
+
+int
+cddb_sum(int n)
+{
+ int ret = 0;
+
+ while (n > 0) {
+ ret = ret + (n % 10);
+ n = n / 10;
+ }
+
+ return ret;
+}
+
+unsigned long
+get_cddb_id(int ntrks)
+{
+ int i, t, n;
+
+ i = t = n = 0;
+
+ while (i < ntrks) {
+ n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
+ i++;
+ }
+
+ t = ((cdtoc[ntrks].min * 60) + cdtoc[ntrks].sec) -
+ ((cdtoc[0].min * 60) + cdtoc[0].sec);
+
+ return ((n % 0xff) << 24 | t << 8 | ntrks);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ntrks, i;
+
+ ntrks = read_toc();
+
+ switch (ntrks) {
+ case 0:
+ case 1:
+ fprintf(stderr, "Disc is not an audio CD\n");
+ return 1;
+ case -1:
+ return ntrks;
+ default:
+ break;
+ }
+
+ printf("%08lx %d", get_cddb_id(ntrks), ntrks);
+ for (i = 0; i < ntrks; i++) {
+ printf(" %d", cdtoc[i].frame);
+ }
+ printf(" %d\n", (cdtoc[ntrks].frame) / 75);
+ return 0;
+}
+
+/* zdiscid.c ends here */
+