Last active
January 12, 2025 12:07
-
-
Save Malvineous/966f56d2df95e8e9f16f362fadb1f91f to your computer and use it in GitHub Desktop.
Bash script to apply a regex to Ogg Vorbis tags, and rename the files to match the tags, showing a diff of what it changed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Apply regular expressions to Ogg Vorbis tags and filenames. | |
# Run with -h for help. | |
# https://gist.github.com/Malvineous/966f56d2df95e8e9f16f362fadb1f91f | |
# | |
set -e | |
# Defaults | |
ALBUM_FIRST=0 | |
FULL_ARTIST=0 | |
DRYRUN=0 | |
RENAME=1 | |
TAG=1 | |
function help() { | |
echo "Apply regular expressions to Ogg Vorbis tags and filenames." | |
echo "" | |
echo "vorbis-retag-regex.sh [options] <regex> *.ogg" | |
echo "" | |
echo " options:" | |
echo " -a Rename files to show album first" | |
echo " -c Don't truncate artist in filename at second comma" | |
echo " -n Dry run/preview, don't modify or rename any files" | |
echo " -r Don't rename files at all (e.g. if name is too long)" | |
echo " -t Don't retag, just rename (i.e. apply regex to filename only)" | |
echo "" | |
echo " regex: sed expression over multiline tags, blank (\"\") to leave tags unmodified, e.g." | |
echo " 's/\(title=\).*/\1New title/' <= Replace title with 'New title'" | |
echo " 's/\(artist=\).*/\1New artist/' <= Replace artist with 'New artist'" | |
echo " 's/\(album=\).*/\1New album/' <= Replace album with 'New album'" | |
echo " '/tracknumber/a date=2000' <= Add new 'date=2000' tag after tracknumber tag" | |
echo " '/^year=/ { d }' <= Completely remove 'year' tag" | |
echo " 's/^\([A-Z_][^=]\+\)=/\L&/' <= Convert all tag names to lowercase" | |
echo " 's/\(\( \(A\|At\|In\|Of\|On\|The\|For\|And\)\)\+ \)/\L\1/g' <= Convert short words to lowercase" | |
echo "" | |
echo " examples:" | |
echo " # Rename all files based on existing tags (dry run, no files changed)" | |
echo " ./vorbis-retag-regex.sh -n '' *.ogg" | |
echo "" | |
echo " # Change album tag and rename files to match" | |
echo " ./vorbis-retag-regex.sh 's/\(album=\).*/\1My Songs/' *.ogg" | |
echo "" | |
echo "Last-modified dates on files are left unchanged." | |
} | |
if [ "$1" == "" ]; then | |
help | |
exit | |
fi | |
while true; do | |
case "$1" in | |
-a) | |
ALBUM_FIRST=1 | |
shift | |
;; | |
-c) | |
FULL_ARTIST=1 | |
shift | |
;; | |
-n) | |
DRYRUN=1 | |
shift | |
;; | |
-r) | |
RENAME=0 | |
shift | |
;; | |
-t) | |
TAG=0 | |
shift | |
;; | |
-h) | |
help | |
exit | |
;; | |
*) | |
break | |
;; | |
esac | |
done | |
REGEX=$1 | |
shift | |
for I in "$@"; do | |
T_ORIG=`vorbiscomment -e "$I"` | |
# Get new tags | |
if [ "$REGEX" != "" ]; then | |
T_NEW=`echo "$T_ORIG" | sed "$REGEX"` | |
else | |
T_NEW="$T_ORIG" | |
fi | |
# Get new name | |
TAGS=`echo "$T_NEW" | sed 'y|/|⁄|'` | |
TITLE=`echo "$TAGS" | grep -i -e '^title=' | cut -d= -f2` | |
ARTIST=`echo "$TAGS" | grep -i -e '^artist=' | cut -d= -f2` | |
if [ $FULL_ARTIST -eq 0 ]; then | |
# Chop off the artist at the second comma, so if multiple artists are | |
# specified, only the first two end up in the filename in order to stop them | |
# from becoming too long and hitting filename length limits. | |
ARTIST=`echo "$ARTIST" | sed 's/^\([^,]*,[^,]*\),.*$/\1/'` | |
fi | |
ALBUM=`echo "$TAGS" | grep -i -e '^album=' | cut -d= -f2` | |
TRACK=`echo "$TAGS" | grep -i -e '^tracknumber=' | cut -d= -f2` | |
if [ "$TRACK" == "" ]; then | |
TRACK=0 | |
TRACKZ=00 | |
else | |
TRACKZ=`printf %02d $[10#$TRACK]` | |
fi | |
if [ $ALBUM_FIRST -eq 0 ]; then | |
F_NEW="${ARTIST} - ${ALBUM} - ${TRACKZ} - ${TITLE}.ogg" | |
else | |
F_NEW="${ALBUM} - ${TRACKZ} - ${ARTIST} - ${TITLE}.ogg" | |
fi | |
if [ "$TITLE" == "" ]; then | |
echo "ERROR: Missing title tag: $I" > /dev/stderr | |
continue | |
fi | |
if [ "$ARTIST" == "" ]; then | |
echo "ERROR: Missing artist tag: $I" > /dev/stderr | |
continue | |
fi | |
if [ "$ALBUM" == "" ]; then | |
echo "ERROR: Missing album tag: $I" > /dev/stderr | |
continue | |
fi | |
echo | |
if [ "$I" != "$F_NEW" ] && [ "$RENAME" -eq 1 ]; then | |
echo -e "\e[30;101m$I\e[0m" | |
echo -e "\e[30;102m$F_NEW\e[0m" | |
else | |
echo -e "\e[30;104m$I\e[0m" | |
fi | |
if [ "$REGEX" != "" ] && [ $TAG -eq 1 ]; then | |
diff --color=always -Nru <(echo "$T_ORIG") <(echo "$T_NEW") | tail -n +4 | |
fi | |
if [ $DRYRUN -eq 0 ]; then | |
if [ "$REGEX" != "" ] && [ $TAG -eq 1 ]; then | |
echo "$T_NEW" | vorbiscomment -w "$I" _retag_out.ogg | |
touch -r "$I" _retag_out.ogg && mv _retag_out.ogg "$I" | |
fi | |
if [ "$I" != "$F_NEW" ] && [ "$RENAME" -eq 1 ]; then | |
mv "$I" "$F_NEW" | |
fi | |
fi | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment