Sync Script for Linux devices
#5
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:
  • 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
  Reply


Messages In This Thread
Sync Script for Linux devices - by dageek247 - 2025-04-08, 03:22 AM
RE: Sync Script for Linux devices - by tebriel - 2025-04-22, 09:36 PM
RE: Sync Script for Linux devices - by dageek247 - 2025-04-28, 11:24 PM
RE: Sync Script for Linux devices - by dageek247 - 2025-05-03, 12:33 AM

Forum Jump: