#!/bin/sh

###########################################################################
#
# Copyright (c) 2010-2022 Fabian Keil <fk@fabiankeil.de>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
############################################################################
#
# wav2ogg runs cdda2wav to get wav files from audio cds and
# converts them to ogg vorbis.
#
# Inspired by Frederick Page's grabit.sh.
#
# There is almost no error checking done.
#
# Adapted for 2.01.01a75 and later.
# Last modifications made for 3.02a07_freebsd_11.0_amd64_amd64 (running on ElectroBSD).
# May no longer work with previous versions. 
#
# Dependencies: audio/vorbis-tools, lang/perl5.$n and sysutils/cdrtools
#
############################################################################

remove_files="Yes" # or Yes
eject_disc="Yes"   # or Yes
rip_files="Yes"
parse_only="No"

dev="${CDDA_DEVICE-1,0,0}"
cdda2wav=cdda2wav

usage() {
    echo "wav2ogg"
    echo "wav2ogg -k"              # keep files mode
    echo "wav2ogg -e directory"    # encode already existing files
    echo "wav2ogg -p directory"    # parse only the audio.cddb
    echo "wav2ogg -t track_number" # only rip and encode one track
}

get_cddb_attribute() {
    local attribute="$1"
    local cddb_file="$2"
    grep "^$attribute" "$cddb_file" | \
        perl -n -p \
            -e 's@.*=@@;' \
	    -e "s/^'//;" \
            -e "s/'$//;" \
            -e "s/\//-/g;" \
            -e 's/[\:*?"<>|]//g;' \
            -e 's@\n@@;'
}

encode_to_vorbis() {
    local directory="${1}"
    local cddb_file=audio.cddb

    if [ ! -e "${directory}/${cddb_file}" ]; then
        echo "'${cddb_file}' does not exist in ${directory}"
        return 1
    fi

    cd "${directory}" || return 1

    genre=$( get_cddb_attribute DGENRE "${cddb_file}")
    date=$(  get_cddb_attribute DYEAR  "${cddb_file}")
    discid=$(get_cddb_attribute DISCID "${cddb_file}")
    dtitle=$(get_cddb_attribute DTITLE "${cddb_file}")

    interpret=${dtitle%% - *}
    album=${dtitle##$interpret - }

    echo "Interpret: ${interpret}"
    echo "Album: ${album}"
    echo "Genre: ${genre}"
    echo "Date: ${date}"
    echo "Discid: ${discid}"

    for ttitle in $(grep TTITLE audio.cddb | perl -n -p -e 's@=.*$@@'); do
        track_number=$(echo "${ttitle}" | cut -c7-9)
        track_number=$(expr "${track_number}" + 1)
        if [ "${track_number}" -lt 10 ]; then
	    track_number="0${track_number}"
        fi
        wave_file="audio_${track_number}.wav"
        if test -e "${wave_file}"; then
            title=$(get_cddb_attribute "${ttitle}=" "${cddb_file}")
            echo "Track ${track_number}: ${title}"

            if [ $parse_only != "No" ]; then
                continue
            fi
            oggenc --artist "${interpret}" \
                   --title  "${title}" \
                   --album  "${album}" \
                   --genre  "${genre}" \
                   --date   "${date}" \
                   --tracknum "${track_number}" \
                   -q 6 \
                   -c "discid=${discid}"\
                   --names="../%a/%l/%n - %t.ogg" \
                   "${wave_file}" || break

            if [ "x${remove_files}" = x"Yes" ]; then
                echo Removing
	        rm -v "${wave_file}"
            fi
        fi
    done

    cd .. || return 1
}

parse_arguments() {
    local arguments

    arguments=$(getopt e:kp:t: $*)
    if [ $? != 0 ]; then
        usage
        exit 1
    fi

    set -- ${arguments}

    while true; do
        case "${1}" in
            -e)
                echo "Enabling encode-only mode"
                rip_files="No"
                parse_only="No"
                temp=$2
                shift; shift;
                break
                ;;
            -k)
                echo "Enabling keep-files mode"
                remove_files="No"
                shift
                ;;
            -p)
                echo "Enabling parse-only mode"
                remove_files="No"
                rip_files="No"
                parse_only="Yes"
                temp="${2}"
                shift; shift;
                break
                ;;
            -t)
                single_track="${2}"
                echo "Only ripping track ${single_track}"
                shift; shift;
                break
                ;;
            --)
                shift; break
                ;;
        esac
    done
}

rip_disc() {
    local device directory single_track track_specification track_number

    device=$1
    directory=$2
    single_track=$3

    if [ -z "${single_track}" ]; then
        # Rip all tracks
        track_specification="-B"
    else
        track_specification="-t ${single_track}"
    fi

    cd "${directory}"
    time env CDDBP_SERVER=gnudb.gnudb.org ${cdda2wav} ${track_specification} -no-hidden-track dev="${device}" --cddb 0 -paranoia || return 1
    if [ -n "${single_track}" ]; then
        # Rename the file name to the name encode_to_vorbis() expects
        if [ ${single_track} -lt 10 ]; then
	    track_number="0${single_track}"
        fi
        mv -v audio.wav "audio_${track_number}.wav"
    fi
    cd ..
}

main() {
    local audio_cddb=audio.cddb

    parse_arguments $*

    if [ -z "${temp}" ]; then
        temp=temp$$
    fi

    if [ "${rip_files}" = "Yes" ]; then
        mkdir "${temp}"
        # Check with -f and -L as the link may have been turned
        # into a regular file in case of races between saving to
        # it in an editor and removing it.
        if [ -f "${audio_cddb}" -o -L "${audio_cddb}" ]; then
            echo "${audio_cddb} already exists. Replacing it."
            rm "${audio_cddb}"
        else
            echo "${audio_cddb} does not exist yet"
        fi
        ln -s "./$temp/${audio_cddb}" "${audio_cddb}"

        rip_disc "${dev}" "${temp}" $single_track || return 1

        if [ "${eject_disc}" = "Yes" ]; then
            cdrecord dev="${dev}" -eject
        fi
    fi

    encode_to_vorbis "${temp}" || return 1

    if [ "$remove_files" = "Yes" ]; then
        echo Removing:
        rm -vr "${temp}"
        if [ -f "${audio_cddb}" -o -L "${audio_cddb}" ]; then
            rm -v "${audio_cddb}"
        fi
    fi
}

main $*
