Copy link to clipboard
Copied
I'm in the midst of developing a plugin for Lightroom Classic, and was wondering if anyone had any tips on how to wait for a withWriteAccessDo() block to complete before proceeding with the code beyond it.
Essentially, I am writing to the catalog [via photo:applyDevelopSettings() method] and later need to access these updated settings from the stored photo in the catalog [via photo:getDevelopSettings() method].
Referencing the API documentation for withWriteAccessDo() in the Lightroom Classic SDK, it would seem that it is no longer designed to be update immediately:
As of version 3.0, changes you make to the database within this call do not have immediate effect, but are written to the database upon successful completion of the callback function. This means, in general, that if you create a new item (for instance, by calling catalog:createCollection()), you cannot retrieve information about that item until the with___AccessDo has finished. There are some special cases where you can reference the newly-created item; for instance, after creating a collection set, you can create a collection within that set. These cases are noted in the API documentation.
Does anyone have a suggestion as to how to wait until this block has completed execution? I wonder if it's possible to set up a polling function on a variable...though I've not yet been able to implement such a solution successfully.
The one way I've gotten it to work thus far is by adding a manual delay [via LrTasks.sleep(1.0) method] immediately after the withWriteAccessDo() block. This delays the timing of things and the later code runs correctly - however I worry that the required delay would vary based on a user's hardware, and am sure there is a better way to do this.
Any advice would be appreciated.
Copy link to clipboard
Copied
When the call to catalog:withWriteAccessDo() returns with result "executed", any changes made by the passed function should be visible via all calls to the SDK.
If you're not observing that, post a small script demonstrating the anomalous behavior.
Copy link to clipboard
Copied
Thanks for replying John. This was very useful in debugging my specific problem - I was able to monitor the return value of withWriteAccessDo and build out my logic following the form of this pseudocode:
local executionStatus = catalog:withWriteAccessDo(progressActionTitle, function(context)
-- some logic here...
currentPhoto:applyDevelopSettings({ SomeSetting = "SomeValue" })
end
if executionStatus == 'executed' then
-- followup logic here...
elseif executionStatus == 'queued' then
-- queued logic here...
elseif executionStatus == 'aborted' then
-- aborted logic here...
end
Just elaborating on this for anyone else who stumbles upon this thread!
Copy link to clipboard
Copied
Hey John, just following up on this as I hit an odd roadblock.
An exception I'm running into following with the logic we've outlined is that when using applyDevelopSettings to specify the 'WhiteBalance' value to 'As Shot', it seems to trigger an asyncronous background routine that further loads the initial white balance values for 'Temperature' and 'Tint' after the function returns 'executed'.
This is causing me some grief, as I want to operate on the initial values for 'Temperature' and 'Tint'. With a polling routine, I'm able to check for nil on these develop values for a photo and continue onwards in logic when they're updated - which works fine for about 20 selected photos (with very small delays under .01 seconds in most cases). However, operating beyond the 20 selected photo mark I get an indefinite timeout where the values are never updated (or, at least not for the 3 hours my code run).
Here's some simplified code for what I'm describing - trying to apply a relative offset to the current temperature.
-- Pass 1: Detect uninitialized white balances and trigger load
local executionStatus = catalog:withWriteAccessDo(writeActionTitle, function(context)
for index, currentPhoto in pairs(selectedPhotos) do
local currentDevelopSettings = currentPhoto:getDevelopSettings()
local currentTemp = currentDevelopSettings["Temperature"]
if currentTemp == nil then
currentPhoto:applyDevelopSettings({ WhiteBalance = "As Shot" })
end -- end if
end -- end for
end ) -- end withWriteAccessDo - all selected photos should be initialized here
-- Debugging check
if executionStatus == 'executed' then
logger:debug( "CHECK: Executed successfully!" )
else
logger:debug( "CHECK: Execute failed!" )
end
-- Pass 2:
local executionStatus = catalog:withWriteAccessDo(writeActionTitle, function(context)
for index, currentPhoto in pairs(selectedPhotos) do
local currentDevelopSettings = currentPhoto:getDevelopSettings()
local currentTemp = currentDevelopSettings["Temperature"]
while currentTemp == nil do -- polling routine (works great for first 20 selected photos)
LrTasks.sleep(0.01)
currentDevelopSettings = currentPhoto:getDevelopSettings()
currentTemp = currentDevelopSettings["Temperature"]
end -- end while
local newTemp = currentTemp + 10
currentPhoto:applyDevelopSettings({ Temperature = newTemp })
end -- end for
end ) -- end withWriteAccessDo
Might you have any insight as to why it's behaving this way? Or, how I might otherwise go about initializing Lightroom's 'Temperature' and 'Tint' values if they are not yet so?
Copy link to clipboard
Copied
Hi.
Delay is not needed at all - when withWriteAccessDo() returns, data have already been written to the catalog.
SDK may be not very clear, but what is really meant there:
- callback is the function you wrap with withWriteAccessDo()
- if this function makes number of changes, you should not expect that they are written until function returns (in general, there are some exceptions to this listed in SDK)
So in short, with your example:
withWriteAccessDo("Apply develop settings", function(context)
photo:applyDevelopPreset()
photo:getDevelopSettings()
end)
is NOT ok, because it is not guaranteed that develop settings will be written immediately. They are guaranteed to be written when function returns.
So it should be like this:
withWriteAccessDo("Apply develop settings", function(context)
photo:applyDevelopPreset()
end)
photo:getDevelopSettings()
Exceptions that I mentioned is that for example you can create collection and then put photos in that collection inside of the same withWriteAccessDo(), but those are explicitly stated in SDK.
Hope this makes things a bit clearer.
Copy link to clipboard
Copied
Thanks for the clarification FSt0p - it definitely helped me interpret the API and what my code was doing better. Much appreciated.