### vim:ft=zsh:foldmethod=marker
### use your favorite editor to edit tags of audio files
### This supports the file-types and tags atag() supports.
###
### Frank Terbeck <ft@bewatermyfriend.org>
### Last-Modified: Mon Mar 10 10:45:50 2008
###
### URI: <http://ft.bewatermyfriend.org/comp/zsh.html>
###
emulate -L zsh
setopt extendedglob
setopt nullglob
setopt noksharrays
# variables {{{
local ATAGEDITOR tmpfile afile force dryrun line tmp usage
local -a atag_options tags
local -A tag_table
tag_table=(
ARTIST ar
ALBUM al
TRACKNUMBER tn
TRACKTITLE tt
YEAR y
COMPILATION comp
GENRE g
)
usage='atag-editor [-d|-f|-v] <FILE(s)>
Load the tags for the specified audio files, list them
in a file. Open that file in an editor. Re-Load the tags
from that file and set them for the according files.
Options:
-d run tag setting via atag() in dry run mode
-f hand the force option for tag setting (see atag()'\''s help)
-v run verbosely
-h this help text
'
ATAGEDITOR="${ATAGEDITOR:-"${VISUAL:-"${EDITOR}"}"}"
#}}}
# functions {{{
function ae_printf() {
local format=$1 ; shift
printf "${format}" "$@" >> "${tmpfile}"
}
function ae_addfile() {
ae_printf '# %s\n' ${1}
}
function ae_data() {
ae_printf '%s=%s\n' ${1} ${2}
}
function ae_writeheader() {
ae_printf '### atag-editor\n###\n'
ae_printf '### edit the tags to your needs\n'
ae_printf '### empty lines and lines starting with three #-signs are ignored.\n'
ae_printf '### lines starting with '\''# '\'' define the start of a new file.\n'
ae_printf '### valid tags: ARTIST, ALBUM, TRACKNUMBER, TRACKTITLE,\n'
ae_printf '### YEAR, COMPILATION and GENRE.\n'
ae_printf '### if you wish to do nothing, uncomment the next line.\n'
ae_printf '#atag-editor-EXIT\n'
}
function cleanup() {
rm "${tmpfile}"
}
function notags() {
local old=$1 new=$2
printf '%s: No tags defined. Skipping.\n' ${old}
afile=${new}
}
TRAPINT TRAPHUP TRAPQUIT() {
printf 'Caught fatal signal (%s).\n' "$1"
printf 'Removing tempfile (%s).\n' "${tmpfile}"
rm "${tmpfile}"
printf 'Bailing out.\n'
return $(( 128 + $1 ))
}
#}}}
# main() {{{
(( force = 0 ))
(( dryrun = 0 ))
(( verbose = 0 ))
while [[ $1 == -* ]] ; do
case $1 in
(-h)
printf '%s' ${usage}
return 0;;
(-d)
dryrun=1 ; shift;;
(-f)
force=1 ; shift;;
(-v)
verbose=1 ; shift;;
(*)
printf "unknown option %s\n\n" "$1"
printf "${usage}"
return 1;;
esac
done
if [[ $# -eq 0 ]] ; then
printf '%s' ${usage}
return 0
fi
atag_options=()
(( dryrun > 0 )) && atag_options+=(-d)
(( force > 0 )) && atag_options+=(-f)
(( no = 0 ))
printf 'Creating data file...\n'
tmpfile="$(mktemp -t atag-editor.XXXXXXXXXX)"
if [[ $? != 0 ]] ; then
printf 'Could not create temporary file. Giving up.\n'
return 1
fi
ae_writeheader
for afile in "$@" ; do
printf ' . processing '\''%s'\''\n' ${afile}
atag ${afile} -e
if [[ $? != 0 ]] ; then
printf ' + ERROR while processing file. Skipping.\n'
continue
fi
(( no++ ))
ae_printf '\n'
ae_addfile ${afile}
ae_data ARTIST ${_ar}
ae_data ALBUM ${_al}
ae_data TRACKNUMBER ${_tn}
ae_data TRACKTITLE ${_tt}
ae_data YEAR ${_yr}
ae_data COMPILATION ${_comp}
ae_data GENRE ${_gr}
done
printf '\n'
if (( no == 0 )) ; then
printf 'All given files were invalid. Giving up early.\n'
cleanup
return 1
fi
printf 'Spawning editor (%s)...\n' ${ATAGEDITOR}
${ATAGEDITOR} ${tmpfile}
printf 'Processing new data file...\n'
afile=''
tags=()
while IFS='' read -r line ; do
case ${line} in
(('#'|)atag-editor-EXIT)
if [[ ${line} != '#'* ]] ; then
printf 'Exit command found. Stopping processing.\n'
cleanup
return 0
fi
continue
;;
("###"*|[ $'\t']#)
continue
;;
((#b)"#" (*))
tmp=${match[1]}
if [[ -z ${afile} ]] ; then
afile=${tmp}
continue
fi
if (( ${#tags} == 0 )) ; then
notags ${afile} ${tmp}
continue
fi
(( verbose > 0 )) && \
print -- atag ${(qqq)afile} ${atag_options} ${(@qqq)tags}
atag ${afile} ${atag_options} ${tags}
afile=${tmp}
tags=()
;;
((#b)(ARTIST|ALBUM|TRACKNUMBER|TRACKTITLE|YEAR|COMPILATION|GENRE)=(*))
tags+="${tag_table[${match[1]}]}=${match[2]}"
;;
(*)
printf 'Broken line (%s). Ignoring.\n' ${line}
;;
esac
done < ${tmpfile}
# set the last file
if (( ${#tags} == 0 )) ; then
notags ${afile} ""
fi
if [[ -n ${afile} ]] ; then
(( verbose > 0 )) && \
print -- atag ${(qqq)afile} ${atag_options} ${(@qqq)tags}
atag ${afile} ${atag_options} ${tags}
fi
cleanup
# }}}