Skip to content

Instantly share code, notes, and snippets.

@trych
Last active September 9, 2023 01:40
Show Gist options
  • Save trych/24f1babebab4fcd85dad476f4b0e65fc to your computer and use it in GitHub Desktop.
Save trych/24f1babebab4fcd85dad476f4b0e65fc to your computer and use it in GitHub Desktop.
Multi-Keywords Plug-in for Lightroom Classic

Multi-Keywords Plugin for Lightroom Classic

Small LrC plug-in that enables a very specific workflow for rapidly applying multiple keywords at once via LR's keyword sets.

This will be mainly helpful for situations where you need to tag photos with 3 or 4 different subjects that might appear in the photos in different combinations. A typical example would be family photos with 3-5 different family members. Also, this plugin makes mostly sense when you tag your photos one after the other instead of selecting a bunch of photos at once.

In my search for the most rapid way to tag such photos I find the described workflow the quickest. However, your milage, or your style of tagging, might vary.

Download

multi-keywords.lrplugin.zip

Multi-keywords

The idea of the plugin is to place both regular keywords into your keywords set, as well as "multi-keywords" that consist of multiple keywords at once, so they can be applied with one keystroke. Let's say, we have a family of four, resulting in the keywords Paul, Mary, Mum and Dad.

Your corresponding keyset could look like this:

20230908-012403_Screenshot_LightroomClassic

Note that there are keywords containing commas, those are the "multi-keywords" that apply several keywords at once. The issue with those multi-keywords is that when you apply them, they get applied as a single keyword containing the commas (despite the LR docs claiming there can be no keywords containing commas).

Splitting multi-keywords to regular keywords

The sole purpose of the plug-in is to split the multi-keywords that were applied to photos into regular keywords, assign those to the photos instead and remove the multi-keywords (so the multi-keywords are just an intermediate format for rapid tagging, not meant to be the end result).

If you run the plug-in, by going into Library -> Plug-in Extras -> Apply Multi-Keywords, it will find all photos that have multi-keywords, split them to regular keywords and remove the multi-keywords. A message will inform you about the details of the operation.

20230908-024450_Screenshot_LightroomClassic

The operation is also undo-able.

Suggested workflow

  1. Create a keyword set with multi-keywords
  2. Go through a batch of photos and tag them using this keywords set, applying multi-keywords. Hint: The fastest way to apply them is by using the Alt + Number Key shortcut, specifically with the numpad that is arranged like the keyword set. Also note that you can switch keywords sets with Alt + 0.
  3. When you are done, run the script by doing Library -> Plug-in Extras -> Apply Multi-Keywords.

Installation

Download the multi-keywords.lrplugin file from the link above and place it whereever you keep your plug-ins. In Lightroom go to File -> Plug-in Manager…, click add at the bottom of plug-in list and select the multi-keywords.lrplugin file.

Warning

⚠️ This is not a fully polished plug-in, use at your own risk. ⚠️ It works for me though. If you give this plug-in a try, I would be happy to hear back from you, if it works for you.

Notes

Note that due to restrictions in LR's plug-in system the multi-keywords will not be removed from the catalog, i.e. they are still listed with 0 photos.

before after

There is no harm in leaving them there, but if you want to keep your Keyword List tidy, you can quickly remove them by doing Metadata -> Purge Unused Keywords.

return {
LrSdkVersion = 8.0,
LrToolkitIdentifier = 'dev.trych.lightroom.multi-keywords',
LrPluginName = 'Multi-Keywords',
LrLibraryMenuItems = {
{
title = "Apply Multi-Keywords",
file = "MultiKeywords.lua"
}
},
VERSION = { major=1, minor=1, revision=0 },
}
local LrApplication = import 'LrApplication'
local LrDialogs = import 'LrDialogs'
local catalog = LrApplication.activeCatalog()
function multiKeywords()
local allKeywords = catalog:getKeywords()
local multiKeywords = {}
for i, keyword in ipairs(allKeywords) do
local keywordName = keyword:getName()
if string.find(keywordName, ",") and #keyword:getPhotos() > 0 then
table.insert(multiKeywords, keyword)
end
end
if #multiKeywords == 0 then
LrDialogs.message("There are no multi-keywords in the catalog.")
return
end
local photoCount = 0
local photoLabel = nil
local allMultiKeywords = {}
local createdKeywords = {}
local keywordsToFind = {}
local duplicateKeyword = nil
for i, multiKeyword in ipairs(multiKeywords) do
local keywordName = multiKeyword:getName()
local separatedNames = split(keywordName, ",")
for j, name in ipairs(separatedNames) do
keywordsToFind[name] = true
end
end
local existingKeywords = {}
local function collectExistingKeywords(keywords)
for _, keyword in ipairs(keywords) do
local name = keyword:getName()
if existingKeywords[name] then
duplicateKeyword = name
return
else
existingKeywords[name] = keyword
end
collectExistingKeywords(keyword:getChildren())
end
end
collectExistingKeywords(catalog:getKeywords())
if duplicateKeyword then
LrDialogs.message("The keyword '" .. duplicateKeyword .. "' was found multiple times in the catalog.", "The plug-in can only operate on non-ambiguos keywords and has to abort.\n\nIf you still need to use the plug-in, you might want to re-name one of the keywords in question temporarily.\n\nNo changes were made to any photos or keywords.", "info")
return
end
catalog:withWriteAccessDo("Apply Multi-Keywords", function(context)
local allHandledPhotos = {}
for i, multiKeyword in ipairs(multiKeywords) do
local keywordPhotos = multiKeyword:getPhotos()
local multiKeywordName = multiKeyword:getName()
local separatedNames = split(multiKeywordName, ",")
local separateKeywords = {}
for j, name in ipairs(separatedNames) do
local separateKeyword
if existingKeywords[name] then
separateKeyword = existingKeywords[name]
elseif createdKeywords[name] then
separateKeyword = createdKeywords[name]
else
separateKeyword = catalog:createKeyword(name, {}, true, nil, true)
createdKeywords[name] = separateKeyword
end
table.insert(separateKeywords, separateKeyword)
end
for k, photo in ipairs(keywordPhotos) do
for kk, separateKeyword in ipairs(separateKeywords) do
photo:addKeyword(separateKeyword)
end
photo:removeKeyword(multiKeyword)
table.insert(allHandledPhotos, photo)
end
table.insert(allMultiKeywords, multiKeywordName)
end
photoCount = #uniqueArray(allHandledPhotos)
photoLabel = photoCount == 1 and "photo" or "photos"
end)
LrDialogs.message( photoCount .. " " .. photoLabel .. " updated!", "The following multi-keywords have been split and assigned as separate keywords to their photos:\n\n" .. table.concat(allMultiKeywords, "\n") .. "\n\nYou can now remove them from the catalog by choosing\nMetadata -> Purge Unused Keywords", "info")
end
import 'LrTasks'.startAsyncTask( multiKeywords )
-- split a string by a delimiter
function split(str, delim)
local result = {}
local regex = "([^" .. delim .. "]+)"
for match in string.gmatch(str, regex) do
table.insert(result, trim(match))
end
return result
end
-- trim whitespace from string
function trim(s)
return s:match'^%s*(.*%S)' or ''
end
-- return array with unique elements
function uniqueArray(arr)
local seen = {}
local result = {}
for i, v in ipairs(arr) do
if not seen[v] then
table.insert(result, v)
seen[v] = true
end
end
return result
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment