Skip to content

Add file size-based parent selection for photo stacks#64

Merged
Majorfi merged 5 commits into
mainfrom
feat/issue-47
May 28, 2026
Merged

Add file size-based parent selection for photo stacks#64
Majorfi merged 5 commits into
mainfrom
feat/issue-47

Conversation

@Majorfi
Copy link
Copy Markdown
Owner

@Majorfi Majorfi commented May 28, 2026

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

  • Added FileSizeInByte field to TExifInfo struct for file size tracking
  • Implemented file size-based parent selection logic in stacker_promote.go with 78 lines of new/modified code
  • Added comprehensive 191-line test suite covering size-based promotion edge cases
  • Updated environment variables documentation with new configuration options
  • Created feature documentation at docs/features/edited-photo-promotion.md explaining the promotion strategy

Risks

  • File size heuristic may be unreliable if images have different compression or processing applied
  • Changes parent selection behavior which may alter existing stack representatives for users
  • Edge cases with similarly-sized files could lead to non-deterministic parent selection
  • Users with existing stacks may see different parents selected if this becomes the default strategy

Test plan

  1. Run size-based promotion tests: go test -run TestSize ./pkg/stacker -v
  2. Test with real burst sequences containing RAW+JPEG pairs to verify largest file selection
  3. Verify behavior in dry-run mode: ./immich-stack --dry-run --env-file .env
  4. Test edge cases: similarly-sized files, compressed variants, multiple RAW formats
  5. Verify configuration via environment variables is properly documented

Docs impact

  • Updated docs/api-reference/environment-variables.md with new size-based promotion configuration
  • Created new feature documentation at docs/features/edited-photo-promotion.md
  • Consider updating README if file size promotion is a promoted feature
  • Verify environment variable documentation is complete and clear

Breaking 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.

Majorfi added 4 commits May 27, 2026 19:46
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
@Majorfi
Copy link
Copy Markdown
Owner Author

Majorfi commented May 28, 2026

Aim to fix #47

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.FileSizeInByte to asset types.
  • Extends stack sorting with biggestSize / smallestSize magic 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.

Comment thread pkg/stacker/stacker_promote.go Outdated
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
@Majorfi Majorfi merged commit 27a568d into main May 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants