340 lines
13 KiB
Markdown
340 lines
13 KiB
Markdown
# Backup & Upload
|
|
|
|
This document describes the photo/video backup functionality, including foreground and background uploads.
|
|
|
|
## Backup Overview
|
|
|
|
The backup system automatically uploads photos and videos from the device to the server:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Backup Flow │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Device Photos → Backup Service → Server │
|
|
│ │
|
|
│ 1. Select albums to backup │
|
|
│ 2. Find new/changed assets │
|
|
│ 3. Check for duplicates (hash) │
|
|
│ 4. Upload assets │
|
|
│ 5. Update local database │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Backup Configuration
|
|
|
|
### Backup Controller Screen
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ ← Backup │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Backup Status │
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
│ │ ✓ Backup Complete │ │
|
|
│ │ 1,234 of 1,234 backed up │ │
|
|
│ │ Last backup: 2 hours ago │ │
|
|
│ └─────────────────────────────────────────────────────┘ │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Backup Albums │
|
|
│ [Select albums to backup] │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Excluded Albums │
|
|
│ [Select albums to exclude] │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ Settings │
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
│ │ Background Backup [Toggle: ON] │ │
|
|
│ │ Use Wi-Fi only [Toggle: ON] │ │
|
|
│ │ Require charging [Toggle: OFF] │ │
|
|
│ │ Ignore iCloud assets [Toggle: OFF] │ │
|
|
│ └─────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Album Selection
|
|
|
|
### Backup Albums
|
|
- Select which device albums to back up
|
|
- "Recents" includes all photos
|
|
- Individual albums for selective backup
|
|
|
|
### Excluded Albums
|
|
- Exclude specific albums
|
|
- Useful for Screenshots, WhatsApp Images, etc.
|
|
- Takes precedence over selected albums
|
|
|
|
### Album Selection Logic
|
|
```
|
|
Backup Candidates = Selected Albums - Excluded Albums
|
|
|
|
If "Recents" selected (Android):
|
|
- Back up all device photos
|
|
- Individual album folders tracked for sync
|
|
|
|
If "Recents" selected (iOS):
|
|
- Use "All Photos" album
|
|
- Check against excluded albums per asset
|
|
```
|
|
|
|
## Backup Process
|
|
|
|
### Step 1: Build Upload Candidates
|
|
```
|
|
1. Get selected backup albums
|
|
2. Get excluded backup albums
|
|
3. For each selected album:
|
|
a. Check if album modified since last backup
|
|
b. Get assets newer than last backup time
|
|
c. Add album name to asset metadata
|
|
4. Remove assets from excluded albums
|
|
```
|
|
|
|
### Step 2: Remove Already Uploaded
|
|
```
|
|
1. Check local duplicates database
|
|
2. Call server to check existing assets
|
|
|
|
POST /assets/exist
|
|
Body:
|
|
{
|
|
"deviceAssetIds": ["local-id-1", "local-id-2", ...],
|
|
"deviceId": "device-uuid"
|
|
}
|
|
|
|
Response:
|
|
{
|
|
"existingIds": ["local-id-1"]
|
|
}
|
|
```
|
|
|
|
### Step 3: Upload Assets
|
|
For each asset:
|
|
```
|
|
1. Get original file from device
|
|
2. If live photo, also get video component
|
|
3. Calculate upload metadata
|
|
4. Upload via multipart form
|
|
|
|
POST /assets
|
|
Content-Type: multipart/form-data
|
|
|
|
Fields:
|
|
- deviceAssetId: local ID
|
|
- deviceId: device UUID
|
|
- fileCreatedAt: creation timestamp
|
|
- fileModifiedAt: modification timestamp
|
|
- isFavorite: boolean
|
|
- duration: video duration
|
|
|
|
Files:
|
|
- assetData: the file
|
|
- livePhotoData: motion video (if applicable)
|
|
```
|
|
|
|
### Step 4: Handle Response
|
|
```
|
|
200 OK: Asset already exists (duplicate)
|
|
201 Created: Asset uploaded successfully
|
|
|
|
Response:
|
|
{
|
|
"id": "remote-asset-uuid",
|
|
"deviceAssetId": "local-id",
|
|
...
|
|
}
|
|
```
|
|
|
|
## Upload Progress Tracking
|
|
|
|
### Progress Model
|
|
```
|
|
CurrentUploadAsset {
|
|
id: String // Local asset ID
|
|
fileName: String // File name
|
|
fileType: String // IMAGE, VIDEO, etc.
|
|
fileSize: Integer // Bytes
|
|
fileCreatedAt: DateTime
|
|
iCloudAsset: Boolean // Downloading from iCloud
|
|
}
|
|
|
|
UploadProgress {
|
|
bytesUploaded: Integer
|
|
totalBytes: Integer
|
|
percentage: Double
|
|
}
|
|
```
|
|
|
|
### Progress UI
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Uploading... │
|
|
│ │
|
|
│ IMG_1234.jpg │
|
|
│ [████████████░░░░░░░░░░░░░░░░░] 45% │
|
|
│ │
|
|
│ 12 of 50 • 2.4 MB / 5.1 MB │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Background Backup
|
|
|
|
### Platform Differences
|
|
|
|
**Android:**
|
|
- Uses WorkManager for scheduling
|
|
- Triggers on content changes
|
|
- Requires battery optimization disabled
|
|
|
|
**iOS:**
|
|
- Uses Background App Refresh
|
|
- Limited execution time
|
|
- BGProcessingTask for longer uploads
|
|
|
|
### Background Service Configuration
|
|
```
|
|
RequireUnmetered: true/false // Wi-Fi only
|
|
RequireCharging: true/false // Charging only
|
|
TriggerDelay: 5000ms // Minimum delay
|
|
MaxDelay: 50000ms // Maximum delay
|
|
```
|
|
|
|
### Background Notification
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Immich │
|
|
│ Uploading 12/50 photos... │
|
|
│ [Progress bar] │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Background Process Flow
|
|
```
|
|
1. System triggers background task
|
|
2. Acquire lock (prevent concurrent runs)
|
|
3. Load translations
|
|
4. Initialize database
|
|
5. Set API endpoint
|
|
6. Get selected/excluded albums
|
|
7. Run backup process
|
|
8. Update last backup timestamps
|
|
9. Release lock
|
|
```
|
|
|
|
## iCloud Assets (iOS)
|
|
|
|
### Handling iCloud Photos
|
|
1. Check if asset is locally available
|
|
2. If not, option to download from iCloud
|
|
3. Show progress during download
|
|
4. Upload after download complete
|
|
|
|
### Settings
|
|
- `ignoreIcloudAssets`: Skip assets not on device
|
|
|
|
## Album Sync Feature
|
|
|
|
### Purpose
|
|
Automatically organize uploads into server albums matching device album names.
|
|
|
|
### How It Works
|
|
1. Asset uploaded with album names in metadata
|
|
2. After upload, check for matching albums
|
|
3. Create album if doesn't exist
|
|
4. Add asset to album
|
|
|
|
### API
|
|
```
|
|
POST /albums/{albumName}/assets
|
|
Body:
|
|
{
|
|
"assetIds": ["uploaded-asset-id"]
|
|
}
|
|
```
|
|
|
|
## Duplicate Detection
|
|
|
|
### Hash-Based Detection
|
|
1. Calculate file hash (checksum)
|
|
2. Store in local duplicates database
|
|
3. Skip uploads for known duplicates
|
|
|
|
### Server-Side Check
|
|
```
|
|
POST /assets/exist
|
|
|
|
Checks if assets already on server by device ID + local ID
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Retry Logic
|
|
- Failed uploads retry automatically
|
|
- Exponential backoff
|
|
- Maximum retry attempts
|
|
|
|
### Error Notifications
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ ⚠️ Upload Failed │
|
|
│ IMG_5678.jpg could not be uploaded │
|
|
│ Error: Network connection lost │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Common Errors
|
|
| Error | Cause | Action |
|
|
|-------|-------|--------|
|
|
| Network error | No connection | Retry when online |
|
|
| Quota exceeded | Storage full | Stop backup, notify user |
|
|
| File not found | Asset deleted | Skip asset |
|
|
| Permission denied | Gallery access lost | Request permission |
|
|
|
|
## Failed Uploads Screen
|
|
|
|
### Layout
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ ← Failed Uploads │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ 5 uploads failed │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
│ │ 📷 IMG_1234.jpg │ │
|
|
│ │ Network timeout │ │
|
|
│ │ [Retry] │ │
|
|
│ └─────────────────────────────────────────────────────┘ │
|
|
│ ... │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ [Retry All] │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Backup Statistics
|
|
|
|
### Tracked Metrics
|
|
- Total assets to backup
|
|
- Successfully uploaded
|
|
- Failed uploads
|
|
- Duplicate (already on server)
|
|
- Last backup timestamp
|
|
|
|
### Storage Usage
|
|
```
|
|
GET /users/me
|
|
|
|
Response includes:
|
|
{
|
|
"quotaUsageInBytes": 1234567890,
|
|
"quotaSizeInBytes": 10737418240
|
|
}
|
|
```
|
|
|
|
## Cellular Data Settings
|
|
|
|
### Options
|
|
- `useCellularForUploadPhotos`: Allow photo upload on cellular
|
|
- `useCellularForUploadVideos`: Allow video upload on cellular
|
|
|
|
---
|
|
|
|
[Previous: Gallery Viewer](./gallery-viewer.md) | [Next: Download](./download.md)
|