How to apply code to a file of a given extension - macos

I've been messing around with Apple's Automator & Quick Actions, and have run into a snag. I want to be able to engage a script that will reverse every audio file in that folder (and paste the reversed audio into a new folder). I want it to be able to work with a range of audio types, and that's my problem. I can't seem to figure out how to work with if statements in this context. I'm very new to terminal commands, so it could be that I'm doing something completely wrong. The quick action will run without throwing up any errors, but all it does is make the new folder.
for f in "$#"
do
cd "$f"
mkdir reversed
if [[ f == *.m4a ]];
then
/opt/homebrew/bin/ffmpeg -nostdin -i "$name" -af areverse -c:a alac -c:v copy "reversed/${name%.*}.m4a"
elif [[ f == *.aiff ]];
then
/opt/homebrew/bin/ffmpeg -nostdin -i "$name" -af areverse -c:a pcm_s16le -c:v copy "reversed/${name%.*}.aiff"
elif [[ f == *.mp3 ]];
then
/opt/homebrew/bin/ffmpeg -nostdin -i "$name" -af areverse -c:a mp3 -c:v copy "reversed/${name%.*}.mp3"
fi
done
Hopefully this makes sense, and thank you in advance!

First, you are matching a literal string against the patterns, not the value of the parameter. Second, you are trying to match the directory name, not names of files in the directory. Something like
process () {
/opt/homebrew/bin/ffmpeg -nostdin -i "$1" -af areverse -c:a "$2" -c:v copy "reversed/${1%.*}".$3
}
for d in "$#"; do
cd "$d"
mkdir reversed
for f in *; do
case $f in
*.m4a) process "$f" alac m4a ;;
*.aiff) process "$f" pcm_s16le aiff ;;
*.mp3) process "$f" mp3 mp3 ;;
esac
done
done

Related

/usr/local/bin/ffmpeg: cannot execute binary file

Want to convert my m4a files into mp3 files using a script. It would save some time... I have over 100 GB of music files.
OS: OSX10.14 / Terminal vs Bash script
I can run ffmpeg -v 5 -y -i musicFile.m4a -acodec libmp3lame -ac 2 -b:a 320k musicFile.mp3 from the terminal. It converts the file and I can see and play the file from itunes.
When I run the same from a bash script it fails to convert.
ffmpeg -v 5 -y -i $ENTRY_FILE -acodec libmp3lame -ac 2 -b:a 320k $MP3NAME
My ipod nano just died and I got a new mp3 player. Now I need to convert my itunes files from AAC format to MP3.
ffmpeg is an established video and music file converter.
When I run it from the bash script I tried a few things.
I added ./ in front of the file, that failed because it was installed under /usr/local/bin and not under the same directory.
I also tried sh ffmpeg... and that gave me the cannot execute a binary file.
#!/usr/bin/env bash
# convert m4a file to mp3
set -e
file_convert() {
ENTRY_FILE=$(printf %q "${entry}")
FILE_NAME=$(printf %q "$(basename "${entry}")")
DIR=$(printf %q "$(dirname "${entry}")")
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
MP3NAME="${DIR}/${NAME}.mp3"
printf "%*s%s\n" $((indent+2)) '' "$ENTRY_FILE"
printf "%*s\tNew File :\t%s\n" $((indent+2)) '' "$MP3NAME"
if [ $EXT == "m4a" ]
then
printf "%*s\tConverting: \t%s\n" $((index+2)) '' "$ENTRY_FILE"
ffmpeg -v 5 -y -i $ENTRY_FILE -acodec libmp3lame -ac 2 -b:a 320k $MP3NAME
fi
}
walk() {
local indent="${2:-0}"
printf "\n%*s%s\n\n" "$indent" '' "$1"
# If the entry is a file convert it
for entry in "$1"/*; do [[ -f "$entry" ]] && file_convert; done
# If the entry is a directory recurse
for entry in "$1"/*; do [[ -d "$entry" ]] && walk "$entry" $((indent+2)); done
}
# If the path is empty use the current, otherwise convert relative to absolute; Exec walk()
[[ -z "${1}" ]] && ABS_PATH="${PWD}" || pushd "${1}" && ABS_PATH="${PWD}"
walk "${ABS_PATH}"
popd
echo
I expect >./aacToMp3.sh ./music to traverses the music directory and convert each m4a file to .mp3.
It is walking the file system and printing out correct files, with the spaces escaped. When it hits the ffmpeg line it halts. I put the set -e at the top of the file to force it to fail if the command fails. Without the set -e it happily walks all the music files and prints them to the stdout.
If you have lots of files to process and a decent multi-core CPU and fast disk, I would recommend GNU Parallel which you can install with homebrew:
brew install parallel
Then make a copy of a few files in a test directory and try:
parallel --dry-run ffmpeg -v 5 -y -i {} -acodec libmp3lame -ac 2 -b:a 320k {.}.mp3 ::: *.m4a
If that looks good, replace --dry-run with --progress.
If that looks good, you can (make a backup first) and do the whole lot:
find path/to/music -name "*.m4a" -print0 | parallel -0 --progress ffmpeg -v 5 -y -i {} -acodec libmp3lame -ac 2 -b:a 320k {.}.mp3
Thanks for all the input.
After a while I ended up writing all the ffmpeg lines to a script file. Glad I did. I was able to quickly scan the file and see some errors and fix them.
This is what I came up with.
Basically I am writing straight text to stdout and directing it to a file. Which I converted to a shell script to convert each file. One at a time. Ran the generated script overnight.
file_convert() {
ENTRY_FILE=$(printf %q "${entry}")
FILE_NAME=$(printf %q "$(basename "${entry}")")
DIR=$(printf %q "$(dirname "${entry}")")
NAME="${FILE_NAME%.*}"
EXT="${FILE_NAME##*.}"
MP3NAME="${DIR}/${NAME}.mp3"
if [ $EXT == "m4a" ]
then
printf 'echo "Converting %s ..."\n' "$FILE_NAME"
printf 'ffmpeg -v 5 -y -i %s -acodec libmp3lame -ac 2 -b:a 320k %s\n\n' "$ENTRY_FILE" "$MP3NAME"
fi
}
The output looked like.
#!/usr/bin/env bash
echo "Converting 03\ It\'s\ Not\ My\ Time.m4a ..."
ffmpeg -v 5 -y -i /Users/arthuranderson/Documents/work/projects/mp3Convert/music/3\ Doors\ Down/3\ Doors\ Down\ \(Bonus\ Track\ Version\)/03\ It\'s\ Not\ My\ Time.m4a -acodec libmp3lame -ac 2 -b:a 320k /Users/arthuranderson/Documents/work/projects/mp3Convert/music/3\ Doors\ Down/3\ Doors\ Down\ \(Bonus\ Track\ Version\)/03\ It\'s\ Not\ My\ Time.mp3
echo "Converting 01\ Down.m4a ..."
ffmpeg -v 5 -y -i /Users/arthuranderson/Documents/work/projects/mp3Convert/music/311/Greatest\ Hits\ \'93-\'03/01\ Down.m4a -acodec libmp3lame -ac 2 -b:a 320k /Users/arthuranderson/Documents/work/projects/mp3Convert/music/311/Greatest\ Hits\ \'93-\'03/01\ Down.mp3
Mark I will try parallel when I purchase some more music next time.
Thanks everyone!

How would i create a bash script to convert .wav files from folder [A] to mp3 format . then move them to new folder [mp3folder]

I want this Script to run in a loop every hour. The main goal is to convert the wav files that I export to my VM share folder when using Ableton.
Messy Idea of what I want but need lots of help with
for file in /mnt/hgfs/VMshare/transfer/*
do
if ["$file" == "/mnt/hgfs/VMshare/transfer/*.wav]
then
find -name "*.wav" -exec ffmpeg -i {} -acodec libmp3lame -ab 128k {}.mp3 \;
else
echo "NO WAV TO CONVERT"
mv /mnt/hgfs/VMshare/transfer/*.mp3 /root/Desktop/MP3Music/
Change the FILE_PATH variable, destination path and ffmpeg command as per your need. This worked for me.
#!/bin/bash
FILE_PATH=/path/to/wav/format/files/*.wav
for FILE in `ls $FILE_PATH`
do
BASENAME=`basename $FILE`
ffmpeg -i $FILE -vn -ar 44100 -ac 2 -ab 192k -f mp3 `dirname "${FILE}"`/${BASENAME%.wav}.mp3 > /dev/null 2>&1
mv `dirname "${FILE}"`/${BASENAME%.wav}.mp3 /path/to/destination/
done
OR
Single command:
find /path/to/wav/files/ -name "*.wav" -type f | xargs -I {} ffmpeg -i {} -vn -ar 44100 -ac 2 -ab 192k -f mp3 {}.mp3
But the above stores the output files as *.wav.mp3, you may need to rename it while moving to destination path.

Print results at conclusion of bash 'for loop'

I'm a beginner.
I have a Bash script that embeds subtitles into mkv files if they exist in a directory.
for i in *.mkv; do
if [ -f "${i%mkv}"*"srt" ]; then
ffmpeg -i "$i" -f srt -i "${i%mkv}"*"srt" -map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy -c:s srt $i.output.mkv
mv "${i%mkv}"*"srt" "${i%mkv}srt".old
mv $i $i.old
mv $i.output.mkv $i
else
echo $i "does not have srt file"
fi
done
It looks for all .mkv files that have an associated .srt file and does some ffmpeg magic to it. If it does not find an associated .srt file it says that the .mkv file "does not have srt file."
How can I make it so that at the conclusion of the for loop I get a print out of all the .mkv files that did have an .srt file and did successfully do all the other actions?
Thank you.
Let's use a Bash array to store completed or skipped MKVs:
SUCCESSMKVS=()
SKIPMKVS=()
for i in *.mkv; do
if [ -f "${i%mkv}"*"srt" ]; then
ffmpeg -i "$i" -f srt -i "${i%mkv}"*"srt" -map 0:0 -map 0:1 \
-map 1:0 -c:v copy -c:a copy -c:s srt "${i}.output.mkv"
mv "${i%mkv}"*"srt" "${i%mkv}srt".old
mv "$i" "${i}.old"
mv "${i}.output.mkv" "$i"
SUCCESSMKVS+=("$i")
else
echo $i "does not have srt file"
SKIPMKVS+=("$i")
fi
done
echo "The following MKVs succeeded:"
for mkv in "${SUCCESSMKVS[#]}"; do
echo -e "\t${mkv}"
done
echo
echo "The following MKVs were skipped:"
for mkv in "${SKIPMKVS[#]}"; do
echo -e "\t${mkv}"
done
echo

Running FFMPEG from Shell Script /bin/sh

I am trying to setup a Shell Script to work within an automator watch folder...
Everything works with the exception of the Run Shell Scrip portion...
Essentially when a file shows up in the watch folder, it runs the shell scrip which calls FFMPEG and then will move the file to an archive folder for safe keeping. However right now automator is telling me everything worked but now file is being created.
I have the Shell set to /bin/sh and Pass input set to as arguments
Here is my script:
for f in "$#"
do
name=$(basename "$f")
dir=$(dirname "$f")
ffmpeg -i "$f" -b 250k -strict experimental -deinterlace -vcodec h264 -acodec aac "$dir/mp4/${name%.*}.mp4"
echo "$dir/mp4/${name%.*}.mp4"
done
it does echo the correct filename, but does not actually run ffmpeg
I have tried adding -exec before it like I have seen in some scripts but still nothing...
FFmpeg searches STDIN while it is running. This is to allow the user to hit q to stop encoding, among other tasks. This could cause a problem with a script. Perhaps to workaround try this:
# notice --+
# |
# v
ffmpeg -nostdin -i "$f" -b 250k -strict experimental -deinterlace \
-vcodec h264 -acodec aac "$dir/mp4/${name%.*}.mp4"
mysterious error with ffmpeg on OSX
Not sure if it is because I am running on a Mac OS X Server but I imagine it is, I had to include the absolute path to ffmpeg...which fixed it
for f in "$#"
do
name=$(basename "$f")
dir=$(dirname "$f")
/opt/local/bin/ffmpeg -i "$f" -b 250k -strict experimental -deinterlace -vcodec h264 -acodec aac "$dir/mp4/${name%.*}.mp4"
echo "$dir/mp4/${name%.*}.mp4"
done

How can I tell an if statement to skip a file but continue onto the next file if a certain condition is met?

for f in ~/Desktop/Uploads/*.flv; do
if /usr/local/bin/ffprobe ${f} 2>&1 | egrep 'Stream #0:0.+flv1'; then
<what do I put here for the batch file to skip the file and continue?>
else
if /usr/local/bin/ffprobe ${f} 2>&1 | egrep 'Stream #0:1.+speex'; then
/usr/local/bin/ffmpeg -i ${f} -vn -acodec libfaac -ab 128k -ar 48000 -async 1 ${f/%.flv/.m4a}
SPEEX_ADD="-i ${f/%.flv/.m4a}"
SPEEX_MAP="-map 1:0"
SPEEX_TRASH="rmtrash ${f/%.flv/.m4a}"
~/Desktop/Uploads/ffmpeg/ffmpeg -i ${f} ${SPEEX_ADD} -vcodec copy -acodec copy -map 0:0 ${SPEEX_MAP} ${f/%.flv/.mp4} && rmtrash ${f} && ${SPEEX_TRASH}
else
~/Desktop/Uploads/ffmpeg/ffmpeg -i ${f} -vcodec copy -an ${f/%.flv/.mp4} && rmtrash ${f}
fi
done
I'm using a batch file to convert video files but I need help. What can I put in that third line that will make the batch file skip over files with flv1 video but continue onto the next file? Thanks for your help.
continue. Check the bash man page for details.
You can use the continue keyword. Have a look at the Loop Control page in the Advanced Bash-Scripting Guide

Resources