Compare commits

...

55 Commits

Author SHA1 Message Date
Jason Rasmussen
aec50aeb59 chore!: queue endpoint migration 2026-04-14 22:34:58 -04:00
Brandon Wees
6da2d3d587 chore!: remove getRandom api endpoint (#27780)
* chore!: remove getRandom api endpoint

* chore: sync openapi

* fix: test

* chore: more cleanup
2026-04-14 21:32:12 -04:00
Jason Rasmussen
41d2d84b21 chore!: remove deprecated env variables (#27802) 2026-04-14 21:30:31 -04:00
Jason Rasmussen
6ba17bb86f refactor!: remove my shared link dto (#27023)
refactor!: remove deprecated shared link apis
2026-04-14 20:58:02 -04:00
Jason Rasmussen
e1a84d3ab6 refactor!: remove replace asset (#27022) 2026-04-14 20:21:05 -04:00
Timon
7d8f843be6 refactor!: migrate class-validator to zod (#26597) 2026-04-14 23:39:03 +02:00
OdinOxin
3753b7a4d1 feat: sort users alphabetically when adding to album (#27731) 2026-04-14 21:21:22 +02:00
Jonathan Jogenfors
84a1fb27ca feat(web): lazy load library and server statistics (#26406)
* feat: add offline library statistics

* fix comments

* feat: add offline library statistics

* fix comments

* fix Daniel's comments

* fix Daniels comment 2
2026-04-14 12:54:09 -04:00
Yaros
81780b0cc0 fix(web): add partner photo to album from multiselect (#27767)
* fix(web): add partner photo to album

* chore: fix formatting

* fix: run-job assets

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2026-04-14 16:48:39 +00:00
Min Idzelis
5e81a5a054 feat(web): remove delay from Skeleton (#27580)
Change-Id: I95a37f1af832c005a8f009d6f07df8ac6a6a6964
2026-04-14 12:47:37 -04:00
Miguel Raposo
e4e2f586b5 fix(server): render storage template date/time tokens in UTC (#24350) (#26917) 2026-04-14 18:45:14 +02:00
OdinOxin
a001adf14a feat: filter users on share (#27732)
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-04-14 16:43:45 +00:00
Daniel Dietzler
136814540a fix: asset multi select download shortcut (#27784) 2026-04-14 12:29:55 -04:00
Jason Rasmussen
fed5cc1ae1 feat: upgrade immich/ui (#27792) 2026-04-14 16:18:12 +00:00
Yaros
641ab51b80 fix(web): selection clearing on preview (#27702)
* fix(web): selection clearing on preview

* chore: remove unnecessary checks
2026-04-14 10:06:32 -05:00
Yaros
3b47ca1c37 fix(mobile): add keys for person tiles in search (#27689)
* fix(mobile): key for person tiles in search

* chore: add key to avatar

* chore: use simple personId

* chore: rename key in person page
2026-04-14 10:05:09 -05:00
Jason Rasmussen
8fb2c7755d feat: commands (#27546) 2026-04-14 09:34:46 -04:00
Jason Rasmussen
1ba0989e15 refactor: auth manager (#27638) 2026-04-14 08:49:24 -04:00
renovate[bot]
daed3f0966 chore(deps): update dependency @sveltejs/kit to v2.57.1 [security] (#27762)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 11:50:25 +02:00
renovate[bot]
46d612ad8c chore(deps): update dependency nodemailer to v8.0.5 [security] (#27623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 11:49:26 +02:00
renovate[bot]
513dead2c2 chore(deps): update dependency @nestjs/core to v11.1.18 [security] (#27544)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 09:49:03 +00:00
renovate[bot]
ca006c1569 fix(deps): update typescript-projects (#27573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-04-14 11:41:09 +02:00
renovate[bot]
4e8e8304fd fix(deps): update react-email monorepo (major) (#27572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-14 11:40:58 +02:00
Nicolas-micuda-becker
d377d2e145 fix(web): center images in RTL layouts (#27678) (#27753) 2026-04-13 13:29:35 -05:00
shenlong
9c9feddf7d refactor: folder page to use new models (#27657)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2026-04-13 12:19:44 -05:00
Andreas Heinz
bfcf34d8b5 feat(web): persist state of file path information in details panel (#27770)
feat(enhancement): persist state of file path info in details panel
2026-04-13 12:18:34 -05:00
github-actions
95e57a24cb chore: version v2.7.5 2026-04-13 14:27:31 +00:00
Weblate (bot)
eada662981 chore(web): update translations (#27589)
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ar/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/da/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/de_CH/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/eo/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/hr/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/id/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/ko/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lt/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/lv/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/nl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/pl/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/th/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/uk/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/vi/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/yue_Hant/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/immich/immich/zh_Hant/
Translation: Immich/immich

Co-authored-by: Aliyss Snow <mangoworksbeta@gmail.com>
Co-authored-by: Bannawat Thongbai <kaji.kanlapat99@gmail.com>
Co-authored-by: Carlo Beltrame <weblate@pendantmusic.ch>
Co-authored-by: Dawnsink <dai@cosmopeace.com>
Co-authored-by: Edmundas <edmius@gmail.com>
Co-authored-by: Happy <59247878+happy2452354@users.noreply.github.com>
Co-authored-by: Jeppe Nellemann <jepnel@proton.me>
Co-authored-by: Linerly <linerly@proton.me>
Co-authored-by: Link Notig <TestMailProtonWhyNot@protonmail.com>
Co-authored-by: Mees Frensel <meesfrensel@gmail.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Osama <laptooxz@proton.me>
Co-authored-by: PPNplus <ppnplus@protonmail.com>
Co-authored-by: Tim Morley <weblate.3919org@timsk.org>
Co-authored-by: UDP <udp@users.noreply.hosted.weblate.org>
Co-authored-by: User 123456789 <user123456789@users.noreply.hosted.weblate.org>
Co-authored-by: Volodymyr Sakharov <savolodya@gmail.com>
Co-authored-by: Vykintas Vyšniauskas <vykintasv@gmail.com>
Co-authored-by: WellsTsai <dan50907@gmail.com>
Co-authored-by: brainheart95 <josephdm4d@gmail.com>
Co-authored-by: dvbthien <dvbthien@users.noreply.hosted.weblate.org>
Co-authored-by: 이찬웅 <lcw7527@gmail.com>
2026-04-13 14:25:01 +00:00
Zack Pollard
352f6ecc28 fix(server): add rate limit and deduplication to version check (#27747) 2026-04-13 12:35:46 +00:00
github-actions
bee49cef02 chore: version v2.7.4 2026-04-10 16:32:26 +00:00
shenlong
6d0c6a4008 chore: pump cronet version (#27685)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2026-04-10 16:29:05 +00:00
Luis Nachtigall
8a975e5ea9 refactor(mobile): cleanup iOS image loading pipeline (#27672)
* refactor: replace DispatchQueue + DispatchSemaphore with OperationQueue for image processing

* implement RequestRegistry and UnfairLock for managing cancellable requests

* implement requests registry for local and remote image processing

* remove Cancellable protocol and cancel method from request registry

* refactor: introduce ImageRequest base class with unified cancellation and finish helpers

* refactor: add get method to RequestRegistry and streamline request removal in image processing

* add guard to cancel to prevent double onCancel calls

* fix duplicate code merge issue

* refactor(ios): enhance finish method to return callback status

* remove unfitting methods form ImageRequest.swift and fix memory issue

* revert bad merge

* refactor(ios): resolve cancellation issues

* refactor(ios): streamline image request completion handling

* add return statements

* refactor(ios): simplify image request cancellation and registry handling

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2026-04-10 10:56:35 -05:00
Luis Nachtigall
d39e7da10d fix(mobile): fix flutter cache eviction on thumbnails (#27663)
* fix: add markFinished parameter to loadRequest and loadCodecRequest methods

* update loadRequest and loadCodecRequest methods to use isFinal

* Apply suggestions from code review

Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>

* remove redundant check

* fix: ensure isFinished is set correctly during cache eviction

* formatting

---------

Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
2026-04-10 10:28:55 -05:00
Daniel Dietzler
bc400d68ac chore: move .tsbuildinfo file to dist folder (#27682) 2026-04-10 16:02:25 +02:00
renovate[bot]
d7f038ec60 chore(deps): update dependency eslint-plugin-unicorn to v64 (#27575)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-04-10 10:23:42 +00:00
Mees Frensel
26957f37ce fix(server): hide original filename when not showing metadata (#27581) 2026-04-10 12:07:18 +02:00
github-actions
3254d31cd2 chore: version v2.7.3 2026-04-09 17:51:40 +00:00
Jason Rasmussen
7b269d1638 fix: ssr open graph tags (#27639)
fix: SSR open graph tags
2026-04-09 12:16:41 -04:00
Luis Nachtigall
b5bed02300 fix(mobile): get provider refs before async gaps in backup page (#27597)
* fix(mobile): get provider refs before async gaps in backup page

* fix(mobile): use previously created provider refs in start backup function
2026-04-08 20:55:53 -05:00
Zack Pollard
5553910236 fix(web): don't cache empty search results for people search (#27632) 2026-04-09 02:33:04 +01:00
Zack Pollard
8d67c1f820 fix(server): people search not showing for 3 or less characters (#27629)
Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
2026-04-09 01:56:07 +01:00
Matthew Momjian
ed0ec30917 fix(docs): updated docker deprecation link (#27633)
new link
2026-04-08 20:33:11 -04:00
Luis Nachtigall
2b0f6c9202 fix(mobile): improve image load cancellation handling (#27624)
fix(image): improve image load cancellation handling
2026-04-08 17:23:42 -04:00
André Erasmus
55ab8c65b6 fix(server): avoid false restore failures on large database imports (#27420)
* fix(server): increase restore health check timeout and reject with Error

* chore: clean up

---------

Co-authored-by: André Erasmus <25480506+NoBadDays@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
2026-04-08 16:03:41 -04:00
Cullen Jennings
781d568f29 fix(docs): typo 'Start rating' to 'Star rating' (#27606) 2026-04-08 18:25:45 +00:00
Zack Pollard
6a361dae72 fix(server): use randomized cron for version check scheduling (#27626)
Also removes unnecessary rate limit
2026-04-08 19:15:38 +01:00
renovate[bot]
64766c8c06 chore(deps): update github-actions (#27560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-08 17:32:54 +02:00
github-actions
6a63e814a5 chore: version v2.7.2 2026-04-07 20:58:38 +00:00
Jason Rasmussen
6441c3b77c fix: server build (#27599) 2026-04-07 20:53:04 +00:00
github-actions
b03a649e74 chore: version v2.7.1 2026-04-07 20:22:28 +00:00
Mert
2903b2653b fix(server): library import batch size (#27595)
* lower batch size

* update test
2026-04-07 15:58:03 -04:00
Mert
9ba9a22c40 fix(ml): downgrade numpy (#27591)
downgrade numpy
2026-04-07 15:57:42 -04:00
bo0tzz
f1882c2926 fix: csp quotes (#27592) 2026-04-07 15:54:30 -04:00
Daniel Dietzler
4278789083 chore: git ignore tsBuildInfo (#27594) 2026-04-07 15:53:10 -04:00
renovate[bot]
921c8a8de3 chore(deps): update dependency typescript to v6 (#27577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-04-07 17:15:55 +02:00
543 changed files with 11141 additions and 13833 deletions

View File

@@ -210,7 +210,7 @@ jobs:
working-directory: ./mobile
- name: Setup Ruby
uses: ruby/setup-ruby@c515ec17f69368147deb311832da000dd229d338 # v1.297.0
uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1.299.0
with:
ruby-version: '3.3'
bundler-cache: true

View File

@@ -89,7 +89,7 @@ jobs:
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Login to GitHub Container Registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
if: ${{ !github.event.pull_request.head.repo.fork }}
with:
registry: ghcr.io

View File

@@ -35,7 +35,7 @@ jobs:
needs: [get_body, should_run]
if: ${{ needs.should_run.outputs.should_run == 'true' }}
container:
image: ghcr.io/immich-app/mdq:main@sha256:df7188ba88abb0800d73cc97d3633280f0c0c3d4c441d678225067bf154150fb
image: ghcr.io/immich-app/mdq:main@sha256:557cca601891b8b7d78b940071d35aaf7aaeb9b327d19b22cf282118edbc5272
outputs:
checked: ${{ steps.get_checkbox.outputs.checked }}
steps:

View File

@@ -57,7 +57,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -70,7 +70,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -83,6 +83,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
category: '/language:${{matrix.language}}'

View File

@@ -60,7 +60,7 @@ jobs:
suffix: ['', '-cuda', '-rocm', '-openvino', '-armnn', '-rknn']
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -90,7 +90,7 @@ jobs:
suffix: ['']
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}

View File

@@ -19,7 +19,7 @@ jobs:
app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}
- uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5 # v3.9.0
- uses: mshick/add-pr-comment@64b8e914979889d746c99dea15a76e77ef64580a # v3.10.0
with:
github-token: ${{ steps.token.outputs.token }}
message-id: 'preview-status'
@@ -48,14 +48,14 @@ jobs:
name: 'preview'
})
- uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5 # v3.9.0
- uses: mshick/add-pr-comment@64b8e914979889d746c99dea15a76e77ef64580a # v3.10.0
if: ${{ github.event.pull_request.head.repo.fork }}
with:
github-token: ${{ steps.token.outputs.token }}
message-id: 'preview-status'
message: 'PRs from forks cannot have preview environments.'
- uses: mshick/add-pr-comment@ffd016c7e151d97d69d21a843022fd4cd5b96fe5 # v3.9.0
- uses: mshick/add-pr-comment@64b8e914979889d746c99dea15a76e77ef64580a # v3.10.0
if: ${{ !github.event.pull_request.head.repo.fork }}
with:
github-token: ${{ steps.token.outputs.token }}

2
.gitignore vendored
View File

@@ -28,3 +28,5 @@ vite.config.js.timestamp-*
.pnpm-store
.devcontainer/library
.devcontainer/.env*
*.tsbuildinfo
*.tsbuildInfo

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.7.0",
"version": "2.7.5",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",
@@ -28,13 +28,13 @@
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^63.0.0",
"eslint-plugin-unicorn": "^64.0.0",
"globals": "^17.0.0",
"mock-fs": "^5.2.0",
"prettier": "^3.7.4",
"prettier-plugin-organize-imports": "^4.0.0",
"typescript": "^5.3.3",
"typescript-eslint": "^8.28.0",
"typescript": "^6.0.0",
"typescript-eslint": "^8.58.0",
"vite": "^8.0.0",
"vitest": "^4.0.0",
"vitest-fetch-mock": "^0.4.0",

View File

@@ -4,7 +4,7 @@ import path from 'node:path';
import { setTimeout as sleep } from 'node:timers/promises';
import { describe, expect, it, MockedFunction, vi } from 'vitest';
import { Action, checkBulkUpload, defaults, getSupportedMediaTypes, Reason } from '@immich/sdk';
import { AssetRejectReason, AssetUploadAction, checkBulkUpload, defaults, getSupportedMediaTypes } from '@immich/sdk';
import createFetchMock from 'vitest-fetch-mock';
import {
@@ -120,7 +120,7 @@ describe('checkForDuplicates', () => {
vi.mocked(checkBulkUpload).mockResolvedValue({
results: [
{
action: Action.Accept,
action: AssetUploadAction.Accept,
id: testFilePath,
},
],
@@ -144,10 +144,10 @@ describe('checkForDuplicates', () => {
vi.mocked(checkBulkUpload).mockResolvedValue({
results: [
{
action: Action.Reject,
action: AssetUploadAction.Reject,
id: testFilePath,
assetId: 'fc5621b1-86f6-44a1-9905-403e607df9f5',
reason: Reason.Duplicate,
reason: AssetRejectReason.Duplicate,
},
],
});
@@ -167,7 +167,7 @@ describe('checkForDuplicates', () => {
vi.mocked(checkBulkUpload).mockResolvedValue({
results: [
{
action: Action.Accept,
action: AssetUploadAction.Accept,
id: testFilePath,
},
],
@@ -187,7 +187,7 @@ describe('checkForDuplicates', () => {
mocked.mockResolvedValue({
results: [
{
action: Action.Accept,
action: AssetUploadAction.Accept,
id: testFilePath,
},
],

View File

@@ -1,9 +1,9 @@
import {
Action,
AssetBulkUploadCheckItem,
AssetBulkUploadCheckResult,
AssetMediaResponseDto,
AssetMediaStatus,
AssetUploadAction,
Permission,
addAssetsToAlbum,
checkBulkUpload,
@@ -234,7 +234,7 @@ export const checkForDuplicates = async (files: string[], { concurrency, skipHas
const results = response.results as AssetBulkUploadCheckResults;
for (const { id: filepath, assetId, action } of results) {
if (action === Action.Accept) {
if (action === AssetUploadAction.Accept) {
newFiles.push(filepath);
} else {
// rejects are always duplicates

View File

@@ -15,8 +15,12 @@
"incremental": true,
"skipLibCheck": true,
"esModuleInterop": true,
"baseUrl": "./",
"rootDir": "./src",
"paths": {
"src/*": ["./src/*"],
},
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo",
"types": ["vitest/globals"]
},
"exclude": ["dist", "node_modules"]
"exclude": ["dist", "node_modules", "vite.config.ts"]
}

View File

@@ -26,7 +26,7 @@ You can search the following types of content:
| Time frame | Start and end date of a specific time bucket |
| Media type | Image or video or both |
| Display options | In Archive, in Favorites or Not in any album |
| Start rating | User-assigned start rating |
| Star rating | User-assigned star rating |
<img src={require('./img/advanced-search-filters.webp').default} width="70%" title='Advanced search filters' />

View File

@@ -49,7 +49,7 @@ Immich requires [**Docker**](https://docs.docker.com/get-started/get-docker/) wi
The Compose plugin will be installed by both Docker Engine and Desktop by following the linked installation guides; it can also be [separately installed](https://docs.docker.com/compose/install/).
:::note
Immich requires the command `docker compose`; the similarly named `docker-compose` is [deprecated](https://docs.docker.com/compose/migrate/) and is no longer supported by Immich.
Immich requires the command `docker compose`; the similarly named `docker-compose` is [deprecated](https://docs.docker.com/retired/#docker-compose-v1-replaced-by-compose-v2) and is no longer supported by Immich.
:::
### Special requirements for Windows users

View File

@@ -6,6 +6,8 @@ You can read more about the differences between storage template engine on and o
The admin user can set the template by using the template builder in the `Administration -> Settings -> Storage Template`. Immich provides a set of variables that you can use in constructing the template, along with additional custom text. If the template produces [multiple files with the same filename, they won't be overwritten](https://github.com/immich-app/immich/discussions/3324) as a sequence number is appended to the filename.
Date and time variables in storage templates are rendered in the server's local timezone.
```bash title="Default template"
Year/Year-Month-Day/Filename.Extension
```

View File

@@ -37,10 +37,10 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "~3.9.0",
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/tsconfig": "^3.10.0",
"@docusaurus/types": "^3.7.0",
"prettier": "^3.7.4",
"typescript": "^5.1.6"
"typescript": "^6.0.0"
},
"browserslist": {
"production": [

View File

@@ -1,7 +1,7 @@
[
{
"label": "v2.7.0",
"url": "https://docs.v2.7.0.archive.immich.app"
"label": "v2.7.5",
"url": "https://docs.v2.7.5.archive.immich.app"
},
{
"label": "v2.6.3",

View File

@@ -1,8 +1,4 @@
{
// This file is not used in compilation. It is here just for a nice editor experience.
"extends": "@docusaurus/tsconfig",
"compilerOptions": {
"baseUrl": "."
}
"extends": "@docusaurus/tsconfig"
}

View File

@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "2.7.0",
"version": "2.7.5",
"description": "",
"main": "index.js",
"type": "module",
@@ -40,7 +40,7 @@
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^63.0.0",
"eslint-plugin-unicorn": "^64.0.0",
"exiftool-vendored": "^35.0.0",
"globals": "^17.0.0",
"luxon": "^3.4.4",
@@ -51,7 +51,7 @@
"sharp": "^0.34.5",
"socket.io-client": "^4.7.4",
"supertest": "^7.0.0",
"typescript": "^5.3.3",
"typescript": "^6.0.0",
"typescript-eslint": "^8.28.0",
"utimes": "^5.2.1",
"vite-tsconfig-paths": "^6.1.1",

View File

@@ -1,7 +1,6 @@
import {
AssetMediaResponseDto,
AssetMediaStatus,
AssetResponseDto,
AssetTypeEnum,
AssetVisibility,
getAssetInfo,
@@ -19,7 +18,7 @@ import { Socket } from 'socket.io-client';
import { createUserDto, uuidDto } from 'src/fixtures';
import { makeRandomImage } from 'src/generators';
import { errorDto } from 'src/responses';
import { app, asBearerAuth, tempDir, TEN_TIMES, testAssetDir, utils } from 'src/utils';
import { app, asBearerAuth, tempDir, testAssetDir, utils } from 'src/utils';
import request from 'supertest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
@@ -95,8 +94,8 @@ describe('/asset', () => {
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken, {
isFavorite: true,
fileCreatedAt: yesterday.toISO(),
fileModifiedAt: yesterday.toISO(),
fileCreatedAt: yesterday.toUTC().toISO(),
fileModifiedAt: yesterday.toUTC().toISO(),
assetData: { filename: 'example.mp4' },
}),
utils.createAsset(user1.accessToken),
@@ -380,62 +379,12 @@ describe('/asset', () => {
});
});
describe('GET /assets/random', () => {
beforeAll(async () => {
await Promise.all([
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken),
utils.createAsset(user1.accessToken),
]);
await utils.waitForQueueFinish(admin.accessToken, 'thumbnailGeneration');
});
it.each(TEN_TIMES)('should return 1 random assets', async () => {
const { status, body } = await request(app)
.get('/assets/random')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
const assets: AssetResponseDto[] = body;
expect(assets.length).toBe(1);
expect(assets[0].ownerId).toBe(user1.userId);
});
it.each(TEN_TIMES)('should return 2 random assets', async () => {
const { status, body } = await request(app)
.get('/assets/random?count=2')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
const assets: AssetResponseDto[] = body;
expect(assets.length).toBe(2);
for (const asset of assets) {
expect(asset.ownerId).toBe(user1.userId);
}
});
it.skip('should return 1 asset if there are 10 assets in the database but user 2 only has 1', async () => {
const { status, body } = await request(app)
.get('/assets/random')
.set('Authorization', `Bearer ${user2.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual([expect.objectContaining({ id: user2Assets[0].id })]);
});
});
describe('PUT /assets/:id', () => {
it('should require access', async () => {
const { status, body } = await request(app)
.put(`/assets/${user2Assets[0].id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({});
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});

View File

@@ -110,7 +110,7 @@ describe('/libraries', () => {
});
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(["All importPaths's elements must be unique"]));
expect(body).toEqual(errorDto.badRequest(['[importPaths] Array must have unique items']));
});
it('should not create an external library with duplicate exclusion patterns', async () => {
@@ -125,7 +125,7 @@ describe('/libraries', () => {
});
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(["All exclusionPatterns's elements must be unique"]));
expect(body).toEqual(errorDto.badRequest(['[exclusionPatterns] Array must have unique items']));
});
});
@@ -157,7 +157,7 @@ describe('/libraries', () => {
.send({ name: '' });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['name should not be empty']));
expect(body).toEqual(errorDto.badRequest(['[name] Too small: expected string to have >=1 characters']));
});
it('should change the import paths', async () => {
@@ -181,7 +181,7 @@ describe('/libraries', () => {
.send({ importPaths: [''] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['each value in importPaths should not be empty']));
expect(body).toEqual(errorDto.badRequest(['[importPaths] Array items must not be empty']));
});
it('should reject duplicate import paths', async () => {
@@ -191,7 +191,7 @@ describe('/libraries', () => {
.send({ importPaths: ['/path', '/path'] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(["All importPaths's elements must be unique"]));
expect(body).toEqual(errorDto.badRequest(['[importPaths] Array must have unique items']));
});
it('should change the exclusion pattern', async () => {
@@ -215,7 +215,7 @@ describe('/libraries', () => {
.send({ exclusionPatterns: ['**/*.jpg', '**/*.jpg'] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(["All exclusionPatterns's elements must be unique"]));
expect(body).toEqual(errorDto.badRequest(['[exclusionPatterns] Array must have unique items']));
});
it('should reject an empty exclusion pattern', async () => {
@@ -225,7 +225,7 @@ describe('/libraries', () => {
.send({ exclusionPatterns: [''] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['each value in exclusionPatterns should not be empty']));
expect(body).toEqual(errorDto.badRequest(['[exclusionPatterns] Array items must not be empty']));
});
});

View File

@@ -109,7 +109,7 @@ describe('/map', () => {
.get('/map/reverse-geocode?lon=123')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lat must be a number between -90 and 90']));
expect(body).toEqual(errorDto.badRequest(['[lat] Invalid input: expected number, received NaN']));
});
it('should throw an error if a lat is not a number', async () => {
@@ -117,7 +117,7 @@ describe('/map', () => {
.get('/map/reverse-geocode?lat=abc&lon=123.456')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lat must be a number between -90 and 90']));
expect(body).toEqual(errorDto.badRequest(['[lat] Invalid input: expected number, received NaN']));
});
it('should throw an error if a lat is out of range', async () => {
@@ -125,7 +125,7 @@ describe('/map', () => {
.get('/map/reverse-geocode?lat=91&lon=123.456')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lat must be a number between -90 and 90']));
expect(body).toEqual(errorDto.badRequest(['[lat] Too big: expected number to be <=90']));
});
it('should throw an error if a lon is not provided', async () => {
@@ -133,7 +133,7 @@ describe('/map', () => {
.get('/map/reverse-geocode?lat=75')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['lon must be a number between -180 and 180']));
expect(body).toEqual(errorDto.badRequest(['[lon] Invalid input: expected number, received NaN']));
});
const reverseGeocodeTestCases = [

View File

@@ -101,7 +101,7 @@ describe(`/oauth`, () => {
it(`should throw an error if a redirect uri is not provided`, async () => {
const { status, body } = await request(app).post('/oauth/authorize').send({});
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['redirectUri must be a string', 'redirectUri should not be empty']));
expect(body).toEqual(errorDto.badRequest(['[redirectUri] Invalid input: expected string, received undefined']));
});
it('should return a redirect uri', async () => {
@@ -123,13 +123,13 @@ describe(`/oauth`, () => {
it(`should throw an error if a url is not provided`, async () => {
const { status, body } = await request(app).post('/oauth/callback').send({});
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['url must be a string', 'url should not be empty']));
expect(body).toEqual(errorDto.badRequest(['[url] Invalid input: expected string, received undefined']));
});
it(`should throw an error if the url is empty`, async () => {
const { status, body } = await request(app).post('/oauth/callback').send({ url: '' });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['url should not be empty']));
expect(body).toEqual(errorDto.badRequest(['[url] Too small: expected string to have >=1 characters']));
});
it(`should throw an error if the state is not provided`, async () => {

View File

@@ -243,9 +243,21 @@ describe('/shared-links', () => {
});
it('should get data for correct password protected link', async () => {
const response = await request(app)
.post('/shared-links/login')
.send({ password: 'foo' })
.query({ key: linkWithPassword.key });
expect(response.status).toBe(201);
const cookies = response.get('Set-Cookie') ?? [];
expect(cookies).toHaveLength(1);
expect(cookies[0]).toContain('immich_shared_link_token');
const { status, body } = await request(app)
.get('/shared-links/me')
.query({ key: linkWithPassword.key, password: 'foo' });
.query({ key: linkWithPassword.key })
.set('Cookie', cookies);
expect(status).toBe(200);
expect(body).toEqual(

View File

@@ -309,7 +309,7 @@ describe('/tags', () => {
.get(`/tags/${uuidDto.invalid}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
expect(body).toEqual(errorDto.badRequest(['[id] Invalid UUID']));
});
it('should get tag details', async () => {
@@ -427,7 +427,7 @@ describe('/tags', () => {
.delete(`/tags/${uuidDto.invalid}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
expect(body).toEqual(errorDto.badRequest(['[id] Invalid UUID']));
});
it('should delete a tag', async () => {

View File

@@ -287,7 +287,8 @@ describe('/admin/users', () => {
it('should delete user', async () => {
const { status, body } = await request(app)
.delete(`/admin/users/${userToDelete.userId}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({});
expect(status).toBe(200);
expect(body).toMatchObject({

View File

@@ -178,7 +178,9 @@ describe('/users', () => {
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['download.archiveSize must be an integer number']));
expect(body).toEqual(
errorDto.badRequest(['[download.archiveSize] Invalid input: expected int, received number']),
);
});
it('should update download archive size', async () => {
@@ -204,7 +206,9 @@ describe('/users', () => {
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['download.includeEmbeddedVideos must be a boolean value']));
expect(body).toEqual(
errorDto.badRequest(['[download.includeEmbeddedVideos] Invalid input: expected boolean, received number']),
);
});
it('should update download include embedded videos', async () => {

View File

@@ -77,18 +77,4 @@ test.describe('Photo Viewer', () => {
});
expect(tagAtCenter).toBe('IMG');
});
test('reloads photo when checksum changes', async ({ page }) => {
await page.goto(`/photos/${asset.id}`);
const preview = page.getByTestId('preview').filter({ visible: true });
await expect(preview).toHaveAttribute('src', /.+/);
const initialSrc = await preview.getAttribute('src');
const websocketEvent = utils.waitForWebsocketEvent({ event: 'assetUpdate', id: asset.id });
await utils.replaceAsset(admin.accessToken, asset.id);
await websocketEvent;
await expect(preview).not.toHaveAttribute('src', initialSrc!);
});
});

View File

@@ -1,5 +1,5 @@
import { BrowserContext } from '@playwright/test';
import { playwrightHost } from 'playwright.config';
import { playwrightHost } from 'src/../playwright.config';
export const setupBaseMockApiRoutes = async (context: BrowserContext, adminUserId: string) => {
await context.addCookies([

View File

@@ -69,7 +69,7 @@ export const createMockStackAsset = (ownerId: string): AssetResponseDto => {
tags: [],
people: [],
unassignedFaces: [],
stack: null,
stack: undefined,
isOffline: false,
hasMetadata: true,
duplicateId: null,

View File

@@ -375,40 +375,6 @@ export const utils = {
return body as AssetMediaResponseDto;
},
replaceAsset: async (
accessToken: string,
assetId: string,
dto?: Partial<Omit<AssetMediaCreateDto, 'assetData'>> & { assetData?: FileData },
) => {
const _dto = {
deviceAssetId: 'test-1',
deviceId: 'test',
fileCreatedAt: new Date().toISOString(),
fileModifiedAt: new Date().toISOString(),
...dto,
};
const assetData = dto?.assetData?.bytes || makeRandomImage();
const filename = dto?.assetData?.filename || 'example.png';
if (dto?.assetData?.bytes) {
console.log(`Uploading ${filename}`);
}
const builder = request(app)
.put(`/assets/${assetId}/original`)
.attach('assetData', assetData, filename)
.set('Authorization', `Bearer ${accessToken}`);
for (const [key, value] of Object.entries(_dto)) {
void builder.field(key, String(value));
}
const { body } = await builder;
return body as AssetMediaResponseDto;
},
createImageFile: (path: string) => {
if (!existsSync(dirname(path))) {
mkdirSync(dirname(path), { recursive: true });

View File

@@ -14,8 +14,10 @@
"outDir": "./dist",
"incremental": true,
"skipLibCheck": true,
"paths": {
"src/*": ["./src/*"]
},
"esModuleInterop": true,
"baseUrl": "./"
},
"include": ["src/**/*.ts", "vitest*.config.ts"],
"exclude": ["dist", "node_modules"]

View File

@@ -3,7 +3,7 @@
"account": "حساب",
"account_settings": "إعدادات الحساب",
"acknowledge": "أُدرك ذلك",
"action": "عملية",
"action": "إجراء",
"action_common_update": "تحديث",
"action_description": "مجموعة من الفعاليات التي ستنفذ على الأصول التي تم تصفيتها",
"actions": "عمليات",
@@ -61,8 +61,8 @@
"backup_onboarding_1_description": "نسخة خارج الموقع في موقع آخر.",
"backup_onboarding_2_description": "نسخ محلية على أجهزة مختلفة. يشمل ذلك الملفات الرئيسية ونسخة احتياطية محلية منها.",
"backup_onboarding_3_description": "إجمالي نُسخ بياناتك، بما في ذلك الملفات الأصلية. يشمل ذلك نسخةً واحدةً خارج الموقع ونسختين محليتين.",
"backup_onboarding_description": "يُنصح باتباع <backblaze-link>استراتيجية النسخ الاحتياطي 3-2-1</backblaze-link> لحماية بياناتك. احتفظ بنسخ احتياطية من صورك/فيديوهاتك المحمّلة، بالإضافة إلى قاعدة بيانات Immich، لضمان حل نسخ احتياطي شامل.",
"backup_onboarding_footer": "لمزيد من المعلومات حول النسخ الاحتياطي لـ Immich، يرجى الرجوع إلى <link> التعليمات </link>.",
"backup_onboarding_description": "يُنصح باتباع <backblaze-link>استراتيجية النسخ الاحتياطي 3-2- 1</backblaze-link> لحماية بياناتك. احتفظ بنسخ احتياطية من صورك/فيديوهاتك المحمّلة، بالإضافة إلى قاعدة بيانات Immich، لضمان حل نسخ احتياطي شامل.",
"backup_onboarding_footer": "لمزيد من المعلومات حول النسخ الاحتياطي لـ <link>Immich</link>، يرجى الرجوع إلى <link>الوثائق</link>.",
"backup_onboarding_parts_title": "يتضمن النسخ الاحتياطي 3-2-1 ما يلي:",
"backup_onboarding_title": "النسخ الاحتياطية",
"backup_settings": "إعدادات تفريغ قاعدة البيانات",
@@ -333,7 +333,7 @@
"storage_template_migration_description": "قم بتطبيق القالب الحالي <link>{template}</link> على المحتويات التي تم رفعها سابقًا",
"storage_template_migration_info": "تغييرات النموذج الخزني ستغير جميع الصيغ الى احرف صغيرة. تغييرات النموذج ستنطبق فقط على المحتويات الجديدة. لتطبيق النموذج على المحتويات التي تم رفعها سابقًا، قم بتشغيل <link>{job}</link>.",
"storage_template_migration_job": "وظيفة تهجير قالب التخزين",
"storage_template_more_details": "لمزيد من التفاصيل حول هذه الميزة، يرجى الرجوع إلى <template-link>Storage Template</template-link> و<implications-link>implications</implications-link>",
"storage_template_more_details": "لمزيد من التفاصيل حول هذه الميزة، يرجى الرجوع إلى <template-link>Storage Template</template-link> و <implications-link>implications</implications-link>.",
"storage_template_onboarding_description_v2": "عند التفعيل. هذه الخاصية ستقوم بالترتيب التلقائي للملفات بناء على نموذج معرف من قبل المستخدم. رجاء اطلع على <link>التوثيق</link>.",
"storage_template_path_length": "الحد التقريبي لطول المسار: <b>{length, number}</b>/{limit, number}",
"storage_template_settings": "قالب التخزين",
@@ -372,7 +372,7 @@
"transcoding_audio_codec": "كود الصوت",
"transcoding_audio_codec_description": "Opus هو الخيار ذو أعلى جودة، ولكنه يتمتع بتوافق أقل مع الأجهزة أو البرمجيات القديمة.",
"transcoding_bitrate_description": "مقاطع الفيديو التي يتجاوز معدل البت أقصى قيمة أو التي لا تكون في تنسيق مقبول",
"transcoding_codecs_learn_more": "لمعرفة المزيد حول المصطلحات المستخدمة هنا، يرجى الرجوع إلى وثائق FFmpeg لل<h264-link>H.264 codec</h264-link>, <hevc-link>HEVC codec</hevc-link> and <vp9-link>VP9 codec</vp9-link>.",
"transcoding_codecs_learn_more": "لمعرفة المزيد حول المصطلحات المستخدمة هنا، يرجى الرجوع إلى وثائق FFmpeg لـ <h264-link>H.264 codec</h264-link>، و <hevc-link>HEVC codec</hevc-link> و <vp9-link>VP9 codec</vp9-link>.",
"transcoding_constant_quality_mode": "وضع الجودة الثابتة",
"transcoding_constant_quality_mode_description": "ICQ أفضل من CQP، ولكن بعض أجهزة عتاد التسريع لا تدعم هذا الوضع. تعيين هذا الخيار يسجعل الأفضلية للوضع المحدد عند استخدام الترميز بناءً على الجودة. يتم تجاهله بواسطة NVENC لأنه لا يدعم ICQ.",
"transcoding_constant_rate_factor": "عامل معدل الجودة الثابت (-crf)",
@@ -2392,7 +2392,7 @@
"view_name": "عرض",
"view_next_asset": "عرض المحتوى التالي",
"view_previous_asset": "عرض المحتوى السابق",
"view_qr_code": "­عرض رمز الاستجابة السريعة",
"view_qr_code": "عرض رمز الاستجابة السريعة",
"view_similar_photos": "عرض صور مشابهة",
"view_stack": "عرض التكديس",
"view_user": "عرض المستخدم",
@@ -2411,14 +2411,14 @@
"welcome_to_immich": "مرحباً بك في Immich",
"width": "عُرض",
"wifi_name": "اسم شبكة Wi-Fi",
"workflow_delete_prompt": "هل أنت متأكد من حذف سير العمل هذا؟",
"workflow_delete_prompt": "متأكد من حذف سير العمل هذا؟",
"workflow_deleted": "تم حذف سير العمل",
"workflow_description": "وصف سير العمل",
"workflow_info": "معلومات سير العمل",
"workflow_json": "ملف JSON لسير العمل",
"workflow_json_help": "قم بتعديل إعدادات سير العمل بصيغة JSON. ستتم مزامنة التغييرات مع أداة الإنشاء المرئية.",
"workflow_name": "اسم سير العمل",
"workflow_navigation_prompt": "هل انت متاكد من المغادرة بدون حفظ التغييرات؟",
"workflow_navigation_prompt": "متاكد من المغادرة بدون حفظ التغييرات؟",
"workflow_summary": "ملخص سير العمل",
"workflow_update_success": "تم تحديث سير العمل بنجاح",
"workflow_updated": "تم تحديث سير العمل",

View File

@@ -849,9 +849,12 @@
"create_link_to_share": "Opret link for at dele",
"create_link_to_share_description": "Tillad alle med linket at se de(t) valgte billede(r)",
"create_new": "OPRET NY",
"create_new_face": "Opret nyt ansigt",
"create_new_person": "Opret ny person",
"create_new_person_hint": "Tildel valgte aktiver til en ny person",
"create_new_user": "Opret ny bruger",
"create_person": "Opret person",
"create_person_subtitle": "Tilføj et navn til det valgte ansigt for at oprette og tagge den nye person",
"create_shared_album_page_share_add_assets": "TILFØJ ELEMENT",
"create_shared_album_page_share_select_photos": "Vælg Billeder",
"create_shared_link": "Opret delt link",
@@ -892,6 +895,7 @@
"day": "Dag",
"days": "Dage",
"deduplicate_all": "Dedubliker alle",
"default_locale": "Standard sprog",
"default_locale_description": "Formatér datoer og tal baseret på din browsers landestandard",
"delete": "Slet",
"delete_action_confirmation_message": "Er du sikker på, at du vil slette dette objekt? Denne handling vil flytte objektet til serverens papirkurv, og vil spørge dig, om du vil slette den lokalt",
@@ -2213,6 +2217,7 @@
"tag": "Tag",
"tag_assets": "Tag mediefiler",
"tag_created": "Oprettet tag: {tag}",
"tag_face": "Tag ansigt",
"tag_feature_description": "Gennemse billeder og videoer grupperet efter logiske tag-emner",
"tag_not_found_question": "Kan du ikke finde et tag? <link>Opret et nyt tag.</link>",
"tag_people": "Tag personer",

View File

@@ -1,132 +1,132 @@
{
"about": "Über",
"account": "Konto",
"account_settings": "Konto Istelligä",
"acknowledge": "Bestätige",
"account_settings": "Konto Einstellungen",
"acknowledge": "Bestätigä",
"action": "Aktion",
"action_common_update": "Update",
"action_description": "Es paar Aktione, wo a de gfilterete Assets usgführt wärde sölled",
"actions": "Aktione",
"action_description": "Aktionä, wo uf de gefilterti Mediä ausgführt werdä solled",
"actions": "Aktionen",
"active": "Aktiv",
"active_count": "Aktivi: {count}",
"active_count": "Aktiv: {count}",
"activity": "Aktivität",
"activity_changed": "Aktivität isch {enabled, select, true {aktiviert} other {deaktiviert}}",
"add": "Hinzuefüe",
"add_a_description": "Beschriibig hinzueege",
"add_a_location": "Standort hinzuefüege",
"add_a_name": "Name hinzuefüege",
"add_a_title": "Titel hinzuefüege",
"add_action": "Aktion hinzuefüege",
"add_action_description": "Aklicke um en Aktion dure zfüehre",
"add_assets": "Assets hinzufüege",
"add_birthday": "Geburtstag hinzuefüege",
"activity_changed": "Aktivität ist {enabled, select, true {aktiviert} other {deaktiviert}}",
"add": "Hinzuefüge",
"add_a_description": "Beschreibung hinzufügen",
"add_a_location": "Standort hinzuefü",
"add_a_name": "Namä hinzefü",
"add_a_title": "Titel hinzufeügä",
"add_action": "Aktion hinzuefü",
"add_action_description": "Klick do zum e Aktion hinzuefüge",
"add_assets": "Mediä hinzuefüge",
"add_birthday": "Geburtstag hinzuefüge",
"add_endpoint": "Endpunkt hinzuefüge",
"add_exclusion_pattern": "Uuschlussmuster hinzueege",
"add_filter": "Filter hinzuefüge",
"add_filter_description": "Klicke, um e Filterbedingig hinzuezfüege",
"add_location": "Standort hinzueege",
"add_more_users": "Meh Benutzer hinzueege",
"add_partner": "Partner hinzueege",
"add_path": "Pfad hinzueege",
"add_photos": "Föteli hinzueege",
"add_tag": "Tag hinzueege",
"add_to": "Hinzueege zu …",
"add_to_album": "Zum Album hinzueege",
"add_to_album_bottom_sheet_added": "Zu {album} hinzuegfüegt",
"add_to_album_bottom_sheet_already_exists": "Scho in {album}",
"add_to_album_bottom_sheet_some_local_assets": "Es hend es paar lokali Dateie nöd chöne im Album hinzuegfüegt werde",
"add_to_album_toggle": "Uuswahl umschalte für {album}",
"add_to_albums": "Zu Albe hinzueege",
"add_to_albums_count": "Zu Albe hinzueege ({count})",
"add_to_bottom_bar": "Hinzueege zu",
"add_to_shared_album": "Zum teilte Album hinzueege",
"add_upload_to_stack": "Upload zum Stack hinzueege",
"add_url": "URL hinzueege",
"add_workflow_step": "Workflow-Schritt hinzueege",
"added_to_archive": "Is Archiv verschobe",
"added_to_favorites": "Zu dine Favoritä hinzuegfüegt",
"added_to_favorites_count": "{count, number} zu Favorite hinzuegfüegt",
"add_exclusion_pattern": "Ausschlussmuster hinzufügen",
"add_filter": "Filter hinzufügen",
"add_filter_description": "Klicke hier um eine Filterbedingung hinzuzufügen",
"add_location": "Standort hinzufügen",
"add_more_users": "Mehr Benutzer hinzufügen",
"add_partner": "Partner hinzufügen",
"add_path": "Pfad hinzufügen",
"add_photos": "Fotos hinzufügen",
"add_tag": "Tag hinzufügen",
"add_to": "Hinzufügen zu…",
"add_to_album": "Zu Album hinzufügen",
"add_to_album_bottom_sheet_added": "Zu {album} hinzugefügt",
"add_to_album_bottom_sheet_already_exists": "Bereits in {album}",
"add_to_album_bottom_sheet_some_local_assets": "Einige lokale Dateien konnten nicht zum Album hinzugefügt werden",
"add_to_album_toggle": "Auswahl umschalten für {album}",
"add_to_albums": "Zu Alben hinzufügen",
"add_to_albums_count": "Zu Alben hinzufügen ({count})",
"add_to_bottom_bar": "Hinzufügen zu",
"add_to_shared_album": "Zu geteiltem Album hinzufügen",
"add_upload_to_stack": "Upload zum Stapel hinzufügen",
"add_url": "URL hinzufügen",
"add_workflow_step": "Workflow-Schritt hinzufügen",
"added_to_archive": "Zum Archiv hinzugefügt",
"added_to_favorites": "Zu Favoriten hinzugefügt",
"added_to_favorites_count": "{count, number} zu Favoriten hinzugefügt",
"admin": {
"add_exclusion_pattern_description": "Uusschlussmuster hinzuefüge. Platzhalter, wie *, **, und ? wärded understützt. Zum all Dateie i eim Verzeichnis namens „Raw\" ignoriere, „**/Raw/**“ verwände. Zum all Dateien ignorieren, wo uf „.tif“ änded, „**/*.tif“ verwände. Zum en absolute Pfad ignoriere, „/pfad/zum/ignoriere/**“ verwände.",
"admin_user": "Admin Benutzer",
"asset_offline_description": "Die Datei vonere externe Bibliothek isch nümme uf de Festplatte und isch in Papierchorb verschobe worde. Falls die Datei innerhalb vo de Bibliothek verschoben worde isch, überprüf dini Ziitleiste uf die neui entsprechendi Datei. Zum die Datei wiederherstelle, stell bitte sicher, dass Immich uf de unde stehendi Dateipfad chan zuegriife und scann d'Bibliothek.",
"authentication_settings": "Authentifizierigs Iistellige",
"authentication_settings_description": "Passwort, OAuth und anderi Authentifizierigseinstellige verwalte",
"authentication_settings_disable_all": "Bisch sicher, dass du alli Login-Methodä wotsch deaktivierä? S Login isch denn komplett deaktiviert.",
"authentication_settings_reenable": "Bruuch ein <link>Server-Befehl</link> zum reaktiviere.",
"background_task_job": "Hintergrund Ufgabä",
"backup_database": "Datenbank-Dump aalege",
"backup_database_enable_description": "Datenbank-Dumps aktiviere",
"backup_keep_last_amount": "Aazahl vo de vorherige Dumps, wo bhalte werde sölle",
"backup_onboarding_1_description": "Offsite-Kopie i dä Cloud oder amene andere physische Standort.",
"backup_onboarding_2_description": "Lokali Kopie uf verschiedene Grät. Das beinhaltet d Hauptdateie und e lokali Sicherig vo dene Dateie.",
"backup_onboarding_3_description": "Total aazahl vo dine Dateikopie, inklusiv d Originaldateie. Das beinhaltet 1 Offsite-Kopie und 2 lokali Kopie.",
"backup_onboarding_description": "E <backblaze-link>3-2-1-Backup-Strategie</backblaze-link> wird empfohle, zum dini Dateie z schütze. Du söttsch sowohl Kopie vo dine ufgeladene Fotos/Videos wie au d Immich-Datenbank bhalte, für e rundum sauberi Backup-Lösig.",
"backup_onboarding_footer": "Für meh Infos zum Backup vo Immich lueg bitte i d <link>Dokumentation</link>.",
"backup_onboarding_parts_title": "Es 3-2-1-Backup beinhaltet:",
"add_exclusion_pattern_description": "Ausschlussmuster hinzufügen. Platzhalter, wie *, **, und ? werden unterstützt. Um alle Dateien in einem Verzeichnis namens „Raw“ zu ignorieren, „**/Raw/**“ verwenden. Um alle Dateien zu ignorieren, die auf „.tif“ enden, „**/*.tif“ verwenden. Um einen absoluten Pfad zu ignorieren, „/pfad/zum/ignorieren/**“ verwenden.",
"admin_user": "Administrator",
"asset_offline_description": "Diese Datei einer externen Bibliothek befindet sich nicht mehr auf der Festplatte und wurde in den Papierkorb verschoben. Falls die Datei innerhalb der Bibliothek verschoben wurde, überprüfe deine Zeitleiste auf die neue entsprechende Datei. Um diese Datei wiederherzustellen, stelle bitte sicher, dass Immich auf den unten stehenden Dateipfad zugreifen kann und scanne die Bibliothek.",
"authentication_settings": "Authentifizierungseinstellungen",
"authentication_settings_description": "Passwort-, OAuth- und andere Authentifizierungseinstellungen verwalten",
"authentication_settings_disable_all": "Bist du sicher, dass du alle Loginmethoden deaktivieren willst? Die Anmeldung wird vollständig deaktiviert.",
"authentication_settings_reenable": "Nutze einen <link>Server-Befehl</link> zur Reaktivierung.",
"background_task_job": "Hintergrundaufgaben",
"backup_database": "Datenbanksicherung erstellen",
"backup_database_enable_description": "Datenbank regelmässig sichern",
"backup_keep_last_amount": "Anzahl der aufzubewahrenden früheren Sicherungen",
"backup_onboarding_1_description": "Offsite-Kopie in der Cloud oder an einem anderen physischen Ort.",
"backup_onboarding_2_description": "lokale Kopien auf verschiedenen Geräten. Dazu gehören die Hauptdateien und eine lokale Sicherung dieser Dateien.",
"backup_onboarding_3_description": "Kopien deiner Daten inklusive Originaldateien. Dies umfasst 1 Kopie an einem anderen Ort und 2 lokale Kopien.",
"backup_onboarding_description": "Eine <backblaze-link>3-2-1 Sicherungsstrategie</backblaze-link> wird empfohlen, um deine Daten zu schützen. Du solltest sowohl Kopien deiner hochgeladenen Fotos/Videos als auch der Immich-Datenbank aufbewahren, um eine umfassende Sicherungslösung zu haben.",
"backup_onboarding_footer": "Weitere Informationen zum Sichern von Immich findest du in der <link>Dokumentation</link>.",
"backup_onboarding_parts_title": "Eine 3-2-1-Sicherung umfasst:",
"backup_onboarding_title": "Backups",
"backup_settings": "Iistellige für Datenbank-Dumps",
"backup_settings_description": "Datenbank-Dump-Iistellige verwalte.",
"cleared_jobs": "Jobs glöscht für: {job}",
"config_set_by_file": "D Konfiguration isch aktuell dur e Konfigurationsdatei gsetzt",
"confirm_delete_library": "Bisch sicher, dass du d Bibliothek {library} wotsch lösche?",
"confirm_delete_library_assets": "Bisch sicher, dass du die Bibliothek wotsch lösche? Das löscht {count, plural, one {# enthaltenes Asset} other {alli # enthaltene Assets}} us Immich und chan nöd rückgängig gmacht werde. D Dateie bliibed uf em Dateträger.",
"confirm_email_below": "Zum bestätige bitte \"{email}\" une iitippe",
"confirm_reprocess_all_faces": "Bisch sicher, dass du alli Gsichter neu verarbeite wotsch? Däbii werde au benannti Persone glöscht.",
"confirm_user_password_reset": "Bisch sicher, dass du s Passwort für {user} möchtisch zruggsetze?",
"confirm_user_pin_code_reset": "Bisch sicher, dass du de PIN-Code vo {user} möchtisch zruggsetze?",
"copy_config_to_clipboard_description": "Kopier die aktuelli Systemkonfiguration als JSON-Objekt i d'Zwüschenablage",
"create_job": "Uufgabe erstelle",
"cron_expression": "Cron-Ziitagabe",
"cron_expression_description": "Setz s Scanintervall im Cron-Format. Hilf mit däm Format bütet z. B. der <link>Crontab Guru</link>",
"cron_expression_presets": "Vorlage für Cron-Uusdruck",
"disable_login": "Login deaktiviere",
"duplicate_detection_job_description": "Die Uufgab füehrt s maschinelle Lärne für jedi Datei us, zum Duplikat finde. Die Uufgabe berueht uf de intelligente Suechi",
"exclusion_pattern_description": "Mit Uusschlussmuster chönnd Dateie und Ordner bim Scanne vo dinere Bibliothek ignoriert wärde. Das isch nützlich, wenn du Ordner häsch, wo Dateien drin händ, wo d nöd wotsch importiere, wie z. B. RAW-Dateie.",
"export_config_as_json_description": "Lad die aktuelli Systemkonfiguration als JSON-Datei abe",
"external_libraries_page_description": "Externi Bibliothekssiite für Administratore",
"face_detection": "Gsichtserkennig",
"face_detection_description": "Die Uufgab erfasst Gsichter in Dateien dur maschinells Lerne. Bi Video wird nur d'Miniaturasicht brucht. „Aktualisiere“ verarbeitet all Dateie neu. „Zruggsetze“ setzt au no all Gsichter zrugg. „Fehlendistellt nur nöd verarbeiteti Dateie in d'Warteschlange. Erfassti Gsichter wärdet zur Gsichtsidentifizierig in diWarteschlange gstellt, damit sie i bestehendi oder neui Persone z'gruppiere.",
"facial_recognition_job_description": "Die Uufgabe gruppiert im Anschluss an d'Gsichtserfassig die erfasste Gsichter zu Persone. „Zruggsetze“ gruppiert alli Gsichter neu und mit „Fehlendi“ werdet Gsichter ohni Zuordnig i d'Warteschlange gstellt.",
"failed_job_command": "Befehl {command} t für d'Uufgabe {job} nöd funktioniert",
"force_delete_user_warning": "WARNIG: Die Aktion löscht Benutzer und all sini Dateie. Das chann nöd rückgängig gmacht wärde und d'Dateie chönnd nöd wiederhergstellt wärde.",
"backup_settings": "Einstellungen für Datenbanksicherung",
"backup_settings_description": "Einstellungen zur regelmässigen Sicherung der Datenbank.",
"cleared_jobs": "Folgende Aufgaben zurückgesetzt: {job}",
"config_set_by_file": "Die Konfiguration ist aktuell durch eine Konfigurationsdatei gsetzt",
"confirm_delete_library": "Bist du sicher, dass du die Bibliothek {library} löschen willst?",
"confirm_delete_library_assets": "Bist du sicher, dass du diese Bibliothek löschen willst? Dies löscht {count, plural, one {# enthaltene Datei} other {alle # enthaltenen Dateien}} aus Immich und kann nicht rückgängig gemacht werden. Die Dateien bleiben auf der Festplatte erhalten.",
"confirm_email_below": "Zum Bestätigen, tippe unten \"{email}\" ein",
"confirm_reprocess_all_faces": "Bist du sicher, dass du alle Gesichter erneut verarbeiten möchtest? Dies löscht auch alle bereits benannten Personen.",
"confirm_user_password_reset": "Bist du sicher, dass du das Passwort für {user} zurücksetzen möchtest?",
"confirm_user_pin_code_reset": "Bist du sicher, dass du den PIN-Code von {user} zurücksetzen möchtest?",
"copy_config_to_clipboard_description": "Aktuelle Systemkonfiguration als JSON-Objekt in die Zwischenablage kopieren",
"create_job": "Aufgabe erstellen",
"cron_expression": "Cron-Ausdruck",
"cron_expression_description": "Setze das Scanintervall im Cron-Format. Für mehr Informationen, siehe z. B. <link>Crontab Guru</link>",
"cron_expression_presets": "Vorlagen für Cron-Ausdrücke",
"disable_login": "Login deaktivieren",
"duplicate_detection_job_description": "Verwendet maschinelles Lernen auf den Dateien, um Duplikate zu finden. Baut auf der intelligenten Suche auf",
"exclusion_pattern_description": "Mit Ausschlussmustern können Dateien und Ordner beim Scannen deiner Bibliothek ignoriert werden. Dies ist nützlich, wenn du Ordner hast, die Dateien enthalten, die du nicht importieren möchtest, wie z. B. RAW-Dateien.",
"export_config_as_json_description": "Aktuelle Systemkonfiguration als JSON-Datei herunterladen",
"external_libraries_page_description": "Externe Bibliotheksseite für Administratoren",
"face_detection": "Gesichtserkennung",
"face_detection_description": "Diese Aufgabe erkennt mit maschinellem Lernen Gesichter in Dateien. Bei Videos wird nur das Vorschaubild verwendet. „Aktualisieren“ verarbeitet alle Dateien neu. „Zurücksetzen“ setzt zusätzlich alle Gesichter zurück. „Fehlendefügt nur nicht verarbeitete Dateien in die Warteschlange ein. Erfasste Gesichter werden zur Gesichtsidentifizierung in die Warteschlange eingefügt, um sie in bestehende oder neue Personen zu gruppieren.",
"facial_recognition_job_description": "Diese Aufgabe gruppiert im Anschluss an die Gesichtserkennung die erkannten Gesichter zu Personen. „Zurücksetzen“ gruppiert alle Gesichter neu, während „Fehlende“ Gesichter ohne Zuordnung in die Warteschlange stellt.",
"failed_job_command": "Befehl {command} ist für Aufgabe {job} fehlgeschlagen",
"force_delete_user_warning": "WARNUNG: Diese Aktion löscht sofort den Benutzer und all seine Dateien. Dies kann nicht rückgängig gemacht werden und die Dateien können nicht wiederhergestellt werden.",
"image_format": "Format",
"image_format_description": "WebP erzeugt chlineri Dateie we JPEG, isch aber es bitz langsamer i de Erstellig.",
"image_fullsize_description": "Hochuflösends Bild mit glöschte Metadate, wo bim Zoome brucht wird",
"image_fullsize_enabled": "Hochuflösendi Vorschaubilder aktiviere",
"image_fullsize_enabled_description": "Generiere hochauflösende Vorschaubilder in Originalauflösung für nicht web-kompatibel Formate. Wenn \"Eingebettete Vorschau bevorzugen\" aktiviert ist, werden eingebettete Vorschaubilder direkt verwendet. Hat keinen Einfluss auf web-kompatible Formate wie JPEG.",
"image_format_description": "WebP erzeugt kleinere Dateien als JPEG, ist aber etwas langsamer in der Erstellung.",
"image_fullsize_description": "Hochauflösendes Bild mit entfernten Metadaten, das beim Zoomen verwendet wird",
"image_fullsize_enabled": "Hochauflösende Vorschaubilder aktivieren",
"image_fullsize_enabled_description": "Generiere Vorschaubilder in Originalauflösung für nicht web-kompatible Formate. Wenn \"Eingebettete Vorschau bevorzugen\" aktiviert ist, werden eingebettete Vorschaubilder direkt verwendet. Hat keinen Einfluss auf web-kompatible Formate wie JPEG.",
"image_fullsize_quality_description": "Qualität der hochauflösenden Vorschaubilder von 1-100. Höher ist besser, erzeugt aber grössere Dateien.",
"image_fullsize_title": "Hochauflösende Vorschaueinstellungen",
"image_prefer_embedded_preview": "Eingebettete Vorschau bevorzugen",
"image_prefer_embedded_preview_setting_description": "Verwende eingebettete Vorschaubilder in RAW-Fotos als Grundlage für die Bildverarbeitung, sofern diese zur Verfügung stehen. Dies kann bei einigen Bildern genauere Farben erzeugen, allerdings ist die Qualität der Vorschau kameraabhängig und das Bild kann mehr Kompressionsartefakte aufweisen.",
"image_prefer_wide_gamut": "Breites Spektrum bevorzugen",
"image_prefer_wide_gamut_setting_description": "Bruuch Display P3 für Vorschaubildli. Das erhaltet d'Vitalität von Bildli mit grossem Farbruum besser. Uf alte Grät mit alte Browser chann das aber andersch uusgseh. sRGB-Bildli wärdet als sRGB bhalte zum Farbänderige vermiide.",
"image_preview_description": "Mittelgrossi Bildli ohni Metadate, bruuchts für Einzelaasichte und fürs maschinelle Lärne",
"image_preview_quality_description": "Vorschauqualität vo 1-100. Höcher isch besser, git aber grösseri Dateie und chan d'App Schwuppdizität reduziere. Z tüffi Wert chönnd s maschinelle Lärne beiträchtige.",
"image_preview_title": "Vorschauiistellige",
"image_prefer_wide_gamut_setting_description": "Display P3 (DCI-P3) für Vorschaubilder verwenden. Dadurch bleibt die Lebendigkeit von Bildern mit breiten Farbräumen besser erhalten, aber die Bilder können auf älteren Geräten mit einer älteren Browserversion etwas anders aussehen. sRGB-Bilder werden im sRGB-Format belassen, um Farbverschiebungen zu vermeiden.",
"image_preview_description": "Mittelgrosses Bild mit entfernten Metadaten, das bei der Betrachtung einer einzelnen Datei und für maschinelles Lernen verwendet wird",
"image_preview_quality_description": "Vorschauqualität von 1-100. Ein höherer Wert ist besser, erzeugt dadurch aber grössere Dateien und kann die Reaktionsfähigkeit der App beeinträchtigen. Ein niedriger Wert kann dafür aber die Qualität des maschinellen Lernens beeinträchtigen.",
"image_preview_title": "Vorschaueinstellungen",
"image_progressive": "Fortlaufend",
"image_progressive_description": "Codier fortlaufendi JPEG-Bildi: Sie wärdet bim Lade aufbauend aazeiget. Das hät kei Würkig uf WebP-Bildi.",
"image_progressive_description": "JPEG-Bilder schrittweise kodieren, um ein stufenweises Laden zu ermöglichen. Dies hat keine Auswirkungen auf WebP-Bilder.",
"image_quality": "Qualität",
"image_resolution": "Uuflösig",
"image_resolution_description": "Höcheri Uuflösig erhaltet meh Detail, gaht aber länger zum codiere, macht grösseri Dateie und chan d'App Schuppdizität reduziere.",
"image_settings": "Bild-Iistellige",
"image_settings_description": "Qualität und Uuflösig von erstellte Bildli verwalte",
"image_thumbnail_description": "Chlini Vorschaubildli ohni Metadate, bruuchts für Aasichte mit Gruppe vo Föteli wie i de Hauptziitachse",
"image_thumbnail_quality_description": "Vorschauqualität vo 1-100. Höcher isch besser, git aber grösseri Dateie und chan d'App Schwuppdizität reduziere.",
"image_thumbnail_title": "Iistellige für Vorschaubildli",
"import_config_from_json_description": "Systemkonfiguration importiere durs Ufelade vonere JSON-Datei",
"job_concurrency": "{job} Näbeläufigkeit",
"job_created": "Uufgab erstellt",
"job_not_concurrency_safe": "Die Uufgabe ist nöd für Paralleluusführig gmacht.",
"job_settings": "Uufgabe-Iistellige",
"job_settings_description": "Uufgabe-Näbeläufigkeit verwalte",
"jobs_over_time": "Uufgabe in ziitliche Verlauf",
"image_resolution": "Auflösung",
"image_resolution_description": "Höhere Auflösungen können mehr Details erhalten, benötigen aber mehr Zeit für die Kodierung, haben grössere Dateigrössen und können die Reaktionsfähigkeit der App beeinträchtigen.",
"image_settings": "Bildeinstellungen",
"image_settings_description": "Qualität und Auflösung der generierten Bilder verwalten",
"image_thumbnail_description": "Kleines Vorschaubild mit entfernten Metadaten, die bei der Anzeige von Sammlungen von Fotos wie der Zeitleiste verwendet wird",
"image_thumbnail_quality_description": "Qualität der Vorschaubilder von 1-100. Höher ist besser, erzeugt aber grössere Dateien und kann die Reaktionsfähigkeit der App beeinträchtigen.",
"image_thumbnail_title": "Einstellungen für Vorschaubilder",
"import_config_from_json_description": "Systemkonfiguration von hochgeladener JSON-Konfigurationsdatei importieren",
"job_concurrency": "{job} (Anzahl gleichzeitig laufende Prozesse)",
"job_created": "Aufgabe erstellt",
"job_not_concurrency_safe": "Diese Aufgabe kann nicht mehrmals parallel laufen gelassen werden.",
"job_settings": "Aufgabeneinstellungen",
"job_settings_description": "Gleichzeitige Ausführung von Aufgaben verwalten",
"jobs_over_time": "Jobs im Laufe der Zeit",
"library_created": "Bibliothek erstellt: {library}",
"library_deleted": "Bibliothek glöscht",
"library_details": "Bibliotheks-Details",
"library_folder_description": "Gib en Order zum Importiere a. Dä Order mit sine Underordner wird nach Bildli und Videos durchsucht.",
"library_remove_exclusion_pattern_prompt": "Bisch sicher, dass das Uuschluss-Muster wotsch lösche?",
"library_remove_folder_prompt": "Bisch sicher, dass dä Import-Ordner wotsch lösche?",
"library_scanning": "Regelmässigi Überprüefig"
"library_deleted": "Bibliothek gelöscht",
"library_details": "Bibliotheksdetails",
"library_folder_description": "Wähle einen Ordner zum Importieren. Dieser Ordner wird inklusive Unterordnern nach Bildern und Videos durchsucht.",
"library_remove_exclusion_pattern_prompt": "Bilst du sicher, dass du dieses Ausschlussmuster entfernen möchtest?",
"library_remove_folder_prompt": "Bist du sicher, dass du diesen Import-Ordner entfernen möchtest?",
"library_scanning": "Regelmässiges Scannen"
}
}

View File

@@ -1392,6 +1392,7 @@
"light_theme": "Switch to light theme",
"like": "Like",
"like_deleted": "Like deleted",
"link": "Link",
"link_motion_video": "Link motion video",
"link_to_docs": "For more information, refer to the <link>documentation</link>.",
"link_to_oauth": "Link to OAuth",
@@ -1562,6 +1563,8 @@
"multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping",
"mute_memories": "Mute Memories",
"my_albums": "My albums",
"my_immich_description": "Copy current page as a My Immich link",
"my_immich_title": "My Immich link",
"name": "Name",
"name_or_nickname": "Name or nickname",
"name_required": "Name is required",
@@ -1926,6 +1929,8 @@
"scan_settings": "Scan Settings",
"scanning": "Scanning",
"scanning_for_album": "Scanning for album...",
"screencast_mode_description": "Show keyboard and mouse event indicators on the screen",
"screencast_mode_title": "Toggle screencast mode",
"search": "Search",
"search_albums": "Search albums",
"search_by_context": "Search by context",
@@ -2214,6 +2219,8 @@
"sync_status": "Sync Status",
"sync_status_subtitle": "View and manage the sync system",
"sync_upload_album_setting_subtitle": "Create and upload your photos and videos to the selected albums on Immich",
"system_theme": "System theme",
"system_theme_command_description": "Use the system theme ({value})",
"tag": "Tag",
"tag_assets": "Tag assets",
"tag_created": "Created tag: {tag}",

View File

@@ -849,9 +849,12 @@
"create_link_to_share": "Krei ligilon por dividi",
"create_link_to_share_description": "Permesi, ke iu ajn kun la ligilo povu vidi la elektita(j)n foto(j)n",
"create_new": "KREI NOVAN",
"create_new_face": "Krei novan vizaĝon",
"create_new_person": "Krei novan homon",
"create_new_person_hint": "Atribui elektitajn elementojn al nova homo",
"create_new_user": "Krei novan uzanton",
"create_person": "Krei homon",
"create_person_subtitle": "Aldoni nomon al la elektita vizaĝo por krei kaj etikedi novan homon",
"create_shared_album_page_share_add_assets": "ALDONI ELEMENTOJN",
"create_shared_album_page_share_select_photos": "Elekti fotojn",
"create_shared_link": "Krei dividitan ligilon",
@@ -1043,7 +1046,7 @@
"cannot_navigate_previous_asset": "Ne eblas navigi al antaŭa elemento",
"cant_apply_changes": "Ne eblas apliki ŝanĝojn",
"cant_change_activity": "Ne eblas {enabled, select, true {malŝalti} other {ŝalti}} tiun agon",
"cant_change_asset_favorite": "Ne eblas ŝanĝi preferaton por tiu elemento",
"cant_change_asset_favorite": "Ne eblas ŝanĝi preferon por tiu elemento",
"cant_change_metadata_assets_count": "Ne eblas ŝanĝi metadatumojn de {count, plural, one {# elemento} other {# elementoj}}",
"cant_get_faces": "Ne eblas trovi vizaĝojn",
"cant_get_number_of_comments": "Ne eblas trovi nombron da komentoj",
@@ -1074,7 +1077,18 @@
"incorrect_email_or_password": "Neĝusta retadreso aŭ pasvorto",
"library_folder_already_exists": "Tiu ĉi import-vojo jam ekzistas.",
"page_not_found": "Paĝo ne trovita",
"paths_validation_failed": "Evidentiĝis, ke {paths, plural, one {# vojo estas nevalida} other {# vojoj estas nevalidaj}}",
"profile_picture_transparent_pixels": "Ne eblas havi travideblaj bilderoj en profilbildo. Bonvolu zomi kaj/aŭ ŝovi la bildon al loko sen tiaj bilderoj.",
"quota_higher_than_disk_size": "Vi donis kvoton pli grandan ol la disko mem",
"something_went_wrong": "Io misis",
"unable_to_add_album_users": "Ne eblas aldoni uzantojn al la albumo",
"unable_to_add_assets_to_shared_link": "Ne eblas aldoni elementojn al la dividita ligilo",
"unable_to_add_comment": "Ne eblas aldoni komenton",
"unable_to_add_exclusion_pattern": "Ne eblas aldoni skemon de ekskludo",
"unable_to_add_partners": "Ne eblas aldoni partnerojn",
"unable_to_add_remove_archive": "Ne eblas {archived, select, true {forigi elementon de} other {aldoni elementon al}} la arĥivo",
"unable_to_add_remove_favorites": "Ne eblas {favorite, select, true {aldoni elementon al} other {forigi elementon de}} preferataĵoj",
"unable_to_change_favorite": "Ne eblas ŝanĝi preferon por tiu elemento",
"unable_to_create": "Ne eblis krei laborfluon",
"unable_to_delete_exclusion_pattern": "Ne eblas forigi skemon de ekskludo",
"unable_to_delete_workflow": "Ne eblis forigi laborfluon",
@@ -1088,15 +1102,25 @@
"expand_all": "Etendi ĉiujn",
"explore": "Esplori",
"explorer": "Foliumilo",
"favorite": "Preferataĵo",
"favorite_action_prompt": "{count} aldonita(j) al Preferataĵoj",
"favorite_or_unfavorite_photo": "Aldoni/forigi foton al/de preferataĵoj",
"favorites": "Preferataĵoj",
"favorites_page_no_favorites": "Neniuj preferataj elementoj trovitaj",
"free_up_space": "Liberigi spacon",
"free_up_space_description": "Vi forigos fotojn kaj/aŭ videojn, kiuj havas savkopiojn en la servilo, por liberigi spacon en via aparato. La kopioj en la servilo restos.",
"general": "Ĝeneralaj",
"home_page_favorite_err_local": "Ankoraŭ ne eblas aldoni lokajn elementojn al Preferataĵoj; ignorita(j)",
"home_page_favorite_err_partner": "Ankoraŭ ne eblas aldoni elementojn de partnero al Preferataĵoj; ignorita(j)",
"keep_favorites": "Konservi preferataĵojn",
"manage_media_access_settings": "Malfermi agordaĵaron",
"manage_the_app_settings": "Agordi la apon",
"map_settings_only_show_favorites": "Montri nur preferataĵojn",
"missing": "Netraktitaj",
"networking_subtitle": "Administri agordojn pri finpunktoj de la servilo",
"no_devices": "Neniuj aprobitaj aparatoj",
"no_explore_results_message": "Alŝutu pli da fotoj por esplori vian kolekton.",
"no_favorites_message": "Aldoni al Preferataĵoj por rapide retrovi viajn plej bonajn bildojn kaj videojn",
"no_notifications": "Neniuj sciigoj",
"no_results_description": "Provu sinonimon aŭ pli ĝeneralan ŝlosilvorton",
"notification_permission_dialog_content": "Por ŝalti sciigojn, iru al Agordoj kaj elektu 'permesi'.",
@@ -1106,10 +1130,14 @@
"notification_toggle_setting_description": "Ŝalti sciigojn per retmesaĝo",
"notifications": "Sciigoj",
"notifications_setting_description": "Administri sciigojn",
"only_favorites": "Nur preferataĵoj",
"preferences_settings_subtitle": "Administri agordojn pri la apo",
"purchase_settings_server_activated": "La administranto respondecas pri la ŝlosilo de aŭtentikeco por la servilo",
"rating_clear": "Forviŝi pritakson",
"refresh": "Denove",
"remove_from_favorites": "Forigi el preferataĵoj",
"removed_from_favorites": "Forigita(j) el preferataĵoj",
"removed_from_favorites_count": "{count, plural, other {Forigis #}} el Preferataĵoj",
"rescan": "Reanalizi",
"reset": "Restartigi",
"reset_sqlite_clear_app_data": "Forviŝi datumojn",
@@ -1127,7 +1155,10 @@
"setting_notifications_subtitle": "Redakti viajn preferojn pri sciigoj",
"start_date": "Komenca dato",
"start_date_before_end_date": "Komenca dato devas esti antaŭ fina dato",
"to_favorite": "Aldoni al preferataĵoj",
"trigger_description": "Evento, kiu ekfunkciigas la laborfluon",
"unfavorite": "Forigi el preferataĵoj",
"unfavorite_action_prompt": "{count} forigita(j) el Preferataĵoj",
"untitled_workflow": "Sentitola laborfluo",
"upload_concurrency": "Nombro da samtempaj alŝutoj",
"user_pin_code_settings_description": "Administri vian PIN-kodon",

View File

@@ -845,9 +845,12 @@
"create_link_to_share": "Izradite vezu za dijeljenje",
"create_link_to_share_description": "Dopusti svakome s vezom da vidi odabrane fotografije",
"create_new": "KREIRAJ NOVO",
"create_new_face": "Stvori novo lice",
"create_new_person": "Stvorite novu osobu",
"create_new_person_hint": "Dodijelite odabrane stavke novoj osobi",
"create_new_user": "Kreiraj novog korisnika",
"create_person": "Stvori novu osobu",
"create_person_subtitle": "Dodaj ime odabranom licu kako bi stvorio i tagirao novu osobu",
"create_shared_album_page_share_add_assets": "DODAJ STAVKE",
"create_shared_album_page_share_select_photos": "Odaberi fotografije",
"create_shared_link": "Kreiraj dijeljeni link",
@@ -922,6 +925,7 @@
"deselect_all": "Poništi odabir svih",
"details": "Detalji",
"direction": "Smjer",
"disable": "Onesposobi",
"disabled": "Onemogućeno",
"disallow_edits": "Zabrani izmjene",
"discord": "Discord",
@@ -947,6 +951,7 @@
"download_include_embedded_motion_videos": "Ugrađeni videozapisi",
"download_include_embedded_motion_videos_description": "Uključite videozapise ugrađene u fotografije s pokretom kao zasebnu datoteku",
"download_notfound": "Preuzimanje nije pronađeno",
"download_original": "Preuzmi original",
"download_paused": "Preuzimanje pauzirano",
"download_settings": "Preuzmi",
"download_settings_description": "Upravljajte postavkama vezanim uz preuzimanje stavki",
@@ -956,10 +961,11 @@
"download_waiting_to_retry": "Čeka se ponovni pokušaj",
"downloading": "Preuzimanje",
"downloading_asset_filename": "Preuzimanje stavke {filename}",
"downloading_from_icloud": "Preuzmi s iCloud",
"downloading_media": "Preuzimanje medija",
"drop_files_to_upload": "Ispustite datoteke bilo gdje za prijenos",
"duplicates": "Duplikati",
"duplicates_description": "Razriješite svaku grupu tako da naznačite koji su duplikati, ako ih ima",
"duplicates_description": "Razriješite svaku grupu tako da naznačite koji su duplikati, ako ih ima.",
"duration": "Trajanje",
"edit": "Izmjena",
"edit_album": "Uredi album",
@@ -987,6 +993,12 @@
"editor": "Urednik",
"editor_close_without_save_prompt": "Promjene neće biti spremljene",
"editor_close_without_save_title": "Zatvoriti uređivač?",
"editor_confirm_reset_all_changes": "Jeste li sigurni da želite resetirati sve opcije?",
"editor_discard_edits_confirm": "Odbaci izmjene",
"editor_discard_edits_prompt": "Imate nesačuvane izmjene. Jeste li sigurni da ih želite odbaciti?",
"editor_discard_edits_title": "Odbaci izmjene?",
"editor_rotate_left": "Rotiraj 90° u suprotnom smjeru kazaljke na satu",
"editor_rotate_right": "Rotiraj 90° u smjeru kazaljke na satu",
"email": "E-pošta",
"email_notifications": "Obavijesti putem e-maila",
"empty_folder": "Ova mapa je prazna",

View File

@@ -849,9 +849,12 @@
"create_link_to_share": "Buat tautan untuk dibagikan",
"create_link_to_share_description": "Biarkan siapa pun dengan tautan melihat foto yang dipilih",
"create_new": "BUAT BARU",
"create_new_face": "Buat wajah baru",
"create_new_person": "Buat orang baru",
"create_new_person_hint": "Tetapkan aset yang dipilih ke orang yang baru",
"create_new_user": "Buat pengguna baru",
"create_person": "Buat orang",
"create_person_subtitle": "Tambahkan nama pada wajah yang dipilih untuk membuat dan menandai orang baru",
"create_shared_album_page_share_add_assets": "TAMBAHKAN ASET",
"create_shared_album_page_share_select_photos": "Pilih Foto",
"create_shared_link": "Buat tautan bersama",
@@ -2214,6 +2217,7 @@
"tag": "Tag",
"tag_assets": "Tag aset",
"tag_created": "Tag yang dibuat: {tag}",
"tag_face": "Tandai wajah",
"tag_feature_description": "Menjelajahi foto dan video yang dikelompokkan berdasarkan topik tag yang logis",
"tag_not_found_question": "Tidak dapat menemukan tag? <link>Buat tag baru.</link>",
"tag_people": "Beri Tag Orang",

View File

@@ -1934,6 +1934,7 @@
"search_by_filename": "파일명 또는 확장자로 검색",
"search_by_filename_example": "예: IMG_1234.JPG 또는 PNG",
"search_by_ocr": "OCR로 검색",
"search_by_ocr_example": "라떼",
"search_camera_lens_model": "렌즈 모델 검색...",
"search_camera_make": "카메라 제조사 검색...",
"search_camera_model": "카메라 모델명 검색...",
@@ -1997,6 +1998,7 @@
"select_all_in": "{group}의 모든 항목 선택",
"select_avatar_color": "아바타 색상 선택",
"select_count": "{count, plural, one {# 선택중} other {# 선택중}}",
"select_cutoff_date": "유지 기간 설정",
"select_face": "얼굴 선택",
"select_featured_photo": "대표 사진 선택",
"select_from_computer": "컴퓨터에서 선택",

View File

@@ -1215,7 +1215,7 @@
"file_name_text": "Failo pavadinimas",
"file_name_with_value": "Failo pavadinimas: {file_name}",
"file_size": "Failo dydis",
"filename": "Failopavadinimas",
"filename": "Failo pavadinimas",
"filetype": "Failo tipas",
"filter": "Filtras",
"filter_description": "Tikslinių elementų filtravimo sąlygos",
@@ -1390,8 +1390,8 @@
"licenses": "Licencijos",
"light": "Šviesi",
"light_theme": "Perjungti į šviesią temą",
"like": "Kaip",
"like_deleted": "Kaip ištrintas",
"like": "Patinka",
"like_deleted": "Patinka panaikintas",
"link_motion_video": "Susieti judesio vaizdo įrašą",
"link_to_docs": "Daugiau informacijos rasite <link>dokumentacijoje</link>.",
"link_to_oauth": "Susieti su OAuth",

View File

@@ -713,9 +713,11 @@
"create_link": "Izveidot saiti",
"create_link_to_share": "Izveidot kopīgošanas saiti",
"create_new": "IZVEIDOT JAUNU",
"create_new_face": "Izveidot jaunu seju",
"create_new_person": "Izveidot jaunu personu",
"create_new_person_hint": "Piesaistīt izvēlētos failus jaunai personai",
"create_new_user": "Izveidot jaunu lietotāju",
"create_person": "Izveidot personu",
"create_shared_album_page_share_add_assets": "PIEVIENOT AKTĪVUS",
"create_shared_album_page_share_select_photos": "Fotoattēlu Izvēle",
"create_user": "Izveidot lietotāju",
@@ -879,6 +881,7 @@
"failed_to_update_notification_status": "Neizdevās mainīt paziņojuma statusu",
"incorrect_email_or_password": "Nepareizs e-pasts vai parole",
"library_folder_already_exists": "Šis importa ceļš jau pastāv.",
"page_not_found": "Lapa nav atrasta",
"profile_picture_transparent_pixels": "Profila attēlos nevar būt caurspīdīgi pikseļi. Lūdzu, palielini un/vai pārvieto attēlu.",
"quota_higher_than_disk_size": "Tu esi iestatījis kvotu, kas pārsniedz diska izmēru",
"something_went_wrong": "Kaut kas nogāja greizi",
@@ -1295,6 +1298,7 @@
"only_favorites": "Tikai izlase",
"open": "Atvērt",
"open_calendar": "Atvērt kalendāru",
"open_in_browser": "Atvērt pārlūkprogrammā",
"open_in_map_view": "Atvērt kartes skatā",
"open_in_openstreetmap": "Atvērt OpenStreetMap",
"open_the_search_filters": "Atvērt meklēšanas filtrus",
@@ -1455,6 +1459,7 @@
"reset_people_visibility": "Atiestatīt personu redzamību",
"reset_pin_code": "Atiestatīt PIN kodu",
"reset_sqlite": "Atiestatīt SQLite datubāzi",
"reset_sqlite_clear_app_data": "Notīrīt datus",
"reset_to_default": "Atiestatīt noklusējuma iestatījumus",
"resolve_duplicates": "Atrisināt dublēšanās gadījumus",
"resolved_all_duplicates": "Visi dublikāti ir atrisināti",
@@ -1705,6 +1710,7 @@
"sync_local": "Sinhronizēt lokāli",
"sync_status": "Sinhronizācijas statuss",
"sync_status_subtitle": "Skatīt un pārvaldīt sinhronizācijas sistēmu",
"tag_face": "Atzīmēt seju",
"text_recognition": "Teksta atpazīšana",
"theme": "Dizains",
"theme_setting_asset_list_storage_indicator_title": "Rādīt krātuves indikatoru uz attēliem režga skatā",
@@ -1833,6 +1839,7 @@
"viewer_remove_from_stack": "Noņemt no Steka",
"viewer_stack_use_as_main_asset": "Izmantot kā Galveno Aktīvu",
"viewer_unstack": "At-Stekot",
"visibility": "Redzamība",
"visual": "Vizuāli",
"visual_builder": "Vizuālais veidotājs",
"waiting": "Gaida",

View File

@@ -544,7 +544,7 @@
"appears_in": "Komt voor in",
"apply_count": "Toepassen ({count, number})",
"archive": "Archief",
"archive_action_prompt": "{count} item(s) toegevoegd aan het archief",
"archive_action_prompt": "{count, plural, one {# item} other {# items}} toegevoegd aan het archief",
"archive_or_unarchive_photo": "Foto archiveren of uit het archief halen",
"archive_page_no_archived_assets": "Geen gearchiveerde items gevonden",
"archive_page_title": "Archief ({count})",
@@ -593,20 +593,20 @@
"assets_cannot_be_added_to_album_count": "{count, plural, one {# item} other {# items}} konden niet aan album toegevoegd worden",
"assets_cannot_be_added_to_albums": "{count, plural, one {Item kan} other {Items kunnen}} niet toegevoegd worden aan de albums",
"assets_count": "{count, plural, one {# item} other {# items}}",
"assets_deleted_permanently": "{count} item(s) permanent verwijderd",
"assets_deleted_permanently_from_server": "{count} item(s) permanent verwijderd van de Immich server",
"assets_deleted_permanently": "{count, plural, one {# item} other {# items}} permanent verwijderd",
"assets_deleted_permanently_from_server": "{count, plural, one {# item} other {# items}} permanent verwijderd van de Immich server",
"assets_downloaded_failed": "{count, plural, one {# bestand gedownload - {error} bestand mislukt} other {# bestanden gedownload - {error} bestanden mislukt}}",
"assets_downloaded_successfully": "{count, plural, one {# bestand succesvol gedownload} other {# bestanden succesvol gedownload}}",
"assets_moved_to_trash_count": "{count, plural, one {# item} other {# items}} verplaatst naar prullenbak",
"assets_permanently_deleted_count": "{count, plural, one {# item} other {# items}} permanent verwijderd",
"assets_removed_count": "{count, plural, one {# item} other {# items}} verwijderd",
"assets_removed_permanently_from_device": "{count} item(s) permanent verwijderd van je apparaat",
"assets_removed_permanently_from_device": "{count, plural, one {# item} other {# items}} permanent verwijderd van je apparaat",
"assets_restore_confirmation": "Weet je zeker dat je alle verwijderde items wilt herstellen? Je kunt deze actie niet ongedaan maken! Offline items kunnen op deze manier niet worden hersteld.",
"assets_restored_count": "{count, plural, one {# item} other {# items}} hersteld",
"assets_restored_successfully": "{count} item(s) succesvol hersteld",
"assets_trashed": "{count} item(s) naar de prullenbak verplaatst",
"assets_restored_successfully": "{count, plural, one {# item} other {# items}} succesvol hersteld",
"assets_trashed": "{count, plural, one {# item} other {# items}} naar de prullenbak verplaatst",
"assets_trashed_count": "{count, plural, one {# item} other {# items}} naar prullenbak verplaatst",
"assets_trashed_from_server": "{count} item(s) naar de prullenbak verplaatst op de Immich server",
"assets_trashed_from_server": "{count, plural, one {# item} other {# items}} naar de prullenbak verplaatst op de Immich server",
"assets_were_part_of_album_count": "{count, plural, one {Item was} other {Items waren}} al onderdeel van het album",
"assets_were_part_of_albums_count": "{count, plural, one {Item is} other {Items zijn}} al onderdeel van de albums",
"authorized_devices": "Geautoriseerde apparaten",
@@ -876,7 +876,7 @@
"current_server_address": "Huidig serveradres",
"custom_date": "Aangepaste datum",
"custom_locale": "Aangepaste landinstelling",
"custom_locale_description": "Formatteer datums, tijden en getallen op basis van de geselecteerde taal en de regio",
"custom_locale_description": "Formatteer datums, tijden, en getallen op basis van de geselecteerde taal en regio",
"custom_url": "Aangepaste URL",
"cutoff_date_description": "Bewaar foto's van de laatste…",
"cutoff_day": "{count, plural, one {dag} other {dagen}}",
@@ -896,10 +896,10 @@
"days": "Dagen",
"deduplicate_all": "Alles dedupliceren",
"default_locale": "Standaard landinstelling",
"default_locale_description": "Formatteer datums en getallen op basis van de taalinstellingen van uw browser",
"default_locale_description": "Formatteer datums en getallen op basis van de taalinstellingen van je browser",
"delete": "Verwijderen",
"delete_action_confirmation_message": "Weet je zeker dat je dit item wilt verwijderen? Deze actie zorgt ervoor dat het item naar de prullenbak van de server wordt verplaatst en je wordt gevraagd of je deze ook lokaal wilt verwijderen",
"delete_action_prompt": "{count} item(s) verwijderd",
"delete_action_prompt": "{count} verwijderd",
"delete_album": "Album verwijderen",
"delete_api_key_prompt": "Weet je zeker dat je deze API-sleutel wilt verwijderen?",
"delete_dialog_alert": "Deze items zullen permanent verwijderd worden van Immich en je apparaat",
@@ -913,12 +913,12 @@
"delete_key": "Verwijder key",
"delete_library": "Verwijder bibliotheek",
"delete_link": "Verwijder link",
"delete_local_action_prompt": "{count} item(s) lokaal verwijderd",
"delete_local_action_prompt": "{count} lokaal verwijderd",
"delete_local_dialog_ok_backed_up_only": "Verwijder alleen met back-up",
"delete_local_dialog_ok_force": "Toch verwijderen",
"delete_others": "Andere verwijderen",
"delete_permanently": "Permanent verwijderen",
"delete_permanently_action_prompt": "{count} item(s) permanent verwijderd",
"delete_permanently_action_prompt": "{count} permanent verwijderd",
"delete_shared_link": "Verwijder gedeelde link",
"delete_shared_link_dialog_title": "Verwijder gedeelde link",
"delete_tag": "Tag verwijderen",
@@ -948,7 +948,7 @@
"documentation": "Documentatie",
"done": "Klaar",
"download": "Downloaden",
"download_action_prompt": "{count} item(s) aan het downloaden",
"download_action_prompt": "{count, plural, one {# item} other {# items}} aan het downloaden",
"download_canceled": "Download geannuleerd",
"download_complete": "Download voltooid",
"download_enqueue": "Download in wachtrij",
@@ -980,7 +980,7 @@
"edit_birthday": "Wijzig verjaardag",
"edit_date": "Datum bewerken",
"edit_date_and_time": "Datum en tijd bewerken",
"edit_date_and_time_action_prompt": "Datum en tijd bijgewerkt van {count} item(s)",
"edit_date_and_time_action_prompt": "Datum en tijd bijgewerkt van {count, plural, one {# item} other {# items}}",
"edit_date_and_time_by_offset": "Wijzigen datum door verschuiving",
"edit_date_and_time_by_offset_interval": "Nieuw datuminterval: {from}-{to}",
"edit_description": "Beschrijving bewerken",
@@ -990,7 +990,7 @@
"edit_key": "Key bewerken",
"edit_link": "Link bewerken",
"edit_location": "Locatie bewerken",
"edit_location_action_prompt": "Locatie bijgewerkt van {count} item(s)",
"edit_location_action_prompt": "Locatie bijgewerkt van {count, plural, one {# item} other {# items}}",
"edit_location_dialog_title": "Locatie",
"edit_name": "Naam bewerken",
"edit_people": "Mensen bewerken",
@@ -1203,7 +1203,7 @@
"failed_to_load_assets": "Kan items niet laden",
"failed_to_load_folder": "Laden van map mislukt",
"favorite": "Favoriet",
"favorite_action_prompt": "{count} item(s) toegevoegd aan je favorieten",
"favorite_action_prompt": "{count, plural, one {# item} other {# items}} toegevoegd aan je favorieten",
"favorite_or_unfavorite_photo": "Foto markeren als of verwijderen uit favorieten",
"favorites": "Favorieten",
"favorites_page_no_favorites": "Geen favoriete items gevonden",
@@ -1389,7 +1389,7 @@
"library_page_sort_title": "Albumtitel",
"licenses": "Licenties",
"light": "Licht",
"light_theme": "Wissel naar lichte thema",
"light_theme": "Wissel naar licht thema",
"like": "Vind ik leuk",
"like_deleted": "Like verwijderd",
"link_motion_video": "Koppel bewegende video",
@@ -1551,7 +1551,7 @@
"move_off_locked_folder": "Verplaats uit vergrendelde map",
"move_to": "Verplaatsen naar",
"move_to_device_trash": "Naar prullenbak van apparaat",
"move_to_lock_folder_action_prompt": "{count} item(s) toegevoegd aan de vergrendelde map",
"move_to_lock_folder_action_prompt": "{count, plural, one {# item} other {# items}} toegevoegd aan de vergrendelde map",
"move_to_locked_folder": "Verplaats naar vergrendelde map",
"move_to_locked_folder_confirmation": "Deze fotos en videos worden uit alle albums verwijderd en zijn alleen te bekijken in de vergrendelde map",
"move_up": "Naar boven verplaatsen",
@@ -1854,9 +1854,9 @@
"remove_custom_date_range": "Aangepast datumbereik verwijderen",
"remove_deleted_assets": "Verwijder offline bestanden",
"remove_from_album": "Verwijderen uit album",
"remove_from_album_action_prompt": "{count} item(s) verwijderd uit het album",
"remove_from_album_action_prompt": "{count, plural, one {# item} other {# items}} verwijderd uit het album",
"remove_from_favorites": "Verwijderen uit favorieten",
"remove_from_lock_folder_action_prompt": "{count} item(s) verwijderd uit de vergrendelde map",
"remove_from_lock_folder_action_prompt": "{count, plural, one {# item} other {# items}} verwijderd uit de vergrendelde map",
"remove_from_locked_folder": "Verwijder uit de vergrendelde map",
"remove_from_locked_folder_confirmation": "Weet je zeker dat je deze foto's en video's uit de vergrendelde map wilt verplaatsen? Ze zijn dan weer zichtbaar in je bibliotheek.",
"remove_from_shared_link": "Verwijderen uit gedeelde link",
@@ -1899,7 +1899,7 @@
"resolved_all_duplicates": "Alle duplicaten opgelost",
"restore": "Herstellen",
"restore_all": "Herstel alle",
"restore_trash_action_prompt": "{count} item(s) teruggehaald uit de prullenbak",
"restore_trash_action_prompt": "{count, plural, one {# item} other {# items}} teruggehaald uit de prullenbak",
"restore_user": "Gebruiker herstellen",
"restored_asset": "Item hersteld",
"resume": "Hervatten",
@@ -2067,9 +2067,9 @@
"settings_saved": "Instellingen opgeslagen",
"setup_pin_code": "Stel een pincode in",
"share": "Delen",
"share_action_prompt": "{count} item(s) gedeeld",
"share_action_prompt": "{count, plural, one {# item} other {# items}} gedeeld",
"share_add_photos": "Foto's toevoegen",
"share_assets_selected": "{count} item(s) geselecteerd",
"share_assets_selected": "{count, plural, one {# item} other {# items}} geselecteerd",
"share_dialog_preparing": "Voorbereiden...",
"share_link": "Link delen",
"shared": "Gedeeld",
@@ -2177,7 +2177,7 @@
"sort_title": "Titel",
"source": "Bron",
"stack": "Stapel",
"stack_action_prompt": "{count} item(s) gestapeld",
"stack_action_prompt": "{count} items gestapeld",
"stack_duplicates": "Stapel duplicaten",
"stack_select_one_photo": "Selecteer één primaire foto voor de stapel",
"stack_selected_photos": "Geselecteerde foto's stapelen",
@@ -2264,7 +2264,7 @@
"total": "Totaal",
"total_usage": "Totaal gebruik",
"trash": "Prullenbak",
"trash_action_prompt": "{count} item(s) verplaatst naar de prullenbak",
"trash_action_prompt": "{count, plural, one {# item} other {# items}} verplaatst naar de prullenbak",
"trash_all": "Verplaats alle naar prullenbak",
"trash_count": "{count, number} naar prullenbak",
"trash_delete_asset": "Items naar prullenbak verplaatsen of verwijderen",
@@ -2314,7 +2314,7 @@
"unselect_all_duplicates": "Deselecteer alle duplicaten",
"unselect_all_in": "Deselecteer alles in {group}",
"unstack": "Ontstapelen",
"unstack_action_prompt": "{count} item(s) ontstapeld",
"unstack_action_prompt": "{count} items ontstapeld",
"unstacked_assets_count": "{count, plural, one {# item} other {# items}} ontstapeld",
"unsupported_field_type": "Veldtype niet ondersteund",
"unsupported_file_type": "Bestand {file} kan niet worden geüpload omdat het bestandstype {type} niet wordt ondersteund.",

View File

@@ -1,6 +1,6 @@
{
"name": "immich-i18n",
"version": "2.7.0",
"version": "2.7.5",
"private": true,
"scripts": {
"format": "prettier --cache --check .",

View File

@@ -1009,8 +1009,8 @@
"editor_edits_applied_success": "Zmiany zostały pomyślnie zastosowane",
"editor_flip_horizontal": "Odwróć poziomo",
"editor_flip_vertical": "Odwróć pionowo",
"editor_handle_corner": "{corner, select, top_left {Top-left} top_right {Top-right} bottom_left {Bottom-left} bottom_right {Bottom-right} other {A}} uchwyt narożny",
"editor_handle_edge": "{edge, select, top {Top} bottom {Bottom} left {Left} right {Right} other {An}} uchwyt krawędziowy",
"editor_handle_corner": "{corner, select, top_left {Górny lewy} top_right {Górny prawy} bottom_left {Dolny lewy} bottom_right {Dolny prawy} other {Jakiś}} uchwyt narożny",
"editor_handle_edge": "{edge, select, top {Górny} bottom {Dolny} left {Lewy} right {Prawy} other {Jakiś}} uchwyt krawędziowy",
"editor_orientation": "Orientacja",
"editor_reset_all_changes": "Zresetuj zmiany",
"editor_rotate_left": "Obróć o 90° przeciwnie do ruchu wskazówek zegara",

View File

@@ -5,6 +5,7 @@
"acknowledge": "รับทราบ",
"action": "ดำเนินการ",
"action_common_update": "อัปเดต",
"action_description": "ชุดการดำเนินการที่จะปฏิบัติกับรายการที่ผ่านการกรอง",
"actions": "การดำเนินการ",
"active": "กำลังทำงาน",
"active_count": "กำลังทำงาน: {count}",
@@ -16,11 +17,13 @@
"add_a_name": "เพิ่มชื่อ",
"add_a_title": "เพิ่มหัวข้อ",
"add_action": "เพิ่มการดำเนินการ",
"add_action_description": "คลิกเพื่อเพิ่มการดำเนินการ",
"add_assets": "เพิ่มสื่อ",
"add_birthday": "เพิ่มวันเกิด",
"add_endpoint": "เพิ่มปลายทาง",
"add_exclusion_pattern": "เพิ่มข้อยกเว้น",
"add_filter": "เพิ่มตัวกรอง",
"add_filter_description": "คลิกเพื่อเพิ่มการกรอง",
"add_location": "เพิ่มตำแหน่ง",
"add_more_users": "เพิ่มผู้ใช้งาน",
"add_partner": "เพิ่มคู่หู",
@@ -32,12 +35,14 @@
"add_to_album_bottom_sheet_added": "เพิ่มไปยัง {album} แล้ว",
"add_to_album_bottom_sheet_already_exists": "อยู่ใน {album} อยู่แล้ว",
"add_to_album_bottom_sheet_some_local_assets": "ไฟล์บางส่วนไม่สามารถเพิ่มไปยังอัลบั้มได้",
"add_to_album_toggle": "สลับการเลือกสำหรับ {album}",
"add_to_albums": "เพิ่มเข้าในอัลบั้ม",
"add_to_albums_count": "เพิ่มไปยังอัลบั้ม ({count})",
"add_to_bottom_bar": "เพิ่มไปยัง",
"add_to_shared_album": "เพิ่มไปยังอัลบั้มที่แชร์",
"add_upload_to_stack": "เพิ่มที่อัปโหลดเข้า stack",
"add_url": "เพิ่ม URL",
"add_workflow_step": "เพิ่มขั้นตอนการทำงาน",
"added_to_archive": "เพิ่มไปยังที่จัดเก็บถาวร",
"added_to_favorites": "เพิ่มเข้ารายการโปรดแล้ว",
"added_to_favorites_count": "เพิ่ม {count, number} รูปเข้ารายการโปรดแล้ว",
@@ -70,6 +75,7 @@
"confirm_reprocess_all_faces": "คุณแน่ใจว่าคุณต้องการประมวลผลใบหน้าทั้งหมดใหม่? ชื่อคนจะถูกลบไปด้วย",
"confirm_user_password_reset": "คุณแน่ใจว่าต้องการรีเซ็ตรหัสผ่านของ {user} หรือไม่?",
"confirm_user_pin_code_reset": "คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตรหัส PIN ของ {user}",
"copy_config_to_clipboard_description": "คัดลอกการตั้งค่าระบบปัจจุบันในรูปแบบ JSON ไปยังคลิปบอร์ด",
"create_job": "สร้างงาน",
"cron_expression": "รูปแบบ cron",
"cron_expression_description": "ตั้งช่วงเวลาในการสแกนโดยใช้รูปแบบ cron สำหรับข้อมูลเพิ่มเติมกรุณาอิง <link>Crontab Guru</link>",
@@ -77,6 +83,7 @@
"disable_login": "ปิดการล็อกอิน",
"duplicate_detection_job_description": "ใช้ machine learning กับสี่อเพื่อตรวจจับรูปภาพที่คล้ายกัน โดยใช้การค้นหาอัจฉริยะ",
"exclusion_pattern_description": "ข้อยกเว้นสามารถละเว้นไฟล์และโฟลเดอร์ขณะสแกนคลังภาพของคุณ มีประโยชน์เมื่อโฟลเดอร์มีไฟล์ที่ไม่อยากนำเข้า เช่นไฟล์ RAW",
"export_config_as_json_description": "ดาวน์โหลดการตั้งค่าระบบปัจจุบันไปยังไฟล์ในรูปแบบ JSON",
"external_libraries_page_description": "หน้าต่างคลังแอดมินภายนอก",
"face_detection": "การตรวจจับใบหน้า",
"face_detection_description": "ตรวจจับใบหน้าในสี่อโดยใช้ machine learning วิดีโอจะใช้ภาพตัวอย่างจากวิดีโอเท่านั้น \"ทั้งหมด\" จะประมวลผลสี่อทั้งหมด \"ขาดหาย\" จะประมวลผลสี่อที่ยังไม่ได้ประมวลผล ใบหน้าที่ถูกตรวจจับแล้วจะถูกเข้าคิวประมวลผลการจดจำใบหน้า เพิ่มเข้าไปในกลุ่มที่มีอยู่แล้วหรือคนใหม่",
@@ -97,6 +104,8 @@
"image_preview_description": "ภาพขนาดปานกลางที่ถูกลบข้อมูลเมตา ใช้สำหรับการดูแอสเซ็ตเดี่ยวและสำหรับการเรียนรู้ของเครื่อง (Machine Learning)",
"image_preview_quality_description": "คุณภาพการแสดงตัวอย่างตั้งแต่ 1-100 ยิ่งสูงยิ่งดี แต่จะทำให้ไฟล์มีขนาดใหญ่ขึ้นและอาจทำให้แอปตอบสนองช้าลง การตั้งค่าต่ำอาจส่งผลต่อคุณภาพ Machine Learning",
"image_preview_title": "ตั้งค่าพรีวิว",
"image_progressive": "รูปภาพแบบโปรเกรสซีฟ",
"image_progressive_description": "เข้ารหัสรูปภาพ JPEG แบบโปรเกรสซีฟเพื่อให้แสดงผลแบบค่อยๆ ชัดขึ้นขณะโหลด ทั้งนี้จะไม่มีผลกับรูปภาพ WebP",
"image_quality": "คุณภาพ",
"image_resolution": "ความละเอียด",
"image_resolution_description": "ความละเอียดสูกว่าสามารถเก็บรายละเอียดได้มากกว่าแต่ใช้เวลา encode นานกว่า ไฟล์ใหญ่กว่า และลดความตอบสนองของแอป",
@@ -105,6 +114,7 @@
"image_thumbnail_description": "รูปขนาดย่อที่มีการลบข้อมูลเมตาด้าต้า ใช้เมื่อดูภาพถ่ายในกลุ่ม เช่น ในไทม์ไลน์หลัก",
"image_thumbnail_quality_description": "คุณภาพของภาพขนาดย่อตั้งแต่ 1-100 ยิ่งสูงยิ่งดี แต่จะทำให้ไฟล์มีขนาดใหญ่ขึ้นและอาจทำให้แอปตอบสนองช้าลง",
"image_thumbnail_title": "ตั้งค่า Thumbnail",
"import_config_from_json_description": "นำเข้าการตั้งค่าระบบโดยการอัปโหลดไฟล์คอนฟิก JSON",
"job_concurrency": "{job} งานพร้อมกัน",
"job_created": "สร้างงานเรียบร้อย",
"job_not_concurrency_safe": "งานนี้ทำงานพร้อมกันแบบปลอดภัยไม่ได้",
@@ -510,10 +520,10 @@
"always_keep_photos_hint": "\"เพิ่มพื้นที่ว่าง\" จะเก็บรูปภาพทั้งหมดบนอุปกรณ์นี้",
"always_keep_videos_hint": "\"เพิ่มพื้นที่ว่าง\" จะเก็บวิดีโอทั้งหมดบนอุปกรณ์นี้",
"anti_clockwise": "ทวนเข็มนาฬิกา",
"api_key": "API key",
"api_key": "คีย์ API",
"api_key_description": "ค่านี้จะแสดงเพียงครั้งเดียว โปรดคัดลอกก่อนปิดหน้าต่าง",
"api_key_empty": "ชื่อ API Key ของคุณไม่ควรว่างเปล่า",
"api_keys": "API Key",
"api_key_empty": "ชื่อคีย์ API ของคุณไม่ควรว่างเปล่า",
"api_keys": "คีย์ API",
"app_architecture_variant": "รูปแบบ (สถาปัตยกรรม)",
"app_bar_signout_dialog_content": "คุณแน่ใจว่าอยากออกจากระบบ",
"app_bar_signout_dialog_ok": "ใช่",
@@ -867,7 +877,7 @@
"delete": "ลบออก",
"delete_action_prompt": "ลบ {count} รายการแล้ว",
"delete_album": "ลบอัลบั้ม",
"delete_api_key_prompt": "คุณต้องการลบ API คีย์ นี้ใช่ไหม ?",
"delete_api_key_prompt": "คุณต้องการลบคีย์ API นี้หรือไม่?",
"delete_dialog_alert": "รายการดังกล่าวจะถูกลบจาก Immich และเครื่องอย่างถาวร",
"delete_dialog_alert_local": "รายการดังกล่าวจะถูกลบจากเครื่องคุณอย่างถาวร แต่จะยังคงอยู่บนเซิร์ฟเวอร์ Immich",
"delete_dialog_alert_local_non_backed_up": "รายการบางตัวไม่ได้ถูกสำรองบน Immich และจะถูกลบจากเครื่องคุณอย่างถาวร",
@@ -1062,7 +1072,7 @@
"unable_to_connect": "ไม่สามารถเชื่อมต่อได้",
"unable_to_copy_to_clipboard": "ไม่สามารถคัดลอกไปยังคลิปบอร์ดได้ ตรวจสอบให้แน่ใจว่าคุณเข้าถึงหน้าผ่านทาง https",
"unable_to_create_admin_account": "ไม่สามารถสร้างบัญชีผู้ดูแลระบบได้",
"unable_to_create_api_key": "ไม่สามารถสร้าง API คีย์ ได้",
"unable_to_create_api_key": "ไม่สามารถสร้างคีย์ API",
"unable_to_create_library": "ไม่สามารถสร้างคลังภาพได้",
"unable_to_create_user": "ไม่สามารถสร้างผู้ใช้ได้",
"unable_to_delete_album": "ไม่สามารถลบอัลบั้มได้",
@@ -1089,7 +1099,7 @@
"unable_to_reassign_assets_new_person": "ไม่สามารถมอบหมาย ให้กับบุคคลใหม่ได้",
"unable_to_refresh_user": "ไม่สามารถรีเฟรชผู้ใช้ได้",
"unable_to_remove_album_users": "ไม่สามารถลบผู้ใช้ออกจากอัลบั้มได้",
"unable_to_remove_api_key": "ไม่สามารถลบ API Key ได้",
"unable_to_remove_api_key": "ไม่สามารถลบคีย์ API",
"unable_to_remove_assets_from_shared_link": "ไม่สามารถลบออกจากลิงก์ที่แชร์ได้",
"unable_to_remove_library": "ไม่สามารถลบคลังภาพได้",
"unable_to_remove_partner": "ไม่สามารถลบคู่หูได้",
@@ -1101,7 +1111,7 @@
"unable_to_restore_trash": "ไม่สามารถเรียกคืนถังขยะได้",
"unable_to_restore_user": "ไม่สามารถเรียกคืนผู้ใช้ได้",
"unable_to_save_album": "ไม่สามารถบันทึกอัลบั้มได้",
"unable_to_save_api_key": "ไม่สามารถบันทึก API คีย์ ได้",
"unable_to_save_api_key": "ไม่สามารถบันทึกคีย์ API",
"unable_to_save_date_of_birth": "ไม่สามารถบันทึกวันเกิดได้",
"unable_to_save_name": "ไม่สามารถบันทึกชื่อได้",
"unable_to_save_profile": "ไม่สามารถบันทึกโปรไฟล์ได้",
@@ -1195,7 +1205,7 @@
"geolocation_instruction_location": "คลิกบนสื่อที่มีพิกัด GPS เพื่อใช้ตำแหน่งนั้น หรือเลือกตำแหน่งจากแผนที่โดยตรง",
"get_help": "ขอความช่วยเหลือ",
"get_people_error": "ข้อผิดพลาดขณะดึงข้อมูลผู้คน",
"get_wifiname_error": "ไม่สามารถรับชื่อ Wi-Fi กรุณายืนยันการให้อนุญาตแอ และยืนยันว่า Wi-Fi เชื่อมต่ออยู่",
"get_wifiname_error": "ไม่สามารถรับชื่อ Wi-Fi กรุณายืนยันการให้อนุญาตแอ และยืนยันว่าเชื่อมต่อกับเครือข่าย Wi-Fi อยู่",
"getting_started": "เริ่มต้นใช้งาน",
"go_back": "กลับ",
"go_to_folder": "ไปที่โฟล์เดอร์",
@@ -1430,7 +1440,7 @@
"manage_sharing_with_partners": "จัดการการแชร์กับคู่หู",
"manage_the_app_settings": "จัดการการตั้งค่าแอป",
"manage_your_account": "จัดการบัญชีของคุณ",
"manage_your_api_keys": "จัดการกุญแจ API ของคุณ",
"manage_your_api_keys": "จัดการคีย์ API ของคุณ",
"manage_your_devices": "จัดการอุปกรณ์ของคุณ",
"manage_your_oauth_connection": "จัดการการเชื่อมต่อ OAuth ของคุณ",
"map": "แผนที่",
@@ -1516,7 +1526,7 @@
"networking_subtitle": "ตั้งค่าปลายทางเซิร์ฟเวอร์",
"never": "ไม่เคย",
"new_album": "อัลบั้มใหม่",
"new_api_key": "สร้าง API คีย์ใหม่",
"new_api_key": "สร้างคีย์ API ใหม่",
"new_date_range": "ช่วงวันที่ใหม่",
"new_password": "รหัสผ่านใหม่",
"new_person": "คนใหม่",
@@ -1581,7 +1591,7 @@
"on_this_device": "บนอุปกรณ์นี้",
"onboarding": "การเริ่มต้นใช้งาน",
"onboarding_locale_description": "เลือกภาษาที่คุณต้องการ คุณสามารถเปลี่ยนได้ภายหลังในการตั้งค่า",
"onboarding_privacy_description": "ฟีเจอร์ (ตัวเลือก) ต่อไปนี้ต้องอาศัยบริการภายนอก และสามารถปิดใช้งานได้ตลอดเวลาในการตั้งค่าการ",
"onboarding_privacy_description": "คุณสมบัติ (ตัวเลือก) ต่อไปนี้ต้องอาศัยบริการภายนอก และสามารถปิดใช้งานได้ตลอดเวลาในการตั้งค่า",
"onboarding_server_welcome_description": "มาตั้งค่าเซิร์ฟเวอร์ของคุณด้วยการตั้งค่าที่ใช้บ่อยกันเถอะ",
"onboarding_theme_description": "เลือกธีมสี คุณสามารถเปลี่ยนแปลงได้ในภายหลังในการตั้งค่าของคุณ",
"onboarding_user_welcome_description": "มาเริ่มต้นกันเถอะ!",
@@ -1631,7 +1641,7 @@
"pattern": "รูปแบบ",
"pause": "หยุด",
"pause_memories": "หยุดดูความทรงจํา",
"paused": "หยุด",
"paused": "หยุดชั่วคราว",
"pending": "กำลังรอ",
"people": "ผู้คน",
"people_edits_count": "{count, plural, one {# person} other {# people}} ถูกแก้ไข",
@@ -1644,11 +1654,13 @@
"permanently_delete_assets_prompt": "คุณแน่ใจหรือไม่ว่าต้องการลบ {count, plural, one {this asset?} other {these <b>#</b> asset?}}อย่างถาวร การดำเนินการนี้จะลบ {count, plural, one {it from its} other {them from their}} อัลบั้มด้วย",
"permanently_deleted_asset": "ลบสื่อถาวรแล้ว",
"permanently_deleted_assets_count": "ลบ {count, plural, one {# asset} other {# assets}} เรียบร้อยแล้ว",
"permission": "สิทธิ์",
"permission_empty": "สิทธิ์ของคุณต้องไม่เว้นว่าง",
"permission_onboarding_back": "กลับ",
"permission_onboarding_continue_anyway": "ดำเนินการต่อ",
"permission_onboarding_get_started": "เริ่มต้น",
"permission_onboarding_go_to_settings": "ไปยังการตั้งค่า",
"permission_onboarding_permission_denied": "ไม่อนุญาต ตั้งค่าสิทธิ์เข้าถึงรูปภาพและวิดีโอเพื่อใช้งาน Immich",
"permission_onboarding_permission_denied": "สิทธิ์ถูกปฏิเสธ กรุณาให้สิทธิ์เข้าถึงรูปภาพและวิดีโอเพื่อใช้งาน Immich",
"permission_onboarding_permission_granted": "ให้สิทธิ์สำเร็จ คุณพร้อมใช้งานแล้ว",
"permission_onboarding_permission_limited": "สิทธ์จำกัด เพื่อให้ Immich สำรองข้อมูลและจัดการคลังภาพได้ ตั้งค่าสิทธิเข้าถึงรูปภาพและวิดีโอ",
"permission_onboarding_request": "Immich จำเป็นจะต้องได้รับสิทธิ์ดูรูปภาพและวิดีโอ",
@@ -1783,7 +1795,7 @@
"remove_photo_from_memory": "ลบรูปออกจากความทรงจำนี้",
"remove_url": "ลบ URL",
"remove_user": "ลบผู้ใช้",
"removed_api_key": "API คีย์ของ: {name} ถูกลบแล้ว",
"removed_api_key": "ลบคีย์ API แล้ว: {name}",
"removed_from_archive": "ลบจากเก็บถาวรแล้ว",
"removed_from_favorites": "ลบจากรายการโปรดแล้ว",
"removed_from_favorites_count": "{count, plural, other {ถูกลบ#}} จากรายการโปรดแล้ว",
@@ -1831,7 +1843,7 @@
"save": "บันทึก",
"save_to_gallery": "บันทึกไปยังแกลเลอรี",
"saved": "บันทึกแล้ว",
"saved_api_key": "บันทึก API คีย์ แล้ว",
"saved_api_key": "บันทึกคีย์ API แล้ว",
"saved_profile": "แก้ไขโปรไฟล์สำเร็จ",
"saved_settings": "บันทึกการตั้งค่าสำเร็จ",
"say_something": "พูดอะไรสักอย่าง",
@@ -2226,7 +2238,7 @@
"upload_status_duplicates": "รายการซ้ำ",
"upload_status_errors": "ข้อผิดพลาด",
"upload_status_uploaded": "อัปโหลดแล้ว",
"upload_success": "อัปโหลดสำเร็จ รีเฟรชหน้าเพื่อดูสื่อใหม่ที่อัปโหลดล่าสุด",
"upload_success": "อัปโหลดสำเร็จ รีเฟรชหน้าเพื่อดูสื่อที่อัปโหลดใหม่",
"upload_to_immich": "อัปโหลดไปยัง Immich ({count})",
"uploading": "กำลังอัปโหลด",
"uploading_media": "กำลังอัปโหลดสื่อ",

View File

@@ -849,9 +849,12 @@
"create_link_to_share": "Створити посилання спільного доступу",
"create_link_to_share_description": "Дати змогу будь-кому переглядати вибрані фото за посиланням",
"create_new": "СТВОРИТИ НОВИЙ",
"create_new_face": "Створити нове обличчя",
"create_new_person": "Створити нову людину",
"create_new_person_hint": "Призначити вибрані елементи новій людині",
"create_new_user": "Створити нового користувача",
"create_person": "Створити людину",
"create_person_subtitle": "Додайте ім'я до вибраного обличчя, щоб створити та позначити нову особу",
"create_shared_album_page_share_add_assets": "ДОДАТИ ЕЛЕМЕНТИ",
"create_shared_album_page_share_select_photos": "Вибрати фото",
"create_shared_link": "Створити спільне посилання",
@@ -2214,6 +2217,7 @@
"tag": "Тег",
"tag_assets": "Додати теги",
"tag_created": "Створено тег: {tag}",
"tag_face": "Тег обличчя",
"tag_feature_description": "Перегляд фото та відео, згрупованих за логічними темами тегів",
"tag_not_found_question": "Не вдається знайти тег? <link>Створіть новий тег.</link>",
"tag_people": "Позначити людей",

View File

@@ -537,10 +537,10 @@
"app_bar_signout_dialog_content": "Bạn có muốn đăng xuất?",
"app_bar_signout_dialog_ok": "Có",
"app_bar_signout_dialog_title": "Đăng xuất",
"app_download_links": "Liên kết tải app",
"app_settings": "App",
"app_stores": "Cửa hàng app",
"app_update_available": "Đã có bản cập nhật app",
"app_download_links": "Liên kết tải ứng dụng",
"app_settings": "Ứng dụng",
"app_stores": "Cửa hàng ứng dụng",
"app_update_available": "Đã có bản cập nhật ứng dụng",
"appears_in": "Xuất hiện trong",
"apply_count": "Áp dụng ({count, number})",
"archive": "Lưu trữ",
@@ -617,7 +617,7 @@
"back_close_deselect": "Quay lại, đóng, hoặc bỏ chọn",
"background_backup_running_error": "Sao lưu nền hiện đang chạy, không thể bắt đầu sao lưu thủ công",
"background_location_permission": "Quyền truy cập vị trí khi chạy nền",
"background_location_permission_content": "Để chuyển đổi mạng khi chạy ở chế độ nền, Immich *luôn* phải có quyền truy cập vị trí chính xác để có thể đọc tên mạng Wi-Fi",
"background_location_permission_content": "Để chuyển đổi mạng khi chạy ở chế độ nền, Immich phải *luôn* có quyền truy cập vị trí chính xác để có thể đọc tên mạng Wi-Fi",
"background_options": "Tùy chọn nền",
"backup": "Sao lưu",
"backup_album_selection_page_albums_device": "Album trên thiết bị ({count})",
@@ -637,8 +637,8 @@
"backup_background_service_in_progress_notification": "Đang sao lưu tệp của bạn…",
"backup_background_service_upload_failure_notification": "Tải lên {filename} thất bại",
"backup_controller_page_albums": "Album sao lưu",
"backup_controller_page_background_app_refresh_disabled_content": "Bật làm mới app trong nền tại Cài đặt > Cài đặt chung > Làm mới app trong nền để dùng sao lưu nền.",
"backup_controller_page_background_app_refresh_disabled_title": "Làm mới app trong nền bị vô hiệu hoá",
"backup_controller_page_background_app_refresh_disabled_content": "Bật làm mới ứng dụng trong nền tại Cài đặt > Cài đặt chung > Làm mới ứng dụng trong nền để dùng sao lưu nền.",
"backup_controller_page_background_app_refresh_disabled_title": "Làm mới ứng dụng trong nền bị vô hiệu hoá",
"backup_controller_page_background_app_refresh_enable_button_text": "Đi tới cài đặt",
"backup_controller_page_background_battery_info_link": "Hướng dẫn tôi",
"backup_controller_page_background_battery_info_message": "Để có trải nghiệm sao lưu nền tốt nhất, vui lòng vô hiệu hóa bất kỳ tối ưu hóa pin nào đang hạn chế hoạt động nền của Immich.\n\nVì điều này phụ thuộc vào thiết bị, vui lòng tham khảo thông tin cần thiết của nhà sản xuất thiết bị của bạn.",
@@ -647,7 +647,7 @@
"backup_controller_page_background_charging": "Chỉ khi đang sạc",
"backup_controller_page_background_configure_error": "Cấu hình dịch vụ nền thất bại",
"backup_controller_page_background_delay": "Trì hoãn sao lưu tệp mới: {duration}",
"backup_controller_page_background_description": "Bật dịch vụ nền để tự động sao lưu tệp mới mà không cần mở app",
"backup_controller_page_background_description": "Bật dịch vụ nền để tự động sao lưu tệp mới mà không cần mở ứng dụng",
"backup_controller_page_background_is_off": "Sao lưu tự động trong nền đang tắt",
"backup_controller_page_background_is_on": "Sao lưu tự động trong nền đang bật",
"backup_controller_page_background_turn_off": "Tắt dịch vụ nền",
@@ -657,7 +657,7 @@
"backup_controller_page_backup_selected": "Đã chọn: ",
"backup_controller_page_backup_sub": "Ảnh và video đã sao lưu",
"backup_controller_page_created": "Tạo vào: {date}",
"backup_controller_page_desc_backup": "Bật sao lưu khi app hoạt động để tự động sao lưu tệp mới lên máy chủ khi mở app.",
"backup_controller_page_desc_backup": "Bật sao lưu khi ứng dụng hoạt động để tự động sao lưu tệp mới lên máy chủ khi mở ứng dụng.",
"backup_controller_page_excluded": "Đã bỏ qua: ",
"backup_controller_page_failed": "Thất bại ({count})",
"backup_controller_page_filename": "Tên tệp: {filename} [{size}]",
@@ -668,12 +668,12 @@
"backup_controller_page_remainder_sub": "Số lượng ảnh và video đã chọn chưa được sao lưu",
"backup_controller_page_server_storage": "Dung lượng máy chủ",
"backup_controller_page_start_backup": "Bắt đầu sao lưu",
"backup_controller_page_status_off": "Sao lưu tự động khi app hoạt động đang tắt",
"backup_controller_page_status_on": "Sao lưu tự động khi app hoạt động đang bật",
"backup_controller_page_status_off": "Sao lưu tự động khi ứng dụng hoạt động đang tắt",
"backup_controller_page_status_on": "Sao lưu tự động khi ứng dụng hoạt động đang bật",
"backup_controller_page_storage_format": "Đã dùng {used} của {total}",
"backup_controller_page_to_backup": "Các album cần được sao lưu",
"backup_controller_page_total_sub": "Tất cả ảnh và video không trùng lập từ các album được chọn",
"backup_controller_page_turn_off": "Tắt sao lưu khi app hoạt động",
"backup_controller_page_turn_off": "Tắt sao lưu khi ứng dụng hoạt động",
"backup_controller_page_turn_on": "Bật sao lưu khi mở app",
"backup_controller_page_uploading_file_info": "Thông tin tệp đang tải lên",
"backup_err_only_album": "Không thể xóa album duy nhất",
@@ -704,16 +704,16 @@
"bulk_trash_duplicates_confirmation": "Bạn có chắc muốn đưa {count, plural, one {# tệp trùng lặp} other {# tệp trùng lặp}} vào thùng rác? Điều này sẽ giữ lại ảnh chất lượng nhất của mỗi nhóm và đưa tất cả các bản trùng lặp khác vào thùng rác.",
"buy": "Mua Immich",
"cache_settings_clear_cache_button": "Xóa bộ nhớ đệm",
"cache_settings_clear_cache_button_title": "Xóa bộ nhớ đệm của app. Điều này sẽ ảnh hưởng đến hiệu suất của app đến khi bộ nhớ đệm được tạo lại.",
"cache_settings_clear_cache_button_title": "Xóa bộ nhớ đệm của ứng dụng. Điều này sẽ ảnh hưởng đến hiệu suất của ứng dụng đến khi bộ nhớ đệm được tạo lại.",
"cache_settings_duplicated_assets_clear_button": "XÓA",
"cache_settings_duplicated_assets_subtitle": "Ảnh và video không được phép hiển thị trên app",
"cache_settings_duplicated_assets_subtitle": "Ảnh và video không được phép hiển thị trên ứng dụng",
"cache_settings_duplicated_assets_title": "Tệp bị trùng ({count})",
"cache_settings_statistics_album": "Ảnh thu nhỏ thư viện",
"cache_settings_statistics_full": "Ảnh đầy đủ",
"cache_settings_statistics_shared": "Ảnh thu nhỏ album chia sẻ",
"cache_settings_statistics_thumbnail": "Ảnh thu nhỏ",
"cache_settings_statistics_title": "Mức sử dụng bộ nhớ đệm",
"cache_settings_subtitle": "Kiểm soát hành vi bộ nhớ đệm của app Immich",
"cache_settings_subtitle": "Kiểm soát hành vi bộ nhớ đệm của Immich",
"cache_settings_tile_subtitle": "Kiểm soát cách xử lý lưu trữ cục bộ",
"cache_settings_tile_title": "Lưu trữ cục bộ",
"cache_settings_title": "Cài đặt bộ nhớ đệm",
@@ -999,8 +999,8 @@
"editor_discard_edits_confirm": "Bỏ thay đổi",
"editor_discard_edits_prompt": "Bạn có những thay đổi chưa được lưu. Bạn có chắc chắn muốn hủy bỏ chúng không?",
"editor_discard_edits_title": "Hủy thay đổi?",
"editor_edits_applied_error": "Lỗi khi áp dụng thay đổi",
"editor_edits_applied_success": "Thay đổi được áp dụng thành công",
"editor_edits_applied_error": "Không thể áp dụng chỉnh sửa",
"editor_edits_applied_success": "Chỉnh sửa được áp dụng thành công",
"editor_flip_horizontal": "Lật ngang",
"editor_flip_vertical": "Lật dọc",
"editor_orientation": "Định hướng",
@@ -1202,7 +1202,7 @@
"feature_photo_updated": "Đã cập nhật ảnh nổi bật",
"features": "Tính năng",
"features_in_development": "Tính năng đang được phát triển",
"features_setting_description": "Quản lý các tính năng app",
"features_setting_description": "Quản lý các tính năng ứng dụng",
"file_name_or_extension": "Tên hoặc phần mở rộng tập tin",
"file_name_text": "Tên tệp",
"file_name_with_value": "Tên tệp: {file_name}",
@@ -1280,7 +1280,7 @@
"home_page_delete_remote_err_local": "Tệp trên thiết bị trong lựa chọn xóa từ xa, bỏ qua",
"home_page_favorite_err_local": "Không thể thích tệp trên thiết bị, bỏ qua",
"home_page_favorite_err_partner": "Không thể thích tệp của người thân, bỏ qua",
"home_page_first_time_notice": "Nếu đây là lần đầu bạn dùng app, hãy chọn một album sao lưu để dòng thời gian có thể hiển thị ảnh và video của bạn",
"home_page_first_time_notice": "Nếu đây là lần đầu bạn dùng ứng dụng, hãy chọn một album sao lưu để dòng thời gian có thể hiển thị ảnh và video của bạn",
"home_page_locked_error_local": "Không thể di chuyển tệp trên thiết bị đến thư mục Khóa, bỏ qua",
"home_page_locked_error_partner": "Không thể di chuyển tệp của người thân đến thư mục Khóa, bỏ qua",
"home_page_share_err_local": "Không thể chia sẻ tệp trên thiết bị qua liên kết, bỏ qua",
@@ -1395,7 +1395,7 @@
"local_id": "ID cục bộ",
"local_media_summary": "Mô tả phương tiện trên thiết bị",
"local_network": "Mạng nội bộ",
"local_network_sheet_info": "App sẽ kết nối với máy chủ qua URL này khi sử dụng mạng Wi-Fi được chỉ định",
"local_network_sheet_info": "Ứng dụng sẽ kết nối với máy chủ qua URL này khi sử dụng mạng Wi-Fi được chỉ định",
"location": "Địa điểm",
"location_permission": "Quyền truy cập vị trí",
"location_permission_content": "Để sử dụng tính năng tự động chuyển đổi, Immich cần có quyền vị trí chính xác để có thể đọc tên của mạng Wi-Fi hiện tại",
@@ -1471,11 +1471,11 @@
"manage_geolocation": "Quản lý địa điểm",
"manage_media_access_rationale": "Để có thể di chuyển tệp vào thùng rác và khôi phục chúng từ đó.",
"manage_media_access_settings": "Mở cài đặt",
"manage_media_access_subtitle": "Cho phép app [Immich] quản lý và di chuyển tệp.",
"manage_media_access_subtitle": "Cho phép ứng dụng [Immich] quản lý và di chuyển tệp.",
"manage_media_access_title": "Quản lý phương tiện",
"manage_shared_links": "Quản lý liên kết chia sẻ",
"manage_sharing_with_partners": "Quản lý chia sẻ với người thân",
"manage_the_app_settings": "Quản lý cài đặt app",
"manage_the_app_settings": "Quản lý cài đặt ứng dụng",
"manage_your_account": "Quản lý tài khoản của bạn",
"manage_your_api_keys": "Quản lý các khóa API của bạn",
"manage_your_devices": "Quản lý các thiết bị đã đăng nhập của bạn",
@@ -1490,7 +1490,7 @@
"map_marker_for_images": "Đánh dấu bản đồ cho ảnh chụp tại {city}, {country}",
"map_marker_with_image": "Đánh dấu bản đồ với ảnh",
"map_no_location_permission_content": "Cần quyền truy cập vị trí để hiển thị tệp từ vị trí hiện tại của bạn. Bạn có muốn cho phép ngay bây giờ không?",
"map_no_location_permission_title": "App không được phép truy cập vị trí",
"map_no_location_permission_title": "Ứng dụng không được phép truy cập vị trí",
"map_settings": "Cài đặt bản đồ",
"map_settings_dark_mode": "Chế độ tối",
"map_settings_date_range_option_day": "Trong vòng 24 giờ qua",
@@ -1746,7 +1746,7 @@
"play_transcoded_video": "Phát video đã chuyển mã",
"please_auth_to_access": "Vui lòng xác thực để truy cập",
"port": "Cổng",
"preferences_settings_subtitle": "Tùy chỉnh trải nghiệm app",
"preferences_settings_subtitle": "Tùy chỉnh trải nghiệm ứng dụng",
"preferences_settings_title": "Cá nhân hóa",
"preparing": "Đang chuẩn bị",
"preset": "Mẫu có sẵn",
@@ -1760,7 +1760,7 @@
"primary": "Chính",
"privacy": "Bảo mật",
"profile": "Hồ sơ",
"profile_drawer_app_logs": "Log",
"profile_drawer_app_logs": "Nhật ký",
"profile_drawer_client_server_up_to_date": "Máy khách và máy chủ đã cập nhật",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "Đã bật chế độ chỉ-xem. Nhấn giữ ảnh đại diện người dùng để tắt.",
@@ -2006,7 +2006,7 @@
"send_message": "Gửi tin nhắn",
"send_welcome_email": "Gửi email chào mừng",
"server_endpoint": "Địa chỉ máy chủ",
"server_info_box_app_version": "Phiên bản app",
"server_info_box_app_version": "Phiên bản ứng dụng",
"server_info_box_server_url": "URL máy chủ",
"server_offline": "Máy chủ ngoại tuyến",
"server_online": "Phiên bản",
@@ -2228,7 +2228,7 @@
"theme_setting_primary_color_title": "Màu chủ đạo",
"theme_setting_system_primary_color_title": "Dùng màu hệ thống",
"theme_setting_system_theme_switch": "Tự động (Giống thiết bị)",
"theme_setting_theme_subtitle": "Chọn cài đặt giao diện app",
"theme_setting_theme_subtitle": "Chọn cài đặt giao diện ứng dụng",
"theme_setting_three_stage_loading_subtitle": "Tải ba giai đoạn có thể tăng tốc độ tải ảnh nhưng sẽ tốn dữ liệu mạng đáng kể",
"theme_setting_three_stage_loading_title": "Bật tải ba giai đoạn",
"then": "Tiếp theo",
@@ -2276,7 +2276,7 @@
"troubleshoot": "Khắc phục sự cố",
"type": "Loại",
"unable_to_change_pin_code": "Thay đổi mã PIN thất bại",
"unable_to_check_version": "Không thể kiểm tra phiên bản app hoặc máy chủ",
"unable_to_check_version": "Không thể kiểm tra phiên bản ứng dụng hoặc máy chủ",
"unable_to_setup_pin_code": "Thiết lập mã PIN thất bại",
"unarchive": "Bỏ lưu trữ",
"unarchive_action_prompt": "{count} đã bỏ khỏi Lưu trữ",

View File

@@ -87,6 +87,7 @@
"external_libraries_page_description": "管理外部媒體庫嘅頁面",
"face_detection": "人面偵測",
"face_detection_description": "使用機器學習偵測項目中嘅臉孔。對於影片,只係會分析縮圖。「重新整理」會重新處理所有嘅項目;「重設」就會額外清除目前嘅臉孔資料;「加入排程」會將尚未處理嘅項目加入序列。完成「臉孔偵測」後,偵測到嘅臉孔將會加入「臉孔辨識」排程,並歸類到而家或者新嘅人物群組。",
"facial_recognition_job_description": "將偵測到嘅臉孔歸類為人物。此步驟會在臉孔偵測完成後執行。「重設」會重新對所有嘅臉孔進行分群;「加入排程」就會將未指派人物嘅臉孔加入序列。",
"failed_job_command": "執行{job}任務嘅{command}指令失敗",
"force_delete_user_warning": "警告:呢個會立即刪除用戶同埋佢所有嘅檔案。呢個係無法撤銷嘅動作,而且刪除嘅檔案將冇辦法復原。",
"image_format": "格式",
@@ -99,6 +100,7 @@
"image_prefer_embedded_preview": "偏向嵌入預覽",
"image_prefer_embedded_preview_setting_description": "喺可用嘅時候將 RAW 相片中的內嵌預覽作為影像處理嘅輸入來源。雖然呢個設定可以令到部分相片嘅色彩更加準確,但預覽品質取決於相機,且影像可能會出現較多壓縮瑕疵。",
"image_prefer_wide_gamut": "傾向廣色域",
"image_prefer_wide_gamut_setting_description": "使用 Display P3 製作縮圖可以更好地保留廣色域影像嘅鮮豔度但係喺舊裝置同舊版瀏覽器上影像呈現嘅效果可能會有所唔同。sRGB 影像會保留為 sRGB以避免色彩偏移。",
"image_preview_description": "中等尺寸嘅圖片,用嚟檢視單一影像同埋機器學習",
"image_preview_title": "預覽設定",
"image_progressive": "逐步",

View File

@@ -1635,7 +1635,7 @@
"notifications": "通知",
"notifications_setting_description": "管理通知",
"oauth": "OAuth",
"obtainium_configurator": "Obtainium配置器",
"obtainium_configurator": "Obtainium 配置器",
"obtainium_configurator_instructions": "使用 Obtainium 直接从 Immich 的 GitHub 发布页安装和更新 Android 应用。请创建一个 API 密钥并选择一个版本,以生成你的 Obtainium 配置链接",
"ocr": "OCR",
"official_immich_resources": "Immich官方资源",
@@ -1710,7 +1710,7 @@
"permanent_deletion_warning_setting_description": "永久删除照片/视频时显示警告",
"permanently_delete": "永久删除",
"permanently_delete_assets_count": "永久删除{count, plural, one {个项目} other {个项目}}",
"permanently_delete_assets_prompt": "确定要永久删除 {count, plural, one {此项目吗?} other {这<b>#</b>个项目吗?}}这也会将{count, plural, one {其} other {它们}}从所属相簿中移除。",
"permanently_delete_assets_prompt": "确定要永久删除 {count, plural, one {此项目吗?} other {这 <b>#</b> 个项目吗?}}这也会将{count, plural, one {其} other {它们}}从所属相簿中移除。",
"permanently_deleted_asset": "永久删除的项目",
"permanently_deleted_assets_count": "已永久删除{count, plural, one {#个项目} other {#个项目}}",
"permission": "权限",

View File

@@ -54,7 +54,7 @@
"authentication_settings_description": "管理密碼、OAuth 與其他驗證設定",
"authentication_settings_disable_all": "您確定要停用所有登入方式嗎?這將導致完全無法登入。",
"authentication_settings_reenable": "如需重新啟用,請使用 <link>伺服器指令</link>。",
"background_task_job": "背景工作",
"background_task_job": "背景任務",
"backup_database": "建立資料庫備份",
"backup_database_enable_description": "啟用資料庫備份",
"backup_keep_last_amount": "保留先前備份的數量",
@@ -63,7 +63,7 @@
"backup_onboarding_3_description": "您資料的總備份份數,包括原始檔案在內。這包括 1 份異地備份與 2 份本機副本。",
"backup_onboarding_description": "建議採用 <backblaze-link>3-2-1 備份策略</backblaze-link> 來保護您的資料。您應保留已上傳的相片/影片副本,以及 Immich 資料庫,以建立完整的備份方案。",
"backup_onboarding_footer": "更多備份 Immich 資訊,請參考 <link>說明文件</link>。",
"backup_onboarding_parts_title": "遵從備份原則 3-2-1",
"backup_onboarding_parts_title": "3-2-1 備份包含",
"backup_onboarding_title": "備份",
"backup_settings": "資料庫備份設定",
"backup_settings_description": "管理資料庫備份設定。",
@@ -81,20 +81,20 @@
"cron_expression_description": "使用 Cron 格式設定掃描間隔。更多資訊請參閱 <link>Crontab Guru</link>",
"cron_expression_presets": "Cron 表達式預設值",
"disable_login": "停用登入",
"duplicate_detection_job_description": "依靠智慧搜尋。對項目執行機器學習偵測相似圖片",
"duplicate_detection_job_description": "針對資產執行機器學習偵測相似圖片。需依賴「智慧搜尋」功能",
"exclusion_pattern_description": "排除模式可讓您在掃描媒體庫時忽略特定檔案與資料夾。若某些資料夾包含您不想匯入的檔案(例如 RAW 檔),此功能將非常有用。",
"export_config_as_json_description": "將目前系統設定下載為 JSON 檔案",
"external_libraries_page_description": "管理外部媒體庫頁面",
"face_detection": "臉孔偵測",
"face_detection_description": "使用機器學習偵測項目中的臉孔。對於影片,僅會分析縮圖。「重新整理」會重新處理所有項目;「重設」則會額外清除目前的臉孔資料;「加入排程」會將尚未處理的項目加入列。完成「臉孔偵測」後,偵測到的臉孔將加入「臉孔辨識」排程,並歸類至現有或新的人物群組。",
"facial_recognition_job_description": "將偵測到的臉孔歸類為人物。此步驟會在臉孔偵測完成後執行。「重設」會重新對所有臉孔進行分群;「加入排程」則會將尚未指派人物的臉孔加入列。",
"face_detection_description": "使用機器學習偵測項目中的臉孔。對於影片,僅會分析縮圖。「重新整理」會重新處理所有項目;「重設」則會額外清除目前的臉孔資料;「加入排程」會將尚未處理的項目加入列。完成「臉孔偵測」後,偵測到的臉孔將加入「臉孔辨識」排程,並歸類至現有或新的人物群組。",
"facial_recognition_job_description": "將偵測到的臉孔歸類為人物。此步驟會在臉孔偵測完成後執行。「重設」會重新對所有臉孔進行分群;「加入排程」則會將尚未指派人物的臉孔加入列。",
"failed_job_command": "{job} 任務的 {command} 指令執行失敗",
"force_delete_user_warning": "警告:這將立即刪除使用者及其所有項目。此動作無法復原,且無法找回已刪除的檔案。",
"image_format": "格式",
"image_format_description": "WebP 能產生相對於 JPEG 更小的檔案,但編碼速度較慢。",
"image_fullsize_description": "移除中繼資料的大尺寸影像,在放大圖片時使用",
"image_fullsize_enabled": "啟用大尺寸影像產生",
"image_fullsize_enabled_description": "為非網頁友善格式產生大尺寸相片。啟用「偏好內嵌預覽」時,系統將直接使用內嵌預覽而不進行轉碼,不影響 JPEG 等網頁友善格式。",
"image_fullsize_enabled_description": "為非網頁相容格式產生大尺寸相片。啟用「偏好內嵌預覽」時,系統將直接使用內嵌預覽而不進行轉碼,不影響 JPEG 等網頁相容格式。",
"image_fullsize_quality_description": "大尺寸影像品質,範圍為 1 到 100。數值越高品質越好但檔案也會越大。",
"image_fullsize_title": "大尺寸影像設定",
"image_prefer_embedded_preview": "偏好內嵌預覽",
@@ -104,14 +104,14 @@
"image_preview_description": "中等尺寸影像(不含中繼資料),用於檢視單一項目與機器學習",
"image_preview_quality_description": "預覽品質範圍為 1 到 100。數值越高品質越好但檔案也會更大並可能降低應用程式的回應速度。設定過低的數值可能會影響機器學習的品質。",
"image_preview_title": "預覽設定",
"image_progressive": "逐步",
"image_progressive_description": "對 JPEG 影像進行漸進式編碼,以實現漸進式載入顯示。這不會影響 WebP 影像。",
"image_progressive": "漸進式",
"image_progressive_description": "對 JPEG 影像進行漸進式編碼,以達成漸進式載入顯示。這不會影響 WebP 影像。",
"image_quality": "品質",
"image_resolution": "解析度",
"image_resolution_description": "較高的解析度能保留更多細節,但編碼時間會更長、檔案大小會更大,並可能降低應用程式的回應速度。",
"image_settings": "圖片設定",
"image_settings_description": "管理產生的影像品質與解析度",
"image_thumbnail_description": "移除中繼資料的小型縮圖,用於檢視大量相片時使用,例如主時間軸",
"image_thumbnail_description": "移除中繼資料的小型縮圖,用於檢視多張相片(如主時間軸",
"image_thumbnail_quality_description": "縮圖品質範圍為 1 到 100。數值越高品質越好但檔案也會更大並可能降低應用程式的回應速度。",
"image_thumbnail_title": "縮圖設定",
"import_config_from_json_description": "透過上傳 JSON 設定檔匯入系統設定",
@@ -160,7 +160,7 @@
"machine_learning_facial_recognition": "人臉辨識",
"machine_learning_facial_recognition_description": "偵測、辨識並對圖片中的臉孔分類",
"machine_learning_facial_recognition_model": "人臉辨識模型",
"machine_learning_facial_recognition_model_description": "模型順序由大至小排列。較大的模型速度較慢且佔用較多記憶體,但果較佳。請注意,更換模型後必須對所有影像重新執行「臉孔偵測」任務。",
"machine_learning_facial_recognition_model_description": "模型順序由大至小排列。較大的模型速度較慢且佔用較多記憶體,但果較佳。請注意,更換模型後必須對所有影像重新執行「臉孔偵測」任務。",
"machine_learning_facial_recognition_setting": "啟用人臉辨識",
"machine_learning_facial_recognition_setting_description": "若停用,影像將不會進行人臉辨識編碼,且「探索」頁面的「人物」區塊將不會顯示任何內容。",
"machine_learning_max_detection_distance": "偵測距離上限",
@@ -173,7 +173,7 @@
"machine_learning_min_recognized_faces_description": "建立新人物所需的最低已辨識臉孔數量。提高此數值可讓臉孔辨識更精確,但同時會增加臉孔未被指派給任何人物的可能性。",
"machine_learning_ocr": "文字辨識(OCR)",
"machine_learning_ocr_description": "使用機器學習辨識影像中的文字",
"machine_learning_ocr_enabled": "啟用OCR",
"machine_learning_ocr_enabled": "啟用 OCR",
"machine_learning_ocr_enabled_description": "若停用,影像將不會進行文字辨識。",
"machine_learning_ocr_max_resolution": "最大解析度",
"machine_learning_ocr_max_resolution_description": "解析度高於此值的預覽影像將在保持長寬比的情況下調整大小。數值越高越準確,但處理時間更長且會佔用更多記憶體。",
@@ -181,7 +181,7 @@
"machine_learning_ocr_min_detection_score_description": "文字偵測的最低信心分數,範圍為 0 - 1。較低的數值會偵測到更多文字但可能導致誤判。",
"machine_learning_ocr_min_recognition_score": "最低辨識分數",
"machine_learning_ocr_min_score_recognition_description": "已偵測文字的最低辨識信心分數,範圍為 0 - 1。較低的數值會辨識出更多文字但可能導致誤判。",
"machine_learning_ocr_model": "OCR模型",
"machine_learning_ocr_model": "OCR 模型",
"machine_learning_ocr_model_description": "伺服器模型比行動裝置模型更準確,但處理時間較長且會佔用更多記憶體。",
"machine_learning_settings": "機器學習設定",
"machine_learning_settings_description": "管理機器學習的功能和設定",
@@ -257,7 +257,7 @@
"notification_email_password_description": "用於與電子郵件伺服器驗證的密碼",
"notification_email_port_description": "電子郵件伺服器的連接埠(例如 25、465 或 587",
"notification_email_secure": "SMTPS",
"notification_email_secure_description": "使用SMTPS基於TLSSMTP",
"notification_email_secure_description": "使用 SMTPS基於 TLSSMTP",
"notification_email_sent_test_email_button": "傳送測試電子郵件並儲存",
"notification_email_setting_description": "寄送電子郵件通知的設定",
"notification_email_test_email": "傳送測試電子郵件",
@@ -281,11 +281,11 @@
"oauth_role_claim_description": "根據此宣告的存在,自動授予管理員權限。該宣告的值可以是 'user' 或 'admin'。",
"oauth_settings": "OAuth",
"oauth_settings_description": "管理 OAuth 登入設定",
"oauth_settings_more_details": "瞭解此功能,請參閱 <link>說明</link>。",
"oauth_settings_more_details": "若要瞭解此功能的詳細資訊,請參閱 <link>說明文件</link>。",
"oauth_storage_label_claim": "儲存標籤宣告",
"oauth_storage_label_claim_description": "自動將使用者的儲存標籤定為此宣告之值。",
"oauth_storage_label_claim_description": "自動將使用者的儲存標籤定為此宣告之值。",
"oauth_storage_quota_claim": "儲存配額宣告",
"oauth_storage_quota_claim_description": "自動將使用者的儲存配額定為此宣告之值。",
"oauth_storage_quota_claim_description": "自動將使用者的儲存配額定為此宣告之值。",
"oauth_storage_quota_default": "預設儲存配額GiB",
"oauth_storage_quota_default_description": "未提供宣告時所使用的配額GiB。",
"oauth_timeout": "請求逾時",
@@ -297,8 +297,8 @@
"paths_validated_successfully": "所有路徑驗證成功",
"person_cleanup_job": "清理人物",
"queue_details": "佇列資訊",
"queues": "任務排程",
"queues_page_description": "序列排程管理界面",
"queues": "任務佇列",
"queues_page_description": "管理員任務佇列頁面",
"quota_size_gib": "配額大小GiB",
"refreshing_all_libraries": "正在重新整理所有媒體庫",
"registration": "管理者註冊",
@@ -320,8 +320,8 @@
"server_welcome_message": "歡迎訊息",
"server_welcome_message_description": "在登入頁面顯示的訊息。",
"settings_page_description": "管理設定頁面",
"sidecar_job": "側接檔案中繼資料",
"sidecar_job_description": "從檔案系統偵測或同步側接檔案中繼資料",
"sidecar_job": "附屬檔案中繼資料",
"sidecar_job_description": "從檔案系統偵測或同步附屬檔案中繼資料",
"slideshow_duration_description": "每張圖片放映的秒數",
"smart_search_job_description": "對項目執行機器學習以支援智慧搜尋",
"storage_template_date_time_description": "檔案的建立時間戳會用於日期與時間資訊",
@@ -428,8 +428,8 @@
"user_delete_delay": "<b>{user}</b> 的帳號和項目會在 {delay, plural, one {# 天} other {# 天}} 後永久刪除。",
"user_delete_delay_settings": "延後刪除",
"user_delete_delay_settings_description": "自移除後起算的天數,逾期後將永久刪除使用者帳號與項目。使用者刪除作業會在每日午夜執行,以檢查符合刪除條件的帳號。此設定的變更將在下一次執行時生效。",
"user_delete_immediately": "<b>{user}</b> 的帳號與項目將 <b>立即</b> 排入永久刪除列。",
"user_delete_immediately_checkbox": "立即將使用者與項目排入永久刪除列",
"user_delete_immediately": "<b>{user}</b> 的帳號與項目將 <b>立即</b> 排入永久刪除列。",
"user_delete_immediately_checkbox": "立即將使用者與項目排入永久刪除列",
"user_details": "使用者詳細資訊",
"user_management": "使用者管理",
"user_password_has_been_reset": "使用者密碼已重設:",
@@ -493,7 +493,7 @@
"album_selected": "已選取相簿",
"album_share_no_users": "看來您與所有使用者共享了這本相簿,或沒有其他使用者可供分享。",
"album_summary": "相簿摘要",
"album_updated": "更新相簿時",
"album_updated": "相簿已更新",
"album_updated_setting_description": "當共享相簿有新項目時用電子郵件通知我",
"album_upload_assets": "從您的電腦上傳檔案並加入相簿",
"album_user_left": "離開 {album}",
@@ -508,11 +508,11 @@
"album_viewer_page_share_add_users": "邀請其他人",
"album_with_link_access": "任何擁有連結的人皆可檢視此相簿中的相片與人物。",
"albums": "相簿",
"albums_count": "{count, plural, one {{count, number} 相簿} other {{count, number} 相簿}}",
"albums_count": "{count, plural, one {{count, number} 相簿} other {{count, number} 相簿}}",
"albums_default_sort_order": "預設相簿排序",
"albums_default_sort_order_description": "建立新相簿時要初始化項目排序方式。",
"albums_feature_description": "可共享給其他使用者的項目集合。",
"albums_on_device_count": "此裝置有 ({count}) 相簿",
"albums_on_device_count": "此裝置有 ({count}) 相簿",
"albums_selected": "{count, plural, one {已選取 # 本相簿} other {已選取 # 本相簿}}",
"all": "全部",
"all_albums": "所有相簿",
@@ -591,7 +591,7 @@
"assets_added_to_album_count": "已將 {count, plural, one {# 個項目} other {# 個項目}}加入至相簿",
"assets_added_to_albums_count": "已將 {assetTotal, plural, other {# 個項目}} 新增至 {albumTotal, plural, other {# 本相簿}}",
"assets_cannot_be_added_to_album_count": "無法將 {count, plural, one {項目} other {項目}} 加入至相簿",
"assets_cannot_be_added_to_albums": "無法將 {count, plural, other {# 個項目}} 加入任何相簿",
"assets_cannot_be_added_to_albums": "無法將 {count, plural, one {項目} other {項目}} 加入任何相簿",
"assets_count": "{count, plural, one {# 個項目} other {# 個項目}}",
"assets_deleted_permanently": "已永久刪除 {count} 個項目",
"assets_deleted_permanently_from_server": "已從 Immich 伺服器中永久移除 {count} 個項目",
@@ -608,7 +608,7 @@
"assets_trashed_count": "已將 {count, plural, one {# 個項目} other {# 個項目}}移至垃圾桶",
"assets_trashed_from_server": "已從 Immich 伺服器將 {count} 個項目移至垃圾桶",
"assets_were_part_of_album_count": "{count, plural, one {該項目已} other {這些項目已}}在相簿中",
"assets_were_part_of_albums_count": "{count, plural, one {} other {個}}項目已被儲存在相簿中",
"assets_were_part_of_albums_count": "{count, plural, one {該項目已} other {這些項目已}}存在相簿中",
"authorized_devices": "已授權裝置",
"automatic_endpoint_switching_subtitle": "當可用時,透過指定的 Wi-Fi 在本機連線,其他情況則使用替代連線",
"automatic_endpoint_switching_title": "自動 URL 切換",
@@ -622,7 +622,7 @@
"backup": "備份",
"backup_album_selection_page_albums_device": "裝置上的相簿({count}",
"backup_album_selection_page_albums_tap": "點一下以選取,點兩下以排除",
"backup_album_selection_page_assets_scatter": "項目可以分散在多相簿中,因此在備份過程中可以選擇納入或排除相簿。",
"backup_album_selection_page_assets_scatter": "項目可以分散在多相簿中,因此在備份過程中可以選擇納入或排除相簿。",
"backup_album_selection_page_select_albums": "選取相簿",
"backup_album_selection_page_selection_info": "選取資訊",
"backup_album_selection_page_total_assets": "總不重複項目數",
@@ -761,11 +761,11 @@
"city": "城市",
"cleanup_confirm_description": "Immich 發現有 {count} 個項目(建立於 {date} 之前)已安全備份至伺服器。是否要從此裝置中刪除本機副本?",
"cleanup_confirm_prompt_title": "從此裝置刪除?",
"cleanup_deleted_assets": "已將{count}項目移到裝置的垃圾桶裡",
"cleanup_deleted_assets": "已將 {count}項目移到裝置的垃圾桶裡",
"cleanup_deleting": "正在移動到垃圾桶...",
"cleanup_found_assets": "找到{count}件已上傳的項目",
"cleanup_found_assets_with_size": "找到{count}件,總共({size})已上傳的項目",
"cleanup_icloud_shared_albums_excluded": "iCloud共享相簿被排除於搜尋之外",
"cleanup_found_assets": "找到 {count} 件已上傳的項目",
"cleanup_found_assets_with_size": "找到 {count} 件,總共 ({size}) 已上傳的項目",
"cleanup_icloud_shared_albums_excluded": "iCloud 共享相簿被排除於搜尋之外",
"cleanup_no_assets_found": "找不到符合上述條件的項目。釋放空間功能僅能移除已備份至伺服器的項目",
"cleanup_preview_title": "{count} 項需要移除的項目",
"cleanup_step3_description": "掃描符合日期與儲存設定的已備份項目。",
@@ -782,8 +782,8 @@
"client_cert_import": "匯入",
"client_cert_import_success_msg": "已匯入用戶端憑證",
"client_cert_invalid_msg": "無效的憑證檔案或密碼錯誤",
"client_cert_password_message": "請輸入此證的密碼",
"client_cert_password_title": "證密碼",
"client_cert_password_message": "請輸入此證的密碼",
"client_cert_password_title": "證密碼",
"client_cert_remove_msg": "用戶端憑證已移除",
"client_cert_subtitle": "僅支援 PKCS12 (.p12, .pfx) 格式。憑證匯入與移除僅可在登入前進行",
"client_cert_title": "SSL 用戶端憑證 [實驗性]",
@@ -794,7 +794,7 @@
"color": "顏色",
"color_theme": "色彩主題",
"command": "命令",
"command_palette_prompt": "快速尋頁面動作或指令",
"command_palette_prompt": "快速尋頁面動作或指令",
"command_palette_to_close": "關閉",
"command_palette_to_navigate": "輸入",
"command_palette_to_select": "選擇",
@@ -837,7 +837,7 @@
"copy_password": "複製密碼",
"copy_to_clipboard": "複製到剪貼簿",
"country": "國家",
"cover": "封面",
"cover": "填滿",
"covers": "封面",
"create": "建立",
"create_album": "建立相簿",
@@ -849,9 +849,12 @@
"create_link_to_share": "建立分享連結",
"create_link_to_share_description": "持有連結的人皆可檢視所選項目",
"create_new": "新增",
"create_new_face": "建立新臉孔",
"create_new_person": "建立新人物",
"create_new_person_hint": "將選取的項目指派給新的人物",
"create_new_user": "建立新使用者",
"create_person": "建立人物",
"create_person_subtitle": "為所選臉孔新增名字以建立和標記新人物",
"create_shared_album_page_share_add_assets": "新增項目",
"create_shared_album_page_share_select_photos": "選取相片",
"create_shared_link": "建立分享連結",
@@ -892,7 +895,7 @@
"day": "日",
"days": "日",
"deduplicate_all": "刪除所有重複項目",
"default_locale": "默認語言",
"default_locale": "預設語言",
"default_locale_description": "使用你的瀏覽器區域以格式日期和數字",
"delete": "刪除",
"delete_action_confirmation_message": "您確定要刪除此項目嗎?此動作會將該項目移至伺服器的垃圾桶,並詢問您是否要在本機同步刪除",
@@ -965,7 +968,7 @@
"download_waiting_to_retry": "等待重試",
"downloading": "下載中",
"downloading_asset_filename": "正在下載項目 {filename}",
"downloading_from_icloud": "正從iCloud下載",
"downloading_from_icloud": "正從 iCloud 下載",
"downloading_media": "正在下載媒體",
"drop_files_to_upload": "將檔案拖放到任何位置以上傳",
"duplicates": "重複項目",
@@ -1010,8 +1013,8 @@
"editor_handle_edge": "{edge, select, top {頂部} bottom {底部} left {左側} right {右側} other {某個}} 邊緣的控制手柄",
"editor_orientation": "方向",
"editor_reset_all_changes": "重設變更",
"editor_rotate_left": "逆時針旋轉90度",
"editor_rotate_right": "順時針旋轉90度",
"editor_rotate_left": "逆時針旋轉 90 度",
"editor_rotate_right": "順時針旋轉 90 度",
"email": "電子郵件",
"email_notifications": "電子郵件通知",
"empty_folder": "這個資料夾是空的",
@@ -1022,7 +1025,7 @@
"enable_biometric_auth_description": "輸入您的 PIN 碼以啟用生物辨識驗證",
"enabled": "已啟用",
"end_date": "結束日期",
"enqueued": "已排入列",
"enqueued": "已排入列",
"enter_wifi_name": "輸入 Wi-Fi 名稱",
"enter_your_pin_code": "輸入您的 PIN 碼",
"enter_your_pin_code_subtitle": "輸入您的 PIN 碼以存取「已鎖定」資料夾",
@@ -1344,11 +1347,11 @@
"ios_debug_info_processing_ran_at": "於 {dateTime} 執行處理",
"items_count": "{count, plural, one {# 個項目} other {# 個項目}}",
"jobs": "任務",
"json_editor": "JSON編輯器",
"json_error": "JSON錯誤",
"json_editor": "JSON 編輯器",
"json_error": "JSON 錯誤",
"keep": "保留",
"keep_albums": "保留相簿",
"keep_albums_count": "保留{count} {count, plural, one {相簿} other {相簿}}",
"keep_albums_count": "保留{count} {count, plural, one {相簿} other {相簿}}",
"keep_all": "全部保留",
"keep_description": "選擇執行釋放空間時要保留在裝置上的項目。",
"keep_favorites": "保留最愛的相片",
@@ -1356,7 +1359,7 @@
"keep_on_device_hint": "選擇保留在裝置上的相片",
"keep_this_delete_others": "保留這個,刪除其他",
"keeping": "保留:{items}",
"kept_this_deleted_others": "保留這個項目並刪除{count, plural, one {# asset} other {# assets}}",
"kept_this_deleted_others": "保留這個項目並刪除{count, plural, one {# 個項目} other {# 個項目}}",
"keyboard_shortcuts": "鍵盤快捷鍵",
"language": "語言",
"language_no_results_subtitle": "試著調整您的搜尋詞彙",
@@ -1390,7 +1393,7 @@
"like": "喜歡",
"like_deleted": "已取消喜歡",
"link_motion_video": "連結動態影片",
"link_to_docs": "請參閱 <link>文案</link> 以獲取更多信息。",
"link_to_docs": "請參閱 <link>說明文件</link> 以獲取更多資訊。",
"link_to_oauth": "連結 OAuth",
"linked_oauth_account": "已連結 OAuth 帳號",
"list": "清單",
@@ -1399,7 +1402,7 @@
"local": "本機",
"local_asset_cast_failed": "無法投放未上傳至伺服器的項目",
"local_assets": "本機項目",
"local_id": "本地ID",
"local_id": "本地 ID",
"local_media_summary": "本機媒體摘要",
"local_network": "本機網路",
"local_network_sheet_info": "當使用指定的 Wi-Fi 網路時,應用程式將透過此網址連線至伺服器",
@@ -1488,14 +1491,14 @@
"manage_your_devices": "管理已登入的裝置",
"manage_your_oauth_connection": "管理您的 OAuth 連結",
"map": "地圖",
"map_assets_in_bounds": "{count, plural, one {# 張相片} other {# 張相片}}",
"map_assets_in_bounds": "{count, plural, =0 {此區域沒有相片} one {# 張相片} other {# 張相片}}",
"map_cannot_get_user_location": "無法取得使用者位置",
"map_location_dialog_yes": "確定",
"map_location_picker_page_use_location": "使用此位置",
"map_location_service_disabled_content": "需要啟用定位服務才能顯示您目前位置相關的項目。要現在啟用嗎?",
"map_location_service_disabled_title": "定位服務已停用",
"map_marker_for_images": "在 {city}、{country} 拍攝影像的地圖記",
"map_marker_with_image": "帶有影像的地圖記",
"map_marker_for_images": "在 {city}、{country} 拍攝影像的地圖記",
"map_marker_with_image": "帶有影像的地圖記",
"map_no_location_permission_content": "需要位置權限才能顯示與您目前位置相關的項目。要現在就授予位置權限嗎?",
"map_no_location_permission_title": "沒有位置權限",
"map_settings": "地圖設定",
@@ -1553,7 +1556,7 @@
"move_to_locked_folder_confirmation": "這些相片與影片將從所有相簿中移除,且僅能從「已鎖定」資料夾中檢視",
"move_up": "向上移動",
"moved_to_archive": "已封存 {count, plural, one {# 個項目} other {# 個項目}}",
"moved_to_library": "已移動 {count, plural, one {# 個項目} other {# 個項目}} 至相簿",
"moved_to_library": "已移動 {count, plural, one {# 個項目} other {# 個項目}} 至媒體庫",
"moved_to_trash": "已丟進垃圾桶",
"multiselect_grid_edit_date_time_err_read_only": "唯讀項目的日期無法編輯,已略過",
"multiselect_grid_edit_gps_err_read_only": "唯讀項目的位置資訊無法編輯,已略過",
@@ -1562,12 +1565,12 @@
"name": "名稱",
"name_or_nickname": "名稱或暱稱",
"name_required": "名稱是必填項",
"navigate": "導",
"navigate": "導",
"navigate_to_time": "跳轉至指定時間",
"network_requirement_photos_upload": "使用行動網路流量備份相片",
"network_requirement_videos_upload": "使用行動網路流量備份影片",
"network_requirements": "網路要求",
"network_requirements_updated": "網路需求已變更,正在重設備份列",
"network_requirements_updated": "網路需求已變更,正在重設備份列",
"networking_settings": "網路",
"networking_subtitle": "管理伺服器端點設定",
"never": "永不失效",
@@ -1591,7 +1594,7 @@
"no_albums_message": "建立相簿來整理相片和影片",
"no_albums_with_name_yet": "看來還沒有這個名字的相簿。",
"no_albums_yet": "看來您還沒有任何相簿。",
"no_archived_assets_message": "將相片與影片封存後,就不會顯示在「相片」視圖中",
"no_archived_assets_message": "將相片與影片封存後,就不會顯示在「相片」頁面中",
"no_assets_message": "按這裡上傳您的第一張相片",
"no_assets_to_show": "無項目展示",
"no_cast_devices_found": "找不到 Google Cast 裝置",
@@ -1707,7 +1710,7 @@
"permanent_deletion_warning_setting_description": "在永久刪除檔案時顯示警告",
"permanently_delete": "永久刪除",
"permanently_delete_assets_count": "永久刪除 {count, plural, one {檔案} other {檔案}}",
"permanently_delete_assets_prompt": "確定要永久刪除 {count, plural, other {這 <b>#</b> 個檔案?}}這樣{count, plural, one {它} other {它們}}也會從自己所在的相簿中消失。",
"permanently_delete_assets_prompt": "確定要永久刪除 {count, plural, one {這個檔案?} other {這 <b>#</b> 個檔案?}}這樣{count, plural, one {它} other {它們}}也會從自己所在的相簿中消失。",
"permanently_deleted_asset": "永久刪除的檔案",
"permanently_deleted_assets_count": "永久刪除的 {count, plural, one {# 個檔案} other {# 個檔案}}",
"permission": "權限",
@@ -1770,7 +1773,7 @@
"profile_drawer_app_logs": "紀錄",
"profile_drawer_client_server_up_to_date": "用戶端與伺服器版本皆為最新",
"profile_drawer_github": "GitHub",
"profile_drawer_readonly_mode": "唯讀模式已啟用。長按使用者個人圖示即可退出。",
"profile_drawer_readonly_mode": "唯讀模式已啟用。長按使用者個人圖示即可關閉。",
"profile_image_of_user": "{user} 的個人資料圖片",
"profile_picture_set": "已設定個人資料圖片。",
"public_album": "公開相簿",
@@ -1812,7 +1815,7 @@
"rate_asset": "項目評分",
"rating": "評星",
"rating_clear": "清除評等",
"rating_count": "{count, plural, =0 {Unrated} other {# 星}}",
"rating_count": "{count, plural, =0 {未評分} one {# 星} other {# 星}}",
"rating_description": "在資訊面板中顯示 EXIF 評等",
"reaction_options": "反應選項",
"read_changelog": "閱覽更新紀錄",
@@ -1832,15 +1835,15 @@
"recently_taken_page_title": "最近拍攝",
"refresh": "重新整理",
"refresh_encoded_videos": "重新整理已編碼的影片",
"refresh_faces": "重整面部資料",
"refresh_faces": "重新整理臉孔資料",
"refresh_metadata": "重新整理中繼資料",
"refresh_thumbnails": "重新整理縮圖",
"refreshed": "重新整理完畢",
"refreshes_every_file": "重新讀取所有現有與新增檔案",
"refreshing_encoded_video": "正在重新整理已編碼的影片",
"refreshing_faces": "重整面部資料",
"refreshing_faces": "正在重新整理臉孔資料",
"refreshing_metadata": "正在重新整理中繼資料",
"regenerating_thumbnails": "重新產生縮圖",
"regenerating_thumbnails": "正在重新產生縮圖",
"remote": "遠端",
"remote_assets": "遠端項目",
"remote_media_summary": "遠端媒體摘要",
@@ -1869,8 +1872,8 @@
"removed_memory": "已移除記憶",
"removed_photo_from_memory": "已從記憶中移除相片",
"removed_tagged_assets": "已移除 {count, plural, one {# 個檔案} other {# 個檔案}}的標籤",
"rename": "名",
"repair": "糾正",
"rename": "重新命名",
"repair": "修復",
"repair_no_results_message": "未被追蹤及遺失的檔案會顯示在這裡",
"replace_with_upload": "用上傳的檔案取代",
"repository": "儲存庫",
@@ -1886,9 +1889,9 @@
"reset_pin_code_with_password": "您可隨時使用您的密碼來重設 PIN 碼",
"reset_sqlite": "重設 SQLite 資料庫",
"reset_sqlite_clear_app_data": "清除資料",
"reset_sqlite_confirmation": "確定要重設所有資料嗎?你的所有設將被重設,且你會被登出。",
"reset_sqlite_confirmation_note": "注意:你需要在清除資料後重新開啟應用。",
"reset_sqlite_done": "資料已清除。請重啟Immich及重新登入。",
"reset_sqlite_confirmation": "確定要重設所有資料嗎?你的所有設將被重設,且你會被登出。",
"reset_sqlite_confirmation_note": "注意:你需要在清除資料後重新開啟 App。",
"reset_sqlite_done": "資料已清除。請重啟 Immich 及重新登入。",
"reset_sqlite_success": "已成功重設 SQLite 資料庫",
"reset_to_default": "重設為預設值",
"resolution": "解析度",
@@ -1910,7 +1913,7 @@
"running": "執行中",
"save": "儲存",
"save_to_gallery": "儲存到相簿",
"saved": "已存",
"saved": "已存",
"saved_api_key": "已儲存 API 金鑰",
"saved_profile": "已儲存個人資料",
"saved_settings": "已儲存設定",
@@ -1930,9 +1933,9 @@
"search_by_description_example": "在沙壩的健行之日",
"search_by_filename": "依檔名或副檔名搜尋",
"search_by_filename_example": "如 IMG_1234.JPG 或 PNG",
"search_by_ocr": "透過OCR搜尋",
"search_by_ocr": "透過 OCR 搜尋",
"search_by_ocr_example": "拿鐵",
"search_camera_lens_model": "蒐索鏡頭型號...",
"search_camera_lens_model": "搜尋鏡頭型號...",
"search_camera_make": "搜尋相機製造商…",
"search_camera_model": "搜尋相機型號…",
"search_city": "搜尋城市…",
@@ -1949,7 +1952,7 @@
"search_filter_location_title": "選擇位置",
"search_filter_media_type": "媒體類型",
"search_filter_media_type_title": "選擇媒體類型",
"search_filter_ocr": "透過OCR搜尋",
"search_filter_ocr": "透過 OCR 搜尋",
"search_filter_people_title": "選擇人物",
"search_filter_star_rating": "評分",
"search_filter_tags_title": "選擇標籤",
@@ -1978,7 +1981,7 @@
"search_settings": "搜尋設定",
"search_state": "搜尋地區…",
"search_suggestion_list_smart_search_hint_1": "智慧搜尋功能預設已啟用,如要搜尋中繼資料,請使用語法 ",
"search_suggestion_list_smart_search_hint_2": "m:您的搜尋關鍵",
"search_suggestion_list_smart_search_hint_2": "m:您的搜尋關鍵",
"search_tags": "搜尋標籤...",
"search_timezone": "搜尋時區…",
"search_type": "搜尋類型",
@@ -2032,7 +2035,7 @@
"set_profile_picture": "設定個人資料圖片",
"set_slideshow_to_fullscreen": "以全螢幕放映幻燈片",
"set_stack_primary_asset": "設定堆疊的首要項目",
"setting_image_navigation_enable_subtitle": "開啟後以觸碰幕左/右邊緣區域的方式切換上/下圖片。",
"setting_image_navigation_enable_subtitle": "開啟後以觸碰幕左/右邊緣區域的方式切換上/下圖片。",
"setting_image_navigation_enable_title": "點擊切換",
"setting_image_navigation_title": "圖片導引",
"setting_image_viewer_help": "詳細資訊檢視器會依序載入小型縮圖、中等尺寸預覽圖(若啟用),最後載入原始相片。",
@@ -2132,7 +2135,7 @@
"show_all_people": "顯示所有人物",
"show_and_hide_people": "顯示與隱藏人物",
"show_file_location": "顯示檔案位置",
"show_gallery": "顯示畫廊",
"show_gallery": "顯示媒體庫",
"show_hidden_people": "顯示隱藏的人物",
"show_in_timeline": "在時間軸中顯示",
"show_in_timeline_setting_description": "在您的時間軸中顯示這位使用者的相片和影片",
@@ -2149,7 +2152,7 @@
"show_supporter_badge": "支持者徽章",
"show_supporter_badge_description": "顯示支持者徽章",
"show_text_recognition": "顯示文字辨識",
"show_text_search_menu": "顯示文字蒐索選單",
"show_text_search_menu": "顯示文字搜尋選單",
"shuffle": "隨機排序",
"sidebar": "側邊欄",
"sidebar_display_description": "在側邊欄中顯示連結",
@@ -2214,6 +2217,7 @@
"tag": "標籤",
"tag_assets": "標記檔案",
"tag_created": "已建立標籤:{tag}",
"tag_face": "標記臉孔",
"tag_feature_description": "以邏輯標記要旨分類瀏覽相片和影片",
"tag_not_found_question": "找不到標籤?<link>建立新標籤。</link>",
"tag_people": "標籤人物",
@@ -2264,11 +2268,11 @@
"trash_all": "全部丟掉",
"trash_count": "丟掉 {count, number} 個檔案",
"trash_delete_asset": "將檔案丟進垃圾桶 / 刪除",
"trash_emptied": "已清空回收桶",
"trash_emptied": "已清空垃圾桶",
"trash_no_results_message": "垃圾桶中的相片和影片將顯示在這裡。",
"trash_page_delete_all": "刪除全部",
"trash_page_empty_trash_dialog_content": "是否清空回收桶?這些項目將被從 Immich 中永久刪除",
"trash_page_info": "回收桶中項目將在 {days} 天後永久刪除",
"trash_page_empty_trash_dialog_content": "是否清空垃圾桶?這些項目將被從 Immich 中永久刪除",
"trash_page_info": "垃圾桶中項目將在 {days} 天後永久刪除",
"trash_page_no_assets": "暫無已刪除項目",
"trash_page_restore_all": "全部還原",
"trash_page_select_assets_btn": "選擇項目",
@@ -2281,7 +2285,7 @@
"trigger_person_recognized": "已辨識人物",
"trigger_person_recognized_description": "偵測到人物時觸發",
"trigger_type": "觸發類型",
"troubleshoot": "疑難解",
"troubleshoot": "疑難解",
"type": "類型",
"unable_to_change_pin_code": "無法變更 PIN 碼",
"unable_to_check_version": "無法檢查應用程式或伺服器版本",
@@ -2313,7 +2317,7 @@
"unstack_action_prompt": "{count} 個取消堆疊",
"unstacked_assets_count": "已解除堆疊 {count, plural, other {# 個檔案}}",
"unsupported_field_type": "不支援的欄位類型",
"unsupported_file_type": "不支 {type} 類型的檔案,無法上傳 {file} 文件。",
"unsupported_file_type": "不支 {type} 類型的檔案,無法上傳 {file} 檔案。",
"untagged": "無標籤",
"untitled_workflow": "未命名工作流程",
"up_next": "下一個",
@@ -2371,7 +2375,7 @@
"version_history": "版本紀錄",
"version_history_item": "{date} 安裝了 {version}",
"video": "影片",
"video_hover_setting": "標停留時播放影片縮圖",
"video_hover_setting": "標停留時播放影片縮圖",
"video_hover_setting_description": "當滑鼠停在項目上時播放影片縮圖。即使停用此功能,仍可透過將滑鼠停在播放圖示上來開始播放。",
"videos": "影片",
"videos_count": "{count, plural, other {# 部影片}}",

View File

@@ -1,6 +1,6 @@
[project]
name = "immich-ml"
version = "2.7.0"
version = "2.7.5"
description = ""
authors = [{ name = "Hau Tran", email = "alex.tran1502@gmail.com" }]
requires-python = ">=3.11,<4.0"
@@ -11,7 +11,7 @@ dependencies = [
"gunicorn>=21.1.0",
"huggingface-hub>=0.20.1,<1.0",
"insightface>=0.7.3,<1.0",
"numpy>=2.3.4",
"numpy<2.4.0",
"opencv-python-headless>=4.7.0.72,<5.0",
"orjson>=3.9.5",
"pillow>=12.1.1,<12.2",

152
machine-learning/uv.lock generated
View File

@@ -898,7 +898,7 @@ wheels = [
[[package]]
name = "immich-ml"
version = "2.7.0"
version = "2.7.5"
source = { editable = "." }
dependencies = [
{ name = "aiocache" },
@@ -987,7 +987,7 @@ requires-dist = [
{ name = "gunicorn", specifier = ">=21.1.0" },
{ name = "huggingface-hub", specifier = ">=0.20.1,<1.0" },
{ name = "insightface", specifier = ">=0.7.3,<1.0" },
{ name = "numpy", specifier = ">=2.3.4" },
{ name = "numpy", specifier = "<2.4.0" },
{ name = "onnxruntime", marker = "extra == 'armnn'", specifier = ">=1.23.2,<2" },
{ name = "onnxruntime", marker = "extra == 'cpu'", specifier = ">=1.23.2,<2" },
{ name = "onnxruntime", marker = "extra == 'rknn'", specifier = ">=1.23.2,<2" },
@@ -1519,81 +1519,83 @@ wheels = [
[[package]]
name = "numpy"
version = "2.4.2"
version = "2.3.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/fd/0005efbd0af48e55eb3c7208af93f2862d4b1a56cd78e84309a2d959208d/numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae", size = 20723651, upload-time = "2026-01-31T23:13:10.135Z" }
sdist = { url = "https://files.pythonhosted.org/packages/76/65/21b3bc86aac7b8f2862db1e808f1ea22b028e30a225a34a5ede9bf8678f2/numpy-2.3.5.tar.gz", hash = "sha256:784db1dcdab56bf0517743e746dfb0f885fc68d948aba86eeec2cba234bdf1c0", size = 20584950, upload-time = "2025-11-16T22:52:42.067Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d3/44/71852273146957899753e69986246d6a176061ea183407e95418c2aa4d9a/numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825", size = 16955478, upload-time = "2026-01-31T23:10:25.623Z" },
{ url = "https://files.pythonhosted.org/packages/74/41/5d17d4058bd0cd96bcbd4d9ff0fb2e21f52702aab9a72e4a594efa18692f/numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1", size = 14965467, upload-time = "2026-01-31T23:10:28.186Z" },
{ url = "https://files.pythonhosted.org/packages/49/48/fb1ce8136c19452ed15f033f8aee91d5defe515094e330ce368a0647846f/numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7", size = 5475172, upload-time = "2026-01-31T23:10:30.848Z" },
{ url = "https://files.pythonhosted.org/packages/40/a9/3feb49f17bbd1300dd2570432961f5c8a4ffeff1db6f02c7273bd020a4c9/numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73", size = 6805145, upload-time = "2026-01-31T23:10:32.352Z" },
{ url = "https://files.pythonhosted.org/packages/3f/39/fdf35cbd6d6e2fcad42fcf85ac04a85a0d0fbfbf34b30721c98d602fd70a/numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1", size = 15966084, upload-time = "2026-01-31T23:10:34.502Z" },
{ url = "https://files.pythonhosted.org/packages/1b/46/6fa4ea94f1ddf969b2ee941290cca6f1bfac92b53c76ae5f44afe17ceb69/numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32", size = 16899477, upload-time = "2026-01-31T23:10:37.075Z" },
{ url = "https://files.pythonhosted.org/packages/09/a1/2a424e162b1a14a5bd860a464ab4e07513916a64ab1683fae262f735ccd2/numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390", size = 17323429, upload-time = "2026-01-31T23:10:39.704Z" },
{ url = "https://files.pythonhosted.org/packages/ce/a2/73014149ff250628df72c58204822ac01d768697913881aacf839ff78680/numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413", size = 18635109, upload-time = "2026-01-31T23:10:41.924Z" },
{ url = "https://files.pythonhosted.org/packages/6c/0c/73e8be2f1accd56df74abc1c5e18527822067dced5ec0861b5bb882c2ce0/numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda", size = 6237915, upload-time = "2026-01-31T23:10:45.26Z" },
{ url = "https://files.pythonhosted.org/packages/76/ae/e0265e0163cf127c24c3969d29f1c4c64551a1e375d95a13d32eab25d364/numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695", size = 12607972, upload-time = "2026-01-31T23:10:47.021Z" },
{ url = "https://files.pythonhosted.org/packages/29/a5/c43029af9b8014d6ea157f192652c50042e8911f4300f8f6ed3336bf437f/numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3", size = 10485763, upload-time = "2026-01-31T23:10:50.087Z" },
{ url = "https://files.pythonhosted.org/packages/51/6e/6f394c9c77668153e14d4da83bcc247beb5952f6ead7699a1a2992613bea/numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a", size = 16667963, upload-time = "2026-01-31T23:10:52.147Z" },
{ url = "https://files.pythonhosted.org/packages/1f/f8/55483431f2b2fd015ae6ed4fe62288823ce908437ed49db5a03d15151678/numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1", size = 14693571, upload-time = "2026-01-31T23:10:54.789Z" },
{ url = "https://files.pythonhosted.org/packages/2f/20/18026832b1845cdc82248208dd929ca14c9d8f2bac391f67440707fff27c/numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e", size = 5203469, upload-time = "2026-01-31T23:10:57.343Z" },
{ url = "https://files.pythonhosted.org/packages/7d/33/2eb97c8a77daaba34eaa3fa7241a14ac5f51c46a6bd5911361b644c4a1e2/numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27", size = 6550820, upload-time = "2026-01-31T23:10:59.429Z" },
{ url = "https://files.pythonhosted.org/packages/b1/91/b97fdfd12dc75b02c44e26c6638241cc004d4079a0321a69c62f51470c4c/numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548", size = 15663067, upload-time = "2026-01-31T23:11:01.291Z" },
{ url = "https://files.pythonhosted.org/packages/f5/c6/a18e59f3f0b8071cc85cbc8d80cd02d68aa9710170b2553a117203d46936/numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f", size = 16619782, upload-time = "2026-01-31T23:11:03.669Z" },
{ url = "https://files.pythonhosted.org/packages/b7/83/9751502164601a79e18847309f5ceec0b1446d7b6aa12305759b72cf98b2/numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460", size = 17013128, upload-time = "2026-01-31T23:11:05.913Z" },
{ url = "https://files.pythonhosted.org/packages/61/c4/c4066322256ec740acc1c8923a10047818691d2f8aec254798f3dd90f5f2/numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba", size = 18345324, upload-time = "2026-01-31T23:11:08.248Z" },
{ url = "https://files.pythonhosted.org/packages/ab/af/6157aa6da728fa4525a755bfad486ae7e3f76d4c1864138003eb84328497/numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f", size = 5960282, upload-time = "2026-01-31T23:11:10.497Z" },
{ url = "https://files.pythonhosted.org/packages/92/0f/7ceaaeaacb40567071e94dbf2c9480c0ae453d5bb4f52bea3892c39dc83c/numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85", size = 12314210, upload-time = "2026-01-31T23:11:12.176Z" },
{ url = "https://files.pythonhosted.org/packages/2f/a3/56c5c604fae6dd40fa2ed3040d005fca97e91bd320d232ac9931d77ba13c/numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa", size = 10220171, upload-time = "2026-01-31T23:11:14.684Z" },
{ url = "https://files.pythonhosted.org/packages/a1/22/815b9fe25d1d7ae7d492152adbc7226d3eff731dffc38fe970589fcaaa38/numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c", size = 16663696, upload-time = "2026-01-31T23:11:17.516Z" },
{ url = "https://files.pythonhosted.org/packages/09/f0/817d03a03f93ba9c6c8993de509277d84e69f9453601915e4a69554102a1/numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979", size = 14688322, upload-time = "2026-01-31T23:11:19.883Z" },
{ url = "https://files.pythonhosted.org/packages/da/b4/f805ab79293c728b9a99438775ce51885fd4f31b76178767cfc718701a39/numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98", size = 5198157, upload-time = "2026-01-31T23:11:22.375Z" },
{ url = "https://files.pythonhosted.org/packages/74/09/826e4289844eccdcd64aac27d13b0fd3f32039915dd5b9ba01baae1f436c/numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef", size = 6546330, upload-time = "2026-01-31T23:11:23.958Z" },
{ url = "https://files.pythonhosted.org/packages/19/fb/cbfdbfa3057a10aea5422c558ac57538e6acc87ec1669e666d32ac198da7/numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7", size = 15660968, upload-time = "2026-01-31T23:11:25.713Z" },
{ url = "https://files.pythonhosted.org/packages/04/dc/46066ce18d01645541f0186877377b9371b8fa8017fa8262002b4ef22612/numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499", size = 16607311, upload-time = "2026-01-31T23:11:28.117Z" },
{ url = "https://files.pythonhosted.org/packages/14/d9/4b5adfc39a43fa6bf918c6d544bc60c05236cc2f6339847fc5b35e6cb5b0/numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb", size = 17012850, upload-time = "2026-01-31T23:11:30.888Z" },
{ url = "https://files.pythonhosted.org/packages/b7/20/adb6e6adde6d0130046e6fdfb7675cc62bc2f6b7b02239a09eb58435753d/numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7", size = 18334210, upload-time = "2026-01-31T23:11:33.214Z" },
{ url = "https://files.pythonhosted.org/packages/78/0e/0a73b3dff26803a8c02baa76398015ea2a5434d9b8265a7898a6028c1591/numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110", size = 5958199, upload-time = "2026-01-31T23:11:35.385Z" },
{ url = "https://files.pythonhosted.org/packages/43/bc/6352f343522fcb2c04dbaf94cb30cca6fd32c1a750c06ad6231b4293708c/numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622", size = 12310848, upload-time = "2026-01-31T23:11:38.001Z" },
{ url = "https://files.pythonhosted.org/packages/6e/8d/6da186483e308da5da1cc6918ce913dcfe14ffde98e710bfeff2a6158d4e/numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71", size = 10221082, upload-time = "2026-01-31T23:11:40.392Z" },
{ url = "https://files.pythonhosted.org/packages/25/a1/9510aa43555b44781968935c7548a8926274f815de42ad3997e9e83680dd/numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262", size = 14815866, upload-time = "2026-01-31T23:11:42.495Z" },
{ url = "https://files.pythonhosted.org/packages/36/30/6bbb5e76631a5ae46e7923dd16ca9d3f1c93cfa8d4ed79a129814a9d8db3/numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913", size = 5325631, upload-time = "2026-01-31T23:11:44.7Z" },
{ url = "https://files.pythonhosted.org/packages/46/00/3a490938800c1923b567b3a15cd17896e68052e2145d8662aaf3e1ffc58f/numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab", size = 6646254, upload-time = "2026-01-31T23:11:46.341Z" },
{ url = "https://files.pythonhosted.org/packages/d3/e9/fac0890149898a9b609caa5af7455a948b544746e4b8fe7c212c8edd71f8/numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82", size = 15720138, upload-time = "2026-01-31T23:11:48.082Z" },
{ url = "https://files.pythonhosted.org/packages/ea/5c/08887c54e68e1e28df53709f1893ce92932cc6f01f7c3d4dc952f61ffd4e/numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f", size = 16655398, upload-time = "2026-01-31T23:11:50.293Z" },
{ url = "https://files.pythonhosted.org/packages/4d/89/253db0fa0e66e9129c745e4ef25631dc37d5f1314dad2b53e907b8538e6d/numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554", size = 17079064, upload-time = "2026-01-31T23:11:52.927Z" },
{ url = "https://files.pythonhosted.org/packages/2a/d5/cbade46ce97c59c6c3da525e8d95b7abe8a42974a1dc5c1d489c10433e88/numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257", size = 18379680, upload-time = "2026-01-31T23:11:55.22Z" },
{ url = "https://files.pythonhosted.org/packages/40/62/48f99ae172a4b63d981babe683685030e8a3df4f246c893ea5c6ef99f018/numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657", size = 6082433, upload-time = "2026-01-31T23:11:58.096Z" },
{ url = "https://files.pythonhosted.org/packages/07/38/e054a61cfe48ad9f1ed0d188e78b7e26859d0b60ef21cd9de4897cdb5326/numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b", size = 12451181, upload-time = "2026-01-31T23:11:59.782Z" },
{ url = "https://files.pythonhosted.org/packages/6e/a4/a05c3a6418575e185dd84d0b9680b6bb2e2dc3e4202f036b7b4e22d6e9dc/numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1", size = 10290756, upload-time = "2026-01-31T23:12:02.438Z" },
{ url = "https://files.pythonhosted.org/packages/18/88/b7df6050bf18fdcfb7046286c6535cabbdd2064a3440fca3f069d319c16e/numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b", size = 16663092, upload-time = "2026-01-31T23:12:04.521Z" },
{ url = "https://files.pythonhosted.org/packages/25/7a/1fee4329abc705a469a4afe6e69b1ef7e915117747886327104a8493a955/numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000", size = 14698770, upload-time = "2026-01-31T23:12:06.96Z" },
{ url = "https://files.pythonhosted.org/packages/fb/0b/f9e49ba6c923678ad5bc38181c08ac5e53b7a5754dbca8e581aa1a56b1ff/numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1", size = 5208562, upload-time = "2026-01-31T23:12:09.632Z" },
{ url = "https://files.pythonhosted.org/packages/7d/12/d7de8f6f53f9bb76997e5e4c069eda2051e3fe134e9181671c4391677bb2/numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74", size = 6543710, upload-time = "2026-01-31T23:12:11.969Z" },
{ url = "https://files.pythonhosted.org/packages/09/63/c66418c2e0268a31a4cf8a8b512685748200f8e8e8ec6c507ce14e773529/numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a", size = 15677205, upload-time = "2026-01-31T23:12:14.33Z" },
{ url = "https://files.pythonhosted.org/packages/5d/6c/7f237821c9642fb2a04d2f1e88b4295677144ca93285fd76eff3bcba858d/numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325", size = 16611738, upload-time = "2026-01-31T23:12:16.525Z" },
{ url = "https://files.pythonhosted.org/packages/c2/a7/39c4cdda9f019b609b5c473899d87abff092fc908cfe4d1ecb2fcff453b0/numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909", size = 17028888, upload-time = "2026-01-31T23:12:19.306Z" },
{ url = "https://files.pythonhosted.org/packages/da/b3/e84bb64bdfea967cc10950d71090ec2d84b49bc691df0025dddb7c26e8e3/numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a", size = 18339556, upload-time = "2026-01-31T23:12:21.816Z" },
{ url = "https://files.pythonhosted.org/packages/88/f5/954a291bc1192a27081706862ac62bb5920fbecfbaa302f64682aa90beed/numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a", size = 6006899, upload-time = "2026-01-31T23:12:24.14Z" },
{ url = "https://files.pythonhosted.org/packages/05/cb/eff72a91b2efdd1bc98b3b8759f6a1654aa87612fc86e3d87d6fe4f948c4/numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75", size = 12443072, upload-time = "2026-01-31T23:12:26.33Z" },
{ url = "https://files.pythonhosted.org/packages/37/75/62726948db36a56428fce4ba80a115716dc4fad6a3a4352487f8bb950966/numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05", size = 10494886, upload-time = "2026-01-31T23:12:28.488Z" },
{ url = "https://files.pythonhosted.org/packages/36/2f/ee93744f1e0661dc267e4b21940870cabfae187c092e1433b77b09b50ac4/numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308", size = 14818567, upload-time = "2026-01-31T23:12:30.709Z" },
{ url = "https://files.pythonhosted.org/packages/a7/24/6535212add7d76ff938d8bdc654f53f88d35cddedf807a599e180dcb8e66/numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef", size = 5328372, upload-time = "2026-01-31T23:12:32.962Z" },
{ url = "https://files.pythonhosted.org/packages/5e/9d/c48f0a035725f925634bf6b8994253b43f2047f6778a54147d7e213bc5a7/numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d", size = 6649306, upload-time = "2026-01-31T23:12:34.797Z" },
{ url = "https://files.pythonhosted.org/packages/81/05/7c73a9574cd4a53a25907bad38b59ac83919c0ddc8234ec157f344d57d9a/numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8", size = 15722394, upload-time = "2026-01-31T23:12:36.565Z" },
{ url = "https://files.pythonhosted.org/packages/35/fa/4de10089f21fc7d18442c4a767ab156b25c2a6eaf187c0db6d9ecdaeb43f/numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5", size = 16653343, upload-time = "2026-01-31T23:12:39.188Z" },
{ url = "https://files.pythonhosted.org/packages/b8/f9/d33e4ffc857f3763a57aa85650f2e82486832d7492280ac21ba9efda80da/numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e", size = 17078045, upload-time = "2026-01-31T23:12:42.041Z" },
{ url = "https://files.pythonhosted.org/packages/c8/b8/54bdb43b6225badbea6389fa038c4ef868c44f5890f95dd530a218706da3/numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a", size = 18380024, upload-time = "2026-01-31T23:12:44.331Z" },
{ url = "https://files.pythonhosted.org/packages/a5/55/6e1a61ded7af8df04016d81b5b02daa59f2ea9252ee0397cb9f631efe9e5/numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443", size = 6153937, upload-time = "2026-01-31T23:12:47.229Z" },
{ url = "https://files.pythonhosted.org/packages/45/aa/fa6118d1ed6d776b0983f3ceac9b1a5558e80df9365b1c3aa6d42bf9eee4/numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236", size = 12631844, upload-time = "2026-01-31T23:12:48.997Z" },
{ url = "https://files.pythonhosted.org/packages/32/0a/2ec5deea6dcd158f254a7b372fb09cfba5719419c8d66343bab35237b3fb/numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181", size = 10565379, upload-time = "2026-01-31T23:12:51.345Z" },
{ url = "https://files.pythonhosted.org/packages/f4/f8/50e14d36d915ef64d8f8bc4a087fc8264d82c785eda6711f80ab7e620335/numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082", size = 16833179, upload-time = "2026-01-31T23:12:53.5Z" },
{ url = "https://files.pythonhosted.org/packages/17/17/809b5cad63812058a8189e91a1e2d55a5a18fd04611dbad244e8aeae465c/numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a", size = 14889755, upload-time = "2026-01-31T23:12:55.933Z" },
{ url = "https://files.pythonhosted.org/packages/3e/ea/181b9bcf7627fc8371720316c24db888dcb9829b1c0270abf3d288b2e29b/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920", size = 5399500, upload-time = "2026-01-31T23:12:58.671Z" },
{ url = "https://files.pythonhosted.org/packages/33/9f/413adf3fc955541ff5536b78fcf0754680b3c6d95103230252a2c9408d23/numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821", size = 6714252, upload-time = "2026-01-31T23:13:00.518Z" },
{ url = "https://files.pythonhosted.org/packages/91/da/643aad274e29ccbdf42ecd94dafe524b81c87bcb56b83872d54827f10543/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb", size = 15797142, upload-time = "2026-01-31T23:13:02.219Z" },
{ url = "https://files.pythonhosted.org/packages/66/27/965b8525e9cb5dc16481b30a1b3c21e50c7ebf6e9dbd48d0c4d0d5089c7e/numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0", size = 16727979, upload-time = "2026-01-31T23:13:04.62Z" },
{ url = "https://files.pythonhosted.org/packages/de/e5/b7d20451657664b07986c2f6e3be564433f5dcaf3482d68eaecd79afaf03/numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0", size = 12502577, upload-time = "2026-01-31T23:13:07.08Z" },
{ url = "https://files.pythonhosted.org/packages/43/77/84dd1d2e34d7e2792a236ba180b5e8fcc1e3e414e761ce0253f63d7f572e/numpy-2.3.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:de5672f4a7b200c15a4127042170a694d4df43c992948f5e1af57f0174beed10", size = 17034641, upload-time = "2025-11-16T22:49:19.336Z" },
{ url = "https://files.pythonhosted.org/packages/2a/ea/25e26fa5837106cde46ae7d0b667e20f69cbbc0efd64cba8221411ab26ae/numpy-2.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acfd89508504a19ed06ef963ad544ec6664518c863436306153e13e94605c218", size = 12528324, upload-time = "2025-11-16T22:49:22.582Z" },
{ url = "https://files.pythonhosted.org/packages/4d/1a/e85f0eea4cf03d6a0228f5c0256b53f2df4bc794706e7df019fc622e47f1/numpy-2.3.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:ffe22d2b05504f786c867c8395de703937f934272eb67586817b46188b4ded6d", size = 5356872, upload-time = "2025-11-16T22:49:25.408Z" },
{ url = "https://files.pythonhosted.org/packages/5c/bb/35ef04afd567f4c989c2060cde39211e4ac5357155c1833bcd1166055c61/numpy-2.3.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:872a5cf366aec6bb1147336480fef14c9164b154aeb6542327de4970282cd2f5", size = 6893148, upload-time = "2025-11-16T22:49:27.549Z" },
{ url = "https://files.pythonhosted.org/packages/f2/2b/05bbeb06e2dff5eab512dfc678b1cc5ee94d8ac5956a0885c64b6b26252b/numpy-2.3.5-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3095bdb8dd297e5920b010e96134ed91d852d81d490e787beca7e35ae1d89cf7", size = 14557282, upload-time = "2025-11-16T22:49:30.964Z" },
{ url = "https://files.pythonhosted.org/packages/65/fb/2b23769462b34398d9326081fad5655198fcf18966fcb1f1e49db44fbf31/numpy-2.3.5-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8cba086a43d54ca804ce711b2a940b16e452807acebe7852ff327f1ecd49b0d4", size = 16897903, upload-time = "2025-11-16T22:49:34.191Z" },
{ url = "https://files.pythonhosted.org/packages/ac/14/085f4cf05fc3f1e8aa95e85404e984ffca9b2275a5dc2b1aae18a67538b8/numpy-2.3.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6cf9b429b21df6b99f4dee7a1218b8b7ffbbe7df8764dc0bd60ce8a0708fed1e", size = 16341672, upload-time = "2025-11-16T22:49:37.2Z" },
{ url = "https://files.pythonhosted.org/packages/6f/3b/1f73994904142b2aa290449b3bb99772477b5fd94d787093e4f24f5af763/numpy-2.3.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:396084a36abdb603546b119d96528c2f6263921c50df3c8fd7cb28873a237748", size = 18838896, upload-time = "2025-11-16T22:49:39.727Z" },
{ url = "https://files.pythonhosted.org/packages/cd/b9/cf6649b2124f288309ffc353070792caf42ad69047dcc60da85ee85fea58/numpy-2.3.5-cp311-cp311-win32.whl", hash = "sha256:b0c7088a73aef3d687c4deef8452a3ac7c1be4e29ed8bf3b366c8111128ac60c", size = 6563608, upload-time = "2025-11-16T22:49:42.079Z" },
{ url = "https://files.pythonhosted.org/packages/aa/44/9fe81ae1dcc29c531843852e2874080dc441338574ccc4306b39e2ff6e59/numpy-2.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:a414504bef8945eae5f2d7cb7be2d4af77c5d1cb5e20b296c2c25b61dff2900c", size = 13078442, upload-time = "2025-11-16T22:49:43.99Z" },
{ url = "https://files.pythonhosted.org/packages/6d/a7/f99a41553d2da82a20a2f22e93c94f928e4490bb447c9ff3c4ff230581d3/numpy-2.3.5-cp311-cp311-win_arm64.whl", hash = "sha256:0cd00b7b36e35398fa2d16af7b907b65304ef8bb4817a550e06e5012929830fa", size = 10458555, upload-time = "2025-11-16T22:49:47.092Z" },
{ url = "https://files.pythonhosted.org/packages/44/37/e669fe6cbb2b96c62f6bbedc6a81c0f3b7362f6a59230b23caa673a85721/numpy-2.3.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74ae7b798248fe62021dbf3c914245ad45d1a6b0cb4a29ecb4b31d0bfbc4cc3e", size = 16733873, upload-time = "2025-11-16T22:49:49.84Z" },
{ url = "https://files.pythonhosted.org/packages/c5/65/df0db6c097892c9380851ab9e44b52d4f7ba576b833996e0080181c0c439/numpy-2.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3888d9ff7c14604052b2ca5535a30216aa0a58e948cdd3eeb8d3415f638769", size = 12259838, upload-time = "2025-11-16T22:49:52.863Z" },
{ url = "https://files.pythonhosted.org/packages/5b/e1/1ee06e70eb2136797abe847d386e7c0e830b67ad1d43f364dd04fa50d338/numpy-2.3.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:612a95a17655e213502f60cfb9bf9408efdc9eb1d5f50535cc6eb365d11b42b5", size = 5088378, upload-time = "2025-11-16T22:49:55.055Z" },
{ url = "https://files.pythonhosted.org/packages/6d/9c/1ca85fb86708724275103b81ec4cf1ac1d08f465368acfc8da7ab545bdae/numpy-2.3.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3101e5177d114a593d79dd79658650fe28b5a0d8abeb8ce6f437c0e6df5be1a4", size = 6628559, upload-time = "2025-11-16T22:49:57.371Z" },
{ url = "https://files.pythonhosted.org/packages/74/78/fcd41e5a0ce4f3f7b003da85825acddae6d7ecb60cf25194741b036ca7d6/numpy-2.3.5-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b973c57ff8e184109db042c842423ff4f60446239bd585a5131cc47f06f789d", size = 14250702, upload-time = "2025-11-16T22:49:59.632Z" },
{ url = "https://files.pythonhosted.org/packages/b6/23/2a1b231b8ff672b4c450dac27164a8b2ca7d9b7144f9c02d2396518352eb/numpy-2.3.5-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0d8163f43acde9a73c2a33605353a4f1bc4798745a8b1d73183b28e5b435ae28", size = 16606086, upload-time = "2025-11-16T22:50:02.127Z" },
{ url = "https://files.pythonhosted.org/packages/a0/c5/5ad26fbfbe2012e190cc7d5003e4d874b88bb18861d0829edc140a713021/numpy-2.3.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:51c1e14eb1e154ebd80e860722f9e6ed6ec89714ad2db2d3aa33c31d7c12179b", size = 16025985, upload-time = "2025-11-16T22:50:04.536Z" },
{ url = "https://files.pythonhosted.org/packages/d2/fa/dd48e225c46c819288148d9d060b047fd2a6fb1eb37eae25112ee4cb4453/numpy-2.3.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b46b4ec24f7293f23adcd2d146960559aaf8020213de8ad1909dba6c013bf89c", size = 18542976, upload-time = "2025-11-16T22:50:07.557Z" },
{ url = "https://files.pythonhosted.org/packages/05/79/ccbd23a75862d95af03d28b5c6901a1b7da4803181513d52f3b86ed9446e/numpy-2.3.5-cp312-cp312-win32.whl", hash = "sha256:3997b5b3c9a771e157f9aae01dd579ee35ad7109be18db0e85dbdbe1de06e952", size = 6285274, upload-time = "2025-11-16T22:50:10.746Z" },
{ url = "https://files.pythonhosted.org/packages/2d/57/8aeaf160312f7f489dea47ab61e430b5cb051f59a98ae68b7133ce8fa06a/numpy-2.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:86945f2ee6d10cdfd67bcb4069c1662dd711f7e2a4343db5cecec06b87cf31aa", size = 12782922, upload-time = "2025-11-16T22:50:12.811Z" },
{ url = "https://files.pythonhosted.org/packages/78/a6/aae5cc2ca78c45e64b9ef22f089141d661516856cf7c8a54ba434576900d/numpy-2.3.5-cp312-cp312-win_arm64.whl", hash = "sha256:f28620fe26bee16243be2b7b874da327312240a7cdc38b769a697578d2100013", size = 10194667, upload-time = "2025-11-16T22:50:16.16Z" },
{ url = "https://files.pythonhosted.org/packages/db/69/9cde09f36da4b5a505341180a3f2e6fadc352fd4d2b7096ce9778db83f1a/numpy-2.3.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d0f23b44f57077c1ede8c5f26b30f706498b4862d3ff0a7298b8411dd2f043ff", size = 16728251, upload-time = "2025-11-16T22:50:19.013Z" },
{ url = "https://files.pythonhosted.org/packages/79/fb/f505c95ceddd7027347b067689db71ca80bd5ecc926f913f1a23e65cf09b/numpy-2.3.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa5bc7c5d59d831d9773d1170acac7893ce3a5e130540605770ade83280e7188", size = 12254652, upload-time = "2025-11-16T22:50:21.487Z" },
{ url = "https://files.pythonhosted.org/packages/78/da/8c7738060ca9c31b30e9301ee0cf6c5ffdbf889d9593285a1cead337f9a5/numpy-2.3.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:ccc933afd4d20aad3c00bcef049cb40049f7f196e0397f1109dba6fed63267b0", size = 5083172, upload-time = "2025-11-16T22:50:24.562Z" },
{ url = "https://files.pythonhosted.org/packages/a4/b4/ee5bb2537fb9430fd2ef30a616c3672b991a4129bb1c7dcc42aa0abbe5d7/numpy-2.3.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:afaffc4393205524af9dfa400fa250143a6c3bc646c08c9f5e25a9f4b4d6a903", size = 6622990, upload-time = "2025-11-16T22:50:26.47Z" },
{ url = "https://files.pythonhosted.org/packages/95/03/dc0723a013c7d7c19de5ef29e932c3081df1c14ba582b8b86b5de9db7f0f/numpy-2.3.5-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c75442b2209b8470d6d5d8b1c25714270686f14c749028d2199c54e29f20b4d", size = 14248902, upload-time = "2025-11-16T22:50:28.861Z" },
{ url = "https://files.pythonhosted.org/packages/f5/10/ca162f45a102738958dcec8023062dad0cbc17d1ab99d68c4e4a6c45fb2b/numpy-2.3.5-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11e06aa0af8c0f05104d56450d6093ee639e15f24ecf62d417329d06e522e017", size = 16597430, upload-time = "2025-11-16T22:50:31.56Z" },
{ url = "https://files.pythonhosted.org/packages/2a/51/c1e29be863588db58175175f057286900b4b3327a1351e706d5e0f8dd679/numpy-2.3.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed89927b86296067b4f81f108a2271d8926467a8868e554eaf370fc27fa3ccaf", size = 16024551, upload-time = "2025-11-16T22:50:34.242Z" },
{ url = "https://files.pythonhosted.org/packages/83/68/8236589d4dbb87253d28259d04d9b814ec0ecce7cb1c7fed29729f4c3a78/numpy-2.3.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51c55fe3451421f3a6ef9a9c1439e82101c57a2c9eab9feb196a62b1a10b58ce", size = 18533275, upload-time = "2025-11-16T22:50:37.651Z" },
{ url = "https://files.pythonhosted.org/packages/40/56/2932d75b6f13465239e3b7b7e511be27f1b8161ca2510854f0b6e521c395/numpy-2.3.5-cp313-cp313-win32.whl", hash = "sha256:1978155dd49972084bd6ef388d66ab70f0c323ddee6f693d539376498720fb7e", size = 6277637, upload-time = "2025-11-16T22:50:40.11Z" },
{ url = "https://files.pythonhosted.org/packages/0c/88/e2eaa6cffb115b85ed7c7c87775cb8bcf0816816bc98ca8dbfa2ee33fe6e/numpy-2.3.5-cp313-cp313-win_amd64.whl", hash = "sha256:00dc4e846108a382c5869e77c6ed514394bdeb3403461d25a829711041217d5b", size = 12779090, upload-time = "2025-11-16T22:50:42.503Z" },
{ url = "https://files.pythonhosted.org/packages/8f/88/3f41e13a44ebd4034ee17baa384acac29ba6a4fcc2aca95f6f08ca0447d1/numpy-2.3.5-cp313-cp313-win_arm64.whl", hash = "sha256:0472f11f6ec23a74a906a00b48a4dcf3849209696dff7c189714511268d103ae", size = 10194710, upload-time = "2025-11-16T22:50:44.971Z" },
{ url = "https://files.pythonhosted.org/packages/13/cb/71744144e13389d577f867f745b7df2d8489463654a918eea2eeb166dfc9/numpy-2.3.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:414802f3b97f3c1eef41e530aaba3b3c1620649871d8cb38c6eaff034c2e16bd", size = 16827292, upload-time = "2025-11-16T22:50:47.715Z" },
{ url = "https://files.pythonhosted.org/packages/71/80/ba9dc6f2a4398e7f42b708a7fdc841bb638d353be255655498edbf9a15a8/numpy-2.3.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5ee6609ac3604fa7780e30a03e5e241a7956f8e2fcfe547d51e3afa5247ac47f", size = 12378897, upload-time = "2025-11-16T22:50:51.327Z" },
{ url = "https://files.pythonhosted.org/packages/2e/6d/db2151b9f64264bcceccd51741aa39b50150de9b602d98ecfe7e0c4bff39/numpy-2.3.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:86d835afea1eaa143012a2d7a3f45a3adce2d7adc8b4961f0b362214d800846a", size = 5207391, upload-time = "2025-11-16T22:50:54.542Z" },
{ url = "https://files.pythonhosted.org/packages/80/ae/429bacace5ccad48a14c4ae5332f6aa8ab9f69524193511d60ccdfdc65fa/numpy-2.3.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:30bc11310e8153ca664b14c5f1b73e94bd0503681fcf136a163de856f3a50139", size = 6721275, upload-time = "2025-11-16T22:50:56.794Z" },
{ url = "https://files.pythonhosted.org/packages/74/5b/1919abf32d8722646a38cd527bc3771eb229a32724ee6ba340ead9b92249/numpy-2.3.5-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1062fde1dcf469571705945b0f221b73928f34a20c904ffb45db101907c3454e", size = 14306855, upload-time = "2025-11-16T22:50:59.208Z" },
{ url = "https://files.pythonhosted.org/packages/a5/87/6831980559434973bebc30cd9c1f21e541a0f2b0c280d43d3afd909b66d0/numpy-2.3.5-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce581db493ea1a96c0556360ede6607496e8bf9b3a8efa66e06477267bc831e9", size = 16657359, upload-time = "2025-11-16T22:51:01.991Z" },
{ url = "https://files.pythonhosted.org/packages/dd/91/c797f544491ee99fd00495f12ebb7802c440c1915811d72ac5b4479a3356/numpy-2.3.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:cc8920d2ec5fa99875b670bb86ddeb21e295cb07aa331810d9e486e0b969d946", size = 16093374, upload-time = "2025-11-16T22:51:05.291Z" },
{ url = "https://files.pythonhosted.org/packages/74/a6/54da03253afcbe7a72785ec4da9c69fb7a17710141ff9ac5fcb2e32dbe64/numpy-2.3.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9ee2197ef8c4f0dfe405d835f3b6a14f5fee7782b5de51ba06fb65fc9b36e9f1", size = 18594587, upload-time = "2025-11-16T22:51:08.585Z" },
{ url = "https://files.pythonhosted.org/packages/80/e9/aff53abbdd41b0ecca94285f325aff42357c6b5abc482a3fcb4994290b18/numpy-2.3.5-cp313-cp313t-win32.whl", hash = "sha256:70b37199913c1bd300ff6e2693316c6f869c7ee16378faf10e4f5e3275b299c3", size = 6405940, upload-time = "2025-11-16T22:51:11.541Z" },
{ url = "https://files.pythonhosted.org/packages/d5/81/50613fec9d4de5480de18d4f8ef59ad7e344d497edbef3cfd80f24f98461/numpy-2.3.5-cp313-cp313t-win_amd64.whl", hash = "sha256:b501b5fa195cc9e24fe102f21ec0a44dffc231d2af79950b451e0d99cea02234", size = 12920341, upload-time = "2025-11-16T22:51:14.312Z" },
{ url = "https://files.pythonhosted.org/packages/bb/ab/08fd63b9a74303947f34f0bd7c5903b9c5532c2d287bead5bdf4c556c486/numpy-2.3.5-cp313-cp313t-win_arm64.whl", hash = "sha256:a80afd79f45f3c4a7d341f13acbe058d1ca8ac017c165d3fa0d3de6bc1a079d7", size = 10262507, upload-time = "2025-11-16T22:51:16.846Z" },
{ url = "https://files.pythonhosted.org/packages/ba/97/1a914559c19e32d6b2e233cf9a6a114e67c856d35b1d6babca571a3e880f/numpy-2.3.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:bf06bc2af43fa8d32d30fae16ad965663e966b1a3202ed407b84c989c3221e82", size = 16735706, upload-time = "2025-11-16T22:51:19.558Z" },
{ url = "https://files.pythonhosted.org/packages/57/d4/51233b1c1b13ecd796311216ae417796b88b0616cfd8a33ae4536330748a/numpy-2.3.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:052e8c42e0c49d2575621c158934920524f6c5da05a1d3b9bab5d8e259e045f0", size = 12264507, upload-time = "2025-11-16T22:51:22.492Z" },
{ url = "https://files.pythonhosted.org/packages/45/98/2fe46c5c2675b8306d0b4a3ec3494273e93e1226a490f766e84298576956/numpy-2.3.5-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:1ed1ec893cff7040a02c8aa1c8611b94d395590d553f6b53629a4461dc7f7b63", size = 5093049, upload-time = "2025-11-16T22:51:25.171Z" },
{ url = "https://files.pythonhosted.org/packages/ce/0e/0698378989bb0ac5f1660c81c78ab1fe5476c1a521ca9ee9d0710ce54099/numpy-2.3.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:2dcd0808a421a482a080f89859a18beb0b3d1e905b81e617a188bd80422d62e9", size = 6626603, upload-time = "2025-11-16T22:51:27Z" },
{ url = "https://files.pythonhosted.org/packages/5e/a6/9ca0eecc489640615642a6cbc0ca9e10df70df38c4d43f5a928ff18d8827/numpy-2.3.5-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727fd05b57df37dc0bcf1a27767a3d9a78cbbc92822445f32cc3436ba797337b", size = 14262696, upload-time = "2025-11-16T22:51:29.402Z" },
{ url = "https://files.pythonhosted.org/packages/c8/f6/07ec185b90ec9d7217a00eeeed7383b73d7e709dae2a9a021b051542a708/numpy-2.3.5-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fffe29a1ef00883599d1dc2c51aa2e5d80afe49523c261a74933df395c15c520", size = 16597350, upload-time = "2025-11-16T22:51:32.167Z" },
{ url = "https://files.pythonhosted.org/packages/75/37/164071d1dde6a1a84c9b8e5b414fa127981bad47adf3a6b7e23917e52190/numpy-2.3.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8f7f0e05112916223d3f438f293abf0727e1181b5983f413dfa2fefc4098245c", size = 16040190, upload-time = "2025-11-16T22:51:35.403Z" },
{ url = "https://files.pythonhosted.org/packages/08/3c/f18b82a406b04859eb026d204e4e1773eb41c5be58410f41ffa511d114ae/numpy-2.3.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2e2eb32ddb9ccb817d620ac1d8dae7c3f641c1e5f55f531a33e8ab97960a75b8", size = 18536749, upload-time = "2025-11-16T22:51:39.698Z" },
{ url = "https://files.pythonhosted.org/packages/40/79/f82f572bf44cf0023a2fe8588768e23e1592585020d638999f15158609e1/numpy-2.3.5-cp314-cp314-win32.whl", hash = "sha256:66f85ce62c70b843bab1fb14a05d5737741e74e28c7b8b5a064de10142fad248", size = 6335432, upload-time = "2025-11-16T22:51:42.476Z" },
{ url = "https://files.pythonhosted.org/packages/a3/2e/235b4d96619931192c91660805e5e49242389742a7a82c27665021db690c/numpy-2.3.5-cp314-cp314-win_amd64.whl", hash = "sha256:e6a0bc88393d65807d751a614207b7129a310ca4fe76a74e5c7da5fa5671417e", size = 12919388, upload-time = "2025-11-16T22:51:45.275Z" },
{ url = "https://files.pythonhosted.org/packages/07/2b/29fd75ce45d22a39c61aad74f3d718e7ab67ccf839ca8b60866054eb15f8/numpy-2.3.5-cp314-cp314-win_arm64.whl", hash = "sha256:aeffcab3d4b43712bb7a60b65f6044d444e75e563ff6180af8f98dd4b905dfd2", size = 10476651, upload-time = "2025-11-16T22:51:47.749Z" },
{ url = "https://files.pythonhosted.org/packages/17/e1/f6a721234ebd4d87084cfa68d081bcba2f5cfe1974f7de4e0e8b9b2a2ba1/numpy-2.3.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:17531366a2e3a9e30762c000f2c43a9aaa05728712e25c11ce1dbe700c53ad41", size = 16834503, upload-time = "2025-11-16T22:51:50.443Z" },
{ url = "https://files.pythonhosted.org/packages/5c/1c/baf7ffdc3af9c356e1c135e57ab7cf8d247931b9554f55c467efe2c69eff/numpy-2.3.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d21644de1b609825ede2f48be98dfde4656aefc713654eeee280e37cadc4e0ad", size = 12381612, upload-time = "2025-11-16T22:51:53.609Z" },
{ url = "https://files.pythonhosted.org/packages/74/91/f7f0295151407ddc9ba34e699013c32c3c91944f9b35fcf9281163dc1468/numpy-2.3.5-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:c804e3a5aba5460c73955c955bdbd5c08c354954e9270a2c1565f62e866bdc39", size = 5210042, upload-time = "2025-11-16T22:51:56.213Z" },
{ url = "https://files.pythonhosted.org/packages/2e/3b/78aebf345104ec50dd50a4d06ddeb46a9ff5261c33bcc58b1c4f12f85ec2/numpy-2.3.5-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:cc0a57f895b96ec78969c34f682c602bf8da1a0270b09bc65673df2e7638ec20", size = 6724502, upload-time = "2025-11-16T22:51:58.584Z" },
{ url = "https://files.pythonhosted.org/packages/02/c6/7c34b528740512e57ef1b7c8337ab0b4f0bddf34c723b8996c675bc2bc91/numpy-2.3.5-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:900218e456384ea676e24ea6a0417f030a3b07306d29d7ad843957b40a9d8d52", size = 14308962, upload-time = "2025-11-16T22:52:01.698Z" },
{ url = "https://files.pythonhosted.org/packages/80/35/09d433c5262bc32d725bafc619e095b6a6651caf94027a03da624146f655/numpy-2.3.5-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a1bea522b25109bf8e6f3027bd810f7c1085c64a0c7ce050c1676ad0ba010b", size = 16655054, upload-time = "2025-11-16T22:52:04.267Z" },
{ url = "https://files.pythonhosted.org/packages/7a/ab/6a7b259703c09a88804fa2430b43d6457b692378f6b74b356155283566ac/numpy-2.3.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04822c00b5fd0323c8166d66c701dc31b7fbd252c100acd708c48f763968d6a3", size = 16091613, upload-time = "2025-11-16T22:52:08.651Z" },
{ url = "https://files.pythonhosted.org/packages/c2/88/330da2071e8771e60d1038166ff9d73f29da37b01ec3eb43cb1427464e10/numpy-2.3.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d6889ec4ec662a1a37eb4b4fb26b6100841804dac55bd9df579e326cdc146227", size = 18591147, upload-time = "2025-11-16T22:52:11.453Z" },
{ url = "https://files.pythonhosted.org/packages/51/41/851c4b4082402d9ea860c3626db5d5df47164a712cb23b54be028b184c1c/numpy-2.3.5-cp314-cp314t-win32.whl", hash = "sha256:93eebbcf1aafdf7e2ddd44c2923e2672e1010bddc014138b229e49725b4d6be5", size = 6479806, upload-time = "2025-11-16T22:52:14.641Z" },
{ url = "https://files.pythonhosted.org/packages/90/30/d48bde1dfd93332fa557cff1972fbc039e055a52021fbef4c2c4b1eefd17/numpy-2.3.5-cp314-cp314t-win_amd64.whl", hash = "sha256:c8a9958e88b65c3b27e22ca2a076311636850b612d6bbfb76e8d156aacde2aaf", size = 13105760, upload-time = "2025-11-16T22:52:17.975Z" },
{ url = "https://files.pythonhosted.org/packages/2d/fd/4b5eb0b3e888d86aee4d198c23acec7d214baaf17ea93c1adec94c9518b9/numpy-2.3.5-cp314-cp314t-win_arm64.whl", hash = "sha256:6203fdf9f3dc5bdaed7319ad8698e685c7a3be10819f41d32a0723e611733b42", size = 10545459, upload-time = "2025-11-16T22:52:20.55Z" },
{ url = "https://files.pythonhosted.org/packages/c6/65/f9dea8e109371ade9c782b4e4756a82edf9d3366bca495d84d79859a0b79/numpy-2.3.5-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f0963b55cdd70fad460fa4c1341f12f976bb26cb66021a5580329bd498988310", size = 16910689, upload-time = "2025-11-16T22:52:23.247Z" },
{ url = "https://files.pythonhosted.org/packages/00/4f/edb00032a8fb92ec0a679d3830368355da91a69cab6f3e9c21b64d0bb986/numpy-2.3.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f4255143f5160d0de972d28c8f9665d882b5f61309d8362fdd3e103cf7bf010c", size = 12457053, upload-time = "2025-11-16T22:52:26.367Z" },
{ url = "https://files.pythonhosted.org/packages/16/a4/e8a53b5abd500a63836a29ebe145fc1ab1f2eefe1cfe59276020373ae0aa/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:a4b9159734b326535f4dd01d947f919c6eefd2d9827466a696c44ced82dfbc18", size = 5285635, upload-time = "2025-11-16T22:52:29.266Z" },
{ url = "https://files.pythonhosted.org/packages/a3/2f/37eeb9014d9c8b3e9c55bc599c68263ca44fdbc12a93e45a21d1d56df737/numpy-2.3.5-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2feae0d2c91d46e59fcd62784a3a83b3fb677fead592ce51b5a6fbb4f95965ff", size = 6801770, upload-time = "2025-11-16T22:52:31.421Z" },
{ url = "https://files.pythonhosted.org/packages/7d/e4/68d2f474df2cb671b2b6c2986a02e520671295647dad82484cde80ca427b/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffac52f28a7849ad7576293c0cb7b9f08304e8f7d738a8cb8a90ec4c55a998eb", size = 14391768, upload-time = "2025-11-16T22:52:33.593Z" },
{ url = "https://files.pythonhosted.org/packages/b8/50/94ccd8a2b141cb50651fddd4f6a48874acb3c91c8f0842b08a6afc4b0b21/numpy-2.3.5-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63c0e9e7eea69588479ebf4a8a270d5ac22763cc5854e9a7eae952a3908103f7", size = 16729263, upload-time = "2025-11-16T22:52:36.369Z" },
{ url = "https://files.pythonhosted.org/packages/2d/ee/346fa473e666fe14c52fcdd19ec2424157290a032d4c41f98127bfb31ac7/numpy-2.3.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f16417ec91f12f814b10bafe79ef77e70113a2f5f7018640e7425ff979253425", size = 12967213, upload-time = "2025-11-16T22:52:39.38Z" },
]
[[package]]

View File

@@ -16,7 +16,7 @@ config_roots = [
[tools]
node = "24.14.1"
flutter = "3.35.7"
pnpm = "10.32.1"
pnpm = "10.33.0"
terragrunt = "0.99.5"
opentofu = "1.11.5"
java = "21.0.2"

View File

@@ -113,8 +113,8 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
implementation 'org.chromium.net:cronet-embedded:143.7445.0'
implementation("androidx.media3:media3-datasource-okhttp:1.9.2")
implementation("androidx.media3:media3-datasource-cronet:1.9.2")
implementation("androidx.media3:media3-datasource-okhttp:1.10.0")
implementation("androidx.media3:media3-datasource-cronet:1.10.0")
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
implementation "androidx.work:work-runtime-ktx:$work_version"
implementation "androidx.concurrent:concurrent-futures:$concurrent_version"

View File

@@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 3042,
"android.injected.version.name" => "2.7.0",
"android.injected.version.code" => 3046,
"android.injected.version.name" => "2.7.5",
}
)
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

@@ -1,5 +1,32 @@
import Foundation
class ImageRequest: @unchecked Sendable {
private struct State: Sendable {
var isCancelled = false
}
let completion: @Sendable (Result<[String: Int64]?, any Error>) -> Void
private let state: Mutex<State>
var isCancelled: Bool {
get {
state.withLock { $0.isCancelled }
}
set {
state.withLock { $0.isCancelled = newValue }
}
}
init(completion: @escaping @Sendable (Result<[String: Int64]?, any Error>) -> Void) {
self.state = Mutex(State())
self.completion = completion
}
func cancel() {
isCancelled = true
}
}
struct RequestRegistry<T: AnyObject & Sendable>: ~Copyable, Sendable {
private let requests = Mutex<[Int64: T]>([:])

View File

@@ -3,21 +3,6 @@ import Flutter
import MobileCoreServices
import Photos
class LocalImageRequest {
weak var operation: Operation?
var isCancelled = false
let callback: (Result<[String: Int64]?, any Error>) -> Void
init(callback: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
self.callback = callback
}
func cancel() {
isCancelled = true
operation?.cancel()
}
}
class LocalImageApiImpl: LocalImageApi {
private static let imageManager = PHImageManager.default()
private static let fetchOptions = {
@@ -36,9 +21,9 @@ class LocalImageApiImpl: LocalImageApi {
return requestOptions
}()
private static let registry = RequestRegistry<LocalImageRequest>()
private static let registry = RequestRegistry<ImageRequest>()
private static var rgbaFormat = vImage_CGImageFormat(
private static let rgbaFormat = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceRGB(),
@@ -67,21 +52,20 @@ class LocalImageApiImpl: LocalImageApi {
}
func requestImage(assetId: String, requestId: Int64, width: Int64, height: Int64, isVideo: Bool, preferEncoded: Bool, completion: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
let request = LocalImageRequest(callback: completion)
let request = ImageRequest(completion: completion)
let operation = BlockOperation {
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
guard let asset = Self.requestAsset(assetId: assetId)
else {
Self.registry.remove(requestId: requestId)
completion(.failure(PigeonError(code: "", message: "Could not get asset data for \(assetId)", details: nil)))
return
return request.completion(.failure(PigeonError(code: "", message: "Could not get asset data for \(assetId)", details: nil)))
}
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
if preferEncoded {
@@ -100,12 +84,12 @@ class LocalImageApiImpl: LocalImageApi {
)
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
guard let data = imageData else {
Self.registry.remove(requestId: requestId)
return completion(.failure(PigeonError(code: "", message: "Could not get image data for \(assetId)", details: nil)))
return request.completion(.failure(PigeonError(code: "", message: "Could not get image data for \(assetId)", details: nil)))
}
let length = data.count
@@ -114,15 +98,14 @@ class LocalImageApiImpl: LocalImageApi {
if request.isCancelled {
free(pointer)
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
request.callback(.success([
Self.registry.remove(requestId: requestId)
return request.completion(.success([
"pointer": Int64(Int(bitPattern: pointer)),
"length": Int64(length),
]))
Self.registry.remove(requestId: requestId)
return
}
var image: UIImage?
@@ -137,17 +120,17 @@ class LocalImageApiImpl: LocalImageApi {
)
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
guard let image = image,
let cgImage = image.cgImage else {
Self.registry.remove(requestId: requestId)
return completion(.failure(PigeonError(code: "", message: "Could not get pixel data for \(assetId)", details: nil)))
return request.completion(.failure(PigeonError(code: "", message: "Could not get pixel data for \(assetId)", details: nil)))
}
if request.isCancelled {
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
do {
@@ -155,23 +138,22 @@ class LocalImageApiImpl: LocalImageApi {
if request.isCancelled {
buffer.free()
return completion(ImageProcessing.cancelledResult)
return request.completion(ImageProcessing.cancelledResult)
}
request.callback(.success([
Self.registry.remove(requestId: requestId)
return request.completion(.success([
"pointer": Int64(Int(bitPattern: buffer.data)),
"width": Int64(buffer.width),
"height": Int64(buffer.height),
"rowBytes": Int64(buffer.rowBytes),
]))
Self.registry.remove(requestId: requestId)
} catch {
Self.registry.remove(requestId: requestId)
return completion(.failure(PigeonError(code: "", message: "Failed to convert image for \(assetId): \(error)", details: nil)))
return request.completion(.failure(PigeonError(code: "", message: "Failed to convert image for \(assetId): \(error)", details: nil)))
}
}
request.operation = operation
Self.registry.add(requestId: requestId, request: request)
ImageProcessing.queue.addOperation(operation)
}

View File

@@ -3,27 +3,24 @@ import Flutter
import MobileCoreServices
import Photos
class RemoteImageRequest {
weak var task: URLSessionDataTask?
final class RemoteImageRequest: ImageRequest {
var task: URLSessionDataTask?
let id: Int64
var isCancelled = false
let completion: (Result<[String: Int64]?, any Error>) -> Void
init(id: Int64, task: URLSessionDataTask, completion: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
init(id: Int64, completion: @escaping @Sendable (Result<[String: Int64]?, any Error>) -> Void) {
self.id = id
self.task = task
self.completion = completion
super.init(completion: completion)
}
func cancel() {
isCancelled = true
override func cancel() {
super.cancel()
task?.cancel()
}
}
class RemoteImageApiImpl: NSObject, RemoteImageApi {
private static let registry = RequestRegistry<RemoteImageRequest>()
private static var rgbaFormat = vImage_CGImageFormat(
private static let rgbaFormat = vImage_CGImageFormat(
bitsPerComponent: 8,
bitsPerPixel: 32,
colorSpace: CGColorSpaceCreateDeviceRGB(),
@@ -41,62 +38,58 @@ class RemoteImageApiImpl: NSObject, RemoteImageApi {
var urlRequest = URLRequest(url: URL(string: url)!)
urlRequest.cachePolicy = .returnCacheDataElseLoad
let request = RemoteImageRequest(id: requestId, completion: completion)
let task = URLSessionManager.shared.session.dataTask(with: urlRequest) { data, response, error in
Self.handleCompletion(requestId: requestId, encoded: preferEncoded, data: data, response: response, error: error)
Self.handleCompletion(request: request, encoded: preferEncoded, data: data, response: response, error: error)
}
let request = RemoteImageRequest(id: requestId, task: task, completion: completion)
request.task = task
Self.registry.add(requestId: requestId, request: request)
task.resume()
}
private static func handleCompletion(requestId: Int64, encoded: Bool, data: Data?, response: URLResponse?, error: Error?) {
guard let request = registry.remove(requestId: requestId) else {
return
}
if let error = error {
if request.isCancelled || (error as NSError).code == NSURLErrorCancelled {
return request.completion(ImageProcessing.cancelledResult)
}
return request.completion(.failure(error))
}
private static func handleCompletion(request: RemoteImageRequest, encoded: Bool, data: Data?, response: URLResponse?, error: Error?) {
if request.isCancelled {
return request.completion(ImageProcessing.cancelledResult)
}
if let error = error {
registry.remove(requestId: request.id)
return request.completion(.failure(error))
}
guard let data = data else {
registry.remove(requestId: request.id)
return request.completion(.failure(PigeonError(code: "", message: "No data received", details: nil)))
}
if encoded {
let length = data.count
let pointer = malloc(length)!
data.copyBytes(to: pointer.assumingMemoryBound(to: UInt8.self), count: length)
if request.isCancelled {
free(pointer)
return request.completion(ImageProcessing.cancelledResult)
}
registry.remove(requestId: request.id)
return request.completion(
.success([
"pointer": Int64(Int(bitPattern: pointer)),
"length": Int64(length),
]))
}
ImageProcessing.queue.addOperation {
if request.isCancelled {
return request.completion(ImageProcessing.cancelledResult)
}
// Return raw encoded bytes when requested (for animated images)
if encoded {
let length = data.count
let pointer = malloc(length)!
data.copyBytes(to: pointer.assumingMemoryBound(to: UInt8.self), count: length)
if request.isCancelled {
free(pointer)
return request.completion(ImageProcessing.cancelledResult)
}
return request.completion(
.success([
"pointer": Int64(Int(bitPattern: pointer)),
"length": Int64(length),
]))
}
guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, decodeOptions) else {
registry.remove(requestId: request.id)
return request.completion(.failure(PigeonError(code: "", message: "Failed to decode image for request", details: nil)))
}
@@ -112,14 +105,16 @@ class RemoteImageApiImpl: NSObject, RemoteImageApi {
return request.completion(ImageProcessing.cancelledResult)
}
request.completion(
.success([
"pointer": Int64(Int(bitPattern: buffer.data)),
"width": Int64(buffer.width),
"height": Int64(buffer.height),
"rowBytes": Int64(buffer.rowBytes),
]))
registry.remove(requestId: request.id)
return request.completion(
.success([
"pointer": Int64(Int(bitPattern: buffer.data)),
"width": Int64(buffer.width),
"height": Int64(buffer.height),
"rowBytes": Int64(buffer.rowBytes),
]))
} catch {
registry.remove(requestId: request.id)
return request.completion(.failure(PigeonError(code: "", message: "Failed to convert image for request: \(error)", details: nil)))
}
}

View File

@@ -80,7 +80,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.7.0</string>
<string>2.7.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

View File

@@ -1,3 +1,5 @@
import 'package:immich_mobile/domain/models/exif.model.dart';
part 'local_asset.model.dart';
part 'remote_asset.model.dart';

View File

@@ -128,3 +128,81 @@ class RemoteAsset extends BaseAsset {
);
}
}
class RemoteAssetExif extends RemoteAsset {
final ExifInfo exifInfo;
const RemoteAssetExif({
required super.id,
super.localId,
required super.name,
required super.ownerId,
required super.checksum,
required super.type,
required super.createdAt,
required super.updatedAt,
super.width,
super.height,
super.durationInSeconds,
super.isFavorite = false,
super.thumbHash,
super.visibility = AssetVisibility.timeline,
super.livePhotoVideoId,
super.stackId,
super.isEdited = false,
this.exifInfo = const ExifInfo(),
});
@override
bool operator ==(Object other) {
if (other is! RemoteAssetExif) return false;
if (identical(this, other)) return true;
return super == other && exifInfo == other.exifInfo;
}
@override
int get hashCode => super.hashCode ^ exifInfo.hashCode;
@override
RemoteAssetExif copyWith({
String? id,
String? localId,
String? name,
String? ownerId,
String? checksum,
AssetType? type,
DateTime? createdAt,
DateTime? updatedAt,
int? width,
int? height,
int? durationInSeconds,
bool? isFavorite,
String? thumbHash,
AssetVisibility? visibility,
String? livePhotoVideoId,
String? stackId,
bool? isEdited,
ExifInfo? exifInfo,
}) {
return RemoteAssetExif(
id: id ?? this.id,
localId: localId ?? this.localId,
name: name ?? this.name,
ownerId: ownerId ?? this.ownerId,
checksum: checksum ?? this.checksum,
type: type ?? this.type,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
width: width ?? this.width,
height: height ?? this.height,
durationInSeconds: durationInSeconds ?? this.durationInSeconds,
isFavorite: isFavorite ?? this.isFavorite,
thumbHash: thumbHash ?? this.thumbHash,
visibility: visibility ?? this.visibility,
livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId,
stackId: stackId ?? this.stackId,
isEdited: isEdited ?? this.isEdited,
exifInfo: exifInfo ?? this.exifInfo, // Use the new parameter
);
}
}

View File

@@ -1,10 +1,9 @@
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/search_result.model.dart';
import 'package:immich_mobile/extensions/asset_extensions.dart';
import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/infrastructure/repositories/search_api.repository.dart';
import 'package:immich_mobile/models/search/search_filter.model.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart' as api show AssetVisibility;
import 'package:openapi/api.dart' hide AssetVisibility;
class SearchService {
@@ -52,43 +51,3 @@ class SearchService {
return null;
}
}
extension on AssetResponseDto {
RemoteAsset toDto() {
return RemoteAsset(
id: id,
name: originalFileName,
checksum: checksum,
createdAt: fileCreatedAt,
updatedAt: updatedAt,
ownerId: ownerId,
visibility: switch (visibility) {
api.AssetVisibility.timeline => AssetVisibility.timeline,
api.AssetVisibility.hidden => AssetVisibility.hidden,
api.AssetVisibility.archive => AssetVisibility.archive,
api.AssetVisibility.locked => AssetVisibility.locked,
_ => AssetVisibility.timeline,
},
durationInSeconds: duration.toDuration()?.inSeconds ?? 0,
height: height?.toInt(),
width: width?.toInt(),
isFavorite: isFavorite,
livePhotoVideoId: livePhotoVideoId,
thumbHash: thumbhash,
localId: null,
type: type.toAssetType(),
stackId: stack?.id,
isEdited: isEdited,
);
}
}
extension on AssetTypeEnum {
AssetType toAssetType() => switch (this) {
AssetTypeEnum.IMAGE => AssetType.image,
AssetTypeEnum.VIDEO => AssetType.video,
AssetTypeEnum.AUDIO => AssetType.audio,
AssetTypeEnum.OTHER => AssetType.other,
_ => throw Exception('Unknown AssetType value: $this'),
};
}

View File

@@ -34,6 +34,7 @@ enum TimelineOrigin {
search,
deepLink,
albumActivities,
folder,
}
class TimelineFactory {

View File

@@ -80,12 +80,14 @@ Future<void> _processCloudIdMappingsInBatches(
AssetMetadataBulkUpsertItemDto(
assetId: mapping.remoteAssetId,
key: kMobileMetadataKey,
value: RemoteAssetMobileAppMetadata(
cloudId: mapping.localAsset.cloudId,
createdAt: mapping.localAsset.createdAt.toIso8601String(),
adjustmentTime: mapping.localAsset.adjustmentTime?.toIso8601String(),
latitude: mapping.localAsset.latitude?.toString(),
longitude: mapping.localAsset.longitude?.toString(),
value: Map<String, Object>.from(
RemoteAssetMobileAppMetadata(
cloudId: mapping.localAsset.cloudId,
createdAt: mapping.localAsset.createdAt.toIso8601String(),
adjustmentTime: mapping.localAsset.adjustmentTime?.toIso8601String(),
latitude: mapping.localAsset.latitude?.toString(),
longitude: mapping.localAsset.longitude?.toString(),
).toJson(),
),
),
);

View File

@@ -1,7 +1,12 @@
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/exif.model.dart';
import 'package:immich_mobile/entities/asset.entity.dart' as isar hide AssetTypeEnumHelper;
import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/infrastructure/utils/exif.converter.dart';
import 'package:immich_mobile/utils/timezone.dart';
import 'package:openapi/api.dart' as api;
extension TZExtension on Asset {
extension TZExtension on isar.Asset {
/// Returns the created time of the asset from the exif info (if available) or from
/// the fileCreatedAt field, adjusted to the timezone value from the exif info along with
/// the timezone offset in [Duration]
@@ -15,3 +20,70 @@ extension TZExtension on Asset {
return (dt, dt.timeZoneOffset);
}
}
extension DTOToAsset on api.AssetResponseDto {
RemoteAsset toDto() {
return RemoteAsset(
id: id,
name: originalFileName,
checksum: checksum,
createdAt: fileCreatedAt,
updatedAt: updatedAt,
ownerId: ownerId,
visibility: visibility.toAssetVisibility(),
durationInSeconds: duration.toDuration()?.inSeconds ?? 0,
height: height?.toInt(),
width: width?.toInt(),
isFavorite: isFavorite,
livePhotoVideoId: livePhotoVideoId,
thumbHash: thumbhash,
localId: null,
type: type.toAssetType(),
stackId: stack?.id,
isEdited: isEdited,
);
}
RemoteAssetExif toDtoWithExif() {
return RemoteAssetExif(
id: id,
name: originalFileName,
checksum: checksum,
createdAt: fileCreatedAt,
updatedAt: updatedAt,
ownerId: ownerId,
visibility: visibility.toAssetVisibility(),
durationInSeconds: duration.toDuration()?.inSeconds ?? 0,
height: height?.toInt(),
width: width?.toInt(),
isFavorite: isFavorite,
livePhotoVideoId: livePhotoVideoId,
thumbHash: thumbhash,
localId: null,
type: type.toAssetType(),
stackId: stack?.id,
isEdited: isEdited,
exifInfo: exifInfo != null ? ExifDtoConverter.fromDto(exifInfo!) : const ExifInfo(),
);
}
}
extension on api.AssetVisibility {
AssetVisibility toAssetVisibility() => switch (this) {
api.AssetVisibility.timeline => AssetVisibility.timeline,
api.AssetVisibility.hidden => AssetVisibility.hidden,
api.AssetVisibility.archive => AssetVisibility.archive,
api.AssetVisibility.locked => AssetVisibility.locked,
_ => AssetVisibility.timeline,
};
}
extension on api.AssetTypeEnum {
AssetType toAssetType() => switch (this) {
api.AssetTypeEnum.IMAGE => AssetType.image,
api.AssetTypeEnum.VIDEO => AssetType.video,
api.AssetTypeEnum.AUDIO => AssetType.audio,
api.AssetTypeEnum.OTHER => AssetType.other,
_ => throw Exception('Unknown AssetType value: $this'),
};
}

View File

@@ -45,14 +45,17 @@ class _DriftBackupPageState extends ConsumerState<DriftBackupPage> {
}
WidgetsBinding.instance.addPostFrameCallback((_) async {
await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id);
final backupNotifier = ref.read(driftBackupProvider.notifier);
final syncManager = ref.read(backgroundSyncProvider);
ref.read(driftBackupProvider.notifier).updateSyncing(true);
syncSuccess = await ref.read(backgroundSyncProvider).syncRemote();
ref.read(driftBackupProvider.notifier).updateSyncing(false);
await backupNotifier.getBackupStatus(currentUser.id);
backupNotifier.updateSyncing(true);
syncSuccess = await syncManager.syncRemote();
backupNotifier.updateSyncing(false);
if (mounted) {
await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id);
await backupNotifier.getBackupStatus(currentUser.id);
}
});
}
@@ -82,9 +85,9 @@ class _DriftBackupPageState extends ConsumerState<DriftBackupPage> {
}
if (syncSuccess == null) {
ref.read(driftBackupProvider.notifier).updateSyncing(true);
backupNotifier.updateSyncing(true);
syncSuccess = await backupSyncManager.syncRemote();
ref.read(driftBackupProvider.notifier).updateSyncing(false);
backupNotifier.updateSyncing(false);
}
await backupNotifier.getBackupStatus(currentUser.id);

View File

@@ -1,19 +1,22 @@
import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/models/folder/recursive_folder.model.dart';
import 'package:immich_mobile/models/folder/root_folder.model.dart';
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.page.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail_tile.widget.dart';
import 'package:immich_mobile/providers/folder.provider.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/utils/bytes_units.dart';
import 'package:immich_mobile/widgets/asset_grid/thumbnail_image.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart';
RecursiveFolder? _findFolderInStructure(RootFolder rootFolder, RecursiveFolder targetFolder) {
@@ -136,8 +139,8 @@ class FolderContent extends HookConsumerWidget {
FolderPath(currentFolder: folder!, root: root),
Expanded(
child: folderRenderlist.when(
data: (list) {
if (folder!.subfolders.isEmpty && list.isEmpty) {
data: (folderAssets) {
if (folder!.subfolders.isEmpty && folderAssets.isEmpty) {
return Center(child: const Text("empty_folder").tr());
}
@@ -164,32 +167,33 @@ class FolderContent extends HookConsumerWidget {
onTap: () => context.pushRoute(FolderRoute(folder: subfolder)),
),
),
if (!list.isEmpty && list.allAssets != null && list.allAssets!.isNotEmpty)
...list.allAssets!.map(
(asset) => LargeLeadingTile(
if (folderAssets.isNotEmpty)
...folderAssets.mapIndexed(
(index, asset) => LargeLeadingTile(
onTap: () {
ref.read(currentAssetProvider.notifier).set(asset);
AssetViewer.setAsset(ref, asset);
context.pushRoute(
GalleryViewerRoute(renderList: list, initialIndex: list.allAssets!.indexOf(asset)),
AssetViewerRoute(
initialIndex: index,
timelineService: ref
.read(timelineFactoryProvider)
.fromAssets(folderAssets, TimelineOrigin.folder),
),
);
},
leading: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(15)),
child: SizedBox(
width: 80,
height: 80,
child: ThumbnailImage(asset: asset, showStorageIndicator: false),
),
child: SizedBox(width: 80, height: 80, child: ThumbnailTile(asset)),
),
title: Text(
asset.fileName,
asset.name,
maxLines: 2,
softWrap: false,
overflow: TextOverflow.ellipsis,
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600),
),
subtitle: Text(
"${asset.exifInfo?.fileSize != null ? formatBytes(asset.exifInfo?.fileSize ?? 0) : ""}${DateFormat.yMMMd().format(asset.fileCreatedAt)}",
"${asset.exifInfo.fileSize != null ? formatBytes(asset.exifInfo.fileSize ?? 0) : ""}${DateFormat.yMMMd().format(asset.createdAt)}",
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
),
),

View File

@@ -89,7 +89,7 @@ class _DriftPeopleCollectionPageState extends ConsumerState<DriftPeopleCollectio
shape: const CircleBorder(side: BorderSide.none),
elevation: 3,
child: CircleAvatar(
key: ValueKey('avatar-${person.id}'),
key: ValueKey(person.id),
maxRadius: isTablet ? 100 / 2 : 96 / 2,
backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(person.id)),
),

View File

@@ -19,6 +19,7 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
static final _log = Logger('CancellableImageProviderMixin');
bool isCancelled = false;
bool isFinished = false;
ImageRequest? request;
CancelableOperation<ImageInfo?>? cachedOperation;
@@ -50,24 +51,26 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
return null;
}
Stream<ImageInfo> loadRequest(ImageRequest request, ImageDecoderCallback decode, {bool evictOnError = true}) async* {
Stream<ImageInfo> loadRequest(ImageRequest request, ImageDecoderCallback decode, {required bool isFinal}) async* {
if (isCancelled) {
this.request = null;
PaintingBinding.instance.imageCache.evict(this);
return;
}
try {
final image = await request.load(decode);
if ((image == null && evictOnError) || isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
} else if (image == null) {
if (isCancelled || image == null) {
image?.dispose();
return;
}
isFinished = isFinal;
yield image;
} catch (e, stack) {
if (evictOnError) {
if (isCancelled) {
return;
}
if (isFinal) {
isFinished = true;
PaintingBinding.instance.imageCache.evict(this);
rethrow;
}
@@ -77,24 +80,27 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
}
}
Future<ui.Codec?> loadCodecRequest(ImageRequest request) async {
Future<ui.Codec?> loadCodecRequest(ImageRequest request, {required bool isFinal}) async {
if (isCancelled) {
this.request = null;
PaintingBinding.instance.imageCache.evict(this);
return null;
}
try {
final codec = await request.loadCodec();
if (codec == null || isCancelled) {
if (isCancelled || codec == null) {
codec?.dispose();
PaintingBinding.instance.imageCache.evict(this);
return null;
}
isFinished = isFinal;
return codec;
} catch (e) {
PaintingBinding.instance.imageCache.evict(this);
rethrow;
if (isFinal) {
isFinished = true;
PaintingBinding.instance.imageCache.evict(this);
rethrow;
}
return null;
} finally {
this.request = null;
}
@@ -121,6 +127,8 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
@override
void cancel() {
isCancelled = true;
final hasActiveWork = !isFinished;
final request = this.request;
if (request != null) {
this.request = null;
@@ -132,6 +140,10 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
cachedOperation = null;
operation.cancel();
}
if (hasActiveWork) {
PaintingBinding.instance.imageCache.evict(this);
}
}
}

View File

@@ -36,7 +36,7 @@ class LocalThumbProvider extends CancellableImageProvider<LocalThumbProvider>
Stream<ImageInfo> _codec(LocalThumbProvider key, ImageDecoderCallback decode) {
final request = this.request = LocalImageRequest(localId: key.id, size: key.size, assetType: key.assetType);
return loadRequest(request, decode);
return loadRequest(request, decode, isFinal: true);
}
@override
@@ -100,37 +100,35 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
yield* initialImageStream();
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
final loadOriginal = Store.get(StoreKey.loadOriginal, false);
final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio;
var request = this.request = LocalImageRequest(
localId: key.id,
size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio),
assetType: key.assetType,
);
yield* loadRequest(request, decode);
yield* loadRequest(request, decode, isFinal: !loadOriginal);
if (!Store.get(StoreKey.loadOriginal, false)) {
if (!loadOriginal) {
return;
}
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
request = this.request = LocalImageRequest(localId: key.id, assetType: key.assetType, size: Size.zero);
yield* loadRequest(request, decode);
yield* loadRequest(request, decode, isFinal: true);
}
Stream<Object> _animatedCodec(LocalFullImageProvider key, ImageDecoderCallback decode) async* {
yield* initialImageStream();
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
@@ -140,17 +138,17 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio),
assetType: key.assetType,
);
yield* loadRequest(previewRequest, decode);
yield* loadRequest(previewRequest, decode, isFinal: false);
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
// always try original for animated, since previews don't support animation
final originalRequest = request = LocalImageRequest(localId: key.id, size: Size.zero, assetType: key.assetType);
final codec = await loadCodecRequest(originalRequest);
final codec = await loadCodecRequest(originalRequest, isFinal: true);
if (codec == null) {
if (isCancelled) return;
throw StateError('Failed to load animated codec for local asset ${key.id}');
}
yield codec;

View File

@@ -38,7 +38,7 @@ class RemoteImageProvider extends CancellableImageProvider<RemoteImageProvider>
Stream<ImageInfo> _codec(RemoteImageProvider key, ImageDecoderCallback decode) {
final request = this.request = RemoteImageRequest(uri: key.url);
return loadRequest(request, decode);
return loadRequest(request, decode, isFinal: true);
}
@override
@@ -105,7 +105,6 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
yield* initialImageStream();
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
@@ -113,43 +112,43 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
uri: getThumbnailUrlForRemoteId(key.assetId, type: AssetMediaSize.preview, thumbhash: key.thumbhash),
);
final loadOriginal = assetType == AssetType.image && AppSetting.get(Setting.loadOriginal);
yield* loadRequest(previewRequest, decode, evictOnError: !loadOriginal);
yield* loadRequest(previewRequest, decode, isFinal: !loadOriginal);
if (!loadOriginal) {
return;
}
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
final originalRequest = request = RemoteImageRequest(uri: getOriginalUrlForRemoteId(key.assetId));
yield* loadRequest(originalRequest, decode);
yield* loadRequest(originalRequest, decode, isFinal: true);
}
Stream<Object> _animatedCodec(RemoteFullImageProvider key, ImageDecoderCallback decode) async* {
yield* initialImageStream();
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
final previewRequest = request = RemoteImageRequest(
uri: getThumbnailUrlForRemoteId(key.assetId, type: AssetMediaSize.preview, thumbhash: key.thumbhash),
);
yield* loadRequest(previewRequest, decode, evictOnError: false);
yield* loadRequest(previewRequest, decode, isFinal: false);
if (isCancelled) {
PaintingBinding.instance.imageCache.evict(this);
return;
}
// always try original for animated, since previews don't support animation
final originalRequest = request = RemoteImageRequest(uri: getOriginalUrlForRemoteId(key.assetId));
final codec = await loadCodecRequest(originalRequest);
final codec = await loadCodecRequest(originalRequest, isFinal: true);
if (codec == null) {
if (isCancelled) {
return;
}
throw StateError('Failed to load animated codec for asset ${key.assetId}');
}
yield codec;

View File

@@ -22,7 +22,7 @@ class ThumbHashProvider extends CancellableImageProvider<ThumbHashProvider>
Stream<ImageInfo> _loadCodec(ThumbHashProvider key, ImageDecoderCallback decode) {
final request = this.request = ThumbhashImageRequest(thumbhash: key.thumbHash);
return loadRequest(request, decode);
return loadRequest(request, decode, isFinal: true);
}
@override

View File

@@ -1,8 +1,8 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/models/folder/root_folder.model.dart';
import 'package:immich_mobile/services/folder.service.dart';
import 'package:immich_mobile/widgets/asset_grid/asset_grid_data_structure.dart';
import 'package:logging/logging.dart';
class FolderStructureNotifier extends StateNotifier<AsyncValue<RootFolder>> {
@@ -26,7 +26,7 @@ final folderStructureProvider = StateNotifierProvider<FolderStructureNotifier, A
return FolderStructureNotifier(ref.watch(folderServiceProvider));
});
class FolderRenderListNotifier extends StateNotifier<AsyncValue<RenderList>> {
class FolderRenderListNotifier extends StateNotifier<AsyncValue<List<RemoteAssetExif>>> {
final FolderService _folderService;
final RootFolder _folder;
final Logger _log = Logger("FolderAssetsNotifier");
@@ -36,8 +36,7 @@ class FolderRenderListNotifier extends StateNotifier<AsyncValue<RenderList>> {
Future<void> fetchAssets(SortOrder order) async {
try {
final assets = await _folderService.getFolderAssets(_folder, order);
final renderList = await RenderList.fromAssets(assets, GroupAssetsBy.none);
state = AsyncData(renderList);
state = AsyncData(assets);
} catch (e, stack) {
_log.severe("Failed to fetch folder assets", e, stack);
state = AsyncError(e, stack);
@@ -46,6 +45,9 @@ class FolderRenderListNotifier extends StateNotifier<AsyncValue<RenderList>> {
}
final folderRenderListProvider =
StateNotifierProvider.family<FolderRenderListNotifier, AsyncValue<RenderList>, RootFolder>((ref, folder) {
StateNotifierProvider.family<FolderRenderListNotifier, AsyncValue<List<RemoteAssetExif>>, RootFolder>((
ref,
folder,
) {
return FolderRenderListNotifier(ref.watch(folderServiceProvider), folder);
});

View File

@@ -97,7 +97,7 @@ class AlbumApiRepository extends ApiRepository {
for (final result in response) {
if (result.success) {
added.add(result.id);
} else if (result.error == BulkIdResponseDtoErrorEnum.duplicate) {
} else if (result.error == BulkIdErrorReason.duplicate) {
duplicates.add(result.id);
}
}

View File

@@ -1,5 +1,6 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/asset_extensions.dart';
import 'package:immich_mobile/providers/api.provider.dart';
import 'package:immich_mobile/repositories/api.repository.dart';
import 'package:logging/logging.dart';
@@ -23,10 +24,10 @@ class FolderApiRepository extends ApiRepository {
}
}
Future<List<Asset>> getAssetsForPath(String? path) async {
Future<List<RemoteAssetExif>> getAssetsForPath(String? path) async {
try {
final list = await _api.getAssetsByOriginalPath(path ?? '/');
return list != null ? list.map(Asset.remote).toList() : [];
return list != null ? list.map((e) => e.toDtoWithExif()).toList() : [];
} catch (e, stack) {
_log.severe("Failed to fetch Assets by original path", e, stack);
return [];

View File

@@ -1,6 +1,6 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/models/folder/recursive_folder.model.dart';
import 'package:immich_mobile/models/folder/root_folder.model.dart';
import 'package:immich_mobile/repositories/folder_api.repository.dart';
@@ -76,7 +76,7 @@ class FolderService {
return RootFolder(subfolders: rootSubfolders, path: '/');
}
Future<List<Asset>> getFolderAssets(RootFolder folder, SortOrder order) async {
Future<List<RemoteAssetExif>> getFolderAssets(RootFolder folder, SortOrder order) async {
try {
if (folder is RecursiveFolder) {
String fullPath = folder.path.isEmpty ? folder.name : '${folder.path}/${folder.name}';
@@ -84,9 +84,9 @@ class FolderService {
var result = await _folderApiRepository.getAssetsForPath(fullPath);
if (order == SortOrder.desc) {
result.sort((a, b) => b.fileCreatedAt.compareTo(a.fileCreatedAt));
result.sort((a, b) => b.createdAt.compareTo(a.createdAt));
} else {
result.sort((a, b) => a.fileCreatedAt.compareTo(b.fileCreatedAt));
result.sort((a, b) => a.createdAt.compareTo(b.createdAt));
}
return result;

View File

@@ -5,13 +5,13 @@ dynamic upgradeDto(dynamic value, String targetType) {
case 'UserPreferencesResponseDto':
if (value is Map) {
addDefault(value, 'download.includeEmbeddedVideos', false);
addDefault(value, 'folders', FoldersResponse().toJson());
addDefault(value, 'memories', MemoriesResponse().toJson());
addDefault(value, 'ratings', RatingsResponse().toJson());
addDefault(value, 'people', PeopleResponse().toJson());
addDefault(value, 'tags', TagsResponse().toJson());
addDefault(value, 'sharedLinks', SharedLinksResponse().toJson());
addDefault(value, 'cast', CastResponse().toJson());
addDefault(value, 'folders', FoldersResponse(enabled: false, sidebarWeb: false).toJson());
addDefault(value, 'memories', MemoriesResponse(enabled: true, duration: 5).toJson());
addDefault(value, 'ratings', RatingsResponse(enabled: false).toJson());
addDefault(value, 'people', PeopleResponse(enabled: true, sidebarWeb: false).toJson());
addDefault(value, 'tags', TagsResponse(enabled: false, sidebarWeb: false).toJson());
addDefault(value, 'sharedLinks', SharedLinksResponse(enabled: true, sidebarWeb: false).toJson());
addDefault(value, 'cast', CastResponse(gCastEnabled: false).toJson());
addDefault(value, 'albums', {'defaultAssetOrder': 'desc'});
}
break;

View File

@@ -57,6 +57,7 @@ class PeoplePicker extends HookConsumerWidget {
final isSelected = selectedPeople.value.contains(person);
return Padding(
key: ValueKey(person.id),
padding: const EdgeInsets.only(bottom: 2.0),
child: LargeLeadingTile(
title: Text(
@@ -73,6 +74,7 @@ class PeoplePicker extends HookConsumerWidget {
shape: const CircleBorder(side: BorderSide.none),
elevation: 3,
child: CircleAvatar(
key: ValueKey(person.id),
maxRadius: imageSize / 2,
backgroundImage: RemoteImageProvider(url: getFaceThumbnailUrl(person.id)),
),

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: 2.7.0
- API version: 2.7.5
- Generator version: 7.8.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
@@ -110,10 +110,8 @@ Class | Method | HTTP request | Description
*AssetsApi* | [**getAssetMetadataByKey**](doc//AssetsApi.md#getassetmetadatabykey) | **GET** /assets/{id}/metadata/{key} | Retrieve asset metadata by key
*AssetsApi* | [**getAssetOcr**](doc//AssetsApi.md#getassetocr) | **GET** /assets/{id}/ocr | Retrieve asset OCR data
*AssetsApi* | [**getAssetStatistics**](doc//AssetsApi.md#getassetstatistics) | **GET** /assets/statistics | Get asset statistics
*AssetsApi* | [**getRandom**](doc//AssetsApi.md#getrandom) | **GET** /assets/random | Get random assets
*AssetsApi* | [**playAssetVideo**](doc//AssetsApi.md#playassetvideo) | **GET** /assets/{id}/video/playback | Play asset video
*AssetsApi* | [**removeAssetEdits**](doc//AssetsApi.md#removeassetedits) | **DELETE** /assets/{id}/edits | Remove edits from an existing asset
*AssetsApi* | [**replaceAsset**](doc//AssetsApi.md#replaceasset) | **PUT** /assets/{id}/original | Replace asset
*AssetsApi* | [**runAssetJobs**](doc//AssetsApi.md#runassetjobs) | **POST** /assets/jobs | Run an asset job
*AssetsApi* | [**updateAsset**](doc//AssetsApi.md#updateasset) | **PUT** /assets/{id} | Update an asset
*AssetsApi* | [**updateAssetMetadata**](doc//AssetsApi.md#updateassetmetadata) | **PUT** /assets/{id}/metadata | Update asset metadata
@@ -147,10 +145,6 @@ Class | Method | HTTP request | Description
*DeprecatedApi* | [**getAllUserAssetsByDeviceId**](doc//DeprecatedApi.md#getalluserassetsbydeviceid) | **GET** /assets/device/{deviceId} | Retrieve assets by device ID
*DeprecatedApi* | [**getDeltaSync**](doc//DeprecatedApi.md#getdeltasync) | **POST** /sync/delta-sync | Get delta sync for user
*DeprecatedApi* | [**getFullSyncForUser**](doc//DeprecatedApi.md#getfullsyncforuser) | **POST** /sync/full-sync | Get full sync for user
*DeprecatedApi* | [**getQueuesLegacy**](doc//DeprecatedApi.md#getqueueslegacy) | **GET** /jobs | Retrieve queue counts and status
*DeprecatedApi* | [**getRandom**](doc//DeprecatedApi.md#getrandom) | **GET** /assets/random | Get random assets
*DeprecatedApi* | [**replaceAsset**](doc//DeprecatedApi.md#replaceasset) | **PUT** /assets/{id}/original | Replace asset
*DeprecatedApi* | [**runQueueCommandLegacy**](doc//DeprecatedApi.md#runqueuecommandlegacy) | **PUT** /jobs/{name} | Run jobs
*DownloadApi* | [**downloadArchive**](doc//DownloadApi.md#downloadarchive) | **POST** /download/archive | Download asset archive
*DownloadApi* | [**getDownloadInfo**](doc//DownloadApi.md#getdownloadinfo) | **POST** /download/info | Retrieve download information
*DuplicatesApi* | [**deleteDuplicate**](doc//DuplicatesApi.md#deleteduplicate) | **DELETE** /duplicates/{id} | Delete a duplicate
@@ -162,8 +156,6 @@ Class | Method | HTTP request | Description
*FacesApi* | [**getFaces**](doc//FacesApi.md#getfaces) | **GET** /faces | Retrieve faces for asset
*FacesApi* | [**reassignFacesById**](doc//FacesApi.md#reassignfacesbyid) | **PUT** /faces/{id} | Re-assign a face to another person
*JobsApi* | [**createJob**](doc//JobsApi.md#createjob) | **POST** /jobs | Create a manual job
*JobsApi* | [**getQueuesLegacy**](doc//JobsApi.md#getqueueslegacy) | **GET** /jobs | Retrieve queue counts and status
*JobsApi* | [**runQueueCommandLegacy**](doc//JobsApi.md#runqueuecommandlegacy) | **PUT** /jobs/{name} | Run jobs
*LibrariesApi* | [**createLibrary**](doc//LibrariesApi.md#createlibrary) | **POST** /libraries | Create a library
*LibrariesApi* | [**deleteLibrary**](doc//LibrariesApi.md#deletelibrary) | **DELETE** /libraries/{id} | Delete a library
*LibrariesApi* | [**getAllLibraries**](doc//LibrariesApi.md#getalllibraries) | **GET** /libraries | Retrieve libraries
@@ -371,6 +363,7 @@ Class | Method | HTTP request | Description
- [AssetFaceUpdateItem](doc//AssetFaceUpdateItem.md)
- [AssetFaceWithoutPersonResponseDto](doc//AssetFaceWithoutPersonResponseDto.md)
- [AssetFullSyncDto](doc//AssetFullSyncDto.md)
- [AssetIdErrorReason](doc//AssetIdErrorReason.md)
- [AssetIdsDto](doc//AssetIdsDto.md)
- [AssetIdsResponseDto](doc//AssetIdsResponseDto.md)
- [AssetJobName](doc//AssetJobName.md)
@@ -388,10 +381,12 @@ Class | Method | HTTP request | Description
- [AssetMetadataUpsertItemDto](doc//AssetMetadataUpsertItemDto.md)
- [AssetOcrResponseDto](doc//AssetOcrResponseDto.md)
- [AssetOrder](doc//AssetOrder.md)
- [AssetRejectReason](doc//AssetRejectReason.md)
- [AssetResponseDto](doc//AssetResponseDto.md)
- [AssetStackResponseDto](doc//AssetStackResponseDto.md)
- [AssetStatsResponseDto](doc//AssetStatsResponseDto.md)
- [AssetTypeEnum](doc//AssetTypeEnum.md)
- [AssetUploadAction](doc//AssetUploadAction.md)
- [AssetVisibility](doc//AssetVisibility.md)
- [AudioCodec](doc//AudioCodec.md)
- [AuthStatusResponseDto](doc//AuthStatusResponseDto.md)
@@ -440,7 +435,6 @@ Class | Method | HTTP request | Description
- [LibraryResponseDto](doc//LibraryResponseDto.md)
- [LibraryStatsResponseDto](doc//LibraryStatsResponseDto.md)
- [LicenseKeyDto](doc//LicenseKeyDto.md)
- [LicenseResponseDto](doc//LicenseResponseDto.md)
- [LogLevel](doc//LogLevel.md)
- [LoginCredentialDto](doc//LoginCredentialDto.md)
- [LoginResponseDto](doc//LoginResponseDto.md)
@@ -504,23 +498,22 @@ Class | Method | HTTP request | Description
- [PluginActionResponseDto](doc//PluginActionResponseDto.md)
- [PluginContextType](doc//PluginContextType.md)
- [PluginFilterResponseDto](doc//PluginFilterResponseDto.md)
- [PluginJsonSchema](doc//PluginJsonSchema.md)
- [PluginJsonSchemaProperty](doc//PluginJsonSchemaProperty.md)
- [PluginJsonSchemaPropertyAdditionalProperties](doc//PluginJsonSchemaPropertyAdditionalProperties.md)
- [PluginJsonSchemaType](doc//PluginJsonSchemaType.md)
- [PluginResponseDto](doc//PluginResponseDto.md)
- [PluginTriggerResponseDto](doc//PluginTriggerResponseDto.md)
- [PluginTriggerType](doc//PluginTriggerType.md)
- [PurchaseResponse](doc//PurchaseResponse.md)
- [PurchaseUpdate](doc//PurchaseUpdate.md)
- [QueueCommand](doc//QueueCommand.md)
- [QueueCommandDto](doc//QueueCommandDto.md)
- [QueueDeleteDto](doc//QueueDeleteDto.md)
- [QueueJobResponseDto](doc//QueueJobResponseDto.md)
- [QueueJobStatus](doc//QueueJobStatus.md)
- [QueueName](doc//QueueName.md)
- [QueueResponseDto](doc//QueueResponseDto.md)
- [QueueResponseLegacyDto](doc//QueueResponseLegacyDto.md)
- [QueueStatisticsDto](doc//QueueStatisticsDto.md)
- [QueueStatusLegacyDto](doc//QueueStatusLegacyDto.md)
- [QueueUpdateDto](doc//QueueUpdateDto.md)
- [QueuesResponseLegacyDto](doc//QueuesResponseLegacyDto.md)
- [RandomSearchDto](doc//RandomSearchDto.md)
- [RatingsResponse](doc//RatingsResponse.md)
- [RatingsUpdate](doc//RatingsUpdate.md)

View File

@@ -109,6 +109,7 @@ part 'model/asset_face_update_dto.dart';
part 'model/asset_face_update_item.dart';
part 'model/asset_face_without_person_response_dto.dart';
part 'model/asset_full_sync_dto.dart';
part 'model/asset_id_error_reason.dart';
part 'model/asset_ids_dto.dart';
part 'model/asset_ids_response_dto.dart';
part 'model/asset_job_name.dart';
@@ -126,10 +127,12 @@ part 'model/asset_metadata_upsert_dto.dart';
part 'model/asset_metadata_upsert_item_dto.dart';
part 'model/asset_ocr_response_dto.dart';
part 'model/asset_order.dart';
part 'model/asset_reject_reason.dart';
part 'model/asset_response_dto.dart';
part 'model/asset_stack_response_dto.dart';
part 'model/asset_stats_response_dto.dart';
part 'model/asset_type_enum.dart';
part 'model/asset_upload_action.dart';
part 'model/asset_visibility.dart';
part 'model/audio_codec.dart';
part 'model/auth_status_response_dto.dart';
@@ -178,7 +181,6 @@ part 'model/job_settings_dto.dart';
part 'model/library_response_dto.dart';
part 'model/library_stats_response_dto.dart';
part 'model/license_key_dto.dart';
part 'model/license_response_dto.dart';
part 'model/log_level.dart';
part 'model/login_credential_dto.dart';
part 'model/login_response_dto.dart';
@@ -242,23 +244,22 @@ part 'model/places_response_dto.dart';
part 'model/plugin_action_response_dto.dart';
part 'model/plugin_context_type.dart';
part 'model/plugin_filter_response_dto.dart';
part 'model/plugin_json_schema.dart';
part 'model/plugin_json_schema_property.dart';
part 'model/plugin_json_schema_property_additional_properties.dart';
part 'model/plugin_json_schema_type.dart';
part 'model/plugin_response_dto.dart';
part 'model/plugin_trigger_response_dto.dart';
part 'model/plugin_trigger_type.dart';
part 'model/purchase_response.dart';
part 'model/purchase_update.dart';
part 'model/queue_command.dart';
part 'model/queue_command_dto.dart';
part 'model/queue_delete_dto.dart';
part 'model/queue_job_response_dto.dart';
part 'model/queue_job_status.dart';
part 'model/queue_name.dart';
part 'model/queue_response_dto.dart';
part 'model/queue_response_legacy_dto.dart';
part 'model/queue_statistics_dto.dart';
part 'model/queue_status_legacy_dto.dart';
part 'model/queue_update_dto.dart';
part 'model/queues_response_legacy_dto.dart';
part 'model/random_search_dto.dart';
part 'model/ratings_response.dart';
part 'model/ratings_update.dart';

View File

@@ -136,10 +136,8 @@ class ActivitiesApi {
/// Asset ID (if activity is for an asset)
///
/// * [ReactionLevel] level:
/// Filter by activity level
///
/// * [ReactionType] type:
/// Filter by activity type
///
/// * [String] userId:
/// Filter by user ID
@@ -195,10 +193,8 @@ class ActivitiesApi {
/// Asset ID (if activity is for an asset)
///
/// * [ReactionLevel] level:
/// Filter by activity level
///
/// * [ReactionType] type:
/// Filter by activity type
///
/// * [String] userId:
/// Filter by user ID

View File

@@ -27,11 +27,7 @@ class AlbumsApi {
/// * [String] id (required):
///
/// * [BulkIdsDto] bulkIdsDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> addAssetsToAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto, { String? key, String? slug, }) async {
Future<Response> addAssetsToAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/albums/{id}/assets'
.replaceAll('{id}', id);
@@ -43,13 +39,6 @@ class AlbumsApi {
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>['application/json'];
@@ -73,12 +62,8 @@ class AlbumsApi {
/// * [String] id (required):
///
/// * [BulkIdsDto] bulkIdsDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<List<BulkIdResponseDto>?> addAssetsToAlbum(String id, BulkIdsDto bulkIdsDto, { String? key, String? slug, }) async {
final response = await addAssetsToAlbumWithHttpInfo(id, bulkIdsDto, key: key, slug: slug, );
Future<List<BulkIdResponseDto>?> addAssetsToAlbum(String id, BulkIdsDto bulkIdsDto,) async {
final response = await addAssetsToAlbumWithHttpInfo(id, bulkIdsDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -104,11 +89,7 @@ class AlbumsApi {
/// Parameters:
///
/// * [AlbumsAddAssetsDto] albumsAddAssetsDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> addAssetsToAlbumsWithHttpInfo(AlbumsAddAssetsDto albumsAddAssetsDto, { String? key, String? slug, }) async {
Future<Response> addAssetsToAlbumsWithHttpInfo(AlbumsAddAssetsDto albumsAddAssetsDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/albums/assets';
@@ -119,13 +100,6 @@ class AlbumsApi {
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>['application/json'];
@@ -147,12 +121,8 @@ class AlbumsApi {
/// Parameters:
///
/// * [AlbumsAddAssetsDto] albumsAddAssetsDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<AlbumsAddAssetsResponseDto?> addAssetsToAlbums(AlbumsAddAssetsDto albumsAddAssetsDto, { String? key, String? slug, }) async {
final response = await addAssetsToAlbumsWithHttpInfo(albumsAddAssetsDto, key: key, slug: slug, );
Future<AlbumsAddAssetsResponseDto?> addAssetsToAlbums(AlbumsAddAssetsDto albumsAddAssetsDto,) async {
final response = await addAssetsToAlbumsWithHttpInfo(albumsAddAssetsDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}

View File

@@ -864,7 +864,6 @@ class AssetsApi {
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<Response> getAssetStatisticsWithHttpInfo({ bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/statistics';
@@ -913,7 +912,6 @@ class AssetsApi {
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<AssetStatsResponseDto?> getAssetStatistics({ bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
final response = await getAssetStatisticsWithHttpInfo( isFavorite: isFavorite, isTrashed: isTrashed, visibility: visibility, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -929,71 +927,6 @@ class AssetsApi {
return null;
}
/// Get random assets
///
/// Retrieve a specified number of random assets for the authenticated user.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<Response> getRandomWithHttpInfo({ num? count, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/random';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (count != null) {
queryParams.addAll(_queryParams('', 'count', count));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
apiPath,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Get random assets
///
/// Retrieve a specified number of random assets for the authenticated user.
///
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<List<AssetResponseDto>?> getRandom({ num? count, }) async {
final response = await getRandomWithHttpInfo( count: count, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<AssetResponseDto>') as List)
.cast<AssetResponseDto>()
.toList(growable: false);
}
return null;
}
/// Play asset video
///
/// Streams the video file for the specified asset. This endpoint also supports byte range requests.
@@ -1115,154 +1048,6 @@ class AssetsApi {
}
}
/// Replace asset
///
/// Replace the asset with new file, without changing its id.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<Response> replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/{id}/original'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>['multipart/form-data'];
bool hasFields = false;
final mp = MultipartRequest('PUT', Uri.parse(apiPath));
if (assetData != null) {
hasFields = true;
mp.fields[r'assetData'] = assetData.field;
mp.files.add(assetData);
}
if (deviceAssetId != null) {
hasFields = true;
mp.fields[r'deviceAssetId'] = parameterToString(deviceAssetId);
}
if (deviceId != null) {
hasFields = true;
mp.fields[r'deviceId'] = parameterToString(deviceId);
}
if (duration != null) {
hasFields = true;
mp.fields[r'duration'] = parameterToString(duration);
}
if (fileCreatedAt != null) {
hasFields = true;
mp.fields[r'fileCreatedAt'] = parameterToString(fileCreatedAt);
}
if (fileModifiedAt != null) {
hasFields = true;
mp.fields[r'fileModifiedAt'] = parameterToString(fileModifiedAt);
}
if (filename != null) {
hasFields = true;
mp.fields[r'filename'] = parameterToString(filename);
}
if (hasFields) {
postBody = mp;
}
return apiClient.invokeAPI(
apiPath,
'PUT',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Replace asset
///
/// Replace the asset with new file, without changing its id.
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<AssetMediaResponseDto?> replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, duration: duration, filename: filename, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetMediaResponseDto',) as AssetMediaResponseDto;
}
return null;
}
/// Run an asset job
///
/// Run a specific job on a set of assets.
@@ -1592,7 +1377,6 @@ class AssetsApi {
/// Sidecar file data
///
/// * [AssetVisibility] visibility:
/// Asset visibility
Future<Response> uploadAssetWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, List<AssetMetadataUpsertItemDto>? metadata, MultipartFile? sidecarData, AssetVisibility? visibility, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets';
@@ -1731,7 +1515,6 @@ class AssetsApi {
/// Sidecar file data
///
/// * [AssetVisibility] visibility:
/// Asset visibility
Future<AssetMediaResponseDto?> uploadAsset(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? xImmichChecksum, String? duration, String? filename, bool? isFavorite, String? livePhotoVideoId, List<AssetMetadataUpsertItemDto>? metadata, MultipartFile? sidecarData, AssetVisibility? visibility, }) async {
final response = await uploadAssetWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, xImmichChecksum: xImmichChecksum, duration: duration, filename: filename, isFavorite: isFavorite, livePhotoVideoId: livePhotoVideoId, metadata: metadata, sidecarData: sidecarData, visibility: visibility, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -1763,7 +1546,6 @@ class AssetsApi {
/// * [String] key:
///
/// * [AssetMediaSize] size:
/// Asset media size
///
/// * [String] slug:
Future<Response> viewAssetWithHttpInfo(String id, { bool? edited, String? key, AssetMediaSize? size, String? slug, }) async {
@@ -1819,7 +1601,6 @@ class AssetsApi {
/// * [String] key:
///
/// * [AssetMediaSize] size:
/// Asset media size
///
/// * [String] slug:
Future<MultipartFile?> viewAsset(String id, { bool? edited, String? key, AssetMediaSize? size, String? slug, }) async {

View File

@@ -218,6 +218,7 @@ class DatabaseBackupsAdminApi {
/// Parameters:
///
/// * [MultipartFile] file:
/// Database backup file
Future<Response> uploadDatabaseBackupWithHttpInfo({ MultipartFile? file, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/admin/database-backups/upload';
@@ -260,6 +261,7 @@ class DatabaseBackupsAdminApi {
/// Parameters:
///
/// * [MultipartFile] file:
/// Database backup file
Future<void> uploadDatabaseBackup({ MultipartFile? file, }) async {
final response = await uploadDatabaseBackupWithHttpInfo( file: file, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -249,328 +249,4 @@ class DeprecatedApi {
}
return null;
}
/// Retrieve queue counts and status
///
/// Retrieve the counts of the current queue, as well as the current status.
///
/// Note: This method returns the HTTP [Response].
Future<Response> getQueuesLegacyWithHttpInfo() async {
// ignore: prefer_const_declarations
final apiPath = r'/jobs';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
apiPath,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Retrieve queue counts and status
///
/// Retrieve the counts of the current queue, as well as the current status.
Future<QueuesResponseLegacyDto?> getQueuesLegacy() async {
final response = await getQueuesLegacyWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueuesResponseLegacyDto',) as QueuesResponseLegacyDto;
}
return null;
}
/// Get random assets
///
/// Retrieve a specified number of random assets for the authenticated user.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<Response> getRandomWithHttpInfo({ num? count, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/random';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (count != null) {
queryParams.addAll(_queryParams('', 'count', count));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
apiPath,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Get random assets
///
/// Retrieve a specified number of random assets for the authenticated user.
///
/// Parameters:
///
/// * [num] count:
/// Number of random assets to return
Future<List<AssetResponseDto>?> getRandom({ num? count, }) async {
final response = await getRandomWithHttpInfo( count: count, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<AssetResponseDto>') as List)
.cast<AssetResponseDto>()
.toList(growable: false);
}
return null;
}
/// Replace asset
///
/// Replace the asset with new file, without changing its id.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<Response> replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/assets/{id}/original'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>['multipart/form-data'];
bool hasFields = false;
final mp = MultipartRequest('PUT', Uri.parse(apiPath));
if (assetData != null) {
hasFields = true;
mp.fields[r'assetData'] = assetData.field;
mp.files.add(assetData);
}
if (deviceAssetId != null) {
hasFields = true;
mp.fields[r'deviceAssetId'] = parameterToString(deviceAssetId);
}
if (deviceId != null) {
hasFields = true;
mp.fields[r'deviceId'] = parameterToString(deviceId);
}
if (duration != null) {
hasFields = true;
mp.fields[r'duration'] = parameterToString(duration);
}
if (fileCreatedAt != null) {
hasFields = true;
mp.fields[r'fileCreatedAt'] = parameterToString(fileCreatedAt);
}
if (fileModifiedAt != null) {
hasFields = true;
mp.fields[r'fileModifiedAt'] = parameterToString(fileModifiedAt);
}
if (filename != null) {
hasFields = true;
mp.fields[r'filename'] = parameterToString(filename);
}
if (hasFields) {
postBody = mp;
}
return apiClient.invokeAPI(
apiPath,
'PUT',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Replace asset
///
/// Replace the asset with new file, without changing its id.
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
/// Asset file data
///
/// * [String] deviceAssetId (required):
/// Device asset ID
///
/// * [String] deviceId (required):
/// Device ID
///
/// * [DateTime] fileCreatedAt (required):
/// File creation date
///
/// * [DateTime] fileModifiedAt (required):
/// File modification date
///
/// * [String] key:
///
/// * [String] slug:
///
/// * [String] duration:
/// Duration (for videos)
///
/// * [String] filename:
/// Filename
Future<AssetMediaResponseDto?> replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? slug, String? duration, String? filename, }) async {
final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, slug: slug, duration: duration, filename: filename, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetMediaResponseDto',) as AssetMediaResponseDto;
}
return null;
}
/// Run jobs
///
/// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<Response> runQueueCommandLegacyWithHttpInfo(QueueName name, QueueCommandDto queueCommandDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/jobs/{name}'
.replaceAll('{name}', name.toString());
// ignore: prefer_final_locals
Object? postBody = queueCommandDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
apiPath,
'PUT',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Run jobs
///
/// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.
///
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<QueueResponseLegacyDto?> runQueueCommandLegacy(QueueName name, QueueCommandDto queueCommandDto,) async {
final response = await runQueueCommandLegacyWithHttpInfo(name, queueCommandDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueueResponseLegacyDto',) as QueueResponseLegacyDto;
}
return null;
}
}

View File

@@ -63,115 +63,4 @@ class JobsApi {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
}
/// Retrieve queue counts and status
///
/// Retrieve the counts of the current queue, as well as the current status.
///
/// Note: This method returns the HTTP [Response].
Future<Response> getQueuesLegacyWithHttpInfo() async {
// ignore: prefer_const_declarations
final apiPath = r'/jobs';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
apiPath,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Retrieve queue counts and status
///
/// Retrieve the counts of the current queue, as well as the current status.
Future<QueuesResponseLegacyDto?> getQueuesLegacy() async {
final response = await getQueuesLegacyWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueuesResponseLegacyDto',) as QueuesResponseLegacyDto;
}
return null;
}
/// Run jobs
///
/// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<Response> runQueueCommandLegacyWithHttpInfo(QueueName name, QueueCommandDto queueCommandDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/jobs/{name}'
.replaceAll('{name}', name.toString());
// ignore: prefer_final_locals
Object? postBody = queueCommandDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
apiPath,
'PUT',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Run jobs
///
/// Queue all assets for a specific job type. Defaults to only queueing assets that have not yet been processed, but the force command can be used to re-process all assets.
///
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueCommandDto] queueCommandDto (required):
Future<QueueResponseLegacyDto?> runQueueCommandLegacy(QueueName name, QueueCommandDto queueCommandDto,) async {
final response = await runQueueCommandLegacyWithHttpInfo(name, queueCommandDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'QueueResponseLegacyDto',) as QueueResponseLegacyDto;
}
return null;
}
}

View File

@@ -260,13 +260,11 @@ class MemoriesApi {
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<Response> memoriesStatisticsWithHttpInfo({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/memories/statistics';
@@ -327,13 +325,11 @@ class MemoriesApi {
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<MemoryStatisticsResponseDto?> memoriesStatistics({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
final response = await memoriesStatisticsWithHttpInfo( for_: for_, isSaved: isSaved, isTrashed: isTrashed, order: order, size: size, type: type, );
if (response.statusCode >= HttpStatus.badRequest) {
@@ -431,13 +427,11 @@ class MemoriesApi {
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<Response> searchMemoriesWithHttpInfo({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/memories';
@@ -498,13 +492,11 @@ class MemoriesApi {
/// Include trashed memories
///
/// * [MemorySearchOrder] order:
/// Sort order
///
/// * [int] size:
/// Number of memories to return
///
/// * [MemoryType] type:
/// Memory type
Future<List<MemoryResponseDto>?> searchMemories({ DateTime? for_, bool? isSaved, bool? isTrashed, MemorySearchOrder? order, int? size, MemoryType? type, }) async {
final response = await searchMemoriesWithHttpInfo( for_: for_, isSaved: isSaved, isTrashed: isTrashed, order: order, size: size, type: type, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -182,10 +182,8 @@ class NotificationsApi {
/// Filter by notification ID
///
/// * [NotificationLevel] level:
/// Filter by notification level
///
/// * [NotificationType] type:
/// Filter by notification type
///
/// * [bool] unread:
/// Filter by unread status
@@ -237,10 +235,8 @@ class NotificationsApi {
/// Filter by notification ID
///
/// * [NotificationLevel] level:
/// Filter by notification level
///
/// * [NotificationType] type:
/// Filter by notification type
///
/// * [bool] unread:
/// Filter by unread status

View File

@@ -138,7 +138,6 @@ class PartnersApi {
/// Parameters:
///
/// * [PartnerDirection] direction (required):
/// Partner direction
Future<Response> getPartnersWithHttpInfo(PartnerDirection direction,) async {
// ignore: prefer_const_declarations
final apiPath = r'/partners';
@@ -173,7 +172,6 @@ class PartnersApi {
/// Parameters:
///
/// * [PartnerDirection] direction (required):
/// Partner direction
Future<List<PartnerResponseDto>?> getPartners(PartnerDirection direction,) async {
final response = await getPartnersWithHttpInfo(direction,);
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -25,7 +25,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueDeleteDto] queueDeleteDto (required):
Future<Response> emptyQueueWithHttpInfo(QueueName name, QueueDeleteDto queueDeleteDto,) async {
@@ -61,7 +60,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueDeleteDto] queueDeleteDto (required):
Future<void> emptyQueue(QueueName name, QueueDeleteDto queueDeleteDto,) async {
@@ -80,7 +78,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
Future<Response> getQueueWithHttpInfo(QueueName name,) async {
// ignore: prefer_const_declarations
final apiPath = r'/queues/{name}'
@@ -114,7 +111,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
Future<QueueResponseDto?> getQueue(QueueName name,) async {
final response = await getQueueWithHttpInfo(name,);
if (response.statusCode >= HttpStatus.badRequest) {
@@ -139,7 +135,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [List<QueueJobStatus>] status:
/// Filter jobs by status
@@ -180,7 +175,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [List<QueueJobStatus>] status:
/// Filter jobs by status
@@ -262,7 +256,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueUpdateDto] queueUpdateDto (required):
Future<Response> updateQueueWithHttpInfo(QueueName name, QueueUpdateDto queueUpdateDto,) async {
@@ -298,7 +291,6 @@ class QueuesApi {
/// Parameters:
///
/// * [QueueName] name (required):
/// Queue name
///
/// * [QueueUpdateDto] queueUpdateDto (required):
Future<QueueResponseDto?> updateQueue(QueueName name, QueueUpdateDto queueUpdateDto,) async {

View File

@@ -127,7 +127,6 @@ class SearchApi {
/// Parameters:
///
/// * [SearchSuggestionType] type (required):
/// Suggestion type
///
/// * [String] country:
/// Filter by country
@@ -198,7 +197,6 @@ class SearchApi {
/// Parameters:
///
/// * [SearchSuggestionType] type (required):
/// Suggestion type
///
/// * [String] country:
/// Filter by country
@@ -434,7 +432,6 @@ class SearchApi {
/// Filter by trash date (before)
///
/// * [AssetTypeEnum] type:
/// Asset type filter
///
/// * [DateTime] updatedAfter:
/// Filter by update date (after)
@@ -443,7 +440,6 @@ class SearchApi {
/// Filter by update date (before)
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
///
/// * [bool] withDeleted:
/// Include deleted assets
@@ -657,7 +653,6 @@ class SearchApi {
/// Filter by trash date (before)
///
/// * [AssetTypeEnum] type:
/// Asset type filter
///
/// * [DateTime] updatedAfter:
/// Filter by update date (after)
@@ -666,7 +661,6 @@ class SearchApi {
/// Filter by update date (before)
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
///
/// * [bool] withDeleted:
/// Include deleted assets

View File

@@ -281,7 +281,7 @@ class ServerApi {
/// Get product key
///
/// Retrieve information about whether the server currently has a product key registered.
Future<LicenseResponseDto?> getServerLicense() async {
Future<UserLicense?> getServerLicense() async {
final response = await getServerLicenseWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -290,7 +290,7 @@ class ServerApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'LicenseResponseDto',) as LicenseResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserLicense',) as UserLicense;
}
return null;
@@ -724,7 +724,7 @@ class ServerApi {
/// Parameters:
///
/// * [LicenseKeyDto] licenseKeyDto (required):
Future<LicenseResponseDto?> setServerLicense(LicenseKeyDto licenseKeyDto,) async {
Future<UserLicense?> setServerLicense(LicenseKeyDto licenseKeyDto,) async {
final response = await setServerLicenseWithHttpInfo(licenseKeyDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -733,7 +733,7 @@ class ServerApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'LicenseResponseDto',) as LicenseResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserLicense',) as UserLicense;
}
return null;

View File

@@ -27,11 +27,7 @@ class SharedLinksApi {
/// * [String] id (required):
///
/// * [AssetIdsDto] assetIdsDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> addSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, String? slug, }) async {
Future<Response> addSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/shared-links/{id}/assets'
.replaceAll('{id}', id);
@@ -43,13 +39,6 @@ class SharedLinksApi {
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>['application/json'];
@@ -73,12 +62,8 @@ class SharedLinksApi {
/// * [String] id (required):
///
/// * [AssetIdsDto] assetIdsDto (required):
///
/// * [String] key:
///
/// * [String] slug:
Future<List<AssetIdsResponseDto>?> addSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String? key, String? slug, }) async {
final response = await addSharedLinkAssetsWithHttpInfo(id, assetIdsDto, key: key, slug: slug, );
Future<List<AssetIdsResponseDto>?> addSharedLinkAssets(String id, AssetIdsDto assetIdsDto,) async {
final response = await addSharedLinkAssetsWithHttpInfo(id, assetIdsDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -235,14 +220,8 @@ class SharedLinksApi {
///
/// * [String] key:
///
/// * [String] password:
/// Link password
///
/// * [String] slug:
///
/// * [String] token:
/// Access token
Future<Response> getMySharedLinkWithHttpInfo({ String? key, String? password, String? slug, String? token, }) async {
Future<Response> getMySharedLinkWithHttpInfo({ String? key, String? slug, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/shared-links/me';
@@ -256,15 +235,9 @@ class SharedLinksApi {
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (password != null) {
queryParams.addAll(_queryParams('', 'password', password));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
if (token != null) {
queryParams.addAll(_queryParams('', 'token', token));
}
const contentTypes = <String>[];
@@ -288,15 +261,9 @@ class SharedLinksApi {
///
/// * [String] key:
///
/// * [String] password:
/// Link password
///
/// * [String] slug:
///
/// * [String] token:
/// Access token
Future<SharedLinkResponseDto?> getMySharedLink({ String? key, String? password, String? slug, String? token, }) async {
final response = await getMySharedLinkWithHttpInfo( key: key, password: password, slug: slug, token: token, );
Future<SharedLinkResponseDto?> getMySharedLink({ String? key, String? slug, }) async {
final response = await getMySharedLinkWithHttpInfo( key: key, slug: slug, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}

View File

@@ -25,7 +25,7 @@ class TimelineApi {
/// Parameters:
///
/// * [String] timeBucket (required):
/// Time bucket identifier in YYYY-MM-DD format (e.g., \"2024-01-01\" for January 2024)
/// Time bucket identifier in YYYY-MM-DD format
///
/// * [String] albumId:
/// Filter assets belonging to a specific album
@@ -142,7 +142,7 @@ class TimelineApi {
/// Parameters:
///
/// * [String] timeBucket (required):
/// Time bucket identifier in YYYY-MM-DD format (e.g., \"2024-01-01\" for January 2024)
/// Time bucket identifier in YYYY-MM-DD format
///
/// * [String] albumId:
/// Filter assets belonging to a specific album

View File

@@ -324,7 +324,6 @@ class UsersAdminApi {
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<Response> getUserStatisticsAdminWithHttpInfo(String id, { bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/admin/users/{id}/statistics'
@@ -376,7 +375,6 @@ class UsersAdminApi {
/// Filter by trash status
///
/// * [AssetVisibility] visibility:
/// Filter by visibility
Future<AssetStatsResponseDto?> getUserStatisticsAdmin(String id, { bool? isFavorite, bool? isTrashed, AssetVisibility? visibility, }) async {
final response = await getUserStatisticsAdminWithHttpInfo(id, isFavorite: isFavorite, isTrashed: isTrashed, visibility: visibility, );
if (response.statusCode >= HttpStatus.badRequest) {

View File

@@ -447,7 +447,7 @@ class UsersApi {
/// Retrieve user product key
///
/// Retrieve information about whether the current user has a registered product key.
Future<LicenseResponseDto?> getUserLicense() async {
Future<UserLicense?> getUserLicense() async {
final response = await getUserLicenseWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -456,7 +456,7 @@ class UsersApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'LicenseResponseDto',) as LicenseResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserLicense',) as UserLicense;
}
return null;
@@ -602,7 +602,7 @@ class UsersApi {
/// Parameters:
///
/// * [LicenseKeyDto] licenseKeyDto (required):
Future<LicenseResponseDto?> setUserLicense(LicenseKeyDto licenseKeyDto,) async {
Future<UserLicense?> setUserLicense(LicenseKeyDto licenseKeyDto,) async {
final response = await setUserLicenseWithHttpInfo(licenseKeyDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -611,7 +611,7 @@ class UsersApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'LicenseResponseDto',) as LicenseResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserLicense',) as UserLicense;
}
return null;

View File

@@ -264,6 +264,8 @@ class ApiClient {
return AssetFaceWithoutPersonResponseDto.fromJson(value);
case 'AssetFullSyncDto':
return AssetFullSyncDto.fromJson(value);
case 'AssetIdErrorReason':
return AssetIdErrorReasonTypeTransformer().decode(value);
case 'AssetIdsDto':
return AssetIdsDto.fromJson(value);
case 'AssetIdsResponseDto':
@@ -298,6 +300,8 @@ class ApiClient {
return AssetOcrResponseDto.fromJson(value);
case 'AssetOrder':
return AssetOrderTypeTransformer().decode(value);
case 'AssetRejectReason':
return AssetRejectReasonTypeTransformer().decode(value);
case 'AssetResponseDto':
return AssetResponseDto.fromJson(value);
case 'AssetStackResponseDto':
@@ -306,6 +310,8 @@ class ApiClient {
return AssetStatsResponseDto.fromJson(value);
case 'AssetTypeEnum':
return AssetTypeEnumTypeTransformer().decode(value);
case 'AssetUploadAction':
return AssetUploadActionTypeTransformer().decode(value);
case 'AssetVisibility':
return AssetVisibilityTypeTransformer().decode(value);
case 'AudioCodec':
@@ -402,8 +408,6 @@ class ApiClient {
return LibraryStatsResponseDto.fromJson(value);
case 'LicenseKeyDto':
return LicenseKeyDto.fromJson(value);
case 'LicenseResponseDto':
return LicenseResponseDto.fromJson(value);
case 'LogLevel':
return LogLevelTypeTransformer().decode(value);
case 'LoginCredentialDto':
@@ -530,6 +534,14 @@ class ApiClient {
return PluginContextTypeTypeTransformer().decode(value);
case 'PluginFilterResponseDto':
return PluginFilterResponseDto.fromJson(value);
case 'PluginJsonSchema':
return PluginJsonSchema.fromJson(value);
case 'PluginJsonSchemaProperty':
return PluginJsonSchemaProperty.fromJson(value);
case 'PluginJsonSchemaPropertyAdditionalProperties':
return PluginJsonSchemaPropertyAdditionalProperties.fromJson(value);
case 'PluginJsonSchemaType':
return PluginJsonSchemaTypeTypeTransformer().decode(value);
case 'PluginResponseDto':
return PluginResponseDto.fromJson(value);
case 'PluginTriggerResponseDto':
@@ -540,10 +552,6 @@ class ApiClient {
return PurchaseResponse.fromJson(value);
case 'PurchaseUpdate':
return PurchaseUpdate.fromJson(value);
case 'QueueCommand':
return QueueCommandTypeTransformer().decode(value);
case 'QueueCommandDto':
return QueueCommandDto.fromJson(value);
case 'QueueDeleteDto':
return QueueDeleteDto.fromJson(value);
case 'QueueJobResponseDto':
@@ -554,16 +562,10 @@ class ApiClient {
return QueueNameTypeTransformer().decode(value);
case 'QueueResponseDto':
return QueueResponseDto.fromJson(value);
case 'QueueResponseLegacyDto':
return QueueResponseLegacyDto.fromJson(value);
case 'QueueStatisticsDto':
return QueueStatisticsDto.fromJson(value);
case 'QueueStatusLegacyDto':
return QueueStatusLegacyDto.fromJson(value);
case 'QueueUpdateDto':
return QueueUpdateDto.fromJson(value);
case 'QueuesResponseLegacyDto':
return QueuesResponseLegacyDto.fromJson(value);
case 'RandomSearchDto':
return RandomSearchDto.fromJson(value);
case 'RatingsResponse':

View File

@@ -61,6 +61,9 @@ String parameterToString(dynamic value) {
if (value is AssetEditAction) {
return AssetEditActionTypeTransformer().encode(value).toString();
}
if (value is AssetIdErrorReason) {
return AssetIdErrorReasonTypeTransformer().encode(value).toString();
}
if (value is AssetJobName) {
return AssetJobNameTypeTransformer().encode(value).toString();
}
@@ -73,9 +76,15 @@ String parameterToString(dynamic value) {
if (value is AssetOrder) {
return AssetOrderTypeTransformer().encode(value).toString();
}
if (value is AssetRejectReason) {
return AssetRejectReasonTypeTransformer().encode(value).toString();
}
if (value is AssetTypeEnum) {
return AssetTypeEnumTypeTransformer().encode(value).toString();
}
if (value is AssetUploadAction) {
return AssetUploadActionTypeTransformer().encode(value).toString();
}
if (value is AssetVisibility) {
return AssetVisibilityTypeTransformer().encode(value).toString();
}
@@ -133,12 +142,12 @@ String parameterToString(dynamic value) {
if (value is PluginContextType) {
return PluginContextTypeTypeTransformer().encode(value).toString();
}
if (value is PluginJsonSchemaType) {
return PluginJsonSchemaTypeTypeTransformer().encode(value).toString();
}
if (value is PluginTriggerType) {
return PluginTriggerTypeTypeTransformer().encode(value).toString();
}
if (value is QueueCommand) {
return QueueCommandTypeTransformer().encode(value).toString();
}
if (value is QueueJobStatus) {
return QueueJobStatusTypeTransformer().encode(value).toString();
}

View File

@@ -40,7 +40,6 @@ class ActivityCreateDto {
///
String? comment;
/// Activity type (like or comment)
ReactionType type;
@override

View File

@@ -33,7 +33,6 @@ class ActivityResponseDto {
/// Activity ID
String id;
/// Activity type
ReactionType type;
UserResponseDto user;
@@ -72,7 +71,9 @@ class ActivityResponseDto {
} else {
// json[r'comment'] = null;
}
json[r'createdAt'] = this.createdAt.toUtc().toIso8601String();
json[r'createdAt'] = _isEpochMarker(r'/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/')
? this.createdAt.millisecondsSinceEpoch
: this.createdAt.toUtc().toIso8601String();
json[r'id'] = this.id;
json[r'type'] = this.type;
json[r'user'] = this.user;
@@ -90,7 +91,7 @@ class ActivityResponseDto {
return ActivityResponseDto(
assetId: mapValueOfType<String>(json, r'assetId'),
comment: mapValueOfType<String>(json, r'comment'),
createdAt: mapDateTime(json, r'createdAt', r'')!,
createdAt: mapDateTime(json, r'createdAt', r'/^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$/')!,
id: mapValueOfType<String>(json, r'id')!,
type: ReactionType.fromJson(json[r'type'])!,
user: UserResponseDto.fromJson(json[r'user'])!,

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