Skip to content

Commit 2386219

Browse files
Merge branch 'main' into main
2 parents a2389a6 + 365abd8 commit 2386219

File tree

7 files changed

+143
-98
lines changed

7 files changed

+143
-98
lines changed

docs/docs/install/config-file.md

Lines changed: 129 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -16,78 +16,112 @@ The default configuration looks like this:
1616

1717
```json
1818
{
19+
"backup": {
20+
"database": {
21+
"cronExpression": "0 02 * * *",
22+
"enabled": true,
23+
"keepLastAmount": 14
24+
}
25+
},
1926
"ffmpeg": {
27+
"accel": "disabled",
28+
"accelDecode": false,
29+
"acceptedAudioCodecs": ["aac", "mp3", "libopus"],
30+
"acceptedContainers": ["mov", "ogg", "webm"],
31+
"acceptedVideoCodecs": ["h264"],
32+
"bframes": -1,
33+
"cqMode": "auto",
2034
"crf": 23,
21-
"threads": 0,
35+
"gopSize": 0,
36+
"maxBitrate": "0",
37+
"preferredHwDevice": "auto",
2238
"preset": "ultrafast",
23-
"targetVideoCodec": "h264",
24-
"acceptedVideoCodecs": ["h264"],
39+
"refs": 0,
2540
"targetAudioCodec": "aac",
26-
"acceptedAudioCodecs": ["aac", "mp3", "libopus", "pcm_s16le"],
27-
"acceptedContainers": ["mov", "ogg", "webm"],
2841
"targetResolution": "720",
29-
"maxBitrate": "0",
30-
"bframes": -1,
31-
"refs": 0,
32-
"gopSize": 0,
42+
"targetVideoCodec": "h264",
3343
"temporalAQ": false,
34-
"cqMode": "auto",
35-
"twoPass": false,
36-
"preferredHwDevice": "auto",
37-
"transcode": "required",
44+
"threads": 0,
3845
"tonemap": "hable",
39-
"accel": "disabled",
40-
"accelDecode": false
46+
"transcode": "required",
47+
"twoPass": false
4148
},
42-
"backup": {
43-
"database": {
44-
"enabled": true,
45-
"cronExpression": "0 02 * * *",
46-
"keepLastAmount": 14
49+
"image": {
50+
"colorspace": "p3",
51+
"extractEmbedded": false,
52+
"fullsize": {
53+
"enabled": false,
54+
"format": "jpeg",
55+
"quality": 80
56+
},
57+
"preview": {
58+
"format": "jpeg",
59+
"quality": 80,
60+
"size": 1440
61+
},
62+
"thumbnail": {
63+
"format": "webp",
64+
"quality": 80,
65+
"size": 250
4766
}
4867
},
4968
"job": {
5069
"backgroundTask": {
5170
"concurrency": 5
5271
},
53-
"smartSearch": {
72+
"faceDetection": {
5473
"concurrency": 2
5574
},
56-
"metadataExtraction": {
75+
"library": {
5776
"concurrency": 5
5877
},
59-
"faceDetection": {
60-
"concurrency": 2
78+
"metadataExtraction": {
79+
"concurrency": 5
6180
},
62-
"search": {
81+
"migration": {
6382
"concurrency": 5
6483
},
65-
"sidecar": {
84+
"notifications": {
6685
"concurrency": 5
6786
},
68-
"library": {
87+
"ocr": {
88+
"concurrency": 1
89+
},
90+
"search": {
6991
"concurrency": 5
7092
},
71-
"migration": {
93+
"sidecar": {
7294
"concurrency": 5
7395
},
96+
"smartSearch": {
97+
"concurrency": 2
98+
},
7499
"thumbnailGeneration": {
75100
"concurrency": 3
76101
},
77102
"videoConversion": {
78103
"concurrency": 1
104+
}
105+
},
106+
"library": {
107+
"scan": {
108+
"cronExpression": "0 0 * * *",
109+
"enabled": true
79110
},
80-
"notifications": {
81-
"concurrency": 5
111+
"watch": {
112+
"enabled": false
82113
}
83114
},
84115
"logging": {
85116
"enabled": true,
86117
"level": "log"
87118
},
88119
"machineLearning": {
89-
"enabled": true,
90-
"urls": ["http://immich-machine-learning:3003"],
120+
"availabilityChecks": {
121+
"enabled": true,
122+
"interval": 30000,
123+
"timeout": 2000
124+
},
91125
"clip": {
92126
"enabled": true,
93127
"modelName": "ViT-B-32__openai"
@@ -96,27 +130,59 @@ The default configuration looks like this:
96130
"enabled": true,
97131
"maxDistance": 0.01
98132
},
133+
"enabled": true,
99134
"facialRecognition": {
100135
"enabled": true,
101-
"modelName": "buffalo_l",
102-
"minScore": 0.7,
103136
"maxDistance": 0.5,
104-
"minFaces": 3
105-
}
137+
"minFaces": 3,
138+
"minScore": 0.7,
139+
"modelName": "buffalo_l"
140+
},
141+
"ocr": {
142+
"enabled": true,
143+
"maxResolution": 736,
144+
"minDetectionScore": 0.5,
145+
"minRecognitionScore": 0.8,
146+
"modelName": "PP-OCRv5_mobile"
147+
},
148+
"urls": ["http://immich-machine-learning:3003"]
106149
},
107150
"map": {
151+
"darkStyle": "https://tiles.immich.cloud/v1/style/dark.json",
108152
"enabled": true,
109-
"lightStyle": "https://tiles.immich.cloud/v1/style/light.json",
110-
"darkStyle": "https://tiles.immich.cloud/v1/style/dark.json"
111-
},
112-
"reverseGeocoding": {
113-
"enabled": true
153+
"lightStyle": "https://tiles.immich.cloud/v1/style/light.json"
114154
},
115155
"metadata": {
116156
"faces": {
117157
"import": false
118158
}
119159
},
160+
"newVersionCheck": {
161+
"enabled": true
162+
},
163+
"nightlyTasks": {
164+
"clusterNewFaces": true,
165+
"databaseCleanup": true,
166+
"generateMemories": true,
167+
"missingThumbnails": true,
168+
"startTime": "00:00",
169+
"syncQuotaUsage": true
170+
},
171+
"notifications": {
172+
"smtp": {
173+
"enabled": false,
174+
"from": "",
175+
"replyTo": "",
176+
"transport": {
177+
"host": "",
178+
"ignoreCert": false,
179+
"password": "",
180+
"port": 587,
181+
"secure": false,
182+
"username": ""
183+
}
184+
}
185+
},
120186
"oauth": {
121187
"autoLaunch": false,
122188
"autoRegister": true,
@@ -128,70 +194,44 @@ The default configuration looks like this:
128194
"issuerUrl": "",
129195
"mobileOverrideEnabled": false,
130196
"mobileRedirectUri": "",
197+
"profileSigningAlgorithm": "none",
198+
"roleClaim": "immich_role",
131199
"scope": "openid email profile",
132200
"signingAlgorithm": "RS256",
133-
"profileSigningAlgorithm": "none",
134201
"storageLabelClaim": "preferred_username",
135-
"storageQuotaClaim": "immich_quota"
202+
"storageQuotaClaim": "immich_quota",
203+
"timeout": 30000,
204+
"tokenEndpointAuthMethod": "client_secret_post"
136205
},
137206
"passwordLogin": {
138207
"enabled": true
139208
},
209+
"reverseGeocoding": {
210+
"enabled": true
211+
},
212+
"server": {
213+
"externalDomain": "",
214+
"loginPageMessage": "",
215+
"publicUsers": true
216+
},
140217
"storageTemplate": {
141218
"enabled": false,
142219
"hashVerificationEnabled": true,
143220
"template": "{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}"
144221
},
145-
"image": {
146-
"thumbnail": {
147-
"format": "webp",
148-
"size": 250,
149-
"quality": 80
150-
},
151-
"preview": {
152-
"format": "jpeg",
153-
"size": 1440,
154-
"quality": 80
155-
},
156-
"colorspace": "p3",
157-
"extractEmbedded": false
158-
},
159-
"newVersionCheck": {
160-
"enabled": true
161-
},
162-
"trash": {
163-
"enabled": true,
164-
"days": 30
222+
"templates": {
223+
"email": {
224+
"albumInviteTemplate": "",
225+
"albumUpdateTemplate": "",
226+
"welcomeTemplate": ""
227+
}
165228
},
166229
"theme": {
167230
"customCss": ""
168231
},
169-
"library": {
170-
"scan": {
171-
"enabled": true,
172-
"cronExpression": "0 0 * * *"
173-
},
174-
"watch": {
175-
"enabled": false
176-
}
177-
},
178-
"server": {
179-
"externalDomain": "",
180-
"loginPageMessage": ""
181-
},
182-
"notifications": {
183-
"smtp": {
184-
"enabled": false,
185-
"from": "",
186-
"replyTo": "",
187-
"transport": {
188-
"ignoreCert": false,
189-
"host": "",
190-
"port": 587,
191-
"username": "",
192-
"password": ""
193-
}
194-
}
232+
"trash": {
233+
"days": 30,
234+
"enabled": true
195235
},
196236
"user": {
197237
"deleteDelay": 7

mobile/lib/domain/services/background_worker.service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ class BackgroundWorkerBgService extends BackgroundWorkerFlutterApi {
239239
final networkCapabilities = await _ref?.read(connectivityApiProvider).getCapabilities() ?? [];
240240
return _ref
241241
?.read(uploadServiceProvider)
242-
.startBackupWithHttpClient(currentUser.id, networkCapabilities.hasWifi, _cancellationToken);
242+
.startBackupWithHttpClient(currentUser.id, networkCapabilities.isUnmetered, _cancellationToken);
243243
},
244244
(error, stack) {
245245
dPrint(() => "Error in backup zone $error, $stack");

mobile/lib/pages/common/splash_screen.page.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class SplashScreenPageState extends ConsumerState<SplashScreenPage> {
6565
if (Store.isBetaTimelineEnabled) {
6666
bool syncSuccess = false;
6767
await Future.wait([
68-
backgroundManager.syncLocal(),
68+
backgroundManager.syncLocal(full: true),
6969
backgroundManager.syncRemote().then((success) => syncSuccess = success),
7070
]);
7171

readme_i18n/README_ru_RU.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
| LivePhoto/MotionPhoto воспроизведение и бекап | Да | Да |
9595
| Отображение 360° изображений | Нет | Да |
9696
| Настраиваемая структура хранилища | Да | Да |
97-
| Общий доступ к контенту | Нет | Да |
97+
| Общий доступ к контенту | Да | Да |
9898
| Архив и избранное | Да | Да |
9999
| Мировая карта | Да | Да |
100100
| Совместное использование | Да | Да |
@@ -104,7 +104,7 @@
104104
| Галереи только для просмотра | Да | Да |
105105
| Коллажи | Да | Да |
106106
| Метки (теги) | Нет | Да |
107-
| Просмотр папкой | Нет | Да |
107+
| Просмотр папкой | Да | Да |
108108

109109
## Перевод
110110

web/src/lib/modals/timezone-utils.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,14 @@ export function getModernOffsetForZoneAndDate(
7070

7171
function zoneOptionForDate(zone: string, date: string) {
7272
const { offsetMinutes, offsetFormat: zoneOffsetAtDate } = getModernOffsetForZoneAndDate(zone, date);
73-
// For validity, we still need to check if the exact date/time exists in the *original* timezone (for gaps/overlaps).
74-
const dateForValidity = DateTime.fromISO(date, { zone });
75-
const valid = dateForValidity.isValid && date === dateForValidity.toFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
73+
// For validity, we still need to check if the exact date/time exists in the *original* timezone.
74+
// Use the fact that in DST gaps Luxon advances the missing time by an hour.
75+
// Ignore milliseconds:
76+
// - milliseconds are not relevant for TZ calculations
77+
// - browsers strip insignificant .000 making string comparison with milliseconds more fragile.
78+
const dateInTimezone = DateTime.fromISO(date, { zone });
79+
const exists = date.replace(/\.\d+/, '') === dateInTimezone.toFormat("yyyy-MM-dd'T'HH:mm:ss");
80+
const valid = dateInTimezone.isValid && exists;
7681
return {
7782
value: zone,
7883
offsetMinutes,

web/src/lib/utils/actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const deleteAssets = async (
3838
props: {
3939
title: $t('success'),
4040
description: force
41-
? $t('assets_permanently_deleted_count')
41+
? $t('assets_permanently_deleted_count', { values: { count: ids.length } })
4242
: $t('assets_trashed_count', { values: { count: ids.length } }),
4343
color: 'success',
4444
button:

web/src/routes/(user)/trash/[[photos=photos]]/[[assetId=id]]/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
</HStack>
104104
{/snippet}
105105

106-
<Timeline enableRouting={true} {options} {assetInteraction} onEscape={handleEscape}>
106+
<Timeline enableRouting={true} bind:timelineManager {options} {assetInteraction} onEscape={handleEscape}>
107107
<p class="font-medium text-gray-500/60 dark:text-gray-300/60 p-4">
108108
{$t('trashed_items_will_be_permanently_deleted_after', { values: { days: $serverConfig.trashDays } })}
109109
</p>

0 commit comments

Comments
 (0)