In case you need to get the path attached to the returned datas (as is done by my original script) you may edit the second loop of Shane’s script this way :
repeat with i from 1 to theCount
set aResult to (theQuery's resultAtIndex:(i - 1))
set thePath to (aResult's valueForAttribute:(current application's NSMetadataItemPathKey)) # ADDED
set theName to (aResult's valueForAttribute:(current application's NSMetadataItemDisplayNameKey))
set theDuration to (aResult's valueForAttribute:(current application's NSMetadataItemDurationSecondsKey))
try
set theDuration to (theFormatter's stringFromTimeInterval:theDuration)
on error
set theDuration to "unknown"
end try
-- format values tab-delimited
-- set thePath to (POSIX file (thePath as text)) as text # If you want to convert it into Hfs path
(theResults's addObject:(current application's NSString's stringWithFormat_("%@ %@ %@", thePath, theName's stringByDeletingPathExtension(), theDuration))) # EDITED
end repeat
CAUTION. I added an instruction which may be enabled if you want to get Hfs path of the files. It may be useful if a component of the Hfs path contained a slash which is automatically replaced by a colon in POSIX format.
Yvan KOENIG running Sierra 10.12.5 in French (VALLAURIS, France) mardi 18 juillet 2017 14:23:50
As the list of names and durations is not linked to a list of paths, it would be difficult to retrieve which file has a given couple of datas.
If a folder contain a file named trucmuche.mov and a file named trucmuche.mp4 how will you identify which one own the couple {trucmuche, 2:34} and which one own the couple {trucmuche, 1:23} ?
It’s why I took care to return the three values for every file.
More, with Shane’s code - which is recursive - we may have different files with the same name in several subfolders.
But maybe it doesn’t make sense for the asker.
I just choose to play safe.
Yvan KOENIG running Sierra 10.12.5 in French (VALLAURIS, France) mardi 18 juillet 2017 15:21:31
OK, I’ve taken the first code provided by Yvan and ran it on a local folder and the result was OK. However, running the same code with the data located on a NAS did not work. The duration is set to null.
More than likely, the video files are going to be on an external drive. Bizarre, when looking at the directory path everything is correct. Why would that be ?
THANKS AGAIN!
--set hfsPath to "Seagate 3TB:Jazz youtube:Jimmy Giuffre:" as alias
set hfsPath to choose folder
set ourFilesAndNames to my listFolder:hfsPath
set localDecimalSeparator to item 2 of (0.1 as text) # Useful to convert the string duration to a number
set ourDescriptors to {}
repeat with aCouple in ourFilesAndNames
set {hfsPath, itsBareName} to contents of aCouple
set theDuration to (do shell script "mdls " & quoted form of POSIX path of hfsPath & " -name kMDItemDurationSeconds")
display dialog "hfsPath: " & hfsPath
--display dialog "theDuration: " & theDuration
--> "kMDItemDurationSeconds = 500.7366666666667"
set theDuration to my remplace(theDuration, "kMDItemDurationSeconds = ", "")
--> "500.7366666666667"
# or
--> "(null)"
try
set theDuration to my remplace(theDuration, ".", localDecimalSeparator) as number
# Convert it in minutes:seconds
set theSeconds to theDuration mod 60
set theMinutes to theDuration div 60
if theMinutes > 59 then
set theHours to theMinutes div 60
set theMinutes to theMinutes mod 60
set theDuration to text 2 thru 3 of ((100 + theHours) as text) & ":" & text 2 thru 3 of ((100 + theMinutes) as text) & ":" & text 2 thru 3 of ((100 + theSeconds) as text)
else
set theDuration to text 2 thru 3 of ((100 + theMinutes) as text) & ":" & text 2 thru 3 of ((100 + theSeconds) as text)
end if
on error
set theDuration to "(null)"
end try
set thePath to hfsPath as text
set thePath to POSIX path of hfsPath # Enable it if you want to get POSIX paths
set end of ourDescriptors to {thePath, itsBareName, theDuration}
end repeat
ourDescriptors
#=====
on listFolder:anAlias
tell application "Finder"
set allFiles to every file in anAlias as alias list
set ourFiles to {}
repeat with aFile in allFiles
set itsExtension to name extension of aFile
if itsExtension is in {"webm", "mp4", "mov"} then # Edit to fit your needs
set itsName to get name of aFile
set end of ourFiles to {aFile as text, text 1 thru -(2 + (count itsExtension)) of itsName}
end if
end repeat
end tell
return ourFiles
end listFolder:
#=====
(*
replaces every occurences of d1 by d2 in the text t
*)
on remplace(t, d1, d2)
local oTIDs, l
set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d1}
set l to text items of t
set AppleScript's text item delimiters to d2
set t to l as text
set AppleScript's text item delimiters to oTIDs
return t
end remplace
#=====
All the alternatives here rely on Spotlight, which won’t index your NAS disks. In fact, I think you will find that Get Info also fails to get the duration of files stored on your NAS disks, for the same reason.
You can, however, get it using AVFoundation. This script requires 10.11 or later:
use AppleScript version "2.5" -- 10.11 or later
use framework "Foundation"
use framework "AVFoundation"
use scripting additions
-- get files
set theFolder to choose folder
set theURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of theFolder)
set fileManager to current application's NSFileManager's defaultManager()
set {theFiles, theError} to fileManager's contentsOfDirectoryAtURL:theURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(reference)
-- eliminate non-video files
set thePred to current application's NSPredicate's predicateWithFormat:"pathExtension IN %@" argumentArray:{{"mp4", "mov", "webm"}}
set vidFiles to theFiles's filteredArrayUsingPredicate:thePred
-- set up results array, formatter for duration
set theResults to current application's NSMutableArray's array()
set theFormatter to current application's NSDateComponentsFormatter's new()
-- lop through
repeat with aFile in vidFiles
-- get localized name
set {theResult, theName, theError} to (aFile's getResourceValue:(reference) forKey:(current application's NSURLLocalizedNameKey) |error|:(reference))
-- create an AVAsset so you can get duration
set theAsset to (current application's AVURLAsset's assetWithURL:aFile)
set durationInfo to theAsset's duration() -- returns record like: {value:2911360, timescale:1000, flags:1, epoch:0}
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)
set theDuration to (theFormatter's stringFromTimeInterval:theDuration)
end if
(theResults's addObject:(current application's NSString's stringWithFormat_("%@ %@", theName's stringByDeletingPathExtension(), theDuration)))
end repeat
return (theResults's componentsJoinedByString:linefeed) as text
Exactly, “Get Info” fails to get the duration of files stored on my NAS disks.
I ran the script created by Shane and it now work on my NAS.
I’ll keep working on the script because this is only the beginning.
Many thanks everybody, this was impossible for me to write something like this. I do have a real lack of knowledge when comes to write such AppleScript programs.
If its possible can the text file be saved in the same location when the script prompted in the beginning where I selected the folder that contained the media
Hopefully I have explained what I am looking to do
Here is how to write to text file. But with avi and mkv movies the Shane’s script gives durations=0. I don’t know why. Well, to write durations to text file replace this:
return (theResults's componentsJoinedByString:linefeed) as text
with this:
set aText to (theResults's componentsJoinedByString:linefeed) as text
set filepath to (POSIX path of theFolder) & "myMoviesDurations.txt"
set openfile to open for access filepath with write permission
write aText as «class utf8» to openfile
close access openfile
Maybe I am pushing my luck here a bit but would it be possible to get the duration with frames also
for eg. 01(hours)04(minutes)23(seconds)04(frames) > 01:04:23:04
also could I set the “myMoviesDurations.txt” to the name of the folder the media is sitting in (POSIX path of theFolder)
use AppleScript version "2.5" -- 10.11 or later
use framework "Foundation"
use framework "AVFoundation"
use scripting additions
-- get files
set theFolder to choose folder
set theURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of theFolder)
set fileManager to current application's NSFileManager's defaultManager()
set {theFiles, theError} to fileManager's contentsOfDirectoryAtURL:theURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(reference)
-- eliminate non-video files
set thePred to current application's NSPredicate's predicateWithFormat:"pathExtension IN %@" argumentArray:{{"mp4", "mov", "webm"}}
set vidFiles to theFiles's filteredArrayUsingPredicate:thePred
-- set up results array, formatter for duration
set theResults to current application's NSMutableArray's array()
set theFormatter to current application's NSDateComponentsFormatter's new()
-- lop through
repeat with aFile in vidFiles
-- get localized name
set {theResult, theName, theError} to (aFile's getResourceValue:(reference) forKey:(current application's NSURLLocalizedNameKey) |error|:(reference))
-- create an AVAsset so you can get duration
set theAsset to (current application's AVURLAsset's assetWithURL:aFile)
set durationInfo to theAsset's duration() -- returns record like: {value:2911360, timescale:1000, flags:1, epoch:0}
if durationInfo is missing value then
set theTime to "unknown"
set framesNumber to "unknown"
else
-- calculate duration in seconds and format as string
set theSeconds to (value of durationInfo) / (timescale of durationInfo)
set theDuration to (theFormatter's stringFromTimeInterval:theSeconds)
-- Determine frames number here
set theTracks to (get theAsset's tracks())
repeat with i from 1 to count theTracks
set aTrack to item i of theTracks
if (aTrack's mediaType()) as string is "vide" then exit repeat
end repeat
set videoTrack to aTrack
set frameRate to videoTrack's nominalFrameRate()
set framesNumber to (theSeconds * frameRate) as integer
end if
(theResults's addObject:(current application's NSString's stringWithFormat_("%@ %@:%@", theName's stringByDeletingPathExtension(), theDuration, framesNumber)))
end repeat
set aText to (theResults's componentsJoinedByString:linefeed) as text
tell application "Finder" to set folderName to name of theFolder
set filepath to (POSIX path of theFolder) & folderName & ".txt"
set openfile to open for access filepath with write permission
set eof of openfile to 0
write aText as «class utf8» to openfile
close access openfile
I see the script works out the entire frame count of the full duration of the file for eg 6530 which is the correct amount of frames for a 4min21sec05frames file at 25frames per a second
The duration of the file I have for eg. 00(h):04(m):21(sec):05(frames)
The previous script would just give the duration of 4m21sec and discard the 05 frames
How can I get the whole timecode represented with out the script rounding off the frames to the closest second ?
I was thinking if we started with the the full frame count and went from frames > timecode
I found the below script about getting frame count and converting to timecode but I haven’t figured how to apply it to KniazidisR frame count in the last script he wrote
tell application “QuickTime Player”
tell document 1 to set {currentTime, timeScale, theDuration, FrameCount} to {current time, time scale, duration, count (frames of track “Video track”)}
end tell
set FrameRate to (FrameCount * timeScale) / theDuration div 1
tell (currentTime / timeScale) to set {hr, mn, sc} to {it div 3600, it mod 3600 div 60, it mod 3600 mod 60 div 1}
set fr to (currentTime mod timeScale div (timeScale / FrameRate))
set SMPTE to addZero(TimeOffset + hr) & “:” & addZero(mn) & “:” & addZero(sc) & “:” & addZero(fr)
display dialog "TCR " & SMPTE
Could anyone help
What I am asking is there a way from the original script in this forum to have not just the hour:Minutes:seconds displayed but also the frames so the whole timecode of each video
hh:mm:ss:ff