* feat(web): Synchronize information from deduplicated images
* Added new settings menu to the the deduplication tab.
* The toggable options in the settings are synchronization of: albums, favorites, ratings, description, visibility and location.
* When synchronizing the albums, the resolved images will be added to all albums of the duplicates.
* When synchronizing the favorite status, the resolved images will be marked as favorite, if at least one selectable image is marked as favorite.
* When synchronizing the ratings, the highest rating from the selectable images will be applied to the resolved image.
* When synchronizing the description, all descriptions from the selectable images will be merged into one description for the resolved image.
* When synchronizing the visibility, the most restrictive visibility setting from the selectable images will be applied to the resolved image.
* When synchronizing the location, if exactly one unique location exists among the selectable images, this location will be applied to the resolved image.
* There is no additional UI for these settings to keep the visual clutter minimal. The settings are applied automatically based on the user's preferences.
* Replace addAssetToAlbums with copyAsset
* fix linter
* feat(web): add duplicate sync fields and fix typo
* feat(web): add tag sync and enhance duplicate resolution
This update introduces tag synchronization for duplicate resolution,
ensuring all unique tag IDs from duplicates are applied to kept assets.
The visibility sync logic is updated to use a simplified ordering, as the hidden status items will never show up in a duplicate set.
Album synchronization now merges albums directly via addAssetsToAlbums; as the approach with copyAsset API endpoint was ineffiecient.
Description, rating, and location sync logic is improved for correctness.
and deduplication. i18n strings were added / updated.
* feat(server): move duplicate resolution to backend with sync and stacking
Moves duplicate metadata synchronization from frontend to backend, enabling robust
batch operations and proper validation. This is an improved refactor of PR #13851.
New endpoints:
- POST /duplicates/resolve - batch resolve with configurable metadata sync
- POST /duplicates/stack - create stacks from duplicate groups
- GET /duplicates - now includes suggestedKeepAssetIds based on file size and EXIF
Key changes:
- Move sync logic (albums, tags, favorites, ratings, descriptions, location, visibility) to server
- Add server-side metadata merge policies with proper conflict resolution
- Replace client-side resolution logic with new backend endpoints
- Add comprehensive E2E tests (70+ test cases) and unit tests
- Update OpenAPI specs and TypeScript SDK
No breaking changes - only additions to existing API.
* feat(preferences): enable all duplicate sync settings by default
* chore: clean up
* chore: clean up
* refactor: rename & clean up
* fix: preference upgrade
* chore: linting
* refactor(e2e): use updateAssets API for setAssetDuplicateId
* fix: visibility sync logic in duplicate resolution
* fix(duplicate): write description to exifUpdate
Previously the duplicate resolution populated assetUpdate.description even
though description belongs to exif info.
* fix(duplicate): remove redundant updateLockedColumns wrapper
updateAllExif already computes lockedProperties via distinctLocked
using Object.keys(options). The wrapper added a lockedProperties key
to the options object, causing the spurious string 'lockedProperties'
to be stored in the lockedProperties array.
* fix(duplicate): write merged tags to asset_exif to survive metadata re-extraction
During duplicate resolution, replaceAssetTags correctly wrote merged tag
IDs to the tag_asset table, but never updated asset_exif.tags or locked
the tags property. The subsequent SidecarWrite → AssetExtractMetadata
chain calls applyTagList, which destructively replaces tag_asset rows
with whatever is in asset_exif.tags — still the original per-asset tags,
not the merged set.
Write merged tag values to asset_exif.tags via updateAllExif (which also
locks the property via distinctLocked), and queue SidecarWrite when tags
change so they persist to the sidecar file.
* docs(duplicates): clarify location and tag sync behavior
* refactor(duplicate): remove sync settings, always sync all metadata on resolve
Remove DuplicateSyncSettingsDto and the per-field sync toggles
(albums, favorites, rating, description, visibility, location, tags).
Duplicate resolution now unconditionally syncs all metadata from
trashed assets to kept assets.
- Remove DuplicateSyncSettingsDto and settings field from DuplicateResolveDto
- Update DuplicateService to always run all sync logic without conditionals
- Delete DuplicateSettingsModal.svelte and settings gear button from UI
- Remove DuplicateSettings type and duplicateSettings persisted store
- Update unit and e2e tests to remove settings from resolve requests
* docs: update duplicates utility to reflect automatic metadata sync
* docs(web): replace duplicates info modal with link to documentation
* chore: clean up
* fix: add missing type cast to jsonAgg in duplicate repository getAll
* fix: skip persisting rating=0 in duplicate merge to avoid unnecessary sidecar write
---------
Co-authored-by: Toni <51962051+EinToni@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* fix(server): prevent album shared link from breaking after uploads
* update test
* add withSharedAssets helper
* remove options
* add more helpers
* update selects
* feat: SyncAssetV2
* feat: mobile sync handling
* feat: request correct sync object based on server version
* fix: mobile queries
* chore: sync sql
* fix: test
* chore: switch to mapper
* fix: sql sync
* fix: download the edited version when downloading multiple photos
* test: update tests
* chore: clean up
---------
Co-authored-by: Jason Rasmussen <jason@rasm.me>
* feat: workflow ui
* wip
* wip
* wip
* pr feedback
* refactor: picker field
* use showDialog directly
* better test
* refactor step selection modal
* move enable button to info form
* use for Props
* pr feedback
* refactor ActionItem
* refactor ActionItem
* more refactor
* fix: new schemaformfield has value of the same type
* chore: clean up
* Test memory creation in advance
Use year 2035 to make sure it's in the future of current time of a test run
* Use target year instead of current year when fetching assets during memory creation
This fixes an edge case of creating memories in advance when target year is
different from current year.
Example: job runs on 2025-12-31 (current year is 2025) and creates memories
to be shown on 2026-01-01 (target year is 2026). If using _current_ year in
calculation then range of years is capped at (2025 - 1 = 2024) thus excluding
2025-01-01 from created memories. With _target_ year it is (2026 - 1 = 2025),
so 2025-01-01 will be included in memories.
* Update sql queries
* feat: add OCR functionality and related configurations
* chore: update labeler configuration for machine learning files
* feat(i18n): enhance OCR model descriptions and add orientation classification and unwarping features
* chore: update Dockerfile to include ccache for improved build performance
* feat(ocr): enhance OCR model configuration with orientation classification and unwarping options, update PaddleOCR integration, and improve response structure
* refactor(ocr): remove OCR_CLEANUP job from enum and type definitions
* refactor(ocr): remove obsolete OCR entity and migration files, and update asset job status and schema to accommodate new OCR table structure
* refactor(ocr): update OCR schema and response structure to use individual coordinates instead of bounding box, and adjust related service and repository files
* feat: enhance OCR configuration and functionality
- Updated OCR settings to include minimum detection box score, minimum detection score, and minimum recognition score.
- Refactored PaddleOCRecognizer to utilize new scoring parameters.
- Introduced new database tables for asset OCR data and search functionality.
- Modified related services and repositories to support the new OCR features.
- Updated translations for improved clarity in settings UI.
* sql changes
* use rapidocr
* change dto
* update web
* update lock
* update api
* store positions as normalized floats
* match column order in db
* update admin ui settings descriptions
fix max resolution key
set min threshold to 0.1
fix bind
* apply config correctly, adjust defaults
* unnecessary model type
* unnecessary sources
* fix(ocr): switch RapidOCR lang type from LangDet to LangRec
* fix(ocr): expose lang_type (LangRec.CH) and font_path on OcrOptions for RapidOCR
* fix(ocr): make OCR text search case- and accent-insensitive using ILIKE + unaccent
* fix(ocr): add OCR search fields
* fix: Add OCR database migration and update ML prediction logic.
* trigrams are already case insensitive
* add tests
* format
* update migrations
* wrong uuid function
* linting
* maybe fix medium tests
* formatting
* fix weblate check
* openapi
* sql
* minor fixes
* maybe fix medium tests part 2
* passing medium tests
* format web
* readd sql
* format dart
* disabled in e2e
* chore: translation ordering
---------
Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>