Add file size-based parent selection for photo stacks#64
Merged
Conversation
Add TExifInfo type to carry file size metadata from Immich API responses. The nullable pointer semantics ensure that assets without exif data fall through cleanly in downstream code rather than treating missing metadata as zero. Change-Type: feature Scope: types
Add biggestSize and smallestSize magic keywords for tie-breaking in parent selection. These keywords act as fallback buckets after extension preferences, allowing size-based promotion while respecting user-configured extension priorities (e.g., a 12MB JPG wins over a 28MB RAW when JPG is listed first in PARENT_EXT_PROMOTE). Introduce isMagicPromoteKeyword() to unify handling of all tie-breaker keywords (biggestNumber, biggestSize, smallestSize, sequence variants). Refactor getPromoteIndex and getPromoteIndexWithMode to use this helper. Scope: stacker Change-Type: feature
Add 11 test cases covering the new size promotion feature: basic biggestSize/smallestSize behavior, interaction with substring matching, missing/partial exif data handling, the real-world DSLR scenario (JPG+RAW+exported JPG), equal sizes, and JSON unmarshaling from Immich API responses. Scope: test Change-Type: test
Document the new biggestSize and smallestSize magic keywords for parent selection. Include configuration examples, the DSLR use case (exported JPG from Lightroom winning over camera originals), and technical details about evaluation order (size tie-break runs after extension preferences but before alphabetical sort). Change-Type: docs Scope: docs
Owner
Author
|
Aim to fix #47 |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds file-size-based parent selection for photo stacks, allowing users to opt into biggestSize or smallestSize as PARENT_FILENAME_PROMOTE tie-breakers using Immich EXIF file-size metadata.
Changes:
- Adds
ExifInfo.FileSizeInByteto asset types. - Extends stack sorting with
biggestSize/smallestSizemagic keywords. - Adds size-promotion tests and updates user-facing documentation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
pkg/utils/types.go |
Adds optional EXIF metadata with file size to TAsset. |
pkg/stacker/stacker_promote.go |
Adds magic keyword handling and file-size sorting tie-breaker. |
pkg/stacker/stacker_size_promote_test.go |
Adds tests for size-based promotion and JSON unmarshalling. |
docs/features/edited-photo-promotion.md |
Documents size-based promotion behavior and examples. |
docs/api-reference/environment-variables.md |
Updates environment variable reference for new promote keywords. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The original size-based comparator was non-transitive when some assets lacked exif data. With 3+ assets (e.g., z:10MB, a:5MB, m:none), pairwise comparisons created cycles: z→a (by size), a→m (alphabetical fallthrough), m→z (alphabetical fallthrough). This violated sort.SliceStable's total-order contract. Fix partitions assets into buckets using a per-asset predicate: assets with positive size go first (sorted by size direction), assets without exif go last. Bucket membership is determined by a single asset property, not the pair, ensuring transitivity. Added regression tests covering both biggestSize and smallestSize directions with mixed exif data. Change-Type: fix Scope: stacker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements file size-based parent selection strategy to intelligently choose the largest file in a stack group as the representative photo. This is particularly valuable for identifying edited versions or RAW files that are typically larger than their JPEG counterparts, improving photo organization quality.
What changed
FileSizeInBytefield toTExifInfostruct for file size trackingstacker_promote.gowith 78 lines of new/modified codedocs/features/edited-photo-promotion.mdexplaining the promotion strategyRisks
Test plan
go test -run TestSize ./pkg/stacker -v./immich-stack --dry-run --env-file .envDocs impact
docs/api-reference/environment-variables.mdwith new size-based promotion configurationdocs/features/edited-photo-promotion.mdBreaking changes
Potentially: Parent photo selection may change for existing stacks if file size-based promotion becomes the default or is enabled. Users should review their stacks in dry-run mode first to preview changes before applying them to their Immich library.