
Description:
Often used alongside mp3-download, an interactive tool for batch injecting and editing MP3 metadata using exiftool and kid3-cli.
Also permits batch renaming of files based on existing metadata.
Usage:
metadata -d, –display ─────── Display current metadata for all MP3s
metadata -i, –inject ─────── Inject metadata from filenames into all MP3s
metadata -r, –rename ─────── Rename MP3s using their embedded metadata
metadata -al, –album <album-name> ─────── Set the album name for all MP3s
metadata -ar, –artist <artist-name> ─────── Set the artist name for all MP3s
metadata -ti, –title <title> <file.mp3> ─────── Set the title for a single MP3
metadata -tr, –track <track> <file.mp3> ─────── Set the track number for a single MP3
metadata -dc, –depend ─────── Run a dependency check
metadata -h, –help ─────── Display this help message
Flags:
metadata -q, –quiet ─────── Suppress metadata display after an operation
Examples:
metadata -ti “New Title” “song.mp3”
metadata -tr 05 “song.mp3”
metadata -al “Album Name”
metadata -ar “Artist Name”
metadata -i
metadata -i -q
metadata -d
Filename formats for –inject:
00 – Artist – Title.mp3
Artist – Title.mp3
#!/bin/bash
#
#
# Dependencies:
# exiftool
# sudo apt install exiftool
#
# sudo apt install kid3-cli
#
set -e
# Set Version
VERSION="metadata 3.0.2"
####################
# COLOUR VARIABLES
####################
# Terminal Formatting
RESET="\033[0m"
BOLD="\033[1m"
# UI Colours
CLR_RED="\033[38;5;196m" # Bright Red
CLR_GREEN="\033[38;5;46m" # Bright Lime Green
CLR_GOLD="\033[38;5;226m" # Gold
CLR_PURPLE="\033[38;5;141m" # Light Purple / Lavender
CLR_LABEL="\033[38;5;81m" # Bright Sky Blue
CLR_LABEL2="\033[38;5;2m" # Dark Forest Green
CLR_PROMPT="${BOLD}\033[38;5;51m" # Aqua + Bold
CLR_TEXT="\033[38;5;254m" # Light Grey (optional)
# Setup Quiet Flag
QUIET=false
for arg in "$@"; do
case "$arg" in
-q | --quiet)
QUIET=true
;;
esac
done
####################
# DEPENDENCY CHECK
####################
dependency_check() {
local depend_found="0"
# Check kid3-cli exists
if ! command -v kid3-cli >/dev/null 2>&1; then
echo -e "${CLR_RED}Error:${RESET} kid3-cli is not installed - Required for updating metadata"
echo
echo "Install it with:"
echo -e "${CLR_TEXT} sudo apt install kid3-cli${RESET}"
echo -e "${CLR_TEXT} or your package manager equivelant${RESET}"
echo
depend_found="1"
fi
# Check exiftool exists
if ! command -v exiftool >/dev/null 2>&1; then
echo
echo -e "${CLR_RED}Error:${RESET} exiftool is not installed - Required for displaying metadata"
echo
echo "Install it with:"
echo -e "${CLR_TEXT} sudo apt install exiftool${RESET}"
echo -e "${CLR_TEXT} or your package manager equivelant${RESET}"
echo
depend_found="1"
fi
if [[ $depend_found -eq "0" && "$1" == "-d" ]]; then
echo ""
echo "───────────────────────────────────────────────────────"
echo -e " ▶ ${CLR_GREEN}All dependencies are met - metadata is ready to use!${RESET}"
echo "───────────────────────────────────────────────────────"
echo ""
exit 0
fi
if [[ $depend_found -eq 1 ]]; then
exit 1
fi
}
if [[ "$1" != "-d" && "$1" != "--depend" ]]; then
dependency_check
fi
####################
# HELP / INFO TEXT
####################
usage() {
echo
echo -e "${CLR_PURPLE}${BOLD}${VERSION}${RESET}"
echo
echo -e "${BOLD}Description:${RESET}${CLR_TEXT}"
echo -e "Often used alongside mp3-download, an interactive tool for batch injecting and editing MP3 metadata using exiftool and kid3-cli."
echo -e "Also permits batch renaming of files based on existing metadata.${RESET}"
echo
echo -e "${BOLD}Usage:${RESET}${CLR_TEXT}"
echo -e " metadata -d, --display ─────── Display current metadata for all MP3s"
echo -e " metadata -i, --inject ─────── Inject metadata from filenames into all MP3s"
echo -e " metadata -r, --rename ─────── Rename MP3s using their embedded metadata"
echo
echo -e " metadata -al, --album <album-name> ─────── Set the album name for all MP3s"
echo -e " metadata -ar, --artist <artist-name> ─────── Set the artist name for all MP3s"
echo
echo -e " metadata -ti, --title <title> <file.mp3> ─────── Set the title for a single MP3"
echo -e " metadata -tr, --track <track> <file.mp3> ─────── Set the track number for a single MP3"
echo
echo -e " metadata -dc, --depend ─────── Run a dependency check"
echo -e " metadata -h, --help ─────── Display this help message${RESET}"
echo
echo -e "${BOLD}Flags:${RESET}${CLR_TEXT}"
echo -e " metadata -q, --quiet ─────── Suppress metadata display after an operation${RESET}"
echo
echo -e "${BOLD}Examples:${RESET}${CLR_TEXT}"
echo -e " metadata -ti \"New Title\" \"song.mp3\""
echo -e " metadata -tr 05 \"song.mp3\""
echo
echo -e " metadata -al \"Album Name\""
echo -e " metadata -ar \"Artist Name\""
echo -e " metadata -i"
echo -e " metadata -i -q"
echo -e " metadata -d${RESET}"
echo
echo -e "${BOLD}Filename formats for --inject:${RESET}${CLR_TEXT}"
echo -e " 00 - Artist - Title.mp3"
echo -e " Artist - Title.mp3${RESET}"
echo
exit 1
}
######################
# HELPER FUNCTINONS
######################
# Catch User CTRL+C Interrupt
handle_interrupt() {
echo
echo -e "${CLR_RED}Cancelled by user${RESET}"
exit 1
}
trap handle_interrupt INT
run_format_select() {
if [[ "$FORMAT" == "1" ]]; then
run_cmd_track
else
run_cmd
fi
}
# EXIT if folder contains no .MP3 files
mp3_check() {
shopt -s nullglob
files=(*.mp3)
if [[ ${#files[@]} -eq 0 ]]; then
echo -e "${CLR_RED}Error: No MP3 files found in this directory.${RESET}"
exit 1
fi
}
success_msg() {
echo
echo "──────────────────────────────"
echo -e "${CLR_GREEN} ▶ Metadata Updated ${RESET}"
echo "──────────────────────────────"
echo
}
######################
# FUNCTINONS
######################
run_cmd() {
echo
echo -e "${CLR_PURPLE} ▶ Injecting Metadata, please wait a moment...${RESET}"
for filename in *.mp3; do
TRACK_ARTIST=$(echo "${filename}" | sed -E 's/^(.*) - .*.mp3$/\1/')
TRACK_TITLE=$(echo "${filename}" | sed -E 's/^.* - (.*).mp3$/\1/')
if [[ "$ALBUM_UPDATE" == "y" || "$ALBUM_UPDATE" == "Y" ]]; then
kid3-cli -c "set album \"${TRACK_ALBUM}\"" -c "set title \"${TRACK_TITLE}\"" -c "set artist \"${TRACK_ARTIST}\"" "$filename"
else
kid3-cli -c "set title \"${TRACK_TITLE}\"" -c "set artist \"${TRACK_ARTIST}\"" "$filename"
fi
done
success_msg
sleep 2
if ! $QUIET; then
run_display
fi
}
run_cmd_track() {
echo
echo -e " ${CLR_PURPLE} ▶ Injecting Metadata, please wait a moment...${RESET}"
echo
for filename in *.mp3; do
TRACK_NUMBER=$(echo "${filename}" | sed -E 's/^([0-9]{2}) - .* - .*.mp3$/\1/')
TRACK_ARTIST=$(echo "${filename}" | sed -E 's/^[0-9]{2} - (.*) - .*.mp3$/\1/')
TRACK_TITLE=$(echo "${filename}" | sed -E 's/^[0-9]{2} - .* - (.*).mp3$/\1/')
if [[ "$ALBUM_UPDATE" == "y" || "$ALBUM_UPDATE" == "Y" ]]; then
kid3-cli -c "set album \"${TRACK_ALBUM}\"" -c "set title \"${TRACK_TITLE}\"" -c "set artist \"${TRACK_ARTIST}\"" -c "set track \"${TRACK_NUMBER}\"" "$filename"
else
kid3-cli -c "set title \"${TRACK_TITLE}\"" -c "set artist \"${TRACK_ARTIST}\"" -c "set track \"${TRACK_NUMBER}\"" "$filename"
fi
done
success_msg
sleep 1
if ! $QUIET; then
run_display
fi
}
run_display() {
for f in *.mp3; do
title=$(exiftool -s3 -Title "$f" | sed 's#[/\\:*?"<>|]#-#g')
artist=$(exiftool -s3 -Artist "$f" | sed 's#[/\\:*?"<>|]#-#g')
TRACK_ALBUM=$(exiftool -s3 -Album "$f" | sed 's#[/\\:*?"<>|]#-#g')
track=$(exiftool -s3 -Track "$f" | sed 's#[/\\:*?"<>|]#-#g')
echo -e "${BOLD}${CLR_LABEL}$f${RESET}"
echo -e "${CLR_LABEL2}Artist:${RESET} $artist"
echo -e "${CLR_LABEL2}Title:${RESET} $title"
echo -e "${CLR_LABEL2}Album:${RESET} $TRACK_ALBUM"
echo -e "${CLR_LABEL2}Track:${RESET} $track"
echo
echo "────"
echo
done
}
######################
# FUNCTIONS - RENAME
######################
cmd_rename() {
echo " "
echo -e "${BOLD}${CLR_GOLD} Embedded metadata suggests these filenames:${RESET}"
echo " "
run_rename_test
ask_proceed
echo
echo "──────────────────────────────"
echo -e "${CLR_GREEN} Tracks Renamed Successfully${RESET}"
echo "──────────────────────────────"
echo
ls -lah
echo
}
run_rename_test() {
for f in *.mp3; do
track=$(exiftool -s3 -Track "$f" | sed 's#/.*##')
artist=$(exiftool -s3 -Artist "$f" | sed 's#[/\\:*?"<>|]#-#g')
title=$(exiftool -s3 -Title "$f" | sed 's#[/\\:*?"<>|]#-#g')
if [[ "$track" =~ ^[0-9]$ ]]; then
track="0$track"
fi
new="$track - $artist - $title.mp3"
echo "$new"
done
}
ask_proceed() {
echo " "
echo -en "${CLR_PROMPT}Does everything look right? [Y/n]: ${RESET}"
read -r CONFIRM
if [[ "$CONFIRM" == "n" || "$CONFIRM" == "N" ]]; then
echo " "
echo -e "${CLR_RED}Cancelled:${RESET} By User Request"
exit 1
else
echo ""
echo -e "${CLR_PURPLE} ▶ Renaming Files, please wait a moment...${RESET}"
echo ""
run_rename
fi
}
run_rename() {
for f in *.mp3; do
track=$(exiftool -s3 -Track "$f" | sed 's#/.*##')
artist=$(exiftool -s3 -Artist "$f" | sed 's#[/\\:*?"<>|]#-#g')
title=$(exiftool -s3 -Title "$f" | sed 's#[/\\:*?"<>|]#-#g')
if [[ "$track" =~ ^[0-9]$ ]]; then
track="0$track"
fi
new="$track - $artist - $title.mp3"
if [[ "$f" == "$new" ]]; then
echo "Skipping: $f (already correct)"
else
mv -- "$f" "$new"
fi
done
}
##############################
# INDIVIDUAL METATADATA EDITS
##############################
# Update ALBUM metadata ONLY & exit
cmd_album() {
if [[ -z "$1" ]]; then
echo -e "${CLR_RED}Error:${RESET} No Album Name Specified."
exit 1
fi
ALBUM_NAME="${*:1}"
echo ""
echo -e " ${CLR_GOLD}Setting album:${RESET} \"$ALBUM_NAME\""
echo ""
echo -e "${CLR_PURPLE} ▶ Injecting Metadata, please wait a moment...${RESET}"
echo ""
for filename in *.mp3; do
kid3-cli -c "set album \"$ALBUM_NAME\"" "$filename"
done
if ! $QUIET; then
run_display
fi
success_msg
exit 0
}
# Update ARTIST metadata ONLY & exit
cmd_artist() {
if [[ -z "$1" ]]; then
echo -e "${CLR_RED}Error:${RESET} No Artist Name Specified."
exit 1
fi
ARTIST_NAME="${*:1}"
echo ""
echo -e " ${CLR_GOLD}Setting Artist:${RESET} \"$ARTIST_NAME\""
echo ""
echo -e "${CLR_PURPLE} ▶ Injecting Metadata, please wait a moment...${RESET}"
echo ""
for filename in *.mp3; do
kid3-cli -c "set artist \"$ARTIST_NAME\"" "$filename"
done
if ! $QUIET; then
run_display
fi
success_msg
exit 0
}
# Update SINGLE TRACK metadata ONLY & exit
cmd_track() {
if [[ -z "$2" ]]; then
echo -e "${CLR_RED}Error: ${RESET}No file specified."
exit 1
fi
local track_input="$1"
local file_input="$2"
echo ""
echo -e " ${CLR_GOLD}Setting Track #:${RESET} \"$track_input\""
echo ""
echo -e "${CLR_PURPLE} ▶ Injecting Metadata, please wait a moment...${RESET}"
echo ""
kid3-cli -c "set track \"$track_input\"" "$file_input"
title=$(exiftool -s3 -Title "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
artist=$(exiftool -s3 -Artist "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
TRACK_ALBUM=$(exiftool -s3 -Album "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
track=$(exiftool -s3 -Track "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
if ! $QUIET; then
echo -e "${BOLD}${CLR_LABEL}${file_input}${RESET}"
echo -e "${CLR_LABEL2}Artist:${RESET} $artist"
echo -e "${CLR_LABEL2}Title:${RESET} $title"
echo -e "${CLR_LABEL2}Album:${RESET} $TRACK_ALBUM"
echo -e "${CLR_LABEL2}Track:${RESET} $track"
echo
echo "────"
echo
fi
success_msg
exit 0
}
# Update SINGLE TITLE metadata ONLY & exit
cmd_title() {
if [[ $# -lt 2 ]]; then
echo -e "${CLR_RED}Error: ${RESET}Title and file must be specified."
exit 1
fi
local file_input="${@: -1}"
local title_input="${*:1:$#-1}"
echo ""
echo -e " ${CLR_GOLD}Setting Title:${RESET} \"${title_input}\""
echo ""
echo -e "${CLR_PURPLE} ▶ Injecting Metadata, please wait a moment...${RESET}"
echo ""
kid3-cli -c "set title \"${title_input}\"" "${file_input}"
title=$(exiftool -s3 -Title "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
artist=$(exiftool -s3 -Artist "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
TRACK_ALBUM=$(exiftool -s3 -Album "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
track=$(exiftool -s3 -Track "$file_input" | sed 's#[/\\:*?"<>|]#-#g')
if ! $QUIET; then
echo -e "${BOLD}${CLR_LABEL}${file_input}${RESET}"
echo -e "${CLR_LABEL2}Artist:${RESET} $artist"
echo -e "${CLR_LABEL2}Title:${RESET} $title"
echo -e "${CLR_LABEL2}Album:${RESET} $TRACK_ALBUM"
echo -e "${CLR_LABEL2}Track:${RESET} $track"
echo
echo "────"
echo
fi
success_msg
exit 0
}
#########################
# INTERACTIVE INJECT TOOL
########################
cmd_inject() {
mp3_check
echo
if ! $QUIET; then
echo -e "${BOLD}${CLR_GOLD}Current Metadata: ${RESET}"
sleep 1.5
echo
run_display
fi
echo -en "${CLR_PROMPT}Update the metadata using the filenames? (Y/n)${RESET} "
read -r UPDATE
if [[ "$UPDATE" == "n" || "$UPDATE" == "N" ]]; then
echo -e "${CLR_RED} Exiting: ${RESET}User Requested"
exit 1
else
echo
echo -e "${CLR_PROMPT}Select filename format: ${RESET}"
echo
echo -e "${BOLD} [1] ${RESET}${CLR_GOLD}00 - Band - Song.mp3${RESET}"
echo -e "${BOLD} [2] ${RESET}${CLR_GOLD}Band - Song.mp3${RESET}"
echo
while true; do
echo -ne "${CLR_PROMPT}Enter choice [1-2]:${RESET} "
read -r FORMAT
case "$FORMAT" in
1 | 2) break ;;
*) echo -e "${CLR_RED}Invalid input. Please enter 1 or 2.${RESET}" ;;
esac
done
echo
echo -e "${CLR_GOLD}Format Selected:${RESET}"
case "$FORMAT" in
1)
echo " 00 - Band - Song.mp3"
;;
2)
echo " Band - Song.mp3"
;;
esac
echo
# ASK IF THE ALBUM NAME NEEDS CHANGING ALSO
echo
echo -en "${CLR_PROMPT}Change the ALBUM name? (Y/N): ${RESET}"
read -r ALBUM_UPDATE
if [[ "$ALBUM_UPDATE" == "y" || "$ALBUM_UPDATE" == "Y" ]]; then
echo""
echo -e "${CLR_GOLD} New ALBUM name Confirmed."
echo
echo -e "${CLR_PROMPT}Specify Album name: ${RESET}"
read -r USER_INPUT
TRACK_ALBUM="$USER_INPUT"
run_format_select
else
run_format_select
fi
fi
}
####################
# COMMANDS
####################
case "$1" in
-d | --display)
run_display
;;
-r | --rename)
cmd_rename
;;
-i | --inject)
cmd_inject
;;
-al | --album)
shift
cmd_album "$@"
;;
-ar | --artist)
shift
cmd_artist "$@"
;;
-tr | --track)
shift
cmd_track "$@"
;;
-ti | --title)
shift
cmd_title "$@"
;;
-dc | --depend)
shift
dependency_check -d
;;
*)
usage
;;
esac
