├── README.md ├── COPYING └── tagedit.sh /README.md: -------------------------------------------------------------------------------- 1 | tagedit 2 | ======= 3 | 4 | This, program, based on the fantastic vorbistagedit, written by martin f. krafft 5 | and included with the vorbis-tools package, allows a person to batch edit 6 | metadata within ogg and mp3 files from the person's preferred text editor. 7 | 8 | The basic usage is thus: 9 | 10 | tagedit ... 11 | 12 | A file containing all the current tags within each file is opened within the 13 | user's $EDITOR. The tags can be edited directly within the file. When the file 14 | is saved, and the $EDITOR is closed, the tags are written back to the file. 15 | 16 | Any vorbis comments are written back to the ogg file completely, i.e., the 17 | original vorbis comments are lost. 18 | 19 | ID3 tags, on the other hand, are appended to the current metadata. 20 | 21 | The actual tag writing requires vorbiscomment and id3v2 to be installed on the 22 | user's system, and within the $PATH. 23 | 24 | Plans 25 | ----- 26 | 27 | I'd like to make the program modular, so that support for additional formats can 28 | be more easily added. I plan to add that feature to the next version. 29 | 30 | Bugs/Features 31 | ------------- 32 | 33 | Please report any bugs, or request new features at the 34 | [Issue Tracker](https://github.com/goodevilgenius/tagedit/issues) on the 35 | project's [GitHub](https://github.com/goodevilgenius/tagedit) page. 36 | 37 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright © 2012, Daniel Ray Jones 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * The name of the author may not be used to endorse or promote products 12 | derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 22 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /tagedit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -eu 2 | 3 | # tagedit -- allows batch editing of vorbis comments and id3 tags with an editor 4 | # 5 | # Copyright © Dan Jones 6 | # Released under the terms of the New BSD License 7 | # 8 | # Based on vorbistagedit copyright © martin f. krafft 9 | # 10 | 11 | VERSION=0.6.3 12 | ME=${0##*/} 13 | 14 | versioninfo() { 15 | echo "tagedit $VERSION" >&2 16 | echo "\$Id$" >&2 17 | echo "$ME is copyright © Dan Jones" >&2 18 | echo Released under the terms of the New BSD License >&2 19 | } 20 | 21 | usage() { 22 | versioninfo 23 | echo 24 | echo Usage: $ME file1 [file2 [file3 ...]] >&2 25 | echo .mp3, .oga, .ogg, .ogv, .ogx, and .spx are the >&2 26 | echo supported file extensions >&2 27 | echo 28 | echo If no filenames are given, the list of filenames >&2 29 | echo is read from stdin, one per line. >&2 30 | } 31 | 32 | if [ $# -eq 0 ]; then 33 | usage 34 | exit 1 35 | fi 36 | 37 | for opt in $(getopt -n $ME -l version,help -o Vh? -- $@); do 38 | case $opt in 39 | --version|-V) 40 | versioninfo 41 | exit 0;; 42 | --help|-h|-\?) 43 | usage 44 | exit 0;; 45 | --) :;; 46 | -*) 47 | echo "E: $ME: invalid argument: $opt" >&2 48 | usage 49 | exit 1;; 50 | *) :;; 51 | esac 52 | done 53 | 54 | if ! command -v vorbiscomment >/dev/null; then 55 | echo "E: $ME: vorbiscomment not found in \$PATH." >&2 56 | exit -1 57 | fi 58 | if ! command -v id3v2 >/dev/null; then 59 | echo "E: $ME: id3v2 not found in \$PATH." >&2 60 | exit -1 61 | fi 62 | 63 | old_IFS="$IFS" 64 | IFS=" 65 | " 66 | [ $# -eq 0 ] && set -- $(cat) 67 | IFS="$old_IFS" 68 | 69 | if [ $# -eq 0 ]; then 70 | exit 0 71 | fi 72 | 73 | TMPFILE=$(mktemp /tmp/tagedit.XXXXXX) 74 | trap "rm -f $TMPFILE" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 75 | 76 | cat <<_eof > $TMPFILE 77 | # tagedit (\$Id$) 78 | # 79 | # Edit the lines in this file to your desire, but 80 | # DO NOT touch lines starting with a colon (:)! 81 | # You may use lines starting with a plus (+) to rename files. 82 | # 83 | # ID3 tags are appended to the current tags, rather than 84 | # replacing all tags, as with vorbis comments. 85 | # Therefore, to remove an ID3 tag, simply set it to an 86 | # empty value. 87 | # 88 | # ID3 comments (COMM) should be formatted as 89 | # ::, where lng is a three-letter 90 | # language code, e.g., eng. should not have any colons 91 | # (:) in it, due to a limitation of id3v2. 92 | # 93 | # We are in directory: 94 | # $(pwd) 95 | # 96 | # Tags that should be applied to all files can be specified 97 | # before the first per-file tag definiton starts. 98 | # Be aware that using global tags when mixing id3 tags and 99 | # vorbis comments can have unexpected results. 100 | 101 | _eof 102 | 103 | for i in "$@"; do 104 | case "$i" in 105 | *.ogg|*.oga|*.ogv|*.ogx|*.spx|*.mp3) 106 | if [ ! -r "$i" ]; then 107 | echo "E: $ME: unreadable file: $i" >&2 108 | exit 2 109 | fi 110 | 111 | if [ ! -w "$i" ]; then 112 | echo "E: $ME: unwriteable file: $i" >&2 113 | exit 3 114 | fi 115 | 116 | echo ": $i" 117 | echo "+ $i" 118 | if [ "${i##*.}" = "mp3" ];then 119 | id3v2 -R "$i" | sed -nr \ 120 | -e 's/^(COMM): \((.*)\)\[(.*)\]: (.*)/\1=\2:\4:\3/p' \ 121 | -e 's/^(TCON): (.*) \([0-9]+\)/\1=\2/p' \ 122 | -e 's/^([A-Z0-9]{3,4}): (.+)/\1=\2/p' | egrep -v '^(PRIV|APIC)' || true 123 | else 124 | vorbiscomment -l "$i" 125 | fi 126 | echo 127 | ;; 128 | 129 | *) 130 | echo "E: $ME: invalid argument: $i" >&2 131 | exit 1 132 | ;; 133 | esac 134 | done >> $TMPFILE 135 | echo : EOF >> $TMPFILE 136 | 137 | MD5SUM=$(md5sum $TMPFILE) 138 | 139 | [ -n "${DISPLAY:-}" ] && [ -n "${VISUAL:-}" ] && EDITOR="$VISUAL" 140 | if [ -z "${EDITOR:-}" ]; then 141 | for i in sensible-editor editor vim emacs nano vi; do 142 | P="$(command -v $i)" 143 | [ -x "$P" ] && EDITOR="$P" && break 144 | done 145 | fi 146 | 147 | if [ -z "${EDITOR}" ]; then 148 | echo "E: $ME: no editor found." >&2 149 | exit 4 150 | fi 151 | 152 | eval $EDITOR $TMPFILE 153 | 154 | if echo "$MD5SUM" | md5sum -c >/dev/null 2>&1; then 155 | echo "I: $ME: no changes, exiting..." >&2 156 | exit 0 157 | fi 158 | 159 | tags='' 160 | 161 | echo "I: processing files..." >&2 162 | 163 | write_tags() { 164 | echo -n "I: processing $file... " >&2 165 | local file="$1"; shift 166 | if [ "${file##*.}" = "mp3" ]; then 167 | while [ $# -gt 0 ]; do 168 | echo "$1" | while read tag; do 169 | [ -z "$tag" ] && continue 170 | id3v2 --"${tag%%=*}" "${tag#*=}" "$file" 171 | done 172 | shift 173 | done 174 | else 175 | for tag; do [ -n "${tag:-}" ] && echo "$tag"; done | \ 176 | vorbiscomment -w "$file" 177 | fi 178 | if [ -n "${filename_new:-}" ] && [ "${filename_new:-}" != "$file" ]; then 179 | echo; echo -n "I: renaming to $filename_new... " >&2 180 | mv "$file" "$filename_new" 181 | unset filename_new 182 | fi 183 | } 184 | 185 | filename_new= 186 | global_tags= 187 | 188 | while read line; do 189 | case "$line" in 190 | ': EOF') 191 | write_tags "$file" "$global_tags" "$tags" 192 | echo "done." >&2 193 | ;; 194 | 195 | :*) 196 | if [ -n "${file:-}" ]; then 197 | write_tags "$file" "$global_tags" "$tags" 198 | echo "done." >&2 199 | tags='' 200 | fi 201 | file="${line#: }" 202 | ;; 203 | 204 | +*) 205 | filename_new="${line#* }";; 206 | 207 | *=*) 208 | if [ -z "${file:-}" ]; then # global scope 209 | global_tags="${global_tags:+$global_tags 210 | }$line" 211 | else # file scope 212 | tags="${tags:+$tags 213 | }$line" 214 | fi 215 | ;; 216 | 217 | *|'#*') :;; 218 | esac 219 | done < $TMPFILE 220 | 221 | echo "I: done." >&2 222 | 223 | rm -f $TMPFILE 224 | trap - 0 225 | 226 | exit 0 227 | --------------------------------------------------------------------------------