AppleScript to Find the Albums Containing an Image
***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 AppleScript to find the user collections (Albums, Projects,Groups, Smart albums) containing an Image. This is most useful for large catalogs with many user collections.
This AppleScript can report results by Dialog, by Notifications, through Text Edit and on the ClipBoard. This Applescript has its own GUI to configure its options and settings.
This Applescript can be compiled as an Application and added to the Capture One Scripts menu.
In implementing the GUI, the length of this Applescript has become larger than PhaseOnes limit for a forum posting. Therefore I have broken it into two parts. The part in this posting is the first part, which is all the code specific to this AppleScript. The second part is a common part which is used by all my AppleScripts, and is in this posting:
Both parts should be copied and pasted into one OSX Script Editor document in sequence.
The First Part
## Applescript to search a COP 11 Catalog for Collections containing selected variants
## Version 1.29 !! NO GUARANTEE OF SUPPORT !! Best effort
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
##
-- ***To Setup
-- Start Script Editor, open a new (blank) file, copy and paste both parts into one Script Editor Document, compile (hammer symbol) and save.
-- Best if you make "Scripts" folder somewhere in your Documents or Desktop
-- This file is suitable to use as an application in Capture One Pro's Script Menu
-- *** Operation in Script Editor
-- 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
-- Run the script
-- Results can appear in Notifications, the Script Editor Log and the Text Edit document when the search for each variant is completed, and in the Clipboard and Display Dialog Window when all searching is completed
--
-- The user may elect to set defaults for enabling or disabling results in Notifications, TextEdit and Script Editor by setting the "enable" variables at beginning of the script
-- The user may change the default amount of reporting by setting the "debugLogLevel" and "ResultsFileMaxDebug" variables at beginning of the script
-- There is a GUI which allows the user to modify settings
-- If you are having some issues, then set debugLogLevel to 3 and send me the results from Script Editors log window, or Text Edit.
## Values in this section are safe to change, within limits indicated. Support is likely but no commitment
use AppleScript version "2.5"
use scripting additions
set debugLogLevel to 0 -- 1...6 Set to 1 to allow changing other settings. Increasing Values result in increasing amounts of debug data that takes longer to report
set enableResultsFile to true -- Enables Results in Textedit file (true/false)
set enableResultsByDialog to false -- (true/false)
set enableResultsByClipboard to true -- (true/false)
set enableNotifications to false -- (true/false)
set ResultsFileMaxDebug to 3 -- 1...6
set maxProgressLevel to 3 -- Levels shown in Script Editor's progress bar 1...6
set maxSearchlevel to 100 -- Reduce if you only want to search top level collections or if you start getting stack overflow messages Range 1....... Verified to 100
property searchTimePerVariant : 0 -- The search time in seconds. The value from the previous run is used
set WarnMaxVariants to 6 -- 1...n (number of variants) If you make this large you will get no warning when the script may lock up CO for a long time
set WarnSearchTime to 30 -- 1...n (seconds) If you make this large you will get no warning when the script may lock up CO for a long time
set SearchDiskFileSystem to false -- untested probably safe (true/false)
set SearchRecentCaptures to false -- (true/false)
set SearchTrash to false -- untested probably safe (true/false)
set ExcludedSubCollectionNames to {} -- The collections in this list will not be searched
set StopSearchAtProject to false -- (true/false)
set enableFastGUI to true -- (true/false)
## ***** 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 may explain the design intent.
set SearchRecentImports to false -- doesn't work in CO 11 (true/false)
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_Parent to (parent_name = "Script Editor")
set SE_Logging to SE_Parent as boolean
set COPisParent to (parent_name = "Capture One 11")
set Result_DocName to "COP_Image_Search.txt"
set Result_ProjectName to "ScriptSearchResults"
set ResultMethod to my InitializeLoqqing3(Result_DocName, Script_Title)
loq_Results2(0, false, ("Started from: " & parent_name & " Action: Find collections where variants are located"))
set minCOPversion to "11.2"
validateCOP(minCOPversion)
validateCOPdoc3({"catalog", "session"})
validateCOPcollections3()
tell application "Capture One 11" to set countSelectedVariants to get count of selected variants
loq_Results2(3, false, ("In this window " & countSelectedVariants & " Selected Variants"))
if countSelectedVariants = 0 then
display alert "No images selected - select one or more images"
my loqqed_Error_Halt3(true, "No images selected")
end if
CO_settingHandler()
set ExcludedTopCollectionNames to {"In Catalog", "Catalog", "All Images"}
if SearchDiskFileSystem then
set ExcludedTopCollectionKinds to {""}
else
set ExcludedTopCollectionKinds to {"catalog folder"}
end if
if not SearchRecentImports then set ExcludedTopCollectionNames to ExcludedTopCollectionNames & "Recent Imports"
if not SearchRecentCaptures then set ExcludedTopCollectionNames to ExcludedTopCollectionNames & "Recent Captures"
if not SearchTrash then set ExcludedTopCollectionNames to ExcludedTopCollectionNames & "Trash"
if not SearchDiskFileSystem then
set max_search_coll_index to topUserCollectionIndex
else
if selectedCollectionMirroredAtTopLast then
set max_search_coll_index to countTopCollections - 1
else
set max_search_coll_index to countTopCollections
end if
end if
set Mark1 to GetTick_Now()
set estimatedDuration to countSelectedVariants * searchTimePerVariant
tell application "System Events" to set frontmost of process parent_name to true
if (estimatedDuration > WarnSearchTime) then
try
display dialog "Are you sure you want to search for " & countSelectedVariants & " variants? Estimated time: " & estimatedDuration & " seconds" with icon caution
set Mark1 to GetTick_Now()
on error errmess
my loqqed_Error_Halt3(true, "User Cancelled the Script")
end try
else if (searchTimePerVariant = 0) and (countSelectedVariants > WarnMaxVariants) then
try
display dialog "Are you sure you want to search for " & countSelectedVariants & " variants? " with icon caution
set Mark1 to GetTick_Now()
on error errmess
my loqqed_Error_Halt3(true, "User Cancelled the Script")
end try
end if
if SE_Logging then set progress description to "Setting up"
tell application "Capture One 11"
set selectedVariantsNameList to get name of variants whose selected is true
set selectedVariantsIDList to get id of variants whose selected is true
set selectedVariantsList to (get selected variants)
end tell
loq_Results2(4, false, (selectedVariantsNameList))
set countFoundVariants to 0
set countProcessedVariants to 0
set Mark2 to GetTick_Now()
set search_executed to false
if SE_Logging then
set progress total steps to countSelectedVariants
set progress completed steps to 0
set progress description to "Searching for Variants ..."
end if
repeat with v_Counter from 1 to countSelectedVariants
set thisVariant to item v_Counter of selectedVariantsList
set searchedVariantName to item v_Counter of selectedVariantsNameList
set searchedVariantID to item v_Counter of selectedVariantsIDList
if SE_Logging then
set progress completed steps to v_Counter
set progress description to "Searching for Variant " & searchedVariantName
end if
loq_Results2(2, false, (return & "Searching for " & searchedVariantName))
set isFound to false
set foundPaths to ""
set pathSeparator to ""
set searchLevel to 0
set nextSearchLevel to searchLevel + 1
if nextSearchLevel ≤ maxSearchlevel then
repeat with c_Counter from 1 to max_search_coll_index
set thisTopCollection to item c_Counter of everyTopCollection
set topCollName to item c_Counter of namesTopCollections
set topCollKind_s to convertKind(item c_Counter of kindsTopCollections_p)
if (ExcludedTopCollectionNames does not contain topCollName) and ¬
(ExcludedTopCollectionKinds does not contain topCollKind_s) then
set search_executed to true
loq_Results2(3, false, ("Search: " & topCollKind_s & " " & topCollName))
set resultPaths to my search_collection(thisTopCollection, nextSearchLevel, topCollName, topCollKind_s) -- The search
set resultCount to count of resultPaths
loq_Results2(3, false, ("Result of search in " & topCollName & " (" & topCollKind_s & ") is: " & resultPaths))
if resultCount > 0 then
set isFound to true
repeat with p_counter from 1 to count of resultPaths
set foundPaths to foundPaths & pathSeparator & item p_counter of resultPaths
set pathSeparator to return -- after the first path is added the separator become the newline character /r
end repeat
end if
else
loq_Results2(3, false, ("Reject: " & topCollKind_s & " " & topCollName))
end if
end repeat
end if
if not search_executed then -- there are no top level collections to search - don't keep searching
if enableNotifications then display notification "No Top Level Collections to Search"
my loqqed_Error_Halt3(true, "No Top Level Collections to Search")
end if
if isFound then
loq_Results2(0, false, (return & searchedVariantName & " was found in:" & return & foundPaths))
set countFoundVariants to countFoundVariants + 1
else
loq_Results2((return & searchedVariantName & " was not found"), false, 0)
if enableNotifications then display notification searchedVariantName & " was not found"
end if
set countProcessedVariants to countProcessedVariants + 1
end repeat
set Mark3 to GetTick_Now()
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
set elapsedTime1s to roundDecimals(Mark2 - Mark1, 3)
set elapsedTime2s to roundDecimals(Mark3 - Mark2, 3)
if countSelectedVariants > 0 then
set searchTimePerVariant to get ((Mark3 - Mark2) / countSelectedVariants) -- update the property to provide a time estimate for the next run
set searchTimePerVariantDisplay to roundDecimals(searchTimePerVariant, 3)
else
set searchTimePerVariantDisplay to "--"
end if
loq_Results2(1, false, (return & "SetupTime: " & elapsedTime1s & "sec Process time: " & elapsedTime2s & "sec per Variant: " & searchTimePerVariantDisplay & "sec"))
loq_Results2(0, true, (return & "*** Done on " & date_string & " *** " & countProcessedVariants & " of " & countFoundVariants & " variants found" & return & return))
finalCleanup() -- cleanup large arrays to avoid the situation where the script cannot be saved
## Arrange the windows to show results on top
tell application "System Events" to set frontmost of process "Capture One 11" to true
if enableResultsFile then
tell application "System Events" to set frontmost of process "TextEdit" to true
else
tell application "System Events" to set frontmost of process parent_name to true
end if
## Script Specific Handlers ########
on search_collection(thisCollection, searchLevel, thisCollName, thisCollKind)
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
-- recursive handler to search a collection and it's subcollections
-- if successful, returns a list of paths each as a text string
global debugLogLevel, SE_Logging, maxSearchlevel, searchedVariantID, searchedVariantName, COPDocName, StopSearchAtProject, ExcludedSubCollectionNames, maxProgressLevel, enableNotifications
global selectedCollectionRef, selectedCollectionIndex, kindSelectedCollection_s, nameSelectedCollection, selectedCollectionAtTopEnd, selectedCollectionIsUser
set found_paths to {} -- initialise the list
if ExcludedSubCollectionNames contains thisCollName then return found_paths
if SE_Logging and (searchLevel ≤ maxProgressLevel) then set progress additional description to thisCollKind & " " & thisCollName
tell application "Capture One 11" to tell document COPDocName to tell thisCollection to ¬
set searchVariantIDhits to get count of (get every variant whose id is searchedVariantID)
if searchVariantIDhits > 0 then
set found_paths to found_paths & (thisCollName & "(" & thisCollKind & ")")
if enableNotifications or (debugLogLevel ≥ 2) then display notification searchedVariantName & " found in: " & thisCollKind & " '" & thisCollName & "'"
loq_Results2(4, false, ("Found " & searchVariantIDhits & " hits in " & thisCollKind & " " & thisCollName))
end if
set countSubcollsthisColl to 0
set namesSubcollsthisColl to {}
set kindsSubcollsthisColl_p to {}
if {"album", "smart album"} does not contain thisCollKind then -- albums and smart albums don't contain collections
tell application "Capture One 11" to tell document COPDocName to tell thisCollection
set listSubcollsthisColl to every collection
tell me to set countSubcollsthisColl to count of listSubcollsthisColl
if countSubcollsthisColl > 0 then set {namesSubcollsthisColl, kindsSubcollsthisColl_p} to {name, kind} of every collection
end tell
end if
if debugLogLevel ≥ 5 then
tell application "Capture One 11" to tell document COPDocName to tell thisCollection
set countImages to count of every image
set countVariants to count of every variant
end tell
loq_Results2(debugLogLevel, false, ("In " & thisCollKind & " " & thisCollName & " at level " & searchLevel & " found " & countImages & " images ," & countVariants & " variants ," & countSubcollsthisColl & " collections"))
end if
set nextSearchLevel to searchLevel + 1
if (nextSearchLevel ≤ maxSearchlevel) and ¬
(not (StopSearchAtProject and thisCollKind = "project")) then
loq_Results2(5, false, ("Searching Collections in " & thisCollKind & " " & thisCollName & " at level " & searchLevel & " found " & countSubcollsthisColl & " collections"))
repeat with c_Counter from 1 to countSubcollsthisColl
set searchColl to item c_Counter of listSubcollsthisColl
set searchCollName to item c_Counter of namesSubcollsthisColl
set searchCollKind_s to convertKind(get item c_Counter of kindsSubcollsthisColl_p)
if selectedCollectionIsUser then
if (searchCollName = nameSelectedCollection) and (searchCollKind_s = kindSelectedCollection_s) then
## Check the collection number to trap the error caused by the selected subcollection returning an invalid reference
try
|| of {searchColl} -- generate an error to capture error text containing the collection reference
on error CO11_errtxt number CO11_errnbr
end try
loq_Results2(4, false, ("***Error Message " & CO11_errtxt & "; number " & CO11_errnbr & " Collection: " & c_Counter & " of " & thisCollKind & " " & thisCollName))
## extract the collection number from the error text
if CO11_errnbr = -1728 then
set CollNum to (get last word of item 2 of splitstringtolist(CO11_errtxt, "of")) as integer
else
loq_Results2(0, false, ("*****" & CO11_errtxt & "; number " & CO11_errnbr))
loqqed_Error_Halt3(true, "Unexpected error when checking collection integrity")
end if
if CollNum ≠c_Counter then
## this is the selected user subcollection, it must be accessed as the last top level collection in the document
if selectedCollectionIndex ≠CollNum then
## the collection reference is wrong in some other unexpected way
loq_Results2(4, false, ("*****" & CO11_errtxt & "; number " & CO11_errnbr))
loqqed_Error_Halt3(false, "Unexpected collection index when checking collection integrity: " & CollNum)
error "Unexpected collection index when checking collection integrity: " & CollNum
end if
## Set the collection reference to the last top level collection
set searchColl to selectedCollectionRef
loq_Results2(3, false, ("Top Level Collection number:" & CollNum & " replaces Sub collection " & c_Counter & " of " & thisCollKind & " " & thisCollName))
end if
loq_Results2(4, false, ("Verified sub-Collection " & c_Counter & " of " & thisCollKind & " " & thisCollName))
end if
end if
loq_Results2(4, false, ("Starting search in " & searchCollName & " (" & searchCollKind_s & ") "))
set resultPaths to my search_collection(searchColl, nextSearchLevel, searchCollName, searchCollKind_s) -- the search
set countResultPaths to count of resultPaths
loq_Results2(3, false, ("Result of search in " & searchCollName & " (" & searchCollKind_s & ") is: " & resultPaths))
if countResultPaths > 0 then
repeat with p_counter from 1 to countResultPaths
set found_paths to found_paths & (thisCollName & ">>" & item p_counter of resultPaths)
end repeat
end if
end repeat
end if
return found_paths
end search_collection
on finalCleanup()
## clean up the large arrays to avoid a large stack that may prevent AppleScript from saving the script
global selectedVariantsList, selectedVariantsNameList, selectedVariantsIDList, enableNotifications
set selectedVariantsList to {}
set selectedVariantsNameList to {}
set selectedVariantsIDList to {}
end finalCleanup
on CO_settingHandler()
## Copyright 2018 Eric Valk, Ottawa, Canada Creative Commons License CC BY-SA No Warranty.
## Initialisation Handler for scripts using Capture One Pro
## Collects and sets up information about the Script settings for the GUI handler
global parent_name, Script_Title, enableFastGUI, debugLogLevel, ResultsFileMaxDebug, maxProgressLevel, countSelectedVariants
global theAppName, copVersion, COPDocName, COPDocKind_s, COPDocRef
global namesTopCollections, bottomUserCollectionIndex, topUserCollectionIndex, selectedCollectionRef, nameSelectedCollection, selectedCollectionIsUser, kindSelectedCollection_s
global SearchDiskFileSystem, SearchRecentImports, SearchRecentCaptures, SearchTrash, ExcludedSubCollectionNames, StopSearchAtProject, maxSearchlevel
global SE_Logging, SE_Parent, enableResultsFile, enableResultsByDialog, enableResultsByClipboard, enableNotifications, ResultMethod, Result_DocName
set basic_setting_list to {}
set end of basic_setting_list to {SettingName:(get copVersion & " in " & COPDocKind_s & " "" & COPDocName & """)}
set end of basic_setting_list to {SettingName:(get kindSelectedCollection_s & " "" & nameSelectedCollection & "" with " & countSelectedVariants & " selected variants")}
set end of basic_setting_list to {SettingName:"Debug Level", SettingValue:debugLogLevel}
set end of basic_setting_list to {SettingName:"Results by " & ResultMethod}
if settingGUI_Bypass(basic_setting_list) then
loq_Results2(0, false, joinListToString(basic_setting_list, return))
return
end if
set helpdebugLogLevel to "the amount of debug info reported"
set helpmaxProgressLevel to "lowest subcollection level reported in the progess bar"
set helpmaxSearchlevel to "lowest subcollection level which is searched"
set helpSearchDiskFileSystem to "search the OSX filesystem"
set helpSearchTrash to "search CaptureOne Trash"
set helpStopSearchAtProject to "do not search Albums within a Project"
set helpExcludedCollection to "collections with these names will not be searched"
set helpFastGUI to "enable faster GUI response, with less help text"
set nameUserCollections to {nameSelectedCollection} & (get items bottomUserCollectionIndex thru topUserCollectionIndex of namesTopCollections)
if selectedCollectionIsUser then tell application "Capture One 11" to tell selectedCollectionRef to ¬
set nameUserCollections to nameUserCollections & (get name of every collection)
set initialLogging to {(get enableNotifications as boolean), (get enableResultsByDialog as boolean), (get enableResultsFile as boolean), (get enableResultsByClipboard as boolean), (get SE_Logging as boolean)}
set setting_list to {}
set end of setting_list to {SettingID:1, SettingName:"Parent", SettingValue:parent_name, UserSet:false}
set end of setting_list to {SettingID:2, SettingName:"Document", SettingValue:(COPDocKind_s & " " & COPDocName), UserSet:false}
set end of setting_list to {SettingID:3, SettingName:"Collection", SettingValue:(kindSelectedCollection_s & " " & nameSelectedCollection & " with " & countSelectedVariants & " selected variants"), UserSet:false}
set end of setting_list to {SettingID:4, SettingName:"Search Managed Files", SettingHelp:"", SettingValue:false, UserSet:false}
set end of setting_list to {SettingID:5, SettingName:"Search Referenced Files", SettingHelp:SearchDiskFileSystem, SettingValue:(a reference to SearchDiskFileSystem), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:7, SettingName:"Search Recent Captures", SettingValue:SearchRecentCaptures, UserSet:false}
set end of setting_list to {SettingID:8, SettingName:"Search All Images", SettingValue:false, UserSet:false}
set end of setting_list to {SettingID:9, SettingName:"Search COP Trash", SettingHelp:helpSearchTrash, SettingValue:(a reference to SearchTrash), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:11, SettingName:"Collections not searched", SettingHelp:"", SettingValue:(a reference to ExcludedSubCollectionNames), UserSet:true, SettingClass:"List_Text", SettingLimited:"List&Free", SettingLimit_L:nameUserCollections}
set end of setting_list to {SettingID:12, SettingName:"Do Not Search below Projects", SettingHelp:helpStopSearchAtProject, SettingValue:(a reference to StopSearchAtProject), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:13, SettingName:"Debug Level", SettingHelp:helpdebugLogLevel, SettingValue:(a reference to debugLogLevel), UserSet:true, SettingClass:"Integer", SettingLimited:"Min_Max", SettingLimit_L:{0, 6}}
set end of setting_list to {SettingID:14, SettingName:"Highest Debug Level in Result File", SettingHelp:"", SettingValue:(a reference to ResultsFileMaxDebug), UserSet:true, SettingClass:"Integer", SettingLimited:"Min_Max", SettingLimit_L:{1, 6}}
set end of setting_list to {SettingID:15, SettingName:"Maximum Search Level", SettingHelp:helpmaxSearchlevel, SettingValue:(a reference to maxSearchlevel), UserSet:true, SettingClass:"Integer", SettingLimited:"Min", SettingLimit_L:{2}}
set end of setting_list to {SettingID:16, SettingName:"Enable Results in Text Edit", SettingHelp:"", SettingValue:(a reference to enableResultsFile), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:17, SettingName:"Enable Results in Dialog", SettingHelp:"", SettingValue:(a reference to enableResultsByDialog), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:18, SettingName:"Enable Results in Clipboard", SettingHelp:"", SettingValue:(a reference to enableResultsByClipboard), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:19, SettingName:"Enable Results in Notifications", SettingHelp:"", SettingValue:(a reference to enableNotifications), UserSet:true, SettingClass:"Boolean"}
set end of setting_list to {SettingID:20, SettingName:"Results Logged by Script Editor", SettingValue:(a reference to SE_Logging), UserSet:SE_Parent, SettingClass:"Boolean"}
if SE_Logging then set end of setting_list to {SettingID:21, SettingName:"Maximum Level in Progress Bar", SettingHelp:helpmaxProgressLevel, SettingValue:(a reference to maxProgressLevel), UserSet:true, SettingClass:"Integer", SettingLimited:"Min_Max", SettingLimit_L:{1, 10}}
set end of setting_list to {SettingID:23, SettingName:"Enable Fast GUI Response", SettingHelp:helpFastGUI, SettingValue:(a reference to enableFastGUI), UserSet:true, SettingClass:"Boolean"}
set settings_display_string to settingGUI(setting_list)
if ((not (get enableNotifications as boolean)) and (not (get enableResultsByDialog as boolean)) and (not (get enableResultsFile as boolean)) and (not (get SE_Logging as boolean))) then
display alert "You have turned off all results notification!! " message "Turning results by Dialog Display on" as critical giving up after 30
set enableResultsByDialog to true
end if
if (initialLogging ≠{(get enableNotifications as boolean), (get enableResultsByDialog as boolean), (get enableResultsFile as boolean), (get enableResultsByClipboard as boolean), (get SE_Logging as boolean)}) then
set ResultMethod to my InitializeLoqqing3(Result_DocName, Script_Title)
end if
set settings_display_string to settings_display_string & "Result Logging Methods: " & ResultMethod & return
loq_Results2(1, false, (return & "Settings:" & return & settings_display_string))
end CO_settingHandler
## Insert the second Part Here ######
Post is closed for comments.
Comments
0 comments