Update Targets by Version or Date

 
 

Explanation

Automates the tedious task of replacing all your audio and video media with newer versions. It's worth being more informed about how this one works.

There are 2 ways the script checks for versions; updating by version numbering (_v1) or by a date string (20201217). And there are scripts that either update selected, or update all cues in the cue list, as well as a script file to make a watch folder using Apple's Folder Action Scripts.

The script looks at each cue and looks at the directory where the file target is, and looks at the other files in that same folder for a matching name with a newer version or date.

The script does not distinguish between file types, having the thought in mind that it is then easier to use a .png placeholder for a future .mov file.

Making "watch folders" only triggers a universal script every time a file is placed inside certain folders. (So it will still consider files stored outside your "watch folders.") That's maybe the most important detail to understand.

 

It is possible to mark a cue in QLab to not be updated by the script (read below).

It also leaves a log in the notes when a cue's target was updates, with the date and time, as well as which specific script did the action.

(It is then possible to use Command+F to search the workspace cue notes for any updates, or specific dates or times)

 

What kind of version notation is accepted?

The basic requirements are an underscore, lowercase v, then a number like "_v1"

The script supports an inconsistent number of character spaces in the version (like _v00003 to _v4) and it also supports one lower case letter. (_v4a to _v4b)

It also adapts to wherever the version number is located in the title, as long as it starts with "_v" and there is either a space or an underscore after the version number. ("blah_v023c blach blach.png" or "blah blahddy blah_v023c.png")

It also checks for a number following the "_v" so that "Vivaldi 4 Seasons_very_violent_violins_v3b_viola stem.mp3" can be used.

 

What kind of date notation is accepted?

The script looks for YYYY-MM-DD-HH-MM format. You can use any character to separate year from month, etc. or use no character separators at all, as long as no more than 2 non-number characters occur in a row before all 12 numbers are found. But you need all 12 numbers. "202012170755" or "2020-+12=)17*&07$%55" are both acceptable.

The script then checks to make sure the set of numbers is a reasonable date (month is 12 or less, day is 31 or less) but doesn't limit by shorter months (February 31st gets no error).

 

How the "watch folders" work.

Setting up a Folder Action Script triggers a script to run any time any file is added to that folder, using the frontmost workspace in QLab at that time. The scripting is then identical to the "update all" script, meaning that every single cue's target is then checked for an update, regardless of their cue target being in that watch folder. If files are added to the watch folder while QLab is not open, the script will just bail and not execute anything.

But once you do open QLab, any file added triggering the script will catch up all the other cues to newer versions. Or you could just execute the "update all" script in QLab on reopening.

If you are using multiple open workspaces, you'll just have to go through the script yourself and adapt it to target a specific workspace, or figure out whatever else you want to do about it. =P

 

How to make a specific cue exempt from updates by the script

If a cue's note contains "do not update" "don't update" or "no update" anywhere in the notes, that cue's target will not be updated. Capitalization doesn't matter, so a cue is exempt if you write "DO NOT UPDATE", "nO uPdaTe", or even "Please don't update, or Kevin is going to fire me."

 

Script

Copy the text to the right, and paste it into a script cue in your QLab workspace.

I recommend assigning it a hotkey, or I like to give each script cue a unique cue number using letters, and then trigger it from Bitfocus Companion.

Download QLab Workspace Here

(*This script takes all audio/video cues in the workspace, finds their locations, and looks for newer versions using the "_v###x " syntax, or  YYYY-MM-DD-HH-MM syntax at the front of the file name. 

For "_v###x " syntax, it adapts to as many digits as are used. Only one lowercase letter can be at the end of the file version, but letters are not required. The version can appear anywhere in the file name. The only requirements are that either a "_" or a " " appear after the version indicator.

For YYYY-MM-DD-HH-MM syntax, 12 numbers must be used in the date, and any character (or no character) can be used to separate years from months, etc. If there are more than 2 non-number characters between numbers, the script considers this a break in the date format. The script also checks if the 12 numbers qualify as a date by checking if the month value is over 12, if the day value is over 31, etc. (This does currently allow non-existent dates like February 31st)

It also checks to make sure the cues are audio or video cues, that their files contain "_v" and that the notes don't contain any of the following: "do not update", "don't update", or "no update" (not case sensitive)
Also recommend saving this script into Folder Actions Setup through finder to create Watch Folders.
Just sandwich it between:"
on adding folder items to theAttachedFolder after receiving theNewItems
tell application "System Events"
if (get name of every application process) contains "QLab" then
"
and...
"
end if --ends condition that QLab is currently running
end tell
end adding folder items to
"

and save the script file to /Library/Scripts/Folder Action Scripts/
then you just apply it by option clicking a folder, "Services", "Folder Actions Setup.."
--guide at https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/WatchFolders.html?fbclid=IwAR2PxiZ8Bh8IzycaasZTcRF5dtIhNgTbiq_Du8TVxId6yP_mWZvgBn2rg8c#//apple_ref/doc/uid/TP40016239-CH39-SW1
-Taylor Glad Updated 7/15/21
*)

