Convert mp4 to mp3 Using Shell Script

5,252

First you will need to replicate the directory structure in the new top directory. Inside the original top directory which contains the .mp4 files run find . -type d >dirs.txt. This will store all directories and their paths in dirs.txt. Then change directory into the new top directory and run xargs mkdir -p <dirs.txt. This will create the same directory structure as orginal.

To change the format and store the files to a different directory run the following command inside the original top directory.

find . -name "*.mp4" -exec bash -c 'var=${1%.mp4}; var=${var#*/};ffmpeg -i "${1#*/}" -vn -acodec libmp3lame -ac 2 -qscale:a 4 -ar 48000 "~/PATH/to/NewTopDIr/$var".mp3' - '{}' \;

Explanation

find . -name "*.mp4" finds all files of .mp4 type. -exec bash -c runs the bash command provided in the succeeding string for each file found. It also passes the filename as variable $1 which can be used in the bash command.

At this point $1 contains something like ./path/file.mp4. To remove the filetype *.mp4 we use var=${1%.mp4} which stores ./path/file to $var. Now we remove the preceding ./ with var=${var#*/} hence the value of $var is path/file.

In the ffmpeg command we get the current file name with ${var#*/} which gives path/file.mp4 and we get the output file with ~/PATH/to/NewTopDIr/$var".mp3 where $var has the value path/file as explained above.

Share:
5,252

Related videos on Youtube

Amir
Author by

Amir

I'm studying electronics engineering at Curtin university in WA.

Updated on September 18, 2022

Comments

  • Amir
    Amir over 1 year

    I have looked at Converting mp4 to mp3 which uses a tool called ffmpeg. The process is great when you have a single file to convert, but I'm trying automate the mp4 to mp3 conversion for any given directory.

    As an example, the directory below with all its sub directories is given, i.e. MusicVideos`:

    .
    ├── Andra
    │   └── Andra::Why.mp4
    ├── Ariana Grande
    │   └── Dangerous Woman
    │       ├── ArianaGrande::IntoYou.mp4
    │       └── ArianaGrande::SideToSide.mp4
    ├── Justin Bieber
    │   └── JustinBieber::LetMeLoveYou.mp4
    ├── Major Lazer
    │   └── De Maxx 37
    │       └── MajorLazer::ColdWater.mp4
    ├── Martin Garrix & Bebe Rexha
    │   └── MartinGarrix&BebeRevha::InTheNameOfLove.mp4
    ├── Shawn Mendes
    │   └── ShawnMendes::TreatYouBetter.mp4
    ├── Sia
    │   └── The Greatest
    │       └── Sia::TheGreatest.mp4
    ├── The Chainsmokers
    │   ├── TheChainsmokers::AllWeKnow.mp4
    │   └── TheChainsmokers::Closer.mp4
    ├── The Weekend
    │   └── Starboy
    │       └── TheWeekend::DaftPunk.mp4
    └── TWENTY ØNE PILØTS
        └── Suicide Squad
            └── TwentyOnePilots::Heathens.mp4
    

    After the script is ran the output directory should look like, i.e., MusicAudio:

    .
    ├── Andra
    │   └── Andra::Why.mp3
    ├── Ariana Grande
    │   └── Dangerous Woman
    │       ├── ArianaGrande::IntoYou.mp3
    │       └── ArianaGrande::SideToSide.mp3
    ├── Justin Bieber
    │   └── JustinBieber::LetMeLoveYou.mp3
    ├── Major Lazer
    │   └── De Maxx 37
    │       └── MajorLazer::ColdWater.mp3
    ├── Martin Garrix & Bebe Rexha
    │   └── MartinGarrix&BebeRevha::InTheNameOfLove.mp3
    ├── Shawn Mendes
    │   └── ShawnMendes::TreatYouBetter.mp3
    ├── Sia
    │   └── The Greatest
    │       └── Sia::TheGreatest.mp3
    ├── The Chainsmokers
    │   ├── TheChainsmokers::AllWeKnow.mp3
    │   └── TheChainsmokers::Closer.mp3
    ├── The Weekend
    │   └── Starboy
    │       └── TheWeekend::DaftPunk.mp3
    └── TWENTY ØNE PILØTS
        └── Suicide Squad
            └── TwentyOnePilots::Heathens.mp3
    

    I was looking at how to do this conversion using bash scripts and i came across Script: Recursively convert wma files to MP3, then remove WMA files.

    This seems a bit harder than what I was anticipating for, any help and guidance will be greatly appreciated.

    Update

    With some help I've written a script: Please confirm that this works!

    cp -a /$1/. /$2/  #copy the whole dir from src to dest
    
    #cd $2 #change dir to dest
    cd $2
    #convert *.mp4 to *.mp3
    #find . -name "*.mp4" -exec bash -c 'var=${1%.mp4}; var=${var#*/};ffmpeg -i "${1#*/}" -vn -acodec libmp3lame -ac 2 -qscale:a 4 -ar 48000 "$dest/$var".mp3' - '{}' \;
    
    find . -name "*.mp4" -exec bash -c 'ffmpeg -i "$1" -vn -acodec libmp3lame -ac 2 -qscale:a 4 -ar 48000 "${1%.mp4}".mp3' - '{}' \;
    
    echo "Cleaning up" 
    find . -name "*.mp4" -exec bash -c 'var=${1%.mp4}; var=${var#*/}; rm "${1#*/}"' - '{}' \;
    

    You can find the source code on my GitHub. Any further contribution will be appreciated greatly.

  • Bilal Baqar
    Bilal Baqar over 7 years
    To see what this command actually prints just add an echo before ffmpeg find . -name "*.mp4" -exec bash -c 'echo ffmpeg -i "$1" -vn -acodec libmp3lame -ac 2 -qscale:a 4 -ar 48000 "${1%.mp4}".mp3' - '{}' \;
  • Amir
    Amir over 7 years
    The code that didn't have the echo did work for me. Just that the converted files are in the same directory as the original files! Is there a way to output to a different directory with the same file structure?
  • Bilal Baqar
    Bilal Baqar over 7 years
    I changed the command. Try now.
  • alexis
    alexis over 7 years
    Just for the record, you don't need the semicolons after setting variables; VAR=value VAR2=value command args is legal syntax (and only sets the variables for the command).
  • Bilal Baqar
    Bilal Baqar over 7 years
    If /home/amir/music-mp3 is your new directory then replace it before the $var variable. i.e. "/home/amir/music-mp3/$var". $var will contain the rest of the file path i.e. Andra/Andra::Why.mp3.
  • Bilal Baqar
    Bilal Baqar over 7 years
    I think the file names or directory names with spaces is causing that problem. See how to rename directories and filenames to replace spaces with underscores.
  • Bilal Baqar
    Bilal Baqar over 7 years
    Oh I get it now. The command does not create the new directories. Let me add a command for that.
  • Bilal Baqar
    Bilal Baqar over 7 years
    Replicate the directory structure using the commands find . -type d >dirs.txt then inside new directory xargs mkdir -p <dirs.txt
  • Amir
    Amir over 7 years
    what >dirs.txt and <dirs.txt do?
  • Bilal Baqar
    Bilal Baqar over 7 years
    >dirs.txt stores the output of the command on the left into a file named dirs.txt. <dirs.txt gives the contents to the command on the left. In this case its xrgs which specifically takes in arguments and performs some actions on them.
  • Amir
    Amir over 7 years
    I see, as you mentioned before. The file names with space will cause problems.
  • Amir
    Amir over 7 years
    Updated question body, please take a look!
  • Bilal Baqar
    Bilal Baqar over 7 years