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 2e730ea1c20dc62c91622b7cc591235a698b6df8..c0d815182983ea5dc6b6061904c6d4936c8eeb56 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 46be818a5a089f5f561e9e563a6d30a48f69fd9f..c0aff99ab6103be0bbeef35f7afaa7a0deef42ba 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 0758b5f2c98227e5b4d469a2281aa9d1f6a5e7ab..0f66447f13f0698c55791ec67b45f5c6f9526fe0 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 db4ccff06b46a554a0b55d82f9ec0afa48df042c..8595484365433e39c0c4e016e9445a25f0ca1e6f 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 9cedbdf2c46edd3238cedb4427cee1c6b81cae96..e8662175a4ae15b1763adeead8cc9ca4bd913992 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 a628df9bd0a9934138f5a275417daec52793d3ed..c3226f228e8254c8437a1b0f42707be8f788b3e1 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 3041500641be63dae054d8b02e7572c9cafeac2c..df742a15411077c2bd8c001abaaf92ac54136b6d 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 6455c12d0378a00a6facb8fefdabd3f9224eebad..b6e42b33e1bf0321261c5cb71a0e57e6d045b6de 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 5ecc26b492adc1420ee4cc32faebb31b4c319d9f..488c9aafd288549cdfaf75134bcbb96445e9238c 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 d5504ba3247311ab9ec5dfcc358855c540cdb855..a60fcbd54405bf04fe37bffc7e540d0f542a1490 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 9a3372ad55358dad63ea759579f291625de5f202..59a387de1be7a0d1d93bddc46816b7ffe804a388 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 9cedbdf2c46edd3238cedb4427cee1c6b81cae96..e8662175a4ae15b1763adeead8cc9ca4bd913992 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 85c82555ba23f2a20b05ff0b5141b3c52011653f..8c8df10d8d52ff88c0853404ec65106991c6e457 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 74030a62ca5100d5910415eb85ab52ea582616d4..782bf64e1e6686c9e82316a265e07a70e9b34356 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 7967e52e87965f820d6203ac89c7efc4787db856..7c69332d02bd516fc82d7b54d4b17d9e12a44478 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 559a93646a6795a25845d37063c1996d9e4f69bc..8b0f9563947479348a3a5885abd6a9ebb3114dfd 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 a1a76c84390aed4e54a9b8be2ed38d07efeaf714..8aeae7043a3821d732b76fbc4e1d7331b3a67f03 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 8915a9d8bc12dfac22422ff76236f3087a62ba6d..6d7e1b0222e93aaace7bfd5c65e1ac0c134a076f 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 6457fbfef2ad2d711a9cab403f94ede285e5ef0b..d7564f0b67a5c03df9bbf3e696a479798663f01d 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 6457fbfef2ad2d711a9cab403f94ede285e5ef0b..d7564f0b67a5c03df9bbf3e696a479798663f01d 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 79cbe7b7ab153fec59d3c7321d9cab92e8683504..152948927024a08e7e2a9c482fe6ec9d9c16535c 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 7a84bd76778a4531bf596278b24a3f8bd07e9103..4c67ba05462d2faa329091f9d55ab42b1ed65aae 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 47e60789ce69968cc6c6e3edf3074ccef963c738..8aeae7043a3821d732b76fbc4e1d7331b3a67f03 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 0f28f5c5ffcb634ab7c08d33b2aa1795fc2f4ec1..87eee7df35e4e269445cf47d7c4e38a491825f44 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 8d737f4a4224c291bd3da9e9c67be73113487860..7e4db36708d90a752fa0c0cf6c279abc4cb5f476 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 78c1f6258f5153378ed5867c741691d17dcb8630..1b3ede0a95f8ef2ca25c3a37ec94c5be63e00582 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 6b60aa38799ad09d3ee56b164233c28c645e91e6..5ee62abe23b61b03009f6a1633b02e4d77d037b3 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 3ce0e7a51f3befd9554c3487cd2ba5e4192c634a..a921971ade96b8aed7528ff6464710f68cf17d13 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 6fcd72a485ae9ef8786e02592c5ca7cee52d5ad1..7c793a412d992bec00e65303fe023c05bb25985f 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 cd9cd38cca2e2bddf9e707586095d7a59bc82f72..509d8fbc311df842bfcd7d69c62497e8165f9cc9 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 501a62a99bd9b2db4a5488d5d72b868229f8fec1..b907e49509fb353c71f07289127e9483816f3da5 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 d3a630422719262113a3b0d6eb1f8cff9d303184..1ed3492122bf2237da28650f6ff2d4d06cbb08a9 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 3cd79f0761e344c5123bc44b19b322dae57a4ad5..27a22850b58d80e5e8b91c9fe75ee7de1fff64f0 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 7ca36b59551f6c214557121f560b55389b2f56a2..ecb968d001d4f440d593989c7782026dab7d806e 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 47e60789ce69968cc6c6e3edf3074ccef963c738..8aeae7043a3821d732b76fbc4e1d7331b3a67f03 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 6d466d052b8875b2be21f2fab421098dce6bc14a..8a2674cf5bda076c440d6f4ab798317e9f5e2317 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 47e60789ce69968cc6c6e3edf3074ccef963c738..8aeae7043a3821d732b76fbc4e1d7331b3a67f03 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 c9b75a25754a19a76fabd6cb022e0d7014f45a46..b61d2ca639dedf293863f20ae78507c15bea611c 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 8359013b64fab8fd0a242a3a50b58302050173b6..d74b81ce8b4596e5e5c4220f5336329141c939c0 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 47e60789ce69968cc6c6e3edf3074ccef963c738..8aeae7043a3821d732b76fbc4e1d7331b3a67f03 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 18298dad93cde92a3ed1af32b50852b5c789fa96..762569ec056079a6a41252b0a453da479ac3c570 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 bba4b16433c9dcaee7207415379d4f0b1a634042..9a2af046d662ebef8d0143228218dfc4aa9d59f7 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 7cb167c39c3027b58622b8f286e8777c1ec7fe65..b9337f8d1bd338a0d3ecf154f77e4406924766a9 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 fad841c22190742181933cc4d3ced1cffb293a73..533ab372efabfb78aa64ed5a870b736fa0ae7a76 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 0000000000000000000000000000000000000000..74dc40a474daae42746cc035cbe7ed50b5ef92eb --- /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 a37ee6a23a48a117063ca71ad5c808c667b47c09..a5f3ed4dd38793a9c5ecfcf2530fc25fcc2cc229 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 975d1e996957e2424e50bc521f087efa456978e4..223a7671eca23e5615dec162987f51a5af76cc4a 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 3a07b0c173a1b5ffcd163e9654c5f6363ea50032..03aeb17f092aa7ccbb7ea70575ff1f72d8db21ec 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 a1cb0a7dfeb3de06c58a5371a63d831e23f8c027..b06720613cc8c732eb6f324a8f8d9e1446b00779 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 e65b45e8088b3d95af68035d0c13439796c22c61..5df79b1590edba05e80aff634401da43006d0c4f 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 e8662175a4ae15b1763adeead8cc9ca4bd913992..956f19ba7bb50dca40fbd24840c3d434e6538160 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 d636bfdd9aa0055c73cb2b7865987acb4e958633..7109cba71e3ada8951c688443ec7b9e7ddcf0a65 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 6b75041a706461fd9b3e1bab1c89cbb21893ba8c..66890914ad3d9123755c40e6fe0b0d89342b8548 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 275f99f72a2c03445f7e980ccffa757b9ef3da98..21fd71538b1036460f6114bbb8b219c6c272110e 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 704745843691dd2fba834c9be91c9eba0fbf54a9..937e9a24aded17608c54b3196e3443b2fb0712a9 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 4547dcb0521a0b4fa0dfbe94ed32de757290f013..b2fa1b28e3d29d15cc1cd14052d54734841b3886 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 0de6cb8aa7ce2f4a9d2fe3de0d3037723ad33333..e9be5f6548c6e6f158c401a7581b394f252774b3 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 56bf4ba34e95e0a15d3cfaf4d96f8a18374aaf10..7707eadb9d51c16a95c3f455e65e52f0b7faee64 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 2942d1d854a63407ec6e482fb94e23030cad7fbe..1e20582fae1d103b070d5b18b28577768c1f92f4 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 5c75bfb7e9439708f5c41fe1c4426a9d00f5a76a..dc90a5373c357245570b0213907e75b26bb345ab 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 a60fcbd54405bf04fe37bffc7e540d0f542a1490..59543353fb44e1687645f3d19d69623cf53e9af8 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 fa3fbf12a6179e60fd61a940dc2df5fb4393e6b4..e6e2de6aba3786d77042c0860d5c929003ddbdd0 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 2baf087bf6219099eae62eca2cfae00bc84071bc..cdfb87d59ac63049121d600845b8eb5e055aae20 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 e8662175a4ae15b1763adeead8cc9ca4bd913992..956f19ba7bb50dca40fbd24840c3d434e6538160 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 d636bfdd9aa0055c73cb2b7865987acb4e958633..7109cba71e3ada8951c688443ec7b9e7ddcf0a65 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 6b75041a706461fd9b3e1bab1c89cbb21893ba8c..66890914ad3d9123755c40e6fe0b0d89342b8548 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 275f99f72a2c03445f7e980ccffa757b9ef3da98..21fd71538b1036460f6114bbb8b219c6c272110e 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 704745843691dd2fba834c9be91c9eba0fbf54a9..937e9a24aded17608c54b3196e3443b2fb0712a9 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 45b5cef2d88e58c0cecebe19e15566e65e0be06d..d268a40aeed6b3a1530216742810a48a19c27cd8 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 7b7cbd0d57db64c34ceffd63590b5d4792a63448..4902388c6d9d0fe582a817643cd35f7e5f0f5bab 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 9f463abbe7310e46dfbf913c3e556097c402b4f7..8bb1e319277bb6b7798edc84458903d6aee44798 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 041dcd2ebd59c9414efe9ba567b1dea5b3c39d3e..ae8c18518e0aa43b4a1b63f98a413fb03e0aed76 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 f1ee5f8278656ef6b7a024102418e0cd8756b0a7..3f00787c157eb02bce63ceb749cb1fda8d6a3c99 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 | 97 ++++++----- 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, 398 insertions(+), 231 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 956f19ba7bb50dca40fbd24840c3d434e6538160..8ade1d5fde43cf95617cb02eafed9d9218bdcdcf 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} - * @memberof AssetApiGetDownloadInfo - */ - readonly assetIds?: Array - - /** - * - * @type {string} - * @memberof AssetApiGetDownloadInfo - */ - readonly albumId?: string - - /** - * - * @type {string} - * @memberof AssetApiGetDownloadInfo - */ - readonly userId?: string - - /** - * - * @type {number} + * @type {DownloadInfoDto} * @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 ea0993be8ca6c6910985c902424620812917707e..bf485ef08b552397ca3d47f4077c137d8eaf8b60 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 1e20582fae1d103b070d5b18b28577768c1f92f4..9167613b255d463913bc2f4e4a1af0025c9aadaa 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 2999f2de2a8943eff8a2d1cf899dcc9c95a64af0..5c1c7bb4bfb2c1f80706cbea11443790ffa228ec 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 0000000000000000000000000000000000000000..14d5d1e712ea8e24bac2454baaa28b33d3c3db6b --- /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 644244a103b1401e8253b2c7e2476ddb7ea948d7..a38d8784e34111d5cc8a58a44c15517c2187811d 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 6f4c391bf8a1083e550b7e8c5d854d3d328c9e42..ba9f1d5a1f598d6c69e82ec83dea422a23b8142d 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 fd1252cc7846c10d28c577f6ac066fc3066b93ae..eb76c12c58dfc6c6bd2c4ce621db67f0255838a7 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 0000000000000000000000000000000000000000..fa3a06eeaccee5d64c38c412ed626d8fe9e40995 --- /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 588902a14c3923c09cd2e772872298de7d1827b8..ebb472c4a05228ea212ef5ed9f972e33f225a724 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 0000000000000000000000000000000000000000..5efd4e11eb4812b4c8b871589f20783ab96dc50e --- /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 59543353fb44e1687645f3d19d69623cf53e9af8..f193eb25e4a71cbd4eb129c77bc476adda8649c8 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -1026,48 +1026,10 @@ ] } }, - "/asset/download": { - "get": { - "operationId": "getDownloadInfo", + "/asset/download/archive": { + "post": { + "operationId": "downloadArchive", "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, @@ -1077,12 +1039,23 @@ } } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetIdsDto" + } + } + }, + "required": true + }, "responses": { "200": { "content": { - "application/json": { + "application/octet-stream": { "schema": { - "$ref": "#/components/schemas/DownloadResponseDto" + "format": "binary", + "type": "string" } } }, @@ -1103,9 +1076,11 @@ "tags": [ "Asset" ] - }, + } + }, + "/asset/download/info": { "post": { - "operationId": "downloadArchive", + "operationId": "getDownloadInfo", "parameters": [ { "name": "key", @@ -1120,19 +1095,18 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AssetIdsDto" + "$ref": "#/components/schemas/DownloadInfoDto" } } }, "required": true }, "responses": { - "200": { + "201": { "content": { - "application/octet-stream": { + "application/json": { "schema": { - "format": "binary", - "type": "string" + "$ref": "#/components/schemas/DownloadResponseDto" } } }, @@ -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 fdd6df6efd716308c71426e5d2146462e6ae7edd..ac655b807700937a11f55730b3512ceb5f1c850c 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 c2cf85685aa8ab97d078c23a5af5fd19605c6d27..604a8ea5fb3b44412e78afc467d354937ec154b6 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 ba3de02cc59256ee38bab50b7186ff1176216022..b55cbb870d3070d5dd118aeaa51e2a6f5a4d7aac 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 956f19ba7bb50dca40fbd24840c3d434e6538160..8ade1d5fde43cf95617cb02eafed9d9218bdcdcf 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} - * @memberof AssetApiGetDownloadInfo - */ - readonly assetIds?: Array - - /** - * - * @type {string} - * @memberof AssetApiGetDownloadInfo - */ - readonly albumId?: string - - /** - * - * @type {string} - * @memberof AssetApiGetDownloadInfo - */ - readonly userId?: string - - /** - * - * @type {number} + * @type {DownloadInfoDto} * @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 0a8ff758d2e17efdbc204fbf95db71721bc69cbd..cb29b503a0a29be8a690becced40bbbe9773b551 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 d8156123658e05aec210380893987da5f41ab2df..3e3d4a469d6cc53096f49843ca06eb741a39a3cc 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 ac655b807700937a11f55730b3512ceb5f1c850c..2d4051b0fa042a87ee2cc0a880624339fff6a63b 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 c7fd51f2a81e66bf3cd2731d4894450c89b881f5..adc718e91839e084b1bd5d62d2ab5ea21f998af4 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 10a946eee3adad0b99b6fac0874e40730d313e2f..d018a4a285117ef6cbb3a038d774b02ce270948f 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 ceeb85e2956af746069fe8fe5b80b5d46228cf75..4a7e7f22bb1a7c21ae26a7f58de05fb4f444cc59 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 6c59d9ca71d33949bd3ed5b23585cc14efbeb115..e7c0f7f2b14889d08ec08e65e6c382f585fbf63c 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 811b85ec9adb446e467b2012715831edfbd7d64e..bc6fa37524e55b3a3583fc73f7951effd7ffda22 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 463d94d7f4da9fd5a1aff72b5e5b2444d68c7bfa..f9ab15374415b8395ef0f9f96f30a57c1bd428c1 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 925b87ac9ac0fe308c648721239099743d24eb52..71c11d93570ea8434aa428d3f6a2942da0d7e15b 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 fcf8c54c1f1d75e69022486a10b0193acdd919a0..5e4ac06ca0828e2bf6af33bdde4564380a9edcdc 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 fb169c399868b7e9475b7a2d200ca63bed9a0f60..8922ab073b329026c905f364f17634857ed770bc 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 3c8432be1eaa7e2235906ac4713d8c714a6bd0f1..973d940cd64592be8920a05cc4e69924aae61263 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 7aaa875f271b81c60e941f76cd287518b34eb246..e5bca7c830d3910e072e740f4e4c2369264b8ff9 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 0f66447f13f0698c55791ec67b45f5c6f9526fe0..187ef3358d5712f35dbc3db1ceef305ac51a146c 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 8595484365433e39c0c4e016e9445a25f0ca1e6f..1203bba381fec2c4442b497896007904f4b380d3 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 bc6fa37524e55b3a3583fc73f7951effd7ffda22..d501964ef590091f45cb68abecebd2eb808d3909 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 a02248b3062716e621eaa8db46ced159857a7267..02fa588c9b0e78b09b4f7fa53bb50d3886acb589 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 c088a2eedf86712ee0a72a036e9b12a2a425ee7e..f605bef4b4d976a50394abc38164c12009ccc5da 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 a8c6ec9dc6dbe5c6c97ea15c923cc97430f57ddf..503440a5cf7f8d42e6d9a923c3a87abb3f1b0801 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 df7949136767d87b6412f7b0b1391d89586f2d8e..1c82908911cb431160d45767c67810d2e0f7ef6f 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 5e4ac06ca0828e2bf6af33bdde4564380a9edcdc..c59589710b142a67913356eae90e5dfce0863f28 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 a8f30e188828084852f83128d12410f7302a833c..1204a6ebdd5536573aba7277e695c3edbf40fdc0 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 a5f3ed4dd38793a9c5ecfcf2530fc25fcc2cc229..7c58f7102e78de99ba16b17c695396314b0fcf61 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 8656fa64a1daa306977a264a4a3094a11bcc7170..3d42630dfb0df26e9ae413fb6fc4bf07cd989de2 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 760c5f48ef11afbeec97f569e5ac0435abbe35b4..5881488508c863f8f1e9b9d52be1e60a7fcca26c 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 5dbe71aca3879de59eb20da39e0ea32d49542e2c..586d5a3042e19ec80a502567bacb328a993fe817 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)}