Initial import from tla repo v0.7
authorSteve Youngs <steve@steveyoungs.com>
Sun, 19 Jun 2011 01:56:46 +0000 (11:56 +1000)
committerSteve Youngs <steve@steveyoungs.com>
Sun, 19 Jun 2011 01:56:46 +0000 (11:56 +1000)
Signed-off-by: Steve Youngs <steve@steveyoungs.com>
build.sh [new file with mode: 0755]
zcdrip.in [new file with mode: 0644]
zdiscid.c [new file with mode: 0644]

diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
index 0000000..046d2d5
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,109 @@
+#!/bin/zsh
+
+## Copyright (C) 2006, 2007 Steve Youngs
+
+## Author:        Steve Youngs <steve@sxemacs.org>
+## Maintainer:    Steve Youngs <steve@sxemacs.org>
+## Created:       <2006-08-16>
+
+## 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:
+## 
+##    Because I suck at writing makefiles
+
+### Code:
+clean ()
+{
+    rm -vf zcdrip ecdrip zdiscid
+}
+
+all ()
+{
+    clean
+    sub=@VERSION@
+    rep=$(tla logs --full|tail -n1)
+    zmodload -i zsh/mapfile
+    gcc -Wall -o zdiscid zdiscid.c
+    mapfile[zcdrip]=${mapfile[zcdrip.in]/$sub/$rep}
+    chmod -v 755 zcdrip
+}
+
+eshell ()
+{
+    [[ -f zcdrip && -f zdiscid ]] || all
+    ln -svf zcdrip ecdrip
+}
+
+target=${target:-/usr/local/bin}
+INSTALL=${INSTALL:-install}
+
+_install ()
+{
+    [[ -f zcdrip && -f zdiscid ]] || all
+
+    $INSTALL -vd $target
+    $INSTALL -v zcdrip zdiscid $target
+    [[ -f ecdrip ]] && $INSTALL -v ecdrip $target
+}
+
+ourname=${0##/}
+help ()
+{
+    cat<<EOF
+Usage:  $ourname [OPTION]
+
+OPTION can be...
+
+    all     -- builds zdiscid and zcdrip, also runs 'clean'
+    eshell  -- create eshell symlink workaround
+    clean   -- removes objects
+    install -- installs zcdrip
+
+Hint:
+
+    If you want to install zcdrip to a directory somewhere in '${HOME}'
+    do something like...
+
+      target=${HOME}/bin ./build.sh install
+
+EOF
+}
+
+case $argv[1] in
+    (all) all ;;
+    (eshell) eshell ;;
+    (clean) clean ;;
+    (install) _install ;;
+    (*) help ;;
+esac
+    
+### build.sh ends here
+
diff --git a/zcdrip.in b/zcdrip.in
new file mode 100644 (file)
index 0000000..768799b
--- /dev/null
+++ b/zcdrip.in
@@ -0,0 +1,868 @@
+#!/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
diff --git a/zdiscid.c b/zdiscid.c
new file mode 100644 (file)
index 0000000..60158a3
--- /dev/null
+++ b/zdiscid.c
@@ -0,0 +1,161 @@
+/* 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 */