1

My problem is related to music encoding on my NAS and optimisation of linux find command.

I have write a script that is totally functionnal but I am sure this not the best way.

To summarize:

1/ Script checks for directories that contain flac to encode

  • all directories containing some .flac files
  • the directories NOT containing a subdirectory named mp3/ or Mp3/

For that specific part I have done something like this :

FILE="./DirContaininfFlacToConvertToMp3.txt"
find . -type f -iname '*.flac' -printf '%h\n' | sort -u > fic1
find . -iname 'mp3' -type d | sort | sed 's/\/Mp3//' | sed 's/\/mp3//' > fic2
comm -3 fic1 fic2 > $FILE
  • The $FILE will be filled with all the directories matching these 2 conditions.
  • fic1 file contains all directories containing flac files.
  • fic2 file contains all directories containing mp3 subdir (sed is used to eliminate mp3/ or Mp3/ at the end of the path for the comm command to work)
  • comm -3 provide me my result in $FILE

It works all right but I am pretty sure this is not the best way to do and it can be optimized just using find parameters or passing it to shell ..

2/ Script Encodes the flac files and move to a Mp3/ subdir

Once the file ($FILE) give the result of the directory that match the conditions next steps I do these:

  • I encode the files in mp3 in the defined directory
  • I move them to a subdirectory named Mp3 (keeping original structure)

For that part I done that in 2 loops:

#1st loop to encode
IFS=$'\n'
for next in `cat $FILE`
do
  find $next -type f  -name "*.flac" -exec ffmpeg -i {} -qscale:a 2 -map_metadata 0 -id3v2_version 3 {}.mp3 \;
done

#2nd loop for moving to subdir
for next in `cat $FILE`
do
  find $next -type f -name '*.flac.mp3' -execdir mkdir -p Mp3 \; -execdir mv {} Mp3/ \;
done

Also here I am pretty sure I could avoid iterating in 2 loops.

However you could find for any purpose the full script here (not very well coded I know ... :-(

Full script

#!/bin/bash
# Convert .flac en .mp3 file for Synology with ffmpeg
# usage : 1st construct list of directory to convert : run:  ./script.sh V
#         2nd verify and to convert run : nohup ./script C & 

#result of list of directories to encode
FILE="./ToConvertToMp3.txt"

# parameter validation
if [ "$#" -ne  "1" ]
  then
     echo "1 parameter required : ./script.sh (V)erify (C)onvert "
 exit 1;
fi


# generate list of directory for encoding
if [ "$1" ==  "V" ]
  then
    echo "-------- VERIFY AND CONSTRUCT LIST -------"
    #1 find dir that contains .flac file
    find . -type f -iname '*.flac' -printf '%h\n' | sort -u > fic1

    # for those directory search if there is some *mp3* subdir
    IFS=$'\n'
    for dirflac in `cat fic1`
    do
      find $dirflac -iname '*mp3*' -type d -exec dirname {} \; >> fic2
    done

    # sort and unicity
    cat fic2 | sort -u > fic3

    # final construc of the list of directory to encode
    comm -3 fic1 fic2 > $FILE
    rm -f fic1 fic2 fic3

    echo "-----DIRECTORY TO CONVERT-------"
    cat $FILE
    echo "-------------------------------------"
    exit 0
fi

# Converting .flav files from directories listed in $FILE
if [ "$1" ==  "C" ]
  then
    echo "-------- CONVERTING FLAC -------"

    if [ -e $FILE ]; then
      echo "$FILE exist : OK"
    else
      echo "$FILE does not exist Please (V)erification first"
    exit 3
    fi

  if [ -s "$FILE" ]; then
    echo "$FILE contains directories : OK"
    cat $FILE
  else
    echo "$FILE is empty , nothing to do"
    exit 2
  fi

  echo "-------- CONVERTING -------"
  IFS=$'\n'
  for next in `cat $FILE`
  do
    find $next -type f  -name "*.flac" -exec ffmpeg -i {} -qscale:a 2 -map_metadata 0 -id3v2_version 3 {}.mp3 \;
    album="$(basename $directory)-Mp3";
    echo "  Processing $directory : creating subdirectory : $album, moving files in progress"
    find $directory -type f -name '*.flac.mp3' -execdir mkdir -p "$album" \; -execdir mv {} "$album/" \;

  done
  echo "-------- END OF CONVERSION -------"

  # renaming $FILE with timestamp
  ficdate=$(date +%Y%M%d-%Hh%m);
  mv $FILE $FILE-$ficdate.done;

  exit 0
fi

echo "WARNING : 1 parameter : usage : ./script.sh (V)erification (C)onversion"
  • Why are you not using -printf '%h\n' | sort -u for fic2? Note that you'd probably want comm -23 as opposed to comm -3 – Stéphane Chazelas Jul 27 '16 at 13:46
  • Hello , I think for fic2 on my system the "-printf '%h\n' | sort -u" is not necessary because not like for fic1 where I do the find command on specific files for fic2 I am doing it on directory so with test I done I do not have any duplicated lines on this fic2 files. – S. Di Cioccio Jul 28 '16 at 15:49
1

You could do:

find . -type f -name '*.flac' -execdir sh -c '
  if [ ! -d mp3 ] && [ ! -d Mp3 ]; then
    for file do
      ffmpeg -i "$file" -qscale:a 2 -map_metadata 0 -id3v2_version 3 "${file%.*}.mp3"
    done
  fi' sh {} +

The idea being that with -execdir cmd {} +, (with some versions of GNU find), find will run cmd for all the matching file in a given directory.

I say some versions of GNU find because it used to work like that, but then was broken in some versions of find (where you'd get one cmd invocation per file as if you had used -execdir cmd {} \;) and it was fixed again in a later version.

You can check if you have a correct version with:

find . -execdir echo {} +

You should get one line per directory with a correct version, or one line per file with the less correct ones.

If you have a correct version, and provided you don't have thousands of flac files per directory, you can do both actions in one go:

find . -type f -name '*.flac' -execdir sh -c '
  if [ ! -d mp3 ] && [ ! -d Mp3 ]; then
    mkdir Mp3 || exit
    for file do
      ffmpeg -i "$file" -qscale:a 2 -map_metadata 0 -id3v2_version 3 "Mp3/${file%.*}.mp3"
    done
  fi' sh {} +
  • thank you very much for your answer. the First bloc of code is functionnal for me ;-) However on my system the code find . -execdir echo {} + code gave me one line per files so I do not have a correct version of find. Thanks again – S. Di Cioccio Jul 28 '16 at 15:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.