Conversation
…lection matching Three fixes/improvements to the Lightroom Classic plug-in, found and fixed while dogfooding it against a real LrC instance: - Ship the publish service's icon (icon.png/icon@2x.png). It was referenced in code but never added to the plug-in folder, so it showed up blank/broken in Lightroom's Publishing Services panel. - Stop duplicate files piling up on re-publish. uploadOnePhoto always created a new Lumio file and never removed the previous one, so editing a photo and republishing (or a manual "Republish") left several versions of the same photo in the online gallery. The plug-in now deletes the old remote file (via rendition.publishedPhotoId) before uploading the new one. - Make Selection-Import matching survive renames and same-basename ambiguity. The Publish-Service now embeds the MD5 of the original master file into a custom XMP segment of the uploaded JPEG (JpegXmp.lua). The worker extracts it via the existing exiftool call and stores it under the already-present (and previously unused) exif.lumio.originalMd5 JSON field -- no schema migration needed. Selection-Import uses it to auto-resolve ambiguous filename matches and, with a new opt-in option, to recover files renamed after publishing. Also: bump the plug-in to v0.3, translate all plug-in comments to English (previously a mix of German/Finnish/English), and update the plug-in's own README/known-limitations docs to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… public gallery goToPublishedCollection built the public customer-facing link (host + /g/<slug>). A photographer clicking "Show in Lumio" from Lightroom wants to manage the gallery, not see the customer's view, so it now opens the Studio management page (host + /studio/<galleryId>) instead. The Studio route is keyed by gallery id, not slug, so this also drops the now-unneeded slug-from-cache lookup and the gallerySlug tracking in processRenderedPhotos that only existed to support it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- JpegXmp.lua: insert the XMP hash segment after a leading APP0/JFIF
segment when present, instead of unconditionally right after SOI.
Verified byte-for-byte against a real JPEG with and without a
leading APP0.
- ImportSelectionTask.lua: the rename-recovery hash map was
hash -> file (single), silently dropping every file after the first
one sharing a hash -- normal when virtual copies of one master were
all published. Now hash -> list of files, all resolved to the same
matched photo.
- LumioPublishService.lua: add goToPublishedPhoto (per-photo "Show
public gallery"), opening the public customer-facing gallery link.
Complements the collection-level "Show in Lumio" now pointing at the
Studio view, for when you do want to see the client's side -- and
doesn't need an active Studio session the way the Studio link does.
Restores the gallerySlug tracking this needs.
- db.py: mark_file_ready no longer touches the exif column at all when
there's no original_md5 to write (previously flipped NULL to {} on
every file). When there is one, it's written via jsonb_set over the
existing 'lumio' object instead of a flat merge, so a future second
field under exif.lumio survives being written alongside originalMd5.
Verified both the previous silent-{} behaviour and the new jsonb_set
merge against a throwaway Postgres instance.
- README.md (DE): fixed an Italian checkbox label ("Rinominati per
hash") accidentally left in the German option description.
- Added worker tests for extract_original_md5/extract_metadata,
including one asserting a single exiftool call for both values.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… speed up rename recovery Addresses the real end-to-end test report from @canja006 on PR markusthiel#27 (LrC 15.5.1, 2774-photo catalog). - goToPublishedPhoto ("Show public gallery") always failed: it assumed info.publishedCollectionInfo had a .collectionSettings field like getCollectionInfoSummary() elsewhere in this file. On a real install it only ever carries {isDefaultCollection, name, parents}, and LrPublishedPhoto has no getPublishedCollection() either. Adopts @canja006's tested fix: fetch the collection through photo:getContainedPublishedCollections() instead, wrapped in LrTasks.startAsyncTask since that call yields. - gallerySlug was only ever captured when a NEW gallery was created from the plug-in dialog; a collection bound to an EXISTING gallery (picked from the dropdown) never got one, leaving the public-gallery link dependent on a cache that goes stale as soon as the gallery is edited in Studio. processRenderedPhotos now self-heals it (same proven catalog:withWriteAccessDo pattern already used for gallery creation) on the next publish to any such collection. - Rename-recovery hash pass took 4m12s on the full 2774-photo catalog (the default scope) vs 3.8s on a 70-photo collection, with Lightroom visibly sluggish and memory climbing. Three fixes: stop scanning once every target hash is found (it never exited early before), skip photos pass 1 already matched by filename (they were hashed again for nothing), and -- the structural fix -- embed the original master's byte size alongside its MD5 (free: the file is already fully in RAM to hash it) so a rename-recovery candidate can be ruled out with a plain LrFileUtils.fileAttributes stat instead of being fully read into memory. Exact byte-size collisions between different photos are rare; identity is still always confirmed by the real hash. exif_meta.py/db.py/plugin.ts extended to carry originalSize alongside originalMd5 through the same pipeline, same reasoning as the original hash (no schema change, jsonb_set-based merge). - Logger.lua/README: corrected the macOS log path for current Lightroom Classic (confirmed on 15.5: ~/Library/Logs/Adobe/Lightroom/ LrClassicLogs/, not ~/Documents/LrClassicLogs/). Verified: XMP round-trip with the new OriginalSize field against a real JPEG + exiftool (with and without a size, matching the existing OriginalMD5 test pattern); worker db.py's extended jsonb_set query against a throwaway Postgres instance including the actual mark_file_ready() function end-to-end (exif=NULL populated with both fields when given, an existing exif with sibling keys left completely untouched when no hash is given); 4 new + all 19 existing worker tests pass; tsc --noEmit clean; luac -p clean on all 9 plug-in files. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Scoped to the Python files touched by this PR (db.py, process_file.py, process_raw.py, test_exif_meta.py) -- exif_meta.py was already in English. Comments only, no functional changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Prepares the plug-in for the Collection Set / Chapters feature (markusthiel#31). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…dialog
Raise maxCollectionSetDepth to 1 and implement the three set-level
callbacks (viewForCollectionSetSettings, endDialogForCollectionSetSettings,
updateCollectionSetSettings) that were missing when the crash-avoidance
maxCollectionSetDepth = 0 was originally put in place. The existing
gallery-picker dialog is factored into shared helpers
(initGalleryPickerProps/buildGalleryPickerView) reused by both a root
collection ("Simple Gallery", the renamed original flat mode) and a
Collection Set ("Lumio Gallery").
viewForCollectionSettings now branches by collection role via the new
classifyCollection helper: root, the Set's auto-created default child,
or an additional chapter collection -- the latter two get placeholder
dialog text for now; wiring them to gallery inheritance and chapter
creation follows in later commits.
No Lumio API calls yet -- pure dialog/terminology groundwork, part 1 of
markusthiel#31's implementation checklist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…publish A default-child or chapter collection with no galleryId yet now resolves its parent Collection Set's Lumio gallery settings (getParentSetSettings) and inherits galleryId/gallerySlug from it, creating the gallery on the Set's own first-ever publish if none exists yet -- mirroring the existing root/flat "create on first publish" pattern one level up. The resolved galleryId/gallerySlug are also cached onto the child's own collection settings, so deletePhotosFromPublishedCollection/goToPublishedCollection/ goToPublishedPhoto keep working completely unchanged. makeLive is read fresh from the parent Set on every publish rather than cached on the child, since it's a live toggle the photographer may flip on the Set after chapters already exist. No section/chapter creation yet -- both default and chapter children just inherit the gallery for now, landing photos in the unsectioned bucket. Part of markusthiel#31. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
createSection, patchSection, deleteSection, assignFilesToSection -- thin wrappers around the generic Studio Section-CRUD routes (galleries.ts), reusing M.request's existing retry/auth handling exactly like initUpload/completeUpload already do. Plumbing only, not wired into the publish flow yet. Part of markusthiel#31. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…them A chapter (non-default) child collection now resolves or creates its Lumio Section on first publish (api.createSection, title = the LR collection's own name), persisting sectionId onto the collection's settings the same withWriteAccessDo way galleryId already is. uploadOnePhoto now returns the Lumio fileId on success instead of nothing, threaded through its LrTasks.pcall call site in processRenderedPhotos so a chapter publish can collect this run's uploaded fileIds and batch-assign them to the Section afterwards (api.assignFilesToSection), chunked to the server's 500-fileIds-per-call limit. A default-child or root collection never gets a sectionId, so this is a no-op for them -- their photos keep landing in the gallery's unsectioned bucket exactly as before. A section-assignment failure is reported in the existing summary dialog but does not fail the publish -- the photos are already uploaded either way. Completes the core Chapters functionality from markusthiel#31's implementation checklist (steps up to markusthiel#7). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New renamePublishedCollection/deletePublishedCollection hooks: for a chapter (non-default) child collection with a sectionId, a rename in Lightroom PATCHes the Section's title and a delete DELETEs the Section (files fall back to the gallery's unsectioned bucket server-side, ON DELETE SET NULL). Root and default-child collections never had a sectionId, so both hooks are a no-op for them. Deleting the whole Collection Set (Lumio Gallery) is deliberately NOT targeted here -- only per-child collection deletes clean up their own Section. The Gallery itself stays Studio-only to delete, unchanged from today, tracked separately. Both hooks are best-effort/logged, matching the file's existing swallow-and-log philosophy -- a sync failure must never block the rename/delete Lightroom already performed locally. The exact `info` payload shape is written defensively pending real-device verification (no CI covers this plugin). Completes markusthiel#31's implementation checklist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CHANGELOG entry (English-only, matching the current convention) plus a new "Chapters" section in both the German and Italian plugin READMEs explaining Collection Sets, the auto-created default child, and how chapter rename/delete syncs to Lumio. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… chapters, auto-create Default
- Rename the Collection Set concept from "Lumio Gallery" to "Chapters
Gallery" throughout (dialog titles, error messages, comments).
"Simple Gallery" (the root/flat mode) is unchanged.
- Drop Smart Collection support (titleForPublishedSmartCollection/
_standalone) entirely: a Chapters Gallery's right-click menu now
offers exactly one way to add a child -- a plain collection/chapter.
Nested Collection Sets were already blocked by maxCollectionSetDepth
= 1. Smart Collections were never wired into any Lumio-specific
logic beyond the title strings, so nothing else is affected.
- updateCollectionSetSettings now explicitly creates a "Default" child
collection the moment the Set itself is saved
(publishService:createPublishedCollection("Default", newSet, true),
inside catalog:withWriteAccessDo -- canReturnExisting = true keeps
it idempotent if the dialog is saved again). The new collection gets
collectionSettings.isDefaultChapter = true.
- classifyCollection now keys off that own isDefaultChapter flag
instead of the SDK's info.isDefaultCollection, which was never
real-device-confirmed at this call site and would misclassify a
collection we create ourselves anyway. This also means renaming
"Default" no longer risks turning it into a chapter -- classification
is entirely under this plug-in's own control now.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Version bump for the Chapters Gallery terminology/menu/Default-chapter refinements. CHANGELOG entry updated in place (still under [Unreleased], 0.4.0 was never released) and both plugin READMEs (German, Italian) updated to describe the Chapters Gallery naming, the restricted right-click menu, and the immediately-created "Default" chapter collection. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nheritance Three real, log-confirmed bugs found via real-device testing on 0.4.1, all wrong SDK method/field names guessed without a live Lightroom Classic install to verify against -- fixed now against the official Lightroom Classic 15 SDK reference (local docs, not third-party mirrors): 1. getParentSetSettings called a non-existent catalog:getPublishedCollectionSetByLocalIdentifier, throwing "attempt to call method ... (a nil value)" on every publish of a default/chapter child -- confirmed in Lumio.log. Fixed by using LrPublishedCollection:getParent() directly on the collection object (confirmed to exist), which also simplifies the function (no more catalog round-trip via localIdentifier). 2. updateCollectionSetSettings read info.publishedCollectionSet, which doesn't exist on this hook's info table -- the confirmed field name is info.publishedCollection (despite holding an LrPublishedCollectionSet value here). This silently skipped Default chapter creation every time, logged as "missing publishService/publishedCollectionSet". 3. The parent Set's own settings were read/written via getCollectionInfoSummary()/setCollectionSettings() -- the plain-collection methods, which don't exist on LrPublishedCollectionSet. Fixed to getCollectionSetInfoSummary()/setCollectionSetSettings(), the confirmed Set-object equivalents. This would have thrown as soon as bug markusthiel#1 was fixed, since it's on the same gallery-creation path. Also simplified renamePublishedCollection/deletePublishedCollection (info.publishedCollection is confirmed singular, never an array, and info.collectionSettings is not a documented field on either hook -- removed the now-provably-dead branches for both) and corrected several comments that claimed uncertainty or behavior later confirmed false (e.g. Set rename does NOT currently sync its title to Lumio, despite an earlier comment implying it did). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… limitation
The 0.4.1 CHANGELOG entry and both plugin READMEs claimed the
right-click menu on a Chapters Gallery shows no Smart Collection
option. Confirmed false via the official SDK reference: omitting
titleForPublishedSmartCollection only changes Lightroom's own fallback
wording ("Published Smart Collection") -- there is no documented way
to remove the menu entry entirely (no canAddSmartCollection-style gate
exists in getCollectionBehaviorInfo). Docs corrected to describe the
actual, confirmed behavior instead of the incorrect earlier claim.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…gates, drop redundant title field Four issues found via a second round of real-device testing on 0.4.1, this time with "Show in Lumio" on a Chapters Gallery itself and a closer look at the log after the previous fixes: 1. "Show in Lumio" on a Collection Set threw an unguarded Lua error (worked fine on a chapter). goToPublishedCollection only ever tried info.publishedCollection:getCollectionInfoSummary() -- the plain-collection method, which doesn't exist on a LrPublishedCollectionSet. Now tries that first and falls back to getCollectionSetInfoSummary() for a Set, matching the same dual-type handling already used in getParentSetSettings. 2. Default chapter creation could still fail even with the updateCollectionSetSettings field-name fix from the previous commit: log confirmed "Can't get collection information after creating collection inside the same withWriteAccessDo function" -- querying/setting collectionSettings on a collection in the SAME write-access gate that created it isn't allowed (the same restriction LrPublishedCollection:getParent's own doc warns about, evidently not unique to getParent). Split into two separate withWriteAccessDo calls: one to create, a second to mark isDefaultChapter. 3. Creating a plain collection inside a Chapters Gallery showed the full root-style dialog (existing-gallery picker, including picking an EXISTING gallery) because viewForCollectionSettings cannot classify a collection as root vs. chapter before it exists (info.parents is only populated when editing an existing collection). If the photographer picked an existing gallery there, that WRONG galleryId would have been used at publish time instead of the parent Set's, since the resolution logic was gated on "galleryId already set" before checking `kind`. Restructured so a default/chapter child's gallery is now ALWAYS resolved from its parent Set, unconditionally overriding any such stray value. 4. Removed the separate "gallery title" edit field from the picker dialog entirely (used both for a root collection and, incorrectly, shown to what turns out to be a chapter per markusthiel#3) -- a new gallery's or chapter's title is now always the Lightroom collection's own name, read at first-publish time via getName(), exactly like a chapter's title already worked. Removes asking the photographer for the same name twice. Also dropped the custom titleForPublishedCollection/_standalone ("Simple Gallery") -- confirmed via the official SDK reference that this single string drives LR's native "Create .../Rename ..." menu text for EVERY plain collection, including ones created inside a Chapters Gallery (which are chapters, not "Simple Gallery"), with no way to vary it by context. Lightroom's own generic default, "Published Collection", is a more honest compromise than a misleading custom name. The dialog content we fully control (group_box titles per classifyCollection) is unaffected and still reads correctly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ified dialog Document that "Show in Lumio" now works on a Chapters Gallery itself, that creating a gallery/chapter no longer asks for a separate title (uses the Lightroom collection's own name), and that the native "Create Published Collection" menu wording inside a Chapters Gallery is Lightroom's generic default rather than "Simple Gallery" -- that text isn't selectively customizable per context. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
There is a confirmed crash risk in the publish flow due to an unguarded fileAttributes() nil dereference, plus a doc formatting issue in the Unreleased changelog entry.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR upgrades the Lightroom Classic plug-in to support modeling a Lumio Gallery as a Collection Set (“Chapters Gallery”), where child collections become Lumio Chapters/Sections, while also carrying forward the earlier work to embed an original-file MD5 (+ size) into published JPEGs for more robust Selection-Import matching.
Changes:
- Lightroom Publish-Service: add Collection Set (“Chapters Gallery”) support with automatic “Default” child creation, chapter (section) create/rename/delete sync, and chapter file assignment batching.
- Lightroom Publish-Service + Worker + API: embed original master MD5/size into uploaded JPEG XMP, extract it in the worker, and surface it via plugin endpoints for Selection-Import hash-based disambiguation/rename recovery.
- Documentation/versioning updates: plug-in version bump plus README/CHANGELOG updates.
File summaries
| File | Description |
|---|---|
| CHANGELOG.md | Documents new plug-in capabilities and hash-based matching behavior. |
| apps/worker/tests/test_exif_meta.py | Adds worker tests for reading embedded original MD5/size and single-call extraction. |
| apps/worker/tasks/process_raw.py | Switches RAW pipeline to single-call EXIF+original-hash extraction and persists it. |
| apps/worker/tasks/process_file.py | Switches image pipeline to single-call EXIF+original-hash extraction and persists it. |
| apps/worker/exif_meta.py | Implements extraction of custom XMP tags + combined extract_metadata() to avoid multiple exiftool invocations. |
| apps/worker/db.py | Persists originalMd5/originalSize into files.exif->lumio without forcing NULL→{} churn. |
| apps/lightroom-plugin/README.md | Updates German README for Simple vs Chapters gallery workflow and hash-matching limitations. |
| apps/lightroom-plugin/README.it.md | Updates Italian README for Simple vs Chapters gallery workflow and hash-matching limitations. |
| apps/lightroom-plugin/lumio.lrdevplugin/PluginManager.lua | Updates plug-in manager strings/comments (host/token UI). |
| apps/lightroom-plugin/lumio.lrdevplugin/LumioPublishService.lua | Core publish-service changes: set support, chapter syncing, assignment batching, “Show in Lumio” fixes, and hash embedding. |
| apps/lightroom-plugin/lumio.lrdevplugin/LumioApi.lua | Adds section CRUD + section file assignment API wrappers for chapters. |
| apps/lightroom-plugin/lumio.lrdevplugin/Logger.lua | Updates logging-path documentation/comments. |
| apps/lightroom-plugin/lumio.lrdevplugin/Json.lua | English comment cleanups in embedded JSON library wrapper. |
| apps/lightroom-plugin/lumio.lrdevplugin/JpegXmp.lua | New module to embed original MD5/size as an APP1-XMP segment (APP0-aware insertion). |
| apps/lightroom-plugin/lumio.lrdevplugin/Info.lua | Bumps plug-in version to 0.4.1 and updates top-level docs/comments. |
| apps/lightroom-plugin/lumio.lrdevplugin/ImportSelectionTask.lua | Adds hash-based disambiguation + optional rename recovery with size prefilter. |
| apps/lightroom-plugin/lumio.lrdevplugin/ImportSelectionDialog.lua | Adds opt-in UI setting for hash-based rename recovery. |
| apps/api/src/routes/plugin.ts | Exposes originalMd5/originalSize from exif.lumio defensively in plugin endpoints. |
| apps/api/prisma/schema.prisma | Documents the exif.lumio.originalMd5 meaning/usage in the schema. |
Review details
- Files reviewed: 19/21 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| -- File size (measure AFTER embedding, see above) | ||
| local sizeBytes = LrFileUtils.fileAttributes(filepath).fileSize or 0 |
|
|
||
| ### Added | ||
|
|
||
| - Lightroom plug-in: the Publish-Service now embeds the MD5 hash of the original master file into a custom XMP field of the uploaded JPEG, and the Selection-Import side uses it to automatically resolve ambiguous filename matches (e.g. the same shot published as both `.NEF` and `.DNG`) and, with a new opt-in option, to recover files that were renamed in Lightroom after publishing. Only available for files published from this plug-in version onward. · *The Lightroom plug-in's Publish-Service now embeds the original master file's MD5 hash into a custom XMP field of the uploaded JPEG, and Selection-Import uses it to automatically resolve ambiguous filename matches (e.g. the same shot published as both `.NEF` and `.DNG`) and, with a new opt-in option, to recover files renamed in Lightroom after publishing. Only available for files published from this plug-in version onward.* |
…CHANGELOG text Addresses Copilot's review on PR markusthiel#32: - uploadOnePhoto: LrFileUtils.fileAttributes(filepath) can return nil (temp render deleted/moved from under us, disk hiccup), and indexing .fileSize on it threw an unhandled "attempt to index a nil value" instead of a clear error. Contained to the one photo (the call site is already inside a pcall in processRenderedPhotos's render loop), but the error message was unhelpful -- now guarded with a clear message instead. - CHANGELOG.md: the 11 bullets in the Unreleased section duplicated their own text as a trailing " · *...*" span -- leftover from this changelog's old bilingual (German · English) format, except the "German" half was never actually translated, so it just repeated the English sentence. Stripped the duplicated span from all 11, matching the plain-English convention already used everywhere else (confirmed: this project moved away from the bilingual per-entry format after 0.74.0). Dated historical sections are untouched -- those bilingual pairs are genuine German+English, not duplicates. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@copilot please review the latest changes. |
|
Thanks for the ping — happy to run this on my setup, the same way as on #27. The earliest I can get to it is tomorrow. I'll go through the full list on Lightroom Classic 15.5.1 / macOS against my self-hosted instance: Set creation dialog, the right-click menus on the Set and on a chapter collection, the auto-created "Default" child, chapter create/rename/delete round-trips, and "Show in Lumio" on the Set itself. Report in the same format as before. |
|
Ran the Chapters Gallery flow on my install — Lightroom Classic 15.5.1 on macOS, self-hosted Lumio still at Menus and dialogs, since you asked specifically. Right-click on the service shows What works
Chapter deletion never reaches Lumio in the case the README describesREADME step 4 says: delete the collection → chapter deleted on Lumio, photos fall back to the unsectioned bucket. On a real install it depends entirely on which button the user presses in Lightroom's own confirmation dialog:
This is documented SDK behaviour, not a 15.5 quirk — the reference for So the README outcome is reachable only through the button whose own dialog says the photos will be deleted from the service, while the choice a photographer will naturally make to keep their photos ("Leave on Service") leaves an orphaned chapter on Lumio. I verified with a log line as the first statement of I don't see a way for the plug-in to cover the "Leave on Service" case — there is no hook. What it can do is say so. README/CHANGELOG should state that removing a chapter on Lumio requires choosing Delete in Lightroom's dialog, that the photos are nevertheless kept in the gallery (unsectioned), and that "Leave on Service" only removes the Lightroom collection — the chapter then has to be deleted in Studio. Deleting the SetDeleting the whole Set (with "Delete") leaves the gallery untouched, as intended — but by accident. Lightroom invokes
Two small things
Happy to re-run the delete cases on a follow-up commit. |
…chapter remoteId Addresses @canja006's real-device follow-up testing on PR markusthiel#32: - renamePublishedCollection/deletePublishedCollection: previously relied on getCollectionInfoSummary() throwing when info.publishedCollection is actually a LrPublishedCollectionSet (the Set itself renamed/deleted, not a chapter), with the pcall silently swallowing that error and falling through to the same nil-collSettings no-op used for "not a chapter". The end result was correct (a Set's rename/delete must never touch the Lumio gallery) but only by accident. Confirmed via real-device testing: "attempt to call method 'getCollectionInfoSummary' (a nil value)" when deleting a Set. Both functions now check for that failure explicitly and return, making the non-goal hold by design. - processRenderedPhotos: also call exportContext.publishedCollection:setRemoteId(sectionId) in the same write-access block that already persists sectionId onto a new chapter's own settings. Not read anywhere in this plug-in today, but costs nothing and gives info.remoteId "for free" in future rename/delete callback work -- verified working on a real install. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… dialog choice README (DE/IT) and CHANGELOG updated per @canja006's real-device testing: a chapter collection's Section only gets deleted on Lumio if the photographer picks "Delete" (not "Leave on Service") in Lightroom's own delete-confirmation dialog -- documented Lightroom SDK behavior (deletePublishedCollection is only invoked for "Delete"), not something the plug-in can influence. Previously the README implied deleting the collection always synced the deletion; now it explains both outcomes and that "Leave on Service" leaves an orphaned chapter that has to be removed manually in Lumio Studio. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@canja006 thank you for the thorough follow-up testing — checking against the DB and log, not just the panel, caught things I wouldn't have found otherwise. Pushed two commits addressing your report:
Really appreciate you running the delete-case matrix in such detail. Let me know if you spot anything else on a follow-up pass. |
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Forgot to bump to Plugin Version 0.4.2 for easier identification in LrC |
|
Re-ran the delete matrix on
So the three cases from my report now behave the same as before but on purpose, and the README wording matches what Lightroom actually does. One small thing on if info.publishedCollection:type() == "LrPublishedCollectionSet" then return endbefore the Nothing else outstanding from my side. |
…t a caught error Non-blocking follow-up from @canja006's re-test of e8d1451 (confirmed all three delete/rename cases now behave correctly and on purpose, and setRemoteId lands as expected). Their one remaining note: keying the Set no-op off getCollectionInfoSummary() throwing conflates two different situations -- "this really is a Set" (intentional no-op) and "this is a chapter but the read genuinely failed for some other reason" (a real bug) -- under the same silent no-op. Both LrPublishedCollection and LrPublishedCollectionSet have a type() method, confirmed against the official Lightroom Classic 15 SDK reference to return exactly "LrPublishedCollection" / "LrPublishedCollectionSet". New shared isPublishedCollectionSet() helper checks that directly before ever calling getCollectionInfoSummary(), so a genuine failure on a real chapter now logs a warning instead of silently doing nothing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@canja006 thanks for the re-test — good to have all three cases confirmed clean after a full reinstall/restart, and that Applied your Nothing else pending on my end either. Thanks again for all the real-device rounds on this one. |
|
Read through this and the whole exchange above. Nothing to add on the code — you two closed this out without me, and the review round is the kind I'd want as the norm here: @canja006 checking One structural note. GitHub shows +2279 across 21 files here, but #27 is an ancestor of this branch, so most of that isn't yours: So this goes in after #27, which still has three open items from Copilot's re-review on the 8th. Merging this first would pull #27 in silently, unfixed. Makes sense that @canja006 tested against a server at No retargeting needed from my side, unlike the print-shop set; I mostly want the ordering written down somewhere. Queue is: #27 → this one. |
|
@markusthiel #27 has got an update, if successful I will rebase this PR with main branch and push agin to update this PR as in my flow this was straight after #27 |
Summary
Implements #31: a published collection can now be a Collection Set, which becomes a Chapters Gallery on Lumio. Saving the Set immediately creates a "Default" child collection (photos published there land in the gallery's normal unsectioned bucket), and every additional child collection becomes a real Chapter (
GallerySection) on Lumio, with its uploaded photos assigned to that chapter automatically. Renaming or deleting a chapter collection in Lightroom syncs to the corresponding chapter on Lumio, and "Show in Lumio" now also works on the Set itself.A plain collection directly under the publish service keeps working exactly as before. No server-side changes were needed — this reuses the existing Studio Section API (
/galleries/:id/sections*), which already accepts the same Bearer-token auth the plugin already uses for uploads.Plugin version bumped to 0.4.1.
Diff scope note: this branch is built on top of
feat/lightroom-plugin-icon-dedupe-hash-matching(#27), which hasn't merged yet, so this diff includes those commits too (icon, anti-duplicate republish, hash-based selection matching, and their follow-up fixes) in addition to the new Chapters Gallery work. Happy to rebase and re-scope once #27 merges, if that's preferred — just let me know.What changed (Chapters Gallery, on top of #27)
Info.lua: version 0.4.1LumioApi.lua: 4 new methods (createSection,patchSection,deleteSection,assignFilesToSection), thin wrappers around the existing Studio Section-CRUD routesLumioPublishService.lua: Collection Set support (maxCollectionSetDepth = 1), the three required set-level dialog callbacks, gallery inheritance from parent Set on first publish, chapter creation + batched/chunked file assignment, rename/delete sync for chapters, and agoToPublishedCollectionfix that now handles both plain collections and SetsKnown SDK limitations (not bugs, confirmed against the official Lightroom Classic SDK reference)
Test plan
No automated test coverage exists for this plugin (no CI job touches
apps/lightroom-plugin, no Lua test framework) — everything below was verified manually against a real Lightroom Classic 15.5.1 install on macOS, against a live Lumio instance, across several rounds of real-device testing and fixes:GallerySection) and assigns its photos to it@canja006 — given your real-device testing on #27, it'd be great if you could also give this a try on your own Lightroom Classic setup when you have a chance, the same way you helped catch the
goToPublishedPhotoissue there. In particular any environment/version differences in how Lightroom handles Collection Set creation dialogs and the right-click menu would be valuable to confirm.🤖 Generated with Claude Code