AppleScript to Automatically identify Sequences
***Edit*** 2020/07/05 The migrated version of this script likely will not complile because the Applescript symbols for "not equal", "less than" and "greater than" are not supported in the new forum
Here is my first working version of a script that automatically identifies and marks Sequences of images - both bursts and brackets are identified. The identification of sequences depends on the images being ordered by date in Capture One.
The mapping of Sequence information to metadata is:
-- Sequence ID: <--> "contact city" {Base name of first Image in the sequence - i.e. not including the extension}
-- Sequence Type: <--> "contact state" {Bracket, Burst}
-- Sequence Count: <--> "contact postal code" {0,1,2,3....}
-- Sequence SubType: <--> "contact country"
-------For Brackets:{White Balence, ISO, Exposure, Flash, Focus,Art}
-------For Bursts:{Fast Burst, Normal Burst, 5fps Burst}
-- Sequence Total: <--> "contact phone" - Valid for Brackets for Panasonic cameras
Once the sequence information is in Metadata, you can isolate the sequences by selecting them (under "Contact City") in the Filters tool. You likely have to configure the filters Tool to show "Contact City"
The script is optimised and works for both Panasonic and Olympus cameras and should be relatively straightforward to modify for other makes. I have it set up so that one can select which camera makes and models it acts on. There are also a couple of lines somewhere (commented out) that will allow it to act only on images with certain copyright names.
It will work properly with paired RAW and JPEG images, on sessions and on catalogs, and is running quite OK on my catalog with 16000 images - although it takes about 1/3 to 1/2 second per image, so this will be an overnight run.
In addition, some information is copied from EXIF to keywords, of interest to me is the LensID which is not available in COP for Panasonic JPEGS, and the Digital Zoom setting. Other EXIF data can be treated the same way if desired. Or this can be removed.
This is about 3 days of work so there is probably considerable improvement possible.
The script depends on exiftool
## Notes
-- Applescript to Copy Lens ID, Digital Teleconverter settings to keywords, and copy Sequencing info to Metadata fields
-- Identifies Sequences
-- Optimised for Panasonic and Olympus Cameras
-- Depends on exiftool https://www.sno.phy.queensu.ca/~phil/exiftool/ to retreive EXIF tags
----- Version 10.94 was used for testing
-- Creates a report in Text Edit
-- Version 1.6 !! NO SUPPORT !! Eric Valk, Ottawa, Canada
-- *** Operation
-- Open the compiled and saved file
-- Open the Script Editor log window, and select the messages tab
-- Select only a small number of variants, from any collection
-- install exiftool https://www.sno.phy.queensu.ca/~phil/exiftool/
-- Run the script
-- Results appear in the Script Editor Log and Text Edit when the search for each variant is completed
-- This script DOES write or delete metadata information in the COP Catalog or Session
-- The user may elect to enable or disable results in Notifications, TextEdit and Script Editor by setting the "enable" variables at beginning of the script
-- The user may change the amount of reporting by setting the "debugLogLevel" and "ResultsFileMaxDebug" variables at beginning of the script
-- If you are having some issues, then set debugLogLevel to 3 and send me the results from Script Editors log window, or Text Edit.
-- Sequence ID: <--> "contact city" {Name of first Image in the Sequence, not including extension}
-- Sequence Type: <--> "contact state" {Bracket, Burst}
-- Sequence Count: <--> "contact postal code" {0,1,2,3....}
-- Sequence SubType: <--> "contact country" Bracket:{White Balence, ISO, Exposure, Flash, Focus,Art} Burst:{Fast Burst, Normal Burst, 5fps Burst}
-- Sequence Total: <--> "contact phone" - Valid for Brackets
## Values in this section are safe to change, within limits indicated. Support is likely but no commitment
set debugLogLevel to 1 -- 0...6 Values >1 result in increasing amounts of debug data that takes longer to report
set enableResultsFile to true -- (true/false)
set enableResultsByDialog to false -- (true/false)
set enableNotifications to false -- (true/false)
set ResultsFileMaxDebug to 2 -- 1...6 suggest not more than 2
set SearchforMakerList to {"Panasonic", "Olympus"}
set SearchforFileTypeList to {"JPEG", "RW2", "ORF"}
set SearchforPanasonicModelList to {"DMC-G1", "DMC-G5", "DMC-GX1", "DMC-GX7", "DMC-GX8", "DMC-GM1", "DMC-GM5"}
set SearchforOlympusModelList to {"E-M1"}
set updateExistingKeywords to true -- If set to false, existing keywords are not updated
set updateExistingSequenceID to true -- If set to false, existing SequenceIDs are not updated. Reccomended choice, unless you have just changed SequenceTimeThreshold
set SequenceTimeThreshold to 4 -- seconds
## ***** Not safe to change stuff below this line, unless you have some background in SW development.
## I generally won't help much if you change stuff below this line. I will usually explain the design intent and suggest improvments, if I'm not busy
tell application "System Events" to set parent_name to name of current application
tell application "Finder"
set script_path to path to me
set Script_Title to name of file script_path as text
end tell
set SE_Logging to (parent_name = "Script Editor")
if enableResultsFile then
set Result_DocName to "COP_EXIF2Keyword.txt"
else
set Result_DocName to "Not Enabled"
end if
set ResultMethod to my InitializeLoqqing(Result_DocName, Script_Title)
loq_Results2(0, false, ("Started from: " & parent_name))
loq_Results2(0, false, ("Action: Copy EXIF Data to keywords"))
set minCOPversion to "11.1"
validateCOP(minCOPversion)
validateCOPdoc3({"catalog", "session"})
validateCOPcollections3()
set options_display_string to "Debug Level: " & debugLogLevel
set options_display_string to options_display_string & return & "Search for Maker: {" & joinListToString(SearchforMakerList, ", ") & "}"
set options_display_string to options_display_string & return & "Search for File Type: {" & joinListToString(SearchforFileTypeList, ", ") & "}"
set options_display_string to options_display_string & return & "Update Existing Keyword Sets: " & updateExistingKeywords
set options_display_string to options_display_string & return & "Update Existing Sequence ID: " & updateExistingSequenceID
set options_display_string to options_display_string & return & "Time Threshold for new Sequence: " & SequenceTimeThreshold & " seconds"
set options_display_string to options_display_string & return & "Highest Debug Level in Result File: " & ResultsFileMaxDebug
set options_display_string to options_display_string & return & "Enable Results in Text Edit: " & enableResultsFile
set options_display_string to options_display_string & return & "Display Dialog on Image Not Found: " & enableResultsByDialog
set options_display_string to options_display_string & return & "Enable Results in Notifications: " & enableNotifications
set options_display_string to options_display_string & return & "Results: " & ResultMethod
tell application "System Events" to set frontmost of process parent_name to true
try
set dialog_result to display dialog options_display_string with title Script_Title
on error errorMessage number errorNumber
if errorNumber ≠-128 then
my loqqed_Error_Halt(errorMessage & " #" & errorNumber & " after Options Display")
else
my loqqed_Error_Halt("User Cancelled the Script after Options Display")
end if
end try
loq_Results2(1, false, (return & "Options:" & return & options_display_string & return))
set Mark1 to GetTick_Now()
tell application "Capture One 11" to set countVariants to count of selected variants
set no_date_info_D to (date "Thursday, January 1, 1970 at 12:00:00 AM")
set Sequence_ID to "Not Found"
set hasSequence_ID to false
set lastSequenceDate to no_date_info_D
set SequenceHasStarted to false
set SequenceTimeThreshold to 3 -- seconds
set lastSequenceCount to 0 as integer
tell application "System Events" to set frontmost of process "Capture One 11" to true
if (countVariants > 0) then
tell application "Capture One 11"
set selectedVariantsList to selected variants
set selectedVariantsCreDateList to EXIF capture date of parent image of every variant whose selected is true
set selectedVariantsNameList to name of every variant whose selected is true
end tell
set thisCollDescr to "Selected Variants (" & countVariants & ") of " & kindSelectedCollection_s & " " & nameSelectedCollection & " of " & COPDocKind_s & " " & COPDocName
CheckVariantSequence(selectedVariantsCreDateList, thisCollDescr)
set Mark2 to GetTick_Now()
set progress description to thisCollDescr
set progress total steps to countVariants
set progress completed steps to 0
repeat with variantCounter from 1 to countVariants
processVariant((item variantCounter of selectedVariantsList), (item variantCounter of selectedVariantsNameList), (item variantCounter of selectedVariantsCreDateList))
set progress completed steps to variantCounter
end repeat
set Mark3 to GetTick_Now()
else
tell application "Capture One 11"
set countVariants to count of every variant
set selectedVariantsCreDateList to EXIF capture date of parent image of every variant
set selectedVariantsNameList to name of every variant
end tell
set thisCollDescr to "Every Variant (" & countVariants & ") of " & kindSelectedCollection_s & " " & nameSelectedCollection & " of " & COPDocKind_s & " " & COPDocName
if countVariants = 0 then
my loq_Results2(0, false, ("No images in " & thisCollDescr))
else
CheckVariantSequence(selectedVariantsCreDateList, thisCollDescr)
set Mark2 to GetTick_Now()
set progress description to thisCollDescr
set progress total steps to countVariants
set progress completed steps to 0
repeat with variantCounter from 1 to countVariants
tell application "Capture One 11" to tell COPDocRef to tell selectedCollectionRef to set thisVariant to variant variantCounter
processVariant(thisVariant, (item variantCounter of selectedVariantsNameList), (item variantCounter of selectedVariantsCreDateList))
set progress completed steps to variantCounter
end repeat
set Mark3 to GetTick_Now()
end if
end if
tell application "System Events" to set frontmost of process "Capture One 11" to true
tell current application to set date_string to (current date) as text
if debugLogLevel ≥ 1 then
set elapsedTime1s to roundToScale(Mark2 - Mark1, 4)
set elapsedTime2ms to MSduration(Mark2, Mark3)
set timePerVariantms to roundToScale(((Mark3 - Mark2) * 1000 / countVariants), 3)
my loq_Results2(1, false, (return & "SetupTime: " & elapsedTime1s & "sec Process time: " & elapsedTime2ms & "msec Per Variant: " & timePerVariantms & "msec Variants: " & countVariants))
else
my loq_Results2(1, false, (return))
end if
set selectedVariantsList to {""}
my loq_Results2(0, true, ("*** Done at " & date_string & " ***"))
finalCleanup()
###########################################################################################################################
-- Script Specific Handlers -------------------
on CheckVariantSequence(theVariantCreDateList, thisCollDescr)
global debugLogLevel, Script_Title, COPDocName, COPDocKind_s, no_date_info_D, VariantsInSequence
set resultMessage to "Images are ordered in date sequence"
set InSequence to true
set creDatePrev to no_date_info_D
repeat with Credate in theVariantCreDateList
if (class of Credate) = date then
if (Credate - creDatePrev) < 0 then
set InSequence to false
set resultMessage to "Images are NOT ordered in date sequence"
exit repeat
end if
set creDatePrev to Credate
end if
end repeat
loq_Results2(1, false, resultMessage)
copy InSequence to VariantsInSequence
if not InSequence then
try
set dialog_result to display dialog resultMessage & ", continue?" & return & "Sequence IDs will not be assigned" & return & "(" & thisCollDescr & ")" with title Script_Title
on error errorMessage number errorNumber
if errorNumber ≠-128 then
my loqqed_Error_Halt(errorMessage & " #" & errorNumber & " after Image Sequence Checking")
else
my loqqed_Error_Halt("User Cancelled the Script after Image Sequence Checking")
end if
end try
end if
end CheckVariantSequence
on processVariant(theVariant, theVariantName, TheVariantCreDate)
global debugLogLevel, SearchforMakerList, SearchforFileTypeList, SearchforPanasonicModelList, SearchforOlympusModelList, updateExistingKeywords, COPDocRef
global Sequence_ID, hasSequence_ID, lastSequenceDate, SequenceHasStarted, VariantsInSequence, no_date_info_D, SequenceTimeThreshold, updateExistingSequenceID, lastSequenceCount
tell application "Capture One 11" to tell theVariant to set the imagepath to the path of the parent image
tell my application "Finder"
if not (exists imagepath as POSIX file) then
my loq_Results2(0, false, ("Unable to locate the image file " & imagepath))
return
end if
end tell
--tell application "Capture One 11" to tell theVariant to set the theCopyrightNotice to status copyright notice
--if ((theCopyrightNotice does not contain "Eric") or (theCopyrightNotice does not contain "Valk")) then return
tell current application to set exifQuery to do shell script "/usr/local/bin/exiftool -D -S2 -FileType -Make -Model -DigitalZoomRatio -LensType -BurstMode -SequenceNumber -BracketSettings -BurstSpeed -LensModel -DriveMode -SpecialMode " & quoted form of imagepath
set hasFileType to false
set foundFileType to "NotFound"
set hasMake to false
set foundFileMaker to "NotFound"
set hasModel to false
set foundFileModel to "NotFound"
set hasDigZoom to false
set foundDigZoom to "NotFound"
set LensName to "NotFound"
set hasLensName to false
set foundBurstMode to "NotFound"
set hasBurstMode to false
set foundBurstSpeed to "NotFound"
set hasBurstSpeed to false
set foundSequenceNumber to "NotFound"
set hasSequenceNumber to false
set foundBracketSettings to "NotFound"
set hasBracketSettings to false
set foundDriveMode to "NotFound"
set hasDriveMode to false
set foundSpecialMode to "NotFound"
set hasSpecialMode to false
repeat with paraCtr from 1 to (get count of paragraphs of exifQuery)
set paraValue to removeLeadingTrailingSpaces(item 2 of splitStringToList((get paragraph paraCtr of exifQuery), ":"))
set paratype to word 1 of (get paragraph paraCtr of exifQuery)
if ("-" = (get text 1 of paragraph paraCtr of exifQuery)) then
if paratype = "FileType" then
set foundFileType to paraValue
set hasFileType to true
if (SearchforFileTypeList does not contain foundFileType) then return
end if
else
set paraNum to paratype as integer
if paraNum = 271 then
set foundFileMaker to (get word 1 of paraValue)
set hasMake to true
if (SearchforMakerList does not contain foundFileMaker) then return
else if paraNum = 272 then
set foundFileModel to paraValue
set hasModel to true
else if paraNum = 41988 then
set foundDigZoom to paraValue
set hasDigZoom to true
else if paraNum = 81 then
set LensName to paraValue
set hasLensName to true
else if paraNum = 42 then
set foundBurstMode to paraValue
set hasBurstMode to true
else if paraNum = 43 then
set foundSequenceNumber to paraValue
set hasSequenceNumber to true
else if paraNum = 69 then
set foundBracketSettings to paraValue
set hasBracketSettings to true
else if paraNum = 119 then
set foundBurstSpeed to paraValue
set hasBurstSpeed to true
else if paraNum = 42036 then
set LensName to paraValue
set hasLensName to true
else if paraNum = 1536 then
set foundDriveMode to paraValue
set hasDriveMode to true
else if paraNum = 512 then
set foundSpecialMode to paraValue
set hasSpecialMode to true
end if
end if
end repeat
-- Sequence Type: {Bracket, Burst}
-- Sequence Count: {0,1,2,3....}
-- Sequence SubType: Bracket:{White Balence, ISO, Exposure, Flash, Focus,Art} Burst:{Fast Burst, Normal Burst, 5fps Burst}
-- Sequence Total: Valid for Brackets
set Sequence_Type to "Not Found"
set hasSequence_Type to false
set Sequence_Count to 0 as integer
set hasSequence_Count to false
set Sequence_SubType to "Not Found"
set hasSequence_SubType to false
set Sequence_Total to 0 as integer
set hasSequence_Total to false
set SequenceParsingError to false
if "Panasonic" = foundFileMaker then
if SearchforPanasonicModelList does not contain foundFileModel then
--set SequenceHasStarted to false
return
end if
if not hasBurstMode then
loq_Results2(0, false, ("Parsing Error - Panasonic Image file has no Burst Mode: " & imagepath))
set SequenceParsingError to true
else if ("Off" = foundBurstMode) then
set SequenceHasStarted to false
else if ("On" = foundBurstMode) then
set Sequence_Type to "Burst"
set hasSequence_Type to true
if hasSequenceNumber then
set Sequence_Count to foundSequenceNumber as integer
set hasSequence_Count to true
else
loq_Results2(0, false, ("Parsing Error - Panasonic Image file burst mode has no Sequence Number: " & imagepath))
set SequenceParsingError to true
end if
if hasBurstSpeed then
set Sequence_SubType to foundBurstSpeed & "fps Burst"
set hasSequence_SubType to true
else
--loq_Results2(0, false, ("Parsing Error - Panasonic Image file burst Mode and no Burst Speed: " & imagepath))
--set SequenceParsingError to true
--This happens for the DMC-G1
end if
else if foundBurstMode contains "Bracketing" then
set Sequence_Type to "Bracket"
set hasSequence_Type to true
set Sequence_SubType to text 1 thru ((offset of "Bracketing" in foundBurstMode) + (count of "Bracketing") - 1) of foundBurstMode
set hasSequence_SubType to true
if hasSequenceNumber then
if foundSequenceNumber = "0" then
set Sequence_Count to 0 as integer
set Sequence_Total to 0 as integer
set hasSequence_Total to true
else
set Sequence_Count to foundSequenceNumber as integer
if hasBracketSettings and ("0123456789" contains text 1 of foundBracketSettings) then
set Sequence_Total to (word 1 of foundBracketSettings) as integer
set hasSequence_Total to true
end if
end if
set hasSequence_Count to true
else
loq_Results2(0, false, ("Parsing Error - Panasonic Image file bracket mode has no Sequence Number: " & imagepath))
set SequenceParsingError to true
end if
else
loq_Results2(0, false, ("Parsing Error - Panasonic Image file Burst Mode has unexpected value::" & foundBurstMode & "::" & imagepath))
set SequenceParsingError to true
end if
else if "Olympus" = foundFileMaker then
if SearchforOlympusModelList does not contain foundFileModel then
--set SequenceHasStarted to false
return
end if
if hasDriveMode then
set foundDriveModeParts to splitStringToList(foundDriveMode, ",")
set foundDriveModePart1 to removeLeadingTrailingSpaces(item 1 of foundDriveModeParts)
if (2 ≤ (count of foundDriveModeParts)) then
set foundDriveModePart2 to removeLeadingTrailingSpaces(item 2 of foundDriveModeParts)
else
set foundDriveModePart2 to ""
end if
if (foundDriveModePart1 contains "Single Shot") then
set SequenceHasStarted to false --Sequence has ended
else
if (2 ≤ (count of foundDriveModeParts)) and "Shot" = (word 1 of (item 2 of foundDriveModeParts)) then
set foundDriveModePart2 to removeLeadingTrailingSpaces(item 2 of foundDriveModeParts)
set Sequence_Count to (word 2 of (item 2 of foundDriveModeParts)) as integer
set hasSequence_Count to true
else
loq_Results2(0, false, ("Parsing Error - Olympus Image file burst mode has no Shot Number: " & imagepath))
set SequenceParsingError to true
end if
if foundDriveModePart1 contains "Continuous Shooting" then
set Sequence_Type to "Burst"
set hasSequence_Type to true
if hasSpecialMode then
set Sequence_SubType to (word 1 of foundSpecialMode) & " Burst"
set hasSequence_SubType to true
end if
else if foundDriveModePart1 contains "Bracketing" then
set Sequence_Type to "Bracket"
set hasSequence_Type to true
set Sequence_SubType to foundDriveModePart1
set hasSequence_SubType to true
else
loq_Results2(0, false, ("Parsing Error - Olympus Image file burst mode has unexpected value::" & foundDriveMode & "::" & imagepath))
set SequenceParsingError to true
end if
end if
end if
else
return -- not a Panasonic nor an Olympus camera
end if
## if we arrive here, this a a valid model of a Panasonic or an Olympus camera
## First, record the data we already have
## Don't clear Metadata if there has been a Sequence parsing error.
tell application "Capture One 11" to tell COPDocRef to tell theVariant
if hasSequence_Type then
set contact state to Sequence_Type
else
if not SequenceParsingError then set contact state to ""
end if
if hasSequence_Count then
set contact postal code to (Sequence_Count as text)
else
if not SequenceParsingError then set contact postal code to ""
end if
if hasSequence_SubType then
set contact country to Sequence_SubType
else
if not SequenceParsingError then set contact country to ""
end if
if hasSequence_Total then
set contact phone to (Sequence_Total as text)
else
if not SequenceParsingError then set contact phone to ""
end if
end tell
--log {return, return, theVariantName, VariantBaseName, "SequenceParsingError", SequenceParsingError,"VariantsInSequence", VariantsInSequence,"updateExistingSequenceID", updateExistingSequenceID}
--log {"Sequence_Type", Sequence_Type, "hasSequence_SubType", hasSequence_SubType, "Sequence_Count", Sequence_Count, "Sequence_Total", Sequence_Total}
if VariantsInSequence then
set VariantBaseName to text 1 thru ((offset of "." in theVariantName) - 1) of theVariantName
--log {"VariantBaseName", VariantBaseName,"Sequence_ID", Sequence_ID, hasSequence_ID, "lastSequenceDate", lastSequenceDate, "SequenceHasStarted", SequenceHasStarted}
if SequenceParsingError then
## This variant has a parsing error, end any sequence
--log {"1.0", "parsing error"}
set Sequence_ID to "NotFound"
set hasSequence_ID to false
set lastSequenceDate to no_date_info_D
set SequenceHasStarted to false
set lastSequenceCount to 0 as integer
else
if ((not hasSequence_Type) or (not SequenceHasStarted)) and hasSequence_ID then
## Was in a sequence but this image is not. End the sequence.
--log {"2.0", "Was in a sequence but this image is not. End the sequence"}
set Sequence_ID to "NotFound"
set hasSequence_ID to false
set lastSequenceDate to no_date_info_D
set lastSequenceCount to 0 as integer
else if not SequenceHasStarted and hasSequence_Type then
## A new sequence is starting
--log {"3.0", "A new sequence is starting"}
set SequenceHasStarted to true
set Sequence_ID to VariantBaseName
set hasSequence_ID to true
set lastSequenceDate to TheVariantCreDate
if hasSequence_Count then set lastSequenceCount to Sequence_Count
else if SequenceHasStarted and hasSequence_Type then
## Sequence is ongoing but is it the same sequence?
--log {"4.0", "Sequence is ongoing but is it the same sequence?"}
-- check if the sequence counter has reset
if hasSequence_Count and Sequence_Count > 0 then
## with a valid sequence counter, the resetting the sequence depends on the sequence counter
set resetFlag to lastSequenceCount > Sequence_Count
else
## without a valid sequence counter, the resetting the sequence depends on the time interval
set resetFlag to ((TheVariantCreDate - lastSequenceDate) > SequenceTimeThreshold)
end if
if resetFlag then
## this is a new sequence starting immediately after the last
--log {"4.1", "New sequence", (TheVariantCreDate - lastSequenceDate)}
set SequenceHasStarted to true
set Sequence_ID to VariantBaseName
set hasSequence_ID to true
set lastSequenceDate to TheVariantCreDate
set lastSequenceCount to Sequence_Count
else
## the existing sequence continues
--log {"4.2", "Existing sequence", (TheVariantCreDate - lastSequenceDate)}
set lastSequenceDate to TheVariantCreDate
set lastSequenceCount to Sequence_Count
end if
end if
--log {"Updating","Sequence_ID", Sequence_ID, hasSequence_ID, "lastSequenceDate", lastSequenceDate, "SequenceHasStarted", SequenceHasStarted}
## Update the sequence ID metadata
if not updateExistingSequenceID then -- Avoid an unnecessary AppleEvent if updateExistingSequenceID is TRUE
tell application "Capture One 11" to tell theVariant to set CountExistingSequenceID to count of contact city
set updateSequenceID to CountExistingSequenceID = 0
else
set updateSequenceID to true
end if
if updateSequenceID then
tell application "Capture One 11" to tell COPDocRef to tell theVariant
if hasSequence_ID then
set contact city to Sequence_ID
else
set contact city to ""
end if
end tell
end if
end if
end if
tell application "Capture One 11" to tell theVariant to set {keywordNameList, keywordParentList} to {name, parent} of keywords
set keywordcount to count of keywordNameList
if debugLogLevel ≥ 2 then
tell application "Capture One 11" to set variantID to id of theVariant
my loq_Results2(2, false, (return & "Path: " & imagepath & " ID: " & variantID & " Keywords: " & keywordcount))
end if
if (0 < keywordcount) and (debugLogLevel > 2) then
set keywdSummaryList to {}
repeat with keywordcounter from 1 to keywordcount
set keywdSummaryList to keywdSummaryList & "Keyword_" & keywordcounter & ": " & (get item keywordcounter of keywordNameList) & " Parent: " & (get item keywordcounter of keywordParentList)
end repeat
my loq_Results2(3, false, keywdSummaryList)
end if
if (updateExistingKeywords = false) and (keywordParentList contains "LensID") then
-- do nothing
else if hasLensName then
## Add or Update the keyword set
if keywordParentList contains "LensID" then
set keywordcountOffset to 0
tell application "Capture One 11" to tell COPDocRef to tell theVariant
repeat with keywordcounter from 1 to keywordcount
set keywordIndex to keywordcounter + keywordcountOffset
if (item keywordcounter of keywordParentList) = "LensID" then
if (get parent of keyword keywordIndex) = "LensID" then
if debugLogLevel ≥ 4 then my loq_Results2(4, false, ("Deleting: " & (get name of keyword keywordIndex)))
delete keyword keywordIndex
set keywordcountOffset to keywordcountOffset - 1
else
error "keyword list LensID parent mismatch: Keyword:" & (get name of keyword keywordIndex)
end if
end if
end repeat
end tell
else if keywordNameList does not contain "LensID" then
tell application "Capture One 11" to tell COPDocRef to tell theVariant
tell theVariant to make new keyword with properties {name:"LensID"}
my loq_Results2(5, false, ("Adding: " & "LensID"))
end tell
end if
tell application "Capture One 11" to tell COPDocRef to tell theVariant
tell theVariant to make new keyword with properties {name:LensName, parent:"LensID"}
my loq_Results2(4, false, ("Adding: " & LensName))
end tell
tell application "Capture One 11" to tell theVariant to set {keywordNameList, keywordParentList} to {name, parent} of keywords
set keywordcount to count of keywordNameList
end if
if ((updateExistingKeywords = false) and (keywordParentList contains "DigZoom")) then
-- do nothing - no update required
else if (foundFileType = "JPEG") and hasDigZoom then
set digZoomName to "NotFound"
if foundDigZoom = "0" then
set digZoomName to "DZM_Off"
else if foundDigZoom = "1" then
set digZoomName to "DTC_Off"
else if foundDigZoom = "2" then
set digZoomName to "DTC_2X"
else if foundDigZoom = "4" then
set digZoomName to "DTC_4X"
else
try
set digZoomName to (foundDigZoom as real)
set digZoomName to "DZM_" & digZoomName & "X"
end try
end if
if digZoomName = "NotFound" then
my loq_Results2(0, false, ("Digital Zoom info could not be parsed: " & imagepath))
else
if keywordParentList contains "DigZoom" then
set keywordcountOffset to 0
tell application "Capture One 11" to tell COPDocRef to tell theVariant
repeat with keywordcounter from 1 to keywordcount
set keywordIndex to keywordcounter + keywordcountOffset
if (item keywordcounter of keywordParentList) = "DigZoom" then
if (get parent of keyword keywordIndex) = "DigZoom" then
if debugLogLevel ≥ 4 then my loq_Results2(4, false, ("Deleting: " & (get name of keyword keywordIndex)))
delete keyword keywordIndex
set keywordcountOffset to keywordcountOffset - 1
else
error "keyword list DigZoom parent mismatch: Keyword: " & (get name of keyword keywordIndex)
end if
end if
end repeat
end tell
else if keywordNameList does not contain "DigZoom" then
tell application "Capture One 11" to tell COPDocRef to tell theVariant
tell theVariant to make new keyword with properties {name:"DigZoom"}
my loq_Results2(5, false, ("Adding: " & "DigZoom"))
end tell
end if
tell application "Capture One 11" to tell COPDocRef to tell theVariant
tell theVariant to make new keyword with properties {name:digZoomName, parent:"DigZoom"}
my loq_Results2(4, false, ("Adding: " & digZoomName))
end tell
end if
end if
end processVariant
###########################################################################################################################
-- Capture One General Handlers -------------------
on validateCOP(minCOPversionstr)
global debugLogLevel
tell application "System Events"
set COPProcList to every process whose name contains "Capture One" and background only is false
if debugLogLevel ≥ 2 then
set COPProcNameList to name of every process whose name contains "Capture One" and background only is false
my loq_Results2(2, false, ("COP Processes:" & COPProcNameList))
end if
end tell
if (count of COPProcList) = 0 then my loqqed_Error_Halt("COP is not running")
if (count of COPProcList) ≠1 then my loqqed_Error_Halt("Unexpected: >1 COP instances")
set theAppRef to item 1 of COPProcList
tell application "System Events" to set theAppName to ((get name of theAppRef) as text)
tell application "System Events" to set copDetailedVersion to get version of my application theAppName
tell application "Capture One 11" to set copVersion to (get app version)
if debugLogLevel ≥ 2 then
--properties of application "Capture One 11"
tell application "System Events"
my loq_Results2(2, false, ("All Processes: " & (get my joinListToString((get name of every process whose background only is false), ", "))))
end tell
loq_Results2(2, false, ("theAppName: " & theAppName))
loq_Results2(2, false, ("COP Version: " & copVersion))
loq_Results2(2, false, ("COP Detailed Version: " & copDetailedVersion))
end if
if the theAppName ≠"Capture One 11" then
display notification "Wrong COP Application"
my loqqed_Error_Halt("Found COP Application " & theAppName & " The only supported COP application is Capture One 11")
end if
set numCOPversion to (splitStringToList((word -1 of copVersion), "."))
set minCOPversion to (splitStringToList(minCOPversionstr, "."))
set digit_mult to 1000000
set Version_digit to 0
repeat with dig_ctr from 1 to count of numCOPversion
set digit_mult to digit_mult / 100
set Version_digit to Version_digit + (get item dig_ctr of numCOPversion as integer) * digit_mult
end repeat
set digit_mult to 1000000
set min_digit to 0
repeat with dig_ctr from 1 to count of minCOPversion
set digit_mult to digit_mult / 100
set min_digit to min_digit + (get item dig_ctr of minCOPversion as integer) * digit_mult
end repeat
if Version_digit < min_digit then
display notification "COP Version is too low"
my loqqed_Error_Halt("This COP Version is " & (word -1 of copVersion) & " - the minimum supported COP version is " & minCOPversionstr)
end if
tell application "System Events" to set frontmost of process theAppName to true
loq_Results2(0, false, ("Using Capture One " & copDetailedVersion))
end validateCOP
on validateCOPdoc3(COP_kind_list)
global debugLogLevel, COPDocName, COPDocKind_s, COPDocRef
tell application "Capture One 11"
set {COPDocName, current_doc_kind_p} to (get {name, kind} of current document)
set current_doc_ref_list to (get every document whose name is COPDocName and kind is current_doc_kind_p)
set number_of_hits to count of current_doc_ref_list
end tell
set COPDocKind_s to convertkind(current_doc_kind_p)
if COPDocKind_s = "session" then set COPDocName to text 1 thru ((offset of "." in COPDocName) - 1) of COPDocName
loq_Results2(2, false, ("Is: " & COPDocKind_s & " was: " & (get current_doc_kind_p as text)))
loq_Results2(2, false, ("Found Documents: " & number_of_hits))
if COP_kind_list does not contain COPDocKind_s then loq_Results2(0, false, (COPDocName & " is a " & COPDocKind_s & " -- unsupported type of document"))
if number_of_hits = 0 then
loqqed_Error_Halt("Could not find find " & COPDocKind_s & COPDocName)
else if number_of_hits > 1 then
loqqed_Error_Halt("Found more than one " & COPDocKind_s & " with the name " & COPDocName)
else
tell application "Capture One 11" to set COPDocRef to item 1 of current_doc_ref_list
end if
loq_Results2(0, false, ("Capture One document: " & COPDocKind_s & " " & COPDocName))
end validateCOPdoc3
on validateCOPcollections3()
global debugLogLevel, COPDocName, COPDocKind_s, COPDocRef, everyTopCollection, namesTopCollections, kindsTopCollections_p, countTopCollections, selectedCollectionRef, selectedCollectionIndex, kindSelectedCollection_s, nameSelectedCollection, selectedCollectionMirroredAtTopLast, selectedCollectionIsUser, bottomUserCollectionIndex, topUserCollectionIndex
-- selectedCollectionMirroredAtTopLast replaces selectedCollectionAtTopEnd
-- bottomUserCollectionIndex, topUserCollectionIndex replaces indexInCatalog
tell application "Capture One 11" to tell COPDocRef
try
set selectedCollectionRef to get current collection
set {nameSelectedCollection, kindSelectedCollection_p} to {name, kind} of selectedCollectionRef
on error
my loqqed_Error_Halt("There is no collection selected in " & COPDocKind_s & COPDocName)
end try
set everyTopCollection to get every collection
set {namesTopCollections, kindsTopCollections_p} to {name, kind} of every collection
end tell
set kindSelectedCollection_s to convertkind(kindSelectedCollection_p)
set countTopCollections to count of namesTopCollections
repeat with collectionCounter from 1 to countTopCollections
if (nameSelectedCollection = item collectionCounter of namesTopCollections) and (kindSelectedCollection_s = convertkind(item collectionCounter of kindsTopCollections_p)) then
set selectedCollectionIndex to collectionCounter
exit repeat
end if
end repeat
if COPDocKind_s = "catalog" then
repeat with collectionCounter from countTopCollections to 1 by -1
if ("in Catalog" = item collectionCounter of namesTopCollections) and ("smart album" = convertkind(item collectionCounter of kindsTopCollections_p)) then
set topUserCollectionIndex to collectionCounter - 1
exit repeat
end if
end repeat
repeat with collectionCounter from 1 to countTopCollections
if ("Trash" = item collectionCounter of namesTopCollections) and ("smart album" = convertkind(item collectionCounter of kindsTopCollections_p)) then
set bottomUserCollectionIndex to collectionCounter + 1
exit repeat
end if
end repeat
set selectedCollectionMirroredAtTopLast to (selectedCollectionIndex = countTopCollections) and ({"catalog folder", "favorite"} does not contain convertkind(last item of kindsTopCollections_p))
set selectedCollectionIsUser to ({"project", "album", "group", "smart album"} contains kindSelectedCollection_s)
else if COPDocKind_s = "session" then
repeat with collectionCounter from countTopCollections to 1 by -1
if ("favorite" ≠convertkind(item collectionCounter of kindsTopCollections_p)) then
set topUserCollectionIndex to collectionCounter
exit repeat
end if
end repeat
repeat with collectionCounter from 1 to countTopCollections
if ("Trash" = item collectionCounter of namesTopCollections) and ("favorite" = convertkind(item collectionCounter of kindsTopCollections_p)) then
set bottomUserCollectionIndex to collectionCounter + 1
exit repeat
end if
end repeat
set selectedCollectionMirroredAtTopLast to false
set selectedCollectionIsUser to ({"project", "album", "group", "smart album"} contains kindSelectedCollection_s)
end if
end validateCOPcollections3
on convertkind(kind_p)
global debugLogLevel
set kind_s to kind_p as text
if (get text 1 of kind_s) ≠"«" then
return kind_s
else
set code_start to (get length of kind_s) - 4
set kind_code to get (text code_start thru (code_start + 3) of kind_s)
if kind_code = "CCpj" then
set kind_res to "project"
else if kind_code = "CCgp" then
set kind_res to "group"
else if kind_code = "CCal" then
set kind_res to "album"
else if kind_code = "CCsm" then
set kind_res to "smart album"
else if kind_code = "CCfv" then
set kind_res to "favorite"
else if kind_code = "CCff" then
set kind_res to "catalog folder"
else if kind_code = "COct" then
set kind_res to "catalog"
else if kind_code = "COsd" then
set kind_res to "session"
else
loqqed_Error_Halt("Unexpected Kind string: " & kind_s)
end if
end if
return kind_res
end convertkind
###########################################################################################################################
-- General Handlers -------------------
on InitializeLoqqing(DocName_Ext, sourceTitle)
global debugLogLevel, Script_Title, Result_Doc_ref, SE_Logging, enableResultsFile, enableResultsByDialog, DialogTextList
tell current application to set date_string to (current date) as text
set LogMethods to {}
if enableResultsFile then
set target_folder_name to "ScriptReports"
set target_folder_p to ((POSIX path of (get path to desktop as text)) & target_folder_name)
set target_folder_a to (POSIX file target_folder_p) as string
set Result_Doc_Path_p to target_folder_p & "/" & DocName_Ext
set Result_Doc_Path_a to (POSIX file Result_Doc_Path_p) as string
tell application "System Events" to if not (exists (alias (target_folder_a))) then ¬
tell application "Finder" to make new folder at desktop with properties {name:target_folder_name}
tell application "System Events" to if not (exists (alias (Result_Doc_Path_a))) then
set First_line to ("Created " & date_string & return)
do shell script "echo " & First_line & " > " & """ & Result_Doc_Path_p & """
if (debugLogLevel ≥ 1) and SE_Logging then log Result_Doc_Path_p & First_line
end if
tell application "TextEdit" to activate
tell application "TextEdit" to set Result_Doc_ref to open Result_Doc_Path_a as alias
set LogMethods to LogMethods & DocName_Ext
end if
if enableResultsByDialog then
set DialogTextList to {}
set LogMethods to LogMethods & "Display Dialog"
end if
loq_Results2(0, false, (sourceTitle & " results on " & date_string))
return joinListToString(LogMethods, ", ")
end InitializeLoqqing
on loq_Results2(thisLogDebugLevel, MakeFront, logText)
global Result_Doc_ref, debugLogLevel, SE_Logging, parent_name, ResultsFileMaxDebug, enableResultsFile, enableResultsByDialog, DialogTextList
if thisLogDebugLevel > debugLogLevel then return
set logText_class to ((get class of logText) as text)
if logText_class ≠"text" then
try
if logText_class = "list" then
set new_logText to joinListToString(logText, ", ")
else
set new_logText to logText as text
end if
set logText to new_logText
set logText_class to "text"
on error errmess
set logText to errmess
set logText_class to "text"
end try
end if
if ((thisLogDebugLevel ≤ ResultsFileMaxDebug) or not SE_Logging) then
if enableResultsFile then
tell application "TextEdit"
set numPara to count paragraphs of the text of Result_Doc_ref
set paragraph (numPara + 1) of the text of Result_Doc_ref to ((logText as text) & return)
end tell
tell application "System Events" to if MakeFront then set frontmost of process "TextEdit" to true
end if
if enableResultsByDialog then
set DialogTextList to DialogTextList & logText
if MakeFront then
tell application "System Events" to set frontmost of process parent_name to true
display dialog joinListToString(DialogTextList, return)
end if
end if
end if
if SE_Logging then log (logText as text)
end loq_Results2
on loqqed_Error_Halt(error_text)
global debugLogLevel, Script_Title
tell current application to set date_string to (current date) as text
loq_Results2(0, true, ("Script "" & Script_Title & "" has exited at " & date_string & return & "Reason: " & error_text & return & return & "Halted"))
finalCleanup()
display notification error_text
error error_text
end loqqed_Error_Halt
on finalCleanup()
global selectedVariantsList, selectedVariantsCreDateList, selectedVariantsNameList
set selectedVariantsList to {""}
set selectedVariantsCreDateList to {""}
set selectedVariantsNameList to {""}
end finalCleanup
on splitStringToList(theString, theDelim)
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theList to text items of theString
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theList
end splitStringToList
to joinListToString(theList, theDelim)
set theString to ""
set astid to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to theDelim
set theString to theList as string
on error
set AppleScript's text item delimiters to astid
end try
set AppleScript's text item delimiters to astid
return theString
end joinListToString
on removeLeadingTrailingSpaces(theString)
repeat while theString begins with space
if 1 ≥ (count of theString) then return ""
set theString to text 2 thru -1 of theString
end repeat
repeat while theString ends with space
set theString to text 1 thru -2 of theString
end repeat
return theString
end removeLeadingTrailingSpaces
on getIndexOf(theItem, theList) -- credits Emmanuel Levy
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return
set theList to return & theList & return
set AppleScript's text item delimiters to astid
try
-1 + (count (paragraphs of (text 1 thru (offset of (return & theItem & return) in theList) of theList)))
on error
0
end try
end getIndexOf
on makeList(listLength, theElement)
-- Note that the theElement can even be a List
if listLength = 0 then return {}
if listLength = 1 then return {theElement}
set theList to {theElement}
repeat while (count of theList) < listLength / 2
set theList to theList & theList
end repeat
return (theList & items 1 thru (listLength - (count of theList)) of theList)
end makeList
on roundToQuantum(thisValue, quantum)
return (round (thisValue / quantum) rounding to nearest) * quantum
end roundToQuantum
on roundToScale(thisValue, Digits)
set qScale to 1
repeat with quantumctr from 1 to Digits - 1
set qScale to qScale / 10
end repeat
if thisValue = 0 then
return thisValue
else if thisValue > 0 then
set scaledValue to thisValue * qScale
else
set scaledValue to -thisValue * qScale
end if
set quantum to 1
if scaledValue < 1 then
repeat with quantumctr from 1 to 50
set quantum to quantum / 10
if quantum < scaledValue then exit repeat
end repeat
else if scaledValue ≥ 10 then
set scaledValue to scaledValue / 10
repeat with quantumctr from 1 to 50
set quantum to quantum * 10
if quantum > scaledValue then exit repeat
end repeat
end if
return (round (thisValue / quantum) rounding to nearest) * quantum
end roundToScale
on calculateLog(TheInput)
set InputType to (class of TheInput) as text
if InputType = "list" then
if (count of TheInput) = 0 then
error "Input is the empty list!!"
else
set TheNumber to (item 1 of TheInput) as real
if (count of TheInput) > 1 then
set logBasis to item 2 of TheInput
else
set logBasis to "10"
end if
end if
else
set TheNumber to TheInput as real
set logBasis to "10"
end if
if TheNumber = (0 as real) then error "Attempted log of 0!!"
set TheLog to (do shell script ("echo 'l(" & (TheNumber as string) & ")' | bc -l")) as real
if (logBasis = "e") then
-- Do nothing
else if (logBasis = "10") or (logBasis = (10 as integer)) then
set TheLog to TheLog / 2.302585092994
else if (logBasis = "2") or (logBasis = (2 as integer)) then
set TheLog to TheLog / 0.69314718056
else
set logBasis to logBasis as real
if (logBasis = (0 as real)) then
error "attempt to use a log basis of 0!!"
else
set TheLogConversion to (do shell script ("echo 'l(" & (logBasis as string) & ")' | bc -l")) as real
set TheLog to TheLog / TheLogConversion
end if
end if
return TheLog
end calculateLog
on MSduration(firstTicks, lastTicks)
--returns duration in ms
--inputs are durations, in seconds, from GetTick's Now()
return (round (10000 * (lastTicks - firstTicks)) rounding to nearest) / 10
end MSduration
on GetTick_Now()
--returns duration in seconds since machine start, calculated using ticks
script GetTick
use framework "Foundation" --> for more precise timing calculations
on Now()
return (current application's NSDate's timeIntervalSinceReferenceDate) as real
end Now
end script
return GetTick's Now()
end GetTick_Now
-
WOW EPIC ERIC
It wont compile for me on the date lineset no_date_info_D to (date "Thursday, January 1, 1970 at 12:00:00 AM")
But for now I'm enjoying just reading your level of de-bugging code 😄0 -
[quote="rapdigital" wrote:
WOW EPIC ERIC
It wont compile for me on the date lineset no_date_info_D to (date "Thursday, January 1, 1970 at 12:00:00 AM")
But for now I'm enjoying just reading your level of de-bugging code 😄
Thanks!! It's a localisation issue that I experienced before when working with seanmurp. That line is trying to set a date for January 1,1970.
Replacing that line with this one worked:
set no_date_string to "01/01/70"
set no_date_info_D to (date no_date_string)
If you want to customize it for some other camera, take a few burst mode and bracket shots, and evalaute the image files like this, and you will see what the EXIF indications are for the various working modes. Once you have the tag number of the key EXIF tags, you can use those numbers in the script.
exiftool -D -G /Volumes/SSD_ss1/evSSD/Photos/2011\ QoV\ Nov/P1020116.RW2
or
exiftool -D -G /Volumes/SSD_ss1/evSSD/Photos/2011\ QoV\ Nov/P1020116.RW2 | grep -i bracket0
Post is closed for comments.
Comments
2 comments