add opus compression

This commit is contained in:
nnduc
2025-08-16 17:50:40 +07:00
parent dc349e8864
commit 2b74dc9b66
3 changed files with 309 additions and 0 deletions

0
ffmpeg-flac-downsampling.sh Normal file → Executable file
View File

0
file-cleaning.sh Normal file → Executable file
View File

309
flac-opus-compressing.sh Executable file
View File

@ -0,0 +1,309 @@
#!/bin/bash
# Media Library FLAC to Opus Conversion Script
# Processes multiple albums in a media library, converting all FLAC files to Opus 448kbps
# Check if ffmpeg is installed
if ! command -v ffmpeg &> /dev/null; then
echo "Error: ffmpeg is not installed or not in PATH"
exit 1
fi
# Check if ffmpeg has opus encoder support
if ! ffmpeg -encoders 2>/dev/null | grep -q "libopus"; then
echo "Error: ffmpeg does not have Opus encoder support (libopus)"
echo "Please install ffmpeg with Opus support"
exit 1
fi
# Function to display usage
show_usage() {
echo "Usage: $0 [OPTIONS] <media_library_path>"
echo ""
echo "Options:"
echo " -o, --output DIR Output directory (default: creates _opus suffix)"
echo " -r, --replace Replace original files with Opus (use with caution)"
echo " -p, --preserve Create Opus files alongside original FLAC files"
echo " -t, --test Test mode - show what would be processed"
echo " -f, --force Force re-conversion of existing Opus files"
echo " -b, --bitrate RATE Opus bitrate in kbps (default: 448)"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 /path/to/music/library"
echo " $0 -o /path/to/output /path/to/music/library"
echo " $0 --test /path/to/music/library"
echo " $0 --replace /path/to/music/library"
echo " $0 -b 384 /path/to/music/library"
}
# Default options
OUTPUT_DIR=""
REPLACE_MODE=false
PRESERVE_MODE=false
TEST_MODE=false
FORCE_MODE=false
OPUS_BITRATE=448
PROCESSED_COUNT=0
SKIPPED_COUNT=0
ERROR_COUNT=0
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-o|--output)
OUTPUT_DIR="$2"
shift 2
;;
-r|--replace)
REPLACE_MODE=true
shift
;;
-p|--preserve)
PRESERVE_MODE=true
shift
;;
-t|--test)
TEST_MODE=true
shift
;;
-f|--force)
FORCE_MODE=true
shift
;;
-b|--bitrate)
OPUS_BITRATE="$2"
shift 2
;;
-h|--help)
show_usage
exit 0
;;
-*)
echo "Unknown option: $1"
show_usage
exit 1
;;
*)
MEDIA_LIBRARY="$1"
shift
;;
esac
done
# Validate bitrate
if ! [[ "$OPUS_BITRATE" =~ ^[0-9]+$ ]] || [ "$OPUS_BITRATE" -lt 64 ] || [ "$OPUS_BITRATE" -gt 512 ]; then
echo "Error: Invalid bitrate '$OPUS_BITRATE'. Must be between 64 and 512 kbps"
exit 1
fi
# Check if media library path is provided
if [ -z "$MEDIA_LIBRARY" ]; then
echo "Error: Media library path is required"
show_usage
exit 1
fi
# Check if media library exists
if [ ! -d "$MEDIA_LIBRARY" ]; then
echo "Error: Media library directory '$MEDIA_LIBRARY' not found"
exit 1
fi
# Set output directory if not specified
if [ -z "$OUTPUT_DIR" ] && [ "$REPLACE_MODE" = false ]; then
OUTPUT_DIR="${MEDIA_LIBRARY}_opus"
fi
# Function to check if file needs conversion
needs_conversion() {
local input_file="$1"
local output_file="$2"
# Check if input file is readable
if [ ! -r "$input_file" ]; then
echo " WARNING: File not readable: $input_file"
return 1
fi
# If force mode, always convert
if [ "$FORCE_MODE" = true ]; then
return 0
fi
# Check if output file already exists and is newer than input
if [ -f "$output_file" ] && [ "$output_file" -nt "$input_file" ]; then
return 1 # No conversion needed
fi
return 0 # Needs conversion
}
# Function to process a single FLAC file
process_flac_file() {
local input_file="$1"
local relative_path="$2"
local output_file=""
# Determine output file path
if [ "$REPLACE_MODE" = true ]; then
# Replace .flac with .opus in same location
output_file="${input_file%.flac}.opus"
elif [ "$PRESERVE_MODE" = true ]; then
local dir=$(dirname "$input_file")
local filename=$(basename "$input_file" .flac)
output_file="$dir/${filename}.opus"
else
# Change extension from .flac to .opus
local opus_relative_path="${relative_path%.flac}.opus"
output_file="$OUTPUT_DIR/$opus_relative_path"
fi
# Check if conversion is needed
if ! needs_conversion "$input_file" "$output_file"; then
echo " SKIP: $relative_path (Opus file exists and is newer)"
((SKIPPED_COUNT++))
return
fi
if [ "$TEST_MODE" = true ]; then
echo " WOULD CONVERT: $relative_path$(basename "$output_file") @ ${OPUS_BITRATE}kbps"
return
fi
# Create output directory if needed
local output_dir=$(dirname "$output_file")
if [ ! -d "$output_dir" ]; then
echo " Creating directory: $output_dir"
if ! mkdir -p "$output_dir"; then
echo " ✗ ERROR: Cannot create output directory: $output_dir"
((ERROR_COUNT++))
return
fi
fi
# Verify input file exists and is readable
if [ ! -f "$input_file" ]; then
echo " ✗ ERROR: Input file not found: $input_file"
((ERROR_COUNT++))
return
fi
if [ ! -r "$input_file" ]; then
echo " ✗ ERROR: Input file not readable: $input_file"
((ERROR_COUNT++))
return
fi
# Create temporary file for safe processing
local temp_file="${output_file}.tmp.opus"
echo " CONVERTING: $relative_path → Opus ${OPUS_BITRATE}kbps"
# Convert the file to Opus
echo " Command: ffmpeg -i \"$input_file\" -c:a libopus -b:a ${OPUS_BITRATE}k -vbr on -compression_level 10 -y \"$temp_file\""
if ffmpeg -i "$input_file" -c:a libopus -b:a "${OPUS_BITRATE}k" -vbr on -compression_level 10 -y "$temp_file" 2>"${temp_file}.log"; then
# Move temp file to final location
mv "$temp_file" "$output_file"
echo " ✓ DONE: $(basename "$output_file")"
rm -f "${temp_file}.log"
((PROCESSED_COUNT++))
# If replace mode, remove original FLAC file
if [ "$REPLACE_MODE" = true ]; then
rm "$input_file"
echo " Removed original: $(basename "$input_file")"
fi
else
echo " ✗ ERROR: Failed to convert $relative_path"
echo " Error log saved to: ${temp_file}.log"
if [ -f "${temp_file}.log" ]; then
echo " Last few lines of error:"
tail -n 5 "${temp_file}.log" | sed 's/^/ /'
fi
rm -f "$temp_file"
((ERROR_COUNT++))
fi
}
# Function to process an album directory
process_album() {
local album_dir="$1"
local album_name=$(basename "$album_dir")
echo "Processing album: $album_name"
# Find all FLAC files in the album directory
local flac_files=()
while IFS= read -r -d '' file; do
flac_files+=("$file")
done < <(find "$album_dir" -name "*.flac" -type f -print0)
if [ ${#flac_files[@]} -eq 0 ]; then
echo " No FLAC files found in $album_name"
return
fi
# Process each FLAC file
for flac_file in "${flac_files[@]}"; do
local relative_path="${flac_file#$MEDIA_LIBRARY/}"
process_flac_file "$flac_file" "$relative_path"
done
echo ""
}
# Main processing
echo "Media Library FLAC to Opus Converter"
echo "===================================="
echo "Input: $MEDIA_LIBRARY"
echo "Bitrate: ${OPUS_BITRATE}kbps"
if [ "$TEST_MODE" = true ]; then
echo "Mode: TEST MODE (no files will be modified)"
elif [ "$REPLACE_MODE" = true ]; then
echo "Mode: REPLACE (original FLAC files will be deleted after conversion)"
elif [ "$PRESERVE_MODE" = true ]; then
echo "Mode: PRESERVE (Opus files created alongside originals)"
else
echo "Output: $OUTPUT_DIR"
fi
if [ "$FORCE_MODE" = true ]; then
echo "Force: Enabled (will re-convert existing Opus files)"
fi
echo ""
# Find all directories that contain FLAC files (potential albums)
album_dirs=()
while IFS= read -r -d '' dir; do
if find "$dir" -maxdepth 1 -name "*.flac" -type f | grep -q .; then
album_dirs+=("$dir")
fi
done < <(find "$MEDIA_LIBRARY" -type d -print0)
if [ ${#album_dirs[@]} -eq 0 ]; then
echo "No albums with FLAC files found in $MEDIA_LIBRARY"
exit 0
fi
echo "Found ${#album_dirs[@]} album(s) with FLAC files"
echo ""
# Process each album
for album_dir in "${album_dirs[@]}"; do
process_album "$album_dir"
done
# Summary
echo "Conversion Summary:"
echo "=================="
echo "Converted: $PROCESSED_COUNT files"
echo "Skipped: $SKIPPED_COUNT files (already converted or newer)"
echo "Errors: $ERROR_COUNT files"
if [ "$ERROR_COUNT" -gt 0 ]; then
exit 1
fi