I'm coming at y'all with a hot new update! I've taken pgronkievitz's advice, and also made a fix!
Here's what changed:
Turns out I was using the wrong codec when looking at wav files in ffprobe, so they would just get silently ignored and i would be none the wiser if I looked at the folder structure. I've also added a little message to tell you if a file has been ignored like that again.
The other thing I have done is add a 'limit' option for lossless files! If you change to that new variable in the script, it will convert any lossless files which have a bitrate higher than the specified number! I've found this useful for flacs that have over 4mbps data rate. My bluetooth speaker (and / or the tangara itself) tends to stutter really badly whenever it tries to play a file with over 4mbps of data.
Finally, here's the new script!
Here's what changed:
- Code Improvements:
- removed extra file detection if statements
- changed to using mktemp
- put filenames in quotes
- Bugfixes:
- fixed wav files not being detected by the script!
- New Features:
- Added a limit option for lossless files!
Turns out I was using the wrong codec when looking at wav files in ffprobe, so they would just get silently ignored and i would be none the wiser if I looked at the folder structure. I've also added a little message to tell you if a file has been ignored like that again.
The other thing I have done is add a 'limit' option for lossless files! If you change to that new variable in the script, it will convert any lossless files which have a bitrate higher than the specified number! I've found this useful for flacs that have over 4mbps data rate. My bluetooth speaker (and / or the tangara itself) tends to stutter really badly whenever it tries to play a file with over 4mbps of data.
Finally, here's the new script!
Code:
#!/bin/bash
#First two variables are the only ones you are required to adjust
#recommend using a copy of your library and sending to another folder (and not the tangara card)
#then just do rsync --progress source dest
#IF YOU LOSE DATA IT'S YOUR OWN FAULT FOR NOT BACKING THINGS UP
#that said, this is deigned to allow for reruns to sync any new music files it finds without overwriting
#any existing data at target directory
#source and destination folders
library="/media/MusicDrive/musiclibrary"
tangara="/media/TangaraSD/Music"
#Options are copy, convert, or limit
#copy keeps lossless files as is
#convert converts all lossless files to target settings to save space
#limit converts all lossless files which have a higher average bitrate than $maxallowedbitrate
#i've found that my bluetooth setup tends to stutter above 4mbps
reincodelossless=limit
maxallowedbitrate=2048
#choose to reincode lossy audio; turn on for uniformity.
#aac and alac will be reencoded regardless of this setting.
reincodelossy=false
#choose what to do with unknown audio formats
#unkown audio is all audio files that ffmpeg can read, but is not listed at
#https://cooltech.zone/tangara/docs/music-library/#supported-audio-formats
reincodeunknowncodecs=true
#this script can handle album art for the tangara
#it grabs whatever cover art it can find and then downsizes it to fit the tangara screen
#capable of using embedded cover art, no problem.
grabalbumart=true
#format to convert to whenever conversion is required
#this will be run on any aac and alac audio
targetcodec=libopus
targetextension=ogg
#use kbps for this option
#opus is indistinguishable from lossless for the average listener at 190kbps.
#https://www.reddit.com/r/ffmpeg/comments/oa9f0x/comment/iifo6nu/
targetquality=192k
#main script loop, iterate through every file in source library and run commands depnding on prior settings
#IFS command keeps the find command as one string instead of splitting strings delimitted by spaces
IFS=$'\n'
#run file operations in temp directory
workingDirectory=$(mktemp -d temp.XXX)
cd $workingDirectory
#loop through all the files in the source library
for file in $(find $library | sort); do
filename=$(basename -a $file)
cutfilename=${filename%.*}
filestruct="${file#$library}"
cutfilestruct=${filestruct%.*}
cutfolderstruct=${filestruct%/*}
#echo "Current Working File: $filestruct"
#ensure folder structure matches source library
if [ -d $file ] ; then #if file is folder
if [ -d "$tangara$filestruct" ] ; then #if folder exists in target library
:
else #if folder does not exist in target library
#create folder in target directory
mkdir -p "$tangara$filestruct"
fi
elif [ -f $file ] ; then
#file is file
#only do very slow ffprobe task if the possible target files don't exist
if [ -f $tangara$cutfilestruct.$targetextension ] ; then
echo "$cutfilestruct.$targetextension already exists on target directory! Skipping."
continue
elif [ -f $tangara$filestruct ] ; then
echo "$filestruct already exists on target directory! Skipping."
continue
else
ffproberesults=$(ffprobe "$file" 2>&1)
#copy the current working file to the current directory
cp -f $library$filestruct $filename
fi
#check codec of file
filecodec=na
filecodectype=na
#used to check for too much data for the tangara to handle, not quality
filebitrate=na
#obtain current working file codec
if [[ $(echo $ffproberesults | grep -w "Audio: aac") ]] ; then
filecodec=aac
filecodectype=lossy
elif [[ $(echo $ffproberesults | grep -w "Audio: alac") ]] ; then
filecodec=alac
filecodectype=lossy
elif [[ $(echo $ffproberesults | grep -w "Audio: flac") ]] ; then
filecodec=flac
filecodectype=lossless
elif [[ $(echo $ffproberesults | grep "Audio: pcm") ]] ; then
filecodec=wav
filecodectype=lossless
elif [[ $(echo $ffproberesults | grep -w "Audio: mp3") ]] ; then
filecodec=mp3
filecodectype=lossy
elif [[ $(echo $ffproberesults | grep -w "Audio: vorbus") ]] ; then
filecodec=vorbus
filecodectype=lossy
elif [[ $(echo $ffproberesults | grep -w "Audio: opus") ]] ; then
filecodec=opus
filecodectype=lossy
elif [[ $(echo $ffproberesults | grep -w "Audio: ") ]] ; then
filecodec=unk
filecodectype=lossy
fi
#obtain current bitrate of audio file
tempbitrate=$(echo $ffproberesults | sed -n -e 's/^.*bitrate: //p')
filebitrate=$(echo $tempbitrate | cut -d ' ' -f 1)
#echo "The bitrate of this audio file is $filebitrate kbps."
#handle cover.jpg
#check if we want to send a cover.jpg to the target library
if [ $grabalbumart = true ] ; then
if [ -f $tangara$cutfolderstruct/cover.jpg ] ; then
#do nothing because we already have a cover.jpg at the target location
:
else
#Check if this file is a cover.jpg equivalent and sync it to the tangara.
if [[ $cutfilename == "cover" || $cutfilename == "folder" ]] ; then
#attempt to compress it to fit the tangara screen size while keeping source ratio
ffmpeg -y -hide_banner -loglevel error -i "$filename" -qscale:v 2 -vf "scale='if(gt(iw,ih),160,-1)':'if(gt(iw,ih),-1,128)" cover.jpg
mv -u cover.jpg "$tangara$cutfolderstruct/cover.jpg"
#ensure file is some sort of music file before running this
elif [[ $filecodectype == "lossless" || $filecodectype == "lossy" ]] ; then
#check for embedded art prior to converting
if [[ $(echo $ffproberesults | grep -w "Video: ") ]] ; then
ffmpeg -y -hide_banner -loglevel error -i "$filename" -qscale:v 2 -vf "scale='if(gt(iw,ih),160,-1)':'if(gt(iw,ih),-1,128)" cover.jpg
mv -u "cover.jpg $tangara$cutfolderstruct/cover.jpg"
fi
else
if [[ $filecodec == "na" ]] ; then
#not a cover or audio file. Tell user it was skipped and let them deal with it.
echo "$filename is an unknown type of file. No actions were taken for this file."
continue
fi
fi
fi
fi
#choose what to do with the file
if [[ $filecodectype == "lossless" ]] ; then
if [[ $reincodelossless == "limit" ]] ; then
#echo "we can't do the limit option just yet"
if (( $filebitrate > $maxallowedbitrate )) ; then
echo "Converting lossless audio file $filename to $cutfilestruct.$targetextension because it has a bitrate of $filebitrate kbps."
ffmpeg -n -hide_banner -loglevel error -i "$filename" -map 0:a -c:a $targetcodec -b:a $targetquality "$cutfilename.$targetextension"
#echo "Copying $cutfilestruct.$targetextension over to $tangara$cutfilestruct"
mv -u "$cutfilename.$targetextension" "$tangara$cutfilestruct.$targetextension"
#remove the unconverted file from the temp directory
rm "$filename"
else
echo "Copying lossless audio file $filename over to $tangara$filestruct"
mv -u "$filename" "$tangara$filestruct"
fi
elif [[ $reincodelossless == "copy" ]] ; then
#safely copy the file to the tangara device without overwriting existing files
echo "Copying lossless audio file $filename over to $tangara$filestruct"
mv -u "$filename" "$tangara$filestruct"
elif [[ $reincodelossless == "convert" ]] ; then
echo "Converting $filename to $cutfilestruct.$targetextension"
ffmpeg -n -hide_banner -loglevel error -i "$filename" -map 0:a -c:a $targetcodec -b:a $targetquality "$cutfilename.$targetextension"
#echo "Copying $cutfilestruct.$targetextension over to $tangara$cutfilestruct"
mv -u "$cutfilename.$targetextension" "$tangara$cutfilestruct.$targetextension"
#remove the unconverted file from the temp directory
rm "$filename"
fi
elif [[ $filecodectype == "lossy" ]] ; then
#start with unspported codecs which will always be converted
if [[ $filecodec == "aac" || $filecodec == "alac" ]] ; then
echo "Converting $filename to $cutfilestruct.$targetextension"
ffmpeg -n -hide_banner -loglevel error -i "$filename" -map 0:a -c:a $targetcodec -b:a $targetquality "$cutfilename.$targetextension"
#echo "Copying $cutfilestruct.$targetextension over to $tangara$cutfilestruct"
mv -u "$cutfilename.$targetextension" "$tangara$cutfilestruct.$targetextension"
#remove the unconverted file from the temp directory
rm "$filename"
#move to supported lossy codecs
elif [[ $filecodec == "mp3" || $filecodec == "opus" || $filecodec == "vorbis" ]] ; then
#echo "$filename is a lossy file. Convert Target result is $tangara$filestruct"
if [ $reincodelossy = false ] ; then
echo "Copying lossy audio file $filename over to $tangara$filestruct"
mv -u "$filename" "$tangara$filestruct"
elif [ $reincodelossy = true ] ; then
echo "Converting $filename to $cutfilestruct.$targetextension"
ffmpeg -n -hide_banner -loglevel error -i "$filename" -map 0:a -c:a $targetcodec -b:a $targetquality "$cutfilename.$targetextension"
#echo "Copying $cutfilestruct.$targetextension over to $tangara$cutfilestruct"
mv -u "$cutfilename.$targetextension" "$tangara$cutfilestruct.$targetextension"
#remove the unconverted file from the temp directory
rm "$filename"
fi
#handle unknown but still audio codecs
elif [[ $filecodec == "unk" ]] ; then
if [ reincodeunknowncodecs = true ] ; then
echo "Converting $filename to $cutfilestruct.$targetextension"
ffmpeg -n -hide_banner -loglevel error -i "$filename" -map 0:a -c:a $targetcodec -b:a $targetquality "$cutfilename.$targetextension"
#echo "Copying $cutfilestruct.$targetextension over to $tangara$cutfilestruct"
mv -u "$cutfilename.$targetextension" "$tangara$cutfilestruct.$targetextension"
#remove the unconverted file from the temp directory
rm "$filename"
else
#safely copy the unknown audio file over to the tangara device and hope the unknoiwn codec works.
mv -u "$filename" "$tangara$filestruct"
fi
fi
fi
fi
done
#temp directory cleanup
cd ..
rm -rf $workingDirectory