tell application id "com.figure53.QLab.4" to tell front workspace


--Dialog asks user if they want to Update all files, or just the selected ones **For Watch Folder Script, replace this dialog with the section immediately below it)
display dialog "Update selected cues, or all cues in the workspace" with title "Update Selected/All" with icon 1 buttons {"Selected", "All"} default button "All"
if button returned of result = "Selected" then
set theCues to the selected as list
set whichScript to "Update-Selected"

else
set theCues to cues whose q type is "Video"
set theCues to theCues & (cues whose q type is "Audio")
set whichScript to "Update-All"
end if

(*For Watch Folder, replace section above with:
set theCues to cues whose q type is "Video"
set theCues to theCues & (cues whose q type is "Audio")
set whichScript to "Update-All"
*)



set filesUpdated to 0
repeat with eachCue in theCues

--Checks that the cue is an audio or video cue
if (the q type of eachCue is not "Video") or (the q type of eachCue is not "Audio") then


--checks if the cue notes contains "do not update" or "don't Update" or "no update"
--this first big chunk is to make the notes all lowercase, so it is not case sensitive
set theDescription to the notes of eachCue
set theComparisonCharacters to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set theSourceCharacters to "abcdefghijklmnopqrstuvwxyz"
set theAlteredText to ""
repeat with aCharacter in theDescription
set theoffset to offset of aCharacter in theComparisonCharacters
if theoffset is not 0 then
set theAlteredText to (theAlteredText & character theoffset of theSourceCharacters) as string
else
set theAlteredText to (theAlteredText & aCharacter) as string
end if
end repeat
if theAlteredText does not contain "do not update" and theAlteredText does not contain "don’t update" and theAlteredText does not contain "no update" then

if (the q default name of eachCue as text) contains "_v" then
try
set currentFileTarget to POSIX path of (file target of eachCue as alias)

set AppleScript's text item delimiters to "/"
set OGFileVersion to last item of every text item of currentFileTarget
set AppleScript's text item delimiters to "_v"
set fileBaseName1 to item 1 of every text item of OGFileVersion

---------check for number after _v
set chunkOptions to number of text items of OGFileVersion
set versionFound to false
set fileBaseName2 to ""
repeat with chunkOption from 2 to chunkOptions
set theFirstCharacter to (item 1 of item chunkOption of every text item of OGFileVersion)

if "0123456789" contains theFirstCharacter then
set fileVersionChunk to item chunkOption of every text item of OGFileVersion
set versionFound to true

else
if versionFound then
set fileBaseName2 to "_v" & item chunkOption of every text item of OGFileVersion
else
set fileBaseName1 to fileBaseName1 & "_v" & item chunkOption of every text item of OGFileVersion
end if
end if

end repeat

--look for "_" or "." or " "   --- need fileVersion and fileBaseName2
if fileVersionChunk contains "_" then
set AppleScript's text item delimiters to "_"
set fileVersion to item 1 of every text item of fileVersionChunk
set AppleScript's text item delimiters to "_v"
set thirdFilePart to last item of every text item of fileVersionChunk
set AppleScript's text item delimiters to fileVersion
set thirdFilePart to last item of every text item of thirdFilePart
set AppleScript's text item delimiters to "."
set fileBaseName2 to fileBaseName2 & item 1 of every text item of thirdFilePart
set AppleScript's text item delimiters to ""

else if fileVersionChunk contains " " then
set AppleScript's text item delimiters to " "
set fileVersion to item 1 of every text item of fileVersionChunk
set AppleScript's text item delimiters to "_v"
set thirdFilePart to last item of every text item of fileVersionChunk
set AppleScript's text item delimiters to fileVersion
set thirdFilePart to last item of every text item of thirdFilePart
set AppleScript's text item delimiters to "."
set fileBaseName2 to fileBaseName2 & item 1 of every text item of thirdFilePart
set AppleScript's text item delimiters to ""
else
set AppleScript's text item delimiters to "."
set fileVersion to item 1 of every text item of fileVersionChunk
set AppleScript's text item delimiters to ""
set fileBaseName2 to fileBaseName2 & ""
end if


---NOW clean off the .mp3 extention from the fileBaseName2
if fileBaseName2 contains "." then
set AppleScript's text item delimiters to "."
set fileBaseName2 to item 1 of every text item of fileBaseName2
set AppleScript's text item delimiters to ""
end if


--locate folder
set filePath to (file target of eachCue as alias)
tell application "Finder" to set fileFolderPath to POSIX path of ((container of filePath) as text)

--Get a list of all the files in the same folder with matching base file name
tell application "Finder" to set fileNames to (list folder (fileFolderPath) without invisibles)
set matchingFiles to {}

if fileBaseName2 is "" then
repeat with eachFile in fileNames
if eachFile contains fileBaseName1 then
set the end of matchingFiles to eachFile as text
end if
end repeat
else
repeat with eachFile in fileNames
if (eachFile contains fileBaseName1) and (eachFile contains fileBaseName2) then
set the end of matchingFiles to eachFile as text
end if
end repeat
end if
--find what the highest version number is
set listPosition to 0
set theHighestNumber to 0
set highestMatchingFileVersionLetterValue to 0
set matchingFileVersionLetter to ""
set finalMatchingFileVersionLetter to ""
set matchingFileVersionLetterValue to 0
set finalList to {}
repeat with eachMatchingFile in matchingFiles
set matchingFileVersionLetter to ""
set listPosition to listPosition + 1


set AppleScript's text item delimiters to "_v"

---------check for number after _v
set matchingChunkOptions to number of text items of eachMatchingFile as text
repeat with matchingChunkOption from 2 to matchingChunkOptions
set theFirstCharacter to (item 1 of item matchingChunkOption of every text item of eachMatchingFile as text)
if "0123456789" contains theFirstCharacter then
set matchingVersionChunk to item matchingChunkOption of every text item of eachMatchingFile as text
end if

end repeat

if matchingVersionChunk contains "_" then
set AppleScript's text item delimiters to "_"
set matchingFileVersion to item 1 of every text item of matchingVersionChunk
else if matchingVersionChunk contains " " then
set AppleScript's text item delimiters to " "
set matchingFileVersion to item 1 of every text item of matchingVersionChunk
else
set AppleScript's text item delimiters to "."
set matchingFileVersion to item 1 of every text item of matchingVersionChunk
end if


--deal with letter suffix
--Look if any of the characters in the version part are letters
set matchingFileVersionCharacters to every character in matchingFileVersion
--log matchingFileVersionCharacters
repeat with eachCharacter in matchingFileVersionCharacters
try
eachCharacter as number
on error
set matchingFileVersionLetter to eachCharacter as string
end try
end repeat
--separate the letter from the numbers if needed
if matchingFileVersionLetter is "" then
set matchingFileVersionNumber to matchingFileVersion as number
else
set AppleScript's text item delimiters to matchingFileVersionLetter
set matchingFileVersionNumber to item 1 of every text item of matchingFileVersion as number
set AppleScript's text item delimiters to ""
--convert letter to a numerical value for comparison
set theList to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}

repeat with a from 1 to 26

if item a of theList is matchingFileVersionLetter then
set matchingFileVersionLetterValue to a
end if
end repeat

end if --this ends the condition that there is a letter used in the file version


--create a new list ranking a new winner

if matchingFileVersionNumber is greater than theHighestNumber then
set theHighestNumber to matchingFileVersionNumber
set end of finalList to (item listPosition of matchingFiles)
set finalMatchingFileVersionLetter to ""
set highestMatchingFileVersionLetterValue to 0

else if matchingFileVersionNumber is theHighestNumber then
if matchingFileVersionLetterValue is greater than highestMatchingFileVersionLetterValue then
set finalMatchingFileVersionLetter to matchingFileVersionLetter
set highestMatchingFileVersionLetterValue to matchingFileVersionLetterValue
set end of finalList to (item listPosition of matchingFiles)
end if
end if

end repeat


--update the cue to the new file target
set latestVersion to last item of finalList
if (latestVersion is not OGFileVersion) then
set file target of eachCue to POSIX file (fileFolderPath & latestVersion)
set filesUpdated to filesUpdated + 1
set theDescription to the notes of eachCue
set the notes of eachCue to theDescription & "
Updated to version " & latestVersion & " by QLab " & whichScript & " script on " & (current date)
end if

end try --trying the target cue

else -----else if eachCue contains "_v" in the default name (file name). Now try to update by date string.---------

try
set currentFileTarget to POSIX path of (file target of eachCue as alias)


set AppleScript's text item delimiters to "/"
set OGFileVersion to last item of every text item of currentFileTarget

set numberCount to 0
set extractedDate to ""
set dateSegment to ""
set notConsecutiveNumber to 0
repeat with eachCharacter in OGFileVersion
if (numberCount is less than 12) and (notConsecutiveNumber is less than 3) then
try
eachCharacter as number
set dateSegment to dateSegment & eachCharacter as string
set extractedDate to extractedDate & eachCharacter as string
set numberCount to numberCount + 1
set notConsecutiveNumber to 0
on error
set dateSegment to dateSegment & eachCharacter as string
set notConsecutiveNumber to notConsecutiveNumber + 1
end try

end if
end repeat


---------------Check to see if this number is a date value
if numberCount is 12 then
set testPassed to true
set testMonth to (item 5 of extractedDate) & (item 6 of extractedDate)
if testMonth is greater than 12 then set testFailed to false
set testDay to (item 7 of extractedDate) & (item 8 of extractedDate)
if testDay is greater than 31 then set testFailed to false
set testHour to (item 9 of extractedDate) & (item 10 of extractedDate)
if testHour is greater than 23 then set testFailed to false
set testMinute to (item 11 of extractedDate) & (item 12 of extractedDate)
if testMinute is greater than 59 then set testFailed to false


if testPassed then


set AppleScript's text item delimiters to dateSegment
set secondFilePart to last item of every text item of OGFileVersion
set AppleScript's text item delimiters to "."
set fileBaseName to item 1 of every text item of secondFilePart
set AppleScript's text item delimiters to ""



--locate folder
set filePath to (file target of eachCue as alias)
tell application "Finder" to set fileFolderPath to POSIX path of ((container of filePath) as text)

--Get a list of all the files in the same folder with matching base file name
tell application "Finder" to set fileNames to (list folder (fileFolderPath) without invisibles)
set matchingFiles to {}

repeat with eachFile in fileNames
if eachFile contains fileBaseName then
set the end of matchingFiles to eachFile as text
end if
end repeat


--find what the highest version number is
set theHighestNumber to 0
set finalList to {}
set listPosition to 0
repeat with eachMatchingFile in matchingFiles
set listPosition to listPosition + 1
set matchingNumberCount to 0
set matchingExtractedDate to ""
set matchingDateSegment to ""
repeat with eachCharacter in eachMatchingFile
if matchingNumberCount is less than 12 then
try
eachCharacter as number
set matchingDateSegment to matchingDateSegment & eachCharacter as string
set matchingExtractedDate to matchingExtractedDate & eachCharacter as string
set matchingNumberCount to matchingNumberCount + 1
on error
set matchingDateSegment to matchingDateSegment & eachCharacter as string
end try

end if
end repeat

--create a new list ranking a new winner

if matchingExtractedDate is greater than theHighestNumber then
set theHighestNumber to matchingExtractedDate
set end of finalList to (item listPosition of matchingFiles)

end if
end repeat


--update the cue to the new file target
set latestVersion to last item of finalList
if (latestVersion is not OGFileVersion) then
set file target of eachCue to POSIX file (fileFolderPath & latestVersion)
set filesUpdated to filesUpdated + 1
set theDescription to the notes of eachCue
set the notes of eachCue to theDescription & "
Updated to version " & latestVersion & " by QLab " & whichScript & " script on " & (current date)
end if


end if -- this ends the condition of testPass - verifying that the 12 numbers could equal a date
end if --end the condition that numberCount is 12
end try --trying the target cue for a date update


end if -- this ends the condition of eachCue containing a "_v" in the default name (file name)                
end if --    this ends the condition of eachCue not having any note saying not to update
end if --this ends the condition of eachCue being either an audio or video cue
end repeat
display notification ("" & filesUpdated & " files updated") with title "File Update"
end tell