From 0a754167ad77ce530d13704fae61175b40be56b3 Mon Sep 17 00:00:00 2001 From: fabs Date: Sat, 12 Dec 2020 00:09:09 +0100 Subject: [PATCH] initial ok --- cuetag.sh | 249 ++++++++++++++++++++++++++++++++++++++++++++++ music_tagmove | 7 +- music_tagmove_lib | 34 ++++--- 3 files changed, 269 insertions(+), 21 deletions(-) create mode 100755 cuetag.sh diff --git a/cuetag.sh b/cuetag.sh new file mode 100755 index 0000000..9bc5c0e --- /dev/null +++ b/cuetag.sh @@ -0,0 +1,249 @@ +#! /bin/bash + +# cuetag.sh - tag files based on cue/toc file information +# uses cueprint output +# usage: cuetag.sh [file]... + +CUEPRINT=cueprint +cue_file="" + +function check_required { + local err= + for var in ${@}; do + if eval "[[ -z \$$var ]]"; then + >&2 echo "CUETAG: Tag $var required but zero" + err=1 + fi + done + + if [[ -n $err ]]; then + exit 1 + fi +} + +# print usage instructions +usage() +{ + echo "usage: cuetag.sh [file]..." + echo + echo "cuetag.sh adds tags to files based on cue or toc information" + echo + echo "Supported formats (format extension, format name, tagging utility):" + echo "ogg, Ogg Vorbis, vorbiscomment" + echo "flac, FLAC, metaflac" + echo "mp3, MP3, mp3info" + echo "txt, Vorbis Comment Text File, tee" + echo + echo "cuetag.sh uses cueprint, which must be in your path" +} + +# Vorbis Comments +# for FLAC and Ogg Vorbis files +vorbis() +{ + trackno=$1; shift + file="$1"; shift + fields="$@" + + # FLAC tagging + # --remove-all-tags overwrites existing comments + METAFLAC="metaflac --remove-all-tags --import-tags-from=-" + + # Ogg Vorbis tagging + # -w overwrites existing comments + # -a appends to existing comments + VORBISCOMMENT="vorbiscomment -w -c -" + + # VC text file format + # TODO: this also outputs to stdout + TXTFILE="tee" + + case "$file" in + *.[Ff][Ll][Aa][Cc]) + VORBISTAG=$METAFLAC + ;; + *.[Oo][Gg][Gg]) + VORBISTAG=$VORBISCOMMENT + ;; + *.[Tt][Xx][Tt]) + VORBISTAG=$TXTFILE + ;; + esac + + # space separated list of recommended standard field names + # see http://www.xiph.org/ogg/vorbis/doc/v-comment.html + # TRACKTOTAL is not in the Xiph recommendation, but is in common use + + [ -n "$fields" ] || + fields='TITLE VERSION ALBUM TRACKNUMBER TRACKTOTAL ARTIST PERFORMER COPYRIGHT LICENSE ORGANIZATION DESCRIPTION GENRE DATE LOCATION CONTACT ISRC' + + # fields' corresponding cueprint conversion characters + # separate alternates with a space + + TITLE='%t' + VERSION='' + ALBUM='%T' + TRACKNUMBER='%02n' + TRACKTOTAL='%02N' + ARTIST='%c %p' + PERFORMER='%p' + COPYRIGHT='' + LICENSE='' + ORGANIZATION='' + DESCRIPTION='%m' + # --------------------------------- my hack! --------------------------------- + #GENRE='%g' + #DATE='' + DATE=`sed -n 's!^REM DATE "\?\([^"]*\)"\?!\1!p' "$cue_file" | tr -d '[:space:]'` + GENRE=`sed -n 's!^REM GENRE "\?\([^"]*\)"\?!\1!p' "$cue_file" | tr -d '[:space:]'` + # --------------------------------- my hack! --------------------------------- + LOCATION='' + CONTACT='' + ISRC='%i %u' + + check_required ARTIST DATE ALBUM TRACKNUMBER TITLE + + (for field in $fields; do + case "$field" in + (*=*) echo "$field";; + (*) + value="" + for conv in $(eval echo \$$field); do + + # --------------------------------- my hack! --------------------------------- + case $field in + DATE) value=$DATE + ;; + GENRE) value=$GENRE + ;; + *) value=$($CUEPRINT -n $trackno -t "$conv\n" "$cue_file") + ;; + esac + # --------------------------------- my hack! --------------------------------- + + if [ -n "$value" ]; then + echo "$field=$value" + break + fi + done + ;; + esac + done) | $VORBISTAG "$file" +} + +id3() +{ + MP3TAG=$(which mid3v2) \ + || MP3TAG=$(which id3v2) + if [ -z "${MP3TAG}" ]; then + echo "error: not found '(m)id3v2'." + exit 1 + fi + + # space separated list of ID3 v1.1 tags + # see http://id3lib.sourceforge.net/id3/idev1.html + + fields="TITLE ALBUM ARTIST YEAR COMMENT GENRE TRACKNUMBER" + + # fields' corresponding cueprint conversion characters + # separate alternates with a space + + TITLE='%t' + ALBUM='%T' + ARTIST='%p' + YEAR='' + COMMENT='%c' + GENRE='%g' + TRACKNUMBER='%n' + + for field in $fields; do + case "$field" in + *=*) value="${field#*=}";; + *) + value="" + for conv in $(eval echo \$$field); do + value=$($CUEPRINT -n $1 -t "$conv\n" "$cue_file") + + if [ -n "$value" ]; then + break + fi + done + ;; + esac + + if [ -n "$value" ]; then + case $field in + TITLE) + $MP3TAG -t "$value" "$2" + ;; + ALBUM) + $MP3TAG -A "$value" "$2" + ;; + ARTIST) + $MP3TAG -a "$value" "$2" + ;; + YEAR) + $MP3TAG -y "$value" "$2" + ;; + COMMENT) + $MP3TAG -c "$value" "$2" + ;; + GENRE) + $MP3TAG -g "$value" "$2" + ;; + TRACKNUMBER) + $MP3TAG -T "$value" "$2" + ;; + esac + fi + done +} + +main() +{ + if [ $# -lt 1 ]; then + usage + exit + fi + + cue_file=$1 + shift + + ntrack=$(cueprint -d '%N' "$cue_file") + trackno=1 + + NUM_FILES=0 FIELDS= + for arg in "$@"; do + case "$arg" in + *.*) NUM_FILES=$(expr $NUM_FILES + 1);; + *) FIELDS="$FIELDS $arg";; + esac + done + + if [ $NUM_FILES -ne $ntrack ]; then + echo "warning: number of files does not match number of tracks" + fi + + for file in "$@"; do + case $file in + *.[Ff][Ll][Aa][Cc]) + vorbis $trackno "$file" $FIELDS + ;; + *.[Oo][Gg][Gg]) + vorbis $trackno "$file" $FIELDS + ;; + *.[Mm][Pp]3) + id3 $trackno "$file" $FIELDS + ;; + *.[Tt][Xx][Tt]) + vorbis $trackno "$file" + ;; + *.*) + echo "$file: uknown file type" + ;; + esac + trackno=$(($trackno + 1)) + done +} + +main "$@" diff --git a/music_tagmove b/music_tagmove index 9f3b864..ecbdeda 100755 --- a/music_tagmove +++ b/music_tagmove @@ -2,9 +2,7 @@ scr_dir=$(dirname "$0") -source "$scr_dir/music_tagmove_lib" - - +source "$scr_dir/music_tagmove_lib" source_dir="$1" dest_root="$2" @@ -12,8 +10,7 @@ dest_root="$2" cuesplit_all tagmove -error yanigga -error dududu +cyan echo -e "\n------- EXECUTION COMPLETE -------\n" if print_error_stack; then exit 1 diff --git a/music_tagmove_lib b/music_tagmove_lib index d91cc49..243d41c 100644 --- a/music_tagmove_lib +++ b/music_tagmove_lib @@ -1,4 +1,4 @@ -#!/bin/zsh +#!/bin/bash source bashcols if [[ -z $DIRECTORY_FORMAT ]]; then @@ -9,6 +9,7 @@ if [[ -z $FILE_FORMAT ]]; then FILE_FORMAT='$track $title' fi +cuetag=$(realpath ./cuetag.sh) global_errf= local_errf= @@ -33,20 +34,14 @@ function info { } function error { - >&2 cyan echo -e "\n::: ENTER ERROR" - print_error_stack global_errf=1 local_errf=1 current_error_line=$(printf "%s %s" $(colthis red "[error]") "$*") global_error_stack+=( "$current_error_line" ) - >&2 printf "%s %s\n" $(colthis green "[CURRENT]") "$current_error_line" - - print_error_stack - >&2 cyan echo "::: EXIT ERROR" + >&2 printf "%s\n" "$current_error_line" } -function clr_errf { - local_errf= +function clr_errf { local_errf= } function read_tag { @@ -98,6 +93,7 @@ function cuesplit_single { for flac_file in "${arr_flac[@]}"; do echo -e "\t$flac_file" done + return fi if [[ ${#arr_cue[@]} -gt 1 ]]; then @@ -105,6 +101,7 @@ function cuesplit_single { for cue_file in "${arr_cue[@]}"; do echo -e "\t$cue_file" done + return fi local flac=${arr_flac[0]} @@ -115,10 +112,13 @@ function cuesplit_single { #### cuebreakpoints can't handle it otherwise echo >> "$cue" + ### Strip BOM + bbe -e 's/\xEF\xBB\xBF//' "$cue" -o ".bomstripped.cue" && mv ".bomstripped.cue" "$cue" + if cuebreakpoints "$cue" | shnsplit -o flac "$flac" || \ cuebreakpoints "$cue" | sed 's/$/0/' | shnsplit -o flac "$flac"; then info "Tagging target \"$image_dir\"" - if cuetag.sh "$cue" split-*.flac; then + if $cuetag "$cue" split-*.flac; then info "Renaming source files" mv "$cue" "$cue.ignore" mv "$flac" "$flac.ignore" @@ -133,9 +133,9 @@ function cuesplit_single { } function cuesplit_all { - find "$source_dir" -type f -name "*.cue" | while read -r cue_file; do + while read -r cue_file; do cuesplit_single "$cue_file" - done + done < <(find "$source_dir" -type f -name "*.cue") } function mv_wrap { @@ -170,13 +170,14 @@ function tagmove_single { fi # Set fixed width for track number - track=$(printf "%02d" "$track") + track=$(printf "%02d" "${track#0}") + eval "dest_directory=\"$DIRECTORY_FORMAT\"" eval "dest_file=\"$FILE_FORMAT\"" mkdir -p "$dest_root/$dest_directory" - mv_wrap "$file_name" "$dest_root/$dest_directory/$dest_file.${filename##*.}" + mv_wrap "$file_name" "$dest_root/$dest_directory/$dest_file.${file_name##*.}" } @@ -186,9 +187,10 @@ function tagmove { return fi - find "$source_dir" -type f | while read -r file; do + while read -r file; do if [[ $(file -b --mime-type "$file") =~ ^audio/ ]]; then tagmove_single "$file" fi - done + done < <(find "$source_dir" -type f -not -name "*.ignore") } +