I’ve created this script where I want to display the name of each file having mp4 as his extension for all subfolders of a parent folder.
i.e I other word I am attempting to: loop through subfolders of a parent folder.
I do not know what my problem is.
Thanks!
use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use framework "AVFoundation"
use scripting additions
set MP4DestinationFolder to POSIX path of "/Volumes/DATA/ZVinformatique/CompétitionCourante/"
--set MP4DestinationFolder to POSIX path of (choose folder)
tell application "Finder"
set thefolders to every folder of entire contents of MP4DestinationFolder
repeat with objItem in thefolders
display dialog "folder" & objItem
set mp4Files to (files in folder objItem whose name extension is "mp4") as alias list
if (count of mp4Files) is equal to 0 then
display dialog ("Aucun fichier mp4 dans le dossier " & MP4DestinationFolder)
return
end if
set countofmp4 to (count of mp4Files) as string
display dialog (countofmp4 & " fichier vidéo de format mp4 seront traiter " & MP4DestinationFolder)
repeat with fvideo in mp4Files
display dialog ("will be converting " & fvideo)
--my createclipvideo(fvideo)
end repeat
end repeat
end tell
The main problem is that the Finder doesn’t accept POSIX paths.
The syntax
POSIX path of "/Volumes/DATA/ZVinformatique/CompétitionCourante/"
is pointless anyway because the literal string is a POSIX path.
I recommend to use an alias with an HFS path (starting with a disk name). And remove the return line because a return statement on the top level will exit the script. Add an else clause instead.
set MP4DestinationFolder to alias "DATA:ZVinformatique:CompétitionCourante:"
tell application "Finder"
set thefolders to every folder of entire contents of MP4DestinationFolder
repeat with objItem in thefolders
display dialog "folder " & objItem
set mp4Files to (files in objItem whose name extension is "mp4")
set countofmp4 to (count of mp4Files)
if countofmp4 is equal to 0 then
display dialog ("Aucun fichier mp4 dans le dossier " & MP4DestinationFolder)
else
display dialog ((countofmp4 as text) & " fichier vidéo de format mp4 seront traiter " & MP4DestinationFolder)
repeat with fvideo in mp4Files
display dialog ("will be converting " & fvideo)
--my createclipvideo(fvideo)
end repeat
end if
end repeat
end tell
This small script is to be attached to a longer working script. I am now attaching the whole script.
The script is to create short video clips of longer video files found in a given folder. At the time, I’ve started this project I was to execute the script subfolder by subfolder individually. The situation has changed where I can no longer execute the script subfolders by subfolders.
To speed uptake execution time, I have to verify the clip already exist. If it does, the script is toby pass that file and go to the next one.
Thanks again for your help.
use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use framework "AVFoundation"
use scripting additions
set MP4DestinationFolder to alias "Volumes:DATA:ZVinformatique:CompétitionCourante:"
--Get the parent folder for which the CLIP function must be executed
tell application "Finder"
-- find all subfloder name
set thefolders to every folder of entire contents of MP4DestinationFolder
-- Go through each subolders found in the parent folder
repeat with objItem in thefolders
display dialog "folder " & objItem
set mp4Files to (files in objItem whose name extension is "mp4")
set countofmp4 to (count of mp4Files)
if countofmp4 is equal to 0 then
display dialog ("Aucun fichier mp4 dans le dossier " & MP4DestinationFolder)
else
repeat with fvideo in mp4Files
--Verify if clip already exist, do not recreate clip if already exist
if exists file fvideo then
return
else
--display dialog ("will be converting " & fvideo)
--call the CLIP function
my createclipvideo(fvideo)
end if
end repeat
end if
end repeat
end tell
on createclipvideo(fvideo)
set thePath to POSIX path of (fvideo)
set theURL to current application's NSURL's fileURLWithPath:thePath
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set destPath to (theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingString:"-clip")'s stringByAppendingPathExtension:"mp4"
set durationInfo to theAsset's duration()
if durationInfo is missing value then
set theTime to "unknown"
else
-- calculate duration in seconds and format as string
set theDuration to (value of durationInfo) / (timescale of durationInfo)
end if
set theStart to (0.65 * theDuration) div 1
set theEnd to 15
if theStart + 15 > theDuration then
set theStart to (0.55 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to (0.4 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to (0.25 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to 1
set theEnd to theDuration
end if
set destURL to current application's NSURL's fileURLWithPath:destPath
set startTime to current application's CMTimeMakeWithSeconds(theStart, 1)
set durTime to current application's CMTimeMakeWithSeconds(15, 1)
set theRange to current application's CMTimeRangeMake(startTime, durTime)
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set exportSession to current application's AVAssetExportSession's alloc()'s initWithAsset:theAsset presetName:(current application's AVAssetExportPresetHighestQuality)
exportSession's setOutputURL:destURL
exportSession's setOutputFileType:(current application's AVFileTypeQuickTimeMovie)
exportSession's setTimeRange:theRange
exportSession's exportAsynchronouslyWithCompletionHandler:(missing value)
repeat
delay 0.01
set theStatus to exportSession's status()
if theStatus > 2 then exit repeat -- 3 is OK
end repeat
if theStatus = 4 then error exportSession's |error|()'s localizedDescription() as text
end createclipvideo
The script is almost complete. I only have problems with verifying if the file exist. I’ve been trying different combination without success. THANKS!
set thePath to alias "Volumes:DATA:ZVinformatique:CompétitionCourante:01:pzv01001.mp4" as string
set the_colon_location to offset of "." in thePath
set the_starting_point to the_colon_location - 2
set the_ending_point to the_colon_location - 1
set theClipPath to characters 1 thru the_ending_point of thePath as string
set theClipPath to "Volumes:" & theClipPath & "-clip.mp4" as alias
display dialog ("***" & theClipPath & "***") as string
if not (exists file theClipPath) then
display dialog ("will be converting " & theClipPath)
--call the CLIP function
my createclipvideo(fvideo)
end if
on createclipvideo(fvideo)
set thePath to POSIX path of ("Volumes:" & fvideo)
end createclipvideo
You’re not going to have any success if you keep trying to use HFS paths and ignore Stefan’s point about not using Volumes.
Given that you’re already using ASObjC, and you’re having problems with how HFS paths work, you’d probably be better to avoid them and the Finder altogether:
use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use framework "AVFoundation"
use scripting additions
set MP4DestinationFolder to "/Volumes/DATA/ZVinformatique/CompétitionCourante/"
set destURL to current application's |NSURL|'s fileURLWithPath:MP4DestinationFolder
set theOptions to (current application's NSDirectoryEnumerationSkipsHiddenFiles) + (get current application's NSDirectoryEnumerationSkipsPackageDescendants)
set theURLs to (current application's NSFileManager's defaultManager()'s enumeratorAtURL:destURL includingPropertiesForKeys:(missing value) options:theOptions errorHandler:(missing value))'s allObjects()
set thePred to current application's NSPredicate's predicateWithFormat_("pathExtension == %@", "mp4")
set theURLs to theURLs's filteredArrayUsingPredicate:thePred
repeat with aURL in theURLs
display dialog ("will be converting " & aURL's |path|() as text)
my createclipvideo(fvideo)
end repeat
on createclipvideo(theURL)
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set destPath to (theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingString:"-clip")'s stringByAppendingPathExtension:"mp4"
set durationInfo to theAsset's duration()
if durationInfo is missing value then
set theTime to "unknown"
else
-- calculate duration in seconds and format as string
set theDuration to (value of durationInfo) / (timescale of durationInfo)
end if
set theStart to (0.65 * theDuration) div 1
set theEnd to 15
if theStart + 15 > theDuration then
set theStart to (0.55 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to (0.4 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to (0.25 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to 1
set theEnd to theDuration
end if
set destURL to current application's NSURL's fileURLWithPath:destPath
set startTime to current application's CMTimeMakeWithSeconds(theStart, 1)
set durTime to current application's CMTimeMakeWithSeconds(15, 1)
set theRange to current application's CMTimeRangeMake(startTime, durTime)
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set exportSession to current application's AVAssetExportSession's alloc()'s initWithAsset:theAsset presetName:(current application's AVAssetExportPresetHighestQuality)
exportSession's setOutputURL:destURL
exportSession's setOutputFileType:(current application's AVFileTypeQuickTimeMovie)
exportSession's setTimeRange:theRange
exportSession's exportAsynchronouslyWithCompletionHandler:(missing value)
repeat
delay 0.01
set theStatus to exportSession's status()
if theStatus > 2 then exit repeat -- 3 is OK
end repeat
if theStatus = 4 then error exportSession's |error|()'s localizedDescription() as text
end createclipvideo
The situation here is that I do not know the differences between HFS’ path and alias. Neither I do understand their behaviour. As of using AObjC, sincerely I do have no experiences.
This script has been growing up by browsing through the internet and asking questions on the MacScripter forum. I have been very fortunate to have people like you on MacScripter.
The AObjC module works very good in building short video clips. I have been using it over the weekend and found I’ve needed to improve the process in which the script was to be executed.
The script is to be executed over a folder name “/DATA/ZVinformatique/CompétitionCourante/xx/” being stored on a NAS by the name of “FARAMIR”. Over a given week-end I will be creating over 250 videos which are going to be of 2, 3, 4, up to 6 minutes.
Under “CompétitionCourante”, there will be up to 99 subfolders being created. Each subfolders will be containing the video files and 15 seconds clips of those video files.
I will be running the script as many time I will be having “xx” subfolders being created. I then need to find a mechanism which avoid trying to recreate clips which have already been created. This is what I what I was trying to do last. i.e skip re-creating a video 15 seconds video which has already been created.
Where could I get some information in order to code the last part being needed?
If I understand correct, I should be using POSIX path names instead of HFS path names?
You use HFS paths if you want to create aliases to pass to applications like the Finder. HFS paths are colon-delimited and never begin with Volumes – they begin with the name of the volume, as it appears in the Finder. POSIX paths are slash-delimited, and for remote volumes will begin with “/Volumes/”.
Where the script says:
on createclipvideo(theURL)
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set destPath to (theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingString:"-clip")'s stringByAppendingPathExtension:"mp4"
Insert the following two lines:
set destURL to current application's NSURL's fileURLWithPath:destPath
if (destURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then return
That will check if the file exists, and if so go no further with it.
Unfortunately at the moment, it keeps running even if the “-clip” file already exist.
Original file : pzv01001.mp4
First time the script run create: pzv01001-clip.mp4
Second time the script run creates : pzv01001-clip-clip.mp4
Third time the script run creates : pzv01001-clip-clip-clip.mp4
on createclipvideo(fvideo)
set thePath to POSIX path of (fvideo)
set theURL to current application's NSURL's fileURLWithPath:thePath
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set destPath to (theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingString:"-clip")'s stringByAppendingPathExtension:"mp4"
set destURL to current application's NSURL's fileURLWithPath:destPath
if (destURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then return
It doesn’t really. It’s just that as you search the folder each time for all .mp4 files, it catches the -clip files and therefore tries to make clips of them. You need to filter them out at the beginning.
So change this line:
set thePred to current application's NSPredicate's predicateWithFormat_("pathExtension == %@", "mp4")
To this:
set thePred to current application's NSPredicate's predicateWithFormat:"(pathExtension == %@) AND (lastPathComponent.stringByDeletingPathExtension ENDSWITH %@)" argumentArray:{"mp4", "-clip"}
At the moment with the new line it does not get into the repeat with aURL in theURLs loop.
If should only process “.mp4” files but not those mp4 files ending by “-clip.mp4”
For example, the first time “pzv01001.mp4” should be processed to create “pzv01001-clip.mp4”.
The next time the script is being processed, a 15 second clip should not be created for “pzv01001.mp4” s because “pzv01001-clip.mp4” already exist.
Let’s say:
pzv01001.mp4 look if (pzv01001-clip.mp4 exist ; yes-skip ; no process to create pzv01001-clip.mp4)
pzv01002.mp4 look if (pzv01002-clip.mp4 exist ; yes-skip ; no process to create pzv01002-clip.mp4)
Thanks!
use AppleScript version "2.5" -- macOS 10.11 or later
use framework "Foundation"
use framework "AVFoundation"
use scripting additions
set MP4DestinationFolder to "/Volumes/DATA/ZVinformatique/CompétitionCourante/"
set destURL to current application's |NSURL|'s fileURLWithPath:MP4DestinationFolder
set theOptions to (current application's NSDirectoryEnumerationSkipsHiddenFiles) + (get current application's NSDirectoryEnumerationSkipsPackageDescendants)
set theURLs to (current application's NSFileManager's defaultManager()'s enumeratorAtURL:destURL includingPropertiesForKeys:(missing value) options:theOptions errorHandler:(missing value))'s allObjects()
--set thePred to current application's NSPredicate's predicateWithFormat_("pathExtension == %@", "mp4")
set thePred to current application's NSPredicate's predicateWithFormat:"(pathExtension == %@) AND (lastPathComponent.stringByDeletingPathExtension ENDSWITH %@)" argumentArray:{"mp4", "-clip"}
set theURLs to theURLs's filteredArrayUsingPredicate:thePred
repeat with aURL in theURLs
--display dialog ("will be converting " & aURL's |path|() as text)
my createclipvideo(aURL)
end repeat
display dialog ("after repeat")
on createclipvideo(theURL)
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set destPath to (theURL's |path|()'s stringByDeletingPathExtension()'s stringByAppendingString:"-clip")'s stringByAppendingPathExtension:"mp4"
set destURL to current application's NSURL's fileURLWithPath:destPath
if (destURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then return
set durationInfo to theAsset's duration()
if durationInfo is missing value then
set theTime to "unknown"
else
-- calculate duration in seconds and format as string
set theDuration to (value of durationInfo) / (timescale of durationInfo)
end if
set theStart to (0.65 * theDuration) div 1
set theEnd to 15
if theStart + 15 > theDuration then
set theStart to (0.55 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to (0.4 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to (0.25 * theDuration) div 1
set theEnd to 15
end if
if theStart + 15 > theDuration then
set theStart to 1
set theEnd to theDuration
end if
set destURL to current application's NSURL's fileURLWithPath:destPath
set startTime to current application's CMTimeMakeWithSeconds(theStart, 1)
set durTime to current application's CMTimeMakeWithSeconds(15, 1)
set theRange to current application's CMTimeRangeMake(startTime, durTime)
set theAsset to current application's AVURLAsset's assetWithURL:theURL
set exportSession to current application's AVAssetExportSession's alloc()'s initWithAsset:theAsset presetName:(current application's AVAssetExportPresetHighestQuality)
exportSession's setOutputURL:destURL
exportSession's setOutputFileType:(current application's AVFileTypeQuickTimeMovie)
exportSession's setTimeRange:theRange
exportSession's exportAsynchronouslyWithCompletionHandler:(missing value)
repeat
delay 0.01
set theStatus to exportSession's status()
if theStatus > 2 then exit repeat -- 3 is OK
end repeat
if theStatus = 4 then error exportSession's |error|()'s localizedDescription() as text
end createclipvideo
set thePred to current application's NSPredicate's predicateWithFormat:"(pathExtension == %@) AND (NOT lastPathComponent.stringByDeletingPathExtension ENDSWITH %@)" argumentArray:{"mp4", "-clip"}
WOW! This one was a VERY big one for me to accomplished.
My process of recording videos with short clips that accompany them will make it easier for me. This is something I wanted to do for many years. I knew this was going to be a VERY BIG challenge for me.
I want to say thanks to all of those who helped me out with this. A special thanks to Stefank and to Shane Stanley. Impossible for me to this without your help.
I will try in the future to be more careful with HFS path ( no “Volumes” and POSIX path (/) “with remote volume (external disk) will start with /Volumes/” paths.