merge main

This commit is contained in:
martabal 2023-08-16 21:19:17 +02:00
commit 6e2ba7acab
No known key found for this signature in database
GPG key ID: C00196E3148A52BD
113 changed files with 1165 additions and 540 deletions

View file

@ -13,7 +13,7 @@
</p>
<h3 align="center">Immich - 高性能的自托管照片和视频备份方案</h3>
<p align="center">
请注意: 此README不是由Immich团队维护, 这意味着它在某一时间点不会被更新,因为我们是依靠贡献者来更新的。感谢理解。
请注意: 此 README 不是由 Immich 团队维护, 而是依靠贡献者来更新的,这意味着它可能并不会被及时更新。感谢理解。
</p>
<br/>
<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/install/requirements)
- [贡献指南](https://immich.app/docs/overview/support-the-project)
- [支持本项目](#support-the-project)
- [已知问题](#known-issues)
- [支持本项目](#支持本项目)
## 官方文档
你可以在 https://immich.app/ 找到包含安装手册的官方文档.
您可以在 https://immich.app/ 找到官方文档(包含安装手册)。
## 示例
你可以在 https://demo.immich.app 访问示例.
您可以在 https://demo.immich.app 访问示例。
在移动端, 可以使用 `https://demo.immich.app/api`获取`服务终端链接`
在移动端, 可以使用 `https://demo.immich.app/api` 获取 `服务终端链接`
```bash title="示例认证信息"
认证信息
@ -62,57 +64,52 @@
```
```
规格: 甲骨文免费虚拟机套餐-阿姆斯特丹 4核 2.4Ghz ARM64 CPU, 24GB RAM。
规格: 甲骨文免费虚拟机套餐——阿姆斯特丹 4核 2.4Ghz ARM64 CPU, 24GB RAM。
```
# 功能特性
| 功能特性 | 移动端 | 网页端 |
| ------------------------------------------- | ------- | --- |
| 上传并查看照片和视频 | 是 | 是 |
| 软件运行时自动备份 | 是 | N/A |
| 上传并查看照片和视频 | 是 | 是 |
| 软件运行时自动备份 | 是 | N/A |
| 选择需要备份的相册 | 是 | N/A |
| 下载照片和视频到本地 | 是 | 是 |
| 下载照片和视频到本地 | 是 | 是 |
| 多用户支持 | 是 | 是 |
| 相册 | 是 | 是 |
| 共享相册 | 是 | 是 |
| 可拖动的快速导航栏 | 是 | 是 |
| 支持RAW格式 (HEIC, HEIF, DNG, Apple ProRaw) | 是 | 是 |
| 元数据视图 (EXIF, 地图) | 是 | 是 |
| 通过元数据、对象和标签进行搜索 | 是 | No |
| 管理功能 (用户管理) | N/A | 是 |
| 后台备份 | Android | N/A |
| 元数据视图EXIF, 地图) | 是 | 是 |
| 通过元数据、对象和标签进行搜索 | 是 | |
| 管理功能(用户管理) | 否 | 是 |
| 后台备份 | | N/A |
| 虚拟滚动 | 是 | 是 |
| OAuth支持 | 是 | 是 |
| 实时照片备份和查看 (仅iOS) | 是 | 是 |
| OAuth 支持 | 是 | 是 |
| API Keys|N/A|是|
| 实况照片备份和查看 | 仅 iOS | 是 |
|用户自定义存储结构|是|是|
|公共分享|否|是|
|归档与收藏功能|是|是|
|全局地图|否|是|
|好友分享|是|是|
|人像识别与分组|是|是|
|回忆(那年今日)|是|是|
|离线支持|是|否|
|只读相册|是|是|
# 支持本项目
我已经致力于本项目并且将我会持续更新文档、新增功能和修复问题。但是我不能一个人走下去,所以我需要你给予我走下去的动力。
我已经致力于本项目并且将我会持续更新文档、新增功能和修复问题。但是独木不成林,我需要您给予我坚持下去的动力。
就像我主页里面 [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418) 说的一样,这是我和团队的一项艰巨的任务。我希望某一天我能够全职开发本项目,在此我希望你们能够助我梦想成真。
就像我 [selfhosted.show - In the episode 'The-organization-must-not-be-name is a Hostile Actor'](https://selfhosted.show/79?t=1418) 节目里说的一样,这是我和团队的一项艰巨任务。并且我希望某一天我能够全职开发本项目,在此我请求您能够助我梦想成真。
如果你使用了本项目一段时间,并且觉得上面的话有道理,那么请你按照如下方式帮助我吧。
如果您使用了本项目一段时间,并且觉得上面的话有道理,那么请您考虑通过下列任一方式支持我吧。
## 捐赠
- [按月捐赠](https://github.com/sponsors/alextran1502) via GitHub Sponsors
- [一次捐赠](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502) via Github Sponsors
# 已知问题
## TensorFlow 构建问题
_这是一个针对于Proxmox的已知问题_
TensorFlow 不能运行在很旧的CPU架构上, 需要运行在AVX和AVX2指令集的CPU上。如果你在docker-compose的命令行中遇到了 `illegal instruction core dump`的错误, 通过如下命令检查你的CPU flag寄存器然后确保你能够看到`AVX``AVX2`的字样:
```bash
more /proc/cpuinfo | grep flags
```
如果你在Proxmox中运行虚拟机, 虚拟机中没有启用flag寄存器。
你需要在虚拟机的硬件面板中把CPU类型从`kvm64`改为`host`
`Hardware > Processors > Edit > Advanced > Type (dropdown menu) > host`
- 通过 GitHub Sponsors [按月捐赠](https://github.com/sponsors/alextran1502)
- 通过 Github Sponsors [单次捐赠](https://github.com/sponsors/alextran1502?frequency=one-time&sponsor=alextran1502)
- [Librepay](https://liberapay.com/alex.tran1502/)
- [buymeacoffee](https://www.buymeacoffee.com/altran1502)
- 比特币: 1FvEp6P6NM8EZEkpGUFAN2LqJ1gxusNxZX

View file

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

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -99,3 +99,29 @@ After removing the containers and volumes, the **Files** can be cleaned up (if n
### Why iOS app shows duplicate photos on the timeline while the web doesn't?
If you are using `My Photo Stream`, the Photos app temporarily creates duplicates of photos taken in the last 30 days. These photos are included in the `Recents` album and thus shown up twice. To fix this, you can disable `My Photo Stream` in the native Photos app or choose a different album in the backup screen in Immich.
### How can I move all data (photos, persons, albums) from one user to another?
This requires some database queries. You can do this on the command line (in the PostgreSQL container using the psql command), or you can add for example an [Adminer](https://www.adminer.org/) container to the `docker-compose.yml` file, so that you can use a web-interface.
:::warning
This is an advanced operation. If you can't to do it with the steps described here, this is not for you.
:::
1. **MAKE A BACKUP** - See [backup and restore](/docs/administration/backup-and-restore.md).
2. Find the id of both the 'source' and the 'destination' user (it's the id column in the users table)
3. Three tables need to be updated:
```sql
// reassign albums
update albums set "ownerId" = '<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.

View file

@ -170,4 +170,10 @@ The proper command for above would be as shown below. You should have access to
immich upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive /path/to/media --import
```
If you are running the import using the docker command, please note that the volumes should point to the `/path/to/media` exactly on the environment the CLI command is being run on
```
docker run -it --rm -v "/path/to/media:/path/to/media" ghcr.io/immich-app/immich-cli:latest upload --key HFEJ38DNSDUEG --server http://192.168.1.216:2283/api --recursive /path/to/media --import
```
:::

View file

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

View file

@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 95,
"android.injected.version.name" => "1.72.2",
"android.injected.version.code" => 96,
"android.injected.version.name" => "1.73.0",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')

View file

@ -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 classname="fastlane.lanes" name="1: bundleRelease" time="68.788432">
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="67.877631">
</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>

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "elements",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Àlbums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Entra",
"login_form_email_hint": "elteu@correu.cat",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Nahrávaný soubor",
"backup_err_only_album": "Nelze odstranit jediné vybrané album",
"backup_info_card_assets": "položek",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Selhalo",
"backup_manual_in_progress": "Zálohování již probíhá. Zkuste znovu později",
"backup_manual_success": "Úspěch",
"backup_manual_title": "Stav zálohování",
"cache_settings_album_thumbnails": "Náhledy stránek knihovny (položek {})",
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Vytváření časové osy",
"home_page_favorite_err_local": "Zatím není možné zařadit lokální média mezi oblíbená, přeskakuje se",
"home_page_first_time_notice": "Pokud aplikaci používáte poprvé, nezapomeňte si vybrat zálohovaná alba, aby se na časové ose mohly nacházet fotografie a videa z vybraných albech.",
"home_page_upload_err_limit": "Lze nahrát nejvýše 30 položek najednou, přeskakuji",
"image_viewer_page_state_provider_download_error": "Chyba stahování",
"image_viewer_page_state_provider_download_success": "Stahování bylo úspěšné",
"library_page_albums": "Alba",
@ -166,6 +172,7 @@
"library_page_sharing": "Sdílení",
"library_page_sort_created": "Naposledy vytvořené",
"library_page_sort_title": "Podle názvu alba",
"login_disabled": "Přihlášení bylo zakázáno",
"login_form_api_exception": "Výjimka API. Zkontrolujte URL serveru a zkuste to znovu.",
"login_form_button_text": "Přihlásit se",
"login_form_email_hint": "tvůjmail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Téma",
"theme_setting_three_stage_loading_subtitle": "Třístupňové načítání může zvýšit výkonnost načítání, ale vede k výrazně vyššímu zatížení sítě.",
"theme_setting_three_stage_loading_title": "Povolení třístupňového načítání",
"upload_dialog_cancel": "Zrušit",
"upload_dialog_info": "Chcete zálohovat vybrané položky na server?",
"upload_dialog_ok": "Zálohovat",
"upload_dialog_title": "Zálohovat položku",
"version_announcement_overlay_ack": "Potvrdit",
"version_announcement_overlay_release_notes": "poznámky k vydání",
"version_announcement_overlay_text_1": "Ahoj, je zde nová verze",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploader filinformation",
"backup_err_only_album": "Kan ikke slette det eneste album",
"backup_info_card_assets": "elementer",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Biblioteksminiaturebilleder ({} elementer)",
"cache_settings_clear_cache_button": "Fjern cache",
"cache_settings_clear_cache_button_title": "Fjern appens cache. Dette vil i stor grad påvirke appens ydeevne indtil cachen er genopbygget.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Bygger tidslinjen",
"home_page_favorite_err_local": "Kan endnu ikke gøre lokale elementer til favoritter. Springer over..",
"home_page_first_time_notice": "Hvis dette er din første gang i appen, bedes du vælge en backup af albummer så tidlinjen kan blive fyldt med billeder og videoer fra albummerne.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Fejl ved download",
"image_viewer_page_state_provider_download_success": "Download succesfuld",
"library_page_albums": "Albummer",
@ -166,6 +172,7 @@
"library_page_sharing": "Delte",
"library_page_sort_created": "Senest oprettet",
"library_page_sort_title": "Albumtitel",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API-undtagelse. Tjek serverens URL og prøv igen. ",
"login_form_button_text": "Log ind",
"login_form_email_hint": "din-e-mail@e-mail.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Tre-trins indlæsning kan øge ydeevnen, men kan ligeledes føre til højere netværksbelastning",
"theme_setting_three_stage_loading_title": "Slå tre-trins indlæsning til",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Accepter",
"version_announcement_overlay_release_notes": "udgivelsesnoterne",
"version_announcement_overlay_text_1": "Hej ven, der er en ny version af",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Informationen",
"backup_err_only_album": "Das einzige Album kann nicht entfernt werden",
"backup_info_card_assets": "Elemente",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Zwischenspeicher löschen",
"cache_settings_clear_cache_button_title": "Löscht den Zwischenspeicher der App. Dies wird die Leistungsfähigkeit der App deutlich einschränken, bis der Zwischenspeicher wieder aufgebaut wurde.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Zeitachse wird erstellt.",
"home_page_favorite_err_local": "Kann lokale Elemente noch nicht favorisieren, überspringe",
"home_page_first_time_notice": "Wenn dies das erste Mal ist dass Du Immich nutzt, stelle bitte sicher, dass mindestens ein Album zur Sicherung ausgewählt ist, sodass die Zeitachse mit Fotos und Videos gefüllt werden kann.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Fehler beim Herunterladen",
"image_viewer_page_state_provider_download_success": "Erfolgreich heruntergeladen",
"library_page_albums": "Alben",
@ -166,6 +172,7 @@
"library_page_sharing": "Teilen",
"library_page_sort_created": "Zuletzt erstellt",
"library_page_sort_title": "Albumtitel",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API Fehler. Bitte die Serveradresse überprüfen und erneut versuchen.",
"login_form_button_text": "Anmelden",
"login_form_email_hint": "deine@email.de",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Das dreistufige Ladeverfahren kann die Performance beim Laden verbessern, erhöht allerdings den Datenverbrauch deutlich",
"theme_setting_three_stage_loading_title": "Dreistufiges Laden aktivieren",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Ich habe verstanden",
"version_announcement_overlay_release_notes": "Änderungsprotokoll",
"version_announcement_overlay_text_1": "Hallo mein Freund! Es gibt eine neue Version von",

View file

@ -92,11 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_success": "Success",
"backup_manual_failed": "Failed",
"backup_manual_cancelled": "Cancelled",
"backup_manual_title": "Upload status",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -143,10 +143,6 @@
"delete_dialog_cancel": "Cancel",
"delete_dialog_ok": "Delete",
"delete_dialog_title": "Delete Permanently",
"upload_dialog_title": "Upload Asset",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_cancel": "Cancel",
"description_input_hint_text": "Add description...",
"description_input_submit_error": "Error updating description, check the log for more details",
"exif_bottom_sheet_description": "Add Description...",
@ -162,10 +158,10 @@
"home_page_add_to_album_err_local": "Can not add local assets to albums yet, skipping",
"home_page_add_to_album_success": "Added {added} assets to album {album}.",
"home_page_archive_err_local": "Can not archive local assets yet, skipping",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -176,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -196,7 +193,6 @@
"login_form_save_login": "Stay logged in",
"login_form_server_empty": "Enter a server URL.",
"login_form_server_error": "Could not connect to server.",
"login_disabled": "Login has been disabled",
"monthly_title_text_date_format": "MMMM y",
"motion_photos_page_title": "Motion Photos",
"notification_permission_dialog_cancel": "Cancel",
@ -295,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Cargando información del archivo",
"backup_err_only_album": "No se puede eliminar el único álbum",
"backup_info_card_assets": "archivos",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Construyendo la línea de tiempo",
"home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Error de descarga",
"image_viewer_page_state_provider_download_success": "Descarga exitosa",
"library_page_albums": "Álbumes",
@ -166,6 +172,7 @@
"library_page_sharing": "Compartiendo",
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_title": "Título del álbum",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
"login_form_button_text": "Iniciar Sesión",
"login_form_email_hint": "tucorreo@correo.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "La carga en tres etapas puede aumentar el rendimiento de carga pero provoca un consumo de red significativamente mayor",
"theme_setting_three_stage_loading_title": "Activar carga en tres etapas",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Aceptar",
"version_announcement_overlay_release_notes": "notas de versión",
"version_announcement_overlay_text_1": "Hola amigo, hay una nueva versión de",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Cargando información del archivo",
"backup_err_only_album": "No se puede eliminar el único álbum",
"backup_info_card_assets": "archivos",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Construyendo la línea de tiempo",
"home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Error de descarga",
"image_viewer_page_state_provider_download_success": "Descarga exitosa",
"library_page_albums": "Álbumes",
@ -166,6 +172,7 @@
"library_page_sharing": "Compartiendo",
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_title": "Título del álbum",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
"login_form_button_text": "Iniciar sesión",
"login_form_email_hint": "tucorreo@correo.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "La carga en tres etapas puede aumentar el rendimiento de carga pero provoca un consumo de red significativamente mayor",
"theme_setting_three_stage_loading_title": "Activar carga en tres etapas",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Aceptar",
"version_announcement_overlay_release_notes": "notas de la versión",
"version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Cargando información del archivo",
"backup_err_only_album": "No se puede eliminar el único álbum",
"backup_info_card_assets": "archivos",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)",
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Construyendo la línea de tiempo",
"home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo",
"home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Error de descarga",
"image_viewer_page_state_provider_download_success": "Descarga exitosa",
"library_page_albums": "Álbumes",
@ -166,6 +172,7 @@
"library_page_sharing": "Compartiendo",
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_title": "Título del álbum",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "Excepción producida por API. Por favor, verifica el URL del servidor e inténtalo de nuevo.",
"login_form_button_text": "Iniciar sesión",
"login_form_email_hint": "tucorreo@correo.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "La carga en tres etapas puede aumentar el rendimiento de carga pero provoca un consumo de red significativamente mayor",
"theme_setting_three_stage_loading_title": "Activar carga en tres etapas",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Aceptar",
"version_announcement_overlay_release_notes": "notas de la versión",
"version_announcement_overlay_text_1": "Hola, amigo, hay una nueva versión de",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Tiedostojen lähetystiedot",
"backup_err_only_album": "Vähintään yhden albumin tulee olla valittuna",
"backup_info_card_assets": "kohdetta",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Kirjastosivun esikatselukuvat ({} kohdetta)",
"cache_settings_clear_cache_button": "Tyhjennä välimuisti",
"cache_settings_clear_cache_button_title": "Tyhjennä sovelluksen välimuisti. Tämä vaikuttaa merkittävästi sovelluksen suorituskykyyn, kunnes välimuisti on rakennettu uudelleen.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Rakennetaan aikajanaa",
"home_page_favorite_err_local": "Paikallisten kohteiden lisääminen suosikkeihin ei ole mahdollista, ohitetaan",
"home_page_first_time_notice": "Jos käytät sovellusta ensimmäistä kertaa, muista valita varmuuskopioitavat albumi(t), jotta aikajanalla voi olla kuvia ja videoita.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Lataus epäonnistui",
"image_viewer_page_state_provider_download_success": "Lataus onnistui",
"library_page_albums": "Albumit",
@ -166,6 +172,7 @@
"library_page_sharing": "Jakaminen",
"library_page_sort_created": "Viimeisin luotu",
"library_page_sort_title": "Albumin otsikko",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API-virhe. Tarkista palvelimen URL-osoite ja yritä uudelleen.",
"login_form_button_text": "Kirjaudu",
"login_form_email_hint": "sahkopostisi@esimerkki.fi",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Teema",
"theme_setting_three_stage_loading_subtitle": "Kolmivaiheinen lataaminen saattaa parantaa latauksen suorituskykyä, mutta lisää kaistankäyttöä huomattavasti.",
"theme_setting_three_stage_loading_title": "Ota kolmivaiheinen lataus käyttöön",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Tiedostan",
"version_announcement_overlay_release_notes": "julkaisutiedoissa",
"version_announcement_overlay_text_1": "Hei, kaveri! Uusi palvelinversio on saatavilla sovelluksesta",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Transfert des informations du fichier",
"backup_err_only_album": "Impossible de retirer le seul album",
"backup_info_card_assets": "éléments",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniatures de la page bibliothèque ({} éléments)",
"cache_settings_clear_cache_button": "Effacer le cache",
"cache_settings_clear_cache_button_title": "Efface le cache de l'application. Cela aura un impact significatif sur les performances de l'application jusqu'à ce que le cache soit reconstruit.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Construction de la chronologie",
"home_page_favorite_err_local": "Impossible d'ajouter des éléments locaux aux favoris pour le moment, étape ignorée",
"home_page_first_time_notice": "Si c'est la première fois que vous utilisez l'application, veillez à choisir un ou plusieurs albums de sauvegarde afin que la chronologie puisse alimenter les photos et les vidéos de cet ou ces albums.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Erreur de téléchargement",
"image_viewer_page_state_provider_download_success": "Téléchargement réussi",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Partage",
"library_page_sort_created": "Créations les plus récentes",
"library_page_sort_title": "Titre de l'album",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "Erreur de l'API. Veuillez vérifier l'URL du serveur et et réessayer.",
"login_form_button_text": "Connexion",
"login_form_email_hint": "votreemail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Thème",
"theme_setting_three_stage_loading_subtitle": "Le chargement en trois étapes peut améliorer les performances de chargement, mais entraîne une augmentation significative de la charge du réseau.",
"theme_setting_three_stage_loading_title": "Activer le chargement en trois étapes",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Confirmer",
"version_announcement_overlay_release_notes": "notes de mise à jour",
"version_announcement_overlay_text_1": "Bonjour, une nouvelle version de",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Helyi médiát még nem lehet a kedvencek közé tenni. Kihagyjuk.",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Letöltési Hiba",
"image_viewer_page_state_provider_download_success": "Letöltés Sikeres",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API hiba. Kérljük, ellenőrid a szerver címét, majd próbáld újra.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Caricando informazioni sul file",
"backup_err_only_album": "Non è possibile rimuovere l'unico album",
"backup_info_card_assets": "oggetti ",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Anteprime pagine librerie ({} assets)",
"cache_settings_clear_cache_button": "Cancella cache",
"cache_settings_clear_cache_button_title": "Cancella la cache dell'app. Questo impatterà significativamente le prestazioni dell''app fino a quando la cache non sarà rigenerata.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Costruendo il Timeline",
"home_page_favorite_err_local": "Non puoi aggiungere tra i preferiti le foto ancora non caricate",
"home_page_first_time_notice": "Se è la prima volta che usi l'app, assicurati di scegliere gli album per avere il Timeline con immagini e video",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Errore nel Download",
"image_viewer_page_state_provider_download_success": "Download con successo",
"library_page_albums": "Album",
@ -166,6 +172,7 @@
"library_page_sharing": "Condividendo",
"library_page_sort_created": "Creato il più recente",
"library_page_sort_title": "Titolo album",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API error, per favore ricontrolli URL del server e riprovi",
"login_form_button_text": "Login",
"login_form_email_hint": "tuaemail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Il caricamento a tre stage aumenterà le performance di caricamento ma anche il consumo di banda",
"theme_setting_three_stage_loading_title": "Abilita il caricamento a tre stage",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Presa visione",
"version_announcement_overlay_release_notes": "note di rilascio ",
"version_announcement_overlay_text_1": "Ciao, c'è una nuova versione di",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "アップロード中のファイル",
"backup_err_only_album": "最低1つのアルバムを選択してください",
"backup_info_card_assets": "写真と動画",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "ライブラリのサムネイル ({}枚)",
"cache_settings_clear_cache_button": "キャッシュをクリア",
"cache_settings_clear_cache_button_title": "キャッシュを削除(キャッシュ再生成までアプリのパフォーマンスが著しく低下)",
@ -156,6 +161,7 @@
"home_page_building_timeline": "タイムライン構築中",
"home_page_favorite_err_local": "まだアップロードされてない項目はお気に入り登録できません",
"home_page_first_time_notice": "はじめてアプリを使う場合、タイムラインに写真を表示するためにアルバムを選択してください",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "ダウンロード失敗",
"image_viewer_page_state_provider_download_success": "ダウンロード成功",
"library_page_albums": "アルバム",
@ -166,6 +172,7 @@
"library_page_sharing": "共有中",
"library_page_sort_created": "作成日時",
"library_page_sort_title": "アルバム名",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "APIエラー。URLをチェックしてもう一度試してください",
"login_form_button_text": "ログイン",
"login_form_email_hint": "hoge@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "テーマ",
"theme_setting_three_stage_loading_subtitle": "三段階読み込みを有効にするとパフォーマンスが改善する可能性がありますが、ネットワーク負荷が著しく増加します",
"theme_setting_three_stage_loading_title": "三段階読み込みをオンにする",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "了解",
"version_announcement_overlay_release_notes": "更新情報",
"version_announcement_overlay_text_1": "こんにちは、またはこんばんは!新しい",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "파일 정보 업로드 중",
"backup_err_only_album": "유일한 앨범은 제거할 수 없습니다",
"backup_info_card_assets": "미디어",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "라이브러리 페이지 썸네일 ({} 미디어)",
"cache_settings_clear_cache_button": "캐시 지우기",
"cache_settings_clear_cache_button_title": "앱의 캐시를 지웁니다. 이 작업은 캐시가 다시 빌드될 때까지 앱의 성능에 상당한 영향을 미칩니다.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "타임라인 생성",
"home_page_favorite_err_local": "미디어파일을 즐겨찾기에 추가할 수 없어, 건너뜁니다.",
"home_page_first_time_notice": "앱을 처음 사용하는 경우 타임라인이 앨범의 사진과 비디오를 채울 수 있도록 백업대상 앨범을 선택해야 합니다.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "다운로드 에러",
"image_viewer_page_state_provider_download_success": "다운로드 완료",
"library_page_albums": "앨범",
@ -166,6 +172,7 @@
"library_page_sharing": "공유",
"library_page_sort_created": "최근생성일",
"library_page_sort_title": "앨범 제목",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "로그인",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "테마",
"theme_setting_three_stage_loading_subtitle": "이 기능은 로딩 성능을 향상시킬 수 있지만 훨씬 더 많은 데이터를 사용합니다.",
"theme_setting_three_stage_loading_title": "3단계 로딩 활성화",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "승인",
"version_announcement_overlay_release_notes": "릴리스 정보",
"version_announcement_overlay_text_1": "안녕하세요!",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Faila informācijas augšupielāde",
"backup_err_only_album": "Nevar noņemt vienīgo albumu",
"backup_info_card_assets": "aktīvi",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Bibliotēkas lapu sīktēli ({} aktīvi)",
"cache_settings_clear_cache_button": "Iztīrīt kešatmiņu",
"cache_settings_clear_cache_button_title": "Iztīra aplikācijas kešatmiņu. Tas būtiski ietekmēs lietotnes veiktspēju, līdz kešatmiņa būs pārbūvēta.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Tiek izveidota laika skala",
"home_page_favorite_err_local": "Vēl nevar pievienot izlaisei vietējos aktīvus, notiek izlaišana",
"home_page_first_time_notice": "Ja šī ir pirmā reize, kad izmantojat aplikāciju, lūdzu, izvēlieties dublējuma albumu(s), lai laika skala varētu aizpildīt fotoattēlus un videoklipus albumā(os).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Lejupielādes Kļūda",
"image_viewer_page_state_provider_download_success": "Lejupielāde Izdevās",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Kopīgošana",
"library_page_sort_created": "Jaunākais izveidotais",
"library_page_sort_title": "Albuma virsraksts",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API izņēmums. Lūdzu, pārbaudiet servera URL un mēģiniet vēlreiz.",
"login_form_button_text": "Pieteikties",
"login_form_email_hint": "jūsuepasts@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Dizains",
"theme_setting_three_stage_loading_subtitle": "Trīspakāpju ielāde var palielināt ielādēšanas veiktspēju, bet izraisa ievērojami lielāku tīkla noslodzi",
"theme_setting_three_stage_loading_title": "Iespējot trīspakāpju ielādi",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Atzīt",
"version_announcement_overlay_release_notes": "informācija par laidienu",
"version_announcement_overlay_text_1": "Sveiks draugs, ir jauns izlaidums no",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Laster opp filinformasjon",
"backup_err_only_album": "Kan ikke fjerne det eneste albumet",
"backup_info_card_assets": "objekter",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Feilet",
"backup_manual_in_progress": "Opplasting er allerede i gang. Prøv igjen om litt",
"backup_manual_success": "Vellykket",
"backup_manual_title": "Opplastingsstatus",
"cache_settings_album_thumbnails": "Bibliotekminiatyrbilder ({} objekter)",
"cache_settings_clear_cache_button": "Tøm buffer",
"cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Genererer tidslinjen",
"home_page_favorite_err_local": "Kan ikke sette favoritt på lokale objekter enda, hopper over",
"home_page_first_time_notice": "Hvis dette er første gangen du benytter appen, velg et album (eller flere) for sikkerhetskopiering, slik at tidslinjen kan fylles med dine bilder og videoer.",
"home_page_upload_err_limit": "Maksimalt 30 objekter kan lastes opp om gangen, hopper over",
"image_viewer_page_state_provider_download_error": "Nedlasting feilet",
"image_viewer_page_state_provider_download_success": "Nedlasting vellykket",
"library_page_albums": "Albumer",
@ -166,6 +172,7 @@
"library_page_sharing": "Deling",
"library_page_sort_created": "Nylig opplastet",
"library_page_sort_title": "Albumtittel",
"login_disabled": "Innlogging har blitt deaktivert",
"login_form_api_exception": "API-feil. Sjekk URL-en til serveren og prøv igjen.",
"login_form_button_text": "Logg inn",
"login_form_email_hint": "dinepost@epost.no",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Tre-trinns innlasting kan øke lasteytelsen, men forårsaker betydelig høyere nettverksbelastning",
"theme_setting_three_stage_loading_title": "Aktiver tre-trinns innlasting",
"upload_dialog_cancel": "Avbryt",
"upload_dialog_info": "Vil du utføre backup av valgte objekt(er) til serveren?",
"upload_dialog_ok": "Last opp",
"upload_dialog_title": "Last opp objekt",
"version_announcement_overlay_ack": "Bekreft",
"version_announcement_overlay_release_notes": "endringsloggen",
"version_announcement_overlay_text_1": "Hei, det er en ny versjon av",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Bestandsgegevens uploaden",
"backup_err_only_album": "Kan het enige album niet verwijderen",
"backup_info_card_assets": "items",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Thumbnails bibliotheekpagina ({} items)",
"cache_settings_clear_cache_button": "Cache wissen",
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Tijdlijn opbouwen",
"home_page_favorite_err_local": "Lokale items kunnen nog niet als favoriet worden aangemerkt, overslaan",
"home_page_first_time_notice": "Als dit de eerste keer is dat je de app gebruikt, zorg er dan voor dat je een back-up album kiest, zodat de tijdlijn gevuld kan worden met foto's en video's uit het album.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download mislukt",
"image_viewer_page_state_provider_download_success": "Download succesvol",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Gedeeld",
"library_page_sort_created": "Meest recent gemaakt",
"library_page_sort_title": "Albumtitel",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API fout. Controleer de server URL en probeer opnieuw.",
"login_form_button_text": "Inloggen",
"login_form_email_hint": "jouwemail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Thema",
"theme_setting_three_stage_loading_subtitle": "Laden in drie fasen kan de laadprestaties verbeteren, maar veroorzaakt een aanzienlijk hogere netwerkbelasting",
"theme_setting_three_stage_loading_title": "Laden in drie fasen inschakelen",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Bevestig",
"version_announcement_overlay_release_notes": "releaseopmerkingen",
"version_announcement_overlay_text_1": "Hoi, er is een nieuwe versie beschikbaar van",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Przesyłanie informacji o pliku",
"backup_err_only_album": "Nie można usunąć tylko i wyłącznie albumu",
"backup_info_card_assets": "zasoby",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniatury stron bibliotek ({} zasobów)",
"cache_settings_clear_cache_button": "Wyczyść Cache",
"cache_settings_clear_cache_button_title": "Czyści pamięć podręczną aplikacji. Wpłynie to znacząco na wydajność aplikacji, dopóki pamięć podręczna nie zostanie odbudowana.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albumy",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "twojmail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Motyw",
"theme_setting_three_stage_loading_subtitle": "Trójstopniowe ładowanie może zwiększyć wydajność ładowania, ale powoduje znacznie większe obciążenie sieci",
"theme_setting_three_stage_loading_title": "Włączenie trójstopniowego ładowania",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Potwierdzam",
"version_announcement_overlay_release_notes": "informacje o wydaniu",
"version_announcement_overlay_text_1": "Cześć przyjacielu, jest nowe wydanie",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Загрузка информации о файле",
"backup_err_only_album": "Невозможно удалить единственный альбом",
"backup_info_card_assets": "объекты",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Миниатюры страниц библиотеки ({} объектов)",
"cache_settings_clear_cache_button": "Очистить кэш",
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это значительно повлияет на производительность приложения, до тех пор, пока кэш не будет перестроен заново.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Построение временной шкалы",
"home_page_favorite_err_local": "Пока не удается добавить в избранное локальные объекты, пропускаем",
"home_page_first_time_notice": "Если вы используете приложение впервые, убедитесь, что вы выбрали резервный(е) альбом(ы), чтобы временная шкала могла заполнить фотографии и видео в альбоме(ах).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Ошибка загрузки",
"image_viewer_page_state_provider_download_success": "Успешно загружено",
"library_page_albums": "Альбомы",
@ -166,6 +172,7 @@
"library_page_sharing": "Общие",
"library_page_sort_created": "По новизне",
"library_page_sort_title": "По названию альбома",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Войти",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Тема",
"theme_setting_three_stage_loading_subtitle": "Трехэтапная загрузка может повысить производительность загрузки, но вызывает значительно более высокую нагрузку на сеть",
"theme_setting_three_stage_loading_title": "Включить трехэтапную загрузку",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Подтверждение",
"version_announcement_overlay_release_notes": "примечания к выпуску",
"version_announcement_overlay_text_1": "Привет друг, вышел новый релиз",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Nahrávaný súbor",
"backup_err_only_album": "Nie je možné odstrániť jediný vybraný album",
"backup_info_card_assets": "položiek",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Náhľady stránok knižnice (položiek {})",
"cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Vytváranie časovej osi",
"home_page_favorite_err_local": "Zatiaľ nie je možné zaradiť lokálne média medzi obľúbené, preskakuje sa",
"home_page_first_time_notice": "Ak aplikáciu používate prvý krát, nezabudnite si vybrať zálohované albumy, aby sa na časovej osi mohli nachádzať fotografie a videá z vybraných albumoch.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Chyba sťahovania",
"image_viewer_page_state_provider_download_success": "Sťahovanie bolo úspešné",
"library_page_albums": "Albumy",
@ -166,6 +172,7 @@
"library_page_sharing": "Zdieľanie",
"library_page_sort_created": "Najnovšie vytvorené",
"library_page_sort_title": "Podľa názvu albumu",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "Chyba API. Skontrolujte adresu URL servera a skúste to znova.",
"login_form_button_text": "Prihlásiť sa",
"login_form_email_hint": "tvojmail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Téma",
"theme_setting_three_stage_loading_subtitle": "Trojstupňové načítanie môže zvýšiť výkonnosť načítania, ale vedie k výrazne vyššiemu zaťaženiu siete.",
"theme_setting_three_stage_loading_title": "Povolenie trojstupňového načítavania",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Potvrdiť",
"version_announcement_overlay_release_notes": "poznámky k vydaniu",
"version_announcement_overlay_text_1": "Ahoj, je tu nová verzia",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Otpremanje svojstava datoteke",
"backup_err_only_album": "Nemoguće brisanje jedinog albuma",
"backup_info_card_assets": "zapisi",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Sličice na stranici biblioteke",
"cache_settings_clear_cache_button": "Obriši keš memoriju",
"cache_settings_clear_cache_button_title": "Ova opcija briše keš memoriju aplikacije. Ovo će bitno uticati na performanse aplikacije dok se keš memorija ne učita ponovo.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Kreiranje hronološke linije",
"home_page_favorite_err_local": "Trenutno nije moguce dodati lokalne zapise u favorite, preskacu se",
"home_page_first_time_notice": "Ako je ovo prvi put da koristite aplikaciju, molimo Vas da odaberete albume koje želite da sačuvate",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Preuzimanje Neuspešno",
"image_viewer_page_state_provider_download_success": "Preuzimanje Uspešno",
"library_page_albums": "Albumi",
@ -166,6 +172,7 @@
"library_page_sharing": "Deljenje",
"library_page_sort_created": "Najnovije kreirano",
"library_page_sort_title": "Naziv albuma",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Prijavi se",
"login_form_email_hint": "vašemail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Teme",
"theme_setting_three_stage_loading_subtitle": "Trostepeno učitavanje možda ubrza učitavanje, po cenu potrošnje podataka",
"theme_setting_three_stage_loading_title": "Aktiviraj trostepeno učitavanje",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Priznati",
"version_announcement_overlay_release_notes": "novine nove verzije",
"version_announcement_overlay_text_1": "Ćao, nova verzija",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Laddar upp filinformation",
"backup_err_only_album": "Kan inte ta bort det enda albumet",
"backup_info_card_assets": "objekt",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Miniatyrbilder för bibliotek ({} bilder och videor)",
"cache_settings_clear_cache_button": "Rensa cacheminnet",
"cache_settings_clear_cache_button_title": "Rensar appens cacheminne. Detta kommer att avsevärt påverka appens prestanda tills cachen har byggts om.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Bygger tidslinjen",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "Om det här är första gången du använder appen, välj ett eller flera backup-album så att tidslinjen kan fyllas med foton och videor från albumen.",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Album",
@ -166,6 +172,7 @@
"library_page_sharing": "Delas",
"library_page_sort_created": "Senast skapad",
"library_page_sort_title": "Albumtitel",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Logga in",
"login_form_email_hint": "din.email@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Tema",
"theme_setting_three_stage_loading_subtitle": "Trestegsladdning kan öka prestandan, men kan också leda till signifikant högre nätverksbelastning",
"theme_setting_three_stage_loading_title": "Aktivera trestegsladdning",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Bekräfta",
"version_announcement_overlay_release_notes": "versionsinformation",
"version_announcement_overlay_text_1": "Hej vännen, det finns en ny version av",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "ไม่สามารถนำอัลบั้มสุดท้ายออกได้",
"backup_info_card_assets": "ทรัพยากร",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "ล้มเหลว",
"backup_manual_in_progress": "อัปโหลดกำลังดำเนินการอยู่ โปรดลองใหม่ในสักพัก",
"backup_manual_success": "สำเร็จ",
"backup_manual_title": "สถานะอัพโหลด",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "ล้างแคช",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "กำลังสร้าง timeline",
"home_page_favorite_err_local": " ไม่สามารถตั้งทรัพยากรบนเครื่องเป็นรายการโปรด กำลังข้าม",
"home_page_first_time_notice": "ถ้าครั้งนี้เป็นครั้งแรกที่ใช้แอปนี้ กรุณาเลือกอัลบั้มที่จะสำรองข้อมูล ไทม์ไลน์จะได้เพิ่มรูปภาพและวิดีโอที่อยู่ในอัลบั้ม",
"home_page_upload_err_limit": "สามารถอัพโหลดได้มากสุดครั้งละ 30 ทรัพยากร กำลังข้าม",
"image_viewer_page_state_provider_download_error": "ดาวน์โหลดผิดพลาด",
"image_viewer_page_state_provider_download_success": "ดาวน์โหลดสำเร็จ",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "การแชร์",
"library_page_sort_created": "สร้างล่าสุด",
"library_page_sort_title": "ชื่ออัลบั้ม",
"login_disabled": "ล็อกอินถูกปิด",
"login_form_api_exception": "ข้อผิดพลาด API กรุณาตรวจสอบ URL แล้วลองใหม่",
"login_form_button_text": "เข้าสู่ระบบ",
"login_form_email_hint": "อีเมลคุณ@อีเมล.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "ยกเลิก",
"upload_dialog_info": "คุณต้องการอัพโหลดทรัพยากรดังกล่าวบนเซิร์ฟเวอร์หรือไม่?",
"upload_dialog_ok": "อัปโหลด",
"upload_dialog_title": "อัปโหลดทรัพยากร",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

@ -92,6 +92,11 @@
"backup_controller_page_uploading_file_info": "Uploading file info",
"backup_err_only_album": "Cannot remove the only album",
"backup_info_card_assets": "assets",
"backup_manual_cancelled": "Cancelled",
"backup_manual_failed": "Failed",
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"cache_settings_album_thumbnails": "Library page thumbnails ({} assets)",
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
@ -156,6 +161,7 @@
"home_page_building_timeline": "Building the timeline",
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
"image_viewer_page_state_provider_download_error": "Download Error",
"image_viewer_page_state_provider_download_success": "Download Success",
"library_page_albums": "Albums",
@ -166,6 +172,7 @@
"library_page_sharing": "Sharing",
"library_page_sort_created": "Most recently created",
"library_page_sort_title": "Album title",
"login_disabled": "Login has been disabled",
"login_form_api_exception": "API exception. Please check the server URL and try again.",
"login_form_button_text": "Login",
"login_form_email_hint": "youremail@email.com",
@ -284,6 +291,10 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"upload_dialog_cancel": "Cancel",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_ok": "Upload",
"upload_dialog_title": "Upload Asset",
"version_announcement_overlay_ack": "Acknowledge",
"version_announcement_overlay_release_notes": "release notes",
"version_announcement_overlay_text_1": "Hi friend, there is a new release of",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 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 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 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 classname="fastlane.lanes" name="4: build_app" time="99.212621">
<testcase classname="fastlane.lanes" name="4: build_app" time="96.47923">
</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>

View file

@ -342,10 +342,11 @@ class HomePage extends HookConsumerWidget {
listener: selectionListener,
selectionActive: selectionEnabledHook.value,
onRefresh: refreshAssets,
topWidget:
(currentUser != null && currentUser.memoryEnabled)
? const MemoryLane()
: const SizedBox(),
topWidget: (currentUser != null &&
currentUser.memoryEnabled != null &&
currentUser.memoryEnabled!)
? const MemoryLane()
: const SizedBox(),
),
error: (error, _) => Center(child: Text(error.toString())),
loading: buildLoadingIndicator,

View file

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

View file

@ -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
});

View file

@ -3,6 +3,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.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';
class VersionAnnouncementOverlay extends HookConsumerWidget {
@ -12,6 +13,12 @@ class VersionAnnouncementOverlay extends HookConsumerWidget {
@override
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 {
final Uri url =
Uri.parse('https://github.com/immich-app/immich/releases/latest');

View file

@ -45,6 +45,7 @@ doc/DeleteAssetDto.md
doc/DeleteAssetResponseDto.md
doc/DeleteAssetStatus.md
doc/DownloadArchiveInfo.md
doc/DownloadInfoDto.md
doc/DownloadResponseDto.md
doc/ExifResponseDto.md
doc/ImportAssetDto.md
@ -186,6 +187,7 @@ lib/model/delete_asset_dto.dart
lib/model/delete_asset_response_dto.dart
lib/model/delete_asset_status.dart
lib/model/download_archive_info.dart
lib/model/download_info_dto.dart
lib/model/download_response_dto.dart
lib/model/exif_response_dto.dart
lib/model/import_asset_dto.dart
@ -298,6 +300,7 @@ test/delete_asset_dto_test.dart
test/delete_asset_response_dto_test.dart
test/delete_asset_status_test.dart
test/download_archive_info_test.dart
test/download_info_dto_test.dart
test/download_response_dto_test.dart
test/exif_response_dto_test.dart
test/import_asset_dto_test.dart

View file

@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.72.2
- API version: 1.73.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements
@ -91,7 +91,7 @@ Class | Method | HTTP request | Description
*AssetApi* | [**checkDuplicateAsset**](doc//AssetApi.md#checkduplicateasset) | **POST** /asset/check |
*AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist |
*AssetApi* | [**deleteAsset**](doc//AssetApi.md#deleteasset) | **DELETE** /asset |
*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download |
*AssetApi* | [**downloadArchive**](doc//AssetApi.md#downloadarchive) | **POST** /asset/download/archive |
*AssetApi* | [**downloadFile**](doc//AssetApi.md#downloadfile) | **POST** /asset/download/{id} |
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |
*AssetApi* | [**getAssetById**](doc//AssetApi.md#getassetbyid) | **GET** /asset/assetById/{id} |
@ -101,7 +101,7 @@ Class | Method | HTTP request | Description
*AssetApi* | [**getByTimeBucket**](doc//AssetApi.md#getbytimebucket) | **GET** /asset/time-bucket |
*AssetApi* | [**getCuratedLocations**](doc//AssetApi.md#getcuratedlocations) | **GET** /asset/curated-locations |
*AssetApi* | [**getCuratedObjects**](doc//AssetApi.md#getcuratedobjects) | **GET** /asset/curated-objects |
*AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **GET** /asset/download |
*AssetApi* | [**getDownloadInfo**](doc//AssetApi.md#getdownloadinfo) | **POST** /asset/download/info |
*AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
*AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
*AssetApi* | [**getTimeBuckets**](doc//AssetApi.md#gettimebuckets) | **GET** /asset/time-buckets |
@ -216,6 +216,7 @@ Class | Method | HTTP request | Description
- [DeleteAssetResponseDto](doc//DeleteAssetResponseDto.md)
- [DeleteAssetStatus](doc//DeleteAssetStatus.md)
- [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
- [DownloadInfoDto](doc//DownloadInfoDto.md)
- [DownloadResponseDto](doc//DownloadResponseDto.md)
- [ExifResponseDto](doc//ExifResponseDto.md)
- [ImportAssetDto](doc//ImportAssetDto.md)

View file

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

18
mobile/openapi/doc/DownloadInfoDto.md generated Normal file
View file

@ -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)

View file

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

View file

@ -81,6 +81,7 @@ part 'model/delete_asset_dto.dart';
part 'model/delete_asset_response_dto.dart';
part 'model/delete_asset_status.dart';
part 'model/download_archive_info.dart';
part 'model/download_info_dto.dart';
part 'model/download_response_dto.dart';
part 'model/exif_response_dto.dart';
part 'model/import_asset_dto.dart';

View file

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

View file

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

View file

@ -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>{
};
}

View file

@ -21,7 +21,7 @@ class UserResponseDto {
required this.id,
required this.isAdmin,
required this.lastName,
required this.memoriesEnabled,
this.memoriesEnabled,
required this.oauthId,
required this.profileImagePath,
required this.shouldChangePassword,
@ -45,7 +45,13 @@ class UserResponseDto {
String lastName;
bool memoriesEnabled;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? memoriesEnabled;
String oauthId;
@ -85,7 +91,7 @@ class UserResponseDto {
(id.hashCode) +
(isAdmin.hashCode) +
(lastName.hashCode) +
(memoriesEnabled.hashCode) +
(memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(oauthId.hashCode) +
(profileImagePath.hashCode) +
(shouldChangePassword.hashCode) +
@ -113,7 +119,11 @@ class UserResponseDto {
json[r'id'] = this.id;
json[r'isAdmin'] = this.isAdmin;
json[r'lastName'] = this.lastName;
if (this.memoriesEnabled != null) {
json[r'memoriesEnabled'] = this.memoriesEnabled;
} else {
// json[r'memoriesEnabled'] = null;
}
json[r'oauthId'] = this.oauthId;
json[r'profileImagePath'] = this.profileImagePath;
json[r'shouldChangePassword'] = this.shouldChangePassword;
@ -142,7 +152,7 @@ class UserResponseDto {
id: mapValueOfType<String>(json, r'id')!,
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
lastName: mapValueOfType<String>(json, r'lastName')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
oauthId: mapValueOfType<String>(json, r'oauthId')!,
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
@ -203,7 +213,6 @@ class UserResponseDto {
'id',
'isAdmin',
'lastName',
'memoriesEnabled',
'oauthId',
'profileImagePath',
'shouldChangePassword',

View file

@ -97,7 +97,7 @@ void main() {
// 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 {
// TODO
});

View file

@ -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
});
});
}

View file

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

View file

@ -1026,84 +1026,7 @@
]
}
},
"/asset/download": {
"get": {
"operationId": "getDownloadInfo",
"parameters": [
{
"name": "assetIds",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"type": "array",
"items": {
"type": "string"
}
}
},
{
"name": "albumId",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"type": "string"
}
},
{
"name": "userId",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"type": "string"
}
},
{
"name": "archiveSize",
"required": false,
"in": "query",
"schema": {
"type": "number"
}
},
{
"name": "key",
"required": false,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DownloadResponseDto"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Asset"
]
},
"/asset/download/archive": {
"post": {
"operationId": "downloadArchive",
"parameters": [
@ -1155,6 +1078,57 @@
]
}
},
"/asset/download/info": {
"post": {
"operationId": "getDownloadInfo",
"parameters": [
{
"name": "key",
"required": false,
"in": "query",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DownloadInfoDto"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DownloadResponseDto"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Asset"
]
}
},
"/asset/download/{id}": {
"post": {
"operationId": "downloadFile",
@ -4590,7 +4564,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "1.72.2",
"version": "1.73.0",
"contact": {}
},
"tags": [],
@ -5549,6 +5523,29 @@
],
"type": "object"
},
"DownloadInfoDto": {
"properties": {
"albumId": {
"format": "uuid",
"type": "string"
},
"archiveSize": {
"type": "integer"
},
"assetIds": {
"items": {
"format": "uuid",
"type": "string"
},
"type": "array"
},
"userId": {
"format": "uuid",
"type": "string"
}
},
"type": "object"
},
"DownloadResponseDto": {
"properties": {
"archives": {
@ -7152,8 +7149,7 @@
"createdAt",
"deletedAt",
"updatedAt",
"oauthId",
"memoriesEnabled"
"oauthId"
],
"type": "object"
},

View file

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

View file

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

View file

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

View file

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

View file

@ -364,6 +364,7 @@ describe(AlbumService.name, () => {
updatedAt: expect.any(Date),
sharedUsers: [],
});
expect(albumMock.getById).toHaveBeenCalledWith(albumStub.sharedWithUser.id, { withAssets: false });
});
it('should prevent removing a shared user from a not-owned album (shared with auth user)', async () => {
@ -432,7 +433,7 @@ describe(AlbumService.name, () => {
await sut.get(authStub.admin, albumStub.oneAsset.id, {});
expect(albumMock.getById).toHaveBeenCalledWith(albumStub.oneAsset.id);
expect(albumMock.getById).toHaveBeenCalledWith(albumStub.oneAsset.id, { withAssets: true });
expect(accessMock.album.hasOwnerAccess).toHaveBeenCalledWith(authStub.admin.id, albumStub.oneAsset.id);
});
@ -442,7 +443,7 @@ describe(AlbumService.name, () => {
await sut.get(authStub.adminSharedLink, 'album-123', {});
expect(albumMock.getById).toHaveBeenCalledWith('album-123');
expect(albumMock.getById).toHaveBeenCalledWith('album-123', { withAssets: true });
expect(accessMock.album.hasSharedLinkAccess).toHaveBeenCalledWith(
authStub.adminSharedLink.sharedLinkId,
'album-123',
@ -455,7 +456,7 @@ describe(AlbumService.name, () => {
await sut.get(authStub.user1, 'album-123', {});
expect(albumMock.getById).toHaveBeenCalledWith('album-123');
expect(albumMock.getById).toHaveBeenCalledWith('album-123', { withAssets: true });
expect(accessMock.album.hasSharedAlbumAccess).toHaveBeenCalledWith(authStub.user1.id, 'album-123');
});

View file

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

View file

@ -13,7 +13,7 @@ import { IAssetRepository } from './asset.repository';
import {
AssetIdsDto,
DownloadArchiveInfo,
DownloadDto,
DownloadInfoDto,
DownloadResponseDto,
MemoryLaneDto,
TimeBucketAssetDto,
@ -148,6 +148,9 @@ export class AssetService {
if (dto.albumId) {
await this.access.requirePermission(authUser, Permission.ALBUM_READ, [dto.albumId]);
} else if (dto.userId) {
if (dto.isArchived !== false) {
await this.access.requirePermission(authUser, Permission.ARCHIVE_READ, [dto.userId]);
}
await this.access.requirePermission(authUser, Permission.LIBRARY_READ, [dto.userId]);
} else {
dto.userId = authUser.id;
@ -176,7 +179,7 @@ export class AssetService {
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 archives: DownloadArchiveInfo[] = [];
let archive: DownloadArchiveInfo = { size: 0, assetIds: [] };
@ -234,7 +237,7 @@ export class AssetService {
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;
if (dto.assetIds) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -47,7 +47,7 @@ describe(PersonService.name, () => {
visible: 1,
people: [responseDto],
});
expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 });
expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: false });
});
it('should get all visible people with thumbnails', async () => {
personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
@ -56,7 +56,7 @@ describe(PersonService.name, () => {
visible: 1,
people: [responseDto],
});
expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 });
expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: false });
});
it('should get all hidden and visible people with thumbnails', async () => {
personMock.getAll.mockResolvedValue([personStub.withName, personStub.hidden]);
@ -73,7 +73,7 @@ describe(PersonService.name, () => {
},
],
});
expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1 });
expect(personMock.getAll).toHaveBeenCalledWith(authStub.admin.id, { minimumFaceCount: 1, withHidden: true });
});
});

View file

@ -26,11 +26,11 @@ export class PersonService {
) {}
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
.filter((person) => !!person.thumbnailPath)
.map((person) => mapPerson(person));

View file

@ -69,9 +69,9 @@ export class ServerInfoService {
getSupportedMediaTypes(): ServerMediaTypesResponseDto {
return {
video: [...Object.keys(mimeTypes.video)],
image: [...Object.keys(mimeTypes.image)],
sidecar: [...Object.keys(mimeTypes.sidecar)],
video: Object.keys(mimeTypes.video),
image: Object.keys(mimeTypes.image),
sidecar: Object.keys(mimeTypes.sidecar),
};
}
}

View file

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

View file

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

View file

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

View file

@ -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
}
}

View file

@ -1,7 +1,7 @@
import { AlbumAssetCount, IAlbumRepository } from '@app/domain';
import { AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from '@app/domain';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, IsNull, Not, Repository } from 'typeorm';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { DataSource, FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
import { dataSource } from '../database.config';
import { AlbumEntity, AssetEntity } from '../entities';
@ -10,27 +10,30 @@ export class AlbumRepository implements IAlbumRepository {
constructor(
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
@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[]> {
@ -82,7 +85,7 @@ export class AlbumRepository implements IAlbumRepository {
*/
async getInvalidThumbnail(): Promise<string[]> {
// Using dataSource, because there is no direct access to albums_assets_assets.
const albumHasAssets = dataSource
const albumHasAssets = this.dataSource
.createQueryBuilder()
.select('1')
.from('albums_assets_assets', 'albums_assets')
@ -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> {
return this.repository.exist({
where: {

View file

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

View file

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

View file

@ -1,4 +1,5 @@
import {
IAlbumRepository,
IAssetRepository,
IBaseJob,
ICryptoRepository,
@ -59,6 +60,7 @@ export class MetadataExtractionProcessor {
constructor(
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
@Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
@Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(IGeocodingRepository) private geocodingRepository: IGeocodingRepository,
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository,
@ -92,6 +94,38 @@ export class MetadataExtractionProcessor {
}
}
async handleLivePhotoLinking(job: IEntityJob) {
const { id } = job;
const [asset] = await this.assetRepository.getByIds([id]);
if (!asset?.exifInfo) {
return false;
}
if (!asset.exifInfo.livePhotoCID) {
return true;
}
const otherType = asset.type === AssetType.VIDEO ? AssetType.IMAGE : AssetType.VIDEO;
const match = await this.assetRepository.findLivePhotoMatch({
livePhotoCID: asset.exifInfo.livePhotoCID,
ownerId: asset.ownerId,
otherAssetId: asset.id,
type: otherType,
});
if (!match) {
return true;
}
const [photoAsset, motionAsset] = asset.type === AssetType.IMAGE ? [asset, match] : [match, asset];
await this.assetRepository.save({ id: photoAsset.id, livePhotoVideoId: motionAsset.id });
await this.assetRepository.save({ id: motionAsset.id, isVisible: false });
await this.albumRepository.removeAsset(motionAsset.id);
return true;
}
async handleQueueMetadataExtraction(job: IBaseJob) {
const { force } = job;
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => {
@ -308,8 +342,16 @@ export class MetadataExtractionProcessor {
const latitude = getExifProperty('GPSLatitude');
const longitude = getExifProperty('GPSLongitude');
newExif.latitude = latitude !== null ? parseLatitude(latitude) : null;
newExif.longitude = longitude !== null ? parseLongitude(longitude) : null;
const lat = parseLatitude(latitude);
const lon = parseLongitude(longitude);
if (lat === 0 && lon === 0) {
this.logger.warn(`Latitude & Longitude were on Null Island (${lat},${lon}), not assigning coordinates`);
} else {
newExif.latitude = lat;
newExif.longitude = lon;
}
if (getExifProperty('MotionPhoto')) {
// Seen on more recent Pixel phones: starting as early as Pixel 4a, possibly earlier.
const rawDirectory = getExifProperty('Directory');
@ -343,19 +385,6 @@ export class MetadataExtractionProcessor {
}
newExif.livePhotoCID = getExifProperty('MediaGroupUUID');
if (newExif.livePhotoCID && !asset.livePhotoVideoId) {
const motionAsset = await this.assetRepository.findLivePhotoMatch({
livePhotoCID: newExif.livePhotoCID,
otherAssetId: asset.id,
ownerId: asset.ownerId,
type: AssetType.VIDEO,
});
if (motionAsset) {
await this.assetRepository.save({ id: asset.id, livePhotoVideoId: motionAsset.id });
await this.assetRepository.save({ id: motionAsset.id, isVisible: false });
}
}
await this.applyReverseGeocoding(asset, newExif);
/**
@ -420,19 +449,6 @@ export class MetadataExtractionProcessor {
newExif.fps = null;
newExif.livePhotoCID = exifData?.ContentIdentifier || null;
if (newExif.livePhotoCID) {
const photoAsset = await this.assetRepository.findLivePhotoMatch({
livePhotoCID: newExif.livePhotoCID,
ownerId: asset.ownerId,
otherAssetId: asset.id,
type: AssetType.IMAGE,
});
if (photoAsset) {
await this.assetRepository.save({ id: photoAsset.id, livePhotoVideoId: asset.id });
await this.assetRepository.save({ id: asset.id, isVisible: false });
}
}
if (videoTags && videoTags['location']) {
const location = videoTags['location'] as string;
const locationRegex = /([+-][0-9]+\.[0-9]+)([+-][0-9]+\.[0-9]+)\/$/;

View file

@ -23,6 +23,12 @@ describe('parsing latitude from string input', () => {
});
});
describe('parsing latitude from null input', () => {
it('returns null for null input', () => {
expect(parseLatitude(null)).toBeNull();
});
});
describe('parsing longitude from string input', () => {
it('returns null for invalid inputs', () => {
expect(parseLongitude('')).toBeNull();
@ -44,3 +50,9 @@ describe('parsing longitude from string input', () => {
expect(parseLongitude('-0.0')).toBeCloseTo(-0.0);
});
});
describe('parsing longitude from null input', () => {
it('returns null for null input', () => {
expect(parseLongitude(null)).toBeNull();
});
});

View file

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

View file

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

View file

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

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -4,7 +4,7 @@
* Immich
* Immich API
*
* The version of the OpenAPI document: 1.72.2
* The version of the OpenAPI document: 1.73.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

View file

@ -118,7 +118,7 @@
<form autocomplete="off" class="flex flex-col" on:submit|preventDefault>
<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
class="mt-2 rounded-lg bg-slate-200 p-2 text-sm hover:cursor-pointer dark:bg-gray-600"
name="presets"

View file

@ -42,8 +42,8 @@
<form autocomplete="off" on:submit|preventDefault>
<div class="ml-4 mt-4 flex flex-col gap-4">
<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
bind:value={thumbnailConfig.webpSize}
options={[
@ -57,8 +57,8 @@
/>
<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
bind:value={thumbnailConfig.jpegSize}
options={[

Some files were not shown because too many files have changed in this diff Show more