Creating a Lightroom Classic Collection from Exported Filenames

This documents the process of creating a Lightroom Classic plugin to find original RAW files based on a directory of previously exported JPEGs.

The Problem

Over time, ~250 photos were exported from Lightroom Classic to share with others, but they were never tagged or organized in the catalog. Now we need to:

  1. Find those original RAW files in the Lightroom catalog
  2. Review and improve the RAW edits
  3. Re-export them at higher quality for a website

The challenge: we only have a directory of exported JPEGs with filenames like DSC_0043-Pano-Enhanced-NR.jpg, and need to match them back to originals like DSC_0043.NEF in the catalog.

The Approach

  1. Extract the base DSC_XXXX identifier from each exported JPEG filename
  2. Exclude photos already processed (listed in a manifest file)
  3. Create a Lightroom Lua plugin that searches the catalog and creates a Collection

Step 1: Extract and Filter Filenames

First, extract the DSC_XXXX pattern from exported JPEGs:

# Extract unique DSC IDs from exported JPEGs
ls /mnt/c/Users/jbuck/Downloads/photo_export/*.jpg \
  | xargs -n1 basename \
  | sed 's/\.[^.]*$//' \
  | sed 's/\(DSC_[0-9]*\).*/\1/' \
  | sort -u > /tmp/export_ids.txt

This handles various suffixes Lightroom adds during export:

  • DSC_0043.jpgDSC_0043
  • DSC_0043-Pano-Enhanced-NR.jpgDSC_0043
  • DSC_0043-Enhanced-NR.jpgDSC_0043

Next, extract IDs already in the manifest (photos already processed for the website):

# Extract DSC IDs from manifest.json
jq -r '.photos[].importedFile' site/src/lib/data/manifest.json \
  | sed 's/.*\(DSC_[0-9]*\).*/\1/' \
  | sort -u > /tmp/manifest_ids.txt

Finally, find IDs that are NOT yet in the manifest:

# Find IDs in export folder but not in manifest
comm -23 /tmp/export_ids.txt /tmp/manifest_ids.txt > /tmp/remaining_ids.txt

# Copy to plugin directory
cp /tmp/remaining_ids.txt \
  "/mnt/c/Users/jbuck/Documents/LrPlugins/FindByFilename.lrplugin/filenames.txt"

Result: 208 unique DSC IDs to find in the Lightroom catalog.

Step 2: Create the Lightroom Plugin

The plugin consists of two Lua files in a .lrplugin folder.

Plugin Structure

FindByFilename.lrplugin/
├── Info.lua           # Plugin metadata
├── CreateCollection.lua   # Main logic
└── filenames.txt      # List of DSC IDs to find

Info.lua

return {
    LrSdkVersion = 10.0,
    LrToolkitIdentifier = "com.jbuck.findbyfilename",
    LrPluginName = "Find By Filename",
    LrLibraryMenuItems = {
        { title = "Create Collection from File List", file = "CreateCollection.lua" }
    },
    VERSION = { major = 1, minor = 0, revision = 0 },
}

CreateCollection.lua

local LrApplication = import "LrApplication"
local LrDialogs = import "LrDialogs"
local LrTasks = import "LrTasks"
local LrPathUtils = import "LrPathUtils"
local LrFileUtils = import "LrFileUtils"

-- Extract DSC_XXXX pattern from a filename
local function extractDscId(filename)
    return filename:match("(DSC_%d+)")
end

LrTasks.startAsyncTask(function()
    local catalog = LrApplication.activeCatalog()

    -- Get the path to filenames.txt (same directory as this script)
    local pluginPath = _PLUGIN.path
    local filenamesPath = LrPathUtils.child(pluginPath, "filenames.txt")

    if not LrFileUtils.exists(filenamesPath) then
        LrDialogs.message("Error", "Could not find filenames.txt in plugin folder:\n" .. filenamesPath)
        return
    end

    -- Read the DSC ID list
    local dscIds = {}
    local file = io.open(filenamesPath, "r")
    if not file then
        LrDialogs.message("Error", "Could not open filenames.txt")
        return
    end

    local lineCount = 0
    for line in file:lines() do
        local trimmed = line:match("^%s*(.-)%s*$")  -- trim whitespace
        if trimmed and #trimmed > 0 then
            dscIds[trimmed:upper()] = true
            lineCount = lineCount + 1
        end
    end
    file:close()

    LrDialogs.showBezel("Searching for " .. lineCount .. " photos...")

    -- Find matching photos in catalog
    local allPhotos = catalog:getAllPhotos()
    local matches = {}
    local matchedIds = {}

    for _, photo in ipairs(allPhotos) do
        local filename = photo:getFormattedMetadata("fileName")
        local dscId = extractDscId(filename)
        if dscId and dscIds[dscId:upper()] then
            table.insert(matches, photo)
            matchedIds[dscId:upper()] = true
        end
    end

    if #matches == 0 then
        LrDialogs.message("No Matches", "No photos found matching the file list.")
        return
    end

    -- Create collection
    catalog:withWriteAccessDo("Create To Re-Export Collection", function()
        -- Remove existing collection if present
        local existingCollections = catalog:getChildCollections()
        for _, coll in ipairs(existingCollections) do
            if coll:getName() == "To Re-Export" then
                coll:delete()
                break
            end
        end

        local collection = catalog:createCollection("To Re-Export", nil, true)
        collection:addPhotos(matches)
    end)

    -- Count how many IDs were not found
    local notFound = 0
    local notFoundList = {}
    for dscId, _ in pairs(dscIds) do
        if not matchedIds[dscId] then
            notFound = notFound + 1
            if #notFoundList < 10 then
                table.insert(notFoundList, dscId)
            end
        end
    end

    local message = "Found " .. #matches .. " photos.\nAdded to 'To Re-Export' collection."
    if notFound > 0 then
        message = message .. "\n\n" .. notFound .. " IDs not found in catalog"
        if #notFoundList > 0 then
            message = message .. ":\n" .. table.concat(notFoundList, ", ")
            if notFound > 10 then
                message = message .. "..."
            end
        end
    end

    LrDialogs.message("Complete", message)
end)

Step 3: Install and Run the Plugin

  1. Open Lightroom Classic
  2. Go to File → Plug-in Manager
  3. Click Add (bottom left)
  4. Navigate to the .lrplugin folder and select it
  5. Click Done
  6. Go to Library → Plug-in Extras → Create Collection from File List

The plugin will:

  • Search the entire catalog for photos matching the DSC IDs
  • Create a collection called “To Re-Export” containing all matches
  • Report how many were found and list any that weren’t in the catalog

Notes

  • The plugin matches on the DSC_XXXX pattern, which handles both original RAW files (DSC_0043.NEF) and Lightroom-generated files (DSC_0043-Pano.dng)
  • Matching is case-insensitive
  • Running the plugin again replaces the existing “To Re-Export” collection
  • To update the file list, edit filenames.txt in the plugin folder and re-run