Page 1 of 4 123 ... LastLast
Results 1 to 10 of 36

Thread: Recursively convert files with ffmpeg using bash?

  1. #1
    Join Date
    Apr 2007
    Location
    Birdsboro, PA
    Beans
    92
    Distro
    Ubuntu 16.04 Xenial Xerus

    Recursively convert files with ffmpeg using bash?

    I am unable to resurrect old posts (for very good reasons).

    This post from 2010 is essentially my exact question with some slight changes to the input and output folder/file locations.

    Here is the text of the linked forum post (reformatted), for reference. I have modified the details of the post so they apply to my specific parameters. The quoted items are generic placeholders if that isn't immediately evident: (I recognize alac is lossless. "compressed" is the folder itunes watches for any compatible files and has mp3's in it, as well.)

    I have several large sets of .flac files that are all organized like so:

    /home/storage/music/lossless/"Artist"/"Album"/"Song.flac"

    I would like to convert these to alac's (.m4a) in order to play them on my iPhone. I have a script that will convert all the flac's in a folder to alac .m4a's and it looks like this:

    Code:
    for i in *.flac; do ffmpeg -i "$i" -acodec alac "`basename "$i" .flac`.m4a"; done;
    The problem is that with my current file structure I have to run that command in the folder of every album, which would take a long time.

    What I would like to do is a write a script that would just run ffmpeg, recursively, in every folder found in /home/storage/music/lossless.

    Then, I'd like to append a script to move all the newly created alac's to another folder in a way that retains the current structure so I could end up with something like:

    input = /home/storage/music/lossless/"Artist"/"Album"/"Song.flac" and output = /home/storage/music/compressed/"Artist"/"Album"/"Song.m4a"

    Any suggestions/advice/feedback would be appreciated.

    Thanks for your time,
    Sohex

    The final reply, with a solution, is as follows:

    Quote Originally Posted by Originally Posted by Sohex
    The converted m4a's show up in the directory containing Music and Music_too (or FLAC and ALAC if you will) instead of in the appropriate location, how can I fix that?
    Sorry, my fault. The "basename" removes the directory part of the names.

    Either replace "`basename "${i/Music/Music_too}" .flac`.m4a" with "`dirname ${i/Music/Music_too}"`/`basename "$i" .flac`.m4a" or edit $i in two steps using neither dirname nor basename, like o=${i/Music/Music_too}; o=${o%.flac%.m4a} and then use "$o" in the ffmpeg command.

    Code:
    for i in Music/*/*/*.flac; do o=${i/Music/Music_too}; o=${o%.flac%.mp4}; ffmpeg -i "$i" -acodec alac "$o"; done
    Put an echo before the ffmpeg the first time you run the command to see what it will do:

    Code:
    for i in Music/*/*/*.flac; do o=${i/Music/Music_too}; o=${o%.flac%.mp4}; echo ffmpeg -i "$i" -acodec alac "$o"; done
    I was able to figure out that for the beginning, I can substitute
    Code:
    for i in /home/storage/music/lossless/*/*/*.flac;
    My confusion lies with the parameters for the do function. Specifically, the subsequent string variable. I am unable to figure out how to properly substitute my parameters into this case and use the script suggested.

    If possible, an additional step that checks the respective "compressed" folder for .m4a's already existing would aid in being able to reuse this single script each time I've added files to the "lossless" folder. Perhaps, as a CRON job that is run nightly. This is not a priority or needed at all, just a hopeful wish, if easily executed.

    Any help would be greatly appreciated.
    Last edited by madhartigan; July 24th, 2016 at 06:40 PM. Reason: Add prefix; Add Solved

  2. #2
    Join Date
    Jun 2016
    Beans
    2,831
    Distro
    Xubuntu

    Re: Recursively convert files with ffmpeg using bash?

    The solution for you probably involves find command, but I don't know exactly how it'd work. Here's an example of how I might go about something like this, NOT TESTED and it probably doesn't quite work how you want
    Code:
    cd /home/storage/music/lossless
    find . -iname \*.flac -exec foo.sh {} \;
    foo.sh
    Code:
    #!/bin/bash
    
    basedir='/home/storage/music/compressed'
    dest=`dirname "$1"`
    
    [ ! -d "$dest" ] && mkdir -p "$dest"
    
    ffmpeg -i "$1" -acodec alac "${basedir}/$dest"/`basename "$1"`.m4a
    I would strongly recommend you test and refine this on some dummy audio files until you're really sure it works exactly how you want, before setting this loose on anything important.

    Refer to man page of find for more information

    Does this help?
    Last edited by halogen2; July 21st, 2016 at 09:47 PM.
    Xubuntu 22.04, ArchLinux ♦ System76 hardware, virt-manager/KVM, VirtualBox
    When your questions are resolved to your satisfaction, please use Thread Tools > "Mark this thread as solved..."

  3. #3
    Join Date
    Oct 2013
    Location
    Colorado
    Beans
    560
    Distro
    Xubuntu 20.04 Focal Fossa

    Re: Recursively convert files with ffmpeg using bash?

    Try this:
    Code:
    inputdir="/home/storage/music/lossless/"
    outputdir="/home/storage/music/compressed/"
    while IFS= read -r file ; do
      song=`basename "$file"`
      dir=`dirname "$file"`
      varyingdir=${dir:${#inputdir}}
      songnotype=${song:0:${#song}-4}
      outputfile="${outputdir}${varyingdir}/${songnotype}m4a"
      # check if output file already exists
      if [ ! -e "$outputfile" ]
      then
        # check if output directory exists
        if [ ! -e "$outputdir/$varyingdir" ]
        then
          mkdir -p "$outputdir/$varyingdir"
        fi
        avconv -i "$file" -acodec alac "$outputfile"
      fi
    done < <(find "$inputdir" -name "*.flac" | head -10)
    ffmpeg was replaced by avconv at some point in Ubuntu, so change it back if you need to. Remove the "| head -10" after testing. That limits the loop to only process 10 files.

  4. #4
    Join Date
    Jun 2016
    Beans
    2,831
    Distro
    Xubuntu

    Re: Recursively convert files with ffmpeg using bash?

    Quote Originally Posted by Keith_Helms View Post
    ffmpeg was replaced by avconv at some point in Ubuntu,
    Not any more
    http://packages.ubuntu.com/xenial/ffmpeg
    http://packages.ubuntu.com/xenial/libav-tools
    Xubuntu 22.04, ArchLinux ♦ System76 hardware, virt-manager/KVM, VirtualBox
    When your questions are resolved to your satisfaction, please use Thread Tools > "Mark this thread as solved..."

  5. #5
    Join Date
    Oct 2013
    Location
    Colorado
    Beans
    560
    Distro
    Xubuntu 20.04 Focal Fossa

    Re: Recursively convert files with ffmpeg using bash?

    Ah. Any news on which is better? Are both being maintained?

  6. #6
    Join Date
    Jun 2016
    Beans
    2,831
    Distro
    Xubuntu

    Re: Recursively convert files with ffmpeg using bash?

    That libav-tools package only contains symlinks to ffmpeg binaries & man pages, so someone who actually wants avconv & Co. will have to build from source.
    Xubuntu 22.04, ArchLinux ♦ System76 hardware, virt-manager/KVM, VirtualBox
    When your questions are resolved to your satisfaction, please use Thread Tools > "Mark this thread as solved..."

  7. #7
    Join Date
    Apr 2007
    Location
    Birdsboro, PA
    Beans
    92
    Distro
    Ubuntu 16.04 Xenial Xerus

    Re: Recursively convert files with ffmpeg using bash?

    Quote Originally Posted by Keith_Helms View Post
    Try this:
    Code:
    inputdir="/home/storage/music/lossless/"
    outputdir="/home/storage/music/compressed/"
    while IFS= read -r file ; do
      song=`basename "$file"`
      dir=`dirname "$file"`
      varyingdir=${dir:${#inputdir}}
      songnotype=${song:0:${#song}-4}
      outputfile="${outputdir}${varyingdir}/${songnotype}m4a"
      # check if output file already exists
      if [ ! -e "$outputfile" ]
      then
        # check if output directory exists
        if [ ! -e "$outputdir/$varyingdir" ]
        then
          mkdir -p "$outputdir/$varyingdir"
        fi
        avconv -i "$file" -acodec alac "$outputfile"
      fi
    done < <(find "$inputdir" -name "*.flac" | head -10)
    ffmpeg was replaced by avconv at some point in Ubuntu, so change it back if you need to. Remove the "| head -10" after testing. That limits the loop to only process 10 files.

    Thank you very much for the replies!!

    I know this script *can* work, there are just some details that I've probably neglected to include that are tripping up the script.

    This is very close. I'm not sure how to explain what is going wrong, but I'll do my best. If you suggest where I could put an echo statement, or have it output to a logfile, I could certainly copy that to Pastebin or share it from my cloud storage.

    The only edit I made to the script was to change 'avconv' to 'ffmpeg'. I used nano to create a file named "flactoalac" and pasted your script into that file. Once it was edited with ffmpeg and saved, I did chmod 755 flactoalac so I could execute the file, then ran ./flactoalac

    Once it completed, I checked the "compressed" folder.

    In the artist directory (/home/storage/music/compressed/"artist"), it had placed an empty directory with a partial string of the input directory's name. In the album directory (/home/storage/music/compressed/"artist"/"album"/), there was a directory with the proper *full* string of the input directory's album title. In that directory, there were three files properly converted to .m4a.

    That was what happened the *first* time.

    I deleted all the output including the stray directory in the "artist" directory, the properly named album directory in the "album" directory and its contents.

    I ran it again. Same type of symptoms, different partial string left in the compressed "artist" directory and now an additional empty directory with the full input directory's name also in the "artist directory. In the album directory, again, the proper *full* string of the input directory's album title with two (not three) properly converted files.

    Similar symptoms, different specific results.


    I apologize if that explanation is nearly impossible to understand. The option for a logfile would probably help you pinpoint precisely what is going on.

    I know nearly nothing about proper bash scripting, but I'm wondering if special characters or spaces in my album and song titles would possibly be the cause? Both album and song titles contain spaces, commas, brackets or parentheses, and dashes (-). I apologize for not including that detail in my original post.

    I very much appreciate your effort and again, thank you very much for this effort. I can understand the gist of what your script is doing, but attempting to debug would likely take me down a rabbit hole rather than fix anything.

    Let me know what I can do to help you help me.

  8. #8
    Join Date
    Oct 2013
    Location
    Colorado
    Beans
    560
    Distro
    Xubuntu 20.04 Focal Fossa

    Re: Recursively convert files with ffmpeg using bash?

    When you put it in "flattoalac" to make a script out of it, did you add the following line at the top of the file?
    Code:
    #!/bin/bash
    If not, make that change and try again.

    If you already had that in there, please list what was created by the script by running the following command
    Code:
    ls -R /home/storage/music/compressed
    and posting the output.

  9. #9
    Join Date
    Oct 2013
    Location
    Colorado
    Beans
    560
    Distro
    Xubuntu 20.04 Focal Fossa

    Re: Recursively convert files with ffmpeg using bash?

    By the way, what version of Ubuntu are you running? Your profile shows 9.10. You're not really on that old a version are you? The bash code I posted should run on relatively recent Ubuntu releases, but I don't know about 7 year old ones.

  10. #10
    Join Date
    Apr 2007
    Location
    Birdsboro, PA
    Beans
    92
    Distro
    Ubuntu 16.04 Xenial Xerus

    Re: Recursively convert files with ffmpeg using bash?

    I apologize for not updating my profile. It's been that long since I have needed support. Once I got my 10.04 LTS up and running, I was easily able to repeat the same steps to set up when upgrading to 12.04 LTS and 14.04 LTS. So, I had no real need for support outside of what I was able to search on Google.

    I'm now on 16.04 LTS.

    I did *not* place that header at the top of the script. Although, placing the hash bang header doesn't seem to have the effect of changing the output.

    http://pastebin.com/MnG1T91F

    That will take you to the output you requested. For the sake of demonstrating how it is not consistent I deleted those output folders and ran it again to show you how it changes.

    http://pastebin.com/sWdCfrx9


    Thank you for sticking with me and helping out.

Page 1 of 4 123 ... LastLast

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •