martabal 1 rok pred
rodič
commit
6e2ba7acab
100 zmenil súbory, kde vykonal 1069 pridanie a 418 odobranie
  1. 40 43
      README_zh_CN.md
  2. 52 59
      cli/src/api/open-api/api.ts
  3. 1 1
      cli/src/api/open-api/base.ts
  4. 1 1
      cli/src/api/open-api/common.ts
  5. 1 1
      cli/src/api/open-api/configuration.ts
  6. 1 1
      cli/src/api/open-api/index.ts
  7. 26 0
      docs/docs/FAQ.md
  8. 6 0
      docs/docs/features/bulk-upload.md
  9. 1 1
      machine-learning/pyproject.toml
  10. 2 2
      mobile/android/fastlane/Fastfile
  11. 3 3
      mobile/android/fastlane/report.xml
  12. 11 0
      mobile/assets/i18n/ca.json
  13. 11 0
      mobile/assets/i18n/cs-CZ.json
  14. 11 0
      mobile/assets/i18n/da-DK.json
  15. 11 0
      mobile/assets/i18n/de-DE.json
  16. 9 9
      mobile/assets/i18n/en-US.json
  17. 11 0
      mobile/assets/i18n/es-ES.json
  18. 11 0
      mobile/assets/i18n/es-MX.json
  19. 11 0
      mobile/assets/i18n/es-PE.json
  20. 11 0
      mobile/assets/i18n/fi-FI.json
  21. 11 0
      mobile/assets/i18n/fr-FR.json
  22. 11 0
      mobile/assets/i18n/hi-IN.json
  23. 11 0
      mobile/assets/i18n/hu-HU.json
  24. 11 0
      mobile/assets/i18n/it-IT.json
  25. 11 0
      mobile/assets/i18n/ja-JP.json
  26. 11 0
      mobile/assets/i18n/ko-KR.json
  27. 11 0
      mobile/assets/i18n/lv-LV.json
  28. 11 0
      mobile/assets/i18n/mn.json
  29. 11 0
      mobile/assets/i18n/nb-NO.json
  30. 11 0
      mobile/assets/i18n/nl-NL.json
  31. 11 0
      mobile/assets/i18n/pl-PL.json
  32. 11 0
      mobile/assets/i18n/ru-RU.json
  33. 11 0
      mobile/assets/i18n/sk-SK.json
  34. 11 0
      mobile/assets/i18n/sr-Cyrl.json
  35. 11 0
      mobile/assets/i18n/sr-Latn.json
  36. 11 0
      mobile/assets/i18n/sv-FI.json
  37. 11 0
      mobile/assets/i18n/sv-SE.json
  38. 11 0
      mobile/assets/i18n/th-TH.json
  39. 11 0
      mobile/assets/i18n/uk-UA.json
  40. 11 0
      mobile/assets/i18n/vi-VN.json
  41. 11 0
      mobile/assets/i18n/zh-CN.json
  42. 11 0
      mobile/assets/i18n/zh-Hans.json
  43. 1 1
      mobile/ios/Podfile.lock
  44. 3 3
      mobile/ios/Runner.xcodeproj/project.pbxproj
  45. 2 2
      mobile/ios/Runner/Info.plist
  46. 1 1
      mobile/ios/fastlane/Fastfile
  47. 6 6
      mobile/ios/fastlane/report.xml
  48. 5 4
      mobile/lib/modules/home/views/home_page.dart
  49. 1 1
      mobile/lib/shared/models/user.dart
  50. 7 0
      mobile/lib/shared/providers/admin_provider.dart
  51. 7 0
      mobile/lib/shared/views/version_announcement_overlay.dart
  52. 3 0
      mobile/openapi/.openapi-generator/FILES
  53. 4 3
      mobile/openapi/README.md
  54. 7 13
      mobile/openapi/doc/AssetApi.md
  55. 18 0
      mobile/openapi/doc/DownloadInfoDto.md
  56. 1 1
      mobile/openapi/doc/UserResponseDto.md
  57. 1 0
      mobile/openapi/lib/api.dart
  58. 12 36
      mobile/openapi/lib/api/asset_api.dart
  59. 2 0
      mobile/openapi/lib/api_client.dart
  60. 150 0
      mobile/openapi/lib/model/download_info_dto.dart
  61. 14 5
      mobile/openapi/lib/model/user_response_dto.dart
  62. 1 1
      mobile/openapi/test/asset_api_test.dart
  63. 42 0
      mobile/openapi/test/download_info_dto_test.dart
  64. 1 1
      mobile/pubspec.yaml
  65. 49 53
      server/immich-openapi-specs.json
  66. 2 2
      server/package-lock.json
  67. 1 1
      server/package.json
  68. 5 0
      server/src/domain/access/access.core.ts
  69. 7 1
      server/src/domain/album/album.repository.ts
  70. 4 3
      server/src/domain/album/album.service.spec.ts
  71. 12 12
      server/src/domain/album/album.service.ts
  72. 6 3
      server/src/domain/asset/asset.service.ts
  73. 2 1
      server/src/domain/asset/dto/download.dto.ts
  74. 2 0
      server/src/domain/domain.constant.ts
  75. 2 0
      server/src/domain/job/job.constants.ts
  76. 1 0
      server/src/domain/job/job.repository.ts
  77. 4 0
      server/src/domain/job/job.service.spec.ts
  78. 5 1
      server/src/domain/job/job.service.ts
  79. 1 0
      server/src/domain/person/person.repository.ts
  80. 3 3
      server/src/domain/person/person.service.spec.ts
  81. 5 5
      server/src/domain/person/person.service.ts
  82. 3 3
      server/src/domain/server-info/server-info.service.ts
  83. 1 1
      server/src/domain/user/response-dto/user-response.dto.ts
  84. 0 1
      server/src/domain/user/user.core.ts
  85. 4 4
      server/src/immich/controllers/asset.controller.ts
  86. 13 0
      server/src/infra/migrations/1692057328660-fixGPSNullIsland.ts
  87. 36 23
      server/src/infra/repositories/album.repository.ts
  88. 11 4
      server/src/infra/repositories/person.repository.ts
  89. 1 0
      server/src/microservices/app.service.ts
  90. 44 28
      server/src/microservices/processors/metadata-extraction.processor.ts
  91. 12 0
      server/src/microservices/utils/exif/coordinates.spec.ts
  92. 9 2
      server/src/microservices/utils/exif/coordinates.ts
  93. 1 0
      server/test/repositories/album.repository.mock.ts
  94. 52 59
      web/src/api/open-api/api.ts
  95. 1 1
      web/src/api/open-api/base.ts
  96. 1 1
      web/src/api/open-api/common.ts
  97. 1 1
      web/src/api/open-api/configuration.ts
  98. 1 1
      web/src/api/open-api/index.ts
  99. 1 1
      web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte
  100. 4 4
      web/src/lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte

+ 40 - 43
README_zh_CN.md

@@ -13,7 +13,7 @@
 </p>
 </p>
 <h3 align="center">Immich - 高性能的自托管照片和视频备份方案</h3>
 <h3 align="center">Immich - 高性能的自托管照片和视频备份方案</h3>
 <p align="center">  
 <p align="center">  
-请注意: 此README不是由Immich团队维护, 这意味着它在某一时间点不会被更新,因为我们是依靠贡献者来更新的。感谢理解。
+请注意: 此 README 不是由 Immich 团队维护, 而是依靠贡献者来更新的,这意味着它可能并不会被及时更新。感谢理解。
 </p>
 </p>
 <br/>
 <br/>
 <a href="https://immich.app">
 <a href="https://immich.app">
@@ -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/overview/introduction)
 - [安装](https://immich.app/docs/install/requirements)
 - [安装](https://immich.app/docs/install/requirements)
 - [贡献指南](https://immich.app/docs/overview/support-the-project)
 - [贡献指南](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="示例认证信息"
 ```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 |
 | 选择需要备份的相册          | 是     | N/A |
-| 下载照片和视频到本地  | 是     | 是 |
+| 下载照片和视频到本地        | 是     | 是 |
 | 多用户支持                          | 是     | 是 |
 | 多用户支持                          | 是     | 是 |
 | 相册                                       | 是     | 是 |
 | 相册                                       | 是     | 是 |
 | 共享相册                               | 是     | 是 |
 | 共享相册                               | 是     | 是 |
 | 可拖动的快速导航栏   | 是     | 是 |
 | 可拖动的快速导航栏   | 是     | 是 |
 | 支持RAW格式 (HEIC, HEIF, DNG, Apple ProRaw) | 是     | 是 |
 | 支持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

+ 52 - 59
cli/src/api/open-api/api.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -1132,6 +1132,37 @@ export interface DownloadArchiveInfo {
      */
      */
     'size': number;
     'size': number;
 }
 }
+/**
+ * 
+ * @export
+ * @interface DownloadInfoDto
+ */
+export interface DownloadInfoDto {
+    /**
+     * 
+     * @type {string}
+     * @memberof DownloadInfoDto
+     */
+    'albumId'?: string;
+    /**
+     * 
+     * @type {number}
+     * @memberof DownloadInfoDto
+     */
+    'archiveSize'?: number;
+    /**
+     * 
+     * @type {Array<string>}
+     * @memberof DownloadInfoDto
+     */
+    'assetIds'?: Array<string>;
+    /**
+     * 
+     * @type {string}
+     * @memberof DownloadInfoDto
+     */
+    'userId'?: string;
+}
 /**
 /**
  * 
  * 
  * @export
  * @export
@@ -3159,7 +3190,7 @@ export interface UserResponseDto {
      * @type {boolean}
      * @type {boolean}
      * @memberof UserResponseDto
      * @memberof UserResponseDto
      */
      */
-    'memoriesEnabled': boolean;
+    'memoriesEnabled'?: boolean;
     /**
     /**
      * 
      * 
      * @type {string}
      * @type {string}
@@ -4880,7 +4911,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
         downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
         downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             // verify required parameter 'assetIdsDto' is not null or undefined
             // verify required parameter 'assetIdsDto' is not null or undefined
             assertParamExists('downloadArchive', 'assetIdsDto', assetIdsDto)
             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.
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             let baseOptions;
             let baseOptions;
@@ -5379,16 +5410,15 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
         },
         },
         /**
         /**
          * 
          * 
-         * @param {Array<string>} [assetIds] 
-         * @param {string} [albumId] 
-         * @param {string} [userId] 
-         * @param {number} [archiveSize] 
+         * @param {DownloadInfoDto} downloadInfoDto 
          * @param {string} [key] 
          * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          * @throws {RequiredError}
          */
          */
-        getDownloadInfo: async (assetIds?: Array<string>, albumId?: string, userId?: string, archiveSize?: number, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/asset/download`;
+        getDownloadInfo: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // 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.
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             let baseOptions;
             let baseOptions;
@@ -5396,7 +5426,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
                 baseOptions = configuration.baseOptions;
                 baseOptions = configuration.baseOptions;
             }
             }
 
 
-            const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
+            const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
             const localVarHeaderParameter = {} as any;
             const localVarHeaderParameter = {} as any;
             const localVarQueryParameter = {} as any;
             const localVarQueryParameter = {} as any;
 
 
@@ -5409,31 +5439,18 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
             // http bearer authentication required
             // http bearer authentication required
             await setBearerAuthToObject(localVarHeaderParameter, configuration)
             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) {
             if (key !== undefined) {
                 localVarQueryParameter['key'] = key;
                 localVarQueryParameter['key'] = key;
             }
             }
 
 
 
 
     
     
+            localVarHeaderParameter['Content-Type'] = 'application/json';
+
             setSearchParams(localVarUrlObj, localVarQueryParameter);
             setSearchParams(localVarUrlObj, localVarQueryParameter);
             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            localVarRequestOptions.data = serializeDataIfNeeded(downloadInfoDto, localVarRequestOptions, configuration)
 
 
             return {
             return {
                 url: toPathString(localVarUrlObj),
                 url: toPathString(localVarUrlObj),
@@ -6141,16 +6158,13 @@ export const AssetApiFp = function(configuration?: Configuration) {
         },
         },
         /**
         /**
          * 
          * 
-         * @param {Array<string>} [assetIds] 
-         * @param {string} [albumId] 
-         * @param {string} [userId] 
-         * @param {number} [archiveSize] 
+         * @param {DownloadInfoDto} downloadInfoDto 
          * @param {string} [key] 
          * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          * @throws {RequiredError}
          */
          */
-        async getDownloadInfo(assetIds?: Array<string>, albumId?: string, userId?: string, archiveSize?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DownloadResponseDto>> {
-            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<DownloadResponseDto>> {
+            const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(downloadInfoDto, key, options);
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
         },
         },
         /**
         /**
@@ -6406,8 +6420,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
          * @param {*} [options] Override http request option.
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          * @throws {RequiredError}
          */
          */
-        getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest = {}, options?: AxiosRequestConfig): AxiosPromise<DownloadResponseDto> {
-            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<DownloadResponseDto> {
+            return localVarFp.getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
         },
         },
         /**
         /**
          * 
          * 
@@ -6788,31 +6802,10 @@ export interface AssetApiGetByTimeBucketRequest {
 export interface AssetApiGetDownloadInfoRequest {
 export interface AssetApiGetDownloadInfoRequest {
     /**
     /**
      * 
      * 
-     * @type {Array<string>}
-     * @memberof AssetApiGetDownloadInfo
-     */
-    readonly assetIds?: Array<string>
-
-    /**
-     * 
-     * @type {string}
-     * @memberof AssetApiGetDownloadInfo
-     */
-    readonly albumId?: string
-
-    /**
-     * 
-     * @type {string}
-     * @memberof AssetApiGetDownloadInfo
-     */
-    readonly userId?: string
-
-    /**
-     * 
-     * @type {number}
+     * @type {DownloadInfoDto}
      * @memberof AssetApiGetDownloadInfo
      * @memberof AssetApiGetDownloadInfo
      */
      */
-    readonly archiveSize?: number
+    readonly downloadInfoDto: DownloadInfoDto
 
 
     /**
     /**
      * 
      * 
@@ -7281,8 +7274,8 @@ export class AssetApi extends BaseAPI {
      * @throws {RequiredError}
      * @throws {RequiredError}
      * @memberof AssetApi
      * @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));
     }
     }
 
 
     /**
     /**

+ 1 - 1
cli/src/api/open-api/base.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
cli/src/api/open-api/common.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
cli/src/api/open-api/configuration.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
cli/src/api/open-api/index.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 26 - 0
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?
 ### 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.
 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" = '<destinationId>' where "ownerId" = '<sourceId>';
+
+   // reassign people
+   update person set "ownerId" = '<destinationId>' where "ownerId" = '<sourceId>';
+
+   // reassign assets
+   update assets set "ownerId" = '<destinationId>' where "ownerId" = '<sourceId>'
+    and checksum not in (select checksum from assets where "ownerId" = '<destinationId>');
+   ```
+
+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.

+ 6 - 0
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
 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
+```
+
 :::
 :::

+ 1 - 1
machine-learning/pyproject.toml

@@ -1,6 +1,6 @@
 [tool.poetry]
 [tool.poetry]
 name = "machine-learning"
 name = "machine-learning"
-version = "1.72.2"
+version = "1.73.0"
 description = ""
 description = ""
 authors = ["Hau Tran <alex.tran1502@gmail.com>"]
 authors = ["Hau Tran <alex.tran1502@gmail.com>"]
 readme = "README.md"
 readme = "README.md"

+ 2 - 2
mobile/android/fastlane/Fastfile

@@ -35,8 +35,8 @@ platform :android do
       task: 'bundle', 
       task: 'bundle', 
       build_type: 'Release',
       build_type: 'Release',
       properties: {
       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')
     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')

+ 3 - 3
mobile/android/fastlane/report.xml

@@ -5,17 +5,17 @@
     
     
     
     
       
       
-      <testcase classname="fastlane.lanes" name="0: default_platform" time="0.000239">
+      <testcase classname="fastlane.lanes" name="0: default_platform" time="0.00023">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="1: bundleRelease" time="68.788432">
+      <testcase classname="fastlane.lanes" name="1: bundleRelease" time="67.877631">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="29.76592">
+      <testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="23.895222">
         
         
       </testcase>
       </testcase>
     
     

+ 11 - 0
mobile/assets/i18n/ca.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "elements",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Àlbums",
   "library_page_albums": "Àlbums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Entra",
   "login_form_button_text": "Entra",
   "login_form_email_hint": "elteu@correu.cat",
   "login_form_email_hint": "elteu@correu.cat",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/cs-CZ.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Nahrávaný soubor",
   "backup_controller_page_uploading_file_info": "Nahrávaný soubor",
   "backup_err_only_album": "Nelze odstranit jediné vybrané album",
   "backup_err_only_album": "Nelze odstranit jediné vybrané album",
   "backup_info_card_assets": "položek",
   "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_album_thumbnails": "Náhledy stránek knihovny (položek {})",
   "cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
   "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í.",
   "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_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_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_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_error": "Chyba stahování",
   "image_viewer_page_state_provider_download_success": "Stahování bylo úspěšné",
   "image_viewer_page_state_provider_download_success": "Stahování bylo úspěšné",
   "library_page_albums": "Alba",
   "library_page_albums": "Alba",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sdílení",
   "library_page_sharing": "Sdílení",
   "library_page_sort_created": "Naposledy vytvořené",
   "library_page_sort_created": "Naposledy vytvořené",
   "library_page_sort_title": "Podle názvu alba",
   "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_api_exception": "Výjimka API. Zkontrolujte URL serveru a zkuste to znovu.",
   "login_form_button_text": "Přihlásit se",
   "login_form_button_text": "Přihlásit se",
   "login_form_email_hint": "tvůjmail@email.com",
   "login_form_email_hint": "tvůjmail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Téma",
   "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_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í",
   "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_ack": "Potvrdit",
   "version_announcement_overlay_release_notes": "poznámky k vydání",
   "version_announcement_overlay_release_notes": "poznámky k vydání",
   "version_announcement_overlay_text_1": "Ahoj, je zde nová verze",
   "version_announcement_overlay_text_1": "Ahoj, je zde nová verze",

+ 11 - 0
mobile/assets/i18n/da-DK.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploader filinformation",
   "backup_controller_page_uploading_file_info": "Uploader filinformation",
   "backup_err_only_album": "Kan ikke slette det eneste album",
   "backup_err_only_album": "Kan ikke slette det eneste album",
   "backup_info_card_assets": "elementer",
   "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_album_thumbnails": "Biblioteksminiaturebilleder ({} elementer)",
   "cache_settings_clear_cache_button": "Fjern cache",
   "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.",
   "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_building_timeline": "Bygger tidslinjen",
   "home_page_favorite_err_local": "Kan endnu ikke gøre lokale elementer til favoritter. Springer over..",
   "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_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_error": "Fejl ved download",
   "image_viewer_page_state_provider_download_success": "Download succesfuld",
   "image_viewer_page_state_provider_download_success": "Download succesfuld",
   "library_page_albums": "Albummer",
   "library_page_albums": "Albummer",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Delte",
   "library_page_sharing": "Delte",
   "library_page_sort_created": "Senest oprettet",
   "library_page_sort_created": "Senest oprettet",
   "library_page_sort_title": "Albumtitel",
   "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_api_exception": "API-undtagelse. Tjek serverens URL og prøv igen. ",
   "login_form_button_text": "Log ind",
   "login_form_button_text": "Log ind",
   "login_form_email_hint": "din-e-mail@e-mail.com",
   "login_form_email_hint": "din-e-mail@e-mail.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_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",
   "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_ack": "Accepter",
   "version_announcement_overlay_release_notes": "udgivelsesnoterne",
   "version_announcement_overlay_release_notes": "udgivelsesnoterne",
   "version_announcement_overlay_text_1": "Hej ven, der er en ny version af",
   "version_announcement_overlay_text_1": "Hej ven, der er en ny version af",

+ 11 - 0
mobile/assets/i18n/de-DE.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Informationen",
   "backup_controller_page_uploading_file_info": "Informationen",
   "backup_err_only_album": "Das einzige Album kann nicht entfernt werden",
   "backup_err_only_album": "Das einzige Album kann nicht entfernt werden",
   "backup_info_card_assets": "Elemente",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Zwischenspeicher löschen",
   "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.",
   "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_building_timeline": "Zeitachse wird erstellt.",
   "home_page_favorite_err_local": "Kann lokale Elemente noch nicht favorisieren, überspringe",
   "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_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_error": "Fehler beim Herunterladen",
   "image_viewer_page_state_provider_download_success": "Erfolgreich heruntergeladen",
   "image_viewer_page_state_provider_download_success": "Erfolgreich heruntergeladen",
   "library_page_albums": "Alben",
   "library_page_albums": "Alben",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Teilen",
   "library_page_sharing": "Teilen",
   "library_page_sort_created": "Zuletzt erstellt",
   "library_page_sort_created": "Zuletzt erstellt",
   "library_page_sort_title": "Albumtitel",
   "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_api_exception": "API Fehler. Bitte die Serveradresse überprüfen und erneut versuchen.",
   "login_form_button_text": "Anmelden",
   "login_form_button_text": "Anmelden",
   "login_form_email_hint": "deine@email.de",
   "login_form_email_hint": "deine@email.de",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Ich habe verstanden",
   "version_announcement_overlay_release_notes": "Änderungsprotokoll",
   "version_announcement_overlay_release_notes": "Änderungsprotokoll",
   "version_announcement_overlay_text_1": "Hallo mein Freund! Es gibt eine neue Version von",
   "version_announcement_overlay_text_1": "Hallo mein Freund! Es gibt eine neue Version von",

+ 9 - 9
mobile/assets/i18n/en-US.json

@@ -92,11 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "backup_info_card_assets": "assets",
-  "backup_manual_success": "Success",
-  "backup_manual_failed": "Failed",
   "backup_manual_cancelled": "Cancelled",
   "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_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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_cancel": "Cancel",
   "delete_dialog_ok": "Delete",
   "delete_dialog_ok": "Delete",
   "delete_dialog_title": "Delete Permanently",
   "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_hint_text": "Add description...",
   "description_input_submit_error": "Error updating description, check the log for more details",
   "description_input_submit_error": "Error updating description, check the log for more details",
   "exif_bottom_sheet_description": "Add Description...",
   "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_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_add_to_album_success": "Added {added} assets to album {album}.",
   "home_page_archive_err_local": "Can not archive local assets yet, skipping",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -176,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -196,7 +193,6 @@
   "login_form_save_login": "Stay logged in",
   "login_form_save_login": "Stay logged in",
   "login_form_server_empty": "Enter a server URL.",
   "login_form_server_empty": "Enter a server URL.",
   "login_form_server_error": "Could not connect to server.",
   "login_form_server_error": "Could not connect to server.",
-  "login_disabled": "Login has been disabled",
   "monthly_title_text_date_format": "MMMM y",
   "monthly_title_text_date_format": "MMMM y",
   "motion_photos_page_title": "Motion Photos",
   "motion_photos_page_title": "Motion Photos",
   "notification_permission_dialog_cancel": "Cancel",
   "notification_permission_dialog_cancel": "Cancel",
@@ -295,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/es-ES.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Cargando información del archivo",
   "backup_controller_page_uploading_file_info": "Cargando información del archivo",
   "backup_err_only_album": "No se puede eliminar el único álbum",
   "backup_err_only_album": "No se puede eliminar el único álbum",
   "backup_info_card_assets": "archivos",
   "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_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
   "cache_settings_clear_cache_button": "Borrar caché",
   "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é.",
   "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_building_timeline": "Construyendo la línea de tiempo",
   "home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
   "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_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_error": "Error de descarga",
   "image_viewer_page_state_provider_download_success": "Descarga exitosa",
   "image_viewer_page_state_provider_download_success": "Descarga exitosa",
   "library_page_albums": "Álbumes",
   "library_page_albums": "Álbumes",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Compartiendo",
   "library_page_sharing": "Compartiendo",
   "library_page_sort_created": "Creado más recientemente",
   "library_page_sort_created": "Creado más recientemente",
   "library_page_sort_title": "Título del álbum",
   "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_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_button_text": "Iniciar Sesión",
   "login_form_email_hint": "tucorreo@correo.com",
   "login_form_email_hint": "tucorreo@correo.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_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",
   "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_ack": "Aceptar",
   "version_announcement_overlay_release_notes": "notas de versión",
   "version_announcement_overlay_release_notes": "notas de versión",
   "version_announcement_overlay_text_1": "Hola amigo, hay una nueva versión de",
   "version_announcement_overlay_text_1": "Hola amigo, hay una nueva versión de",

+ 11 - 0
mobile/assets/i18n/es-MX.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Cargando información del archivo",
   "backup_controller_page_uploading_file_info": "Cargando información del archivo",
   "backup_err_only_album": "No se puede eliminar el único álbum",
   "backup_err_only_album": "No se puede eliminar el único álbum",
   "backup_info_card_assets": "archivos",
   "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_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
   "cache_settings_clear_cache_button": "Borrar caché",
   "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é.",
   "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_building_timeline": "Construyendo la línea de tiempo",
   "home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
   "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_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_error": "Error de descarga",
   "image_viewer_page_state_provider_download_success": "Descarga exitosa",
   "image_viewer_page_state_provider_download_success": "Descarga exitosa",
   "library_page_albums": "Álbumes",
   "library_page_albums": "Álbumes",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Compartiendo",
   "library_page_sharing": "Compartiendo",
   "library_page_sort_created": "Creado más recientemente",
   "library_page_sort_created": "Creado más recientemente",
   "library_page_sort_title": "Título del álbum",
   "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_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_button_text": "Iniciar sesión",
   "login_form_email_hint": "tucorreo@correo.com",
   "login_form_email_hint": "tucorreo@correo.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_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",
   "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_ack": "Aceptar",
   "version_announcement_overlay_release_notes": "notas de la versión",
   "version_announcement_overlay_release_notes": "notas de la versión",
   "version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",
   "version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",

+ 11 - 0
mobile/assets/i18n/es-PE.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Cargando información del archivo",
   "backup_controller_page_uploading_file_info": "Cargando información del archivo",
   "backup_err_only_album": "No se puede eliminar el único álbum",
   "backup_err_only_album": "No se puede eliminar el único álbum",
   "backup_info_card_assets": "archivos",
   "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_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
   "cache_settings_clear_cache_button": "Borrar caché",
   "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é.",
   "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_building_timeline": "Construyendo la línea de tiempo",
   "home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
   "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_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_error": "Error de descarga",
   "image_viewer_page_state_provider_download_success": "Descarga exitosa",
   "image_viewer_page_state_provider_download_success": "Descarga exitosa",
   "library_page_albums": "Álbumes",
   "library_page_albums": "Álbumes",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Compartiendo",
   "library_page_sharing": "Compartiendo",
   "library_page_sort_created": "Creado más recientemente",
   "library_page_sort_created": "Creado más recientemente",
   "library_page_sort_title": "Título del álbum",
   "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_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_button_text": "Iniciar sesión",
   "login_form_email_hint": "tucorreo@correo.com",
   "login_form_email_hint": "tucorreo@correo.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_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",
   "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_ack": "Aceptar",
   "version_announcement_overlay_release_notes": "notas de la versión",
   "version_announcement_overlay_release_notes": "notas de la versión",
   "version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",
   "version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",

+ 11 - 0
mobile/assets/i18n/fi-FI.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Tiedostojen lähetystiedot",
   "backup_controller_page_uploading_file_info": "Tiedostojen lähetystiedot",
   "backup_err_only_album": "Vähintään yhden albumin tulee olla valittuna",
   "backup_err_only_album": "Vähintään yhden albumin tulee olla valittuna",
   "backup_info_card_assets": "kohdetta",
   "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_album_thumbnails": "Kirjastosivun esikatselukuvat ({} kohdetta)",
   "cache_settings_clear_cache_button": "Tyhjennä välimuisti",
   "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.",
   "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_building_timeline": "Rakennetaan aikajanaa",
   "home_page_favorite_err_local": "Paikallisten kohteiden lisääminen suosikkeihin ei ole mahdollista, ohitetaan",
   "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_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_error": "Lataus epäonnistui",
   "image_viewer_page_state_provider_download_success": "Lataus onnistui",
   "image_viewer_page_state_provider_download_success": "Lataus onnistui",
   "library_page_albums": "Albumit",
   "library_page_albums": "Albumit",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Jakaminen",
   "library_page_sharing": "Jakaminen",
   "library_page_sort_created": "Viimeisin luotu",
   "library_page_sort_created": "Viimeisin luotu",
   "library_page_sort_title": "Albumin otsikko",
   "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_api_exception": "API-virhe. Tarkista palvelimen URL-osoite ja yritä uudelleen.",
   "login_form_button_text": "Kirjaudu",
   "login_form_button_text": "Kirjaudu",
   "login_form_email_hint": "sahkopostisi@esimerkki.fi",
   "login_form_email_hint": "sahkopostisi@esimerkki.fi",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Teema",
   "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_subtitle": "Kolmivaiheinen lataaminen saattaa parantaa latauksen suorituskykyä, mutta lisää kaistankäyttöä huomattavasti.",
   "theme_setting_three_stage_loading_title": "Ota kolmivaiheinen lataus käyttöön",
   "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_ack": "Tiedostan",
   "version_announcement_overlay_release_notes": "julkaisutiedoissa",
   "version_announcement_overlay_release_notes": "julkaisutiedoissa",
   "version_announcement_overlay_text_1": "Hei, kaveri! Uusi palvelinversio on saatavilla sovelluksesta",
   "version_announcement_overlay_text_1": "Hei, kaveri! Uusi palvelinversio on saatavilla sovelluksesta",

+ 11 - 0
mobile/assets/i18n/fr-FR.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Transfert des informations du fichier",
   "backup_controller_page_uploading_file_info": "Transfert des informations du fichier",
   "backup_err_only_album": "Impossible de retirer le seul album",
   "backup_err_only_album": "Impossible de retirer le seul album",
   "backup_info_card_assets": "éléments",
   "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_album_thumbnails": "Miniatures de la page bibliothèque ({} éléments)",
   "cache_settings_clear_cache_button": "Effacer le cache",
   "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.",
   "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_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_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_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_error": "Erreur de téléchargement",
   "image_viewer_page_state_provider_download_success": "Téléchargement réussi",
   "image_viewer_page_state_provider_download_success": "Téléchargement réussi",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Partage",
   "library_page_sharing": "Partage",
   "library_page_sort_created": "Créations les plus récentes",
   "library_page_sort_created": "Créations les plus récentes",
   "library_page_sort_title": "Titre de l'album",
   "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_api_exception": "Erreur de l'API. Veuillez vérifier l'URL du serveur et et réessayer.",
   "login_form_button_text": "Connexion",
   "login_form_button_text": "Connexion",
   "login_form_email_hint": "votreemail@email.com",
   "login_form_email_hint": "votreemail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Thème",
   "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_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",
   "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_ack": "Confirmer",
   "version_announcement_overlay_release_notes": "notes de mise à jour",
   "version_announcement_overlay_release_notes": "notes de mise à jour",
   "version_announcement_overlay_text_1": "Bonjour, une nouvelle version de",
   "version_announcement_overlay_text_1": "Bonjour, une nouvelle version de",

+ 11 - 0
mobile/assets/i18n/hi-IN.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/hu-HU.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_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_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_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_error": "Letöltési Hiba",
   "image_viewer_page_state_provider_download_success": "Letöltés Sikeres",
   "image_viewer_page_state_provider_download_success": "Letöltés Sikeres",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_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_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/it-IT.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Caricando informazioni sul file",
   "backup_controller_page_uploading_file_info": "Caricando informazioni sul file",
   "backup_err_only_album": "Non è possibile rimuovere l'unico album",
   "backup_err_only_album": "Non è possibile rimuovere l'unico album",
   "backup_info_card_assets": "oggetti ",
   "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_album_thumbnails": "Anteprime pagine librerie ({} assets)",
   "cache_settings_clear_cache_button": "Cancella cache",
   "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.",
   "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_building_timeline": "Costruendo il Timeline",
   "home_page_favorite_err_local": "Non puoi aggiungere tra i preferiti le foto ancora non caricate",
   "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_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_error": "Errore nel Download",
   "image_viewer_page_state_provider_download_success": "Download con successo",
   "image_viewer_page_state_provider_download_success": "Download con successo",
   "library_page_albums": "Album",
   "library_page_albums": "Album",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Condividendo",
   "library_page_sharing": "Condividendo",
   "library_page_sort_created": "Creato il più recente",
   "library_page_sort_created": "Creato il più recente",
   "library_page_sort_title": "Titolo album",
   "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_api_exception": "API error, per favore ricontrolli URL del server e riprovi",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "tuaemail@email.com",
   "login_form_email_hint": "tuaemail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_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",
   "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_ack": "Presa visione",
   "version_announcement_overlay_release_notes": "note di rilascio ",
   "version_announcement_overlay_release_notes": "note di rilascio ",
   "version_announcement_overlay_text_1": "Ciao, c'è una nuova versione di",
   "version_announcement_overlay_text_1": "Ciao, c'è una nuova versione di",

+ 11 - 0
mobile/assets/i18n/ja-JP.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "アップロード中のファイル",
   "backup_controller_page_uploading_file_info": "アップロード中のファイル",
   "backup_err_only_album": "最低1つのアルバムを選択してください",
   "backup_err_only_album": "最低1つのアルバムを選択してください",
   "backup_info_card_assets": "写真と動画",
   "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_album_thumbnails": "ライブラリのサムネイル ({}枚)",
   "cache_settings_clear_cache_button": "キャッシュをクリア",
   "cache_settings_clear_cache_button": "キャッシュをクリア",
   "cache_settings_clear_cache_button_title": "キャッシュを削除(キャッシュ再生成までアプリのパフォーマンスが著しく低下)",
   "cache_settings_clear_cache_button_title": "キャッシュを削除(キャッシュ再生成までアプリのパフォーマンスが著しく低下)",
@@ -156,6 +161,7 @@
   "home_page_building_timeline": "タイムライン構築中",
   "home_page_building_timeline": "タイムライン構築中",
   "home_page_favorite_err_local": "まだアップロードされてない項目はお気に入り登録できません",
   "home_page_favorite_err_local": "まだアップロードされてない項目はお気に入り登録できません",
   "home_page_first_time_notice": "はじめてアプリを使う場合、タイムラインに写真を表示するためにアルバムを選択してください",
   "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_error": "ダウンロード失敗",
   "image_viewer_page_state_provider_download_success": "ダウンロード成功",
   "image_viewer_page_state_provider_download_success": "ダウンロード成功",
   "library_page_albums": "アルバム",
   "library_page_albums": "アルバム",
@@ -166,6 +172,7 @@
   "library_page_sharing": "共有中",
   "library_page_sharing": "共有中",
   "library_page_sort_created": "作成日時",
   "library_page_sort_created": "作成日時",
   "library_page_sort_title": "アルバム名",
   "library_page_sort_title": "アルバム名",
+  "login_disabled": "Login has been disabled",
   "login_form_api_exception": "APIエラー。URLをチェックしてもう一度試してください",
   "login_form_api_exception": "APIエラー。URLをチェックしてもう一度試してください",
   "login_form_button_text": "ログイン",
   "login_form_button_text": "ログイン",
   "login_form_email_hint": "hoge@email.com",
   "login_form_email_hint": "hoge@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "テーマ",
   "theme_setting_theme_title": "テーマ",
   "theme_setting_three_stage_loading_subtitle": "三段階読み込みを有効にするとパフォーマンスが改善する可能性がありますが、ネットワーク負荷が著しく増加します",
   "theme_setting_three_stage_loading_subtitle": "三段階読み込みを有効にするとパフォーマンスが改善する可能性がありますが、ネットワーク負荷が著しく増加します",
   "theme_setting_three_stage_loading_title": "三段階読み込みをオンにする",
   "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_ack": "了解",
   "version_announcement_overlay_release_notes": "更新情報",
   "version_announcement_overlay_release_notes": "更新情報",
   "version_announcement_overlay_text_1": "こんにちは、またはこんばんは!新しい",
   "version_announcement_overlay_text_1": "こんにちは、またはこんばんは!新しい",

+ 11 - 0
mobile/assets/i18n/ko-KR.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "파일 정보 업로드 중",
   "backup_controller_page_uploading_file_info": "파일 정보 업로드 중",
   "backup_err_only_album": "유일한 앨범은 제거할 수 없습니다",
   "backup_err_only_album": "유일한 앨범은 제거할 수 없습니다",
   "backup_info_card_assets": "미디어",
   "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_album_thumbnails": "라이브러리 페이지 썸네일 ({} 미디어)",
   "cache_settings_clear_cache_button": "캐시 지우기",
   "cache_settings_clear_cache_button": "캐시 지우기",
   "cache_settings_clear_cache_button_title": "앱의 캐시를 지웁니다. 이 작업은 캐시가 다시 빌드될 때까지 앱의 성능에 상당한 영향을 미칩니다.",
   "cache_settings_clear_cache_button_title": "앱의 캐시를 지웁니다. 이 작업은 캐시가 다시 빌드될 때까지 앱의 성능에 상당한 영향을 미칩니다.",
@@ -156,6 +161,7 @@
   "home_page_building_timeline": "타임라인 생성",
   "home_page_building_timeline": "타임라인 생성",
   "home_page_favorite_err_local": "미디어파일을 즐겨찾기에 추가할 수 없어, 건너뜁니다.",
   "home_page_favorite_err_local": "미디어파일을 즐겨찾기에 추가할 수 없어, 건너뜁니다.",
   "home_page_first_time_notice": "앱을 처음 사용하는 경우 타임라인이 앨범의 사진과 비디오를 채울 수 있도록 백업대상 앨범을 선택해야 합니다.",
   "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_error": "다운로드 에러",
   "image_viewer_page_state_provider_download_success": "다운로드 완료",
   "image_viewer_page_state_provider_download_success": "다운로드 완료",
   "library_page_albums": "앨범",
   "library_page_albums": "앨범",
@@ -166,6 +172,7 @@
   "library_page_sharing": "공유",
   "library_page_sharing": "공유",
   "library_page_sort_created": "최근생성일",
   "library_page_sort_created": "최근생성일",
   "library_page_sort_title": "앨범 제목",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "로그인",
   "login_form_button_text": "로그인",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "테마",
   "theme_setting_theme_title": "테마",
   "theme_setting_three_stage_loading_subtitle": "이 기능은 로딩 성능을 향상시킬 수 있지만 훨씬 더 많은 데이터를 사용합니다.",
   "theme_setting_three_stage_loading_subtitle": "이 기능은 로딩 성능을 향상시킬 수 있지만 훨씬 더 많은 데이터를 사용합니다.",
   "theme_setting_three_stage_loading_title": "3단계 로딩 활성화",
   "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_ack": "승인",
   "version_announcement_overlay_release_notes": "릴리스 정보",
   "version_announcement_overlay_release_notes": "릴리스 정보",
   "version_announcement_overlay_text_1": "안녕하세요!",
   "version_announcement_overlay_text_1": "안녕하세요!",

+ 11 - 0
mobile/assets/i18n/lv-LV.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Faila informācijas augšupielāde",
   "backup_controller_page_uploading_file_info": "Faila informācijas augšupielāde",
   "backup_err_only_album": "Nevar noņemt vienīgo albumu",
   "backup_err_only_album": "Nevar noņemt vienīgo albumu",
   "backup_info_card_assets": "aktīvi",
   "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_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": "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.",
   "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_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_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_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_error": "Lejupielādes Kļūda",
   "image_viewer_page_state_provider_download_success": "Lejupielāde Izdevās",
   "image_viewer_page_state_provider_download_success": "Lejupielāde Izdevās",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Kopīgošana",
   "library_page_sharing": "Kopīgošana",
   "library_page_sort_created": "Jaunākais izveidotais",
   "library_page_sort_created": "Jaunākais izveidotais",
   "library_page_sort_title": "Albuma virsraksts",
   "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_api_exception": "API izņēmums. Lūdzu, pārbaudiet servera URL un mēģiniet vēlreiz.",
   "login_form_button_text": "Pieteikties",
   "login_form_button_text": "Pieteikties",
   "login_form_email_hint": "jūsuepasts@email.com",
   "login_form_email_hint": "jūsuepasts@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Dizains",
   "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_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",
   "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_ack": "Atzīt",
   "version_announcement_overlay_release_notes": "informācija par laidienu",
   "version_announcement_overlay_release_notes": "informācija par laidienu",
   "version_announcement_overlay_text_1": "Sveiks draugs, ir jauns izlaidums no",
   "version_announcement_overlay_text_1": "Sveiks draugs, ir jauns izlaidums no",

+ 11 - 0
mobile/assets/i18n/mn.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/nb-NO.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Laster opp filinformasjon",
   "backup_controller_page_uploading_file_info": "Laster opp filinformasjon",
   "backup_err_only_album": "Kan ikke fjerne det eneste albumet",
   "backup_err_only_album": "Kan ikke fjerne det eneste albumet",
   "backup_info_card_assets": "objekter",
   "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_album_thumbnails": "Bibliotekminiatyrbilder ({} objekter)",
   "cache_settings_clear_cache_button": "Tøm buffer",
   "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.",
   "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_building_timeline": "Genererer tidslinjen",
   "home_page_favorite_err_local": "Kan ikke sette favoritt på lokale objekter enda, hopper over",
   "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_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_error": "Nedlasting feilet",
   "image_viewer_page_state_provider_download_success": "Nedlasting vellykket",
   "image_viewer_page_state_provider_download_success": "Nedlasting vellykket",
   "library_page_albums": "Albumer",
   "library_page_albums": "Albumer",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Deling",
   "library_page_sharing": "Deling",
   "library_page_sort_created": "Nylig opplastet",
   "library_page_sort_created": "Nylig opplastet",
   "library_page_sort_title": "Albumtittel",
   "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_api_exception": "API-feil. Sjekk URL-en til serveren og prøv igjen.",
   "login_form_button_text": "Logg inn",
   "login_form_button_text": "Logg inn",
   "login_form_email_hint": "dinepost@epost.no",
   "login_form_email_hint": "dinepost@epost.no",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_subtitle": "Tre-trinns innlasting kan øke lasteytelsen, men forårsaker betydelig høyere nettverksbelastning",
   "theme_setting_three_stage_loading_title": "Aktiver tre-trinns innlasting",
   "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_ack": "Bekreft",
   "version_announcement_overlay_release_notes": "endringsloggen",
   "version_announcement_overlay_release_notes": "endringsloggen",
   "version_announcement_overlay_text_1": "Hei, det er en ny versjon av",
   "version_announcement_overlay_text_1": "Hei, det er en ny versjon av",

+ 11 - 0
mobile/assets/i18n/nl-NL.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Bestandsgegevens uploaden",
   "backup_controller_page_uploading_file_info": "Bestandsgegevens uploaden",
   "backup_err_only_album": "Kan het enige album niet verwijderen",
   "backup_err_only_album": "Kan het enige album niet verwijderen",
   "backup_info_card_assets": "items",
   "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_album_thumbnails": "Thumbnails bibliotheekpagina ({} items)",
   "cache_settings_clear_cache_button": "Cache wissen",
   "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.",
   "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_building_timeline": "Tijdlijn opbouwen",
   "home_page_favorite_err_local": "Lokale items kunnen nog niet als favoriet worden aangemerkt, overslaan",
   "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_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_error": "Download mislukt",
   "image_viewer_page_state_provider_download_success": "Download succesvol",
   "image_viewer_page_state_provider_download_success": "Download succesvol",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Gedeeld",
   "library_page_sharing": "Gedeeld",
   "library_page_sort_created": "Meest recent gemaakt",
   "library_page_sort_created": "Meest recent gemaakt",
   "library_page_sort_title": "Albumtitel",
   "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_api_exception": "API fout. Controleer de server URL en probeer opnieuw.",
   "login_form_button_text": "Inloggen",
   "login_form_button_text": "Inloggen",
   "login_form_email_hint": "jouwemail@email.com",
   "login_form_email_hint": "jouwemail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Thema",
   "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_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",
   "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_ack": "Bevestig",
   "version_announcement_overlay_release_notes": "releaseopmerkingen",
   "version_announcement_overlay_release_notes": "releaseopmerkingen",
   "version_announcement_overlay_text_1": "Hoi, er is een nieuwe versie beschikbaar van",
   "version_announcement_overlay_text_1": "Hoi, er is een nieuwe versie beschikbaar van",

+ 11 - 0
mobile/assets/i18n/pl-PL.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Przesyłanie informacji o pliku",
   "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_err_only_album": "Nie można usunąć tylko i wyłącznie albumu",
   "backup_info_card_assets": "zasoby",
   "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_album_thumbnails": "Miniatury stron bibliotek ({} zasobów)",
   "cache_settings_clear_cache_button": "Wyczyść Cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albumy",
   "library_page_albums": "Albumy",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "twojmail@email.com",
   "login_form_email_hint": "twojmail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Motyw",
   "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_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",
   "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_ack": "Potwierdzam",
   "version_announcement_overlay_release_notes": "informacje o wydaniu",
   "version_announcement_overlay_release_notes": "informacje o wydaniu",
   "version_announcement_overlay_text_1": "Cześć przyjacielu, jest nowe wydanie",
   "version_announcement_overlay_text_1": "Cześć przyjacielu, jest nowe wydanie",

+ 11 - 0
mobile/assets/i18n/ru-RU.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Загрузка информации о файле",
   "backup_controller_page_uploading_file_info": "Загрузка информации о файле",
   "backup_err_only_album": "Невозможно удалить единственный альбом",
   "backup_err_only_album": "Невозможно удалить единственный альбом",
   "backup_info_card_assets": "объекты",
   "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_album_thumbnails": "Миниатюры страниц библиотеки ({} объектов)",
   "cache_settings_clear_cache_button": "Очистить кэш",
   "cache_settings_clear_cache_button": "Очистить кэш",
   "cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это значительно повлияет на производительность приложения, до тех пор, пока кэш не будет перестроен заново.",
   "cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это значительно повлияет на производительность приложения, до тех пор, пока кэш не будет перестроен заново.",
@@ -156,6 +161,7 @@
   "home_page_building_timeline": "Построение временной шкалы",
   "home_page_building_timeline": "Построение временной шкалы",
   "home_page_favorite_err_local": "Пока не удается добавить в избранное локальные объекты, пропускаем",
   "home_page_favorite_err_local": "Пока не удается добавить в избранное локальные объекты, пропускаем",
   "home_page_first_time_notice": "Если вы используете приложение впервые, убедитесь, что вы выбрали резервный(е) альбом(ы), чтобы временная шкала могла заполнить фотографии и видео в альбоме(ах).",
   "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_error": "Ошибка загрузки",
   "image_viewer_page_state_provider_download_success": "Успешно загружено",
   "image_viewer_page_state_provider_download_success": "Успешно загружено",
   "library_page_albums": "Альбомы",
   "library_page_albums": "Альбомы",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Общие",
   "library_page_sharing": "Общие",
   "library_page_sort_created": "По новизне",
   "library_page_sort_created": "По новизне",
   "library_page_sort_title": "По названию альбома",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Войти",
   "login_form_button_text": "Войти",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Тема",
   "theme_setting_theme_title": "Тема",
   "theme_setting_three_stage_loading_subtitle": "Трехэтапная загрузка может повысить производительность загрузки, но вызывает значительно более высокую нагрузку на сеть",
   "theme_setting_three_stage_loading_subtitle": "Трехэтапная загрузка может повысить производительность загрузки, но вызывает значительно более высокую нагрузку на сеть",
   "theme_setting_three_stage_loading_title": "Включить трехэтапную загрузку",
   "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_ack": "Подтверждение",
   "version_announcement_overlay_release_notes": "примечания к выпуску",
   "version_announcement_overlay_release_notes": "примечания к выпуску",
   "version_announcement_overlay_text_1": "Привет друг, вышел новый релиз",
   "version_announcement_overlay_text_1": "Привет друг, вышел новый релиз",

+ 11 - 0
mobile/assets/i18n/sk-SK.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Nahrávaný súbor",
   "backup_controller_page_uploading_file_info": "Nahrávaný súbor",
   "backup_err_only_album": "Nie je možné odstrániť jediný vybraný album",
   "backup_err_only_album": "Nie je možné odstrániť jediný vybraný album",
   "backup_info_card_assets": "položiek",
   "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_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": "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í.",
   "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_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_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_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_error": "Chyba sťahovania",
   "image_viewer_page_state_provider_download_success": "Sťahovanie bolo úspešné",
   "image_viewer_page_state_provider_download_success": "Sťahovanie bolo úspešné",
   "library_page_albums": "Albumy",
   "library_page_albums": "Albumy",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Zdieľanie",
   "library_page_sharing": "Zdieľanie",
   "library_page_sort_created": "Najnovšie vytvorené",
   "library_page_sort_created": "Najnovšie vytvorené",
   "library_page_sort_title": "Podľa názvu albumu",
   "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_api_exception": "Chyba API. Skontrolujte adresu URL servera a skúste to znova.",
   "login_form_button_text": "Prihlásiť sa",
   "login_form_button_text": "Prihlásiť sa",
   "login_form_email_hint": "tvojmail@email.com",
   "login_form_email_hint": "tvojmail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Téma",
   "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_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",
   "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_ack": "Potvrdiť",
   "version_announcement_overlay_release_notes": "poznámky k vydaniu",
   "version_announcement_overlay_release_notes": "poznámky k vydaniu",
   "version_announcement_overlay_text_1": "Ahoj, je tu nová verzia",
   "version_announcement_overlay_text_1": "Ahoj, je tu nová verzia",

+ 11 - 0
mobile/assets/i18n/sr-Cyrl.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/sr-Latn.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Otpremanje svojstava datoteke",
   "backup_controller_page_uploading_file_info": "Otpremanje svojstava datoteke",
   "backup_err_only_album": "Nemoguće brisanje jedinog albuma",
   "backup_err_only_album": "Nemoguće brisanje jedinog albuma",
   "backup_info_card_assets": "zapisi",
   "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_album_thumbnails": "Sličice na stranici biblioteke",
   "cache_settings_clear_cache_button": "Obriši keš memoriju",
   "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.",
   "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_building_timeline": "Kreiranje hronološke linije",
   "home_page_favorite_err_local": "Trenutno nije moguce dodati lokalne zapise u favorite, preskacu se",
   "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_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_error": "Preuzimanje Neuspešno",
   "image_viewer_page_state_provider_download_success": "Preuzimanje Uspešno",
   "image_viewer_page_state_provider_download_success": "Preuzimanje Uspešno",
   "library_page_albums": "Albumi",
   "library_page_albums": "Albumi",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Deljenje",
   "library_page_sharing": "Deljenje",
   "library_page_sort_created": "Najnovije kreirano",
   "library_page_sort_created": "Najnovije kreirano",
   "library_page_sort_title": "Naziv albuma",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Prijavi se",
   "login_form_button_text": "Prijavi se",
   "login_form_email_hint": "vašemail@email.com",
   "login_form_email_hint": "vašemail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Teme",
   "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_subtitle": "Trostepeno učitavanje možda ubrza učitavanje, po cenu potrošnje podataka",
   "theme_setting_three_stage_loading_title": "Aktiviraj trostepeno učitavanje",
   "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_ack": "Priznati",
   "version_announcement_overlay_release_notes": "novine nove verzije",
   "version_announcement_overlay_release_notes": "novine nove verzije",
   "version_announcement_overlay_text_1": "Ćao, nova verzija",
   "version_announcement_overlay_text_1": "Ćao, nova verzija",

+ 11 - 0
mobile/assets/i18n/sv-FI.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/sv-SE.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Laddar upp filinformation",
   "backup_controller_page_uploading_file_info": "Laddar upp filinformation",
   "backup_err_only_album": "Kan inte ta bort det enda albumet",
   "backup_err_only_album": "Kan inte ta bort det enda albumet",
   "backup_info_card_assets": "objekt",
   "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_album_thumbnails": "Miniatyrbilder för bibliotek ({} bilder och videor)",
   "cache_settings_clear_cache_button": "Rensa cacheminnet",
   "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.",
   "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_building_timeline": "Bygger tidslinjen",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Album",
   "library_page_albums": "Album",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Delas",
   "library_page_sharing": "Delas",
   "library_page_sort_created": "Senast skapad",
   "library_page_sort_created": "Senast skapad",
   "library_page_sort_title": "Albumtitel",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Logga in",
   "login_form_button_text": "Logga in",
   "login_form_email_hint": "din.email@email.com",
   "login_form_email_hint": "din.email@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Tema",
   "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_subtitle": "Trestegsladdning kan öka prestandan, men kan också leda till signifikant högre nätverksbelastning",
   "theme_setting_three_stage_loading_title": "Aktivera trestegsladdning",
   "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_ack": "Bekräfta",
   "version_announcement_overlay_release_notes": "versionsinformation",
   "version_announcement_overlay_release_notes": "versionsinformation",
   "version_announcement_overlay_text_1": "Hej vännen, det finns en ny version av",
   "version_announcement_overlay_text_1": "Hej vännen, det finns en ny version av",

+ 11 - 0
mobile/assets/i18n/th-TH.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "ไม่สามารถนำอัลบั้มสุดท้ายออกได้",
   "backup_err_only_album": "ไม่สามารถนำอัลบั้มสุดท้ายออกได้",
   "backup_info_card_assets": "ทรัพยากร",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "ล้างแคช",
   "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.",
   "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_building_timeline": "กำลังสร้าง timeline",
   "home_page_favorite_err_local": " ไม่สามารถตั้งทรัพยากรบนเครื่องเป็นรายการโปรด กำลังข้าม",
   "home_page_favorite_err_local": " ไม่สามารถตั้งทรัพยากรบนเครื่องเป็นรายการโปรด กำลังข้าม",
   "home_page_first_time_notice": "ถ้าครั้งนี้เป็นครั้งแรกที่ใช้แอปนี้ กรุณาเลือกอัลบั้มที่จะสำรองข้อมูล ไทม์ไลน์จะได้เพิ่มรูปภาพและวิดีโอที่อยู่ในอัลบั้ม",
   "home_page_first_time_notice": "ถ้าครั้งนี้เป็นครั้งแรกที่ใช้แอปนี้ กรุณาเลือกอัลบั้มที่จะสำรองข้อมูล ไทม์ไลน์จะได้เพิ่มรูปภาพและวิดีโอที่อยู่ในอัลบั้ม",
+  "home_page_upload_err_limit": "สามารถอัพโหลดได้มากสุดครั้งละ 30 ทรัพยากร กำลังข้าม",
   "image_viewer_page_state_provider_download_error": "ดาวน์โหลดผิดพลาด",
   "image_viewer_page_state_provider_download_error": "ดาวน์โหลดผิดพลาด",
   "image_viewer_page_state_provider_download_success": "ดาวน์โหลดสำเร็จ",
   "image_viewer_page_state_provider_download_success": "ดาวน์โหลดสำเร็จ",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "การแชร์",
   "library_page_sharing": "การแชร์",
   "library_page_sort_created": "สร้างล่าสุด",
   "library_page_sort_created": "สร้างล่าสุด",
   "library_page_sort_title": "ชื่ออัลบั้ม",
   "library_page_sort_title": "ชื่ออัลบั้ม",
+  "login_disabled": "ล็อกอินถูกปิด",
   "login_form_api_exception": "ข้อผิดพลาด API กรุณาตรวจสอบ URL แล้วลองใหม่",
   "login_form_api_exception": "ข้อผิดพลาด API กรุณาตรวจสอบ URL แล้วลองใหม่",
   "login_form_button_text": "เข้าสู่ระบบ",
   "login_form_button_text": "เข้าสู่ระบบ",
   "login_form_email_hint": "อีเมลคุณ@อีเมล.com",
   "login_form_email_hint": "อีเมลคุณ@อีเมล.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/uk-UA.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/vi-VN.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_controller_page_uploading_file_info": "Uploading file info",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_err_only_album": "Cannot remove the only album",
   "backup_info_card_assets": "assets",
   "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_album_thumbnails": "Library page thumbnails ({} assets)",
   "cache_settings_clear_cache_button": "Clear cache",
   "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.",
   "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_building_timeline": "Building the timeline",
   "home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
   "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_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_error": "Download Error",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "image_viewer_page_state_provider_download_success": "Download Success",
   "library_page_albums": "Albums",
   "library_page_albums": "Albums",
@@ -166,6 +172,7 @@
   "library_page_sharing": "Sharing",
   "library_page_sharing": "Sharing",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_created": "Most recently created",
   "library_page_sort_title": "Album title",
   "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_api_exception": "API exception. Please check the server URL and try again.",
   "login_form_button_text": "Login",
   "login_form_button_text": "Login",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "Theme",
   "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_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",
   "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_ack": "Acknowledge",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_release_notes": "release notes",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",
   "version_announcement_overlay_text_1": "Hi friend, there is a new release of",

+ 11 - 0
mobile/assets/i18n/zh-CN.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "正在上传文件信息",
   "backup_controller_page_uploading_file_info": "正在上传文件信息",
   "backup_err_only_album": "不能移除唯一的一个相册",
   "backup_err_only_album": "不能移除唯一的一个相册",
   "backup_info_card_assets": "张",
   "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_album_thumbnails": "图库缩略图({} 张)",
   "cache_settings_clear_cache_button": "清除缓存",
   "cache_settings_clear_cache_button": "清除缓存",
   "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
   "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
@@ -156,6 +161,7 @@
   "home_page_building_timeline": "正在生成时间线",
   "home_page_building_timeline": "正在生成时间线",
   "home_page_favorite_err_local": "暂不能收藏本地项目,跳过",
   "home_page_favorite_err_local": "暂不能收藏本地项目,跳过",
   "home_page_first_time_notice": "如果这是您第一次使用该应用程序,请确保选择一个要备份的本地相册,以便可以在时间线中预览该相册中的照片和视频。",
   "home_page_first_time_notice": "如果这是您第一次使用该应用程序,请确保选择一个要备份的本地相册,以便可以在时间线中预览该相册中的照片和视频。",
+  "home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
   "image_viewer_page_state_provider_download_error": "下载出现错误",
   "image_viewer_page_state_provider_download_error": "下载出现错误",
   "image_viewer_page_state_provider_download_success": "下载成功",
   "image_viewer_page_state_provider_download_success": "下载成功",
   "library_page_albums": "相册",
   "library_page_albums": "相册",
@@ -166,6 +172,7 @@
   "library_page_sharing": "共享",
   "library_page_sharing": "共享",
   "library_page_sort_created": "最近创建的",
   "library_page_sort_created": "最近创建的",
   "library_page_sort_title": "相册标题",
   "library_page_sort_title": "相册标题",
+  "login_disabled": "登录已被禁用",
   "login_form_api_exception": "API 异常,请检查服务器地址并重试。",
   "login_form_api_exception": "API 异常,请检查服务器地址并重试。",
   "login_form_button_text": "登录",
   "login_form_button_text": "登录",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "主题",
   "theme_setting_theme_title": "主题",
   "theme_setting_three_stage_loading_subtitle": "三段式加载可能会提升加载性能,但可能会导致更高的网络负载",
   "theme_setting_three_stage_loading_subtitle": "三段式加载可能会提升加载性能,但可能会导致更高的网络负载",
   "theme_setting_three_stage_loading_title": "启用三段式加载",
   "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_ack": "我知道了",
   "version_announcement_overlay_release_notes": "发行说明",
   "version_announcement_overlay_release_notes": "发行说明",
   "version_announcement_overlay_text_1": "号外号外,有新版本的",
   "version_announcement_overlay_text_1": "号外号外,有新版本的",

+ 11 - 0
mobile/assets/i18n/zh-Hans.json

@@ -92,6 +92,11 @@
   "backup_controller_page_uploading_file_info": "正在上传文件信息",
   "backup_controller_page_uploading_file_info": "正在上传文件信息",
   "backup_err_only_album": "不能移除唯一的一个相册",
   "backup_err_only_album": "不能移除唯一的一个相册",
   "backup_info_card_assets": "张",
   "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_album_thumbnails": "图库缩略图({} 张)",
   "cache_settings_clear_cache_button": "清除缓存",
   "cache_settings_clear_cache_button": "清除缓存",
   "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
   "cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
@@ -156,6 +161,7 @@
   "home_page_building_timeline": "正在生成时间线",
   "home_page_building_timeline": "正在生成时间线",
   "home_page_favorite_err_local": "暂不能收藏本地项目,跳过",
   "home_page_favorite_err_local": "暂不能收藏本地项目,跳过",
   "home_page_first_time_notice": "如果这是您第一次使用该应用程序,请确保选择一个要备份的本地相册,以便可以在时间线中预览该相册中的照片和视频。",
   "home_page_first_time_notice": "如果这是您第一次使用该应用程序,请确保选择一个要备份的本地相册,以便可以在时间线中预览该相册中的照片和视频。",
+  "home_page_upload_err_limit": "一次最多只能上传 30 个项目,跳过",
   "image_viewer_page_state_provider_download_error": "下载出现错误",
   "image_viewer_page_state_provider_download_error": "下载出现错误",
   "image_viewer_page_state_provider_download_success": "下载成功",
   "image_viewer_page_state_provider_download_success": "下载成功",
   "library_page_albums": "相册",
   "library_page_albums": "相册",
@@ -166,6 +172,7 @@
   "library_page_sharing": "共享",
   "library_page_sharing": "共享",
   "library_page_sort_created": "最近创建的",
   "library_page_sort_created": "最近创建的",
   "library_page_sort_title": "相册标题",
   "library_page_sort_title": "相册标题",
+  "login_disabled": "登录已被禁用",
   "login_form_api_exception": "API 异常,请检查服务器地址并重试。",
   "login_form_api_exception": "API 异常,请检查服务器地址并重试。",
   "login_form_button_text": "登录",
   "login_form_button_text": "登录",
   "login_form_email_hint": "youremail@email.com",
   "login_form_email_hint": "youremail@email.com",
@@ -284,6 +291,10 @@
   "theme_setting_theme_title": "主题",
   "theme_setting_theme_title": "主题",
   "theme_setting_three_stage_loading_subtitle": "三段式加载可能会提升加载性能,但可能会导致更高的网络负载",
   "theme_setting_three_stage_loading_subtitle": "三段式加载可能会提升加载性能,但可能会导致更高的网络负载",
   "theme_setting_three_stage_loading_title": "启用三段式加载",
   "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_ack": "我知道了",
   "version_announcement_overlay_release_notes": "发行说明",
   "version_announcement_overlay_release_notes": "发行说明",
   "version_announcement_overlay_text_1": "号外号外,有新版本的",
   "version_announcement_overlay_text_1": "号外号外,有新版本的",

+ 1 - 1
mobile/ios/Podfile.lock

@@ -163,4 +163,4 @@ SPEC CHECKSUMS:
 
 
 PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
 PODFILE CHECKSUM: 599d8aeb73728400c15364e734525722250a5382
 
 
-COCOAPODS: 1.11.3
+COCOAPODS: 1.12.1

+ 3 - 3
mobile/ios/Runner.xcodeproj/project.pbxproj

@@ -379,7 +379,7 @@
 				CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
 				CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 110;
+				CURRENT_PROJECT_VERSION = 113;
 				DEVELOPMENT_TEAM = 2F67MQ8R79;
 				DEVELOPMENT_TEAM = 2F67MQ8R79;
 				ENABLE_BITCODE = NO;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
 				INFOPLIST_FILE = Runner/Info.plist;
@@ -515,7 +515,7 @@
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 110;
+				CURRENT_PROJECT_VERSION = 113;
 				DEVELOPMENT_TEAM = 2F67MQ8R79;
 				DEVELOPMENT_TEAM = 2F67MQ8R79;
 				ENABLE_BITCODE = NO;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
 				INFOPLIST_FILE = Runner/Info.plist;
@@ -543,7 +543,7 @@
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 110;
+				CURRENT_PROJECT_VERSION = 113;
 				DEVELOPMENT_TEAM = 2F67MQ8R79;
 				DEVELOPMENT_TEAM = 2F67MQ8R79;
 				ENABLE_BITCODE = NO;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = Runner/Info.plist;
 				INFOPLIST_FILE = Runner/Info.plist;

+ 2 - 2
mobile/ios/Runner/Info.plist

@@ -59,11 +59,11 @@
     <key>CFBundlePackageType</key>
     <key>CFBundlePackageType</key>
     <string>APPL</string>
     <string>APPL</string>
     <key>CFBundleShortVersionString</key>
     <key>CFBundleShortVersionString</key>
-    <string>1.70.0</string>
+    <string>1.73.0</string>
     <key>CFBundleSignature</key>
     <key>CFBundleSignature</key>
     <string>????</string>
     <string>????</string>
     <key>CFBundleVersion</key>
     <key>CFBundleVersion</key>
-    <string>110</string>
+    <string>113</string>
     <key>FLTEnableImpeller</key>
     <key>FLTEnableImpeller</key>
     <true />
     <true />
     <key>ITSAppUsesNonExemptEncryption</key>
     <key>ITSAppUsesNonExemptEncryption</key>

+ 1 - 1
mobile/ios/fastlane/Fastfile

@@ -19,7 +19,7 @@ platform :ios do
   desc "iOS Beta"
   desc "iOS Beta"
   lane :beta do
   lane :beta do
     increment_version_number(
     increment_version_number(
-      version_number: "1.72.2"
+      version_number: "1.73.0"
     )
     )
     increment_build_number(
     increment_build_number(
       build_number: latest_testflight_build_number + 1,
       build_number: latest_testflight_build_number + 1,

+ 6 - 6
mobile/ios/fastlane/report.xml

@@ -5,32 +5,32 @@
     
     
     
     
       
       
-      <testcase classname="fastlane.lanes" name="0: default_platform" time="0.000211">
+      <testcase classname="fastlane.lanes" name="0: default_platform" time="0.000187">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="1: increment_version_number" time="2.108738">
+      <testcase classname="fastlane.lanes" name="1: increment_version_number" time="2.403882">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="28.952846">
+      <testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="5.068392">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="3: increment_build_number" time="1.821481">
+      <testcase classname="fastlane.lanes" name="3: increment_build_number" time="1.988079">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="4: build_app" time="99.212621">
+      <testcase classname="fastlane.lanes" name="4: build_app" time="96.47923">
         
         
       </testcase>
       </testcase>
     
     
       
       
-      <testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="68.366701">
+      <testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="57.517755">
         
         
       </testcase>
       </testcase>
     
     

+ 5 - 4
mobile/lib/modules/home/views/home_page.dart

@@ -342,10 +342,11 @@ class HomePage extends HookConsumerWidget {
                           listener: selectionListener,
                           listener: selectionListener,
                           selectionActive: selectionEnabledHook.value,
                           selectionActive: selectionEnabledHook.value,
                           onRefresh: refreshAssets,
                           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())),
                   error: (error, _) => Center(child: Text(error.toString())),
                   loading: buildLoadingIndicator,
                   loading: buildLoadingIndicator,

+ 1 - 1
mobile/lib/shared/models/user.dart

@@ -44,7 +44,7 @@ class User {
   bool isPartnerSharedWith;
   bool isPartnerSharedWith;
   bool isAdmin;
   bool isAdmin;
   String profileImagePath;
   String profileImagePath;
-  bool memoryEnabled;
+  bool? memoryEnabled;
   @Backlink(to: 'owner')
   @Backlink(to: 'owner')
   final IsarLinks<Album> albums = IsarLinks<Album>();
   final IsarLinks<Album> albums = IsarLinks<Album>();
   @Backlink(to: 'sharedUsers')
   @Backlink(to: 'sharedUsers')

+ 7 - 0
mobile/lib/shared/providers/admin_provider.dart

@@ -0,0 +1,7 @@
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/shared/providers/user.provider.dart';
+
+final isAdminProvider = Provider<bool>((ref) {
+  final currentUser = ref.watch(currentUserProvider);
+  return currentUser?.isAdmin ?? false;  // Default to non-admin if no user
+});

+ 7 - 0
mobile/lib/shared/views/version_announcement_overlay.dart

@@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:immich_mobile/shared/providers/release_info.provider.dart';
 import 'package:immich_mobile/shared/providers/release_info.provider.dart';
+import 'package:immich_mobile/shared/providers/admin_provider.dart';
 import 'package:url_launcher/url_launcher.dart';
 import 'package:url_launcher/url_launcher.dart';
 
 
 class VersionAnnouncementOverlay extends HookConsumerWidget {
 class VersionAnnouncementOverlay extends HookConsumerWidget {
@@ -12,6 +13,12 @@ class VersionAnnouncementOverlay extends HookConsumerWidget {
 
 
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
+    final bool isAdmin = ref.watch(isAdminProvider);
+
+    if (!isAdmin) {
+      return const SizedBox.shrink();  // Don't show anything for non-admins
+    }
+
     void goToReleaseNote() async {
     void goToReleaseNote() async {
       final Uri url =
       final Uri url =
           Uri.parse('https://github.com/immich-app/immich/releases/latest');
           Uri.parse('https://github.com/immich-app/immich/releases/latest');

+ 3 - 0
mobile/openapi/.openapi-generator/FILES

@@ -45,6 +45,7 @@ doc/DeleteAssetDto.md
 doc/DeleteAssetResponseDto.md
 doc/DeleteAssetResponseDto.md
 doc/DeleteAssetStatus.md
 doc/DeleteAssetStatus.md
 doc/DownloadArchiveInfo.md
 doc/DownloadArchiveInfo.md
+doc/DownloadInfoDto.md
 doc/DownloadResponseDto.md
 doc/DownloadResponseDto.md
 doc/ExifResponseDto.md
 doc/ExifResponseDto.md
 doc/ImportAssetDto.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_response_dto.dart
 lib/model/delete_asset_status.dart
 lib/model/delete_asset_status.dart
 lib/model/download_archive_info.dart
 lib/model/download_archive_info.dart
+lib/model/download_info_dto.dart
 lib/model/download_response_dto.dart
 lib/model/download_response_dto.dart
 lib/model/exif_response_dto.dart
 lib/model/exif_response_dto.dart
 lib/model/import_asset_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_response_dto_test.dart
 test/delete_asset_status_test.dart
 test/delete_asset_status_test.dart
 test/download_archive_info_test.dart
 test/download_archive_info_test.dart
+test/download_info_dto_test.dart
 test/download_response_dto_test.dart
 test/download_response_dto_test.dart
 test/exif_response_dto_test.dart
 test/exif_response_dto_test.dart
 test/import_asset_dto_test.dart
 test/import_asset_dto_test.dart

+ 4 - 3
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:
 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
 - Build package: org.openapitools.codegen.languages.DartClientCodegen
 
 
 ## Requirements
 ## Requirements
@@ -91,7 +91,7 @@ Class | Method | HTTP request | Description
 *AssetApi* | [**checkDuplicateAsset**](doc//AssetApi.md#checkduplicateasset) | **POST** /asset/check | 
 *AssetApi* | [**checkDuplicateAsset**](doc//AssetApi.md#checkduplicateasset) | **POST** /asset/check | 
 *AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist | 
 *AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist | 
 *AssetApi* | [**deleteAsset**](doc//AssetApi.md#deleteasset) | **DELETE** /asset | 
 *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* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **POST** /asset/download/{id} | 
 *AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset | 
 *AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset | 
 *AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | 
 *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* | [**getByTimeBucket**](doc//AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket | 
 *AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | 
 *AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | 
 *AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects | 
 *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* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | 
 *AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | 
 *AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | 
 *AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | 
 *AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | 
@@ -216,6 +216,7 @@ Class | Method | HTTP request | Description
  - [DeleteAssetResponseDto](doc//DeleteAssetResponseDto.md)
  - [DeleteAssetResponseDto](doc//DeleteAssetResponseDto.md)
  - [DeleteAssetStatus](doc//DeleteAssetStatus.md)
  - [DeleteAssetStatus](doc//DeleteAssetStatus.md)
  - [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
  - [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
+ - [DownloadInfoDto](doc//DownloadInfoDto.md)
  - [DownloadResponseDto](doc//DownloadResponseDto.md)
  - [DownloadResponseDto](doc//DownloadResponseDto.md)
  - [ExifResponseDto](doc//ExifResponseDto.md)
  - [ExifResponseDto](doc//ExifResponseDto.md)
  - [ImportAssetDto](doc//ImportAssetDto.md)
  - [ImportAssetDto](doc//ImportAssetDto.md)

+ 7 - 13
mobile/openapi/doc/AssetApi.md

@@ -13,7 +13,7 @@ Method | HTTP request | Description
 [**checkDuplicateAsset**](AssetApi.md#checkduplicateasset) | **POST** /asset/check | 
 [**checkDuplicateAsset**](AssetApi.md#checkduplicateasset) | **POST** /asset/check | 
 [**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist | 
 [**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist | 
 [**deleteAsset**](AssetApi.md#deleteasset) | **DELETE** /asset | 
 [**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} | 
 [**downloadFile**](AssetApi.md#downloadfile) | **POST** /asset/download/{id} | 
 [**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | 
 [**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | 
 [**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | 
 [**getAssetById**](AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} | 
@@ -23,7 +23,7 @@ Method | HTTP request | Description
 [**getByTimeBucket**](AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket | 
 [**getByTimeBucket**](AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket | 
 [**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | 
 [**getCuratedLocations**](AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations | 
 [**getCuratedObjects**](AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects | 
 [**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 | 
 [**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | 
 [**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | 
 [**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | 
 [**getTimeBuckets**](AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets | 
 [**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)
 [[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**
 # **getDownloadInfo**
-> DownloadResponseDto getDownloadInfo(assetIds, albumId, userId, archiveSize, key)
+> DownloadResponseDto getDownloadInfo(downloadInfoDto, key)
 
 
 
 
 
 
@@ -865,14 +865,11 @@ import 'package:openapi/api.dart';
 //defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 //defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
 
 
 final api_instance = AssetApi();
 final api_instance = AssetApi();
-final assetIds = []; // List<String> | 
-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 | 
 final key = key_example; // String | 
 
 
 try {
 try {
-    final result = api_instance.getDownloadInfo(assetIds, albumId, userId, archiveSize, key);
+    final result = api_instance.getDownloadInfo(downloadInfoDto, key);
     print(result);
     print(result);
 } catch (e) {
 } catch (e) {
     print('Exception when calling AssetApi->getDownloadInfo: $e\n');
     print('Exception when calling AssetApi->getDownloadInfo: $e\n');
@@ -883,10 +880,7 @@ try {
 
 
 Name | Type | Description  | Notes
 Name | Type | Description  | Notes
 ------------- | ------------- | ------------- | -------------
 ------------- | ------------- | ------------- | -------------
- **assetIds** | [**List<String>**](String.md)|  | [optional] [default to const []]
- **albumId** | **String**|  | [optional] 
- **userId** | **String**|  | [optional] 
- **archiveSize** | **num**|  | [optional] 
+ **downloadInfoDto** | [**DownloadInfoDto**](DownloadInfoDto.md)|  | 
  **key** | **String**|  | [optional] 
  **key** | **String**|  | [optional] 
 
 
 ### Return type
 ### Return type
@@ -899,7 +893,7 @@ Name | Type | Description  | Notes
 
 
 ### HTTP request headers
 ### HTTP request headers
 
 
- - **Content-Type**: Not defined
+ - **Content-Type**: application/json
  - **Accept**: 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)
 [[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)

+ 18 - 0
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<String>** |  | [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)
+
+

+ 1 - 1
mobile/openapi/doc/UserResponseDto.md

@@ -16,7 +16,7 @@ Name | Type | Description | Notes
 **id** | **String** |  | 
 **id** | **String** |  | 
 **isAdmin** | **bool** |  | 
 **isAdmin** | **bool** |  | 
 **lastName** | **String** |  | 
 **lastName** | **String** |  | 
-**memoriesEnabled** | **bool** |  | 
+**memoriesEnabled** | **bool** |  | [optional] 
 **oauthId** | **String** |  | 
 **oauthId** | **String** |  | 
 **profileImagePath** | **String** |  | 
 **profileImagePath** | **String** |  | 
 **shouldChangePassword** | **bool** |  | 
 **shouldChangePassword** | **bool** |  | 

+ 1 - 0
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_response_dto.dart';
 part 'model/delete_asset_status.dart';
 part 'model/delete_asset_status.dart';
 part 'model/download_archive_info.dart';
 part 'model/download_archive_info.dart';
+part 'model/download_info_dto.dart';
 part 'model/download_response_dto.dart';
 part 'model/download_response_dto.dart';
 part 'model/exif_response_dto.dart';
 part 'model/exif_response_dto.dart';
 part 'model/import_asset_dto.dart';
 part 'model/import_asset_dto.dart';

+ 12 - 36
mobile/openapi/lib/api/asset_api.dart

@@ -230,7 +230,7 @@ class AssetApi {
     return null;
     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:
   /// Parameters:
   ///
   ///
   /// * [AssetIdsDto] assetIdsDto (required):
   /// * [AssetIdsDto] assetIdsDto (required):
@@ -238,7 +238,7 @@ class AssetApi {
   /// * [String] key:
   /// * [String] key:
   Future<Response> downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async {
   Future<Response> downloadArchiveWithHttpInfo(AssetIdsDto assetIdsDto, { String? key, }) async {
     // ignore: prefer_const_declarations
     // ignore: prefer_const_declarations
-    final path = r'/asset/download';
+    final path = r'/asset/download/archive';
 
 
     // ignore: prefer_final_locals
     // ignore: prefer_final_locals
     Object? postBody = assetIdsDto;
     Object? postBody = assetIdsDto;
@@ -853,51 +853,33 @@ class AssetApi {
     return null;
     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:
   /// Parameters:
   ///
   ///
-  /// * [List<String>] assetIds:
-  ///
-  /// * [String] albumId:
-  ///
-  /// * [String] userId:
-  ///
-  /// * [num] archiveSize:
+  /// * [DownloadInfoDto] downloadInfoDto (required):
   ///
   ///
   /// * [String] key:
   /// * [String] key:
-  Future<Response> getDownloadInfoWithHttpInfo({ List<String>? assetIds, String? albumId, String? userId, num? archiveSize, String? key, }) async {
+  Future<Response> getDownloadInfoWithHttpInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
     // ignore: prefer_const_declarations
     // ignore: prefer_const_declarations
-    final path = r'/asset/download';
+    final path = r'/asset/download/info';
 
 
     // ignore: prefer_final_locals
     // ignore: prefer_final_locals
-    Object? postBody;
+    Object? postBody = downloadInfoDto;
 
 
     final queryParams = <QueryParam>[];
     final queryParams = <QueryParam>[];
     final headerParams = <String, String>{};
     final headerParams = <String, String>{};
     final formParams = <String, String>{};
     final formParams = <String, String>{};
 
 
-    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) {
     if (key != null) {
       queryParams.addAll(_queryParams('', 'key', key));
       queryParams.addAll(_queryParams('', 'key', key));
     }
     }
 
 
-    const contentTypes = <String>[];
+    const contentTypes = <String>['application/json'];
 
 
 
 
     return apiClient.invokeAPI(
     return apiClient.invokeAPI(
       path,
       path,
-      'GET',
+      'POST',
       queryParams,
       queryParams,
       postBody,
       postBody,
       headerParams,
       headerParams,
@@ -908,17 +890,11 @@ class AssetApi {
 
 
   /// Parameters:
   /// Parameters:
   ///
   ///
-  /// * [List<String>] assetIds:
-  ///
-  /// * [String] albumId:
-  ///
-  /// * [String] userId:
-  ///
-  /// * [num] archiveSize:
+  /// * [DownloadInfoDto] downloadInfoDto (required):
   ///
   ///
   /// * [String] key:
   /// * [String] key:
-  Future<DownloadResponseDto?> getDownloadInfo({ List<String>? 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<DownloadResponseDto?> getDownloadInfo(DownloadInfoDto downloadInfoDto, { String? key, }) async {
+    final response = await getDownloadInfoWithHttpInfo(downloadInfoDto,  key: key, );
     if (response.statusCode >= HttpStatus.badRequest) {
     if (response.statusCode >= HttpStatus.badRequest) {
       throw ApiException(response.statusCode, await _decodeBodyBytes(response));
       throw ApiException(response.statusCode, await _decodeBodyBytes(response));
     }
     }

+ 2 - 0
mobile/openapi/lib/api_client.dart

@@ -257,6 +257,8 @@ class ApiClient {
           return DeleteAssetStatusTypeTransformer().decode(value);
           return DeleteAssetStatusTypeTransformer().decode(value);
         case 'DownloadArchiveInfo':
         case 'DownloadArchiveInfo':
           return DownloadArchiveInfo.fromJson(value);
           return DownloadArchiveInfo.fromJson(value);
+        case 'DownloadInfoDto':
+          return DownloadInfoDto.fromJson(value);
         case 'DownloadResponseDto':
         case 'DownloadResponseDto':
           return DownloadResponseDto.fromJson(value);
           return DownloadResponseDto.fromJson(value);
         case 'ExifResponseDto':
         case 'ExifResponseDto':

+ 150 - 0
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<String> 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<String, dynamic> toJson() {
+    final json = <String, dynamic>{};
+    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<String, dynamic>();
+
+      return DownloadInfoDto(
+        albumId: mapValueOfType<String>(json, r'albumId'),
+        archiveSize: mapValueOfType<int>(json, r'archiveSize'),
+        assetIds: json[r'assetIds'] is List
+            ? (json[r'assetIds'] as List).cast<String>()
+            : const [],
+        userId: mapValueOfType<String>(json, r'userId'),
+      );
+    }
+    return null;
+  }
+
+  static List<DownloadInfoDto> listFromJson(dynamic json, {bool growable = false,}) {
+    final result = <DownloadInfoDto>[];
+    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<String, DownloadInfoDto> mapFromJson(dynamic json) {
+    final map = <String, DownloadInfoDto>{};
+    if (json is Map && json.isNotEmpty) {
+      json = json.cast<String, dynamic>(); // 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<String, List<DownloadInfoDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
+    final map = <String, List<DownloadInfoDto>>{};
+    if (json is Map && json.isNotEmpty) {
+      // ignore: parameter_assignments
+      json = json.cast<String, dynamic>();
+      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 = <String>{
+  };
+}
+

+ 14 - 5
mobile/openapi/lib/model/user_response_dto.dart

@@ -21,7 +21,7 @@ class UserResponseDto {
     required this.id,
     required this.id,
     required this.isAdmin,
     required this.isAdmin,
     required this.lastName,
     required this.lastName,
-    required this.memoriesEnabled,
+    this.memoriesEnabled,
     required this.oauthId,
     required this.oauthId,
     required this.profileImagePath,
     required this.profileImagePath,
     required this.shouldChangePassword,
     required this.shouldChangePassword,
@@ -45,7 +45,13 @@ class UserResponseDto {
 
 
   String lastName;
   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;
   String oauthId;
 
 
@@ -85,7 +91,7 @@ class UserResponseDto {
     (id.hashCode) +
     (id.hashCode) +
     (isAdmin.hashCode) +
     (isAdmin.hashCode) +
     (lastName.hashCode) +
     (lastName.hashCode) +
-    (memoriesEnabled.hashCode) +
+    (memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
     (oauthId.hashCode) +
     (oauthId.hashCode) +
     (profileImagePath.hashCode) +
     (profileImagePath.hashCode) +
     (shouldChangePassword.hashCode) +
     (shouldChangePassword.hashCode) +
@@ -113,7 +119,11 @@ class UserResponseDto {
       json[r'id'] = this.id;
       json[r'id'] = this.id;
       json[r'isAdmin'] = this.isAdmin;
       json[r'isAdmin'] = this.isAdmin;
       json[r'lastName'] = this.lastName;
       json[r'lastName'] = this.lastName;
+    if (this.memoriesEnabled != null) {
       json[r'memoriesEnabled'] = this.memoriesEnabled;
       json[r'memoriesEnabled'] = this.memoriesEnabled;
+    } else {
+    //  json[r'memoriesEnabled'] = null;
+    }
       json[r'oauthId'] = this.oauthId;
       json[r'oauthId'] = this.oauthId;
       json[r'profileImagePath'] = this.profileImagePath;
       json[r'profileImagePath'] = this.profileImagePath;
       json[r'shouldChangePassword'] = this.shouldChangePassword;
       json[r'shouldChangePassword'] = this.shouldChangePassword;
@@ -142,7 +152,7 @@ class UserResponseDto {
         id: mapValueOfType<String>(json, r'id')!,
         id: mapValueOfType<String>(json, r'id')!,
         isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
         isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
         lastName: mapValueOfType<String>(json, r'lastName')!,
         lastName: mapValueOfType<String>(json, r'lastName')!,
-        memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled')!,
+        memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
         oauthId: mapValueOfType<String>(json, r'oauthId')!,
         oauthId: mapValueOfType<String>(json, r'oauthId')!,
         profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
         profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
         shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
         shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
@@ -203,7 +213,6 @@ class UserResponseDto {
     'id',
     'id',
     'isAdmin',
     'isAdmin',
     'lastName',
     'lastName',
-    'memoriesEnabled',
     'oauthId',
     'oauthId',
     'profileImagePath',
     'profileImagePath',
     'shouldChangePassword',
     'shouldChangePassword',

+ 1 - 1
mobile/openapi/test/asset_api_test.dart

@@ -97,7 +97,7 @@ void main() {
       // TODO
       // TODO
     });
     });
 
 
-    //Future<DownloadResponseDto> getDownloadInfo({ List<String> assetIds, String albumId, String userId, num archiveSize, String key }) async
+    //Future<DownloadResponseDto> getDownloadInfo(DownloadInfoDto downloadInfoDto, { String key }) async
     test('test getDownloadInfo', () async {
     test('test getDownloadInfo', () async {
       // TODO
       // TODO
     });
     });

+ 42 - 0
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<String> assetIds (default value: const [])
+    test('to test the property `assetIds`', () async {
+      // TODO
+    });
+
+    // String userId
+    test('to test the property `userId`', () async {
+      // TODO
+    });
+
+
+  });
+
+}

+ 1 - 1
mobile/pubspec.yaml

@@ -2,7 +2,7 @@ name: immich_mobile
 description: Immich - selfhosted backup media file on mobile phone
 description: Immich - selfhosted backup media file on mobile phone
 
 
 publish_to: "none"
 publish_to: "none"
-version: 1.72.2+95
+version: 1.73.0+96
 isar_version: &isar_version 3.1.0+1
 isar_version: &isar_version 3.1.0+1
 
 
 environment:
 environment:

+ 49 - 53
server/immich-openapi-specs.json

@@ -1026,48 +1026,10 @@
         ]
         ]
       }
       }
     },
     },
-    "/asset/download": {
-      "get": {
-        "operationId": "getDownloadInfo",
+    "/asset/download/archive": {
+      "post": {
+        "operationId": "downloadArchive",
         "parameters": [
         "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",
             "name": "key",
             "required": false,
             "required": false,
@@ -1077,12 +1039,23 @@
             }
             }
           }
           }
         ],
         ],
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/AssetIdsDto"
+              }
+            }
+          },
+          "required": true
+        },
         "responses": {
         "responses": {
           "200": {
           "200": {
             "content": {
             "content": {
-              "application/json": {
+              "application/octet-stream": {
                 "schema": {
                 "schema": {
-                  "$ref": "#/components/schemas/DownloadResponseDto"
+                  "format": "binary",
+                  "type": "string"
                 }
                 }
               }
               }
             },
             },
@@ -1103,9 +1076,11 @@
         "tags": [
         "tags": [
           "Asset"
           "Asset"
         ]
         ]
-      },
+      }
+    },
+    "/asset/download/info": {
       "post": {
       "post": {
-        "operationId": "downloadArchive",
+        "operationId": "getDownloadInfo",
         "parameters": [
         "parameters": [
           {
           {
             "name": "key",
             "name": "key",
@@ -1120,19 +1095,18 @@
           "content": {
           "content": {
             "application/json": {
             "application/json": {
               "schema": {
               "schema": {
-                "$ref": "#/components/schemas/AssetIdsDto"
+                "$ref": "#/components/schemas/DownloadInfoDto"
               }
               }
             }
             }
           },
           },
           "required": true
           "required": true
         },
         },
         "responses": {
         "responses": {
-          "200": {
+          "201": {
             "content": {
             "content": {
-              "application/octet-stream": {
+              "application/json": {
                 "schema": {
                 "schema": {
-                  "format": "binary",
-                  "type": "string"
+                  "$ref": "#/components/schemas/DownloadResponseDto"
                 }
                 }
               }
               }
             },
             },
@@ -4590,7 +4564,7 @@
   "info": {
   "info": {
     "title": "Immich",
     "title": "Immich",
     "description": "Immich API",
     "description": "Immich API",
-    "version": "1.72.2",
+    "version": "1.73.0",
     "contact": {}
     "contact": {}
   },
   },
   "tags": [],
   "tags": [],
@@ -5549,6 +5523,29 @@
         ],
         ],
         "type": "object"
         "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": {
       "DownloadResponseDto": {
         "properties": {
         "properties": {
           "archives": {
           "archives": {
@@ -7152,8 +7149,7 @@
           "createdAt",
           "createdAt",
           "deletedAt",
           "deletedAt",
           "updatedAt",
           "updatedAt",
-          "oauthId",
-          "memoriesEnabled"
+          "oauthId"
         ],
         ],
         "type": "object"
         "type": "object"
       },
       },

+ 2 - 2
server/package-lock.json

@@ -1,12 +1,12 @@
 {
 {
   "name": "immich",
   "name": "immich",
-  "version": "1.72.2",
+  "version": "1.73.0",
   "lockfileVersion": 2,
   "lockfileVersion": 2,
   "requires": true,
   "requires": true,
   "packages": {
   "packages": {
     "": {
     "": {
       "name": "immich",
       "name": "immich",
-      "version": "1.72.2",
+      "version": "1.73.0",
       "license": "UNLICENSED",
       "license": "UNLICENSED",
       "dependencies": {
       "dependencies": {
         "@babel/runtime": "^7.20.13",
         "@babel/runtime": "^7.20.13",

+ 1 - 1
server/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "immich",
   "name": "immich",
-  "version": "1.72.2",
+  "version": "1.73.0",
   "description": "",
   "description": "",
   "author": "",
   "author": "",
   "private": true,
   "private": true,

+ 5 - 0
server/src/domain/access/access.core.ts

@@ -19,6 +19,8 @@ export enum Permission {
   ALBUM_SHARE = 'album.share',
   ALBUM_SHARE = 'album.share',
   ALBUM_DOWNLOAD = 'album.download',
   ALBUM_DOWNLOAD = 'album.download',
 
 
+  ARCHIVE_READ = 'archive.read',
+
   LIBRARY_READ = 'library.read',
   LIBRARY_READ = 'library.read',
   LIBRARY_DOWNLOAD = 'library.download',
   LIBRARY_DOWNLOAD = 'library.download',
 }
 }
@@ -156,6 +158,9 @@ export class AccessCore {
       case Permission.ALBUM_REMOVE_ASSET:
       case Permission.ALBUM_REMOVE_ASSET:
         return this.repository.album.hasOwnerAccess(authUser.id, id);
         return this.repository.album.hasOwnerAccess(authUser.id, id);
 
 
+      case Permission.ARCHIVE_READ:
+        return authUser.id === id;
+
       case Permission.LIBRARY_READ:
       case Permission.LIBRARY_READ:
         return authUser.id === id || (await this.repository.library.hasPartnerAccess(authUser.id, id));
         return authUser.id === id || (await this.repository.library.hasPartnerAccess(authUser.id, id));
 
 

+ 7 - 1
server/src/domain/album/album.repository.ts

@@ -7,11 +7,17 @@ export interface AlbumAssetCount {
   assetCount: number;
   assetCount: number;
 }
 }
 
 
+export interface AlbumInfoOptions {
+  withAssets: boolean;
+}
+
 export interface IAlbumRepository {
 export interface IAlbumRepository {
-  getById(id: string): Promise<AlbumEntity | null>;
+  getById(id: string, options: AlbumInfoOptions): Promise<AlbumEntity | null>;
   getByIds(ids: string[]): Promise<AlbumEntity[]>;
   getByIds(ids: string[]): Promise<AlbumEntity[]>;
   getByAssetId(ownerId: string, assetId: string): Promise<AlbumEntity[]>;
   getByAssetId(ownerId: string, assetId: string): Promise<AlbumEntity[]>;
   hasAsset(id: string, assetId: string): Promise<boolean>;
   hasAsset(id: string, assetId: string): Promise<boolean>;
+  /** Remove an asset from _all_ albums */
+  removeAsset(id: string): Promise<void>;
   getAssetCountForIds(ids: string[]): Promise<AlbumAssetCount[]>;
   getAssetCountForIds(ids: string[]): Promise<AlbumAssetCount[]>;
   getInvalidThumbnail(): Promise<string[]>;
   getInvalidThumbnail(): Promise<string[]>;
   getOwned(ownerId: string): Promise<AlbumEntity[]>;
   getOwned(ownerId: string): Promise<AlbumEntity[]>;

+ 4 - 3
server/src/domain/album/album.service.spec.ts

@@ -364,6 +364,7 @@ describe(AlbumService.name, () => {
         updatedAt: expect.any(Date),
         updatedAt: expect.any(Date),
         sharedUsers: [],
         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 () => {
     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, {});
       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);
       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', {});
       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(
       expect(accessMock.album.hasSharedLinkAccess).toHaveBeenCalledWith(
         authStub.adminSharedLink.sharedLinkId,
         authStub.adminSharedLink.sharedLinkId,
         'album-123',
         'album-123',
@@ -455,7 +456,7 @@ describe(AlbumService.name, () => {
 
 
       await sut.get(authStub.user1, 'album-123', {});
       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');
       expect(accessMock.album.hasSharedAlbumAccess).toHaveBeenCalledWith(authStub.user1.id, 'album-123');
     });
     });
 
 

+ 12 - 12
server/src/domain/album/album.service.ts

@@ -12,7 +12,7 @@ import {
   mapAlbumWithAssets,
   mapAlbumWithAssets,
   mapAlbumWithoutAssets,
   mapAlbumWithoutAssets,
 } from './album-response.dto';
 } from './album-response.dto';
-import { IAlbumRepository } from './album.repository';
+import { AlbumInfoOptions, IAlbumRepository } from './album.repository';
 import { AddUsersDto, AlbumInfoDto, CreateAlbumDto, GetAlbumsDto, UpdateAlbumDto } from './dto';
 import { AddUsersDto, AlbumInfoDto, CreateAlbumDto, GetAlbumsDto, UpdateAlbumDto } from './dto';
 
 
 @Injectable()
 @Injectable()
@@ -84,7 +84,7 @@ export class AlbumService {
   async get(authUser: AuthUserDto, id: string, dto: AlbumInfoDto) {
   async get(authUser: AuthUserDto, id: string, dto: AlbumInfoDto) {
     await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
     await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
     await this.albumRepository.updateThumbnails();
     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<AlbumResponseDto> {
   async create(authUser: AuthUserDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
@@ -111,7 +111,7 @@ export class AlbumService {
   async update(authUser: AuthUserDto, id: string, dto: UpdateAlbumDto): Promise<AlbumResponseDto> {
   async update(authUser: AuthUserDto, id: string, dto: UpdateAlbumDto): Promise<AlbumResponseDto> {
     await this.access.requirePermission(authUser, Permission.ALBUM_UPDATE, id);
     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) {
     if (dto.albumThumbnailAssetId) {
       const valid = await this.albumRepository.hasAsset(id, 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] } });
     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<void> {
   async delete(authUser: AuthUserDto, id: string): Promise<void> {
     await this.access.requirePermission(authUser, Permission.ALBUM_DELETE, id);
     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) {
     if (!album) {
       throw new BadRequestException('Album not found');
       throw new BadRequestException('Album not found');
     }
     }
@@ -145,7 +145,7 @@ export class AlbumService {
   }
   }
 
 
   async addAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
   async addAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
-    const album = await this.findOrFail(id);
+    const album = await this.findOrFail(id, { withAssets: true });
 
 
     await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
     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<BulkIdResponseDto[]> {
   async removeAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
-    const album = await this.findOrFail(id);
+    const album = await this.findOrFail(id, { withAssets: true });
 
 
     await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
     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<AlbumResponseDto> {
   async addUsers(authUser: AuthUserDto, id: string, dto: AddUsersDto): Promise<AlbumResponseDto> {
     await this.access.requirePermission(authUser, Permission.ALBUM_SHARE, id);
     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) {
     for (const userId of dto.sharedUserIds) {
       const exists = album.sharedUsers.find((user) => user.id === userId);
       const exists = album.sharedUsers.find((user) => user.id === userId);
@@ -247,7 +247,7 @@ export class AlbumService {
         updatedAt: new Date(),
         updatedAt: new Date(),
         sharedUsers: album.sharedUsers,
         sharedUsers: album.sharedUsers,
       })
       })
-      .then(mapAlbumWithAssets);
+      .then(mapAlbumWithoutAssets);
   }
   }
 
 
   async removeUser(authUser: AuthUserDto, id: string, userId: string | 'me'): Promise<void> {
   async removeUser(authUser: AuthUserDto, id: string, userId: string | 'me'): Promise<void> {
@@ -255,7 +255,7 @@ export class AlbumService {
       userId = authUser.id;
       userId = authUser.id;
     }
     }
 
 
-    const album = await this.findOrFail(id);
+    const album = await this.findOrFail(id, { withAssets: false });
 
 
     if (album.ownerId === userId) {
     if (album.ownerId === userId) {
       throw new BadRequestException('Cannot remove album owner');
       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) {
     if (!album) {
       throw new BadRequestException('Album not found');
       throw new BadRequestException('Album not found');
     }
     }

+ 6 - 3
server/src/domain/asset/asset.service.ts

@@ -13,7 +13,7 @@ import { IAssetRepository } from './asset.repository';
 import {
 import {
   AssetIdsDto,
   AssetIdsDto,
   DownloadArchiveInfo,
   DownloadArchiveInfo,
-  DownloadDto,
+  DownloadInfoDto,
   DownloadResponseDto,
   DownloadResponseDto,
   MemoryLaneDto,
   MemoryLaneDto,
   TimeBucketAssetDto,
   TimeBucketAssetDto,
@@ -148,6 +148,9 @@ export class AssetService {
     if (dto.albumId) {
     if (dto.albumId) {
       await this.access.requirePermission(authUser, Permission.ALBUM_READ, [dto.albumId]);
       await this.access.requirePermission(authUser, Permission.ALBUM_READ, [dto.albumId]);
     } else if (dto.userId) {
     } 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]);
       await this.access.requirePermission(authUser, Permission.LIBRARY_READ, [dto.userId]);
     } else {
     } else {
       dto.userId = authUser.id;
       dto.userId = authUser.id;
@@ -176,7 +179,7 @@ export class AssetService {
     return this.storageRepository.createReadStream(asset.originalPath, mimeTypes.lookup(asset.originalPath));
     return this.storageRepository.createReadStream(asset.originalPath, mimeTypes.lookup(asset.originalPath));
   }
   }
 
 
-  async getDownloadInfo(authUser: AuthUserDto, dto: DownloadDto): Promise<DownloadResponseDto> {
+  async getDownloadInfo(authUser: AuthUserDto, dto: DownloadInfoDto): Promise<DownloadResponseDto> {
     const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
     const targetSize = dto.archiveSize || HumanReadableSize.GiB * 4;
     const archives: DownloadArchiveInfo[] = [];
     const archives: DownloadArchiveInfo[] = [];
     let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
     let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
@@ -234,7 +237,7 @@ export class AssetService {
     return { stream: zip.stream };
     return { stream: zip.stream };
   }
   }
 
 
-  private async getDownloadAssets(authUser: AuthUserDto, dto: DownloadDto): Promise<AsyncGenerator<AssetEntity[]>> {
+  private async getDownloadAssets(authUser: AuthUserDto, dto: DownloadInfoDto): Promise<AsyncGenerator<AssetEntity[]>> {
     const PAGINATION_SIZE = 2500;
     const PAGINATION_SIZE = 2500;
 
 
     if (dto.assetIds) {
     if (dto.assetIds) {

+ 2 - 1
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 { IsInt, IsOptional, IsPositive } from 'class-validator';
 import { ValidateUUID } from '../../domain.util';
 import { ValidateUUID } from '../../domain.util';
 
 
-export class DownloadDto {
+export class DownloadInfoDto {
   @ValidateUUID({ each: true, optional: true })
   @ValidateUUID({ each: true, optional: true })
   assetIds?: string[];
   assetIds?: string[];
 
 
@@ -15,6 +15,7 @@ export class DownloadDto {
   @IsInt()
   @IsInt()
   @IsPositive()
   @IsPositive()
   @IsOptional()
   @IsOptional()
+  @ApiProperty({ type: 'integer' })
   archiveSize?: number;
   archiveSize?: number;
 }
 }
 
 

+ 2 - 0
server/src/domain/domain.constant.ts

@@ -48,6 +48,7 @@ const image: Record<string, string[]> = {
   '.heic': ['image/heic'],
   '.heic': ['image/heic'],
   '.heif': ['image/heif'],
   '.heif': ['image/heif'],
   '.iiq': ['image/iiq', 'image/x-phaseone-iiq'],
   '.iiq': ['image/iiq', 'image/x-phaseone-iiq'],
+  '.insp': ['image/jpeg'],
   '.jpeg': ['image/jpeg'],
   '.jpeg': ['image/jpeg'],
   '.jpg': ['image/jpeg'],
   '.jpg': ['image/jpeg'],
   '.jxl': ['image/jxl'],
   '.jxl': ['image/jxl'],
@@ -79,6 +80,7 @@ const video: Record<string, string[]> = {
   '.3gp': ['video/3gpp'],
   '.3gp': ['video/3gpp'],
   '.avi': ['video/avi', 'video/msvideo', 'video/vnd.avi', 'video/x-msvideo'],
   '.avi': ['video/avi', 'video/msvideo', 'video/vnd.avi', 'video/x-msvideo'],
   '.flv': ['video/x-flv'],
   '.flv': ['video/x-flv'],
+  '.insv': ['video/mp4'],
   '.m2ts': ['video/mp2t'],
   '.m2ts': ['video/mp2t'],
   '.mkv': ['video/x-matroska'],
   '.mkv': ['video/x-matroska'],
   '.mov': ['video/quicktime'],
   '.mov': ['video/quicktime'],

+ 2 - 0
server/src/domain/job/job.constants.ts

@@ -32,6 +32,7 @@ export enum JobName {
   // metadata
   // metadata
   QUEUE_METADATA_EXTRACTION = 'queue-metadata-extraction',
   QUEUE_METADATA_EXTRACTION = 'queue-metadata-extraction',
   METADATA_EXTRACTION = 'metadata-extraction',
   METADATA_EXTRACTION = 'metadata-extraction',
+  LINK_LIVE_PHOTOS = 'link-live-photos',
 
 
   // user deletion
   // user deletion
   USER_DELETION = 'user-deletion',
   USER_DELETION = 'user-deletion',
@@ -98,6 +99,7 @@ export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
   // metadata
   // metadata
   [JobName.QUEUE_METADATA_EXTRACTION]: QueueName.METADATA_EXTRACTION,
   [JobName.QUEUE_METADATA_EXTRACTION]: QueueName.METADATA_EXTRACTION,
   [JobName.METADATA_EXTRACTION]: QueueName.METADATA_EXTRACTION,
   [JobName.METADATA_EXTRACTION]: QueueName.METADATA_EXTRACTION,
+  [JobName.LINK_LIVE_PHOTOS]: QueueName.METADATA_EXTRACTION,
 
 
   // storage template
   // storage template
   [JobName.STORAGE_TEMPLATE_MIGRATION]: QueueName.STORAGE_TEMPLATE_MIGRATION,
   [JobName.STORAGE_TEMPLATE_MIGRATION]: QueueName.STORAGE_TEMPLATE_MIGRATION,

+ 1 - 0
server/src/domain/job/job.repository.ts

@@ -45,6 +45,7 @@ export type JobItem =
   // Metadata Extraction
   // Metadata Extraction
   | { name: JobName.QUEUE_METADATA_EXTRACTION; data: IBaseJob }
   | { name: JobName.QUEUE_METADATA_EXTRACTION; data: IBaseJob }
   | { name: JobName.METADATA_EXTRACTION; data: IEntityJob }
   | { name: JobName.METADATA_EXTRACTION; data: IEntityJob }
+  | { name: JobName.LINK_LIVE_PHOTOS; data: IEntityJob }
 
 
   // Sidecar Scanning
   // Sidecar Scanning
   | { name: JobName.QUEUE_SIDECAR; data: IBaseJob }
   | { name: JobName.QUEUE_SIDECAR; data: IBaseJob }

+ 4 - 0
server/src/domain/job/job.service.spec.ts

@@ -252,6 +252,10 @@ describe(JobService.name, () => {
       },
       },
       {
       {
         item: { name: JobName.METADATA_EXTRACTION, data: { id: 'asset-1' } },
         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],
         jobs: [JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE, JobName.SEARCH_INDEX_ASSET],
       },
       },
       {
       {

+ 5 - 1
server/src/domain/job/job.service.ts

@@ -149,6 +149,10 @@ export class JobService {
         break;
         break;
 
 
       case JobName.METADATA_EXTRACTION:
       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 });
         await this.jobRepository.queue({ name: JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE, data: item.data });
         break;
         break;
 
 
@@ -186,7 +190,7 @@ export class JobService {
       case JobName.CLASSIFY_IMAGE:
       case JobName.CLASSIFY_IMAGE:
       case JobName.ENCODE_CLIP:
       case JobName.ENCODE_CLIP:
       case JobName.RECOGNIZE_FACES:
       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] } });
         await this.jobRepository.queue({ name: JobName.SEARCH_INDEX_ASSET, data: { ids: [item.data.id] } });
         break;
         break;
     }
     }

+ 1 - 0
server/src/domain/person/person.repository.ts

@@ -4,6 +4,7 @@ export const IPersonRepository = 'IPersonRepository';
 
 
 export interface PersonSearchOptions {
 export interface PersonSearchOptions {
   minimumFaceCount: number;
   minimumFaceCount: number;
+  withHidden: boolean;
 }
 }
 
 
 export interface UpdateFacesData {
 export interface UpdateFacesData {

+ 3 - 3
server/src/domain/person/person.service.spec.ts

@@ -47,7 +47,7 @@ describe(PersonService.name, () => {
         visible: 1,
         visible: 1,
         people: [responseDto],
         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 () => {
     it('should get all visible people with thumbnails', async () => {
       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
@@ -56,7 +56,7 @@ describe(PersonService.name, () => {
         visible: 1,
         visible: 1,
         people: [responseDto],
         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 () => {
     it('should get all hidden and visible people with thumbnails', async () => {
       personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
       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 });
     });
     });
   });
   });
 
 

+ 5 - 5
server/src/domain/person/person.service.ts

@@ -26,11 +26,11 @@ export class PersonService {
   ) {}
   ) {}
 
 
   async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise<PeopleResponseDto> {
   async getAll(authUser: AuthUserDto, dto: PersonSearchDto): Promise<PeopleResponseDto> {
-    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 people = await this.repository.getAll(authUser.id, {
+      minimumFaceCount: 1,
+      withHidden: dto.withHidden || false,
+    });
+    const persons: PersonResponseDto[] = people
       // with thumbnails
       // with thumbnails
       .filter((person) => !!person.thumbnailPath)
       .filter((person) => !!person.thumbnailPath)
       .map((person) => mapPerson(person));
       .map((person) => mapPerson(person));

+ 3 - 3
server/src/domain/server-info/server-info.service.ts

@@ -69,9 +69,9 @@ export class ServerInfoService {
 
 
   getSupportedMediaTypes(): ServerMediaTypesResponseDto {
   getSupportedMediaTypes(): ServerMediaTypesResponseDto {
     return {
     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),
     };
     };
   }
   }
 }
 }

+ 1 - 1
server/src/domain/user/response-dto/user-response.dto.ts

@@ -14,7 +14,7 @@ export class UserResponseDto {
   deletedAt!: Date | null;
   deletedAt!: Date | null;
   updatedAt!: Date;
   updatedAt!: Date;
   oauthId!: string;
   oauthId!: string;
-  memoriesEnabled!: boolean;
+  memoriesEnabled?: boolean;
 }
 }
 
 
 export function mapUser(entity: UserEntity): UserResponseDto {
 export function mapUser(entity: UserEntity): UserResponseDto {

+ 0 - 1
server/src/domain/user/user.core.ts

@@ -60,7 +60,6 @@ export class UserCore {
         dto.externalPath = null;
         dto.externalPath = null;
       }
       }
 
 
-      console.log(dto.memoriesEnabled);
       return this.userRepository.update(id, dto);
       return this.userRepository.update(id, dto);
     } catch (e) {
     } catch (e) {
       Logger.error(e, 'Failed to update user info');
       Logger.error(e, 'Failed to update user info');

+ 4 - 4
server/src/immich/controllers/asset.controller.ts

@@ -5,7 +5,7 @@ import {
   AssetStatsDto,
   AssetStatsDto,
   AssetStatsResponseDto,
   AssetStatsResponseDto,
   AuthUserDto,
   AuthUserDto,
-  DownloadDto,
+  DownloadInfoDto,
   DownloadResponseDto,
   DownloadResponseDto,
   MapMarkerResponseDto,
   MapMarkerResponseDto,
   MemoryLaneDto,
   MemoryLaneDto,
@@ -39,13 +39,13 @@ export class AssetController {
   }
   }
 
 
   @SharedLinkRoute()
   @SharedLinkRoute()
-  @Get('download')
-  getDownloadInfo(@AuthUser() authUser: AuthUserDto, @Query() dto: DownloadDto): Promise<DownloadResponseDto> {
+  @Post('download/info')
+  getDownloadInfo(@AuthUser() authUser: AuthUserDto, @Body() dto: DownloadInfoDto): Promise<DownloadResponseDto> {
     return this.service.getDownloadInfo(authUser, dto);
     return this.service.getDownloadInfo(authUser, dto);
   }
   }
 
 
   @SharedLinkRoute()
   @SharedLinkRoute()
-  @Post('download')
+  @Post('download/archive')
   @HttpCode(HttpStatus.OK)
   @HttpCode(HttpStatus.OK)
   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } })
   @ApiOkResponse({ content: { 'application/octet-stream': { schema: { type: 'string', format: 'binary' } } } })
   downloadArchive(@AuthUser() authUser: AuthUserDto, @Body() dto: AssetIdsDto): Promise<StreamableFile> {
   downloadArchive(@AuthUser() authUser: AuthUserDto, @Body() dto: AssetIdsDto): Promise<StreamableFile> {

+ 13 - 0
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<void> {
+        await queryRunner.query(`UPDATE "exif" SET latitude = NULL, longitude = NULL WHERE latitude = 0 AND longitude = 0;`);
+    }
+
+    public async down(): Promise<void> {
+        // Setting lat,lon to 0 not necessary
+    }
+
+}

+ 36 - 23
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 { Injectable } from '@nestjs/common';
-import { InjectRepository } from '@nestjs/typeorm';
-import { 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 { dataSource } from '../database.config';
 import { AlbumEntity, AssetEntity } from '../entities';
 import { AlbumEntity, AssetEntity } from '../entities';
 
 
@@ -10,27 +10,30 @@ export class AlbumRepository implements IAlbumRepository {
   constructor(
   constructor(
     @InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
     @InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
     @InjectRepository(AlbumEntity) private repository: Repository<AlbumEntity>,
     @InjectRepository(AlbumEntity) private repository: Repository<AlbumEntity>,
+    @InjectDataSource() private dataSource: DataSource,
   ) {}
   ) {}
 
 
-  getById(id: string): Promise<AlbumEntity | null> {
-    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<AlbumEntity | null> {
+    const relations: FindOptionsRelations<AlbumEntity> = {
+      owner: true,
+      sharedUsers: true,
+      assets: false,
+      sharedLinks: true,
+    };
+
+    const order: FindOptionsOrder<AlbumEntity> = {};
+
+    if (options.withAssets) {
+      relations.assets = {
+        exifInfo: true,
+      };
+
+      order.assets = {
+        fileCreatedAt: 'DESC',
+      };
+    }
+
+    return this.repository.findOne({ where: { id }, relations, order });
   }
   }
 
 
   getByIds(ids: string[]): Promise<AlbumEntity[]> {
   getByIds(ids: string[]): Promise<AlbumEntity[]> {
@@ -82,7 +85,7 @@ export class AlbumRepository implements IAlbumRepository {
    */
    */
   async getInvalidThumbnail(): Promise<string[]> {
   async getInvalidThumbnail(): Promise<string[]> {
     // Using dataSource, because there is no direct access to albums_assets_assets.
     // Using dataSource, because there is no direct access to albums_assets_assets.
-    const albumHasAssets = dataSource
+    const albumHasAssets = this.dataSource
       .createQueryBuilder()
       .createQueryBuilder()
       .select('1')
       .select('1')
       .from('albums_assets_assets', 'albums_assets')
       .from('albums_assets_assets', 'albums_assets')
@@ -148,6 +151,16 @@ export class AlbumRepository implements IAlbumRepository {
     });
     });
   }
   }
 
 
+  async removeAsset(assetId: string): Promise<void> {
+    // 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<boolean> {
   hasAsset(id: string, assetId: string): Promise<boolean> {
     return this.repository.exist({
     return this.repository.exist({
       where: {
       where: {

+ 11 - 4
server/src/infra/repositories/person.repository.ts

@@ -51,15 +51,22 @@ export class PersonRepository implements IPersonRepository {
   }
   }
 
 
   getAll(userId: string, options?: PersonSearchOptions): Promise<PersonEntity[]> {
   getAll(userId: string, options?: PersonSearchOptions): Promise<PersonEntity[]> {
-    return this.personRepository
+    const queryBuilder = this.personRepository
       .createQueryBuilder('person')
       .createQueryBuilder('person')
       .leftJoin('person.faces', 'face')
       .leftJoin('person.faces', 'face')
       .where('person.ownerId = :userId', { userId })
       .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 })
       .having('COUNT(face.assetId) >= :faces', { faces: options?.minimumFaceCount || 1 })
       .groupBy('person.id')
       .groupBy('person.id')
-      .limit(500)
-      .getMany();
+      .limit(500);
+    if (!options?.withHidden) {
+      queryBuilder.andWhere('person.isHidden = false');
+    }
+
+    return queryBuilder.getMany();
   }
   }
 
 
   getAllWithoutFaces(): Promise<PersonEntity[]> {
   getAllWithoutFaces(): Promise<PersonEntity[]> {

+ 1 - 0
server/src/microservices/app.service.ts

@@ -66,6 +66,7 @@ export class AppService {
       [JobName.VIDEO_CONVERSION]: (data) => this.mediaService.handleVideoConversion(data),
       [JobName.VIDEO_CONVERSION]: (data) => this.mediaService.handleVideoConversion(data),
       [JobName.QUEUE_METADATA_EXTRACTION]: (data) => this.metadataProcessor.handleQueueMetadataExtraction(data),
       [JobName.QUEUE_METADATA_EXTRACTION]: (data) => this.metadataProcessor.handleQueueMetadataExtraction(data),
       [JobName.METADATA_EXTRACTION]: (data) => this.metadataProcessor.handleMetadataExtraction(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.QUEUE_RECOGNIZE_FACES]: (data) => this.facialRecognitionService.handleQueueRecognizeFaces(data),
       [JobName.RECOGNIZE_FACES]: (data) => this.facialRecognitionService.handleRecognizeFaces(data),
       [JobName.RECOGNIZE_FACES]: (data) => this.facialRecognitionService.handleRecognizeFaces(data),
       [JobName.GENERATE_FACE_THUMBNAIL]: (data) => this.facialRecognitionService.handleGenerateFaceThumbnail(data),
       [JobName.GENERATE_FACE_THUMBNAIL]: (data) => this.facialRecognitionService.handleGenerateFaceThumbnail(data),

+ 44 - 28
server/src/microservices/processors/metadata-extraction.processor.ts

@@ -1,4 +1,5 @@
 import {
 import {
+  IAlbumRepository,
   IAssetRepository,
   IAssetRepository,
   IBaseJob,
   IBaseJob,
   ICryptoRepository,
   ICryptoRepository,
@@ -59,6 +60,7 @@ export class MetadataExtractionProcessor {
 
 
   constructor(
   constructor(
     @Inject(IAssetRepository) private assetRepository: IAssetRepository,
     @Inject(IAssetRepository) private assetRepository: IAssetRepository,
+    @Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
     @Inject(IJobRepository) private jobRepository: IJobRepository,
     @Inject(IJobRepository) private jobRepository: IJobRepository,
     @Inject(IGeocodingRepository) private geocodingRepository: IGeocodingRepository,
     @Inject(IGeocodingRepository) private geocodingRepository: IGeocodingRepository,
     @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository,
     @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) {
   async handleQueueMetadataExtraction(job: IBaseJob) {
     const { force } = job;
     const { force } = job;
     const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
     const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
@@ -308,8 +342,16 @@ export class MetadataExtractionProcessor {
 
 
     const latitude = getExifProperty('GPSLatitude');
     const latitude = getExifProperty('GPSLatitude');
     const longitude = getExifProperty('GPSLongitude');
     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')) {
     if (getExifProperty('MotionPhoto')) {
       // Seen on more recent Pixel phones: starting as early as Pixel 4a, possibly earlier.
       // Seen on more recent Pixel phones: starting as early as Pixel 4a, possibly earlier.
       const rawDirectory = getExifProperty('Directory');
       const rawDirectory = getExifProperty('Directory');
@@ -343,19 +385,6 @@ export class MetadataExtractionProcessor {
     }
     }
 
 
     newExif.livePhotoCID = getExifProperty('MediaGroupUUID');
     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);
     await this.applyReverseGeocoding(asset, newExif);
 
 
     /**
     /**
@@ -420,19 +449,6 @@ export class MetadataExtractionProcessor {
     newExif.fps = null;
     newExif.fps = null;
     newExif.livePhotoCID = exifData?.ContentIdentifier || 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']) {
     if (videoTags && videoTags['location']) {
       const location = videoTags['location'] as string;
       const location = videoTags['location'] as string;
       const locationRegex = /([+-][0-9]+\.[0-9]+)([+-][0-9]+\.[0-9]+)\/$/;
       const locationRegex = /([+-][0-9]+\.[0-9]+)([+-][0-9]+\.[0-9]+)\/$/;

+ 12 - 0
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', () => {
 describe('parsing longitude from string input', () => {
   it('returns null for invalid inputs', () => {
   it('returns null for invalid inputs', () => {
     expect(parseLongitude('')).toBeNull();
     expect(parseLongitude('')).toBeNull();
@@ -44,3 +50,9 @@ describe('parsing longitude from string input', () => {
     expect(parseLongitude('-0.0')).toBeCloseTo(-0.0);
     expect(parseLongitude('-0.0')).toBeCloseTo(-0.0);
   });
   });
 });
 });
+
+describe('parsing longitude from null input', () => {
+  it('returns null for null input', () => {
+    expect(parseLongitude(null)).toBeNull();
+  });
+});

+ 9 - 2
server/src/microservices/utils/exif/coordinates.ts

@@ -1,6 +1,9 @@
 import { isNumberInRange } from '../numbers';
 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;
   const latitude = typeof input === 'string' ? Number.parseFloat(input) : input;
 
 
   if (isNumberInRange(latitude, -90, 90)) {
   if (isNumberInRange(latitude, -90, 90)) {
@@ -9,7 +12,11 @@ export function parseLatitude(input: string | number): number | null {
   return 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;
   const longitude = typeof input === 'string' ? Number.parseFloat(input) : input;
 
 
   if (isNumberInRange(longitude, -180, 180)) {
   if (isNumberInRange(longitude, -180, 180)) {

+ 1 - 0
server/test/repositories/album.repository.mock.ts

@@ -12,6 +12,7 @@ export const newAlbumRepositoryMock = (): jest.Mocked<IAlbumRepository> => {
     getNotShared: jest.fn(),
     getNotShared: jest.fn(),
     deleteAll: jest.fn(),
     deleteAll: jest.fn(),
     getAll: jest.fn(),
     getAll: jest.fn(),
+    removeAsset: jest.fn(),
     hasAsset: jest.fn(),
     hasAsset: jest.fn(),
     create: jest.fn(),
     create: jest.fn(),
     update: jest.fn(),
     update: jest.fn(),

+ 52 - 59
web/src/api/open-api/api.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -1132,6 +1132,37 @@ export interface DownloadArchiveInfo {
      */
      */
     'size': number;
     'size': number;
 }
 }
+/**
+ * 
+ * @export
+ * @interface DownloadInfoDto
+ */
+export interface DownloadInfoDto {
+    /**
+     * 
+     * @type {string}
+     * @memberof DownloadInfoDto
+     */
+    'albumId'?: string;
+    /**
+     * 
+     * @type {number}
+     * @memberof DownloadInfoDto
+     */
+    'archiveSize'?: number;
+    /**
+     * 
+     * @type {Array<string>}
+     * @memberof DownloadInfoDto
+     */
+    'assetIds'?: Array<string>;
+    /**
+     * 
+     * @type {string}
+     * @memberof DownloadInfoDto
+     */
+    'userId'?: string;
+}
 /**
 /**
  * 
  * 
  * @export
  * @export
@@ -3159,7 +3190,7 @@ export interface UserResponseDto {
      * @type {boolean}
      * @type {boolean}
      * @memberof UserResponseDto
      * @memberof UserResponseDto
      */
      */
-    'memoriesEnabled': boolean;
+    'memoriesEnabled'?: boolean;
     /**
     /**
      * 
      * 
      * @type {string}
      * @type {string}
@@ -4880,7 +4911,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
         downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
         downloadArchive: async (assetIdsDto: AssetIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
             // verify required parameter 'assetIdsDto' is not null or undefined
             // verify required parameter 'assetIdsDto' is not null or undefined
             assertParamExists('downloadArchive', 'assetIdsDto', assetIdsDto)
             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.
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             let baseOptions;
             let baseOptions;
@@ -5379,16 +5410,15 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
         },
         },
         /**
         /**
          * 
          * 
-         * @param {Array<string>} [assetIds] 
-         * @param {string} [albumId] 
-         * @param {string} [userId] 
-         * @param {number} [archiveSize] 
+         * @param {DownloadInfoDto} downloadInfoDto 
          * @param {string} [key] 
          * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          * @throws {RequiredError}
          */
          */
-        getDownloadInfo: async (assetIds?: Array<string>, albumId?: string, userId?: string, archiveSize?: number, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
-            const localVarPath = `/asset/download`;
+        getDownloadInfo: async (downloadInfoDto: DownloadInfoDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // 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.
             // use dummy base URL string because the URL constructor only accepts absolute URLs.
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
             let baseOptions;
             let baseOptions;
@@ -5396,7 +5426,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
                 baseOptions = configuration.baseOptions;
                 baseOptions = configuration.baseOptions;
             }
             }
 
 
-            const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
+            const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
             const localVarHeaderParameter = {} as any;
             const localVarHeaderParameter = {} as any;
             const localVarQueryParameter = {} as any;
             const localVarQueryParameter = {} as any;
 
 
@@ -5409,31 +5439,18 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
             // http bearer authentication required
             // http bearer authentication required
             await setBearerAuthToObject(localVarHeaderParameter, configuration)
             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) {
             if (key !== undefined) {
                 localVarQueryParameter['key'] = key;
                 localVarQueryParameter['key'] = key;
             }
             }
 
 
 
 
     
     
+            localVarHeaderParameter['Content-Type'] = 'application/json';
+
             setSearchParams(localVarUrlObj, localVarQueryParameter);
             setSearchParams(localVarUrlObj, localVarQueryParameter);
             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
             let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
             localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+            localVarRequestOptions.data = serializeDataIfNeeded(downloadInfoDto, localVarRequestOptions, configuration)
 
 
             return {
             return {
                 url: toPathString(localVarUrlObj),
                 url: toPathString(localVarUrlObj),
@@ -6141,16 +6158,13 @@ export const AssetApiFp = function(configuration?: Configuration) {
         },
         },
         /**
         /**
          * 
          * 
-         * @param {Array<string>} [assetIds] 
-         * @param {string} [albumId] 
-         * @param {string} [userId] 
-         * @param {number} [archiveSize] 
+         * @param {DownloadInfoDto} downloadInfoDto 
          * @param {string} [key] 
          * @param {string} [key] 
          * @param {*} [options] Override http request option.
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          * @throws {RequiredError}
          */
          */
-        async getDownloadInfo(assetIds?: Array<string>, albumId?: string, userId?: string, archiveSize?: number, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DownloadResponseDto>> {
-            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<DownloadResponseDto>> {
+            const localVarAxiosArgs = await localVarAxiosParamCreator.getDownloadInfo(downloadInfoDto, key, options);
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
             return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
         },
         },
         /**
         /**
@@ -6406,8 +6420,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
          * @param {*} [options] Override http request option.
          * @param {*} [options] Override http request option.
          * @throws {RequiredError}
          * @throws {RequiredError}
          */
          */
-        getDownloadInfo(requestParameters: AssetApiGetDownloadInfoRequest = {}, options?: AxiosRequestConfig): AxiosPromise<DownloadResponseDto> {
-            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<DownloadResponseDto> {
+            return localVarFp.getDownloadInfo(requestParameters.downloadInfoDto, requestParameters.key, options).then((request) => request(axios, basePath));
         },
         },
         /**
         /**
          * 
          * 
@@ -6788,31 +6802,10 @@ export interface AssetApiGetByTimeBucketRequest {
 export interface AssetApiGetDownloadInfoRequest {
 export interface AssetApiGetDownloadInfoRequest {
     /**
     /**
      * 
      * 
-     * @type {Array<string>}
-     * @memberof AssetApiGetDownloadInfo
-     */
-    readonly assetIds?: Array<string>
-
-    /**
-     * 
-     * @type {string}
-     * @memberof AssetApiGetDownloadInfo
-     */
-    readonly albumId?: string
-
-    /**
-     * 
-     * @type {string}
-     * @memberof AssetApiGetDownloadInfo
-     */
-    readonly userId?: string
-
-    /**
-     * 
-     * @type {number}
+     * @type {DownloadInfoDto}
      * @memberof AssetApiGetDownloadInfo
      * @memberof AssetApiGetDownloadInfo
      */
      */
-    readonly archiveSize?: number
+    readonly downloadInfoDto: DownloadInfoDto
 
 
     /**
     /**
      * 
      * 
@@ -7281,8 +7274,8 @@ export class AssetApi extends BaseAPI {
      * @throws {RequiredError}
      * @throws {RequiredError}
      * @memberof AssetApi
      * @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));
     }
     }
 
 
     /**
     /**

+ 1 - 1
web/src/api/open-api/base.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
web/src/api/open-api/common.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
web/src/api/open-api/configuration.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
web/src/api/open-api/index.ts

@@ -4,7 +4,7 @@
  * Immich
  * Immich
  * Immich API
  * 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).
  * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

+ 1 - 1
web/src/lib/components/admin-page/settings/storage-template/storage-template-settings.svelte

@@ -118,7 +118,7 @@
 
 
       <form autocomplete="off" class="flex flex-col" on:submit|preventDefault>
       <form autocomplete="off" class="flex flex-col" on:submit|preventDefault>
         <div class="my-2 flex flex-col">
         <div class="my-2 flex flex-col">
-          <label class="text-xs" for="presets">PRESET</label>
+          <label class="text-xs" for="preset-select">PRESET</label>
           <select
           <select
             class="mt-2 rounded-lg bg-slate-200 p-2 text-sm hover:cursor-pointer dark:bg-gray-600"
             class="mt-2 rounded-lg bg-slate-200 p-2 text-sm hover:cursor-pointer dark:bg-gray-600"
             name="presets"
             name="presets"

+ 4 - 4
web/src/lib/components/admin-page/settings/thumbnail/thumbnail-settings.svelte

@@ -42,8 +42,8 @@
     <form autocomplete="off" on:submit|preventDefault>
     <form autocomplete="off" on:submit|preventDefault>
       <div class="ml-4 mt-4 flex flex-col gap-4">
       <div class="ml-4 mt-4 flex flex-col gap-4">
         <SettingSelect
         <SettingSelect
-          label="WEBP RESOLUTION"
-          desc="Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness."
+          label="SMALL THUMBNAIL RESOLUTION"
+          desc="Used when viewing groups of photos (main timeline, album view, etc.). Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness."
           number
           number
           bind:value={thumbnailConfig.webpSize}
           bind:value={thumbnailConfig.webpSize}
           options={[
           options={[
@@ -57,8 +57,8 @@
         />
         />
 
 
         <SettingSelect
         <SettingSelect
-          label="JPEG RESOLUTION"
-          desc="Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness."
+          label="LARGE THUMBNAIL RESOLUTION"
+          desc="Used when viewing a single photo and for machine learning. Higher resolutions can preserve more detail but take longer to encode, have larger file sizes, and can reduce app responsiveness."
           number
           number
           bind:value={thumbnailConfig.jpegSize}
           bind:value={thumbnailConfig.jpegSize}
           options={[
           options={[

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov