#!/bin/sh # Copyright (c) 2009-2015 Serge "ftrvxmtrx" Ziryukin # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # Dependencies: # shntool, cuetools # SPLIT: flac, wavpack, mac # CONVERT: flac/flake, faac, libmp4v2, id3lib/mutagen, lame, vorbis-tools # ART: ImageMagick # CHARSET: iconv, enca # GAIN: flac, aacgain, mp3gain, vorbisgain # Exit codes: # 0 - success # 1 - error in arguments # 2 - file or path is not accessible # 3 - something has failed [ -n "${XDG_CONFIG_HOME}" ] && CONFIG="${XDG_CONFIG_HOME}/split2flac/split2flac.conf" [ -r "${CONFIG}" ] || CONFIG="${HOME}/.split2flac" TMPPIC="${HOME}/.split2flac_cover.jpg" FAILED="split_failed.txt" NOSUBDIRS=0 NOPIC=0 REMOVE=0 NOCOLORS=0 PIC_SIZE="192x192" REPLAY_GAIN=0 FORMAT="${0##*split2}" DIR="." OUTPATTERN="@artist/{@year - }@album/@track - @title.@ext" COPYMASKS="[Cc]overs \*.log \*.txt \*.jpg \*.cbr" COPYFILES=1 ENCA_ARGS="" # codecs default arguments ENCARGS_flac="-8" ENCARGS_m4a="-q 500" ENCARGS_mp3="--preset standard" ENCARGS_ogg="-q 5" ENCARGS_wav="" # load settings eval $(cat "${CONFIG}" 2>/dev/null) DRY=0 SAVE=0 NASK=0 unset PIC INPATH CUE CHARSET FORCE=0 # do not forget to update before commit VERSION=121 HELP="\${cG}split2flac version: ${VERSION} Splits one big \${cU}APE/FLAC/WV/WAV\$cZ\$cG audio image (or a collection) into \${cU}FLAC/M4A/MP3/OGG_VORBIS/WAV\$cZ\$cG tracks with tagging and renaming. Usage: \${cZ}split2\${FORMAT} [\${cU}OPTIONS\$cZ] \${cU}FILE\$cZ [\${cU}OPTIONS\$cZ]\$cZ \${cZ}split2\${FORMAT} [\${cU}OPTIONS\$cZ] \${cU}DIR\$cZ [\${cU}OPTIONS\$cZ]\$cZ \$cG-p\$cZ - dry run \$cG-o \${cU}DIRECTORY\$cZ \$cR*\$cZ - set output directory (current is \$cP\${DIR}\$cZ) \$cG-of \${cU}'PATTERN'\$cZ \$cR*\$cZ - use specific output naming pattern (current is \$cP'\${OUTPATTERN}'\$cZ) \$cG-cue \${cU}FILE\$cZ - use file as a cue sheet (does not work with \${cU}DIR\$cZ) \$cG-cuecharset \${cU}CHARSET\$cZ - convert cue sheet from CHARSET to UTF-8 (no conversion by default) \$cG-nask\$cZ - do not ask to enter proper charset of a cue sheet (default is to ask) \$cG-f \${cU}FORMAT\$cZ - use specific output format (current is \$cP\${FORMAT}\$cZ) \$cG-e \${cU}'ARG1 ARG2'\$cZ \$cR*\$cZ - encoder arguments (current is \$cP'\${ENCARGS}'\$cZ) \$cG-eh\$cZ - show help for current encoder and exit\$cZ \$cG-enca \${cU}'ARG1 ARG2'\$cZ \$cR*\$cZ - enca additional arguments (current is \$cP'\${ENCA_ARGS}'\$cZ) \$cG-c \${cU}FILE\$cZ \$cR*\$cZ - use file as a cover image (does not work with \${cU}DIR\$cZ) \$cG-nc \${cR}*\$cZ - do not set any cover images \$cG-C \${cU}MASKS\$cZ \$cR*\$cZ - specify wildcards for files to copy over (current is \$cP'\${COPYMASKS}'\$cZ) \$cG-nC \${cR}*\$cZ - do not copy any files \$cG-cs \${cU}WxH\$cZ \$cR*\$cZ - set cover image size (current is \$cP\${PIC_SIZE}\$cZ) \$cG-d \$cR*\$cZ - create artist/album subdirs (default) \$cG-nd \$cR*\$cZ - do not create any subdirs \$cG-D \$cR*\$cZ - delete original file \$cG-nD \$cR*\$cZ - do not remove the original (default) \$cG-F\$cZ - force deletion without asking \$cG-colors\$cZ \$cR*\$cZ - colorized output (default) \$cG-nocolors\$cZ \$cR*\$cZ - turn off colors \$cG-g\$cZ \$cR*\$cZ - adjust audio gain \$cG-ng\$cZ \$cR*\$cZ - do not adjust audio gain (default) \$cG-s\$cZ - save configuration to \$cP\"\${CONFIG}\"\$cZ \$cG-h\$cZ - print this message \$cG-v\$cZ - print version \$cR*\$cZ - option affects configuration if \$cP'-s'\$cZ option passed. \${cP}NOTE: \$cG'-c some_file.jpg -s'\$cP only \${cU}allows\$cZ\$cP cover images, it doesn't set a default one. \${cZ}Supported \$cU\${cG}FORMATs\${cZ}: flac, m4a, mp3, ogg, wav. Supported tags for \$cU\${cG}PATTERN\${cZ}: @artist, @album, @year, @track, @performer, @title, @genre, @ext. @performer tag is useful with 'various artists' albums, when you want to add each artist's name to the track filename. It works as @artist if track performer is undefined. Special \"underscored\" tags are also supported (@_artist, @_album, etc). If used, spaces will be replaced with underscores. It's useful if you want to have filenames without spaces. It's better to pass \$cP'-p'\$cZ option to see what will happen when actually splitting tracks. You may want to pass \$cP'-s'\$cZ option for the first run to save default configuration (output dir, cover image size, etc.) so you won't need to pass a lot of options every time, just a filename. Script will try to find CUE sheet if it wasn't specified. It also supports internal CUE sheets (FLAC, APE and WV).\n" msg="printf" emsg () { $msg "${cR}$1${cZ}" } SKIP_UPDATE_ENCARGS=0 update_encargs () { if [ ${SKIP_UPDATE_ENCARGS} -eq 0 ]; then e="\${ENCARGS_${FORMAT}}" ENCARGS=`eval echo "$e"` ENCHELP=0 fi } update_colors () { if [ "${NOCOLORS}" -eq 0 ]; then cR="\033[31m" cG="\033[32m" cC="\033[35m" cP="\033[36m" cU="\033[4m" cZ="\033[0m" else unset cR cG cC cP cU cZ fi } update_encargs update_colors # parse arguments while [ "$1" ]; do case "$1" in -o) DIR=$2; shift;; -of) OUTPATTERN=$2; shift;; -cue) CUE=$2; shift;; -cuecharset) CHARSET=$2; shift;; -nask) NASK=1;; -f) FORMAT=$2; update_encargs; shift;; -e) ENCARGS=$2; SKIP_UPDATE_ENCARGS=1; shift;; -eh) ENCHELP=1;; -enca) ENCA_ARGS=$2; shift;; -c) NOPIC=0; PIC=$2; shift;; -nc) NOPIC=1;; -C) COPYMASKS=$2; COPYFILES=1; shift;; -nC) COPYFILES=0;; -cs) PIC_SIZE=$2; shift;; -d) NOSUBDIRS=0;; -nd) NOSUBDIRS=1;; -p) DRY=1;; -D) REMOVE=1;; -nD) REMOVE=0;; -F) FORCE=1;; -colors) NOCOLORS=0; update_colors;; -nocolors) NOCOLORS=1; update_colors;; -g) REPLAY_GAIN=1;; -ng) REPLAY_GAIN=0;; -s) SAVE=1;; -h|--help|-help) eval "$msg \"${HELP}\""; exit 0;; -v|--version) $msg "split2${FORMAT} version: ${VERSION}\n\n"; shntool -v 2>&1 | grep '^shntool'; flac --version 2>/dev/null; wavpack --help 2>&1 | grep 'Version'; mac 2>&1 | grep '(v '; faac -h 2>&1 | grep '^FAAC'; oggenc --version 2>/dev/null; lame --version | grep '^LAME'; exit 0;; -*) eval "$msg \"${HELP}\""; emsg "\nUnknown option $1\n"; exit 1;; *) if [ -n "${INPATH}" ]; then eval "$msg \"${HELP}\"" emsg "\nUnknown option $1\n" exit 1 elif [ ! -r "$1" ]; then emsg "Unable to read $1\n" exit 2 else INPATH="$1" fi;; esac shift done eval "export ENCARGS_${FORMAT}=\"${ENCARGS}\"" # save configuration if needed if [ ${SAVE} -eq 1 ]; then echo "DIR=\"${DIR}\"" > "${CONFIG}" echo "OUTPATTERN=\"${OUTPATTERN}\"" >> "${CONFIG}" echo "COPYMASKS=\"${COPYMASKS}\"" >> "${CONFIG}" echo "COPYFILES=${COPYFILES}" >> "${CONFIG}" echo "NOSUBDIRS=${NOSUBDIRS}" >> "${CONFIG}" echo "NOPIC=${NOPIC}" >> "${CONFIG}" echo "REMOVE=${REMOVE}" >> "${CONFIG}" echo "PIC_SIZE=${PIC_SIZE}" >> "${CONFIG}" echo "NOCOLORS=${NOCOLORS}" >> "${CONFIG}" echo "REPLAY_GAIN=${REPLAY_GAIN}" >> "${CONFIG}" echo "ENCARGS_flac=\"${ENCARGS_flac}\"" >> "${CONFIG}" echo "ENCARGS_m4a=\"${ENCARGS_m4a}\"" >> "${CONFIG}" echo "ENCARGS_mp3=\"${ENCARGS_mp3}\"" >> "${CONFIG}" echo "ENCARGS_ogg=\"${ENCARGS_ogg}\"" >> "${CONFIG}" echo "ENCARGS_wav=\"${ENCARGS_wav}\"" >> "${CONFIG}" echo "ENCA_ARGS=\"${ENCA_ARGS}\"" >> "${CONFIG}" $msg "${cP}Configuration saved$cZ\n" fi # use flake if possible command -v flake >/dev/null && FLAC_ENCODER="flake" || FLAC_ENCODER="flac" METAFLAC="metaflac --no-utf8-convert" VORBISCOMMENT="vorbiscomment -R -a" command -v mid3v2 >/dev/null && ID3TAG="mid3v2" || ID3TAG="id3tag -2" MP4TAGS="mp4tags" GETTAG="cueprint -n 1 -t" VALIDATE="sed s/[^][[:space:][:alnum:]&_#,.'\"\(\)!-]//g" # check & print output format msg_format="${cG}Output format :$cZ" case ${FORMAT} in flac) $msg "$msg_format FLAC [using ${FLAC_ENCODER} tool]"; enc_help="${FLAC_ENCODER} -h";; m4a) $msg "$msg_format M4A"; enc_help="faac --help";; mp3) $msg "$msg_format MP3"; enc_help="lame --help";; ogg) $msg "$msg_format OGG VORBIS"; enc_help="oggenc --help";; wav) $msg "$msg_format WAVE"; enc_help="echo Sorry, no arguments available for this encoder";; *) emsg "Unknown output format \"${FORMAT}\"\n"; exit 1;; esac $msg " (${ENCARGS})\n" if [ ${ENCHELP} -eq 1 ]; then ${enc_help} exit 0 fi $msg "${cG}Output dir :$cZ ${DIR:?Output directory was not set}\n" # replaces a tag name with the value of the tag. $1=pattern $2=tag_name $3=tag_value update_pattern_aux () { tag_name="$2" tag_value="$3" expr_match="@${tag_name}" expr_match_opt="[{]\([^}{]*\)${expr_match}\([^}]*\)[}]" echo "$1" | { [ "${tag_value}" ] \ && sed "s/${expr_match_opt}/\1${tag_value}\2/g;s/${expr_match}/${tag_value}/g" \ || sed "s/${expr_match_opt}//g;s/${expr_match}//g"; } } # replaces a tag name with the value of the tag. $1=pattern $2=tag_name $3=tag_value update_pattern () { # replace '/' with '\' and '&' with '\&' for proper sed call tag_name=$(echo "$2" | sed 's,/,\\\\,g;s,&,\\&,g') tag_value=$(echo "$3" | sed 's,/,\\\\,g;s,&,\\&,g') v=$(update_pattern_aux "$1" "${tag_name}" "${tag_value}") update_pattern_aux "$v" "_${tag_name}" $(echo "${tag_value}" | sed "s/ /_/g") } # splits a file split_file () { TMPCUE="${HOME}/.split2flac_XXXXX.cue" FILE="$1" if [ ! -r "${FILE}" ]; then emsg "Can not read the file\n" return 1 fi # search for a cue sheet if not specified if [ -z "${CUE}" ]; then CUE="${FILE}.cue" if [ ! -r "${CUE}" ]; then CUE="${FILE%.*}.cue" if [ ! -r "${CUE}" ]; then # try to extract internal one CUESHEET=$(${METAFLAC} --show-tag=CUESHEET "${FILE}" 2>/dev/null | sed 's/^cuesheet=//;s/^CUESHEET=//') # try WV internal cue sheet [ -z "${CUESHEET}" ] && CUESHEET=$(wvunpack -q -c "${FILE}" 2>/dev/null) # try APE internal cue sheet (omfg!) if [ -z "${CUESHEET}" ]; then APETAGEX=$(tail -c 32 "$1" | cut -b 1-8 2>/dev/null) if [ "${APETAGEX}" = "APETAGEX" ]; then LENGTH=$(tail -c 32 "$1" | cut -b 13-16 | od -t u4 | awk '{printf $2}') 2>/dev/null tail -c ${LENGTH} "$1" | grep -a CUESHEET >/dev/null 2>&1 if [ $? -eq 0 ]; then CUESHEET=$(tail -c ${LENGTH} "$1" | sed 's/.*CUESHEET.//g' 2>/dev/null) [ $? -ne 0 ] && CUESHEET="" fi fi fi if [ -n "${CUESHEET}" ]; then $msg "${cP}Found internal cue sheet$cZ\n" TMPCUE=$(mktemp "${TMPCUE}") CUE="${TMPCUE}" echo "${CUESHEET}" > "${CUE}" TMPCUE="${HOME}/.split2flac_XXXXX.cue" if [ $? -ne 0 ]; then emsg "Unable to save internal cue sheet\n" return 1 fi else unset CUE fi fi fi fi # print cue sheet filename if [ -z "${CUE}" ]; then emsg "No cue sheet\n" return 1 fi # cue sheet charset [ -z "${CHARSET}" ] && CHARSET="utf-8" || $msg "${cG}Cue charset : $cP${CHARSET} -> utf-8$cZ\n" CUESHEET=$(iconv -f "${CHARSET}" -t utf-8 "${CUE}" 2>/dev/null) # try to guess the charset using enca if [ $? -ne 0 ]; then CUESHEET=$(enconv ${ENCA_ARGS} -x utf8 < "${CUE}" 2>/dev/null) fi if [ $? -ne 0 ]; then [ "${CHARSET}" = "utf-8" ] \ && emsg "Cue sheet is not utf-8\n" \ || emsg "Unable to convert cue sheet from ${CHARSET} to utf-8\n" if [ ${NASK} -eq 0 ]; then while [ 1 ]; do echo -n "Please enter the charset (or just press ENTER to ignore) > " read CHARSET [ -z "${CHARSET}" ] && break $msg "${cG}Converted cue sheet:$cZ\n" iconv -f "${CHARSET}" -t utf-8 "${CUE}" || continue echo -n "Is this right? [Y/n] > " read YEP [ -z "${YEP}" -o "${YEP}" = "y" -o "${YEP}" = "Y" ] && break done CUESHEET=$(iconv -f "${CHARSET}" -t utf-8 "${CUE}" 2>/dev/null) fi fi # save converted cue sheet TMPCUE=$(mktemp "${TMPCUE}") CUE="${TMPCUE}" echo "${CUESHEET}" > "${CUE}" if [ $? -ne 0 ]; then emsg "Unable to save converted cue sheet\n" return 1 fi SDIR=$(dirname "${FILE}") # search for a front cover image if [ ${NOPIC} -eq 1 ]; then unset PIC elif [ -z "${PIC}" ]; then # try common names for i in *[Cc]over*.jpg *[Ff]older*.jpg */*[Cc]over*.jpg */*[Ff]older*.jpg; do if [ -r "${SDIR}/$i" ]; then PIC="${SDIR}/$i" break fi done # try to extract internal one if [ -z "${PIC}" ]; then ${METAFLAC} --export-picture-to="${TMPPIC}" "${FILE}" 2>/dev/null if [ $? -ne 0 ]; then unset PIC else PIC="${TMPPIC}" fi fi fi $msg "${cG}Cue sheet :$cZ ${CUE}\n" $msg "${cG}Cover image :$cZ ${PIC:-not set}\n" # file removal warning if [ ${REMOVE} -eq 1 ]; then msg_removal="\n${cR}Also remove original" [ ${FORCE} -eq 1 ] \ && $msg "$msg_removal (WITHOUT ASKING)$cZ\n" \ || $msg "$msg_removal if user says 'y'$cZ\n" fi # files to copy over if [ ${COPYFILES} -eq 1 -a -n "${COPYMASKS}" ]; then $msg "${cG}Copy over :$cZ ${COPYMASKS}\n" fi # get common tags TAG_ARTIST=$(${GETTAG} %P "${CUE}" 2>/dev/null) TAG_ALBUM=$(${GETTAG} %T "${CUE}" 2>/dev/null) TRACKS_NUM=$(${GETTAG} %N "${CUE}" 2>/dev/null) # some cue sheets may have non-audio tracks # we can check the difference between what cuebreakpoints and cueprint gives us BREAKPOINTS_NUM=$(($(cuebreakpoints "${CUE}" 2>/dev/null | wc -l) + 1)) # too bad, we can't fix that in a _right_ way if [ ${BREAKPOINTS_NUM} -lt ${TRACKS_NUM} ]; then emsg "'cueprint' tool reported ${TRACKS_NUM} tracks, " emsg "but there seem to be only ${BREAKPOINTS_NUM} audio ones\n" emsg "Sorry, there is no any helpful options in the 'cueprint' tool for this problem.\n" emsg "You probably remove non-audio tracks from the cue sheet (\"${CUE}\") by hand.\n" return 1 fi if [ -z "${TRACKS_NUM}" ]; then emsg "Failed to get number of tracks from CUE sheet.\n" emsg "There may be an error in the sheet.\n" emsg "Running ${GETTAG} %N \"${CUE}\" produces this:\n" ${GETTAG} %N "${CUE}" return 1 fi TAG_GENRE=$(grep 'REM[ \t]\+GENRE[ \t]\+' "${CUE}" | head -1 | sed 's/REM[ \t]\+GENRE[ \t]\+//;s/^"\(.*\)"$/\1/') YEAR=$(awk '{ if (/REM[ \t]+DATE/) { printf "%i", $3; exit } }' < "${CUE}") YEAR=$(echo ${YEAR} | tr -d -c '[:digit:]') unset TAG_DATE if [ -n "${YEAR}" ]; then [ ${YEAR} -ne 0 ] && TAG_DATE="${YEAR}" fi $msg "\n${cG}Artist :$cZ ${TAG_ARTIST}\n" $msg "${cG}Album :$cZ ${TAG_ALBUM}\n" [ "${TAG_GENRE}" ] && $msg "${cG}Genre :$cZ ${TAG_GENRE}\n" [ "${TAG_DATE}" ] && $msg "${cG}Year :$cZ ${TAG_DATE}\n" $msg "${cG}Tracks :$cZ ${TRACKS_NUM}\n\n" # those tags won't change, so update the pattern now DIR_ARTIST=$(echo "${TAG_ARTIST}" | ${VALIDATE}) DIR_ALBUM=$(echo "${TAG_ALBUM}" | ${VALIDATE}) PATTERN=$(update_pattern "${OUTPATTERN}" "artist" "${DIR_ARTIST}") PATTERN=$(update_pattern "${PATTERN}" "album" "${DIR_ALBUM}") PATTERN=$(update_pattern "${PATTERN}" "genre" "${TAG_GENRE}") PATTERN=$(update_pattern "${PATTERN}" "year" "${TAG_DATE}") PATTERN=$(update_pattern "${PATTERN}" "ext" "${FORMAT}") # construct output directory name OUT="${DIR}" if [ ${NOSUBDIRS} -eq 0 ]; then # add path from the pattern path=$(dirname "${PATTERN}") [ "${path}" != "${PATTERN}" ] && OUT="${OUT}/${path}" fi # shnsplit is retarded enough to break on double slash OUT=$(echo "${OUT}" | sed s,/[/]*,/,g) # remove path from the pattern PATTERN=$(basename "${PATTERN}") $msg "${cP}Saving tracks to $cZ\"${OUT}\"\n" # split to tracks if [ ${DRY} -ne 1 ]; then # remove if empty and create output dir if [ ${NOSUBDIRS} -eq 0 ]; then rmdir "${OUT}" 2>/dev/null mkdir -p "${OUT}" [ $? -ne 0 ] && { emsg "Failed to create output directory ${OUT} (already split?)\n"; return 1; } fi case ${FORMAT} in flac) ENC="flac ${FLAC_ENCODER} ${ENCARGS} - -o %f"; RG="metaflac --add-replay-gain";; m4a) ENC="cust ext=m4a faac ${ENCARGS} -o %f -"; RG="aacgain";; mp3) ENC="cust ext=mp3 lame ${ENCARGS} - %f"; RG="mp3gain";; ogg) ENC="cust ext=ogg oggenc ${ENCARGS} - -o %f"; RG="vorbisgain -a";; wav) ENC="wav ${ENCARGS}"; REPLAY_GAIN=0;; *) emsg "Unknown output format ${FORMAT}\n"; exit 1;; esac # split to tracks # sed expression is a fix for "shnsplit: error: m:ss.ff format can only be used with CD-quality files" cuebreakpoints "${CUE}" 2>/dev/null | \ sed 's/$/0/' | \ shnsplit -O never -o "${ENC}" -d "${OUT}" -t "%n" "${FILE}" if [ $? -ne 0 ]; then emsg "Failed to split\n" return 1 fi # prepare cover image if [ -n "${PIC}" ]; then convert "${PIC}" -resize "${PIC_SIZE}" "${TMPPIC}" if [ $? -eq 0 ]; then PIC="${TMPPIC}" else $msg "${cR}Failed to convert cover image$cZ\n" unset PIC fi fi fi # set tags and rename $msg "\n${cP}Setting tags$cZ\n" i=1 while [ $i -le ${TRACKS_NUM} ]; do TAG_TITLE=$(cueprint -n $i -t %t "${CUE}" 2>/dev/null) FILE_TRACK="$(printf %02i $i)" FILE_TITLE=$(echo "${TAG_TITLE}" | ${VALIDATE}) f="${OUT}/${FILE_TRACK}.${FORMAT}" TAG_PERFORMER=$(cueprint -n $i -t %p "${CUE}" 2>/dev/null) if [ -n "${TAG_PERFORMER}" -a "${TAG_PERFORMER}" != "${TAG_ARTIST}" ]; then $msg "$i: $cG${TAG_PERFORMER} - ${TAG_TITLE}$cZ\n" else TAG_PERFORMER="${TAG_ARTIST}" $msg "$i: $cG${TAG_TITLE}$cZ\n" fi FINAL=$(update_pattern "${OUT}/${PATTERN}" "title" "${FILE_TITLE}") FINAL=$(update_pattern "${FINAL}" "performer" "${TAG_PERFORMER}") FINAL=$(update_pattern "${FINAL}" "track" "${FILE_TRACK}") if [ ${DRY} -ne 1 -a "$f" != "${FINAL}" ]; then mv "$f" "${FINAL}" if [ $? -ne 0 ]; then emsg "Failed to rename track file\n" return 1 fi fi if [ ${DRY} -ne 1 ]; then case ${FORMAT} in flac) ${METAFLAC} --remove-all-tags \ --set-tag="ARTIST=${TAG_PERFORMER}" \ --set-tag="ALBUM=${TAG_ALBUM}" \ --set-tag="TITLE=${TAG_TITLE}" \ --set-tag="TRACKNUMBER=$i" \ --set-tag="TRACKTOTAL=${TRACKS_NUM}" \ "${FINAL}" >/dev/null RES=$? [ "${TAG_GENRE}" ] && { ${METAFLAC} --set-tag="GENRE=${TAG_GENRE}" "${FINAL}" >/dev/null; RES=$RES$?; } [ "${TAG_DATE}" ] && { ${METAFLAC} --set-tag="DATE=${TAG_DATE}" "${FINAL}" >/dev/null; RES=$RES$?; } [ "${PIC}" ] && { ${METAFLAC} --import-picture-from="${PIC}" "${FINAL}" >/dev/null; RES=$RES$?; } ;; mp3) ${ID3TAG} --artist="${TAG_PERFORMER}" \ --album="${TAG_ALBUM}" \ --song="${TAG_TITLE}" \ --track="$i" \ "${FINAL}" >/dev/null RES=$? [ "${TAG_GENRE}" ] && { ${ID3TAG} --genre="${TAG_GENRE}" "${FINAL}" >/dev/null; RES=$RES$?; } [ "${TAG_DATE}" ] && { ${ID3TAG} --year="${TAG_DATE}" "${FINAL}" >/dev/null; RES=$RES$?; } ;; ogg) ${VORBISCOMMENT} "${FINAL}" \ -t "ARTIST=${TAG_PERFORMER}" \ -t "ALBUM=${TAG_ALBUM}" \ -t "TITLE=${TAG_TITLE}" \ -t "TRACKNUMBER=$i" \ -t "TRACKTOTAL=${TRACKS_NUM}" >/dev/null RES=$? [ "${TAG_GENRE}" ] && { ${VORBISCOMMENT} "${FINAL}" -t "GENRE=${TAG_GENRE}" >/dev/null; RES=$RES$?; } [ "${TAG_DATE}" ] && { ${VORBISCOMMENT} "${FINAL}" -t "DATE=${TAG_DATE}" >/dev/null; RES=$RES$?; } ;; m4a) ${MP4TAGS} "${FINAL}" \ -a "${TAG_PERFORMER}" \ -A "${TAG_ALBUM}" \ -s "${TAG_TITLE}" \ -t "$i" \ -T "${TRACKS_NUM}" >/dev/null RES=$? [ "${TAG_GENRE}" ] && { ${MP4TAGS} "${FINAL}" -g "${TAG_GENRE}" >/dev/null; RES=$RES$?; } [ "${TAG_DATE}" ] && { ${MP4TAGS} "${FINAL}" -y "${TAG_DATE}" >/dev/null; RES=$RES$?; } [ "${PIC}" ] && { ${MP4TAGS} "${FINAL}" -P "${PIC}" >/dev/null; RES=$RES$?; } ;; wav) RES=0 ;; *) emsg "Unknown output format ${FORMAT}\n" return 1 ;; esac if [ ${RES} -ne 0 ]; then emsg "Failed to set tags for track\n" return 1 fi fi $msg " -> ${cP}${FINAL}$cZ\n" i=$(($i + 1)) done # adjust gain if [ ${REPLAY_GAIN} -ne 0 ]; then $msg "\n${cP}Adjusting gain$cZ\n" if [ ${DRY} -ne 1 ]; then ${RG} "${OUT}/"*.${FORMAT} >/dev/null if [ $? -ne 0 ]; then emsg "Failed to adjust gain for track\n" return 1 fi fi fi # copy files if [ ${COPYFILES} -eq 1 -a "${COPYMASKS}" ]; then old=`pwd` cd "${SDIR}" $msg "\n${cG}Copying files:$cZ\n" eval "for i in ${COPYMASKS}; do \ test -r \"\$i\" && \ echo \" +> \$i\" 2>/dev/null; done" cd "${old}" if [ ${DRY} -ne 1 ]; then eval "for i in ${COPYMASKS}; do \ test -r/\"${SDIR}/\$i\" && \ cp -r \"${SDIR}/\$i\" \"\${OUT}/\"; done" fi fi rm -f "${TMPPIC}" rm -f "${TMPCUE}" if [ ${DRY} -ne 1 -a ${REMOVE} -eq 1 ]; then YEP="n" if [ ${FORCE} -ne 1 ]; then echo -n "Are you sure you want to delete original? [y/N] > " read YEP fi [ "${YEP}" = "y" -o "${YEP}" = "Y" -o ${FORCE} -eq 1 ] && rm -f "${FILE}" fi return 0 } # searches for files in a directory and splits them split_collection () { rm -f "${FAILED}" NUM_FAILED=0 OLDIFS=${IFS} OLDCHARSET="${CHARSET}" # set IFS to newline. we do not use 'read' here because we may want to ask user for input IFS=" " for FILE in `find "$1" -iname '*.flac' -o -iname '*.ape' -o -iname '*.tta' -o -iname '*.wv' -o -iname '*.wav'`; do IFS=${OLDIFS} CHARSET=${OLDCHARSET} $msg "$cG>> $cC\"${FILE}\"$cZ\n" unset PIC CUE split_file "${FILE}" if [ ! $? -eq 0 ]; then emsg "Failed to split \"${FILE}\"\n" echo "${FILE}" >> "${FAILED}" NUM_FAILED=$((${NUM_FAILED} + 1)) fi echo done if [ ${NUM_FAILED} -ne 0 ]; then emsg "${NUM_FAILED} file(s) failed to split (already split?):\n" $msg "${cR}\n" sort "${FAILED}" -o "${FAILED}" cat "${FAILED}" emsg "\nThese files are also listed in ${FAILED}.\n" return 1 fi return 0 } if [ -d "${INPATH}" ]; then if [ ! -x "${INPATH}" ]; then emsg "Directory \"${INPATH}\" is not accessible\n" exit 2 fi $msg "${cG}Input dir :$cZ ${INPATH}$cZ\n\n" split_collection "${INPATH}" elif [ -n "${INPATH}" ]; then split_file "${INPATH}" else emsg "No input filename given. Use -h for help.\n" exit 1 fi # exit code of split_collection or split_file STATUS=$? $msg "\n${cP}Finished$cZ\n" [ ${STATUS} -ne 0 ] && exit 3 || exit 0 ### Local Variables: *** ### mode:sh *** ### tab-width:4 *** ### End: ***