#!/bin/bash carcp=0 fixcaps=0 fixspaces=0 target="" stripvowels=0 stripspaces=1 strippunc=1 striplen=10 for arg in "$@" do if [[ "$arg" =~ ^- ]] then an="$(echo "$arg" | sed 's/-\(.*\)\(\(=\(.*\)\)\|$\)/\1/')" av="$(echo "$arg" | sed 's/-\(.*\)\(\(=\(.*\)\)\|$\)/\4/')" if [[ "$an" == "carcp" ]] then echo "Car mp3 player copy mode selected" carcp=1 continue fi if [[ "$an" == "strpvwls" ]] then if [[ "$av" != "" ]] then echo "Stripping vowels using method $av" stripvowels="$av" else echo "Stripping vowels" stripvowels=1 fi continue fi if [[ "$an" == "stripspaces" ]] then if [[ "$av" != "" ]] then echo "Stripping spaces using method $av" stripspaces="$av" else echo "Stripping spaces" stripspaces=1 fi continue fi if [[ "$an" == "strippunc" ]] then if [[ "$av" != "" ]] then echo "Stripping punctuation using method $av" strippunc="$av" else echo "Stripping punctuation" strippunc=1 fi continue fi if [[ "$an" == "striplen" ]] then if [[ "$av" != "" ]] then echo "Adaptively stripping after $av chars" striplen="$av" else echo "Use -striplen=10" exit fi continue fi if [[ "$an" == "fixspaces" ]] then echo "Forcing fixing spaces on" fixspaces=1 continue fi if [[ "$an" == "fixcaps" ]] then echo "Forcing fixing capitalization on" fixcaps=1 continue fi echo "Unknown argument: $arg" exit fi if [[ "$target" != "" ]] then echo "Only one destination may be given." exit fi target="$arg" done if (( carcp == 1 )) && [[ "$target" == "" ]] then echo "Please provide a target for the carcp operation." exit fi i=0 while read line do files[ $i ]="$line" (( i++ )) done < <(ls *.[mM][pP]3) numfiles=$i echo "$numfiles files found" if (( numfiles == 0 )) then echo "Exiting, no files found." exit fi printfiles=0 if (( printfiles == 1 )) then for f in "${files[@]}" do echo "$f" done fi minstrlen() { minlenout=-1 for f in "${minlenin[@]}" do if (( ${#f} < minlenout || minlenout < 0 )) then (( minlenout = ${#f} )) fi done } trimfixed() { nokrchar='[^ _-\.()\[\]]$' noklchar='^[^ _-\.()\[\]]' max=0 maxr=0 minlenin=( "${trimin[@]}" ) minstrlen minlen=minlenout for (( i=0; i<$minlen; i++ )) do l="" lr="" good=1 goodr=1 ff=0 for f in "${trimin[@]}" do n=${f: 0 : $i} nr=${f: -$i} if ( (( ff > 0 )) && [ "$n" != "$l" ] ) || [[ "$n" =~ $nokrchar ]] then good=0 fi l=$n if ( (( ff > 0 )) && [ "$nr" != "$lr" ] ) || [[ "$nr" =~ $noklchar ]] then goodr=0 fi lr=$nr ff=1 done if (( good > 0 )) then max=$i fi if (( goodr > 0 )) then maxr=$i fi done echo "Constant $max on left and $maxr on right" i=0 for f in "${trimin[@]}" do trimout[$i]=${f: $max : ${#f}-$max-$maxr} (( i++ )) done } trimin=( "${files[@]}" ) trimfixed sfiles=( "${trimout[@]}" ) #sfiles=( "${files[@]}" ) #for (( i=0; i<$numfiles; i++ )) # do # f="${files[$i]}" # echo "'${f: 0 : $max}' '${sfiles[$i]}' '${f: -$maxr}'" # done splitnum() { if (( $splitpos >= 0 )) && [ $splitpos != "-0" ] then splittnum="$(echo $splitstr | sed -rn 's/^(.{'$(( $splitpos ))'})(0*)([0-9]*)([^0-9].*)$/\3/p' )" splittname="$(echo $splitstr | sed -rn 's/^(.{'$(( $splitpos ))'})(0*)([0-9]*)([^0-9].*)$/\1\4/p' )" else splittnum="$(echo $splitstr | sed -rn 's/^(.*[^0-9])(0*)([0-9]*)(.{'$(( -$splitpos ))'})$/\3/p' )" splittname="$(echo $splitstr | sed -rn 's/^(.*[^0-9])(0*)([0-9]*)(.{'$(( -$splitpos ))'})$/\1\4/p' )" fi } minlenin=( "${sfiles[@]}" ) minstrlen minlen=minlenout besti=0 bestt=0 for (( i=0; i<$minlen; i++ )) do t=0 l=-1 for f in "${sfiles[@]}" do splitstr=$f splitpos=$i splitnum n=$splittnum if [ -z $n ] || (( $n == $l )) then t=0 break fi (( t+=n )) l=$n done tr=0 lr=-1 for f in "${sfiles[@]}" do splitstr=$f splitpos=-$i splitnum nr=$splittnum if [ -z $nr ] || (( nr == lr )) then tr=0 break fi (( tr+=nr )) lr=$nr done if (( t > bestt )) then bestt=$t besti=$i fi if (( tr >= bestt )) then bestt=$tr besti=-$i fi done echo "Position $besti is best at $bestt" if (( bestt != 0 )) && ( [[ "$besti" == "-0" ]] || (( $besti < 0 )) ) then echo "Please kill the person who put the numbers at the end of the filename." fi j=0 for (( i=1; i<=$numfiles; i++ )) do (( j+=i )) done if (( bestt < j )) then echo "Warning: Sum of track numbers less than expected - may be mis-identified or missing tracks." fi if (( bestt > j )) then echo "Warning: Sum of track numbers greater than expected - may be mis-identified or duplicate tracks." fi if (( bestt == j )) then echo "Yay! Sum of track numbers exactly as expected." fi for (( i=0; i<$numfiles; i++ )) do f="${sfiles[$i]}" splitpos=$besti splitstr=$f splitnum #echo "'$f' '$splittnum' '$splittname'" tnums[$i]=$splittnum tnames[$i]=$splittname done trimin=( "${tnames[@]}" ) trimfixed tnames=( "${trimout[@]}" ) maxtnum=0 foundspaces=0 foundcaps=0 for (( i=0; i<$numfiles; i++ )) do f="${tnums[$i]}" if (( f > maxtnum )) then maxtnum=$f fi #echo "Track $f: '${tnames[$i]}'" tname="${tnames[$i]}" if [[ "$tname" =~ " " ]] then (( foundspaces++ )) fi caps="$(echo "$tname" | sed 's/[^A-Z]//g')" (( foundcaps += ${#caps} )) done if (( foundspaces <= 0 )) || (( fixspaces == 1 )) then echo "Fixing spaces..." for (( i=0; i<$numfiles; i++ )) do tname="${tnames[$i]}" tname2="$(echo "$tname" | sed 's/\([a-zA-Z()\.]\)\([_\.]\)\([a-zA-Z()\.]\)/\1 \3/g')" tname2="$(echo "$tname2" | sed 's/\([a-zA-Z()\.]\)\([_\.]\)\([a-zA-Z()\.]\)/\1 \3/g')" tname2="$(echo "$tname2" | sed 's/\([a-zA-Z()\.]\)\([_\.]\)\([a-zA-Z()\.]\)/\1 \3/g')" #echo "'$tname' '$tname2'" tnames[$i]="$tname2" done fi if (( foundcaps <= numfiles )) || (( fixcaps == 1 )) then echo "Fixing capitalization..." for (( i=0; i<$numfiles; i++ )) do tname="${tnames[$i]}" tns=( $tname ) tname2="" for t in "${tns[@]}" do p="$(echo "$t" | sed 's/^\([^a-zA-Z]*\).*/\1/')" t="$(echo "$t" | sed 's/^[^a-zA-Z]*\(.*\)/\1/')" # Too much work, let's just capitalize everything? if true || [[ -z $tname2 ]] || [[ $t != "for" && $t != "of" && $t != "the" && $t != "and" ]] then tname2+="$p$(echo "${t:0:1}" | tr '[a-z]' '[A-Z]')${t:1} " else tname2+="$p$t " fi done tname2="$(echo "$tname2" | sed 's/ $//')" #echo "'$tname' '$tname2'" tnames[$i]="$tname2" done fi for (( i=0; i<$numfiles; i++ )) do tname="${tnames[$i]}" tname2="$(echo "$tname" | sed "s/Dont/Don't/")" tname2="$(echo "$tname2" | sed "s/Shouldnt/Shouldn't/")" tname2="$(echo "$tname2" | sed "s/Cant/Can't/")" tname2="$(echo "$tname2" | sed "s/Wont/Won't/")" tname2="$(echo "$tname2" | sed "s/Im /I'm /")" tname2="$(echo "$tname2" | sed "s/Hes /He's /")" tname2="$(echo "$tname2" | sed "s/Shes /She's /")" tname2="$(echo "$tname2" | sed "s/Its /It's /")" tname2="$(echo "$tname2" | sed "s/Theyre/They're/")" tname2="$(echo "$tname2" | sed "s/\`/'/")" if [[ "$tname2" != "$tname" ]] then echo "Fixing punctuation..." #echo "'$tname' '$tname2'" tnames[$i]="$tname2" fi done trackfile="tracks.txt" if (( bestt < numfiles )) then if [ -e "tracks.txt" ] then echo "Failed at finding track numbers, trying to match with $trackfile." for (( i=0; i<$numfiles; i++ )) do tname="${tnames[$i]}" # high -D biases tre-agrep to try to include every character of the track name ag="$(tre-agrep -s -n -i -B -D 15 -S 20 "^$tname\$" $trackfile | head -n 1)" agtnum="$(echo $ag | cut -d ':' -f 1)" agscore="$(echo $ag | cut -d ':' -f 2)" agtname="$(echo $ag | cut -d ':' -f 3-)" echo "Name '$tname' matched to track $agtnum '$agtname' with score $agscore." tnums[$i]=$agtnum done else echo "Failed at finding track numbers, try creating $trackfile with track names in sequence." fi fi pref=$(pwd | sed 's/.*\///') tnumw=2 if (( maxtnum > 99 )) then tnumw=3 fi for (( i=0; i<$numfiles; i++ )) do if (( carcp == 1 )) then tn="${tnames[$i]}" while (( stripspaces != 0 )) && ( (( ${#tn} > striplen )) || (( stripspaces == 1 )) ) && [[ "$tn" =~ " " ]] do tn="$(echo "$tn" | sed 's/[ ]\([^ ]*\)$/\1/')" done while (( strippunc != 0 )) && ( (( ${#tn} > striplen )) || (( strippunc == 1 )) ) && [[ "$tn" =~ [,()\-] ]] do tn="$(echo "$tn" | sed 's/[,()\-]\([^,()\-]*\)$/\1/')" done while (( strippunc != 0 )) && ( (( ${#tn} > striplen )) || (( strippunc == 1 )) ) && [[ "$tn" =~ [\'] ]] do tn="$(echo "$tn" | sed 's/['"'"']\([^'"'"']*\)$/\1/')" done while (( stripvowels != 0 )) && ( (( ${#tn} > striplen )) || (( stripvowels == 1 )) ) && [[ "$tn" =~ [aeiou] ]] do tn="$(echo "$tn" | sed 's/[aeiou]\([^aeiou]*\)$/\1/')" done printf -v of "%s (%s - %0"$tnumw"d - %s).mp3" "$tn" "$pref" ${tnums[$i]} "${tnames[$i]}" else printf -v of "$pref - %0"$tnumw"d - ${tnames[$i]}.mp3" ${tnums[$i]} fi ofiles[$i]="$of" done for (( i=0; i<$numfiles; i++ )) do if="${files[$i]}" if (( carcp != 0 )) then of="$(echo "$target/${ofiles[$i]}" | sed 's/\/\//\//g')" else of="${ofiles[$i]}" fi of="$(echo "$of" | sed 's/`/\\`/g')" if="$(echo "$if" | sed 's/`/\\`/g')" if [ "$of" != "$if" ] then if (( carcp != 0 )) then cmds[$i]="cp -v \"$if\" \"$of\"" else cmds[$i]="mv -v \"$if\" \"$of\"" ucmds[$i]="mv -v \"$of\" \"$if\"" fi #echo "mv -v '$if' '$of'" fi done #if (( carcp == 0 )) # then for c in "${cmds[@]}" do echo "$c" done # fi savefile="./mvtracks.sh" undofile="./undotracks.sh" if [[ -z ${cmds[*]} ]] then echo "Nothing to do!" echo exit fi if (( carcp != 0 )) then echo "Copying files..." for c in "${cmds[@]}" do echo "$c" #eval "$c" done exit fi echo -n "Move files (y=yes, s=save)? " read line if [[ "$line" == "y" ]] then echo "Moving tracks..." for c in "${cmds[@]}" do eval "$c" done fi if [[ "$line" == "s" ]] then echo "Saving move to $savefile" rm $savefile 2>/dev/null for c in "${cmds[@]}" do echo "$c" >>$savefile done fi if [[ "$line" == "y" ]] || [[ "$line" == "s" ]] then echo "Saving undo to $undofile" rm $undofile 2>/dev/null for c in "${ucmds[@]}" do echo "$c" >>$undofile done fi