Skip to content

Instantly share code, notes, and snippets.

@psiborg
Last active November 21, 2024 03:50
Show Gist options
  • Save psiborg/8199b7e2eb503d44ed0aef15a5c4c9bf to your computer and use it in GitHub Desktop.
Save psiborg/8199b7e2eb503d44ed0aef15a5c4c9bf to your computer and use it in GitHub Desktop.
Clean FLAC and MP3 tags
#!/usr/bin/env bash
# ============================================================================
# clean-tags.sh
#
# Author: Jim Ing
# Date: 2024-11-19
#
# Description: This script processes audio files (.mp3 and .flac) to remove
# specified metadata tags, displays metadata before and after
# cleaning, and saves the cleaned files in a designated output
# directory.
# Command-Line Options:
# --dry-run: Simulates processing without modifying any files.
# --output-dir DIR: Specifies a custom output directory.
# --keywords "keyword1 keyword2": Custom keywords for metadata filtering.
# ============================================================================
# Define constants
DEFAULT_KEYWORDS="pmedia p.m.e.d.i.a k2nblog"
OUTPUT_DIR="cleaned"
# Flag to check if it's the first iteration
first=true
# Initialize counters for the summary report
processed_count=0
skipped_count=0
error_count=0
# Dry run mode flag
dry_run=false
# List of metadata tags to be cleared from audio files
metadata_tags=(
"artists"
"barcode"
"catalog #"
"catalog number"
"comment"
"compilation"
"copyright"
"credits"
"encoded_by"
"encoded-by"
"encoder"
"encodersettings"
"grouping"
"info"
"isrc"
"itunesadvisory"
"label"
"lyrics-eng"
"organization"
"performer"
"pmedia"
"provider"
"publisher"
"releasecountry"
"source"
"tbpm"
"text"
"thnx"
"tit3"
"tlen"
"tmed"
"toly"
"tope"
"tpe4"
"trsn"
"tsrc"
"upload"
"uploader"
"work"
"wwwaudiofile"
"wwwaudiosource"
)
# Function to check prerequisites
check_prerequisites() {
command -v ffmpeg >/dev/null || { echo "Error: ffmpeg is not installed."; exit 1; }
command -v ffprobe >/dev/null || { echo "Error: ffprobe is not installed."; exit 1; }
}
# Function to create output directory
create_output_dir() {
if [ ! -d "$OUTPUT_DIR" ]; then
mkdir "$OUTPUT_DIR"
echo "Directory '$OUTPUT_DIR' created."
else
echo "Directory '$OUTPUT_DIR' already exists."
fi
}
# Function to process a single file
process_file() {
local file="$1"
echo "Processing file ($((processed_count + skipped_count + error_count + 1))/$total_files): $file"
# Display input metadata
echo "---[ Input Metadata ]---------------------------------------------------------"
for keyword in "${keyword_array[@]}"; do
ffprobe -i "$file" -show_entries format_tags -v quiet | grep -i "$keyword"
done
echo "------------------------------------------------------------------------------"
if $dry_run; then
echo "Dry run: Skipping metadata removal for $file."
((skipped_count++))
return
fi
# Prepare metadata clearing arguments
local clear_metadata_args=()
for tag in "${metadata_tags[@]}"; do
clear_metadata_args+=("-metadata" "$tag=")
done
# Remove metadata and save cleaned file
if ffmpeg -i "$file" "${clear_metadata_args[@]}" -codec copy "$OUTPUT_DIR/$file" -loglevel warning; then
((processed_count++))
echo "---[ Output Metadata ]--------------------------------------------------------"
ffprobe -i "$OUTPUT_DIR/$file" -show_entries format_tags -v quiet -print_format flat
echo "------------------------------------------------------------------------------"
else
echo "Error processing file: $file"
((error_count++))
fi
}
# Function to display summary report
display_summary() {
echo
echo "------------------------------[ Summary Report ]------------------------------"
echo "Total files found: $total_files"
echo "Files processed: $processed_count"
echo "Files skipped: $skipped_count"
echo "Errors: $error_count"
echo "------------------------------------------------------------------------------"
}
# Parse command-line arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
--dry-run) dry_run=true; shift ;;
--output-dir) OUTPUT_DIR="$2"; shift 2 ;;
--keywords) DEFAULT_KEYWORDS="$2"; shift 2 ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
# Parse keywords into an array
IFS=' ' read -r -a keyword_array <<< "${DEFAULT_KEYWORDS}"
# Start script execution
check_prerequisites
# Count total files for progress reporting
files=(*.mp3 *.flac)
total_files=0
for file in "${files[@]}"; do
if [ -f "$file" ]; then
((total_files++))
fi
done
if [ "$total_files" -eq 0 ]; then
echo "No .mp3 or .flac files found in the current directory."
exit 0
fi
# Create the output directory
create_output_dir
# Process each file
for file in "${files[@]}"; do
if [ -f "$file" ]; then
process_file "$file"
# Ask the user whether to continue after processing the first file
if [ "$first" = true ]; then
first=false
read -p "Please review the above output. Do you want to continue (y/n)? " user_input
if [ "$user_input" != "y" ]; then
echo "Exiting..."
break
else
echo "Continuing..."
fi
fi
fi
done
# Display summary report
display_summary
# TODO: Replace original files with cleaned files
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment