AppleScript + QuickTime — batch trim + create edit + export video - applescript

I'm looking for some help.
What I'm trying to do is to have AppleScript open a folder of videos, then get QuickTime to randomly trim them (as in the start frame from where it trims) and then have a variable length of the trim itself (say random between 1sec to 2sec as boundaries for the new 'clip'). After trimming and creating the new 'edit' (it would add this new random trimming to all the videos in the folder then add to timeline). QT then needs to export the edit to a new folder.
In summary, trying to make a quick auto-editing app that can just pick random selects from a folder full of videos then save an edit to a new video.
ANY help with this would be hugely appreciated!
I've been trying but to nail avail (I'm fairly new to coding to going around in circles).
Thanks!
Dylan

Like #CJK, I would recommend you use bash and ffmpeg as they are both available on macOS and both better known and more widely applicable than Applescript and QuickTime.
IMHO, as Apple does not ship a package manager, you would be well advised to use homebrew to install, update and remove packages. It is available on the homebrew website.
Once you have that, you can find any package you want with:
brew search packageXYZ
So, you can now install ffmpeg with:
brew install ffmpeg
Now you would want a bash script that:
loops through all your ".mov" files in a directory
gets their lengths
calculates a random duration
calculates a random start time
extracts that piece of video as a clip
and, finally at the end, assembles all the clips together
That will look something like this, which I would suggest you save in a bash script called $HOME/RandomClips
#!/bin/bash
# Set up globbing
shopt -s nullglob nocaseglob
# Clear list of files we are going to concatenate
> list.txt
N=1
# Loop through all ".MOV" files
for f in *.MOV ; do
# Tell user which one we are processing
echo Processing file $f
# Get length of this video in seconds
duration=$(mdls -raw -name kMDItemDurationSeconds "$f")
echo ... Duration: $duration
# Generate a random clip length less than 5 seconds
((seconds=RANDOM%5))
echo ... Clip length: $seconds
# Generate start time
((start=RANDOM%(duration-seconds)))
echo ... Start time: $start
# Extract clip into file called "Clip-1.mov", "Clip-2.mov" etc
clipname="Clip-$N.mov"
echo ... Extracting $clipname
ffmpeg -hide_banner -ss $start -i "$f" -t $seconds -pix_fmt yuv420p "$clipname"
# Add name of this clip to the list of files to concatenate at the end
echo "file $clipname" >> list.txt
# Increment clip counter
((N=N+1))
done
# Now join together all the extracted clips into a single file
ffmpeg -hide_banner -f concat -i list.txt -c copy -pix_fmt yuv420p mergedVideo.mov
Now you need to make that executable, just necessary once, with:
chmod +x $HOME/RandomClips
Then use cd to navigate to a directory of movies:
cd some/place/with/movies
and run the script with:
$HOME/RandomClips
The script is not the most robust or well-tested in the entire world but it should be 90+% good. You may have to resize videos to a fixed size so they all match formats. Likewise with codecs. Probably ask another question if that becomes an issue.
No-one said answers have to be 100% perfect, and as no-one else has suggested anything, this will hopefully get you well on your way.
If you want to debug the script, you can:
read the debug output line by line
check all the extracted clips look correct, i.e, "Clip-1.mov", "Clip-2.mov"
read the file called "list.txt" to see if it contains all the clips

Related

omxplayer - Seamless looping of a directory

I'm trying to make a script/program that will seamlessly loop through all video files in a directory using omxplayer. So far my best solution was using ffmpeg to concat the videos of the directory and loop the output using omxplayer --loop output, but I've kept running into issues with different framerates and codecs of videos and the concating itself takes way longer than I can afford. Does anyone have a clue or a snippet on how digital signage software solutions loop their videos?
Try this.
#!/bin/sh
while : ;
do for f in /videos-location/*.mp4;
do omxplayer -n -l "$f";
done;
done

Bash single quote in filename and ffmpeg escaping

I want to convert a list of flac files to mp3 using ffmpeg.
I have written the list of files to convert in a file.
Here is my script
#!/bin/bash
while read -r line
do
ffmpeg -i "$line" -ab 320k "${line%.flac}.mp3"
done < flac_list
It works, however when a filename contains a single quote, it does not work.
And here begins my escaping nightmare.
I have found dozens of combinations without find how to make it work.
Could someone help ?
Thanks to #chepner, the -nostdin flag appended to ffmpeg solves the issue.
I have found too that ffmpeg has surprising problems sometimes if it encounters certain characters in the filename. I stumbled over this problem when converting m4a to mp3 using a script. I didn't know that an innocent single-quote is one of them.
What you can do - aside of reporting a bug to ffmpeg - is to test, whether your filename contains an unwanted character, and either rename the file or create a symbolic link to the file, using a "good" name, and undo these changes when your conversion is done.

passing script variable of filename with spaces in bash to external program (ffmpeg) fails

Short story: I'm trying to write a script that will use FFmpeg to convert the many files stored in one directory to a "standard" mp4 format and save the converted files in another directory. It's been a learning experience (a fun one!) since I haven't done any real coding since using Pascal and FORTRAN on an IBM 370 mainframe was in vogue.
Essentially the script takes the filename, strips the path and extension off it, reassembles the filename with the path and an mp4 extension and calls FFmpeg with some set parameters to do the conversion. If the directory contains only video files with without spaces in the names, then everything works fine. If the filenames contain spaces, then FFmpeg is not able to process the file and moves on to the next one. The error indicates that FFMpeg is only seeing the filename up to the first space. I've included both the script and output below.
Thanks for any help and suggestions you may have. If you think I should be doing this in another way, please by all means, give me your suggestions. As I said, it's been a long time since I did anything like this. I'm enjoying it though.
I've include the code first followed by example output.
for file in ./TBC/*.mp4
do
echo "Start of iteration"
echo "Full text of file name:" $file
#Remove everything up to "C/" (filename without path)
fn_orig=${file#*C/}
echo "Original file name:" $fn_orig
#Length of file name
fn_len=${#fn_orig}
echo "Filename Length:" $fn_len
#file name without path or extension
fn_base=${fn_orig:0:$fn_len-4}
echo "Base file name:" $fn_base
#new filename suffix
newsuffix=".conv.mp4"
fn_out=./CONV/$fn_base$newsuffix
echo "Converted file name:" $fn_out
ffmpeg -i $file -metadata title="$fn_orig" -c:v libx264 -c:a libfdk_aac -b:a 128k $fn_out
echo "End of iteration"
echo
done
echo "Script completed"
With the ffmpeg line commented out, and two files in the ./TBC directory, this is the output that I get
Start of iteration
Full text of file name: ./TBC/Test file with spaces.mp4
Original filename: Test file with spaces.mp4
Filename Length: 25
Base filename: Test file with spaces
Converted file name: ./CONV/Test file with spaces.conv.mp4
End of iteration
Start of iteration
Full text of file name: ./TBC/Test_file_with_NO_spaces.mp4
Original file name: Test_file_with_NO_spaces.mp4
Filename Length: 28
Base file name: Test_file_with_NO_spaces
Converted file name: ./CONV/Test_file_with_NO_spaces.conv.mp4
End of iteration
Script completed
I won't bother to post the results when ffmpeg is uncommented, other than to state that it fails with the error:
./TBC/Test: No such file or directory
The script then continues to the next file which completes successfully because it has no spaces in its name. The actual filename is "Test file with spaces.mp4" so you can see that ffmpeg stops after the word "Test" when it encounters a space.
I hope this has been clear and concise and hopefully someone will be able to point me in the right direction. There is a lot more that I want to do with this script such as parsing subdirectories and ignoring non-video files, etc.
I look forward to any insight you can give!
try quoting you output file:
ffmpeg -i "$file" ... "$fn_out"
bash separates arguments based on spaces, so you have to tell him that $fn_out is one single argument; whence the "" to show that this is one argument.
There is another edge-case where spaces break bash for loops.
"BASH for loop works nicely under UNIX / Linux / Windows and OS X while working on set of files. However, if you try to process a for loop on file name with spaces in them you are going to have some problem. For loop uses $IFS variable to determine what the field separators are. By default $IFS is set to the space character..."
https://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html
Before:
for file in $(find . -name '*.txt'); do echo "$file"; done
Outputs:
./files/my
documents/item1.txt
./files/my
documents/item2.txt
./files/my
documents/item3.txt
Therefore you should set IFS to ignore spaces.
After:
IFS=$'\n'
for file in $(find . -name '*.txt'); do echo "$file"; done
Outputs:
./files/my documents/item1.txt
./files/my documents/item2.txt
./files/my documents/item3.txt

Incorporating ffmpeg in a bash script

I have a very large audio mp4 file that contains several songs.
I have generated a script which reads a text file with the times and the song names and successfully assigns starttime, endtime and songtitle in 3 variables. The script successfully echoes the variables and returns the following format:
00:00:00 00:10:15 Song1
00:10:15 00:14:20 Song2
and so on...
Now I am intending to use this script with ffmpeg and crop each part of the big file into smaller audio files.
The script thus, after feeding the variables in a while loop, it reaches to the command
ffmpeg -ss $START -t $END -i ${1} -acodec copy $SONGNAME.mp4
Once I run the script, the first two songs are cropped, but then the whole process stops with
Press [q] to stop, [?] for help
error parsing debug value
debug=0
I checked the generated files and they play ok, but there is no way for me to know why the script stopped there and did no proceed to the rest of the file (considering that when in the script I replace ffmpeg with echo, the script echoes the variables flawlessly).
In other words I don't know if there is a problem in my script, ffmpeg, or the source music file.
In this case I would add the argument -nostdin to ffmpeg.

bash while loop and ffmpeg

Sorry for this questions I imagine the answer is pretty straightforward however I have had a search and I haven't found anything that answers it.
I have written the following:
while read p # reads in each line of the text
do # file- folder_list.txt each iteration.
echo "$p" # print out current line
if [ -f $p/frame_number1.jpg ] # checks if the image exists in the specific folder
then
echo "$p" #prints specific folder name
sleep 1 #pause for 1 second
ffmpeg -f image2 -r 10 -i $p/frame_number%01d.jpg -r 30 $p/out.mp4 #create video
fi # end if statement
done <folder_list.txt #end of while loop
The script is supposed to read a text file which contains the folder tree structure, then check if the folder contains the specified JPEG if it does then the code should create a video from the images contained within the specified folder.
However what appears to be happening is the script skips whole folders that definitely contain images. I was wondering if the while loop is continuing to iterate whilst the video is being created or if something else is happening?
Any help would be greatly appreciated.
Many thanks in advance
Laurence
It could be because some folders contain spaces, or other weird characters.
Try this (won't work for ALL but for MOST cases):
while read p # reads in each line of the text file- folder_list.txt
do #each iteration
echo "$p" #print out current line
if [ -f "${p}/frame_number1.jpg" ] #checks wether the image exists in the specific folder
then echo "$p" #printsout specific folder name
sleep 1 #pause for 1 second
ffmpeg -f image2 -r 10 -i "${p}/frame_number%01d.jpg" -r 30 "${p}/out.mp4" #create video
fi # end if statement
done <folder_list.txt #end of while loop
I just added quotes around arguments involving "$p" so that if it contains space (and other things) it's not separated into several arguments, breaking the command
If this doesn't work, tell us exactly a few of the directories that are OK and the ones that are NOT ok :
ls -ald /some/ok/dir /some/NOTOK/dir #will show which directories belong to who
id #will tell us which user you are using, so we can compare to the previous and find out why you can't access some

Resources