From c81bb2b70a368b7e900b72072d94b1daf5675f5a Mon Sep 17 00:00:00 2001
From: abhi-chakrab <112197661+abhi-chakrab@users.noreply.github.com>
Date: Mon, 14 Aug 2023 08:39:47 -0600
Subject: [PATCH 01/22] doc: update bulk-upload.md (#3673)
* Update bulk-upload.md
This PR is to add a small clarification to use the same volumes for read only gallery in the docker command. Since the current docker commands refer to "/import" volume mounts that caused some confusion to me.
* chore: formatting
---------
Co-authored-by: Jason Rasmussen
---
docs/docs/features/bulk-upload.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/docs/docs/features/bulk-upload.md b/docs/docs/features/bulk-upload.md
index 2e730ea1c..c0d815182 100644
--- a/docs/docs/features/bulk-upload.md
+++ b/docs/docs/features/bulk-upload.md
@@ -170,4 +170,10 @@ The proper command for above would be as shown below. You should have access to
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive /path/to/media --import
```
+If you are running the import using the docker command, please note that the volumes should point to the `/path/to/media` exactly on the environment the CLI command is being run on
+
+```
+docker run -it --rm -v "/path/to/media:/path/to/media" ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive /path/to/media --import
+```
+
:::
From f55c80eadf113814a3f780e6a646c5abd68b0cee Mon Sep 17 00:00:00 2001
From: BMaster <6114149+bmaster001@users.noreply.github.com>
Date: Mon, 14 Aug 2023 16:50:59 +0200
Subject: [PATCH 02/22] doc: how move assets,albums,persons from one account to
another (#3652)
* Update FAQ.md
Added an item to document what can be done to move photos, albums and persons from one account to another,
* Update FAQ.md
typo in the numbering
* Update FAQ.md
add an 'advanced operation' warning
* Update FAQ.md
Typos
* chore: format
* chore: cleanup syntax codeblock
---------
Co-authored-by: Jason Rasmussen
---
docs/docs/FAQ.md | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/docs/docs/FAQ.md b/docs/docs/FAQ.md
index 46be818a5..c0aff99ab 100644
--- a/docs/docs/FAQ.md
+++ b/docs/docs/FAQ.md
@@ -99,3 +99,29 @@ After removing the containers and volumes, the **Files** can be cleaned up (if n
### Why iOS app shows duplicate photos on the timeline while the web doesn't?
If you are using `My Photo Stream`, the Photos app temporarily creates duplicates of photos taken in the last 30 days. These photos are included in the `Recents` album and thus shown up twice. To fix this, you can disable `My Photo Stream` in the native Photos app or choose a different album in the backup screen in Immich.
+
+### How can I move all data (photos, persons, albums) from one user to another?
+
+This requires some database queries. You can do this on the command line (in the PostgreSQL container using the psql command), or you can add for example an [Adminer](https://www.adminer.org/) container to the `docker-compose.yml` file, so that you can use a web-interface.
+
+:::warning
+This is an advanced operation. If you can't to do it with the steps described here, this is not for you.
+:::
+
+1. **MAKE A BACKUP** - See [backup and restore](/docs/administration/backup-and-restore.md).
+2. Find the id of both the 'source' and the 'destination' user (it's the id column in the users table)
+3. Three tables need to be updated:
+
+ ```sql
+ // reassign albums
+ update albums set "ownerId" = '' where "ownerId" = '';
+
+ // reassign people
+ update person set "ownerId" = '' where "ownerId" = '';
+
+ // reassign assets
+ update assets set "ownerId" = '' where "ownerId" = ''
+ and checksum not in (select checksum from assets where "ownerId" = '');
+ ```
+
+4. There might be left-over assets in the 'source' user's library if they are skipped by the last query because of duplicate checksums. These are probably duplicates anyway, and can probably be removed.
From b1b215f0836e575162b5183d63cdf4ce5e3c1140 Mon Sep 17 00:00:00 2001
From: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Date: Mon, 14 Aug 2023 21:39:26 +0530
Subject: [PATCH 03/22] fix(server): sort un-named faces in query (#3662)
---
server/src/domain/person/person.service.ts | 4 +---
server/src/infra/repositories/person.repository.ts | 1 +
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/server/src/domain/person/person.service.ts b/server/src/domain/person/person.service.ts
index 0758b5f2c..0f66447f1 100644
--- a/server/src/domain/person/person.service.ts
+++ b/server/src/domain/person/person.service.ts
@@ -27,10 +27,8 @@ export class PersonService {
async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise {
const people = await this.repository.getAll(authUser.id, { minimumFaceCount: 1 });
- const named = people.filter((person) => !!person.name);
- const unnamed = people.filter((person) => !person.name);
- const persons: PersonResponseDto[] = [...named, ...unnamed]
+ const persons: PersonResponseDto[] = people
// with thumbnails
.filter((person) => !!person.thumbnailPath)
.map((person) => mapPerson(person));
diff --git a/server/src/infra/repositories/person.repository.ts b/server/src/infra/repositories/person.repository.ts
index db4ccff06..859548436 100644
--- a/server/src/infra/repositories/person.repository.ts
+++ b/server/src/infra/repositories/person.repository.ts
@@ -56,6 +56,7 @@ export class PersonRepository implements IPersonRepository {
.leftJoin('person.faces', 'face')
.where('person.ownerId = :userId', { userId })
.orderBy('COUNT(face.assetId)', 'DESC')
+ .addOrderBy("NULLIF(person.name, '')", 'ASC', 'NULLS LAST')
.having('COUNT(face.assetId) >= :faces', { faces: options?.minimumFaceCount || 1 })
.groupBy('person.id')
.limit(500)
From 0d80ae3a91b09d66a837ed58b160e2193baeaa98 Mon Sep 17 00:00:00 2001
From: Alex
Date: Mon, 14 Aug 2023 12:52:06 -0500
Subject: [PATCH 04/22] fix(mobile): make user.memoryEnable optional (#3680)
* chore(server): avoid breaking changes
* generate api
* mobile app
---
cli/src/api/open-api/api.ts | 2 +-
mobile/lib/modules/home/views/home_page.dart | 9 +++++----
mobile/lib/shared/models/user.dart | 2 +-
mobile/openapi/doc/UserResponseDto.md | 2 +-
.../openapi/lib/model/user_response_dto.dart | 19 ++++++++++++++-----
server/immich-openapi-specs.json | 3 +--
.../user/response-dto/user-response.dto.ts | 2 +-
web/src/api/open-api/api.ts | 2 +-
8 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts
index 9cedbdf2c..e8662175a 100644
--- a/cli/src/api/open-api/api.ts
+++ b/cli/src/api/open-api/api.ts
@@ -3159,7 +3159,7 @@ export interface UserResponseDto {
* @type {boolean}
* @memberof UserResponseDto
*/
- 'memoriesEnabled': boolean;
+ 'memoriesEnabled'?: boolean;
/**
*
* @type {string}
diff --git a/mobile/lib/modules/home/views/home_page.dart b/mobile/lib/modules/home/views/home_page.dart
index a628df9bd..c3226f228 100644
--- a/mobile/lib/modules/home/views/home_page.dart
+++ b/mobile/lib/modules/home/views/home_page.dart
@@ -342,10 +342,11 @@ class HomePage extends HookConsumerWidget {
listener: selectionListener,
selectionActive: selectionEnabledHook.value,
onRefresh: refreshAssets,
- topWidget:
- (currentUser != null && currentUser.memoryEnabled)
- ? const MemoryLane()
- : const SizedBox(),
+ topWidget: (currentUser != null &&
+ currentUser.memoryEnabled != null &&
+ currentUser.memoryEnabled!)
+ ? const MemoryLane()
+ : const SizedBox(),
),
error: (error, _) => Center(child: Text(error.toString())),
loading: buildLoadingIndicator,
diff --git a/mobile/lib/shared/models/user.dart b/mobile/lib/shared/models/user.dart
index 304150064..df742a154 100644
--- a/mobile/lib/shared/models/user.dart
+++ b/mobile/lib/shared/models/user.dart
@@ -44,7 +44,7 @@ class User {
bool isPartnerSharedWith;
bool isAdmin;
String profileImagePath;
- bool memoryEnabled;
+ bool? memoryEnabled;
@Backlink(to: 'owner')
final IsarLinks albums = IsarLinks();
@Backlink(to: 'sharedUsers')
diff --git a/mobile/openapi/doc/UserResponseDto.md b/mobile/openapi/doc/UserResponseDto.md
index 6455c12d0..b6e42b33e 100644
--- a/mobile/openapi/doc/UserResponseDto.md
+++ b/mobile/openapi/doc/UserResponseDto.md
@@ -16,7 +16,7 @@ Name | Type | Description | Notes
**id** | **String** | |
**isAdmin** | **bool** | |
**lastName** | **String** | |
-**memoriesEnabled** | **bool** | |
+**memoriesEnabled** | **bool** | | [optional]
**oauthId** | **String** | |
**profileImagePath** | **String** | |
**shouldChangePassword** | **bool** | |
diff --git a/mobile/openapi/lib/model/user_response_dto.dart b/mobile/openapi/lib/model/user_response_dto.dart
index 5ecc26b49..488c9aafd 100644
--- a/mobile/openapi/lib/model/user_response_dto.dart
+++ b/mobile/openapi/lib/model/user_response_dto.dart
@@ -21,7 +21,7 @@ class UserResponseDto {
required this.id,
required this.isAdmin,
required this.lastName,
- required this.memoriesEnabled,
+ this.memoriesEnabled,
required this.oauthId,
required this.profileImagePath,
required this.shouldChangePassword,
@@ -45,7 +45,13 @@ class UserResponseDto {
String lastName;
- bool memoriesEnabled;
+ ///
+ /// Please note: This property should have been non-nullable! Since the specification file
+ /// does not include a default value (using the "default:" property), however, the generated
+ /// source code must fall back to having a nullable type.
+ /// Consider adding a "default:" property in the specification file to hide this note.
+ ///
+ bool? memoriesEnabled;
String oauthId;
@@ -85,7 +91,7 @@ class UserResponseDto {
(id.hashCode) +
(isAdmin.hashCode) +
(lastName.hashCode) +
- (memoriesEnabled.hashCode) +
+ (memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(oauthId.hashCode) +
(profileImagePath.hashCode) +
(shouldChangePassword.hashCode) +
@@ -113,7 +119,11 @@ class UserResponseDto {
json[r'id'] = this.id;
json[r'isAdmin'] = this.isAdmin;
json[r'lastName'] = this.lastName;
+ if (this.memoriesEnabled != null) {
json[r'memoriesEnabled'] = this.memoriesEnabled;
+ } else {
+ // json[r'memoriesEnabled'] = null;
+ }
json[r'oauthId'] = this.oauthId;
json[r'profileImagePath'] = this.profileImagePath;
json[r'shouldChangePassword'] = this.shouldChangePassword;
@@ -142,7 +152,7 @@ class UserResponseDto {
id: mapValueOfType(json, r'id')!,
isAdmin: mapValueOfType(json, r'isAdmin')!,
lastName: mapValueOfType(json, r'lastName')!,
- memoriesEnabled: mapValueOfType(json, r'memoriesEnabled')!,
+ memoriesEnabled: mapValueOfType(json, r'memoriesEnabled'),
oauthId: mapValueOfType(json, r'oauthId')!,
profileImagePath: mapValueOfType(json, r'profileImagePath')!,
shouldChangePassword: mapValueOfType(json, r'shouldChangePassword')!,
@@ -203,7 +213,6 @@ class UserResponseDto {
'id',
'isAdmin',
'lastName',
- 'memoriesEnabled',
'oauthId',
'profileImagePath',
'shouldChangePassword',
diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json
index d5504ba32..a60fcbd54 100644
--- a/server/immich-openapi-specs.json
+++ b/server/immich-openapi-specs.json
@@ -7152,8 +7152,7 @@
"createdAt",
"deletedAt",
"updatedAt",
- "oauthId",
- "memoriesEnabled"
+ "oauthId"
],
"type": "object"
},
diff --git a/server/src/domain/user/response-dto/user-response.dto.ts b/server/src/domain/user/response-dto/user-response.dto.ts
index 9a3372ad5..59a387de1 100644
--- a/server/src/domain/user/response-dto/user-response.dto.ts
+++ b/server/src/domain/user/response-dto/user-response.dto.ts
@@ -14,7 +14,7 @@ export class UserResponseDto {
deletedAt!: Date | null;
updatedAt!: Date;
oauthId!: string;
- memoriesEnabled!: boolean;
+ memoriesEnabled?: boolean;
}
export function mapUser(entity: UserEntity): UserResponseDto {
diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts
index 9cedbdf2c..e8662175a 100644
--- a/web/src/api/open-api/api.ts
+++ b/web/src/api/open-api/api.ts
@@ -3159,7 +3159,7 @@ export interface UserResponseDto {
* @type {boolean}
* @memberof UserResponseDto
*/
- 'memoriesEnabled': boolean;
+ 'memoriesEnabled'?: boolean;
/**
*
* @type {string}
From 67bac9ff596a9087b5e8476ed2ebc06796f16f4f Mon Sep 17 00:00:00 2001
From: Alex
Date: Mon, 14 Aug 2023 13:16:16 -0500
Subject: [PATCH 05/22] [Localizely] Translations update (#3682)
---
mobile/assets/i18n/ca.json | 11 +++++++++++
mobile/assets/i18n/cs-CZ.json | 11 +++++++++++
mobile/assets/i18n/da-DK.json | 11 +++++++++++
mobile/assets/i18n/de-DE.json | 11 +++++++++++
mobile/assets/i18n/en-US.json | 18 +++++++++---------
mobile/assets/i18n/es-ES.json | 11 +++++++++++
mobile/assets/i18n/es-MX.json | 11 +++++++++++
mobile/assets/i18n/es-PE.json | 11 +++++++++++
mobile/assets/i18n/fi-FI.json | 11 +++++++++++
mobile/assets/i18n/fr-FR.json | 11 +++++++++++
mobile/assets/i18n/hi-IN.json | 11 +++++++++++
mobile/assets/i18n/hu-HU.json | 11 +++++++++++
mobile/assets/i18n/it-IT.json | 11 +++++++++++
mobile/assets/i18n/ja-JP.json | 11 +++++++++++
mobile/assets/i18n/ko-KR.json | 11 +++++++++++
mobile/assets/i18n/lv-LV.json | 11 +++++++++++
mobile/assets/i18n/mn.json | 11 +++++++++++
mobile/assets/i18n/nb-NO.json | 11 +++++++++++
mobile/assets/i18n/nl-NL.json | 11 +++++++++++
mobile/assets/i18n/pl-PL.json | 11 +++++++++++
mobile/assets/i18n/ru-RU.json | 11 +++++++++++
mobile/assets/i18n/sk-SK.json | 11 +++++++++++
mobile/assets/i18n/sr-Cyrl.json | 11 +++++++++++
mobile/assets/i18n/sr-Latn.json | 11 +++++++++++
mobile/assets/i18n/sv-FI.json | 11 +++++++++++
mobile/assets/i18n/sv-SE.json | 11 +++++++++++
mobile/assets/i18n/th-TH.json | 11 +++++++++++
mobile/assets/i18n/uk-UA.json | 11 +++++++++++
mobile/assets/i18n/vi-VN.json | 11 +++++++++++
mobile/assets/i18n/zh-CN.json | 11 +++++++++++
mobile/assets/i18n/zh-Hans.json | 11 +++++++++++
31 files changed, 339 insertions(+), 9 deletions(-)
diff --git a/mobile/assets/i18n/ca.json b/mobile/assets/i18n/ca.json
index 85c82555b..8c8df10d8 100644
--- a/mobile/assets/i18n/ca.json
+++ b/mobile/assets/i18n/ca.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "elements",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Àlbums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Entra",
"login_form_email_hint": "elteu@correu.cat",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/cs-CZ.json b/mobile/assets/i18n/cs-CZ.json
index 74030a62c..782bf64e1 100644
--- a/mobile/assets/i18n/cs-CZ.json
+++ b/mobile/assets/i18n/cs-CZ.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Nahrávaný soubor",
"backup_err_only_album": "Nelze odstranit jediné vybrané album",
"backup_info_card_assets": "položek",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Selhalo",
+ "backup_manual_in_progress": "Zálohování již probíhá. Zkuste znovu později",
+ "backup_manual_success": "Úspěch",
+ "backup_manual_title": "Stav zálohování",
"cache_settings_album_thumbnails": "Náhledy stránek knihovny (položek {})",
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Vytváření časové osy",
"home_page_favorite_err_local": "Zatím není možné zařadit lokální média mezi oblíbená, přeskakuje se",
"home_page_first_time_notice": "Pokud aplikaci používáte poprvé, nezapomeňte si vybrat zálohovaná alba, aby se na časové ose mohly nacházet fotografie a videa z vybraných albech.",
+ "home_page_upload_err_limit": "Lze nahrát nejvýše 30 položek najednou, přeskakuji",
"image_viewer_page_state_provider_download_error": "Chyba stahování",
"image_viewer_page_state_provider_download_success": "Stahování bylo úspěšné",
"library_page_albums": "Alba",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sdílení",
"library_page_sort_created": "Naposledy vytvořené",
"library_page_sort_title": "Podle názvu alba",
+ "login_disabled": "Přihlášení bylo zakázáno",
"login_form_api_exception": "Výjimka API. Zkontrolujte URL serveru a zkuste to znovu.",
"login_form_button_text": "Přihlásit se",
"login_form_email_hint": "tvůjmail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Téma",
"theme_setting_three_stage_loading_subtitle": "Třístupňové načítání může zvýšit výkonnost načítání, ale vede k výrazně vyššímu zatížení sítě.",
"theme_setting_three_stage_loading_title": "Povolení třístupňového načítání",
+ "upload_dialog_cancel": "Zrušit",
+ "upload_dialog_info": "Chcete zálohovat vybrané položky na server?",
+ "upload_dialog_ok": "Zálohovat",
+ "upload_dialog_title": "Zálohovat položku",
"version_announcement_overlay_ack": "Potvrdit",
"version_announcement_overlay_release_notes": "poznámky k vydání",
"version_announcement_overlay_text_1": "Ahoj, je zde nová verze",
diff --git a/mobile/assets/i18n/da-DK.json b/mobile/assets/i18n/da-DK.json
index 7967e52e8..7c69332d0 100644
--- a/mobile/assets/i18n/da-DK.json
+++ b/mobile/assets/i18n/da-DK.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploader filinformation",
"backup_err_only_album": "Kan ikke slette det eneste album",
"backup_info_card_assets": "elementer",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Biblioteksminiaturebilleder ({} elementer)",
"cache_settings_clear_cache_button": "Fjern cache",
"cache_settings_clear_cache_button_title": "Fjern appens cache. Dette vil i stor grad påvirke appens ydeevne indtil cachen er genopbygget.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Bygger tidslinjen",
"home_page_favorite_err_local": "Kan endnu ikke gøre lokale elementer til favoritter. Springer over..",
"home_page_first_time_notice": "Hvis dette er din første gang i appen, bedes du vælge en backup af albummer så tidlinjen kan blive fyldt med billeder og videoer fra albummerne.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Fejl ved download",
"image_viewer_page_state_provider_download_success": "Download succesfuld",
"library_page_albums": "Albummer",
@@ -166,6 +172,7 @@
"library_page_sharing": "Delte",
"library_page_sort_created": "Senest oprettet",
"library_page_sort_title": "Albumtitel",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API-undtagelse. Tjek serverens URL og prøv igen. ",
"login_form_button_text": "Log ind",
"login_form_email_hint": "din-e-mail@e-mail.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Tre-trins indlæsning kan øge ydeevnen, men kan ligeledes føre til højere netværksbelastning",
"theme_setting_three_stage_loading_title": "Slå tre-trins indlæsning til",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Accepter",
"version_announcement_overlay_release_notes": "udgivelsesnoterne",
"version_announcement_overlay_text_1": "Hej ven, der er en ny version af",
diff --git a/mobile/assets/i18n/de-DE.json b/mobile/assets/i18n/de-DE.json
index 559a93646..8b0f95639 100644
--- a/mobile/assets/i18n/de-DE.json
+++ b/mobile/assets/i18n/de-DE.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Informationen",
"backup_err_only_album": "Das einzige Album kann nicht entfernt werden",
"backup_info_card_assets": "Elemente",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Zwischenspeicher löschen",
"cache_settings_clear_cache_button_title": "Löscht den Zwischenspeicher der App. Dies wird die Leistungsfähigkeit der App deutlich einschränken, bis der Zwischenspeicher wieder aufgebaut wurde.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Zeitachse wird erstellt.",
"home_page_favorite_err_local": "Kann lokale Elemente noch nicht favorisieren, überspringe",
"home_page_first_time_notice": "Wenn dies das erste Mal ist dass Du Immich nutzt, stelle bitte sicher, dass mindestens ein Album zur Sicherung ausgewählt ist, sodass die Zeitachse mit Fotos und Videos gefüllt werden kann.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Fehler beim Herunterladen",
"image_viewer_page_state_provider_download_success": "Erfolgreich heruntergeladen",
"library_page_albums": "Alben",
@@ -166,6 +172,7 @@
"library_page_sharing": "Teilen",
"library_page_sort_created": "Zuletzt erstellt",
"library_page_sort_title": "Albumtitel",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API Fehler. Bitte die Serveradresse überprüfen und erneut versuchen.",
"login_form_button_text": "Anmelden",
"login_form_email_hint": "deine@email.de",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Das dreistufige Ladeverfahren kann die Performance beim Laden verbessern, erhöht allerdings den Datenverbrauch deutlich",
"theme_setting_three_stage_loading_title": "Dreistufiges Laden aktivieren",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Ich habe verstanden",
"version_announcement_overlay_release_notes": "Änderungsprotokoll",
"version_announcement_overlay_text_1": "Hallo mein Freund! Es gibt eine neue Version von",
diff --git a/mobile/assets/i18n/en-US.json b/mobile/assets/i18n/en-US.json
index a1a76c843..8aeae7043 100644
--- a/mobile/assets/i18n/en-US.json
+++ b/mobile/assets/i18n/en-US.json
@@ -92,11 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
- "backup_manual_success": "Success",
- "backup_manual_failed": "Failed",
"backup_manual_cancelled": "Cancelled",
- "backup_manual_title": "Upload status",
+ "backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -143,10 +143,6 @@
"delete_dialog_cancel": "Cancel",
"delete_dialog_ok": "Delete",
"delete_dialog_title": "Delete Permanently",
- "upload_dialog_title": "Upload Asset",
- "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
- "upload_dialog_ok": "Upload",
- "upload_dialog_cancel": "Cancel",
"description_input_hint_text": "Add description...",
"description_input_submit_error": "Error updating description, check the log for more details",
"exif_bottom_sheet_description": "Add Description...",
@@ -162,10 +158,10 @@
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
"home_page_archive_err_local": "Can not archive local assets yet, skipping",
- "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -176,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -196,7 +193,6 @@
"login_form_save_login": "Stay logged in",
"login_form_server_empty": "Enter a server URL.",
"login_form_server_error": "Could not connect to server.",
- "login_disabled": "Login has been disabled",
"monthly_title_text_date_format": "MMMM y",
"motion_photos_page_title": "Motion Photos",
"notification_permission_dialog_cancel": "Cancel",
@@ -295,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/es-ES.json b/mobile/assets/i18n/es-ES.json
index 8915a9d8b..6d7e1b022 100644
--- a/mobile/assets/i18n/es-ES.json
+++ b/mobile/assets/i18n/es-ES.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Cargando información del archivo",
"backup_err_only_album": "No se puede eliminar el único álbum",
"backup_info_card_assets": "archivos",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Construyendo la línea de tiempo",
"home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Error de descarga",
"image_viewer_page_state_provider_download_success": "Descarga exitosa",
"library_page_albums": "Álbumes",
@@ -166,6 +172,7 @@
"library_page_sharing": "Compartiendo",
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_title": "Título del álbum",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
"login_form_button_text": "Iniciar Sesión",
"login_form_email_hint": "tucorreo@correo.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "La carga en tres etapas puede aumentar el rendimiento de carga pero provoca un consumo de red significativamente mayor",
"theme_setting_three_stage_loading_title": "Activar carga en tres etapas",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Aceptar",
"version_announcement_overlay_release_notes": "notas de versión",
"version_announcement_overlay_text_1": "Hola amigo, hay una nueva versión de",
diff --git a/mobile/assets/i18n/es-MX.json b/mobile/assets/i18n/es-MX.json
index 6457fbfef..d7564f0b6 100644
--- a/mobile/assets/i18n/es-MX.json
+++ b/mobile/assets/i18n/es-MX.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Cargando información del archivo",
"backup_err_only_album": "No se puede eliminar el único álbum",
"backup_info_card_assets": "archivos",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Construyendo la línea de tiempo",
"home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Error de descarga",
"image_viewer_page_state_provider_download_success": "Descarga exitosa",
"library_page_albums": "Álbumes",
@@ -166,6 +172,7 @@
"library_page_sharing": "Compartiendo",
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_title": "Título del álbum",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
"login_form_button_text": "Iniciar sesión",
"login_form_email_hint": "tucorreo@correo.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "La carga en tres etapas puede aumentar el rendimiento de carga pero provoca un consumo de red significativamente mayor",
"theme_setting_three_stage_loading_title": "Activar carga en tres etapas",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Aceptar",
"version_announcement_overlay_release_notes": "notas de la versión",
"version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",
diff --git a/mobile/assets/i18n/es-PE.json b/mobile/assets/i18n/es-PE.json
index 6457fbfef..d7564f0b6 100644
--- a/mobile/assets/i18n/es-PE.json
+++ b/mobile/assets/i18n/es-PE.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Cargando información del archivo",
"backup_err_only_album": "No se puede eliminar el único álbum",
"backup_info_card_assets": "archivos",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Construyendo la línea de tiempo",
"home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Error de descarga",
"image_viewer_page_state_provider_download_success": "Descarga exitosa",
"library_page_albums": "Álbumes",
@@ -166,6 +172,7 @@
"library_page_sharing": "Compartiendo",
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_title": "Título del álbum",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
"login_form_button_text": "Iniciar sesión",
"login_form_email_hint": "tucorreo@correo.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "La carga en tres etapas puede aumentar el rendimiento de carga pero provoca un consumo de red significativamente mayor",
"theme_setting_three_stage_loading_title": "Activar carga en tres etapas",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Aceptar",
"version_announcement_overlay_release_notes": "notas de la versión",
"version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",
diff --git a/mobile/assets/i18n/fi-FI.json b/mobile/assets/i18n/fi-FI.json
index 79cbe7b7a..152948927 100644
--- a/mobile/assets/i18n/fi-FI.json
+++ b/mobile/assets/i18n/fi-FI.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Tiedostojen lähetystiedot",
"backup_err_only_album": "Vähintään yhden albumin tulee olla valittuna",
"backup_info_card_assets": "kohdetta",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Kirjastosivun esikatselukuvat ({} kohdetta)",
"cache_settings_clear_cache_button": "Tyhjennä välimuisti",
"cache_settings_clear_cache_button_title": "Tyhjennä sovelluksen välimuisti. Tämä vaikuttaa merkittävästi sovelluksen suorituskykyyn, kunnes välimuisti on rakennettu uudelleen.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Rakennetaan aikajanaa",
"home_page_favorite_err_local": "Paikallisten kohteiden lisääminen suosikkeihin ei ole mahdollista, ohitetaan",
"home_page_first_time_notice": "Jos käytät sovellusta ensimmäistä kertaa, muista valita varmuuskopioitavat albumi(t), jotta aikajanalla voi olla kuvia ja videoita.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Lataus epäonnistui",
"image_viewer_page_state_provider_download_success": "Lataus onnistui",
"library_page_albums": "Albumit",
@@ -166,6 +172,7 @@
"library_page_sharing": "Jakaminen",
"library_page_sort_created": "Viimeisin luotu",
"library_page_sort_title": "Albumin otsikko",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API-virhe. Tarkista palvelimen URL-osoite ja yritä uudelleen.",
"login_form_button_text": "Kirjaudu",
"login_form_email_hint": "sahkopostisi@esimerkki.fi",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Teema",
"theme_setting_three_stage_loading_subtitle": "Kolmivaiheinen lataaminen saattaa parantaa latauksen suorituskykyä, mutta lisää kaistankäyttöä huomattavasti.",
"theme_setting_three_stage_loading_title": "Ota kolmivaiheinen lataus käyttöön",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Tiedostan",
"version_announcement_overlay_release_notes": "julkaisutiedoissa",
"version_announcement_overlay_text_1": "Hei, kaveri! Uusi palvelinversio on saatavilla sovelluksesta",
diff --git a/mobile/assets/i18n/fr-FR.json b/mobile/assets/i18n/fr-FR.json
index 7a84bd767..4c67ba054 100644
--- a/mobile/assets/i18n/fr-FR.json
+++ b/mobile/assets/i18n/fr-FR.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Transfert des informations du fichier",
"backup_err_only_album": "Impossible de retirer le seul album",
"backup_info_card_assets": "éléments",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniatures de la page bibliothèque ({} éléments)",
"cache_settings_clear_cache_button": "Effacer le cache",
"cache_settings_clear_cache_button_title": "Efface le cache de l'application. Cela aura un impact significatif sur les performances de l'application jusqu'à ce que le cache soit reconstruit.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Construction de la chronologie",
"home_page_favorite_err_local": "Impossible d'ajouter des éléments locaux aux favoris pour le moment, étape ignorée",
"home_page_first_time_notice": "Si c'est la première fois que vous utilisez l'application, veillez à choisir un ou plusieurs albums de sauvegarde afin que la chronologie puisse alimenter les photos et les vidéos de cet ou ces albums.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Erreur de téléchargement",
"image_viewer_page_state_provider_download_success": "Téléchargement réussi",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Partage",
"library_page_sort_created": "Créations les plus récentes",
"library_page_sort_title": "Titre de l'album",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "Erreur de l'API. Veuillez vérifier l'URL du serveur et et réessayer.",
"login_form_button_text": "Connexion",
"login_form_email_hint": "votreemail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Thème",
"theme_setting_three_stage_loading_subtitle": "Le chargement en trois étapes peut améliorer les performances de chargement, mais entraîne une augmentation significative de la charge du réseau.",
"theme_setting_three_stage_loading_title": "Activer le chargement en trois étapes",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Confirmer",
"version_announcement_overlay_release_notes": "notes de mise à jour",
"version_announcement_overlay_text_1": "Bonjour, une nouvelle version de",
diff --git a/mobile/assets/i18n/hi-IN.json b/mobile/assets/i18n/hi-IN.json
index 47e60789c..8aeae7043 100644
--- a/mobile/assets/i18n/hi-IN.json
+++ b/mobile/assets/i18n/hi-IN.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/hu-HU.json b/mobile/assets/i18n/hu-HU.json
index 0f28f5c5f..87eee7df3 100644
--- a/mobile/assets/i18n/hu-HU.json
+++ b/mobile/assets/i18n/hu-HU.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Helyi médiát még nem lehet a kedvencek közé tenni. Kihagyjuk.",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Letöltési Hiba",
"image_viewer_page_state_provider_download_success": "Letöltés Sikeres",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API hiba. Kérljük, ellenőrid a szerver címét, majd próbáld újra.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/it-IT.json b/mobile/assets/i18n/it-IT.json
index 8d737f4a4..7e4db3670 100644
--- a/mobile/assets/i18n/it-IT.json
+++ b/mobile/assets/i18n/it-IT.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Caricando informazioni sul file",
"backup_err_only_album": "Non è possibile rimuovere l'unico album",
"backup_info_card_assets": "oggetti ",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Anteprime pagine librerie ({} assets)",
"cache_settings_clear_cache_button": "Cancella cache",
"cache_settings_clear_cache_button_title": "Cancella la cache dell'app. Questo impatterà significativamente le prestazioni dell''app fino a quando la cache non sarà rigenerata.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Costruendo il Timeline",
"home_page_favorite_err_local": "Non puoi aggiungere tra i preferiti le foto ancora non caricate",
"home_page_first_time_notice": "Se è la prima volta che usi l'app, assicurati di scegliere gli album per avere il Timeline con immagini e video",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Errore nel Download",
"image_viewer_page_state_provider_download_success": "Download con successo",
"library_page_albums": "Album",
@@ -166,6 +172,7 @@
"library_page_sharing": "Condividendo",
"library_page_sort_created": "Creato il più recente",
"library_page_sort_title": "Titolo album",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API error, per favore ricontrolli URL del server e riprovi",
"login_form_button_text": "Login",
"login_form_email_hint": "tuaemail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Il caricamento a tre stage aumenterà le performance di caricamento ma anche il consumo di banda",
"theme_setting_three_stage_loading_title": "Abilita il caricamento a tre stage",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Presa visione",
"version_announcement_overlay_release_notes": "note di rilascio ",
"version_announcement_overlay_text_1": "Ciao, c'è una nuova versione di",
diff --git a/mobile/assets/i18n/ja-JP.json b/mobile/assets/i18n/ja-JP.json
index 78c1f6258..1b3ede0a9 100644
--- a/mobile/assets/i18n/ja-JP.json
+++ b/mobile/assets/i18n/ja-JP.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "アップロード中のファイル",
"backup_err_only_album": "最低1つのアルバムを選択してください",
"backup_info_card_assets": "写真と動画",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "ライブラリのサムネイル ({}枚)",
"cache_settings_clear_cache_button": "キャッシュをクリア",
"cache_settings_clear_cache_button_title": "キャッシュを削除(キャッシュ再生成までアプリのパフォーマンスが著しく低下)",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "タイムライン構築中",
"home_page_favorite_err_local": "まだアップロードされてない項目はお気に入り登録できません",
"home_page_first_time_notice": "はじめてアプリを使う場合、タイムラインに写真を表示するためにアルバムを選択してください",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "ダウンロード失敗",
"image_viewer_page_state_provider_download_success": "ダウンロード成功",
"library_page_albums": "アルバム",
@@ -166,6 +172,7 @@
"library_page_sharing": "共有中",
"library_page_sort_created": "作成日時",
"library_page_sort_title": "アルバム名",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "APIエラー。URLをチェックしてもう一度試してください",
"login_form_button_text": "ログイン",
"login_form_email_hint": "hoge@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "テーマ",
"theme_setting_three_stage_loading_subtitle": "三段階読み込みを有効にするとパフォーマンスが改善する可能性がありますが、ネットワーク負荷が著しく増加します",
"theme_setting_three_stage_loading_title": "三段階読み込みをオンにする",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "了解",
"version_announcement_overlay_release_notes": "更新情報",
"version_announcement_overlay_text_1": "こんにちは、またはこんばんは!新しい",
diff --git a/mobile/assets/i18n/ko-KR.json b/mobile/assets/i18n/ko-KR.json
index 6b60aa387..5ee62abe2 100644
--- a/mobile/assets/i18n/ko-KR.json
+++ b/mobile/assets/i18n/ko-KR.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "파일 정보 업로드 중",
"backup_err_only_album": "유일한 앨범은 제거할 수 없습니다",
"backup_info_card_assets": "미디어",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "라이브러리 페이지 썸네일 ({} 미디어)",
"cache_settings_clear_cache_button": "캐시 지우기",
"cache_settings_clear_cache_button_title": "앱의 캐시를 지웁니다. 이 작업은 캐시가 다시 빌드될 때까지 앱의 성능에 상당한 영향을 미칩니다.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "타임라인 생성",
"home_page_favorite_err_local": "미디어파일을 즐겨찾기에 추가할 수 없어, 건너뜁니다.",
"home_page_first_time_notice": "앱을 처음 사용하는 경우 타임라인이 앨범의 사진과 비디오를 채울 수 있도록 백업대상 앨범을 선택해야 합니다.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "다운로드 에러",
"image_viewer_page_state_provider_download_success": "다운로드 완료",
"library_page_albums": "앨범",
@@ -166,6 +172,7 @@
"library_page_sharing": "공유",
"library_page_sort_created": "최근생성일",
"library_page_sort_title": "앨범 제목",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "로그인",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "테마",
"theme_setting_three_stage_loading_subtitle": "이 기능은 로딩 성능을 향상시킬 수 있지만 훨씬 더 많은 데이터를 사용합니다.",
"theme_setting_three_stage_loading_title": "3단계 로딩 활성화",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "승인",
"version_announcement_overlay_release_notes": "릴리스 정보",
"version_announcement_overlay_text_1": "안녕하세요!",
diff --git a/mobile/assets/i18n/lv-LV.json b/mobile/assets/i18n/lv-LV.json
index 3ce0e7a51..a921971ad 100644
--- a/mobile/assets/i18n/lv-LV.json
+++ b/mobile/assets/i18n/lv-LV.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Faila informācijas augšupielāde",
"backup_err_only_album": "Nevar noņemt vienīgo albumu",
"backup_info_card_assets": "aktīvi",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Bibliotēkas lapu sīktēli ({} aktīvi)",
"cache_settings_clear_cache_button": "Iztīrīt kešatmiņu",
"cache_settings_clear_cache_button_title": "Iztīra aplikācijas kešatmiņu. Tas būtiski ietekmēs lietotnes veiktspēju, līdz kešatmiņa būs pārbūvēta.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Tiek izveidota laika skala",
"home_page_favorite_err_local": "Vēl nevar pievienot izlaisei vietējos aktīvus, notiek izlaišana",
"home_page_first_time_notice": "Ja šī ir pirmā reize, kad izmantojat aplikāciju, lūdzu, izvēlieties dublējuma albumu(s), lai laika skala varētu aizpildīt fotoattēlus un videoklipus albumā(os).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Lejupielādes Kļūda",
"image_viewer_page_state_provider_download_success": "Lejupielāde Izdevās",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Kopīgošana",
"library_page_sort_created": "Jaunākais izveidotais",
"library_page_sort_title": "Albuma virsraksts",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API izņēmums. Lūdzu, pārbaudiet servera URL un mēģiniet vēlreiz.",
"login_form_button_text": "Pieteikties",
"login_form_email_hint": "jūsuepasts@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Dizains",
"theme_setting_three_stage_loading_subtitle": "Trīspakāpju ielāde var palielināt ielādēšanas veiktspēju, bet izraisa ievērojami lielāku tīkla noslodzi",
"theme_setting_three_stage_loading_title": "Iespējot trīspakāpju ielādi",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Atzīt",
"version_announcement_overlay_release_notes": "informācija par laidienu",
"version_announcement_overlay_text_1": "Sveiks draugs, ir jauns izlaidums no",
diff --git a/mobile/assets/i18n/mn.json b/mobile/assets/i18n/mn.json
index 6fcd72a48..7c793a412 100644
--- a/mobile/assets/i18n/mn.json
+++ b/mobile/assets/i18n/mn.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/nb-NO.json b/mobile/assets/i18n/nb-NO.json
index cd9cd38cc..509d8fbc3 100644
--- a/mobile/assets/i18n/nb-NO.json
+++ b/mobile/assets/i18n/nb-NO.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Laster opp filinformasjon",
"backup_err_only_album": "Kan ikke fjerne det eneste albumet",
"backup_info_card_assets": "objekter",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Feilet",
+ "backup_manual_in_progress": "Opplasting er allerede i gang. Prøv igjen om litt",
+ "backup_manual_success": "Vellykket",
+ "backup_manual_title": "Opplastingsstatus",
"cache_settings_album_thumbnails": "Bibliotekminiatyrbilder ({} objekter)",
"cache_settings_clear_cache_button": "Tøm buffer",
"cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Genererer tidslinjen",
"home_page_favorite_err_local": "Kan ikke sette favoritt på lokale objekter enda, hopper over",
"home_page_first_time_notice": "Hvis dette er første gangen du benytter appen, velg et album (eller flere) for sikkerhetskopiering, slik at tidslinjen kan fylles med dine bilder og videoer.",
+ "home_page_upload_err_limit": "Maksimalt 30 objekter kan lastes opp om gangen, hopper over",
"image_viewer_page_state_provider_download_error": "Nedlasting feilet",
"image_viewer_page_state_provider_download_success": "Nedlasting vellykket",
"library_page_albums": "Albumer",
@@ -166,6 +172,7 @@
"library_page_sharing": "Deling",
"library_page_sort_created": "Nylig opplastet",
"library_page_sort_title": "Albumtittel",
+ "login_disabled": "Innlogging har blitt deaktivert",
"login_form_api_exception": "API-feil. Sjekk URL-en til serveren og prøv igjen.",
"login_form_button_text": "Logg inn",
"login_form_email_hint": "dinepost@epost.no",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Tre-trinns innlasting kan øke lasteytelsen, men forårsaker betydelig høyere nettverksbelastning",
"theme_setting_three_stage_loading_title": "Aktiver tre-trinns innlasting",
+ "upload_dialog_cancel": "Avbryt",
+ "upload_dialog_info": "Vil du utføre backup av valgte objekt(er) til serveren?",
+ "upload_dialog_ok": "Last opp",
+ "upload_dialog_title": "Last opp objekt",
"version_announcement_overlay_ack": "Bekreft",
"version_announcement_overlay_release_notes": "endringsloggen",
"version_announcement_overlay_text_1": "Hei, det er en ny versjon av",
diff --git a/mobile/assets/i18n/nl-NL.json b/mobile/assets/i18n/nl-NL.json
index 501a62a99..b907e4950 100644
--- a/mobile/assets/i18n/nl-NL.json
+++ b/mobile/assets/i18n/nl-NL.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Bestandsgegevens uploaden",
"backup_err_only_album": "Kan het enige album niet verwijderen",
"backup_info_card_assets": "items",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Thumbnails bibliotheekpagina ({} items)",
"cache_settings_clear_cache_button": "Cache wissen",
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Tijdlijn opbouwen",
"home_page_favorite_err_local": "Lokale items kunnen nog niet als favoriet worden aangemerkt, overslaan",
"home_page_first_time_notice": "Als dit de eerste keer is dat je de app gebruikt, zorg er dan voor dat je een back-up album kiest, zodat de tijdlijn gevuld kan worden met foto's en video's uit het album.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download mislukt",
"image_viewer_page_state_provider_download_success": "Download succesvol",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Gedeeld",
"library_page_sort_created": "Meest recent gemaakt",
"library_page_sort_title": "Albumtitel",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API fout. Controleer de server URL en probeer opnieuw.",
"login_form_button_text": "Inloggen",
"login_form_email_hint": "jouwemail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Thema",
"theme_setting_three_stage_loading_subtitle": "Laden in drie fasen kan de laadprestaties verbeteren, maar veroorzaakt een aanzienlijk hogere netwerkbelasting",
"theme_setting_three_stage_loading_title": "Laden in drie fasen inschakelen",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Bevestig",
"version_announcement_overlay_release_notes": "releaseopmerkingen",
"version_announcement_overlay_text_1": "Hoi, er is een nieuwe versie beschikbaar van",
diff --git a/mobile/assets/i18n/pl-PL.json b/mobile/assets/i18n/pl-PL.json
index d3a630422..1ed349212 100644
--- a/mobile/assets/i18n/pl-PL.json
+++ b/mobile/assets/i18n/pl-PL.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Przesyłanie informacji o pliku",
"backup_err_only_album": "Nie można usunąć tylko i wyłącznie albumu",
"backup_info_card_assets": "zasoby",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniatury stron bibliotek ({} zasobów)",
"cache_settings_clear_cache_button": "Wyczyść Cache",
"cache_settings_clear_cache_button_title": "Czyści pamięć podręczną aplikacji. Wpłynie to znacząco na wydajność aplikacji, dopóki pamięć podręczna nie zostanie odbudowana.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albumy",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "twojmail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Motyw",
"theme_setting_three_stage_loading_subtitle": "Trójstopniowe ładowanie może zwiększyć wydajność ładowania, ale powoduje znacznie większe obciążenie sieci",
"theme_setting_three_stage_loading_title": "Włączenie trójstopniowego ładowania",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Potwierdzam",
"version_announcement_overlay_release_notes": "informacje o wydaniu",
"version_announcement_overlay_text_1": "Cześć przyjacielu, jest nowe wydanie",
diff --git a/mobile/assets/i18n/ru-RU.json b/mobile/assets/i18n/ru-RU.json
index 3cd79f076..27a22850b 100644
--- a/mobile/assets/i18n/ru-RU.json
+++ b/mobile/assets/i18n/ru-RU.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Загрузка информации о файле",
"backup_err_only_album": "Невозможно удалить единственный альбом",
"backup_info_card_assets": "объекты",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Миниатюры страниц библиотеки ({} объектов)",
"cache_settings_clear_cache_button": "Очистить кэш",
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это значительно повлияет на производительность приложения, до тех пор, пока кэш не будет перестроен заново.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Построение временной шкалы",
"home_page_favorite_err_local": "Пока не удается добавить в избранное локальные объекты, пропускаем",
"home_page_first_time_notice": "Если вы используете приложение впервые, убедитесь, что вы выбрали резервный(е) альбом(ы), чтобы временная шкала могла заполнить фотографии и видео в альбоме(ах).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Ошибка загрузки",
"image_viewer_page_state_provider_download_success": "Успешно загружено",
"library_page_albums": "Альбомы",
@@ -166,6 +172,7 @@
"library_page_sharing": "Общие",
"library_page_sort_created": "По новизне",
"library_page_sort_title": "По названию альбома",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Войти",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Тема",
"theme_setting_three_stage_loading_subtitle": "Трехэтапная загрузка может повысить производительность загрузки, но вызывает значительно более высокую нагрузку на сеть",
"theme_setting_three_stage_loading_title": "Включить трехэтапную загрузку",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Подтверждение",
"version_announcement_overlay_release_notes": "примечания к выпуску",
"version_announcement_overlay_text_1": "Привет друг, вышел новый релиз",
diff --git a/mobile/assets/i18n/sk-SK.json b/mobile/assets/i18n/sk-SK.json
index 7ca36b595..ecb968d00 100644
--- a/mobile/assets/i18n/sk-SK.json
+++ b/mobile/assets/i18n/sk-SK.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Nahrávaný súbor",
"backup_err_only_album": "Nie je možné odstrániť jediný vybraný album",
"backup_info_card_assets": "položiek",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Náhľady stránok knižnice (položiek {})",
"cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Vytváranie časovej osi",
"home_page_favorite_err_local": "Zatiaľ nie je možné zaradiť lokálne média medzi obľúbené, preskakuje sa",
"home_page_first_time_notice": "Ak aplikáciu používate prvý krát, nezabudnite si vybrať zálohované albumy, aby sa na časovej osi mohli nachádzať fotografie a videá z vybraných albumoch.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Chyba sťahovania",
"image_viewer_page_state_provider_download_success": "Sťahovanie bolo úspešné",
"library_page_albums": "Albumy",
@@ -166,6 +172,7 @@
"library_page_sharing": "Zdieľanie",
"library_page_sort_created": "Najnovšie vytvorené",
"library_page_sort_title": "Podľa názvu albumu",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "Chyba API. Skontrolujte adresu URL servera a skúste to znova.",
"login_form_button_text": "Prihlásiť sa",
"login_form_email_hint": "tvojmail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Téma",
"theme_setting_three_stage_loading_subtitle": "Trojstupňové načítanie môže zvýšiť výkonnosť načítania, ale vedie k výrazne vyššiemu zaťaženiu siete.",
"theme_setting_three_stage_loading_title": "Povolenie trojstupňového načítavania",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Potvrdiť",
"version_announcement_overlay_release_notes": "poznámky k vydaniu",
"version_announcement_overlay_text_1": "Ahoj, je tu nová verzia",
diff --git a/mobile/assets/i18n/sr-Cyrl.json b/mobile/assets/i18n/sr-Cyrl.json
index 47e60789c..8aeae7043 100644
--- a/mobile/assets/i18n/sr-Cyrl.json
+++ b/mobile/assets/i18n/sr-Cyrl.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/sr-Latn.json b/mobile/assets/i18n/sr-Latn.json
index 6d466d052..8a2674cf5 100644
--- a/mobile/assets/i18n/sr-Latn.json
+++ b/mobile/assets/i18n/sr-Latn.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Otpremanje svojstava datoteke",
"backup_err_only_album": "Nemoguće brisanje jedinog albuma",
"backup_info_card_assets": "zapisi",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Sličice na stranici biblioteke",
"cache_settings_clear_cache_button": "Obriši keš memoriju",
"cache_settings_clear_cache_button_title": "Ova opcija briše keš memoriju aplikacije. Ovo će bitno uticati na performanse aplikacije dok se keš memorija ne učita ponovo.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Kreiranje hronološke linije",
"home_page_favorite_err_local": "Trenutno nije moguce dodati lokalne zapise u favorite, preskacu se",
"home_page_first_time_notice": "Ako je ovo prvi put da koristite aplikaciju, molimo Vas da odaberete albume koje želite da sačuvate",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Preuzimanje Neuspešno",
"image_viewer_page_state_provider_download_success": "Preuzimanje Uspešno",
"library_page_albums": "Albumi",
@@ -166,6 +172,7 @@
"library_page_sharing": "Deljenje",
"library_page_sort_created": "Najnovije kreirano",
"library_page_sort_title": "Naziv albuma",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Prijavi se",
"login_form_email_hint": "vašemail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Teme",
"theme_setting_three_stage_loading_subtitle": "Trostepeno učitavanje možda ubrza učitavanje, po cenu potrošnje podataka",
"theme_setting_three_stage_loading_title": "Aktiviraj trostepeno učitavanje",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Priznati",
"version_announcement_overlay_release_notes": "novine nove verzije",
"version_announcement_overlay_text_1": "Ćao, nova verzija",
diff --git a/mobile/assets/i18n/sv-FI.json b/mobile/assets/i18n/sv-FI.json
index 47e60789c..8aeae7043 100644
--- a/mobile/assets/i18n/sv-FI.json
+++ b/mobile/assets/i18n/sv-FI.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/sv-SE.json b/mobile/assets/i18n/sv-SE.json
index c9b75a257..b61d2ca63 100644
--- a/mobile/assets/i18n/sv-SE.json
+++ b/mobile/assets/i18n/sv-SE.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Laddar upp filinformation",
"backup_err_only_album": "Kan inte ta bort det enda albumet",
"backup_info_card_assets": "objekt",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniatyrbilder för bibliotek ({} bilder och videor)",
"cache_settings_clear_cache_button": "Rensa cacheminnet",
"cache_settings_clear_cache_button_title": "Rensar appens cacheminne. Detta kommer att avsevärt påverka appens prestanda tills cachen har byggts om.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Bygger tidslinjen",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "Om det här är första gången du använder appen, välj ett eller flera backup-album så att tidslinjen kan fyllas med foton och videor från albumen.",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Album",
@@ -166,6 +172,7 @@
"library_page_sharing": "Delas",
"library_page_sort_created": "Senast skapad",
"library_page_sort_title": "Albumtitel",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Logga in",
"login_form_email_hint": "din.email@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Trestegsladdning kan öka prestandan, men kan också leda till signifikant högre nätverksbelastning",
"theme_setting_three_stage_loading_title": "Aktivera trestegsladdning",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Bekräfta",
"version_announcement_overlay_release_notes": "versionsinformation",
"version_announcement_overlay_text_1": "Hej vännen, det finns en ny version av",
diff --git a/mobile/assets/i18n/th-TH.json b/mobile/assets/i18n/th-TH.json
index 8359013b6..d74b81ce8 100644
--- a/mobile/assets/i18n/th-TH.json
+++ b/mobile/assets/i18n/th-TH.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "ไม่สามารถนำอัลบั้มสุดท้ายออกได้",
"backup_info_card_assets": "ทรัพยากร",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "ล้มเหลว",
+ "backup_manual_in_progress": "อัปโหลดกำลังดำเนินการอยู่ โปรดลองใหม่ในสักพัก",
+ "backup_manual_success": "สำเร็จ",
+ "backup_manual_title": "สถานะอัพโหลด",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "ล้างแคช",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "กำลังสร้าง timeline",
"home_page_favorite_err_local": " ไม่สามารถตั้งทรัพยากรบนเครื่องเป็นรายการโปรด กำลังข้าม",
"home_page_first_time_notice": "ถ้าครั้งนี้เป็นครั้งแรกที่ใช้แอปนี้ กรุณาเลือกอัลบั้มที่จะสำรองข้อมูล ไทม์ไลน์จะได้เพิ่มรูปภาพและวิดีโอที่อยู่ในอัลบั้ม",
+ "home_page_upload_err_limit": "สามารถอัพโหลดได้มากสุดครั้งละ 30 ทรัพยากร กำลังข้าม",
"image_viewer_page_state_provider_download_error": "ดาวน์โหลดผิดพลาด",
"image_viewer_page_state_provider_download_success": "ดาวน์โหลดสำเร็จ",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "การแชร์",
"library_page_sort_created": "สร้างล่าสุด",
"library_page_sort_title": "ชื่ออัลบั้ม",
+ "login_disabled": "ล็อกอินถูกปิด",
"login_form_api_exception": "ข้อผิดพลาด API กรุณาตรวจสอบ URL แล้วลองใหม่",
"login_form_button_text": "เข้าสู่ระบบ",
"login_form_email_hint": "อีเมลคุณ@อีเมล.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "ยกเลิก",
+ "upload_dialog_info": "คุณต้องการอัพโหลดทรัพยากรดังกล่าวบนเซิร์ฟเวอร์หรือไม่?",
+ "upload_dialog_ok": "อัปโหลด",
+ "upload_dialog_title": "อัปโหลดทรัพยากร",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/uk-UA.json b/mobile/assets/i18n/uk-UA.json
index 47e60789c..8aeae7043 100644
--- a/mobile/assets/i18n/uk-UA.json
+++ b/mobile/assets/i18n/uk-UA.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/vi-VN.json b/mobile/assets/i18n/vi-VN.json
index 18298dad9..762569ec0 100644
--- a/mobile/assets/i18n/vi-VN.json
+++ b/mobile/assets/i18n/vi-VN.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "Failed",
+ "backup_manual_in_progress": "Upload already in progress. Try after sometime",
+ "backup_manual_success": "Success",
+ "backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
+ "home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
+ "login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
+ "upload_dialog_cancel": "Cancel",
+ "upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
+ "upload_dialog_ok": "Upload",
+ "upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",
diff --git a/mobile/assets/i18n/zh-CN.json b/mobile/assets/i18n/zh-CN.json
index bba4b1643..9a2af046d 100644
--- a/mobile/assets/i18n/zh-CN.json
+++ b/mobile/assets/i18n/zh-CN.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "正在上传文件信息",
"backup_err_only_album": "不能移除唯一的一个相册",
"backup_info_card_assets": "张",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "失败",
+ "backup_manual_in_progress": "上传正在进行中,请稍后再试",
+ "backup_manual_success": "成功",
+ "backup_manual_title": "上传状态",
"cache_settings_album_thumbnails": "图库缩略图({} 张)",
"cache_settings_clear_cache_button": "清除缓存",
"cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "正在生成时间线",
"home_page_favorite_err_local": "暂不能收藏本地项目,跳过",
"home_page_first_time_notice": "如果这是您第一次使用该应用程序,请确保选择一个要备份的本地相册,以便可以在时间线中预览该相册中的照片和视频。",
+ "home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
"image_viewer_page_state_provider_download_error": "下载出现错误",
"image_viewer_page_state_provider_download_success": "下载成功",
"library_page_albums": "相册",
@@ -166,6 +172,7 @@
"library_page_sharing": "共享",
"library_page_sort_created": "最近创建的",
"library_page_sort_title": "相册标题",
+ "login_disabled": "登录已被禁用",
"login_form_api_exception": "API 异常,请检查服务器地址并重试。",
"login_form_button_text": "登录",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "主题",
"theme_setting_three_stage_loading_subtitle": "三段式加载可能会提升加载性能,但可能会导致更高的网络负载",
"theme_setting_three_stage_loading_title": "启用三段式加载",
+ "upload_dialog_cancel": "取消",
+ "upload_dialog_info": "是否要将所选项目备份到服务器?",
+ "upload_dialog_ok": "上传",
+ "upload_dialog_title": "上传项目",
"version_announcement_overlay_ack": "我知道了",
"version_announcement_overlay_release_notes": "发行说明",
"version_announcement_overlay_text_1": "号外号外,有新版本的",
diff --git a/mobile/assets/i18n/zh-Hans.json b/mobile/assets/i18n/zh-Hans.json
index 7cb167c39..b9337f8d1 100644
--- a/mobile/assets/i18n/zh-Hans.json
+++ b/mobile/assets/i18n/zh-Hans.json
@@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "正在上传文件信息",
"backup_err_only_album": "不能移除唯一的一个相册",
"backup_info_card_assets": "张",
+ "backup_manual_cancelled": "Cancelled",
+ "backup_manual_failed": "失败",
+ "backup_manual_in_progress": "上传正在进行中,请稍后再试",
+ "backup_manual_success": "成功",
+ "backup_manual_title": "上传状态",
"cache_settings_album_thumbnails": "图库缩略图({} 张)",
"cache_settings_clear_cache_button": "清除缓存",
"cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
@@ -156,6 +161,7 @@
"home_page_building_timeline": "正在生成时间线",
"home_page_favorite_err_local": "暂不能收藏本地项目,跳过",
"home_page_first_time_notice": "如果这是您第一次使用该应用程序,请确保选择一个要备份的本地相册,以便可以在时间线中预览该相册中的照片和视频。",
+ "home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
"image_viewer_page_state_provider_download_error": "下载出现错误",
"image_viewer_page_state_provider_download_success": "下载成功",
"library_page_albums": "相册",
@@ -166,6 +172,7 @@
"library_page_sharing": "共享",
"library_page_sort_created": "最近创建的",
"library_page_sort_title": "相册标题",
+ "login_disabled": "登录已被禁用",
"login_form_api_exception": "API 异常,请检查服务器地址并重试。",
"login_form_button_text": "登录",
"login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
"theme_setting_theme_title": "主题",
"theme_setting_three_stage_loading_subtitle": "三段式加载可能会提升加载性能,但可能会导致更高的网络负载",
"theme_setting_three_stage_loading_title": "启用三段式加载",
+ "upload_dialog_cancel": "取消",
+ "upload_dialog_info": "是否要将所选项目备份到服务器?",
+ "upload_dialog_ok": "上传",
+ "upload_dialog_title": "上传正在进行中,请稍后再试",
"version_announcement_overlay_ack": "我知道了",
"version_announcement_overlay_release_notes": "发行说明",
"version_announcement_overlay_text_1": "号外号外,有新版本的",
From 079aa13edbc5edc4055466d88abdb26c8f265e98 Mon Sep 17 00:00:00 2001
From: Jason Rasmussen
Date: Mon, 14 Aug 2023 21:22:33 -0400
Subject: [PATCH 06/22] fix(web): use server api media types (#3687)
---
web/src/lib/utils/file-uploader.ts | 62 +++++++-----------------------
1 file changed, 13 insertions(+), 49 deletions(-)
diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts
index fad841c22..533ab372e 100644
--- a/web/src/lib/utils/file-uploader.ts
+++ b/web/src/lib/utils/file-uploader.ts
@@ -1,62 +1,25 @@
import { uploadAssetsStore } from '$lib/stores/upload';
import { addAssetsToAlbum } from '$lib/utils/asset-utils';
-import type { AssetFileUploadResponseDto } from '@api';
+import { api, AssetFileUploadResponseDto } from '@api';
import axios from 'axios';
import { notificationController, NotificationType } from './../components/shared-components/notification/notification';
-const extensions = [
- '.3fr',
- '.3gp',
- '.ari',
- '.arw',
- '.avi',
- '.avif',
- '.cap',
- '.cin',
- '.cr2',
- '.cr3',
- '.crw',
- '.dcr',
- '.dng',
- '.erf',
- '.fff',
- '.flv',
- '.gif',
- '.heic',
- '.heif',
- '.iiq',
- '.jpeg',
- '.jpg',
- '.k25',
- '.kdc',
- '.mkv',
- '.mov',
- '.mp2t',
- '.mp4',
- '.mpeg',
- '.mrw',
- '.nef',
- '.orf',
- '.ori',
- '.pef',
- '.png',
- '.raf',
- '.raw',
- '.rwl',
- '.sr2',
- '.srf',
- '.srw',
- '.tiff',
- '.webm',
- '.webp',
- '.wmv',
- '.x3f',
-];
+let _extensions: string[];
+
+const getExtensions = async () => {
+ if (!_extensions) {
+ const { data } = await api.serverInfoApi.getSupportedMediaTypes();
+ _extensions = [...data.image, ...data.video];
+ }
+ return _extensions;
+};
export const openFileUploadDialog = async (
albumId: string | undefined = undefined,
sharedKey: string | undefined = undefined,
) => {
+ const extensions = await getExtensions();
+
return new Promise<(string | undefined)[]>((resolve, reject) => {
try {
const fileSelector = document.createElement('input');
@@ -87,6 +50,7 @@ export const fileUploadHandler = async (
albumId: string | undefined = undefined,
sharedKey: string | undefined = undefined,
) => {
+ const extensions = await getExtensions();
const iterable = {
files: files.filter((file) => extensions.some((ext) => file.name.toLowerCase().endsWith(ext)))[Symbol.iterator](),
From f1b8a7ab5474fa3364fe3a5835374b85232d1dd0 Mon Sep 17 00:00:00 2001
From: Russell Tan
Date: Mon, 14 Aug 2023 18:37:17 -0700
Subject: [PATCH 07/22] fix(server): Does not assign lat/lon if they are at 0,0
#2991 (#3669)
* fix(server): Does not assign lat/lon if they are at 0,0 #2991
* Adds migration file to fix null island rows
* Removed down migration
* Leave empty down function
---
.../migrations/1692057328660-fixGPSNullIsland.ts | 13 +++++++++++++
.../processors/metadata-extraction.processor.ts | 12 ++++++++++--
.../microservices/utils/exif/coordinates.spec.ts | 12 ++++++++++++
server/src/microservices/utils/exif/coordinates.ts | 11 +++++++++--
4 files changed, 44 insertions(+), 4 deletions(-)
create mode 100644 server/src/infra/migrations/1692057328660-fixGPSNullIsland.ts
diff --git a/server/src/infra/migrations/1692057328660-fixGPSNullIsland.ts b/server/src/infra/migrations/1692057328660-fixGPSNullIsland.ts
new file mode 100644
index 000000000..74dc40a47
--- /dev/null
+++ b/server/src/infra/migrations/1692057328660-fixGPSNullIsland.ts
@@ -0,0 +1,13 @@
+import { MigrationInterface, QueryRunner } from "typeorm"
+
+export class FixGPSNullIsland1692057328660 implements MigrationInterface {
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`UPDATE "exif" SET latitude = NULL, longitude = NULL WHERE latitude = 0 AND longitude = 0;`);
+ }
+
+ public async down(): Promise {
+ // Setting lat,lon to 0 not necessary
+ }
+
+}
diff --git a/server/src/microservices/processors/metadata-extraction.processor.ts b/server/src/microservices/processors/metadata-extraction.processor.ts
index a37ee6a23..a5f3ed4dd 100644
--- a/server/src/microservices/processors/metadata-extraction.processor.ts
+++ b/server/src/microservices/processors/metadata-extraction.processor.ts
@@ -308,8 +308,16 @@ export class MetadataExtractionProcessor {
const latitude = getExifProperty('GPSLatitude');
const longitude = getExifProperty('GPSLongitude');
- newExif.latitude = latitude !== null ? parseLatitude(latitude) : null;
- newExif.longitude = longitude !== null ? parseLongitude(longitude) : null;
+ const lat = parseLatitude(latitude);
+ const lon = parseLongitude(longitude);
+
+ if (lat === 0 && lon === 0) {
+ this.logger.warn(`Latitude & Longitude were on Null Island (${lat},${lon}), not assigning coordinates`);
+ } else {
+ newExif.latitude = lat;
+ newExif.longitude = lon;
+ }
+
if (getExifProperty('MotionPhoto')) {
// Seen on more recent Pixel phones: starting as early as Pixel 4a, possibly earlier.
const rawDirectory = getExifProperty('Directory');
diff --git a/server/src/microservices/utils/exif/coordinates.spec.ts b/server/src/microservices/utils/exif/coordinates.spec.ts
index 975d1e996..223a7671e 100644
--- a/server/src/microservices/utils/exif/coordinates.spec.ts
+++ b/server/src/microservices/utils/exif/coordinates.spec.ts
@@ -23,6 +23,12 @@ describe('parsing latitude from string input', () => {
});
});
+describe('parsing latitude from null input', () => {
+ it('returns null for null input', () => {
+ expect(parseLatitude(null)).toBeNull();
+ });
+});
+
describe('parsing longitude from string input', () => {
it('returns null for invalid inputs', () => {
expect(parseLongitude('')).toBeNull();
@@ -44,3 +50,9 @@ describe('parsing longitude from string input', () => {
expect(parseLongitude('-0.0')).toBeCloseTo(-0.0);
});
});
+
+describe('parsing longitude from null input', () => {
+ it('returns null for null input', () => {
+ expect(parseLongitude(null)).toBeNull();
+ });
+});
diff --git a/server/src/microservices/utils/exif/coordinates.ts b/server/src/microservices/utils/exif/coordinates.ts
index 3a07b0c17..03aeb17f0 100644
--- a/server/src/microservices/utils/exif/coordinates.ts
+++ b/server/src/microservices/utils/exif/coordinates.ts
@@ -1,6 +1,9 @@
import { isNumberInRange } from '../numbers';
-export function parseLatitude(input: string | number): number | null {
+export function parseLatitude(input: string | number | null): number | null {
+ if (input === null) {
+ return null;
+ }
const latitude = typeof input === 'string' ? Number.parseFloat(input) : input;
if (isNumberInRange(latitude, -90, 90)) {
@@ -9,7 +12,11 @@ export function parseLatitude(input: string | number): number | null {
return null;
}
-export function parseLongitude(input: string | number): number | null {
+export function parseLongitude(input: string | number | null): number | null {
+ if (input === null) {
+ return null;
+ }
+
const longitude = typeof input === 'string' ? Number.parseFloat(input) : input;
if (isNumberInRange(longitude, -180, 180)) {
From 7ca6f80ed26aa78ed21a3e1cf3fff02f2223a594 Mon Sep 17 00:00:00 2001
From: Jason Rasmussen
Date: Mon, 14 Aug 2023 23:14:52 -0400
Subject: [PATCH 08/22] fix(server): display insta-360 (#3688)
---
server/src/domain/domain.constant.ts | 2 ++
web/src/lib/components/asset-viewer/asset-viewer.svelte | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/server/src/domain/domain.constant.ts b/server/src/domain/domain.constant.ts
index a1cb0a7df..b06720613 100644
--- a/server/src/domain/domain.constant.ts
+++ b/server/src/domain/domain.constant.ts
@@ -48,6 +48,7 @@ const image: Record = {
'.heic': ['image/heic'],
'.heif': ['image/heif'],
'.iiq': ['image/iiq', 'image/x-phaseone-iiq'],
+ '.insp': ['image/jpeg'],
'.jpeg': ['image/jpeg'],
'.jpg': ['image/jpeg'],
'.jxl': ['image/jxl'],
@@ -79,6 +80,7 @@ const video: Record = {
'.3gp': ['video/3gpp'],
'.avi': ['video/avi', 'video/msvideo', 'video/vnd.avi', 'video/x-msvideo'],
'.flv': ['video/x-flv'],
+ '.insv': ['video/mp4'],
'.m2ts': ['video/mp2t'],
'.mkv': ['video/x-matroska'],
'.mov': ['video/quicktime'],
diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte
index e65b45e80..5df79b159 100644
--- a/web/src/lib/components/asset-viewer/asset-viewer.svelte
+++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte
@@ -297,7 +297,9 @@
on:close={closeViewer}
on:onVideoEnded={() => (shouldPlayMotionPhoto = false)}
/>
- {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR}
+ {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || asset.originalPath
+ .toLowerCase()
+ .endsWith('.insp')}
{:else}
From a3b6095b614ae5123cf7ce3fbead8c234da7d56e Mon Sep 17 00:00:00 2001
From: Alex The Bot
Date: Tue, 15 Aug 2023 12:45:48 +0000
Subject: [PATCH 09/22] Version v1.73.0
---
cli/src/api/open-api/api.ts | 2 +-
cli/src/api/open-api/base.ts | 2 +-
cli/src/api/open-api/common.ts | 2 +-
cli/src/api/open-api/configuration.ts | 2 +-
cli/src/api/open-api/index.ts | 2 +-
machine-learning/pyproject.toml | 2 +-
mobile/android/fastlane/Fastfile | 4 ++--
mobile/ios/fastlane/Fastfile | 2 +-
mobile/openapi/README.md | 2 +-
mobile/pubspec.yaml | 2 +-
server/immich-openapi-specs.json | 2 +-
server/package-lock.json | 4 ++--
server/package.json | 2 +-
web/src/api/open-api/api.ts | 2 +-
web/src/api/open-api/base.ts | 2 +-
web/src/api/open-api/common.ts | 2 +-
web/src/api/open-api/configuration.ts | 2 +-
web/src/api/open-api/index.ts | 2 +-
18 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts
index e8662175a..956f19ba7 100644
--- a/cli/src/api/open-api/api.ts
+++ b/cli/src/api/open-api/api.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/cli/src/api/open-api/base.ts b/cli/src/api/open-api/base.ts
index d636bfdd9..7109cba71 100644
--- a/cli/src/api/open-api/base.ts
+++ b/cli/src/api/open-api/base.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/cli/src/api/open-api/common.ts b/cli/src/api/open-api/common.ts
index 6b75041a7..66890914a 100644
--- a/cli/src/api/open-api/common.ts
+++ b/cli/src/api/open-api/common.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/cli/src/api/open-api/configuration.ts b/cli/src/api/open-api/configuration.ts
index 275f99f72..21fd71538 100644
--- a/cli/src/api/open-api/configuration.ts
+++ b/cli/src/api/open-api/configuration.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/cli/src/api/open-api/index.ts b/cli/src/api/open-api/index.ts
index 704745843..937e9a24a 100644
--- a/cli/src/api/open-api/index.ts
+++ b/cli/src/api/open-api/index.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml
index 4547dcb05..b2fa1b28e 100644
--- a/machine-learning/pyproject.toml
+++ b/machine-learning/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "machine-learning"
-version = "1.72.2"
+version = "1.73.0"
description = ""
authors = ["Hau Tran "]
readme = "README.md"
diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile
index 0de6cb8aa..e9be5f654 100644
--- a/mobile/android/fastlane/Fastfile
+++ b/mobile/android/fastlane/Fastfile
@@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
- "android.injected.version.code" => 95,
- "android.injected.version.name" => "1.72.2",
+ "android.injected.version.code" => 96,
+ "android.injected.version.name" => "1.73.0",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile
index 56bf4ba34..7707eadb9 100644
--- a/mobile/ios/fastlane/Fastfile
+++ b/mobile/ios/fastlane/Fastfile
@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta"
lane :beta do
increment_version_number(
- version_number: "1.72.2"
+ version_number: "1.73.0"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,
diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md
index 2942d1d85..1e20582fa 100644
--- a/mobile/openapi/README.md
+++ b/mobile/openapi/README.md
@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
-- API version: 1.72.2
+- API version: 1.73.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements
diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml
index 5c75bfb7e..dc90a5373 100644
--- a/mobile/pubspec.yaml
+++ b/mobile/pubspec.yaml
@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: "none"
-version: 1.72.2+95
+version: 1.73.0+96
isar_version: &isar_version 3.1.0+1
environment:
diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json
index a60fcbd54..59543353f 100644
--- a/server/immich-openapi-specs.json
+++ b/server/immich-openapi-specs.json
@@ -4590,7 +4590,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
- "version": "1.72.2",
+ "version": "1.73.0",
"contact": {}
},
"tags": [],
diff --git a/server/package-lock.json b/server/package-lock.json
index fa3fbf12a..e6e2de6ab 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "immich",
- "version": "1.72.2",
+ "version": "1.73.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "immich",
- "version": "1.72.2",
+ "version": "1.73.0",
"license": "UNLICENSED",
"dependencies": {
"@babel/runtime": "^7.20.13",
diff --git a/server/package.json b/server/package.json
index 2baf087bf..cdfb87d59 100644
--- a/server/package.json
+++ b/server/package.json
@@ -1,6 +1,6 @@
{
"name": "immich",
- "version": "1.72.2",
+ "version": "1.73.0",
"description": "",
"author": "",
"private": true,
diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts
index e8662175a..956f19ba7 100644
--- a/web/src/api/open-api/api.ts
+++ b/web/src/api/open-api/api.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/base.ts b/web/src/api/open-api/base.ts
index d636bfdd9..7109cba71 100644
--- a/web/src/api/open-api/base.ts
+++ b/web/src/api/open-api/base.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/common.ts b/web/src/api/open-api/common.ts
index 6b75041a7..66890914a 100644
--- a/web/src/api/open-api/common.ts
+++ b/web/src/api/open-api/common.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/configuration.ts b/web/src/api/open-api/configuration.ts
index 275f99f72..21fd71538 100644
--- a/web/src/api/open-api/configuration.ts
+++ b/web/src/api/open-api/configuration.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/index.ts b/web/src/api/open-api/index.ts
index 704745843..937e9a24a 100644
--- a/web/src/api/open-api/index.ts
+++ b/web/src/api/open-api/index.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.72.2
+ * The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
From a75f368d5b323d978e9a83a9723495bccf1d8402 Mon Sep 17 00:00:00 2001
From: Alex
Date: Tue, 15 Aug 2023 09:42:28 -0500
Subject: [PATCH 10/22] chore: post update
---
mobile/android/fastlane/report.xml | 6 +++---
mobile/ios/Podfile.lock | 2 +-
mobile/ios/Runner.xcodeproj/project.pbxproj | 6 +++---
mobile/ios/Runner/Info.plist | 4 ++--
mobile/ios/fastlane/report.xml | 12 ++++++------
5 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/mobile/android/fastlane/report.xml b/mobile/android/fastlane/report.xml
index 45b5cef2d..d268a40ae 100644
--- a/mobile/android/fastlane/report.xml
+++ b/mobile/android/fastlane/report.xml
@@ -5,17 +5,17 @@
-
+
-
+
-
+
diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock
index 7b7cbd0d5..4902388c6 100644
--- a/mobile/ios/Podfile.lock
+++ b/mobile/ios/Podfile.lock
@@ -163,4 +163,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
-COCOAPODS: 1.11.3
+COCOAPODS: 1.12.1
diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj
index 9f463abbe..8bb1e3192 100644
--- a/mobile/ios/Runner.xcodeproj/project.pbxproj
+++ b/mobile/ios/Runner.xcodeproj/project.pbxproj
@@ -379,7 +379,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 110;
+ CURRENT_PROJECT_VERSION = 113;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -515,7 +515,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 110;
+ CURRENT_PROJECT_VERSION = 113;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -543,7 +543,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 110;
+ CURRENT_PROJECT_VERSION = 113;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist
index 041dcd2eb..ae8c18518 100644
--- a/mobile/ios/Runner/Info.plist
+++ b/mobile/ios/Runner/Info.plist
@@ -59,11 +59,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.70.0
+ 1.73.0
CFBundleSignature
????
CFBundleVersion
- 110
+ 113
FLTEnableImpeller
ITSAppUsesNonExemptEncryption
diff --git a/mobile/ios/fastlane/report.xml b/mobile/ios/fastlane/report.xml
index f1ee5f827..3f00787c1 100644
--- a/mobile/ios/fastlane/report.xml
+++ b/mobile/ios/fastlane/report.xml
@@ -5,32 +5,32 @@
-
+
-
+
-
+
-
+
-
+
-
+
From efc7fdb669002ab8ed6363141e1ea0400cd2355b Mon Sep 17 00:00:00 2001
From: Jason Rasmussen
Date: Tue, 15 Aug 2023 11:49:32 -0400
Subject: [PATCH 11/22] fix(web,server): use POST request to get download info
(#3694)
* fix(web,server): use POST request to get download info
* chore: open api
---
cli/src/api/open-api/api.ts | 107 ++++++------
mobile/openapi/.openapi-generator/FILES | 3 +
mobile/openapi/README.md | 5 +-
mobile/openapi/doc/AssetApi.md | 20 +--
mobile/openapi/doc/DownloadInfoDto.md | 18 +++
mobile/openapi/lib/api.dart | 1 +
mobile/openapi/lib/api/asset_api.dart | 48 ++----
mobile/openapi/lib/api_client.dart | 2 +
.../openapi/lib/model/download_info_dto.dart | 150 +++++++++++++++++
mobile/openapi/test/asset_api_test.dart | 2 +-
.../openapi/test/download_info_dto_test.dart | 42 +++++
server/immich-openapi-specs.json | 153 +++++++++---------
server/src/domain/asset/asset.service.ts | 6 +-
server/src/domain/asset/dto/download.dto.ts | 3 +-
.../immich/controllers/asset.controller.ts | 8 +-
web/src/api/open-api/api.ts | 107 ++++++------
web/src/lib/utils/asset-utils.ts | 10 +-
17 files changed, 426 insertions(+), 259 deletions(-)
create mode 100644 mobile/openapi/doc/DownloadInfoDto.md
create mode 100644 mobile/openapi/lib/model/download_info_dto.dart
create mode 100644 mobile/openapi/test/download_info_dto_test.dart
diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts
index 956f19ba7..8ade1d5fd 100644
--- a/cli/src/api/open-api/api.ts
+++ b/cli/src/api/open-api/api.ts
@@ -1132,6 +1132,37 @@ export interface DownloadArchiveInfo {
*/
'size': number;
}
+/**
+ *
+ * @export
+ * @interface DownloadInfoDto
+ */
+export interface DownloadInfoDto {
+ /**
+ *
+ * @type {string}
+ * @memberof DownloadInfoDto
+ */
+ 'albumId'?: string;
+ /**
+ *
+ * @type {number}
+ * @memberof DownloadInfoDto
+ */
+ 'archiveSize'?: number;
+ /**
+ *
+ * @type {Array}
+ * @memberof DownloadInfoDto
+ */
+ 'assetIds'?: Array;
+ /**
+ *
+ * @type {string}
+ * @memberof DownloadInfoDto
+ */
+ 'userId'?: string;
+}
/**
*
* @export
@@ -4880,7 +4911,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise => {
// verify required parameter 'assetIdsDto' is not null or undefined
assertParamExists('downloadArchive', 'assetIdsDto', assetIdsDto)
- const localVarPath = `/asset/download`;
+ const localVarPath = `/asset/download/archive`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@@ -5379,16 +5410,15 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
},
/**
*
- * @param {Array} [assetIds]
- * @param {string} [albumId]
- * @param {string} [userId]
- * @param {number} [archiveSize]
+ * @param {DownloadInfoDto} downloadInfoDto
* @param {string} [key]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- getDownloadInfo: async (assetIds?: Array, albumId?: string, userId?: string, archiveSize?: number, key?: string, options: AxiosRequestConfig = {}): Promise => {
- const localVarPath = `/asset/download`;
+ getDownloadInfo: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise => {
+ // verify required parameter 'downloadInfoDto' is not null or undefined
+ assertParamExists('getDownloadInfo', 'downloadInfoDto', downloadInfoDto)
+ const localVarPath = `/asset/download/info`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@@ -5396,7 +5426,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
baseOptions = configuration.baseOptions;
}
- const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
@@ -5409,31 +5439,18 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
- if (assetIds) {
- localVarQueryParameter['assetIds'] = assetIds;
- }
-
- if (albumId !== undefined) {
- localVarQueryParameter['albumId'] = albumId;
- }
-
- if (userId !== undefined) {
- localVarQueryParameter['userId'] = userId;
- }
-
- if (archiveSize !== undefined) {
- localVarQueryParameter['archiveSize'] = archiveSize;
- }
-
if (key !== undefined) {
localVarQueryParameter['key'] = key;
}
+ localVarHeaderParameter['Content-Type'] = 'application/json';
+
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ localVarRequestOptions.data = serializeDataIfNeeded(downloadInfoDto, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
@@ -6141,16 +6158,13 @@ export const AssetApiFp = function(configuration?: Configuration) {
},
/**
*
- * @param {Array} [assetIds]
- * @param {string} [albumId]
- * @param {string} [userId]
- * @param {number} [archiveSize]
+ * @param {DownloadInfoDto} downloadInfoDto
* @param {string} [key]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async getDownloadInfo(assetIds?: Array, albumId?: string, userId?: string, archiveSize?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
- const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(assetIds, albumId, userId, archiveSize, key, options);
+ async getDownloadInfo(downloadInfoDto: DownloadInfoDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(downloadInfoDto, key, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
@@ -6406,8 +6420,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest = {}, options?: AxiosRequestConfig): AxiosPromise {
- return localVarFp.getDownloadInfo(requestParameters.assetIds, requestParameters.albumId, requestParameters.userId, requestParameters.archiveSize, requestParameters.key, options).then((request) => request(axios, basePath));
+ getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest, options?: AxiosRequestConfig): AxiosPromise {
+ return localVarFp.getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
},
/**
*
@@ -6788,31 +6802,10 @@ export interface AssetApiGetByTimeBucketRequest {
export interface AssetApiGetDownloadInfoRequest {
/**
*
- * @type {Array}
+ * @type {DownloadInfoDto}
* @memberof AssetApiGetDownloadInfo
*/
- readonly assetIds?: Array
-
- /**
- *
- * @type {string}
- * @memberof AssetApiGetDownloadInfo
- */
- readonly albumId?: string
-
- /**
- *
- * @type {string}
- * @memberof AssetApiGetDownloadInfo
- */
- readonly userId?: string
-
- /**
- *
- * @type {number}
- * @memberof AssetApiGetDownloadInfo
- */
- readonly archiveSize?: number
+ readonly downloadInfoDto: DownloadInfoDto
/**
*
@@ -7281,8 +7274,8 @@ export class AssetApi extends BaseAPI {
* @throws {RequiredError}
* @memberof AssetApi
*/
- public getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest = {}, options?: AxiosRequestConfig) {
- return AssetApiFp(this.configuration).getDownloadInfo(requestParameters.assetIds, requestParameters.albumId, requestParameters.userId, requestParameters.archiveSize, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
+ public getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest, options?: AxiosRequestConfig) {
+ return AssetApiFp(this.configuration).getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
}
/**
diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES
index ea0993be8..bf485ef08 100644
--- a/mobile/openapi/.openapi-generator/FILES
+++ b/mobile/openapi/.openapi-generator/FILES
@@ -45,6 +45,7 @@ doc/DeleteAssetDto.md
doc/DeleteAssetResponseDto.md
doc/DeleteAssetStatus.md
doc/DownloadArchiveInfo.md
+doc/DownloadInfoDto.md
doc/DownloadResponseDto.md
doc/ExifResponseDto.md
doc/ImportAssetDto.md
@@ -186,6 +187,7 @@ lib/model/delete_asset_dto.dart
lib/model/delete_asset_response_dto.dart
lib/model/delete_asset_status.dart
lib/model/download_archive_info.dart
+lib/model/download_info_dto.dart
lib/model/download_response_dto.dart
lib/model/exif_response_dto.dart
lib/model/import_asset_dto.dart
@@ -298,6 +300,7 @@ test/delete_asset_dto_test.dart
test/delete_asset_response_dto_test.dart
test/delete_asset_status_test.dart
test/download_archive_info_test.dart
+test/download_info_dto_test.dart
test/download_response_dto_test.dart
test/exif_response_dto_test.dart
test/import_asset_dto_test.dart
diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md
index 1e20582fa..9167613b2 100644
--- a/mobile/openapi/README.md
+++ b/mobile/openapi/README.md
@@ -91,7 +91,7 @@ Class | Method | HTTP request | Description
*AssetApi* | [**checkDuplicateAsset**](doc//AssetApi.md#checkduplicateasset) | **POST** /asset/check |
*AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist |
*AssetApi* | [**deleteAsset**](doc//AssetApi.md#deleteasset) | **DELETE** /asset |
-*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download |
+*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
*AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |
*AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
@@ -101,7 +101,7 @@ Class | Method | HTTP request | Description
*AssetApi* | [**getByTimeBucket**](doc//AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket |
*AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
*AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
-*AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **GET** /asset/download |
+*AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
*AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
*AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
*AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
@@ -216,6 +216,7 @@ Class | Method | HTTP request | Description
- [DeleteAssetResponseDto](doc//DeleteAssetResponseDto.md)
- [DeleteAssetStatus](doc//DeleteAssetStatus.md)
- [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
+ - [DownloadInfoDto](doc//DownloadInfoDto.md)
- [DownloadResponseDto](doc//DownloadResponseDto.md)
- [ExifResponseDto](doc//ExifResponseDto.md)
- [ImportAssetDto](doc//ImportAssetDto.md)
diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md
index 2999f2de2..5c1c7bb4b 100644
--- a/mobile/openapi/doc/AssetApi.md
+++ b/mobile/openapi/doc/AssetApi.md
@@ -13,7 +13,7 @@ Method | HTTP request | Description
[**checkDuplicateAsset**](AssetApi.md#checkduplicateasset) | **POST** /asset/check |
[**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist |
[**deleteAsset**](AssetApi.md#deleteasset) | **DELETE** /asset |
-[**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download |
+[**downloadArchive**](AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
[**downloadFile**](AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
[**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset |
[**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
@@ -23,7 +23,7 @@ Method | HTTP request | Description
[**getByTimeBucket**](AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket |
[**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
[**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
-[**getDownloadInfo**](AssetApi.md#getdownloadinfo) | **GET** /asset/download |
+[**getDownloadInfo**](AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
[**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
[**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
[**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
@@ -842,7 +842,7 @@ This endpoint does not need any parameter.
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
# **getDownloadInfo**
-> DownloadResponseDto getDownloadInfo(assetIds, albumId, userId, archiveSize, key)
+> DownloadResponseDto getDownloadInfo(downloadInfoDto, key)
@@ -865,14 +865,11 @@ import 'package:openapi/api.dart';
//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction);
final api_instance = AssetApi();
-final assetIds = []; // List |
-final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
-final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String |
-final archiveSize = 8.14; // num |
+final downloadInfoDto = DownloadInfoDto(); // DownloadInfoDto |
final key = key_example; // String |
try {
- final result = api_instance.getDownloadInfo(assetIds, albumId, userId, archiveSize, key);
+ final result = api_instance.getDownloadInfo(downloadInfoDto, key);
print(result);
} catch (e) {
print('Exception when calling AssetApi->getDownloadInfo: $e\n');
@@ -883,10 +880,7 @@ try {
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
- **assetIds** | [**List**](String.md)| | [optional] [default to const []]
- **albumId** | **String**| | [optional]
- **userId** | **String**| | [optional]
- **archiveSize** | **num**| | [optional]
+ **downloadInfoDto** | [**DownloadInfoDto**](DownloadInfoDto.md)| |
**key** | **String**| | [optional]
### Return type
@@ -899,7 +893,7 @@ Name | Type | Description | Notes
### HTTP request headers
- - **Content-Type**: Not defined
+ - **Content-Type**: application/json
- **Accept**: application/json
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
diff --git a/mobile/openapi/doc/DownloadInfoDto.md b/mobile/openapi/doc/DownloadInfoDto.md
new file mode 100644
index 000000000..14d5d1e71
--- /dev/null
+++ b/mobile/openapi/doc/DownloadInfoDto.md
@@ -0,0 +1,18 @@
+# openapi.model.DownloadInfoDto
+
+## Load the model package
+```dart
+import 'package:openapi/api.dart';
+```
+
+## Properties
+Name | Type | Description | Notes
+------------ | ------------- | ------------- | -------------
+**albumId** | **String** | | [optional]
+**archiveSize** | **int** | | [optional]
+**assetIds** | **List** | | [optional] [default to const []]
+**userId** | **String** | | [optional]
+
+[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
+
+
diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart
index 644244a10..a38d8784e 100644
--- a/mobile/openapi/lib/api.dart
+++ b/mobile/openapi/lib/api.dart
@@ -81,6 +81,7 @@ part 'model/delete_asset_dto.dart';
part 'model/delete_asset_response_dto.dart';
part 'model/delete_asset_status.dart';
part 'model/download_archive_info.dart';
+part 'model/download_info_dto.dart';
part 'model/download_response_dto.dart';
part 'model/exif_response_dto.dart';
part 'model/import_asset_dto.dart';
diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart
index 6f4c391bf..ba9f1d5a1 100644
--- a/mobile/openapi/lib/api/asset_api.dart
+++ b/mobile/openapi/lib/api/asset_api.dart
@@ -230,7 +230,7 @@ class AssetApi {
return null;
}
- /// Performs an HTTP 'POST /asset/download' operation and returns the [Response].
+ /// Performs an HTTP 'POST /asset/download/archive' operation and returns the [Response].
/// Parameters:
///
/// * [AssetIdsDto] assetIdsDto (required):
@@ -238,7 +238,7 @@ class AssetApi {
/// * [String] key:
Future downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async {
// ignore: prefer_const_declarations
- final path = r'/asset/download';
+ final path = r'/asset/download/archive';
// ignore: prefer_final_locals
Object? postBody = assetIdsDto;
@@ -853,51 +853,33 @@ class AssetApi {
return null;
}
- /// Performs an HTTP 'GET /asset/download' operation and returns the [Response].
+ /// Performs an HTTP 'POST /asset/download/info' operation and returns the [Response].
/// Parameters:
///
- /// * [List] assetIds:
- ///
- /// * [String] albumId:
- ///
- /// * [String] userId:
- ///
- /// * [num] archiveSize:
+ /// * [DownloadInfoDto] downloadInfoDto (required):
///
/// * [String] key:
- Future getDownloadInfoWithHttpInfo({ List? assetIds, String? albumId, String? userId, num? archiveSize, String? key, }) async {
+ Future getDownloadInfoWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
// ignore: prefer_const_declarations
- final path = r'/asset/download';
+ final path = r'/asset/download/info';
// ignore: prefer_final_locals
- Object? postBody;
+ Object? postBody = downloadInfoDto;
final queryParams = [];
final headerParams = {};
final formParams = {};
- if (assetIds != null) {
- queryParams.addAll(_queryParams('multi', 'assetIds', assetIds));
- }
- if (albumId != null) {
- queryParams.addAll(_queryParams('', 'albumId', albumId));
- }
- if (userId != null) {
- queryParams.addAll(_queryParams('', 'userId', userId));
- }
- if (archiveSize != null) {
- queryParams.addAll(_queryParams('', 'archiveSize', archiveSize));
- }
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
- const contentTypes = [];
+ const contentTypes = ['application/json'];
return apiClient.invokeAPI(
path,
- 'GET',
+ 'POST',
queryParams,
postBody,
headerParams,
@@ -908,17 +890,11 @@ class AssetApi {
/// Parameters:
///
- /// * [List] assetIds:
- ///
- /// * [String] albumId:
- ///
- /// * [String] userId:
- ///
- /// * [num] archiveSize:
+ /// * [DownloadInfoDto] downloadInfoDto (required):
///
/// * [String] key:
- Future getDownloadInfo({ List? assetIds, String? albumId, String? userId, num? archiveSize, String? key, }) async {
- final response = await getDownloadInfoWithHttpInfo( assetIds: assetIds, albumId: albumId, userId: userId, archiveSize: archiveSize, key: key, );
+ Future getDownloadInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
+ final response = await getDownloadInfoWithHttpInfo(downloadInfoDto, key: key, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart
index fd1252cc7..eb76c12c5 100644
--- a/mobile/openapi/lib/api_client.dart
+++ b/mobile/openapi/lib/api_client.dart
@@ -257,6 +257,8 @@ class ApiClient {
return DeleteAssetStatusTypeTransformer().decode(value);
case 'DownloadArchiveInfo':
return DownloadArchiveInfo.fromJson(value);
+ case 'DownloadInfoDto':
+ return DownloadInfoDto.fromJson(value);
case 'DownloadResponseDto':
return DownloadResponseDto.fromJson(value);
case 'ExifResponseDto':
diff --git a/mobile/openapi/lib/model/download_info_dto.dart b/mobile/openapi/lib/model/download_info_dto.dart
new file mode 100644
index 000000000..fa3a06eea
--- /dev/null
+++ b/mobile/openapi/lib/model/download_info_dto.dart
@@ -0,0 +1,150 @@
+//
+// AUTO-GENERATED FILE, DO NOT MODIFY!
+//
+// @dart=2.12
+
+// ignore_for_file: unused_element, unused_import
+// ignore_for_file: always_put_required_named_parameters_first
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: lines_longer_than_80_chars
+
+part of openapi.api;
+
+class DownloadInfoDto {
+ /// Returns a new [DownloadInfoDto] instance.
+ DownloadInfoDto({
+ this.albumId,
+ this.archiveSize,
+ this.assetIds = const [],
+ this.userId,
+ });
+
+ ///
+ /// Please note: This property should have been non-nullable! Since the specification file
+ /// does not include a default value (using the "default:" property), however, the generated
+ /// source code must fall back to having a nullable type.
+ /// Consider adding a "default:" property in the specification file to hide this note.
+ ///
+ String? albumId;
+
+ ///
+ /// Please note: This property should have been non-nullable! Since the specification file
+ /// does not include a default value (using the "default:" property), however, the generated
+ /// source code must fall back to having a nullable type.
+ /// Consider adding a "default:" property in the specification file to hide this note.
+ ///
+ int? archiveSize;
+
+ List assetIds;
+
+ ///
+ /// Please note: This property should have been non-nullable! Since the specification file
+ /// does not include a default value (using the "default:" property), however, the generated
+ /// source code must fall back to having a nullable type.
+ /// Consider adding a "default:" property in the specification file to hide this note.
+ ///
+ String? userId;
+
+ @override
+ bool operator ==(Object other) => identical(this, other) || other is DownloadInfoDto &&
+ other.albumId == albumId &&
+ other.archiveSize == archiveSize &&
+ other.assetIds == assetIds &&
+ other.userId == userId;
+
+ @override
+ int get hashCode =>
+ // ignore: unnecessary_parenthesis
+ (albumId == null ? 0 : albumId!.hashCode) +
+ (archiveSize == null ? 0 : archiveSize!.hashCode) +
+ (assetIds.hashCode) +
+ (userId == null ? 0 : userId!.hashCode);
+
+ @override
+ String toString() => 'DownloadInfoDto[albumId=$albumId, archiveSize=$archiveSize, assetIds=$assetIds, userId=$userId]';
+
+ Map toJson() {
+ final json = {};
+ if (this.albumId != null) {
+ json[r'albumId'] = this.albumId;
+ } else {
+ // json[r'albumId'] = null;
+ }
+ if (this.archiveSize != null) {
+ json[r'archiveSize'] = this.archiveSize;
+ } else {
+ // json[r'archiveSize'] = null;
+ }
+ json[r'assetIds'] = this.assetIds;
+ if (this.userId != null) {
+ json[r'userId'] = this.userId;
+ } else {
+ // json[r'userId'] = null;
+ }
+ return json;
+ }
+
+ /// Returns a new [DownloadInfoDto] instance and imports its values from
+ /// [value] if it's a [Map], null otherwise.
+ // ignore: prefer_constructors_over_static_methods
+ static DownloadInfoDto? fromJson(dynamic value) {
+ if (value is Map) {
+ final json = value.cast();
+
+ return DownloadInfoDto(
+ albumId: mapValueOfType(json, r'albumId'),
+ archiveSize: mapValueOfType(json, r'archiveSize'),
+ assetIds: json[r'assetIds'] is List
+ ? (json[r'assetIds'] as List).cast()
+ : const [],
+ userId: mapValueOfType(json, r'userId'),
+ );
+ }
+ return null;
+ }
+
+ static List listFromJson(dynamic json, {bool growable = false,}) {
+ final result = [];
+ if (json is List && json.isNotEmpty) {
+ for (final row in json) {
+ final value = DownloadInfoDto.fromJson(row);
+ if (value != null) {
+ result.add(value);
+ }
+ }
+ }
+ return result.toList(growable: growable);
+ }
+
+ static Map mapFromJson(dynamic json) {
+ final map = {};
+ if (json is Map && json.isNotEmpty) {
+ json = json.cast(); // ignore: parameter_assignments
+ for (final entry in json.entries) {
+ final value = DownloadInfoDto.fromJson(entry.value);
+ if (value != null) {
+ map[entry.key] = value;
+ }
+ }
+ }
+ return map;
+ }
+
+ // maps a json object with a list of DownloadInfoDto-objects as value to a dart map
+ static Map> mapListFromJson(dynamic json, {bool growable = false,}) {
+ final map = >{};
+ if (json is Map && json.isNotEmpty) {
+ // ignore: parameter_assignments
+ json = json.cast();
+ for (final entry in json.entries) {
+ map[entry.key] = DownloadInfoDto.listFromJson(entry.value, growable: growable,);
+ }
+ }
+ return map;
+ }
+
+ /// The list of required keys that must be present in a JSON.
+ static const requiredKeys = {
+ };
+}
+
diff --git a/mobile/openapi/test/asset_api_test.dart b/mobile/openapi/test/asset_api_test.dart
index 588902a14..ebb472c4a 100644
--- a/mobile/openapi/test/asset_api_test.dart
+++ b/mobile/openapi/test/asset_api_test.dart
@@ -97,7 +97,7 @@ void main() {
// TODO
});
- //Future getDownloadInfo({ List assetIds, String albumId, String userId, num archiveSize, String key }) async
+ //Future getDownloadInfo(DownloadInfoDto downloadInfoDto, { String key }) async
test('test getDownloadInfo', () async {
// TODO
});
diff --git a/mobile/openapi/test/download_info_dto_test.dart b/mobile/openapi/test/download_info_dto_test.dart
new file mode 100644
index 000000000..5efd4e11e
--- /dev/null
+++ b/mobile/openapi/test/download_info_dto_test.dart
@@ -0,0 +1,42 @@
+//
+// AUTO-GENERATED FILE, DO NOT MODIFY!
+//
+// @dart=2.12
+
+// ignore_for_file: unused_element, unused_import
+// ignore_for_file: always_put_required_named_parameters_first
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: lines_longer_than_80_chars
+
+import 'package:openapi/api.dart';
+import 'package:test/test.dart';
+
+// tests for DownloadInfoDto
+void main() {
+ // final instance = DownloadInfoDto();
+
+ group('test DownloadInfoDto', () {
+ // String albumId
+ test('to test the property `albumId`', () async {
+ // TODO
+ });
+
+ // int archiveSize
+ test('to test the property `archiveSize`', () async {
+ // TODO
+ });
+
+ // List assetIds (default value: const [])
+ test('to test the property `assetIds`', () async {
+ // TODO
+ });
+
+ // String userId
+ test('to test the property `userId`', () async {
+ // TODO
+ });
+
+
+ });
+
+}
diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json
index 59543353f..f193eb25e 100644
--- a/server/immich-openapi-specs.json
+++ b/server/immich-openapi-specs.json
@@ -1026,84 +1026,7 @@
]
}
},
- "/asset/download": {
- "get": {
- "operationId": "getDownloadInfo",
- "parameters": [
- {
- "name": "assetIds",
- "required": false,
- "in": "query",
- "schema": {
- "format": "uuid",
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- },
- {
- "name": "albumId",
- "required": false,
- "in": "query",
- "schema": {
- "format": "uuid",
- "type": "string"
- }
- },
- {
- "name": "userId",
- "required": false,
- "in": "query",
- "schema": {
- "format": "uuid",
- "type": "string"
- }
- },
- {
- "name": "archiveSize",
- "required": false,
- "in": "query",
- "schema": {
- "type": "number"
- }
- },
- {
- "name": "key",
- "required": false,
- "in": "query",
- "schema": {
- "type": "string"
- }
- }
- ],
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/DownloadResponseDto"
- }
- }
- },
- "description": ""
- }
- },
- "security": [
- {
- "bearer": []
- },
- {
- "cookie": []
- },
- {
- "api_key": []
- }
- ],
- "tags": [
- "Asset"
- ]
- },
+ "/asset/download/archive": {
"post": {
"operationId": "downloadArchive",
"parameters": [
@@ -1155,6 +1078,57 @@
]
}
},
+ "/asset/download/info": {
+ "post": {
+ "operationId": "getDownloadInfo",
+ "parameters": [
+ {
+ "name": "key",
+ "required": false,
+ "in": "query",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DownloadInfoDto"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DownloadResponseDto"
+ }
+ }
+ },
+ "description": ""
+ }
+ },
+ "security": [
+ {
+ "bearer": []
+ },
+ {
+ "cookie": []
+ },
+ {
+ "api_key": []
+ }
+ ],
+ "tags": [
+ "Asset"
+ ]
+ }
+ },
"/asset/download/{id}": {
"post": {
"operationId": "downloadFile",
@@ -5549,6 +5523,29 @@
],
"type": "object"
},
+ "DownloadInfoDto": {
+ "properties": {
+ "albumId": {
+ "format": "uuid",
+ "type": "string"
+ },
+ "archiveSize": {
+ "type": "integer"
+ },
+ "assetIds": {
+ "items": {
+ "format": "uuid",
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "userId": {
+ "format": "uuid",
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
"DownloadResponseDto": {
"properties": {
"archives": {
diff --git a/server/src/domain/asset/asset.service.ts b/server/src/domain/asset/asset.service.ts
index fdd6df6ef..ac655b807 100644
--- a/server/src/domain/asset/asset.service.ts
+++ b/server/src/domain/asset/asset.service.ts
@@ -13,7 +13,7 @@ import { IAssetRepository } from './asset.repository';
import {
AssetIdsDto,
DownloadArchiveInfo,
- DownloadDto,
+ DownloadInfoDto,
DownloadResponseDto,
MemoryLaneDto,
TimeBucketAssetDto,
@@ -176,7 +176,7 @@ export class AssetService {
return this.storageRepository.createReadStream(asset.originalPath, mimeTypes.lookup(asset.originalPath));
}
- async getDownloadInfo(authUser: AuthUserDto, dto: DownloadDto): Promise {
+ async getDownloadInfo(authUser: AuthUserDto, dto: DownloadInfoDto): Promise {
const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
const archives: DownloadArchiveInfo[] = [];
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
@@ -234,7 +234,7 @@ export class AssetService {
return { stream: zip.stream };
}
- private async getDownloadAssets(authUser: AuthUserDto, dto: DownloadDto): Promise> {
+ private async getDownloadAssets(authUser: AuthUserDto, dto: DownloadInfoDto): Promise> {
const PAGINATION_SIZE = 2500;
if (dto.assetIds) {
diff --git a/server/src/domain/asset/dto/download.dto.ts b/server/src/domain/asset/dto/download.dto.ts
index c2cf85685..604a8ea5f 100644
--- a/server/src/domain/asset/dto/download.dto.ts
+++ b/server/src/domain/asset/dto/download.dto.ts
@@ -2,7 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsOptional, IsPositive } from 'class-validator';
import { ValidateUUID } from '../../domain.util';
-export class DownloadDto {
+export class DownloadInfoDto {
@ValidateUUID({ each: true, optional: true })
assetIds?: string[];
@@ -15,6 +15,7 @@ export class DownloadDto {
@IsInt()
@IsPositive()
@IsOptional()
+ @ApiProperty({ type: 'integer' })
archiveSize?: number;
}
diff --git a/server/src/immich/controllers/asset.controller.ts b/server/src/immich/controllers/asset.controller.ts
index ba3de02cc..b55cbb870 100644
--- a/server/src/immich/controllers/asset.controller.ts
+++ b/server/src/immich/controllers/asset.controller.ts
@@ -5,7 +5,7 @@ import {
AssetStatsDto,
AssetStatsResponseDto,
AuthUserDto,
- DownloadDto,
+ DownloadInfoDto,
DownloadResponseDto,
MapMarkerResponseDto,
MemoryLaneDto,
@@ -39,13 +39,13 @@ export class AssetController {
}
@SharedLinkRoute()
- @Get('download')
- getDownloadInfo(@AuthUser() authUser: AuthUserDto, @Query() dto: DownloadDto): Promise {
+ @Post('download/info')
+ getDownloadInfo(@AuthUser() authUser: AuthUserDto, @Body() dto: DownloadInfoDto): Promise {
return this.service.getDownloadInfo(authUser, dto);
}
@SharedLinkRoute()
- @Post('download')
+ @Post('download/archive')
@HttpCode(HttpStatus.OK)
@ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } })
downloadArchive(@AuthUser() authUser: AuthUserDto, @Body() dto: AssetIdsDto): Promise {
diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts
index 956f19ba7..8ade1d5fd 100644
--- a/web/src/api/open-api/api.ts
+++ b/web/src/api/open-api/api.ts
@@ -1132,6 +1132,37 @@ export interface DownloadArchiveInfo {
*/
'size': number;
}
+/**
+ *
+ * @export
+ * @interface DownloadInfoDto
+ */
+export interface DownloadInfoDto {
+ /**
+ *
+ * @type {string}
+ * @memberof DownloadInfoDto
+ */
+ 'albumId'?: string;
+ /**
+ *
+ * @type {number}
+ * @memberof DownloadInfoDto
+ */
+ 'archiveSize'?: number;
+ /**
+ *
+ * @type {Array}
+ * @memberof DownloadInfoDto
+ */
+ 'assetIds'?: Array;
+ /**
+ *
+ * @type {string}
+ * @memberof DownloadInfoDto
+ */
+ 'userId'?: string;
+}
/**
*
* @export
@@ -4880,7 +4911,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise => {
// verify required parameter 'assetIdsDto' is not null or undefined
assertParamExists('downloadArchive', 'assetIdsDto', assetIdsDto)
- const localVarPath = `/asset/download`;
+ const localVarPath = `/asset/download/archive`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@@ -5379,16 +5410,15 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
},
/**
*
- * @param {Array} [assetIds]
- * @param {string} [albumId]
- * @param {string} [userId]
- * @param {number} [archiveSize]
+ * @param {DownloadInfoDto} downloadInfoDto
* @param {string} [key]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- getDownloadInfo: async (assetIds?: Array, albumId?: string, userId?: string, archiveSize?: number, key?: string, options: AxiosRequestConfig = {}): Promise => {
- const localVarPath = `/asset/download`;
+ getDownloadInfo: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise => {
+ // verify required parameter 'downloadInfoDto' is not null or undefined
+ assertParamExists('getDownloadInfo', 'downloadInfoDto', downloadInfoDto)
+ const localVarPath = `/asset/download/info`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
@@ -5396,7 +5426,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
baseOptions = configuration.baseOptions;
}
- const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
@@ -5409,31 +5439,18 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
- if (assetIds) {
- localVarQueryParameter['assetIds'] = assetIds;
- }
-
- if (albumId !== undefined) {
- localVarQueryParameter['albumId'] = albumId;
- }
-
- if (userId !== undefined) {
- localVarQueryParameter['userId'] = userId;
- }
-
- if (archiveSize !== undefined) {
- localVarQueryParameter['archiveSize'] = archiveSize;
- }
-
if (key !== undefined) {
localVarQueryParameter['key'] = key;
}
+ localVarHeaderParameter['Content-Type'] = 'application/json';
+
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ localVarRequestOptions.data = serializeDataIfNeeded(downloadInfoDto, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
@@ -6141,16 +6158,13 @@ export const AssetApiFp = function(configuration?: Configuration) {
},
/**
*
- * @param {Array} [assetIds]
- * @param {string} [albumId]
- * @param {string} [userId]
- * @param {number} [archiveSize]
+ * @param {DownloadInfoDto} downloadInfoDto
* @param {string} [key]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async getDownloadInfo(assetIds?: Array, albumId?: string, userId?: string, archiveSize?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
- const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(assetIds, albumId, userId, archiveSize, key, options);
+ async getDownloadInfo(downloadInfoDto: DownloadInfoDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(downloadInfoDto, key, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
@@ -6406,8 +6420,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest = {}, options?: AxiosRequestConfig): AxiosPromise {
- return localVarFp.getDownloadInfo(requestParameters.assetIds, requestParameters.albumId, requestParameters.userId, requestParameters.archiveSize, requestParameters.key, options).then((request) => request(axios, basePath));
+ getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest, options?: AxiosRequestConfig): AxiosPromise {
+ return localVarFp.getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
},
/**
*
@@ -6788,31 +6802,10 @@ export interface AssetApiGetByTimeBucketRequest {
export interface AssetApiGetDownloadInfoRequest {
/**
*
- * @type {Array}
+ * @type {DownloadInfoDto}
* @memberof AssetApiGetDownloadInfo
*/
- readonly assetIds?: Array
-
- /**
- *
- * @type {string}
- * @memberof AssetApiGetDownloadInfo
- */
- readonly albumId?: string
-
- /**
- *
- * @type {string}
- * @memberof AssetApiGetDownloadInfo
- */
- readonly userId?: string
-
- /**
- *
- * @type {number}
- * @memberof AssetApiGetDownloadInfo
- */
- readonly archiveSize?: number
+ readonly downloadInfoDto: DownloadInfoDto
/**
*
@@ -7281,8 +7274,8 @@ export class AssetApi extends BaseAPI {
* @throws {RequiredError}
* @memberof AssetApi
*/
- public getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest = {}, options?: AxiosRequestConfig) {
- return AssetApiFp(this.configuration).getDownloadInfo(requestParameters.assetIds, requestParameters.albumId, requestParameters.userId, requestParameters.archiveSize, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
+ public getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest, options?: AxiosRequestConfig) {
+ return AssetApiFp(this.configuration).getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
}
/**
diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts
index 0a8ff758d..cb29b503a 100644
--- a/web/src/lib/utils/asset-utils.ts
+++ b/web/src/lib/utils/asset-utils.ts
@@ -1,6 +1,6 @@
import { notificationController, NotificationType } from '$lib/components/shared-components/notification/notification';
import { downloadManager } from '$lib/stores/download';
-import { api, AssetApiGetDownloadInfoRequest, BulkIdResponseDto, AssetResponseDto, DownloadResponseDto } from '@api';
+import { api, BulkIdResponseDto, AssetResponseDto, DownloadResponseDto, DownloadInfoDto } from '@api';
import { handleError } from './handle-error';
export const addAssetsToAlbum = async (
@@ -32,15 +32,11 @@ const downloadBlob = (data: Blob, filename: string) => {
URL.revokeObjectURL(url);
};
-export const downloadArchive = async (
- fileName: string,
- options: Omit,
- key?: string,
-) => {
+export const downloadArchive = async (fileName: string, options: DownloadInfoDto, key?: string) => {
let downloadInfo: DownloadResponseDto | null = null;
try {
- const { data } = await api.assetApi.getDownloadInfo({ ...options, key });
+ const { data } = await api.assetApi.getDownloadInfo({ downloadInfoDto: options, key });
downloadInfo = data;
} catch (error) {
handleError(error, 'Unable to download files');
From 74da15e20d353e9c0cc0221a791962454f6abf90 Mon Sep 17 00:00:00 2001
From: Sergey Kondrikov
Date: Tue, 15 Aug 2023 19:02:38 +0300
Subject: [PATCH 12/22] fix(web,server): disable partner's archive access
(#3695)
---
server/src/domain/access/access.core.ts | 5 +++++
server/src/domain/asset/asset.service.ts | 3 +++
web/src/routes/(user)/partners/[userId]/+page.svelte | 2 +-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/server/src/domain/access/access.core.ts b/server/src/domain/access/access.core.ts
index d81561236..3e3d4a469 100644
--- a/server/src/domain/access/access.core.ts
+++ b/server/src/domain/access/access.core.ts
@@ -19,6 +19,8 @@ export enum Permission {
ALBUM_SHARE = 'album.share',
ALBUM_DOWNLOAD = 'album.download',
+ ARCHIVE_READ = 'archive.read',
+
LIBRARY_READ = 'library.read',
LIBRARY_DOWNLOAD = 'library.download',
}
@@ -156,6 +158,9 @@ export class AccessCore {
case Permission.ALBUM_REMOVE_ASSET:
return this.repository.album.hasOwnerAccess(authUser.id, id);
+ case Permission.ARCHIVE_READ:
+ return authUser.id === id;
+
case Permission.LIBRARY_READ:
return authUser.id === id || (await this.repository.library.hasPartnerAccess(authUser.id, id));
diff --git a/server/src/domain/asset/asset.service.ts b/server/src/domain/asset/asset.service.ts
index ac655b807..2d4051b0f 100644
--- a/server/src/domain/asset/asset.service.ts
+++ b/server/src/domain/asset/asset.service.ts
@@ -148,6 +148,9 @@ export class AssetService {
if (dto.albumId) {
await this.access.requirePermission(authUser, Permission.ALBUM_READ, [dto.albumId]);
} else if (dto.userId) {
+ if (dto.isArchived !== false) {
+ await this.access.requirePermission(authUser, Permission.ARCHIVE_READ, [dto.userId]);
+ }
await this.access.requirePermission(authUser, Permission.LIBRARY_READ, [dto.userId]);
} else {
dto.userId = authUser.id;
diff --git a/web/src/routes/(user)/partners/[userId]/+page.svelte b/web/src/routes/(user)/partners/[userId]/+page.svelte
index c7fd51f2a..adc718e91 100644
--- a/web/src/routes/(user)/partners/[userId]/+page.svelte
+++ b/web/src/routes/(user)/partners/[userId]/+page.svelte
@@ -18,7 +18,7 @@
export let data: PageData;
- const assetStore = new AssetStore({ size: TimeBucketSize.Month, userId: data.partner.id });
+ const assetStore = new AssetStore({ size: TimeBucketSize.Month, userId: data.partner.id, isArchived: false });
const assetInteractionStore = createAssetInteractionStore();
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
From 35b4c9d3754b37d95685e1ac58dbe69974ec17f8 Mon Sep 17 00:00:00 2001
From: Vantao
Date: Wed, 16 Aug 2023 00:05:00 +0800
Subject: [PATCH 13/22] doc: update README_zh_CN.md (#3701)
---
README_zh_CN.md | 83 ++++++++++++++++++++++++-------------------------
1 file changed, 40 insertions(+), 43 deletions(-)
diff --git a/README_zh_CN.md b/README_zh_CN.md
index 10a946eee..d018a4a28 100644
--- a/README_zh_CN.md
+++ b/README_zh_CN.md
@@ -13,7 +13,7 @@
Immich - 高性能的自托管照片和视频备份方案
-请注意: 此README不是由Immich团队维护, 这意味着它在某一时间点不会被更新,因为我们是依靠贡献者来更新的。感谢理解。
+请注意: 此 README 不是由 Immich 团队维护, 而是依靠贡献者来更新的,这意味着它可能并不会被及时更新。感谢理解。
@@ -31,29 +31,31 @@
## 免责声明
-- ⚠️ 本项目正在 **非常活跃** 的开发中。
-- ⚠️ 可能存在bug或者重大变更。
-- ⚠️ **不要把本软件作为你存储照片或视频的唯一方式!**
+- ⚠️ 本项目正在 **非常活跃** 地开发中。
+- ⚠️ 可能存在 bug 或者随时有重大变更。
+- ⚠️ **不要把本软件作为您存储照片或视频的唯一方式。**
+- ⚠️ 为了您宝贵的照片与视频,始终遵守 [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) 备份方案!
## 目录
-- [官方文档](https://immich.app/docs/overview/introduction)
+- [官方文档](https://immich.app/docs)
+- [路线图](https://github.com/orgs/immich-app/projects/1)
- [示例](#示例)
- [功能特性](#功能特性)
- [介绍](https://immich.app/docs/overview/introduction)
- [安装](https://immich.app/docs/install/requirements)
- [贡献指南](https://immich.app/docs/overview/support-the-project)
-- [支持本项目](#support-the-project)
-- [已知问题](#known-issues)
+- [支持本项目](#支持本项目)
## 官方文档
-你可以在 https://immich.app/ 找到包含安装手册的官方文档.
+您可以在 https://immich.app/ 找到官方文档(包含安装手册)。
+
## 示例
-你可以在 https://demo.immich.app 访问示例.
+您可以在 https://demo.immich.app 访问示例。
-在移动端, 你可以使用 `https://demo.immich.app/api`获取`服务终端链接`
+在移动端, 您可以使用 `https://demo.immich.app/api` 获取 `服务终端链接`
```bash title="示例认证信息"
认证信息
@@ -62,57 +64,52 @@
```
```
-规格: 甲骨文免费虚拟机套餐-阿姆斯特丹 4核 2.4Ghz ARM64 CPU, 24GB RAM。
+规格: 甲骨文免费虚拟机套餐——阿姆斯特丹 4核 2.4Ghz ARM64 CPU, 24GB RAM。
```
# 功能特性
| 功能特性 | 移动端 | 网页端 |
| ------------------------------------------- | ------- | --- |
-| 上传并查看照片和视频 | 是 | 是 |
-| 软件运行时自动备份 | 是 | N/A |
+| 上传并查看照片和视频 | 是 | 是 |
+| 软件运行时自动备份 | 是 | N/A |
| 选择需要备份的相册 | 是 | N/A |
-| 下载照片和视频到本地 | 是 | 是 |
+| 下载照片和视频到本地 | 是 | 是 |
| 多用户支持 | 是 | 是 |
| 相册 | 是 | 是 |
| 共享相册 | 是 | 是 |
| 可拖动的快速导航栏 | 是 | 是 |
| 支持RAW格式 (HEIC, HEIF, DNG, Apple ProRaw) | 是 | 是 |
-| 元数据视图 (EXIF, 地图) | 是 | 是 |
-| 通过元数据、对象和标签进行搜索 | 是 | No |
-| 管理功能 (用户管理) | N/A | 是 |
-| 后台备份 | Android | N/A |
+| 元数据视图(EXIF, 地图) | 是 | 是 |
+| 通过元数据、对象和标签进行搜索 | 是 | 是 |
+| 管理功能(用户管理) | 否 | 是 |
+| 后台备份 | 是 | N/A |
| 虚拟滚动 | 是 | 是 |
-| OAuth支持 | 是 | 是 |
-| 实时照片备份和查看 (仅iOS) | 是 | 是 |
+| OAuth 支持 | 是 | 是 |
+| API Keys|N/A|是|
+| 实况照片备份和查看 | 仅 iOS | 是 |
+|用户自定义存储结构|是|是|
+|公共分享|否|是|
+|归档与收藏功能|是|是|
+|全局地图|否|是|
+|好友分享|是|是|
+|人像识别与分组|是|是|
+|回忆(那年今日)|是|是|
+|离线支持|是|否|
+|只读相册|是|是|
# 支持本项目
-我已经致力于本项目并且将我会持续更新文档、新增功能和修复问题。但是我不能一个人走下去,所以我需要你给予我走下去的动力。
+我已经致力于本项目并且将我会持续更新文档、新增功能和修复问题。但是独木不成林,我需要您给予我坚持下去的动力。
-就像我主页里面 [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418) 说的一样,这是我和团队的一项艰巨的任务。我希望某一天我能够全职开发本项目,在此我希望你们能够助我梦想成真。
+就像我在 [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418) 节目里说的一样,这是我和团队的一项艰巨任务。并且我希望某一天我能够全职开发本项目,在此我请求您能够助我梦想成真。
-如果你使用了本项目一段时间,并且觉得上面的话有道理,那么请你按照如下方式帮助我吧。
+如果您使用了本项目一段时间,并且觉得上面的话有道理,那么请您考虑通过下列任一方式支持我吧。
## 捐赠
-- [按月捐赠](https://github.com/sponsors/alextran1502) via GitHub Sponsors
-- [一次捐赠](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502) via Github Sponsors
-
-# 已知问题
-
-## TensorFlow 构建问题
-
-_这是一个针对于Proxmox的已知问题_
-
-TensorFlow 不能运行在很旧的CPU架构上, 需要运行在AVX和AVX2指令集的CPU上。如果你在docker-compose的命令行中遇到了 `illegal instruction core dump`的错误, 通过如下命令检查你的CPU flag寄存器然后确保你能够看到`AVX`和`AVX2`的字样:
-
-```bash
-more /proc/cpuinfo | grep flags
-```
-
-如果你在Proxmox中运行虚拟机, 虚拟机中没有启用flag寄存器。
-
-你需要在虚拟机的硬件面板中把CPU类型从`kvm64`改为`host`。
-
-`Hardware > Processors > Edit > Advanced > Type (dropdown menu) > host`
+- 通过 GitHub Sponsors [按月捐赠](https://github.com/sponsors/alextran1502)
+- 通过 Github Sponsors [单次捐赠](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502)
+- [Librepay](https://liberapay.com/alex.tran1502/)
+- [buymeacoffee](https://www.buymeacoffee.com/altran1502)
+- 比特币: 1FvEp6P6NM8EZEkpGUFAN2LqJ1gxusNxZX
From af1f00dff94a7f09ac76f28fec2f5c250aa6d558 Mon Sep 17 00:00:00 2001
From: Jason Rasmussen
Date: Tue, 15 Aug 2023 12:05:32 -0400
Subject: [PATCH 14/22] chore(server): cleanup (#3699)
---
server/src/domain/server-info/server-info.service.ts | 6 +++---
server/src/domain/user/user.core.ts | 1 -
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/server/src/domain/server-info/server-info.service.ts b/server/src/domain/server-info/server-info.service.ts
index ceeb85e29..4a7e7f22b 100644
--- a/server/src/domain/server-info/server-info.service.ts
+++ b/server/src/domain/server-info/server-info.service.ts
@@ -69,9 +69,9 @@ export class ServerInfoService {
getSupportedMediaTypes(): ServerMediaTypesResponseDto {
return {
- video: [...Object.keys(mimeTypes.video)],
- image: [...Object.keys(mimeTypes.image)],
- sidecar: [...Object.keys(mimeTypes.sidecar)],
+ video: Object.keys(mimeTypes.video),
+ image: Object.keys(mimeTypes.image),
+ sidecar: Object.keys(mimeTypes.sidecar),
};
}
}
diff --git a/server/src/domain/user/user.core.ts b/server/src/domain/user/user.core.ts
index 6c59d9ca7..e7c0f7f2b 100644
--- a/server/src/domain/user/user.core.ts
+++ b/server/src/domain/user/user.core.ts
@@ -60,7 +60,6 @@ export class UserCore {
dto.externalPath = null;
}
- console.log(dto.memoriesEnabled);
return this.userRepository.update(id, dto);
} catch (e) {
Logger.error(e, 'Failed to update user info');
From 0abbd85134035b04ec3b980661e9b497d63394e0 Mon Sep 17 00:00:00 2001
From: Jason Rasmussen
Date: Tue, 15 Aug 2023 14:34:02 -0400
Subject: [PATCH 15/22] fix(web,server): album share performance (#3698)
---
server/src/domain/album/album.repository.ts | 6 ++-
server/src/domain/album/album.service.spec.ts | 7 +--
server/src/domain/album/album.service.ts | 24 +++++-----
.../infra/repositories/album.repository.ts | 44 ++++++++++---------
.../(user)/albums/[albumId]/+page.svelte | 6 +--
5 files changed, 47 insertions(+), 40 deletions(-)
diff --git a/server/src/domain/album/album.repository.ts b/server/src/domain/album/album.repository.ts
index 811b85ec9..bc6fa3752 100644
--- a/server/src/domain/album/album.repository.ts
+++ b/server/src/domain/album/album.repository.ts
@@ -7,8 +7,12 @@ export interface AlbumAssetCount {
assetCount: number;
}
+export interface AlbumInfoOptions {
+ withAssets: boolean;
+}
+
export interface IAlbumRepository {
- getById(id: string): Promise;
+ getById(id: string, options: AlbumInfoOptions): Promise;
getByIds(ids: string[]): Promise;
getByAssetId(ownerId: string, assetId: string): Promise;
hasAsset(id: string, assetId: string): Promise;
diff --git a/server/src/domain/album/album.service.spec.ts b/server/src/domain/album/album.service.spec.ts
index 463d94d7f..f9ab15374 100644
--- a/server/src/domain/album/album.service.spec.ts
+++ b/server/src/domain/album/album.service.spec.ts
@@ -364,6 +364,7 @@ describe(AlbumService.name, () => {
updatedAt: expect.any(Date),
sharedUsers: [],
});
+ expect(albumMock.getById).toHaveBeenCalledWith(albumStub.sharedWithUser.id, { withAssets: false });
});
it('should prevent removing a shared user from a not-owned album (shared with auth user)', async () => {
@@ -432,7 +433,7 @@ describe(AlbumService.name, () => {
await sut.get(authStub.admin, albumStub.oneAsset.id, {});
- expect(albumMock.getById).toHaveBeenCalledWith(albumStub.oneAsset.id);
+ expect(albumMock.getById).toHaveBeenCalledWith(albumStub.oneAsset.id, { withAssets: true });
expect(accessMock.album.hasOwnerAccess).toHaveBeenCalledWith(authStub.admin.id, albumStub.oneAsset.id);
});
@@ -442,7 +443,7 @@ describe(AlbumService.name, () => {
await sut.get(authStub.adminSharedLink, 'album-123', {});
- expect(albumMock.getById).toHaveBeenCalledWith('album-123');
+ expect(albumMock.getById).toHaveBeenCalledWith('album-123', { withAssets: true });
expect(accessMock.album.hasSharedLinkAccess).toHaveBeenCalledWith(
authStub.adminSharedLink.sharedLinkId,
'album-123',
@@ -455,7 +456,7 @@ describe(AlbumService.name, () => {
await sut.get(authStub.user1, 'album-123', {});
- expect(albumMock.getById).toHaveBeenCalledWith('album-123');
+ expect(albumMock.getById).toHaveBeenCalledWith('album-123', { withAssets: true });
expect(accessMock.album.hasSharedAlbumAccess).toHaveBeenCalledWith(authStub.user1.id, 'album-123');
});
diff --git a/server/src/domain/album/album.service.ts b/server/src/domain/album/album.service.ts
index 925b87ac9..71c11d935 100644
--- a/server/src/domain/album/album.service.ts
+++ b/server/src/domain/album/album.service.ts
@@ -12,7 +12,7 @@ import {
mapAlbumWithAssets,
mapAlbumWithoutAssets,
} from './album-response.dto';
-import { IAlbumRepository } from './album.repository';
+import { AlbumInfoOptions, IAlbumRepository } from './album.repository';
import { AddUsersDto, AlbumInfoDto, CreateAlbumDto, GetAlbumsDto, UpdateAlbumDto } from './dto';
@Injectable()
@@ -84,7 +84,7 @@ export class AlbumService {
async get(authUser: AuthUserDto, id: string, dto: AlbumInfoDto) {
await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
await this.albumRepository.updateThumbnails();
- return mapAlbum(await this.findOrFail(id), !dto.withoutAssets);
+ return mapAlbum(await this.findOrFail(id, { withAssets: true }), !dto.withoutAssets);
}
async create(authUser: AuthUserDto, dto: CreateAlbumDto): Promise {
@@ -111,7 +111,7 @@ export class AlbumService {
async update(authUser: AuthUserDto, id: string, dto: UpdateAlbumDto): Promise {
await this.access.requirePermission(authUser, Permission.ALBUM_UPDATE, id);
- const album = await this.findOrFail(id);
+ const album = await this.findOrFail(id, { withAssets: true });
if (dto.albumThumbnailAssetId) {
const valid = await this.albumRepository.hasAsset(id, dto.albumThumbnailAssetId);
@@ -129,13 +129,13 @@ export class AlbumService {
await this.jobRepository.queue({ name: JobName.SEARCH_INDEX_ALBUM, data: { ids: [updatedAlbum.id] } });
- return mapAlbumWithAssets(updatedAlbum);
+ return mapAlbumWithoutAssets(updatedAlbum);
}
async delete(authUser: AuthUserDto, id: string): Promise {
await this.access.requirePermission(authUser, Permission.ALBUM_DELETE, id);
- const album = await this.albumRepository.getById(id);
+ const album = await this.findOrFail(id, { withAssets: false });
if (!album) {
throw new BadRequestException('Album not found');
}
@@ -145,7 +145,7 @@ export class AlbumService {
}
async addAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise {
- const album = await this.findOrFail(id);
+ const album = await this.findOrFail(id, { withAssets: true });
await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
@@ -181,7 +181,7 @@ export class AlbumService {
}
async removeAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise {
- const album = await this.findOrFail(id);
+ const album = await this.findOrFail(id, { withAssets: true });
await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
@@ -225,7 +225,7 @@ export class AlbumService {
async addUsers(authUser: AuthUserDto, id: string, dto: AddUsersDto): Promise {
await this.access.requirePermission(authUser, Permission.ALBUM_SHARE, id);
- const album = await this.findOrFail(id);
+ const album = await this.findOrFail(id, { withAssets: false });
for (const userId of dto.sharedUserIds) {
const exists = album.sharedUsers.find((user) => user.id === userId);
@@ -247,7 +247,7 @@ export class AlbumService {
updatedAt: new Date(),
sharedUsers: album.sharedUsers,
})
- .then(mapAlbumWithAssets);
+ .then(mapAlbumWithoutAssets);
}
async removeUser(authUser: AuthUserDto, id: string, userId: string | 'me'): Promise {
@@ -255,7 +255,7 @@ export class AlbumService {
userId = authUser.id;
}
- const album = await this.findOrFail(id);
+ const album = await this.findOrFail(id, { withAssets: false });
if (album.ownerId === userId) {
throw new BadRequestException('Cannot remove album owner');
@@ -278,8 +278,8 @@ export class AlbumService {
});
}
- private async findOrFail(id: string) {
- const album = await this.albumRepository.getById(id);
+ private async findOrFail(id: string, options: AlbumInfoOptions) {
+ const album = await this.albumRepository.getById(id, options);
if (!album) {
throw new BadRequestException('Album not found');
}
diff --git a/server/src/infra/repositories/album.repository.ts b/server/src/infra/repositories/album.repository.ts
index fcf8c54c1..5e4ac06ca 100644
--- a/server/src/infra/repositories/album.repository.ts
+++ b/server/src/infra/repositories/album.repository.ts
@@ -1,7 +1,7 @@
-import { AlbumAssetCount, IAlbumRepository } from '@app/domain';
+import { AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from '@app/domain';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
-import { In, IsNull, Not, Repository } from 'typeorm';
+import { FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
import { dataSource } from '../database.config';
import { AlbumEntity, AssetEntity } from '../entities';
@@ -12,25 +12,27 @@ export class AlbumRepository implements IAlbumRepository {
@InjectRepository(AlbumEntity) private repository: Repository,
) {}
- getById(id: string): Promise {
- return this.repository.findOne({
- where: {
- id,
- },
- relations: {
- owner: true,
- sharedUsers: true,
- assets: {
- exifInfo: true,
- },
- sharedLinks: true,
- },
- order: {
- assets: {
- fileCreatedAt: 'DESC',
- },
- },
- });
+ getById(id: string, options: AlbumInfoOptions): Promise {
+ const relations: FindOptionsRelations = {
+ owner: true,
+ sharedUsers: true,
+ assets: false,
+ sharedLinks: true,
+ };
+
+ const order: FindOptionsOrder = {};
+
+ if (options.withAssets) {
+ relations.assets = {
+ exifInfo: true,
+ };
+
+ order.assets = {
+ fileCreatedAt: 'DESC',
+ };
+ }
+
+ return this.repository.findOne({ where: { id }, relations, order });
}
getByIds(ids: string[]): Promise {
diff --git a/web/src/routes/(user)/albums/[albumId]/+page.svelte b/web/src/routes/(user)/albums/[albumId]/+page.svelte
index fb169c399..8922ab073 100644
--- a/web/src/routes/(user)/albums/[albumId]/+page.svelte
+++ b/web/src/routes/(user)/albums/[albumId]/+page.svelte
@@ -100,7 +100,7 @@
});
const refreshAlbum = async () => {
- const { data } = await api.albumApi.getAlbumInfo({ id: album.id, withoutAssets: false });
+ const { data } = await api.albumApi.getAlbumInfo({ id: album.id, withoutAssets: true });
album = data;
};
@@ -261,9 +261,9 @@
}
};
- const handleUpdateDescription = (description: string) => {
+ const handleUpdateDescription = async (description: string) => {
try {
- api.albumApi.updateAlbumInfo({
+ await api.albumApi.updateAlbumInfo({
id: album.id,
updateAlbumDto: {
description,
From c27c12d975e94cf21cf5fcc40e0eac63bda6a36b Mon Sep 17 00:00:00 2001
From: martin <74269598+martabal@users.noreply.github.com>
Date: Wed, 16 Aug 2023 02:06:49 +0200
Subject: [PATCH 16/22] fix(server): people sorting (#3713)
---
server/src/domain/person/person.repository.ts | 1 +
server/src/domain/person/person.service.spec.ts | 6 +++---
server/src/domain/person/person.service.ts | 6 ++++--
server/src/infra/repositories/person.repository.ts | 14 ++++++++++----
4 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/server/src/domain/person/person.repository.ts b/server/src/domain/person/person.repository.ts
index 3c8432be1..973d940cd 100644
--- a/server/src/domain/person/person.repository.ts
+++ b/server/src/domain/person/person.repository.ts
@@ -4,6 +4,7 @@ export const IPersonRepository = 'IPersonRepository';
export interface PersonSearchOptions {
minimumFaceCount: number;
+ withHidden: boolean;
}
export interface UpdateFacesData {
diff --git a/server/src/domain/person/person.service.spec.ts b/server/src/domain/person/person.service.spec.ts
index 7aaa875f2..e5bca7c83 100644
--- a/server/src/domain/person/person.service.spec.ts
+++ b/server/src/domain/person/person.service.spec.ts
@@ -47,7 +47,7 @@ describe(PersonService.name, () => {
visible: 1,
people: [responseDto],
});
- expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 });
+ expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: false });
});
it('should get all visible people with thumbnails', async () => {
personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
@@ -56,7 +56,7 @@ describe(PersonService.name, () => {
visible: 1,
people: [responseDto],
});
- expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 });
+ expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: false });
});
it('should get all hidden and visible people with thumbnails', async () => {
personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
@@ -73,7 +73,7 @@ describe(PersonService.name, () => {
},
],
});
- expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 });
+ expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: true });
});
});
diff --git a/server/src/domain/person/person.service.ts b/server/src/domain/person/person.service.ts
index 0f66447f1..187ef3358 100644
--- a/server/src/domain/person/person.service.ts
+++ b/server/src/domain/person/person.service.ts
@@ -26,8 +26,10 @@ export class PersonService {
) {}
async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise {
- const people = await this.repository.getAll(authUser.id, { minimumFaceCount: 1 });
-
+ const people = await this.repository.getAll(authUser.id, {
+ minimumFaceCount: 1,
+ withHidden: dto.withHidden || false,
+ });
const persons: PersonResponseDto[] = people
// with thumbnails
.filter((person) => !!person.thumbnailPath)
diff --git a/server/src/infra/repositories/person.repository.ts b/server/src/infra/repositories/person.repository.ts
index 859548436..1203bba38 100644
--- a/server/src/infra/repositories/person.repository.ts
+++ b/server/src/infra/repositories/person.repository.ts
@@ -51,16 +51,22 @@ export class PersonRepository implements IPersonRepository {
}
getAll(userId: string, options?: PersonSearchOptions): Promise {
- return this.personRepository
+ const queryBuilder = this.personRepository
.createQueryBuilder('person')
.leftJoin('person.faces', 'face')
.where('person.ownerId = :userId', { userId })
- .orderBy('COUNT(face.assetId)', 'DESC')
+ .orderBy('person.isHidden', 'ASC')
+ .addOrderBy("NULLIF(person.name, '') IS NULL", 'ASC')
+ .addOrderBy('COUNT(face.assetId)', 'DESC')
.addOrderBy("NULLIF(person.name, '')", 'ASC', 'NULLS LAST')
.having('COUNT(face.assetId) >= :faces', { faces: options?.minimumFaceCount || 1 })
.groupBy('person.id')
- .limit(500)
- .getMany();
+ .limit(500);
+ if (!options?.withHidden) {
+ queryBuilder.andWhere('person.isHidden = false');
+ }
+
+ return queryBuilder.getMany();
}
getAllWithoutFaces(): Promise {
From 4762fd83d414cc239124a9d2902c18be99a1d2f5 Mon Sep 17 00:00:00 2001
From: Jason Rasmussen
Date: Tue, 15 Aug 2023 21:34:57 -0400
Subject: [PATCH 17/22] fix(server): link live photos after metadata extraction
finishes (#3702)
* fix(server): link live photos after metadata extraction finishes
* chore: fix test
---------
Co-authored-by: Alex
---
server/src/domain/album/album.repository.ts | 2 +
server/src/domain/job/job.constants.ts | 2 +
server/src/domain/job/job.repository.ts | 1 +
server/src/domain/job/job.service.spec.ts | 4 ++
server/src/domain/job/job.service.ts | 6 +-
.../infra/repositories/album.repository.ts | 17 +++++-
server/src/microservices/app.service.ts | 1 +
.../metadata-extraction.processor.ts | 60 +++++++++++--------
.../repositories/album.repository.mock.ts | 1 +
9 files changed, 64 insertions(+), 30 deletions(-)
diff --git a/server/src/domain/album/album.repository.ts b/server/src/domain/album/album.repository.ts
index bc6fa3752..d501964ef 100644
--- a/server/src/domain/album/album.repository.ts
+++ b/server/src/domain/album/album.repository.ts
@@ -16,6 +16,8 @@ export interface IAlbumRepository {
getByIds(ids: string[]): Promise;
getByAssetId(ownerId: string, assetId: string): Promise;
hasAsset(id: string, assetId: string): Promise;
+ /** Remove an asset from _all_ albums */
+ removeAsset(id: string): Promise;
getAssetCountForIds(ids: string[]): Promise;
getInvalidThumbnail(): Promise;
getOwned(ownerId: string): Promise;
diff --git a/server/src/domain/job/job.constants.ts b/server/src/domain/job/job.constants.ts
index a02248b30..02fa588c9 100644
--- a/server/src/domain/job/job.constants.ts
+++ b/server/src/domain/job/job.constants.ts
@@ -32,6 +32,7 @@ export enum JobName {
// metadata
QUEUE_METADATA_EXTRACTION = 'queue-metadata-extraction',
METADATA_EXTRACTION = 'metadata-extraction',
+ LINK_LIVE_PHOTOS = 'link-live-photos',
// user deletion
USER_DELETION = 'user-deletion',
@@ -98,6 +99,7 @@ export const JOBS_TO_QUEUE: Record = {
// metadata
[JobName.QUEUE_METADATA_EXTRACTION]: QueueName.METADATA_EXTRACTION,
[JobName.METADATA_EXTRACTION]: QueueName.METADATA_EXTRACTION,
+ [JobName.LINK_LIVE_PHOTOS]: QueueName.METADATA_EXTRACTION,
// storage template
[JobName.STORAGE_TEMPLATE_MIGRATION]: QueueName.STORAGE_TEMPLATE_MIGRATION,
diff --git a/server/src/domain/job/job.repository.ts b/server/src/domain/job/job.repository.ts
index c088a2eed..f605bef4b 100644
--- a/server/src/domain/job/job.repository.ts
+++ b/server/src/domain/job/job.repository.ts
@@ -45,6 +45,7 @@ export type JobItem =
// Metadata Extraction
| { name: JobName.QUEUE_METADATA_EXTRACTION; data: IBaseJob }
| { name: JobName.METADATA_EXTRACTION; data: IEntityJob }
+ | { name: JobName.LINK_LIVE_PHOTOS; data: IEntityJob }
// Sidecar Scanning
| { name: JobName.QUEUE_SIDECAR; data: IBaseJob }
diff --git a/server/src/domain/job/job.service.spec.ts b/server/src/domain/job/job.service.spec.ts
index a8c6ec9dc..503440a5c 100644
--- a/server/src/domain/job/job.service.spec.ts
+++ b/server/src/domain/job/job.service.spec.ts
@@ -252,6 +252,10 @@ describe(JobService.name, () => {
},
{
item: { name: JobName.METADATA_EXTRACTION, data: { id: 'asset-1' } },
+ jobs: [JobName.LINK_LIVE_PHOTOS],
+ },
+ {
+ item: { name: JobName.LINK_LIVE_PHOTOS, data: { id: 'asset-1' } },
jobs: [JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE, JobName.SEARCH_INDEX_ASSET],
},
{
diff --git a/server/src/domain/job/job.service.ts b/server/src/domain/job/job.service.ts
index df7949136..1c8290891 100644
--- a/server/src/domain/job/job.service.ts
+++ b/server/src/domain/job/job.service.ts
@@ -149,6 +149,10 @@ export class JobService {
break;
case JobName.METADATA_EXTRACTION:
+ await this.jobRepository.queue({ name: JobName.LINK_LIVE_PHOTOS, data: item.data });
+ break;
+
+ case JobName.LINK_LIVE_PHOTOS:
await this.jobRepository.queue({ name: JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE, data: item.data });
break;
@@ -186,7 +190,7 @@ export class JobService {
case JobName.CLASSIFY_IMAGE:
case JobName.ENCODE_CLIP:
case JobName.RECOGNIZE_FACES:
- case JobName.METADATA_EXTRACTION:
+ case JobName.LINK_LIVE_PHOTOS:
await this.jobRepository.queue({ name: JobName.SEARCH_INDEX_ASSET, data: { ids: [item.data.id] } });
break;
}
diff --git a/server/src/infra/repositories/album.repository.ts b/server/src/infra/repositories/album.repository.ts
index 5e4ac06ca..c59589710 100644
--- a/server/src/infra/repositories/album.repository.ts
+++ b/server/src/infra/repositories/album.repository.ts
@@ -1,7 +1,7 @@
import { AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from '@app/domain';
import { Injectable } from '@nestjs/common';
-import { InjectRepository } from '@nestjs/typeorm';
-import { FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
+import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
+import { DataSource, FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
import { dataSource } from '../database.config';
import { AlbumEntity, AssetEntity } from '../entities';
@@ -10,6 +10,7 @@ export class AlbumRepository implements IAlbumRepository {
constructor(
@InjectRepository(AssetEntity) private assetRepository: Repository,
@InjectRepository(AlbumEntity) private repository: Repository,
+ @InjectDataSource() private dataSource: DataSource,
) {}
getById(id: string, options: AlbumInfoOptions): Promise {
@@ -84,7 +85,7 @@ export class AlbumRepository implements IAlbumRepository {
*/
async getInvalidThumbnail(): Promise {
// Using dataSource, because there is no direct access to albums_assets_assets.
- const albumHasAssets = dataSource
+ const albumHasAssets = this.dataSource
.createQueryBuilder()
.select('1')
.from('albums_assets_assets', 'albums_assets')
@@ -150,6 +151,16 @@ export class AlbumRepository implements IAlbumRepository {
});
}
+ async removeAsset(assetId: string): Promise {
+ // Using dataSource, because there is no direct access to albums_assets_assets.
+ await this.dataSource
+ .createQueryBuilder()
+ .delete()
+ .from('albums_assets_assets')
+ .where('"albums_assets_assets"."assetsId" = :assetId', { assetId })
+ .execute();
+ }
+
hasAsset(id: string, assetId: string): Promise {
return this.repository.exist({
where: {
diff --git a/server/src/microservices/app.service.ts b/server/src/microservices/app.service.ts
index a8f30e188..1204a6ebd 100644
--- a/server/src/microservices/app.service.ts
+++ b/server/src/microservices/app.service.ts
@@ -66,6 +66,7 @@ export class AppService {
[JobName.VIDEO_CONVERSION]: (data) => this.mediaService.handleVideoConversion(data),
[JobName.QUEUE_METADATA_EXTRACTION]: (data) => this.metadataProcessor.handleQueueMetadataExtraction(data),
[JobName.METADATA_EXTRACTION]: (data) => this.metadataProcessor.handleMetadataExtraction(data),
+ [JobName.LINK_LIVE_PHOTOS]: (data) => this.metadataProcessor.handleLivePhotoLinking(data),
[JobName.QUEUE_RECOGNIZE_FACES]: (data) => this.facialRecognitionService.handleQueueRecognizeFaces(data),
[JobName.RECOGNIZE_FACES]: (data) => this.facialRecognitionService.handleRecognizeFaces(data),
[JobName.GENERATE_FACE_THUMBNAIL]: (data) => this.facialRecognitionService.handleGenerateFaceThumbnail(data),
diff --git a/server/src/microservices/processors/metadata-extraction.processor.ts b/server/src/microservices/processors/metadata-extraction.processor.ts
index a5f3ed4dd..7c58f7102 100644
--- a/server/src/microservices/processors/metadata-extraction.processor.ts
+++ b/server/src/microservices/processors/metadata-extraction.processor.ts
@@ -1,4 +1,5 @@
import {
+ IAlbumRepository,
IAssetRepository,
IBaseJob,
ICryptoRepository,
@@ -59,6 +60,7 @@ export class MetadataExtractionProcessor {
constructor(
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
+ @Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
@Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(IGeocodingRepository) private geocodingRepository: IGeocodingRepository,
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository,
@@ -92,6 +94,38 @@ export class MetadataExtractionProcessor {
}
}
+ async handleLivePhotoLinking(job: IEntityJob) {
+ const { id } = job;
+ const [asset] = await this.assetRepository.getByIds([id]);
+ if (!asset?.exifInfo) {
+ return false;
+ }
+
+ if (!asset.exifInfo.livePhotoCID) {
+ return true;
+ }
+
+ const otherType = asset.type === AssetType.VIDEO ? AssetType.IMAGE : AssetType.VIDEO;
+ const match = await this.assetRepository.findLivePhotoMatch({
+ livePhotoCID: asset.exifInfo.livePhotoCID,
+ ownerId: asset.ownerId,
+ otherAssetId: asset.id,
+ type: otherType,
+ });
+
+ if (!match) {
+ return true;
+ }
+
+ const [photoAsset, motionAsset] = asset.type === AssetType.IMAGE ? [asset, match] : [match, asset];
+
+ await this.assetRepository.save({ id: photoAsset.id, livePhotoVideoId: motionAsset.id });
+ await this.assetRepository.save({ id: motionAsset.id, isVisible: false });
+ await this.albumRepository.removeAsset(motionAsset.id);
+
+ return true;
+ }
+
async handleQueueMetadataExtraction(job: IBaseJob) {
const { force } = job;
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
@@ -351,19 +385,6 @@ export class MetadataExtractionProcessor {
}
newExif.livePhotoCID = getExifProperty('MediaGroupUUID');
- if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
- const motionAsset = await this.assetRepository.findLivePhotoMatch({
- livePhotoCID: newExif.livePhotoCID,
- otherAssetId: asset.id,
- ownerId: asset.ownerId,
- type: AssetType.VIDEO,
- });
- if (motionAsset) {
- await this.assetRepository.save({ id: asset.id, livePhotoVideoId: motionAsset.id });
- await this.assetRepository.save({ id: motionAsset.id, isVisible: false });
- }
- }
-
await this.applyReverseGeocoding(asset, newExif);
/**
@@ -428,19 +449,6 @@ export class MetadataExtractionProcessor {
newExif.fps = null;
newExif.livePhotoCID = exifData?.ContentIdentifier || null;
- if (newExif.livePhotoCID) {
- const photoAsset = await this.assetRepository.findLivePhotoMatch({
- livePhotoCID: newExif.livePhotoCID,
- ownerId: asset.ownerId,
- otherAssetId: asset.id,
- type: AssetType.IMAGE,
- });
- if (photoAsset) {
- await this.assetRepository.save({ id: photoAsset.id, livePhotoVideoId: asset.id });
- await this.assetRepository.save({ id: asset.id, isVisible: false });
- }
- }
-
if (videoTags && videoTags['location']) {
const location = videoTags['location'] as string;
const locationRegex = /([+-][0-9]+\.[0-9]+)([+-][0-9]+\.[0-9]+)\/$/;
diff --git a/server/test/repositories/album.repository.mock.ts b/server/test/repositories/album.repository.mock.ts
index 8656fa64a..3d42630df 100644
--- a/server/test/repositories/album.repository.mock.ts
+++ b/server/test/repositories/album.repository.mock.ts
@@ -12,6 +12,7 @@ export const newAlbumRepositoryMock = (): jest.Mocked => {
getNotShared: jest.fn(),
deleteAll: jest.fn(),
getAll: jest.fn(),
+ removeAsset: jest.fn(),
hasAsset: jest.fn(),
create: jest.fn(),
update: jest.fn(),
From bc66b1a556bf51a496397a4a618fb415e2183985 Mon Sep 17 00:00:00 2001
From: martin <74269598+martabal@users.noreply.github.com>
Date: Wed, 16 Aug 2023 03:46:23 +0200
Subject: [PATCH 18/22] fix(web): user-management layout (#3704)
* fix: user-management layout
* better user form scrollbar
---------
Co-authored-by: Alex Tran
---
.../components/forms/edit-user-form.svelte | 2 +-
web/src/routes/admin/+layout.svelte | 4 +--
.../routes/admin/user-management/+page.svelte | 36 +++++++++----------
3 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/web/src/lib/components/forms/edit-user-form.svelte b/web/src/lib/components/forms/edit-user-form.svelte
index 760c5f48e..588148850 100644
--- a/web/src/lib/components/forms/edit-user-form.svelte
+++ b/web/src/lib/components/forms/edit-user-form.svelte
@@ -67,7 +67,7 @@
-
-
+
diff --git a/web/src/routes/admin/user-management/+page.svelte b/web/src/routes/admin/user-management/+page.svelte
index 5dbe71aca..586d5a304 100644
--- a/web/src/routes/admin/user-management/+page.svelte
+++ b/web/src/routes/admin/user-management/+page.svelte
@@ -168,11 +168,11 @@
class="mb-4 flex h-12 w-full rounded-md border bg-gray-50 text-immich-primary dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-primary"
>
- Email |
- First name |
- Last name |
- Can import |
- Action |
+ Email |
+ First name |
+ Last name |
+ Can import |
+ Action |
@@ -187,10 +187,10 @@
: 'bg-immich-bg dark:bg-immich-dark-gray/50'
}`}
>
- {user.email} |
- {user.firstName} |
- {user.lastName} |
-
+ | {user.email} |
+ {user.firstName} |
+ {user.lastName} |
+
{#if user.externalPath}
@@ -199,7 +199,7 @@
{/if}
|
-
+ |
{#if !isDeleted(user)}
|