Sync Script for Linux devices
#1
Hey y'all! I made a bash sync script for the Tangara!

What it assumes:
 * you are running linux
 * You have a single source folder containing all your music files
 * You want that single library folder structure to be mirrored on your tangara
 * You have ffmpeg installed and accessible on your PATH
 * you have read access to your music library
 * You too struggled to get https://github.com/complexlogic/EasyAudioSync running on your system

What it does:
 * Converts incompatible aac/alac files
 * Handles embedded and folder-local cover files
 * lets you choose your target audio settings
 * Lets you choose if you want to compress lossless audio to save space
 * lets you choose which categories of lossy files you want converted

What it doesn't do:
* Anything other than music. Playlists don't work either.
 * Delete things. 
 * It doesn't update your tangara if you remove an album from your library
 * It does its best to never overwrite any existing files (But no promises! Backups are YOUR job!)

Running the script:

Step 1:

Check for ffmpeg in your path:
Code:
ffmpeg -version
[*]
Step 2:
Copy your music library to a folder the script has read permission in!

Step 3:
Make a new folder somewhere the script has write permissions in.

Step 4:
Paste this code into an empty shell script file.

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="/home/dageek247/Music Copy"
tangara="/home/dageek247/tangaraMusic"

#Options are copy or convert
  #copy keeps lossless files as is
  #convert converts all lossless files to target settings to save space
reincodelossless=copy

#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
targetquality=256k


#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
mkdir temp
cd temp

#loop through all the files in the source library
for file in $(find $library); 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
     

        #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 -w "Audio: wav") ]] ; 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
       
        #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
                fi
            fi
        fi
       
        #choose what to do with the file
        if [[ $filecodectype == "lossless" ]] ; then
            #First check to see if an encoded or copy version already exists on target library
            if [ -f $tangara$cutfilestruct.$targetextension ] ; then
                echo "$cutfilestruct.$targetextension already exists on target directory! Skipping."
            elif [ -f $tangara$filestruct ] ; then
                echo "$filestruct already exists on target directory! Skipping."
            else
                if [[ $reincodelossless == "limit" ]] ; then
                    echo "we can't do the limit option just yet"
                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
                fi
            fi
        elif [[ $filecodectype == "lossy" ]] ; then
            #start with unspported codecs which will always be converted
            if [[ $filecodec == "aac" || $filecodec == "alac" ]] ; then
                if [ -f $tangara$cutfilestruct.$targetextension ] ; then
                    echo "$tangara$cutfilestruct.$targetextension already exists. Skipping."
                else
                    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
                fi
            #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
                    #verify if a copied file version exists
                    if [ -f $tangara$filestruct ] ; then
                        echo "$filestruct already exists. Skipping."
                    else
                        #safely copy the lossy file over to the tangara device.
                        echo "Copying lossy audio file $filename over to $tangara$filestruct"
                        mv -u $filename $tangara$filestruct
                    fi
                elif [ $reincodelossy = true ] ; then
                    #verify if a converted file version exists
                    if [ -f $tangara$cutfilestruct.$targetextension ] ; then
                        echo "$cutfilestruct.$targetextension already exists. Skipping."
                    else
                        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
                    fi
                fi
            #handle unknown but still audio codecs
            elif [[ $filecodec == "unk" ]] ; then
                if [ reincodeunknowncodecs = true ] ; then
                    #verify if a converted file version exists
                    if [ -f $tangara$cutfilestruct.$targetextension ] ; then
                        echo "$cutfilestruct.$targetextension already exists. Skipping."
                    else
                        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
                    fi
                else
                    #safely copy the unknown audio file over to the tangara device.
                    mv -u $filename $tangara$filestruct
                fi
            fi
        fi
    fi
done

#temp directory cleanup
cd ..
rm -rf temp

Step 5:
Edit the first two variables to match the locations of your duplicate music library and your new writable folder.

Step 6:
Run the script and watch it go!

Step 7:
Rsync the destination folder contents to your tangara sd card.
Code:
rsync --progress "/home/dageek247/tangaraMusic" "/media/SDCard01/Music"

Step 8:
Rerun the script whenever you have new music to add!


I consider this to be version 1.0. Its feature complete (for now) but bug testing is only mildly been done!
  Reply
#2
Star 
hey, nice job!
I've got three issues in my mind after a quick look - two aren't that big of a deal and one might cause unexpected results
1. less serious one is creating temp dir in current working directory - it will fail if temp dir exists on mkdir temp (but won't fail the whole script). mktemp -d may be more suitable in here
2. you may want to take a look at bash(1) manpage, specifically at shell builtin commands section set command (-e, -u and -o pipefail options)
3. the more serious one - filenames should be quoted, as they may contain spaces and this will cause weird behavior

other than this, it looks good!
  Reply


Forum Jump: