top of page
Writer's pictureTaylor Glad

Update Targets / Watch Folder

Updated: Jun 15, 2023

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 below, 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.




(*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
							
							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

237 views0 comments

Recent Posts

See All

Comments


bottom of page