#!/bin/sh # this script renames directories and flac files using the following format: # directories: ${artist} [${date}] ${album} [FLAC-${bitdepth}bit-${samplerate}] # eg: YENA [2023.01.16] Love War [FLAC-24bit-48kHz] # files: ${discnumber}-${tracknumber} ${title}.flac # eg: 1-03 Love War (Feat. BE'O).flac # it is intended to be run AFTER the metadata script. # for safety, the script will perform a dry run by default. to actually move files, run the script with the -m flag. # if a variable cannot be set, the script will skip making changes and print a warning to the terminal and to the log file. # check dirs and files check() { [ ! -d "$master" ] && echo "invalid directory!" && exit [ ! -d logs ] && mkdir logs [ ! -f lists/tags.csv ] && echo "could not find tags.csv database. generate it using ./list.sh -d -t" && exit } # print to log file log() { printf "\033[1m\033[38;5;210mcould not set %s. manual intervention required!\033[0m\n" "$2" echo "$1 - could not set $2" >> logs/rename.log } # filter to remove illegal characters from file names. mostly relevant for shitty windows filesystems. filter() { if echo "$name" | grep -qE '(<|>|:|"|/|\\|\||\?|\*|(\.| )$)' || echo "$name" | grep -qP '\t' || echo "$name" | grep -qzP '\n'; then name="$(echo "$name" | tr '\n' ' ' | tr '\t' ' ' | sed 's|^-||; s|^\.||; s|^_||; s|<||g; s|>||g; s|:||g; s|"||g; s|/|-|g; s|\\||g; s|\||-|g; s|\?||g; s|\*||g; s| $||; s|\.$||')" fi } # process file names renamefile() { disc=$(metaflac --show-tag=DISCNUMBER "$file" | cut -d '=' -f 2) # if first character of DISCNUMBER is 0, remove it [ "$(echo "$disc" | cut -c 1)" = "0" ] && disc="$(echo "$disc" | cut -c 2)" track=$(metaflac --show-tag=TRACKNUMBER "$file" | cut -d '=' -f 2 | cut -d '/' -f 1) # if TRACKNUMBER is only a single character, prefix it with a 0 [ "$(printf "%s" "$track" | wc -c)" -eq 1 ] && track="0${track}" title=$(metaflac --show-tag=TITLE "$file" | cut -d '=' -f 2-) if [ -z "$disc" ] || [ -z "$track" ] || [ -z "$title" ]; then # log missing tags [ -z "$disc" ] && log "$file" "disc number" [ -z "$track" ] && log "$file" "track number" [ -z "$title" ] && log "$file" "track title" else name="$disc-$track $title.flac" filter [ "$mod" = "true" ] && mv -iv "$file" "$dir/$name" || echo "$(basename "$file") -> $name" fi } # process directory names renamedir() { # prefer using a track without features file="$(find "$dir" -type f -name '*.flac' | grep -ivE feat | head -n 1)" if [ "$(find "$dir" -type f -name '*.flac' | wc -l)" -eq 1 ] || [ -z "$file" ]; then file="$(find "$dir" -type f -name '*.flac' | head -n 1)" fi artist="$(metaflac --show-tag=ARTIST "$file" | cut -d '=' -f 2)" # ALBUMARTIST tag should be used unless artist is a sub-unit if ! grep ^U lists/tags.csv | cut -f 2 | grep -qi -m 1 "$artist"; then artist="$(metaflac --show-tag=ALBUMARTIST "$file" | cut -d '=' -f 2)" fi date="$(metaflac --show-tag=DATE "$file" | cut -d '=' -f 2)" album="$(metaflac --show-tag=ALBUM "$file" | cut -d '=' -f 2)" rate="$(metaflac --show-sample-rate "$file" | sed 's/0.*$//;s/44/44./;s/88/88./')" depth="$(metaflac --show-bps "$file")" # assemble date tag if [ -n "$date" ]; then y=$(echo "$date" | cut -c 1-4) m=$(echo "$date" | cut -c 5,6) d=$(echo "$date" | cut -c 7,8) date="$y.$m.$d" fi if [ -z "$artist" ] || [ -z "$date" ] || [ -z "$album" ] || [ -z "$rate" ] || [ -z "$depth" ]; then # log missing tags [ -z "$artist" ] && log "$dir" "artist name" [ -z "$date" ] && log "$dir" "release date" [ -z "$album" ] && log "$dir" "album name" [ -z "$rate" ] && log "$dir" "sample rate" [ -z "$depth" ] && log "$dir" "bit depth" else path="${dir%/*}" name="$artist [$date] $album [FLAC-${depth}bit-${rate}kHz]" filter [ "$mod" = "true" ] && mv -iv "$dir" "$path/$name" || echo "$(basename "$dir") -> $name" fi } while getopts "d:mh" o; do case "${o}" in d) master="$OPTARG";; m) mod="true";; h|*) printf "usage: ./%s [OPTION]...\n\noptions:\n -d specify directory to scan\n -m modify files\n" "$(basename "$0")" && exit 1 esac done check # begin new log printf "\nscript run - %s\n" "$(date)" >> logs/rename.log [ "$mod" != "true" ] && printf "\033[1mPerforming DRY RUN. use -m to modify files.\033[0m\n" # set numbers total="$(find "$master" -type d -links 2 | wc -l)" num=1 # main loop find "$master" -type d -links 2 | while read -r dir; do if ls "$dir"/*.flac >/dev/null 2>&1; then printf "\n\033[1m[%d/%d] %s\033[0m\n" "$num" "$total" "$(basename "$dir")" for file in "$dir"/*.flac; do renamefile done renamedir num=$((num+1)) fi done printf "\n\033[1mscript completed! remember to check log for errors.\033[0m\n"