mirror of
https://github.com/immich-app/immich.git
synced 2025-12-11 07:11:05 -08:00
Compare commits
105 Commits
fix/timeli
...
drift-map-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03c820931e | ||
|
|
6cea779b2d | ||
|
|
196f2a72f4 | ||
|
|
7f9bc092ac | ||
|
|
dc807777d6 | ||
|
|
6ad2e8e155 | ||
|
|
e6c46fe0bf | ||
|
|
749582b6d8 | ||
|
|
94c073e58f | ||
|
|
5d722eef98 | ||
|
|
d308d023c2 | ||
|
|
da5deffd03 | ||
|
|
9f20522df5 | ||
|
|
baadf9db20 | ||
|
|
4ea4ee40af | ||
|
|
d8a6552811 | ||
|
|
444133a72b | ||
|
|
29f16c6a47 | ||
|
|
268b411a6f | ||
|
|
07ed060c32 | ||
|
|
2f5d543ad9 | ||
|
|
9b65cd4d7b | ||
|
|
290e325c5c | ||
|
|
58521c9efb | ||
|
|
4cae15f28d | ||
|
|
e6ec019852 | ||
|
|
3b5e00131b | ||
|
|
a0fa7318ed | ||
|
|
2a005629a0 | ||
|
|
59a50b8697 | ||
|
|
90eac40e02 | ||
|
|
ad6f7f8089 | ||
|
|
056b262cba | ||
|
|
cfae134ecf | ||
|
|
fbbb6af27a | ||
|
|
1804a8fe58 | ||
|
|
ae1d60e259 | ||
|
|
7d759edfcc | ||
|
|
34974b036c | ||
|
|
e52b9d15b5 | ||
|
|
9b3718120b | ||
|
|
16b14b390f | ||
|
|
7e7b8da128 | ||
|
|
66ea75072d | ||
|
|
d34670bae6 | ||
|
|
1e1c2ea627 | ||
|
|
c7fcb23a23 | ||
|
|
708e42d8a3 | ||
|
|
d15f67da5d | ||
|
|
6becf409da | ||
|
|
ee4ae40d61 | ||
|
|
ebd644eedd | ||
|
|
7c36cbaf0f | ||
|
|
3a5d82f790 | ||
|
|
b14c768208 | ||
|
|
07cb2fb04e | ||
|
|
9bbad45990 | ||
|
|
e85655d34c | ||
|
|
d0576697c3 | ||
|
|
f9847bee51 | ||
|
|
f2141de5bb | ||
|
|
cb344cb014 | ||
|
|
c6b25ef111 | ||
|
|
0fdeac0417 | ||
|
|
153bb70f6e | ||
|
|
da80b69062 | ||
|
|
f9292c9c96 | ||
|
|
2e0ee6ec05 | ||
|
|
7f2e4f85f8 | ||
|
|
c63f805cb4 | ||
|
|
03a13828e1 | ||
|
|
e5ee1c8db6 | ||
|
|
25e2d37490 | ||
|
|
ed5759fe07 | ||
|
|
edefed56ae | ||
|
|
13281f8531 | ||
|
|
b48406bd20 | ||
|
|
06c78dfa91 | ||
|
|
de67d22bc0 | ||
|
|
b4780e89af | ||
|
|
ad65e9011a | ||
|
|
977c9b96ba | ||
|
|
aa2828ab33 | ||
|
|
a36840d7cc | ||
|
|
e34f46fa0d | ||
|
|
6170a3843c | ||
|
|
563e2ab503 | ||
|
|
79157e1043 | ||
|
|
02688a2a03 | ||
|
|
3b9bfceef0 | ||
|
|
089085fcdb | ||
|
|
fc68cf4f32 | ||
|
|
0051a9bba5 | ||
|
|
f27bdf7523 | ||
|
|
c1c9f30ea4 | ||
|
|
bc8cb9b671 | ||
|
|
a675922172 | ||
|
|
2bead445bd | ||
|
|
0e1c8c2b80 | ||
|
|
0174de19dd | ||
|
|
1a35a01149 | ||
|
|
08122d6871 | ||
|
|
92384c28de | ||
|
|
ab597155fa | ||
|
|
1d9cc4ca5f |
@@ -11,8 +11,8 @@ services:
|
||||
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
||||
- server_node_modules:/workspaces/immich/server/node_modules
|
||||
- web_node_modules:/workspaces/immich/web/node_modules
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}/photos:/data
|
||||
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
database:
|
||||
|
||||
@@ -13,8 +13,8 @@ services:
|
||||
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
|
||||
- server_node_modules:/workspaces/immich/server/node_modules
|
||||
- web_node_modules:/workspaces/immich/web/node_modules
|
||||
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/usr/src/app/upload/upload
|
||||
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
|
||||
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
immich-web:
|
||||
|
||||
8
.github/workflows/build-mobile.yml
vendored
8
.github/workflows/build-mobile.yml
vendored
@@ -122,17 +122,17 @@ jobs:
|
||||
IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
|
||||
run: |
|
||||
if [[ $IS_MAIN == 'true' ]]; then
|
||||
flutter build apk --release --flavor production
|
||||
flutter build apk --release --flavor production --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
||||
flutter build apk --release
|
||||
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
|
||||
else
|
||||
flutter build apk --debug --flavor production --split-per-abi --target-platform android-arm64
|
||||
flutter build apk --debug --split-per-abi --target-platform android-arm64
|
||||
fi
|
||||
|
||||
- name: Publish Android Artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: release-apk-signed
|
||||
path: mobile/build/app/outputs/flutter-apk/**/*.apk
|
||||
path: mobile/build/app/outputs/flutter-apk/*.apk
|
||||
|
||||
- name: Save Gradle Cache
|
||||
id: cache-gradle-save
|
||||
|
||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -63,7 +63,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@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||
uses: github/codeql-action/autobuild@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
|
||||
# ℹ️ 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
|
||||
@@ -76,6 +76,6 @@ jobs:
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||
uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
with:
|
||||
category: '/language:${{matrix.language}}'
|
||||
|
||||
6
.github/workflows/static_analysis.yml
vendored
6
.github/workflows/static_analysis.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
env:
|
||||
CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }}
|
||||
run: |
|
||||
echo "ERROR: Generated files not up to date! Run make_build inside the mobile directory"
|
||||
echo "ERROR: Generated files not up to date! Run 'make build' and 'make pigeon' inside the mobile directory"
|
||||
echo "Changed files: ${CHANGED_FILES}"
|
||||
exit 1
|
||||
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
run: dart analyze --fatal-infos
|
||||
|
||||
- name: Run dart format
|
||||
run: dart format lib/ --set-exit-if-changed
|
||||
run: make format
|
||||
|
||||
- name: Run dart custom_lint
|
||||
run: dart run custom_lint
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
|
||||
uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
category: zizmor
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -668,7 +668,7 @@ jobs:
|
||||
contents: read
|
||||
services:
|
||||
postgres:
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:1f5583fe3397210a0fbc7f11b0cec18bacc4a99e3e8ea0548e9bd6bcf26ec37a
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:ec713143dca1a426eba2e03707c319e2ec3cc9d304ef767f777f8e297dee820c
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
|
||||
2
.github/workflows/weblate-lock.yml
vendored
2
.github/workflows/weblate-lock.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
- name: Find Pull Request
|
||||
uses: juliangruber/find-pull-request-action@48b6133aa6c826f267ebd33aa2d29470f9d9e7d0 # v1.9.0
|
||||
uses: juliangruber/find-pull-request-action@952b3bb1ddb2dcc0aa3479e98bb1c2d1a922f096 # v1.10.0
|
||||
id: find-pr
|
||||
with:
|
||||
branch: chore/translations
|
||||
|
||||
23
.vscode/launch.json
vendored
23
.vscode/launch.json
vendored
@@ -7,7 +7,7 @@
|
||||
"restart": true,
|
||||
"port": 9231,
|
||||
"name": "Immich API Server",
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"remoteRoot": "/usr/src/app/server",
|
||||
"localRoot": "${workspaceFolder}/server"
|
||||
},
|
||||
{
|
||||
@@ -16,27 +16,8 @@
|
||||
"restart": true,
|
||||
"port": 9230,
|
||||
"name": "Immich Workers",
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"remoteRoot": "/usr/src/app/server",
|
||||
"localRoot": "${workspaceFolder}/server"
|
||||
},
|
||||
{
|
||||
"name": "Flavor - Production",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"codeLens": {
|
||||
"for": [
|
||||
"run-test",
|
||||
"run-test-file",
|
||||
"run-file",
|
||||
"debug-test",
|
||||
"debug-test-file",
|
||||
"debug-file",
|
||||
],
|
||||
"title": "${debugType}",
|
||||
},
|
||||
"args": [
|
||||
"--flavor", "production"
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
154
cli/package-lock.json
generated
154
cli/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.73",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.73",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"chokidar": "^4.0.3",
|
||||
@@ -27,13 +27,13 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"commander": "^12.0.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"globals": "^16.0.0",
|
||||
@@ -54,14 +54,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.135.3",
|
||||
"version": "1.136.0",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -1365,17 +1365,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz",
|
||||
"integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz",
|
||||
"integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.37.0",
|
||||
"@typescript-eslint/type-utils": "8.37.0",
|
||||
"@typescript-eslint/utils": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0",
|
||||
"@typescript-eslint/scope-manager": "8.38.0",
|
||||
"@typescript-eslint/type-utils": "8.38.0",
|
||||
"@typescript-eslint/utils": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@@ -1389,7 +1389,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.37.0",
|
||||
"@typescript-eslint/parser": "^8.38.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@@ -1405,16 +1405,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz",
|
||||
"integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz",
|
||||
"integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.37.0",
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0",
|
||||
"@typescript-eslint/scope-manager": "8.38.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1430,14 +1430,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz",
|
||||
"integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
|
||||
"integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.37.0",
|
||||
"@typescript-eslint/types": "^8.37.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.38.0",
|
||||
"@typescript-eslint/types": "^8.38.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1452,14 +1452,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz",
|
||||
"integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz",
|
||||
"integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0"
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1470,9 +1470,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz",
|
||||
"integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
|
||||
"integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1487,15 +1487,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz",
|
||||
"integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz",
|
||||
"integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0",
|
||||
"@typescript-eslint/utils": "8.37.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0",
|
||||
"@typescript-eslint/utils": "8.38.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@@ -1512,9 +1512,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz",
|
||||
"integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz",
|
||||
"integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1526,16 +1526,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz",
|
||||
"integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
|
||||
"integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.37.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.37.0",
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0",
|
||||
"@typescript-eslint/project-service": "8.38.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.38.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -1581,16 +1581,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz",
|
||||
"integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz",
|
||||
"integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.37.0",
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0"
|
||||
"@typescript-eslint/scope-manager": "8.38.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1605,13 +1605,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz",
|
||||
"integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz",
|
||||
"integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2367,9 +2367,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "10.1.5",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz",
|
||||
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
|
||||
"version": "10.1.8",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -2383,9 +2383,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz",
|
||||
"integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==",
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz",
|
||||
"integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3548,15 +3548,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-organize-imports": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz",
|
||||
"integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz",
|
||||
"integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"prettier": ">=2.0",
|
||||
"typescript": ">=2.9",
|
||||
"vue-tsc": "^2.1.0"
|
||||
"vue-tsc": "^2.1.0 || 3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"vue-tsc": {
|
||||
@@ -4139,16 +4139,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz",
|
||||
"integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz",
|
||||
"integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.37.0",
|
||||
"@typescript-eslint/parser": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0",
|
||||
"@typescript-eslint/utils": "8.37.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.38.0",
|
||||
"@typescript-eslint/parser": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0",
|
||||
"@typescript-eslint/utils": "8.38.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.73",
|
||||
"description": "Command Line Interface (CLI) for Immich",
|
||||
"type": "module",
|
||||
"exports": "./dist/index.js",
|
||||
@@ -21,13 +21,13 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"commander": "^12.0.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"globals": "^16.0.0",
|
||||
|
||||
@@ -2,37 +2,37 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.52.0"
|
||||
constraints = "4.52.0"
|
||||
version = "4.52.1"
|
||||
constraints = "4.52.1"
|
||||
hashes = [
|
||||
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
|
||||
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
|
||||
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
|
||||
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
|
||||
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
|
||||
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
|
||||
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
|
||||
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
|
||||
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
|
||||
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
|
||||
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
|
||||
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
|
||||
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
|
||||
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
|
||||
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
|
||||
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
|
||||
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
|
||||
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
|
||||
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
|
||||
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
|
||||
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
|
||||
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
|
||||
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
|
||||
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
|
||||
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
|
||||
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
|
||||
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
|
||||
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
|
||||
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
|
||||
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
|
||||
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
|
||||
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
|
||||
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
|
||||
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
|
||||
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
|
||||
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
|
||||
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
|
||||
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
|
||||
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
|
||||
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
|
||||
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
|
||||
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
|
||||
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
|
||||
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
|
||||
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
|
||||
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
|
||||
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
|
||||
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
|
||||
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
|
||||
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
|
||||
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
|
||||
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
|
||||
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
|
||||
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
|
||||
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.52.0"
|
||||
version = "4.52.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,37 +2,37 @@
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.opentofu.org/cloudflare/cloudflare" {
|
||||
version = "4.52.0"
|
||||
constraints = "4.52.0"
|
||||
version = "4.52.1"
|
||||
constraints = "4.52.1"
|
||||
hashes = [
|
||||
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
|
||||
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
|
||||
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
|
||||
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
|
||||
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
|
||||
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
|
||||
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
|
||||
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
|
||||
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
|
||||
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
|
||||
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
|
||||
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
|
||||
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
|
||||
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
|
||||
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
|
||||
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
|
||||
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
|
||||
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
|
||||
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
|
||||
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
|
||||
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
|
||||
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
|
||||
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
|
||||
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
|
||||
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
|
||||
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
|
||||
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
|
||||
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
|
||||
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
|
||||
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
|
||||
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
|
||||
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
|
||||
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
|
||||
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
|
||||
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
|
||||
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
|
||||
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
|
||||
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
|
||||
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
|
||||
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
|
||||
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
|
||||
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
|
||||
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
|
||||
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
|
||||
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
|
||||
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
|
||||
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
|
||||
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
|
||||
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
|
||||
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
|
||||
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
|
||||
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
|
||||
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
|
||||
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
|
||||
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ terraform {
|
||||
required_providers {
|
||||
cloudflare = {
|
||||
source = "cloudflare/cloudflare"
|
||||
version = "4.52.0"
|
||||
version = "4.52.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ services:
|
||||
volumes:
|
||||
- ../server:/usr/src/app/server
|
||||
- ../open-api:/usr/src/app/open-api
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload
|
||||
- ${UPLOAD_LOCATION}/photos:/data
|
||||
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
|
||||
- /usr/src/app/server/node_modules
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
@@ -123,7 +123,7 @@ services:
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
|
||||
@@ -20,7 +20,7 @@ services:
|
||||
context: ../
|
||||
dockerfile: server/Dockerfile
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}/photos:/data
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
@@ -63,7 +63,7 @@ services:
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
|
||||
volumes:
|
||||
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}:/data
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
env_file:
|
||||
- .env
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
|
||||
@@ -180,7 +180,7 @@ services:
|
||||
...
|
||||
volumes:
|
||||
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}:/data
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
+ - originals:/usr/src/app/originals
|
||||
...
|
||||
|
||||
@@ -94,19 +94,16 @@ Change media location
|
||||
|
||||
```
|
||||
immich-admin change-media-location
|
||||
? Enter the previous value of IMMICH_MEDIA_LOCATION: /usr/src/app/upload
|
||||
? Enter the new value of IMMICH_MEDIA_LOCATION: /data
|
||||
? Enter the previous value of IMMICH_MEDIA_LOCATION: /data
|
||||
? Enter the new value of IMMICH_MEDIA_LOCATION: /my-data
|
||||
...
|
||||
Previous value: /data
|
||||
Current value: /my-data
|
||||
|
||||
Previous value: /usr/src/app/upload
|
||||
Current value: /data
|
||||
|
||||
Changing database paths from "/usr/src/app/upload/*" to "/data/*"
|
||||
Changing database paths from "/data/*" to "/my-data/*"
|
||||
|
||||
? Do you want to proceed? [Y/n] y
|
||||
|
||||
Database file paths updated successfully! 🎉
|
||||
|
||||
You may now set IMMICH_MEDIA_LOCATION=/data and restart!
|
||||
|
||||
(please remember to update applicable volume mounts e.g. ${UPLOAD_LOCATION}:/data)
|
||||
...
|
||||
```
|
||||
|
||||
@@ -38,6 +38,19 @@ Run all server checks with `npm run check:all`
|
||||
You can use `npm run __:fix` to potentially correct some issues automatically for `npm run format` and `lint`.
|
||||
:::
|
||||
|
||||
## Mobile Checks
|
||||
|
||||
The following commands must be executed from within the mobile app directory of the codebase.
|
||||
|
||||
- [ ] `make build` (auto-generate files using build_runner)
|
||||
- [ ] `make analyze` (static analysis via Dart Analyzer and DCM)
|
||||
- [ ] `make format` (formatting via Dart Formatter)
|
||||
- [ ] `make test` (unit tests)
|
||||
|
||||
:::info Auto Fix
|
||||
You can use `dart fix --apply` and `dcm fix lib` to potentially correct some issues automatically for `make analyze`.
|
||||
:::
|
||||
|
||||
## OpenAPI
|
||||
|
||||
The OpenAPI client libraries need to be regenerated whenever there are changes to the `immich-openapi-specs.json` file. Note that you should not modify this file directly as it is auto-generated. See [OpenAPI](/docs/developer/open-api.md) for more details.
|
||||
|
||||
@@ -58,7 +58,7 @@ Internally, Immich uses the [glob](https://www.npmjs.com/package/glob) package t
|
||||
|
||||
This feature is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan.
|
||||
|
||||
If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a periodic library refresh to pull in your changes.
|
||||
If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a [periodic library refresh](#set-custom-scan-interval) to pull in your changes.
|
||||
|
||||
#### Troubleshooting
|
||||
|
||||
@@ -72,7 +72,9 @@ In rare cases, the library watcher can hang, preventing Immich from starting up.
|
||||
|
||||
### Nightly job
|
||||
|
||||
There is an automatic scan job that is scheduled to run once a day. This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page.
|
||||
There is an automatic scan job that is scheduled to run once a day. Its schedule is configurable, see [Set Custom Scan Interval](#set-custom-scan-interval).
|
||||
|
||||
This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -91,7 +93,7 @@ The `immich-server` container will need access to the gallery. Modify your docke
|
||||
```diff title="docker-compose.yml"
|
||||
immich-server:
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}:/data
|
||||
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
|
||||
+ - /home/user/old-pics:/mnt/media/old-pics:ro
|
||||
+ - /mnt/media/videos:/mnt/media/videos:ro
|
||||
|
||||
@@ -27,11 +27,11 @@ After defining the locations of these files, we will edit the `docker-compose.ym
|
||||
services:
|
||||
immich-server:
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs
|
||||
+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video
|
||||
+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile
|
||||
+ - ${BACKUP_LOCATION}:/usr/src/app/upload/backups
|
||||
- ${UPLOAD_LOCATION}:/data
|
||||
+ - ${THUMB_LOCATION}:/data/thumbs
|
||||
+ - ${ENCODED_VIDEO_LOCATION}:/data/encoded-video
|
||||
+ - ${PROFILE_LOCATION}:/data/profile
|
||||
+ - ${BACKUP_LOCATION}:/data/backups
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ docker compose up -d
|
||||
|
||||
:::note
|
||||
Because of the underlying properties of docker bind mounts, it is not recommended to mount the `upload/` and `library/` folders as separate bind mounts if they are on the same device.
|
||||
For this reason, we mount the HDD or the network storage (NAS) to `/usr/src/app/upload` and then mount the folders we want to access under that folder.
|
||||
For this reason, we mount the HDD or the network storage (NAS) to `/data` and then mount the folders we want to access under that folder.
|
||||
|
||||
The `thumbs/` folder contains both the small thumbnails displayed in the timeline and the larger previews shown when clicking into an image. These cannot be separated.
|
||||
|
||||
|
||||
@@ -12,118 +12,148 @@ Run `docker exec -it immich_postgres psql --dbname=<DB_DATABASE_NAME> --username
|
||||
|
||||
## Assets
|
||||
|
||||
### Name
|
||||
|
||||
:::note
|
||||
The `"originalFileName"` column is the name of the file at time of upload, including the extension.
|
||||
:::
|
||||
|
||||
```sql title="Find by original filename"
|
||||
SELECT * FROM "assets" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
|
||||
SELECT * FROM "assets" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_
|
||||
SELECT * FROM "assets" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle
|
||||
SELECT * FROM "asset" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
|
||||
SELECT * FROM "asset" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_
|
||||
SELECT * FROM "asset" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle
|
||||
```
|
||||
|
||||
```sql title="Find by path"
|
||||
SELECT * FROM "assets" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg';
|
||||
SELECT * FROM "assets" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
|
||||
SELECT * FROM "asset" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg';
|
||||
SELECT * FROM "asset" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
|
||||
```
|
||||
|
||||
### ID
|
||||
|
||||
```sql title="Find by ID"
|
||||
SELECT * FROM "assets" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
|
||||
SELECT * FROM "asset" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
|
||||
```
|
||||
|
||||
```sql title="Find by partial ID"
|
||||
SELECT * FROM "assets" WHERE "id"::text LIKE '%ab431d3a%';
|
||||
SELECT * FROM "asset" WHERE "id"::text LIKE '%ab431d3a%';
|
||||
```
|
||||
|
||||
### Checksum
|
||||
|
||||
:::note
|
||||
You can calculate the checksum for a particular file by using the command `sha1sum <filename>`.
|
||||
:::
|
||||
|
||||
```sql title="Find by checksum (SHA-1)"
|
||||
SELECT encode("checksum", 'hex') FROM "assets";
|
||||
SELECT * FROM "assets" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
|
||||
SELECT * FROM "assets" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
|
||||
SELECT encode("checksum", 'hex') FROM "asset";
|
||||
SELECT * FROM "asset" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
|
||||
SELECT * FROM "asset" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
|
||||
```
|
||||
|
||||
```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)"
|
||||
SELECT T1."checksum", array_agg(T2."id") ids FROM "assets" T1
|
||||
INNER JOIN "assets" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL
|
||||
SELECT T1."checksum", array_agg(T2."id") ids FROM "asset" T1
|
||||
INNER JOIN "asset" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL
|
||||
WHERE T1."deletedAt" IS NULL GROUP BY T1."checksum";
|
||||
```
|
||||
|
||||
### Metadata
|
||||
|
||||
```sql title="Live photos"
|
||||
SELECT * FROM "assets" WHERE "livePhotoVideoId" IS NOT NULL;
|
||||
SELECT * FROM "asset" WHERE "livePhotoVideoId" IS NOT NULL;
|
||||
```
|
||||
|
||||
```sql title="By description"
|
||||
SELECT "assets".*, "exif"."description" FROM "exif"
|
||||
JOIN "assets" ON "assets"."id" = "exif"."assetId"
|
||||
WHERE TRIM("exif"."description") <> ''; -- all files with a description
|
||||
SELECT "assets".*, "exif"."description" FROM "exif"
|
||||
JOIN "assets" ON "assets"."id" = "exif"."assetId"
|
||||
WHERE "exif"."description" ILIKE '%string to match%'; -- search by string
|
||||
SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
|
||||
JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
|
||||
WHERE TRIM("asset_exif"."description") <> ''; -- all files with a description
|
||||
SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
|
||||
JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
|
||||
WHERE "asset_exif"."description" ILIKE '%string to match%'; -- search by string
|
||||
```
|
||||
|
||||
```sql title="Without metadata"
|
||||
SELECT "assets".* FROM "exif"
|
||||
LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId"
|
||||
WHERE "exif"."assetId" IS NULL;
|
||||
SELECT "asset".* FROM "asset_exif"
|
||||
LEFT JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
|
||||
WHERE "asset_exif"."assetId" IS NULL;
|
||||
```
|
||||
|
||||
```sql title="size < 100,000 bytes, smallest to largest"
|
||||
SELECT * FROM "assets"
|
||||
JOIN "exif" ON "assets"."id" = "exif"."assetId"
|
||||
WHERE "exif"."fileSizeInByte" < 100000
|
||||
ORDER BY "exif"."fileSizeInByte" ASC;
|
||||
SELECT * FROM "asset"
|
||||
JOIN "asset_exif" ON "asset"."id" = "asset_exif"."assetId"
|
||||
WHERE "asset_exif"."fileSizeInByte" < 100000
|
||||
ORDER BY "asset_exif"."fileSizeInByte" ASC;
|
||||
```
|
||||
|
||||
```sql title="Without thumbnails"
|
||||
SELECT * FROM "assets" WHERE "assets"."previewPath" IS NULL OR "assets"."thumbnailPath" IS NULL;
|
||||
```
|
||||
### Type
|
||||
|
||||
```sql title="By type"
|
||||
SELECT * FROM "assets" WHERE "assets"."type" = 'VIDEO';
|
||||
SELECT * FROM "assets" WHERE "assets"."type" = 'IMAGE';
|
||||
SELECT * FROM "asset" WHERE "asset"."type" = 'VIDEO';
|
||||
SELECT * FROM "asset" WHERE "asset"."type" = 'IMAGE';
|
||||
```
|
||||
|
||||
```sql title="Count by type"
|
||||
SELECT "assets"."type", COUNT(*) FROM "assets" GROUP BY "assets"."type";
|
||||
SELECT "asset"."type", COUNT(*) FROM "asset" GROUP BY "asset"."type";
|
||||
```
|
||||
|
||||
```sql title="Count by type (per user)"
|
||||
SELECT "users"."email", "assets"."type", COUNT(*) FROM "assets"
|
||||
JOIN "users" ON "assets"."ownerId" = "users"."id"
|
||||
GROUP BY "assets"."type", "users"."email" ORDER BY "users"."email";
|
||||
SELECT "user"."email", "asset"."type", COUNT(*) FROM "asset"
|
||||
JOIN "user" ON "asset"."ownerId" = "user"."id"
|
||||
GROUP BY "asset"."type", "user"."email" ORDER BY "user"."email";
|
||||
```
|
||||
|
||||
```sql title="Failed file movements"
|
||||
SELECT * FROM "move_history";
|
||||
## Tags
|
||||
|
||||
```sql title="Count by tag"
|
||||
SELECT "t"."value" AS "tag_name", COUNT(*) AS "number_assets" FROM "tag" "t"
|
||||
JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id"
|
||||
WHERE "a"."visibility" != 'hidden'
|
||||
GROUP BY "t"."value" ORDER BY "number_assets" DESC;
|
||||
```
|
||||
|
||||
```sql title="Count by tag (per user)"
|
||||
SELECT "t"."value" AS "tag_name", "u"."email" as "user_email", COUNT(*) AS "number_assets" FROM "tag" "t"
|
||||
JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id" JOIN "user" "u" ON "a"."ownerId" = "u"."id"
|
||||
WHERE "a"."visibility" != 'hidden'
|
||||
GROUP BY "t"."value", "u"."email" ORDER BY "number_assets" DESC;
|
||||
```
|
||||
|
||||
## Users
|
||||
|
||||
```sql title="List all users"
|
||||
SELECT * FROM "users";
|
||||
SELECT * FROM "user";
|
||||
```
|
||||
|
||||
```sql title="Get owner info from asset ID"
|
||||
SELECT "users".* FROM "users" JOIN "assets" ON "users"."id" = "assets"."ownerId" WHERE "assets"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f';
|
||||
SELECT "user".* FROM "user" JOIN "asset" ON "user"."id" = "asset"."ownerId" WHERE "asset"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f';
|
||||
```
|
||||
|
||||
## System Config
|
||||
|
||||
```sql title="Custom settings"
|
||||
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
|
||||
```
|
||||
|
||||
(Only used when not using the [config file](/docs/install/config-file))
|
||||
|
||||
## Persons
|
||||
|
||||
```sql title="Delete person and unset it for the faces it was associated with"
|
||||
DELETE FROM "person" WHERE "name" = 'PersonNameHere';
|
||||
```
|
||||
|
||||
## System
|
||||
|
||||
### Config
|
||||
|
||||
```sql title="Custom settings"
|
||||
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
|
||||
```
|
||||
|
||||
(Only used when not using the [config file](/docs/install/config-file))
|
||||
|
||||
### File properties
|
||||
|
||||
```sql title="Without thumbnails"
|
||||
SELECT * FROM "asset" WHERE "asset"."previewPath" IS NULL OR "asset"."thumbnailPath" IS NULL;
|
||||
```
|
||||
|
||||
```sql title="Failed file movements"
|
||||
SELECT * FROM "move_history";
|
||||
```
|
||||
|
||||
## Postgres internal
|
||||
|
||||
```sql title="Change DB_PASSWORD"
|
||||
|
||||
@@ -12,7 +12,7 @@ If you want Immich to be able to delete the images in the external library or ad
|
||||
```diff
|
||||
immich-server:
|
||||
volumes:
|
||||
- ${UPLOAD_LOCATION}:/usr/src/app/upload
|
||||
- ${UPLOAD_LOCATION}:/data
|
||||
+ - /home/user/photos1:/home/user/photos1:ro
|
||||
+ - /mnt/photos2:/mnt/photos2:ro # you can delete this line if you only have one mount point, or you can add more lines if you have more than two
|
||||
```
|
||||
|
||||
@@ -29,29 +29,26 @@ These environment variables are used by the `docker-compose.yml` file and do **N
|
||||
|
||||
## General
|
||||
|
||||
| Variable | Description | Default | Containers | Workers |
|
||||
| :---------------------------------- | :---------------------------------------------------------------------------------------- | :---------------------------------: | :----------------------- | :----------------- |
|
||||
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
|
||||
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
|
||||
| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
|
||||
| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `/usr/src/app/upload`<sup>\*3</sup> | server | api, microservices |
|
||||
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
|
||||
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
|
||||
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
|
||||
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
|
||||
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
|
||||
| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices |
|
||||
| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api |
|
||||
| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices |
|
||||
| Variable | Description | Default | Containers | Workers |
|
||||
| :---------------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------: | :----------------------- | :----------------- |
|
||||
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
|
||||
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
|
||||
| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
|
||||
| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `/data` | server | api, microservices |
|
||||
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
|
||||
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
|
||||
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
|
||||
| `IMMICH_API_METRICS_PORT` | Port for the OTEL metrics | `8081` | server | api |
|
||||
| `IMMICH_MICROSERVICES_METRICS_PORT` | Port for the OTEL metrics | `8082` | server | microservices |
|
||||
| `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices |
|
||||
| `IMMICH_TRUSTED_PROXIES` | List of comma-separated IPs set as trusted proxies | | server | api |
|
||||
| `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices |
|
||||
|
||||
\*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`.
|
||||
`TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution.
|
||||
|
||||
\*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead.
|
||||
|
||||
\*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
|
||||
It only needs to be set if the Immich deployment method is changing.
|
||||
|
||||
## Workers
|
||||
|
||||
| Variable | Description | Default | Containers |
|
||||
@@ -202,12 +199,11 @@ Additional machine learning parameters can be tuned from the admin UI.
|
||||
| `IMMICH_TELEMETRY_INCLUDE` | Collect these telemetries. List of `host`, `api`, `io`, `repo`, `job`. Note: You can also specify `all` to enable all | | server | api, microservices |
|
||||
| `IMMICH_TELEMETRY_EXCLUDE` | Do not collect these telemetries. List of `host`, `api`, `io`, `repo`, `job` | | server | api, microservices |
|
||||
|
||||
## Docker Secrets
|
||||
## Secrets
|
||||
|
||||
The following variables support the use of [Docker secrets][docker-secrets] for additional security.
|
||||
The following variables support reading from files, either via [Systemd Credentials][systemd-creds] or [Docker secrets][docker-secrets] for additional security.
|
||||
|
||||
To use any of these, replace the regular environment variable with the equivalent `_FILE` environment variable. The value of
|
||||
the `_FILE` variable should be set to the path of a file containing the variable value.
|
||||
To use any of these, either set `CREDENTIALS_DIRECTORY` to a directory that contains files whose name is the “regular variable” name, and whose content is the secret. If using Docker Secrets, setting `CREDENTIALS_DIRECTORY=/run/secrets` will cause all secrets present to be used. Alternatively, replace the regular variable with the equivalent `_FILE` environment variable as below. The value of the `_FILE` variable should be set to the path of a file containing the variable value.
|
||||
|
||||
| Regular Variable | Equivalent Docker Secrets '\_FILE' Variable |
|
||||
| :----------------- | :------------------------------------------ |
|
||||
@@ -229,3 +225,4 @@ to use a Docker secret for the password in the Redis container.
|
||||
[docker-secrets-docs]: https://github.com/docker-library/docs/tree/master/postgres#docker-secrets
|
||||
[docker-secrets]: https://docs.docker.com/engine/swarm/secrets/
|
||||
[ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis
|
||||
[systemd-creds]: https://systemd.io/CREDENTIALS/
|
||||
|
||||
@@ -100,6 +100,11 @@ const projects: CommunityProjectProps[] = [
|
||||
description: 'Automatically optimize files uploaded to Immich in order to save storage space',
|
||||
url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer',
|
||||
},
|
||||
{
|
||||
title: 'Immich Machine Learning Load Balancer',
|
||||
description: 'Speed up your machine learning by load balancing your requests to multiple computers',
|
||||
url: 'https://github.com/apetersson/immich_ml_balancer',
|
||||
},
|
||||
];
|
||||
|
||||
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {
|
||||
|
||||
@@ -2,4 +2,23 @@
|
||||
|
||||
## TypeORM Upgrade
|
||||
|
||||
The upgrade to Immich `v2.x.x` has a required upgrade path to `v1.132.0+`. This means it is required to start up the application at least once on version `1.132.0` (or later). Doing so will complete database schema upgrades that are required for `v2.0.0`. After Immich has successfully booted on this version, shut the system down and try the `v2.x.x` upgrade again.
|
||||
In order to update to Immich to `v1.137.0` (or above), the application must be started at least once on a version in the range between `1.132.0` and `1.136.0`. Doing so will complete database schema upgrades that are required for `v1.137.0` (and above). After Immich has successfully updated to a version in this range, you can now attempt to update to v1.137.0 (or above). We recommend users upgrade to `1.132.0` since it does not have any other breaking changes.
|
||||
|
||||
## Inconsistent Media Location
|
||||
|
||||
:::caution
|
||||
This error is related to the location of media files _inside the container_. Never move files on the host system when you run into this error message.
|
||||
:::
|
||||
|
||||
Immich automatically tries to detect where your Immich data is located. On start up, it compares the detected media location with the file paths in the database and throws an Inconsistent Media Location error when they do not match.
|
||||
|
||||
To fix this issue, verify that the `IMMICH_MEDIA_LOCATION` environment variable and `UPLOAD_LOCATION` volume mount are in sync with the database paths.
|
||||
|
||||
If you would like to migrate from one media location to another, simply successfully start Immich on `v1.136.0` or later, then do the following steps:
|
||||
|
||||
1. Stop Immich
|
||||
2. Update `IMMICH_MEDIA_LOCATION` to the new location
|
||||
3. Update the right-hand side of the `UPLOAD_LOCATION` volume mount to the new location
|
||||
4. Start up Immich
|
||||
|
||||
After version `1.136.0`, Immich can detect when a media location has moved and will automatically update the database paths to keep them in sync.
|
||||
|
||||
4
docs/static/archived-versions.json
vendored
4
docs/static/archived-versions.json
vendored
@@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"label": "v1.136.0",
|
||||
"url": "https://v1.136.0.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v1.135.3",
|
||||
"url": "https://v1.135.3.archive.immich.app"
|
||||
|
||||
@@ -38,7 +38,7 @@ services:
|
||||
image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb
|
||||
|
||||
database:
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:3aef84a0a4fabbda17ef115c3019ba0c914ec73e9f6e59203674322d858b8eea
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:0e763a2383d56f90364fcd72767ac41400cd30d2627f407f7e7960c9f1923c21
|
||||
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
|
||||
environment:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
|
||||
189
e2e/package-lock.json
generated
189
e2e/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.135.3",
|
||||
"version": "1.136.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "immich-e2e",
|
||||
"version": "1.135.3",
|
||||
"version": "1.136.0",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
@@ -16,14 +16,14 @@
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@socket.io/component-emitter": "^3.1.2",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"@types/oidc-provider": "^9.0.0",
|
||||
"@types/pg": "^8.15.1",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"exiftool-vendored": "^28.3.1",
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"../cli": {
|
||||
"name": "@immich/cli",
|
||||
"version": "2.2.72",
|
||||
"version": "2.2.73",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
@@ -68,13 +68,13 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"byte-size": "^9.0.0",
|
||||
"cli-progress": "^3.12.0",
|
||||
"commander": "^12.0.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"globals": "^16.0.0",
|
||||
@@ -95,14 +95,14 @@
|
||||
},
|
||||
"../open-api/typescript-sdk": {
|
||||
"name": "@immich/sdk",
|
||||
"version": "1.135.3",
|
||||
"version": "1.136.0",
|
||||
"dev": true,
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"dependencies": {
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -2125,17 +2125,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.37.0.tgz",
|
||||
"integrity": "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz",
|
||||
"integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.37.0",
|
||||
"@typescript-eslint/type-utils": "8.37.0",
|
||||
"@typescript-eslint/utils": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0",
|
||||
"@typescript-eslint/scope-manager": "8.38.0",
|
||||
"@typescript-eslint/type-utils": "8.38.0",
|
||||
"@typescript-eslint/utils": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
@@ -2149,7 +2149,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.37.0",
|
||||
"@typescript-eslint/parser": "^8.38.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
@@ -2165,16 +2165,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.37.0.tgz",
|
||||
"integrity": "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz",
|
||||
"integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.37.0",
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0",
|
||||
"@typescript-eslint/scope-manager": "8.38.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2190,14 +2190,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.37.0.tgz",
|
||||
"integrity": "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
|
||||
"integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.37.0",
|
||||
"@typescript-eslint/types": "^8.37.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.38.0",
|
||||
"@typescript-eslint/types": "^8.38.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2212,14 +2212,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.37.0.tgz",
|
||||
"integrity": "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz",
|
||||
"integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0"
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2230,9 +2230,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.37.0.tgz",
|
||||
"integrity": "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
|
||||
"integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2247,15 +2247,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.37.0.tgz",
|
||||
"integrity": "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz",
|
||||
"integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0",
|
||||
"@typescript-eslint/utils": "8.37.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0",
|
||||
"@typescript-eslint/utils": "8.38.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
@@ -2272,9 +2272,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.37.0.tgz",
|
||||
"integrity": "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz",
|
||||
"integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2286,16 +2286,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.37.0.tgz",
|
||||
"integrity": "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
|
||||
"integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.37.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.37.0",
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/visitor-keys": "8.37.0",
|
||||
"@typescript-eslint/project-service": "8.38.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.38.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/visitor-keys": "8.38.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@@ -2341,16 +2341,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.37.0.tgz",
|
||||
"integrity": "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz",
|
||||
"integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.37.0",
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0"
|
||||
"@typescript-eslint/scope-manager": "8.38.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2365,13 +2365,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.37.0.tgz",
|
||||
"integrity": "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz",
|
||||
"integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.37.0",
|
||||
"@typescript-eslint/types": "8.38.0",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3525,9 +3525,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "10.1.5",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz",
|
||||
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
|
||||
"version": "10.1.8",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
|
||||
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -3541,9 +3541,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.1.tgz",
|
||||
"integrity": "sha512-dobTkHT6XaEVOo8IO90Q4DOSxnm3Y151QxPJlM/vKC0bVy+d6cVWQZLlFiuZPP0wS6vZwSKeJgKkcS+KfMBlRw==",
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz",
|
||||
"integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3983,15 +3983,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
@@ -5708,15 +5709,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier-plugin-organize-imports": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz",
|
||||
"integrity": "sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.2.0.tgz",
|
||||
"integrity": "sha512-Zdy27UhlmyvATZi67BTnLcKTo8fm6Oik59Sz6H64PgZJVs6NJpPD1mT240mmJn62c98/QaL+r3kx9Q3gRpDajg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"prettier": ">=2.0",
|
||||
"typescript": ">=2.9",
|
||||
"vue-tsc": "^2.1.0"
|
||||
"vue-tsc": "^2.1.0 || 3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"vue-tsc": {
|
||||
@@ -6469,35 +6470,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/superagent": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.2.tgz",
|
||||
"integrity": "sha512-vWMq11OwWCC84pQaFPzF/VO3BrjkCeewuvJgt1jfV0499Z1QSAWN4EqfMM5WlFDDX9/oP8JjlDKpblrmEoyu4Q==",
|
||||
"version": "10.2.3",
|
||||
"resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz",
|
||||
"integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"component-emitter": "^1.3.0",
|
||||
"component-emitter": "^1.3.1",
|
||||
"cookiejar": "^2.1.4",
|
||||
"debug": "^4.3.4",
|
||||
"debug": "^4.3.7",
|
||||
"fast-safe-stringify": "^2.1.1",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "^4.0.4",
|
||||
"formidable": "^3.5.4",
|
||||
"methods": "^1.1.2",
|
||||
"mime": "2.6.0",
|
||||
"qs": "^6.11.0"
|
||||
"qs": "^6.11.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/supertest": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.3.tgz",
|
||||
"integrity": "sha512-ORY0gPa6ojmg/C74P/bDoS21WL6FMXq5I8mawkEz30/zkwdu0gOeqstFy316vHG6OKxqQ+IbGneRemHI8WraEw==",
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz",
|
||||
"integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"methods": "^1.1.2",
|
||||
"superagent": "^10.2.2"
|
||||
"superagent": "^10.2.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.0"
|
||||
@@ -6817,16 +6818,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.37.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.37.0.tgz",
|
||||
"integrity": "sha512-TnbEjzkE9EmcO0Q2zM+GE8NQLItNAJpMmED1BdgoBMYNdqMhzlbqfdSwiRlAzEK2pA9UzVW0gzaaIzXWg2BjfA==",
|
||||
"version": "8.38.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz",
|
||||
"integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.37.0",
|
||||
"@typescript-eslint/parser": "8.37.0",
|
||||
"@typescript-eslint/typescript-estree": "8.37.0",
|
||||
"@typescript-eslint/utils": "8.37.0"
|
||||
"@typescript-eslint/eslint-plugin": "8.38.0",
|
||||
"@typescript-eslint/parser": "8.38.0",
|
||||
"@typescript-eslint/typescript-estree": "8.38.0",
|
||||
"@typescript-eslint/utils": "8.38.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "1.135.3",
|
||||
"version": "1.136.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -26,14 +26,14 @@
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@socket.io/component-emitter": "^3.1.2",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.16.4",
|
||||
"@types/node": "^22.16.5",
|
||||
"@types/oidc-provider": "^9.0.0",
|
||||
"@types/pg": "^8.15.1",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^59.0.0",
|
||||
"exiftool-vendored": "^28.3.1",
|
||||
|
||||
@@ -470,7 +470,7 @@ describe('/albums', () => {
|
||||
.send({ ids: [asset.id] });
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest('Not found or no album.addAsset access'));
|
||||
expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.create access'));
|
||||
});
|
||||
|
||||
it('should add duplicate assets only once', async () => {
|
||||
@@ -599,7 +599,7 @@ describe('/albums', () => {
|
||||
.send({ ids: [user1Asset1.id] });
|
||||
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(errorDto.badRequest('Not found or no album.removeAsset access'));
|
||||
expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.delete access'));
|
||||
});
|
||||
|
||||
it('should remove duplicate assets only once', async () => {
|
||||
|
||||
@@ -186,18 +186,6 @@ export const utils = {
|
||||
}
|
||||
},
|
||||
|
||||
resetFilesystem: async () => {
|
||||
const mediaInternal = '/usr/src/app/upload';
|
||||
const dirs = [
|
||||
`"${mediaInternal}/thumbs"`,
|
||||
`"${mediaInternal}/upload"`,
|
||||
`"${mediaInternal}/library"`,
|
||||
`"${mediaInternal}/encoded-video"`,
|
||||
].join(' ');
|
||||
|
||||
await execPromise(`docker exec -i "immich-e2e-server" /bin/bash -c "rm -rf ${dirs} && mkdir ${dirs}"`);
|
||||
},
|
||||
|
||||
unzip: async (input: string, output: string) => {
|
||||
await execPromise(`unzip -o -d "${output}" "${input}"`);
|
||||
},
|
||||
|
||||
@@ -37,6 +37,7 @@ test.describe('Registration', () => {
|
||||
await page.getByRole('button', { name: 'Server Privacy' }).click();
|
||||
await page.getByRole('button', { name: 'User Privacy' }).click();
|
||||
await page.getByRole('button', { name: 'Storage Template' }).click();
|
||||
await page.getByRole('button', { name: 'Backups' }).click();
|
||||
await page.getByRole('button', { name: 'Done' }).click();
|
||||
|
||||
// success
|
||||
|
||||
Submodule e2e/test-assets updated: 18736fc27a...37f60ea537
23
i18n/cs.json
23
i18n/cs.json
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Nastavení záloh",
|
||||
"backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí",
|
||||
"backward": "Pozpátku",
|
||||
"beta_sync": "Stav synchronizace beta verze",
|
||||
"beta_sync_subtitle": "Správa nového systému synchronizace",
|
||||
"biometric_auth_enabled": "Biometrické ověřování je povoleno",
|
||||
"biometric_locked_out": "Jste vyloučeni z biometrického ověřování",
|
||||
"biometric_no_options": "Biometrické možnosti nejsou k dispozici",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
|
||||
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.",
|
||||
"cache_settings_duplicated_assets_clear_button": "VYMAZAT",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace zařadila na černou listinu",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace ignoruje",
|
||||
"cache_settings_duplicated_assets_title": "Duplicitní položky ({count})",
|
||||
"cache_settings_statistics_album": "Knihovna náhledů",
|
||||
"cache_settings_statistics_full": "Kompletní fotografie",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
|
||||
"haptic_feedback_title": "Dotyková zpětná vazba",
|
||||
"has_quota": "Má kvótu",
|
||||
"hash_asset": "Hash položky",
|
||||
"hashed_assets": "Hashované položky",
|
||||
"hashing": "Hashování",
|
||||
"header_settings_add_header_tip": "Přidat hlavičku",
|
||||
"header_settings_field_validator_msg": "Hodnota nemůže být prázdná",
|
||||
"header_settings_header_name_input": "Název hlavičky",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Hostitel",
|
||||
"hour": "Hodina",
|
||||
"id": "ID",
|
||||
"idle": "Nečinnost",
|
||||
"ignore_icloud_photos": "Ignorovat fotografie na iCloudu",
|
||||
"ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server",
|
||||
"image": "Obrázek",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Seznam",
|
||||
"loading": "Načítání",
|
||||
"loading_search_results_failed": "Načítání výsledků vyhledávání se nezdařilo",
|
||||
"local": "Místní",
|
||||
"local_asset_cast_failed": "Nelze odeslat položku, která není nahraná na serveru",
|
||||
"local_assets": "Místní položky",
|
||||
"local_network": "Místní síť",
|
||||
"local_network_sheet_info": "Aplikace se při použití zadané sítě Wi-Fi připojí k serveru prostřednictvím tohoto URL",
|
||||
"location_permission": "Oprávnění polohy",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Žádné výsledky",
|
||||
"no_results_description": "Zkuste použít synonymum nebo obecnější klíčové slovo",
|
||||
"no_shared_albums_message": "Vytvořte si album a sdílejte fotografie a videa s lidmi ve své síti",
|
||||
"no_uploads_in_progress": "Neprobíhá žádné nahrávání",
|
||||
"not_in_any_album": "Bez alba",
|
||||
"not_selected": "Není vybráno",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Upozornění: Chcete-li použít štítek úložiště na dříve nahrané položky, spusťte příkaz",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "originál",
|
||||
"other": "Ostatní",
|
||||
"other_devices": "Ostatní zařízení",
|
||||
"other_entities": "Ostatní entity",
|
||||
"other_variables": "Další proměnné",
|
||||
"owned": "Vlastní",
|
||||
"owner": "Vlastník",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Obnovování obličejů",
|
||||
"refreshing_metadata": "Obnovování metadat",
|
||||
"regenerating_thumbnails": "Regenerace miniatur",
|
||||
"remote": "Vzdálený",
|
||||
"remote_assets": "Vzdálené položky",
|
||||
"remove": "Odstranit",
|
||||
"remove_assets_album_confirmation": "Opravdu chcete z alba odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
|
||||
"remove_assets_shared_link_confirmation": "Opravdu chcete ze sdíleného odkazu odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "Obnovit heslo",
|
||||
"reset_people_visibility": "Obnovit viditelnost lidí",
|
||||
"reset_pin_code": "Resetovat PIN kód",
|
||||
"reset_sqlite": "Obnovit SQLite databázi",
|
||||
"reset_sqlite_confirmation": "Jste si jisti, že chcete obnovit SQLite databázi? Pro opětovnou synchronizaci dat se budete muset odhlásit a znovu přihlásit",
|
||||
"reset_sqlite_success": "Obnovení SQLite databáze proběhlo úspěšně",
|
||||
"reset_to_default": "Obnovit výchozí nastavení",
|
||||
"resolve_duplicates": "Vyřešit duplicity",
|
||||
"resolved_all_duplicates": "Vyřešeny všechny duplicity",
|
||||
"restore": "Obnovit",
|
||||
"restore_all": "Obnovit vše",
|
||||
"restore_trash_action_prompt": "{count} obnoveno z koše",
|
||||
"restore_user": "Obnovit uživatele",
|
||||
"restored_asset": "Položka obnovena",
|
||||
"resume": "Pokračovat",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "Role",
|
||||
"role_editor": "Editor",
|
||||
"role_viewer": "Divák",
|
||||
"running": "Probíhá",
|
||||
"save": "Uložit",
|
||||
"save_to_gallery": "Uložit do galerie",
|
||||
"saved_api_key": "API klíč uložen",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Kvóta úložiště",
|
||||
"storage_usage": "Využito {used} z {available}",
|
||||
"submit": "Odeslat",
|
||||
"success": "Úspěch",
|
||||
"suggestions": "Návrhy",
|
||||
"sunrise_on_the_beach": "Východ slunce na pláži",
|
||||
"support": "Podpora",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "Synchronizovat",
|
||||
"sync_albums": "Synchronizovat alba",
|
||||
"sync_albums_manual_subtitle": "Synchronizovat všechna nahraná videa a fotografie do vybraných záložních alb",
|
||||
"sync_local": "Synchronizovat místní",
|
||||
"sync_remote": "Synchronizovat vzdálené",
|
||||
"sync_upload_album_setting_subtitle": "Vytvořit a nahrát fotografie a videa do vybraných alb na Immich",
|
||||
"tag": "Značka",
|
||||
"tag_assets": "Přiřadit značku",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Aktualizována značka: {tag}",
|
||||
"tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}",
|
||||
"tags": "Značky",
|
||||
"tap_to_run_job": "Klepnutím na spustíte úlohu",
|
||||
"template": "Šablona",
|
||||
"theme": "Motiv",
|
||||
"theme_selection": "Výběr motivu",
|
||||
|
||||
21
i18n/de.json
21
i18n/de.json
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Sicherungsoptionen",
|
||||
"backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund",
|
||||
"backward": "Rückwärts",
|
||||
"beta_sync": "Status des Beta Sync",
|
||||
"beta_sync_subtitle": "Verwalte das neue Synchronisierungssystem",
|
||||
"biometric_auth_enabled": "Biometrische Authentifizierung aktiviert",
|
||||
"biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen",
|
||||
"biometric_no_options": "Keine biometrischen Optionen verfügbar",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Haptisches Feedback aktivieren",
|
||||
"haptic_feedback_title": "Haptisches Feedback",
|
||||
"has_quota": "Kontingent",
|
||||
"hash_asset": "Dateihash",
|
||||
"hashed_assets": "Gehashte Dateien",
|
||||
"hashing": "Hashen",
|
||||
"header_settings_add_header_tip": "Header hinzufügen",
|
||||
"header_settings_field_validator_msg": "Der Wert darf nicht leer sein",
|
||||
"header_settings_header_name_input": "Header-Name",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Host",
|
||||
"hour": "Stunde",
|
||||
"id": "ID",
|
||||
"idle": "Untätig",
|
||||
"ignore_icloud_photos": "iCloud Fotos ignorieren",
|
||||
"ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen",
|
||||
"image": "Bild",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Liste",
|
||||
"loading": "Laden",
|
||||
"loading_search_results_failed": "Laden von Suchergebnissen fehlgeschlagen",
|
||||
"local": "Lokal",
|
||||
"local_asset_cast_failed": "Eine Datei, die nicht auf den Server hochgeladen wurde, kann nicht gecastet werden",
|
||||
"local_assets": "Lokale Dateien",
|
||||
"local_network": "Lokales Netzwerk",
|
||||
"local_network_sheet_info": "Die App stellt über diese URL eine Verbindung zum Server her, wenn sie das angegebene WLAN-Netzwerk verwendet",
|
||||
"location_permission": "Standort Genehmigung",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Keine Ergebnisse",
|
||||
"no_results_description": "Versuche es mit einem Synonym oder einem allgemeineren Stichwort",
|
||||
"no_shared_albums_message": "Erstelle ein Album, um Fotos und Videos mit Personen in deinem Netzwerk zu teilen",
|
||||
"no_uploads_in_progress": "Kein Upload in Bearbeitung",
|
||||
"not_in_any_album": "In keinem Album",
|
||||
"not_selected": "Nicht ausgewählt",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "Original",
|
||||
"other": "Sonstiges",
|
||||
"other_devices": "Andere Geräte",
|
||||
"other_entities": "Andere Entitäten",
|
||||
"other_variables": "Sonstige Variablen",
|
||||
"owned": "Eigenes",
|
||||
"owner": "Besitzer",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Gesichter werden aktualisiert",
|
||||
"refreshing_metadata": "Metadaten werden aktualisiert",
|
||||
"regenerating_thumbnails": "Miniaturansichten werden neu erstellt",
|
||||
"remote": "Entfernt",
|
||||
"remote_assets": "Entfernte Dateien",
|
||||
"remove": "Entfernen",
|
||||
"remove_assets_album_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} aus dem Album entfernen willst?",
|
||||
"remove_assets_shared_link_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} von diesem geteilten Link entfernen willst?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "Passwort zurücksetzen",
|
||||
"reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen",
|
||||
"reset_pin_code": "PIN Code zurücksetzen",
|
||||
"reset_sqlite": "SQLite Datenbank zurücksetzen",
|
||||
"reset_sqlite_confirmation": "Bist du sicher, dass du die SQLite-Datenbank zurücksetzen willst? Du musst dich ab- und wieder anmelden, um die Daten neu zu synchronisieren",
|
||||
"reset_sqlite_success": "SQLite Datenbank erfolgreich zurückgesetzt",
|
||||
"reset_to_default": "Auf Standard zurücksetzen",
|
||||
"resolve_duplicates": "Duplikate entfernen",
|
||||
"resolved_all_duplicates": "Alle Duplikate aufgelöst",
|
||||
"restore": "Wiederherstellen",
|
||||
"restore_all": "Alle wiederherstellen",
|
||||
"restore_trash_action_prompt": "{count} aus dem Papierkorb wiederhergestellt",
|
||||
"restore_user": "Nutzer wiederherstellen",
|
||||
"restored_asset": "Datei wiederhergestellt",
|
||||
"resume": "Fortsetzen",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "Rolle",
|
||||
"role_editor": "Bearbeiter",
|
||||
"role_viewer": "Betrachter",
|
||||
"running": "Läuft",
|
||||
"save": "Speichern",
|
||||
"save_to_gallery": "In Galerie speichern",
|
||||
"saved_api_key": "API-Schlüssel wurde gespeichert",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Speicherplatz-Kontingent",
|
||||
"storage_usage": "{used} von {available} verwendet",
|
||||
"submit": "Bestätigen",
|
||||
"success": "Erfolgreich",
|
||||
"suggestions": "Vorschläge",
|
||||
"sunrise_on_the_beach": "Sonnenaufgang am Strand",
|
||||
"support": "Unterstützung",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "Synchronisieren",
|
||||
"sync_albums": "Alben synchronisieren",
|
||||
"sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben",
|
||||
"sync_local": "Lokal synchronisieren",
|
||||
"sync_remote": "Entfernt synchronisieren",
|
||||
"sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch",
|
||||
"tag": "Tag",
|
||||
"tag_assets": "Dateien taggen",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Tag aktualisiert: {tag}",
|
||||
"tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged",
|
||||
"tags": "Tags",
|
||||
"tap_to_run_job": "Tippen um den Job zu starten",
|
||||
"template": "Vorlage",
|
||||
"theme": "Theme",
|
||||
"theme_selection": "Themenauswahl",
|
||||
|
||||
31
i18n/en.json
31
i18n/en.json
@@ -14,6 +14,7 @@
|
||||
"add_a_location": "Add a location",
|
||||
"add_a_name": "Add a name",
|
||||
"add_a_title": "Add a title",
|
||||
"add_birthday": "Add a birthday",
|
||||
"add_endpoint": "Add endpoint",
|
||||
"add_exclusion_pattern": "Add exclusion pattern",
|
||||
"add_import_path": "Add import path",
|
||||
@@ -44,6 +45,13 @@
|
||||
"backup_database": "Create Database Dump",
|
||||
"backup_database_enable_description": "Enable database dumps",
|
||||
"backup_keep_last_amount": "Amount of previous dumps to keep",
|
||||
"backup_onboarding_1_description": "offsite copy in the cloud or at another physical location.",
|
||||
"backup_onboarding_2_description": "local copies on different devices. This includes the main files and a backup of those files locally.",
|
||||
"backup_onboarding_3_description": "total copies of your data, including the original files. This includes 1 offsite copy and 2 local copies.",
|
||||
"backup_onboarding_description": "A <backblaze-link>3-2-1 backup strategy</backblaze-link> is recommended to protect your data. You should keep copies of your uploaded photos/videos as well as the Immich database for a comprehensive backup solution.",
|
||||
"backup_onboarding_footer": "For more information about backing up Immich, please refer to the <link>documentation</link>.",
|
||||
"backup_onboarding_parts_title": "A 3-2-1 backup includes:",
|
||||
"backup_onboarding_title": "Backups",
|
||||
"backup_settings": "Database Dump Settings",
|
||||
"backup_settings_description": "Manage database dump settings.",
|
||||
"cleared_jobs": "Cleared jobs for: {job}",
|
||||
@@ -397,6 +405,7 @@
|
||||
"album_cover_updated": "Album cover updated",
|
||||
"album_delete_confirmation": "Are you sure you want to delete the album {album}?",
|
||||
"album_delete_confirmation_description": "If this album is shared, other users will not be able to access it anymore.",
|
||||
"album_deleted": "Album deleted",
|
||||
"album_info_card_backup_album_excluded": "EXCLUDED",
|
||||
"album_info_card_backup_album_included": "INCLUDED",
|
||||
"album_info_updated": "Album info updated",
|
||||
@@ -510,6 +519,7 @@
|
||||
"back_close_deselect": "Back, close, or deselect",
|
||||
"background_location_permission": "Background location permission",
|
||||
"background_location_permission_content": "In order to switch networks when running in the background, Immich must *always* have precise location access so the app can read the Wi-Fi network's name",
|
||||
"backup": "Backup",
|
||||
"backup_album_selection_page_albums_device": "Albums on device ({count})",
|
||||
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude",
|
||||
"backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
|
||||
@@ -723,6 +733,7 @@
|
||||
"current_server_address": "Current server address",
|
||||
"custom_locale": "Custom Locale",
|
||||
"custom_locale_description": "Format dates and numbers based on the language and the region",
|
||||
"custom_url": "Custom URL",
|
||||
"daily_title_text_date": "E, MMM dd",
|
||||
"daily_title_text_date_year": "E, MMM dd, yyyy",
|
||||
"dark": "Dark",
|
||||
@@ -742,7 +753,8 @@
|
||||
"default_locale": "Default Locale",
|
||||
"default_locale_description": "Format dates and numbers based on your browser locale",
|
||||
"delete": "Delete",
|
||||
"delete_action_prompt": "{count} deleted permanently",
|
||||
"delete_action_confirmation_message": "Are you sure you want to delete this asset? This action will move the asset to the server's trash and will prompt if you want to delete it locally",
|
||||
"delete_action_prompt": "{count} deleted",
|
||||
"delete_album": "Delete album",
|
||||
"delete_api_key_prompt": "Are you sure you want to delete this API key?",
|
||||
"delete_dialog_alert": "These items will be permanently deleted from Immich and from your device",
|
||||
@@ -760,6 +772,8 @@
|
||||
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
|
||||
"delete_local_dialog_ok_force": "Delete Anyway",
|
||||
"delete_others": "Delete others",
|
||||
"delete_permanently": "Delete permanently",
|
||||
"delete_permanently_action_prompt": "{count} deleted permanently",
|
||||
"delete_shared_link": "Delete shared link",
|
||||
"delete_shared_link_dialog_title": "Delete Shared Link",
|
||||
"delete_tag": "Delete tag",
|
||||
@@ -815,6 +829,7 @@
|
||||
"edit": "Edit",
|
||||
"edit_album": "Edit album",
|
||||
"edit_avatar": "Edit avatar",
|
||||
"edit_birthday": "Edit Birthday",
|
||||
"edit_date": "Edit date",
|
||||
"edit_date_and_time": "Edit date and time",
|
||||
"edit_description": "Edit description",
|
||||
@@ -982,6 +997,7 @@
|
||||
},
|
||||
"exif": "Exif",
|
||||
"exif_bottom_sheet_description": "Add Description...",
|
||||
"exif_bottom_sheet_description_error": "Error updating description",
|
||||
"exif_bottom_sheet_details": "DETAILS",
|
||||
"exif_bottom_sheet_location": "LOCATION",
|
||||
"exif_bottom_sheet_people": "PEOPLE",
|
||||
@@ -1002,6 +1018,8 @@
|
||||
"explorer": "Explorer",
|
||||
"export": "Export",
|
||||
"export_as_json": "Export as JSON",
|
||||
"export_database": "Export Database",
|
||||
"export_database_description": "Export the SQLite database",
|
||||
"extension": "Extension",
|
||||
"external": "External",
|
||||
"external_libraries": "External Libraries",
|
||||
@@ -1146,6 +1164,7 @@
|
||||
"language_no_results_title": "No languages found",
|
||||
"language_search_hint": "Search languages...",
|
||||
"language_setting_description": "Select your preferred language",
|
||||
"large_files": "Large Files",
|
||||
"last_seen": "Last seen",
|
||||
"latest_version": "Latest Version",
|
||||
"latitude": "Latitude",
|
||||
@@ -1165,7 +1184,6 @@
|
||||
"light": "Light",
|
||||
"like_deleted": "Like deleted",
|
||||
"link_motion_video": "Link motion video",
|
||||
"link_options": "Link options",
|
||||
"link_to_oauth": "Link to OAuth",
|
||||
"linked_oauth_account": "Linked OAuth account",
|
||||
"list": "List",
|
||||
@@ -1230,8 +1248,7 @@
|
||||
"manage_your_devices": "Manage your logged-in devices",
|
||||
"manage_your_oauth_connection": "Manage your OAuth connection",
|
||||
"map": "Map",
|
||||
"map_assets_in_bound": "{count} photo",
|
||||
"map_assets_in_bounds": "{count} photos",
|
||||
"map_assets_in_bounds": "{count, plural, one {# photo} other {# photos}}",
|
||||
"map_cannot_get_user_location": "Cannot get user's location",
|
||||
"map_location_dialog_yes": "Yes",
|
||||
"map_location_picker_page_use_location": "Use this location",
|
||||
@@ -1582,6 +1599,7 @@
|
||||
"resume": "Resume",
|
||||
"retry_upload": "Retry upload",
|
||||
"review_duplicates": "Review duplicates",
|
||||
"review_large_files": "Review large files",
|
||||
"role": "Role",
|
||||
"role_editor": "Editor",
|
||||
"role_viewer": "Viewer",
|
||||
@@ -1739,6 +1757,7 @@
|
||||
"shared_link_clipboard_copied_massage": "Copied to clipboard",
|
||||
"shared_link_clipboard_text": "Link: {link}\nPassword: {password}",
|
||||
"shared_link_create_error": "Error while creating shared link",
|
||||
"shared_link_custom_url_description": "Access this shared link with a custom URL",
|
||||
"shared_link_edit_description_hint": "Enter the share description",
|
||||
"shared_link_edit_expire_after_option_day": "1 day",
|
||||
"shared_link_edit_expire_after_option_days": "{count} days",
|
||||
@@ -1764,6 +1783,7 @@
|
||||
"shared_link_info_chip_metadata": "EXIF",
|
||||
"shared_link_manage_links": "Manage Shared links",
|
||||
"shared_link_options": "Shared link options",
|
||||
"shared_link_password_description": "Require a password to access this shared link",
|
||||
"shared_links": "Shared links",
|
||||
"shared_links_description": "Share photos and videos with a link",
|
||||
"shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}",
|
||||
@@ -1941,11 +1961,13 @@
|
||||
"updated_at": "Updated",
|
||||
"updated_password": "Updated password",
|
||||
"upload": "Upload",
|
||||
"upload_action_prompt": "{count} queued for upload",
|
||||
"upload_concurrency": "Upload concurrency",
|
||||
"upload_details": "Upload Details",
|
||||
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
|
||||
"upload_dialog_title": "Upload Asset",
|
||||
"upload_errors": "Upload completed with {count, plural, one {# error} other {# errors}}, refresh the page to see new upload assets.",
|
||||
"upload_finished": "Upload finished",
|
||||
"upload_progress": "Remaining {remaining, number} - Processed {processed, number}/{total, number}",
|
||||
"upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}",
|
||||
"upload_status_duplicates": "Duplicates",
|
||||
@@ -1954,6 +1976,7 @@
|
||||
"upload_success": "Upload success, refresh the page to see new upload assets.",
|
||||
"upload_to_immich": "Upload to Immich ({count})",
|
||||
"uploading": "Uploading",
|
||||
"uploading_media": "Uploading media",
|
||||
"url": "URL",
|
||||
"usage": "Usage",
|
||||
"use_biometric": "Use biometric",
|
||||
|
||||
23
i18n/et.json
23
i18n/et.json
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Varundamise valikud",
|
||||
"backup_setting_subtitle": "Halda taustal ja esiplaanil üleslaadimise seadeid",
|
||||
"backward": "Tagasi",
|
||||
"beta_sync": "Beeta sünkroonimise staatus",
|
||||
"beta_sync_subtitle": "Halda uut sünkroonimissüsteemi",
|
||||
"biometric_auth_enabled": "Biomeetriline autentimine lubatud",
|
||||
"biometric_locked_out": "Biomeetriline autentimine on blokeeritud",
|
||||
"biometric_no_options": "Biomeetrilisi valikuid ei ole",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Tühjenda puhver",
|
||||
"cache_settings_clear_cache_button_title": "Tühjendab rakenduse puhvri. See mõjutab oluliselt rakenduse jõudlust, kuni puhver uuesti täidetakse.",
|
||||
"cache_settings_duplicated_assets_clear_button": "TÜHJENDA",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt mustfiltreeritud",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotod ja videod, mis on rakenduse poolt ignoreeritud",
|
||||
"cache_settings_duplicated_assets_title": "Dubleeritud üksused ({count})",
|
||||
"cache_settings_statistics_album": "Kogu pisipildid",
|
||||
"cache_settings_statistics_full": "Täismõõdus pildid",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Luba haptiline tagasiside",
|
||||
"haptic_feedback_title": "Haptiline tagasiside",
|
||||
"has_quota": "On kvoot",
|
||||
"hash_asset": "Arvuta üksuse räsi",
|
||||
"hashed_assets": "Räsiga üksused",
|
||||
"hashing": "Räsi arvutamine",
|
||||
"header_settings_add_header_tip": "Lisa päis",
|
||||
"header_settings_field_validator_msg": "Väärtus ei saa olla tühi",
|
||||
"header_settings_header_name_input": "Päise nimi",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Host",
|
||||
"hour": "Tund",
|
||||
"id": "ID",
|
||||
"idle": "Jõude",
|
||||
"ignore_icloud_photos": "Ignoreeri iCloud fotosid",
|
||||
"ignore_icloud_photos_description": "Fotosid, mis on iCloud'is, ei laadita üles Immich'i serverisse",
|
||||
"image": "Pilt",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Loend",
|
||||
"loading": "Laadimine",
|
||||
"loading_search_results_failed": "Otsitulemuste laadimine ebaõnnestus",
|
||||
"local": "Lokaalne üksus",
|
||||
"local_asset_cast_failed": "Ei saa edastada üksust, mis pole serverisse üles laaditud",
|
||||
"local_assets": "Lokaalsed üksused",
|
||||
"local_network": "Kohalik võrk",
|
||||
"local_network_sheet_info": "Rakendus ühendub valitud Wi-Fi võrgus olles serveriga selle URL-i kaudu",
|
||||
"location_permission": "Asukoha luba",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Vasteid pole",
|
||||
"no_results_description": "Proovi sünonüümi või üldisemat märksõna",
|
||||
"no_shared_albums_message": "Lisa album, et fotosid ja videosid teistega jagada",
|
||||
"no_uploads_in_progress": "Üleslaadimisi käimas ei ole",
|
||||
"not_in_any_album": "Pole üheski albumis",
|
||||
"not_selected": "Ei ole valitud",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Märkus: Et rakendada talletussilt varem üleslaaditud üksustele, käivita",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "originaal",
|
||||
"other": "Muud",
|
||||
"other_devices": "Muud seadmed",
|
||||
"other_entities": "Muud objektid",
|
||||
"other_variables": "Muud muutujad",
|
||||
"owned": "Minu omad",
|
||||
"owner": "Omanik",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Nägude värskendamine",
|
||||
"refreshing_metadata": "Metaandmete värskendamine",
|
||||
"regenerating_thumbnails": "Pisipiltide uuesti genereerimine",
|
||||
"remote": "Kaugüksus",
|
||||
"remote_assets": "Kaugüksused",
|
||||
"remove": "Eemalda",
|
||||
"remove_assets_album_confirmation": "Kas oled kindel, et soovid {count, plural, one {# üksuse} other {# üksust}} albumist eemaldada?",
|
||||
"remove_assets_shared_link_confirmation": "Kas oled kindel, et soovid eemaldada {count, plural, one {# üksuse} other {# üksust}} sellelt jagatud lingilt?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "Lähtesta parool",
|
||||
"reset_people_visibility": "Lähtesta isikute nähtavus",
|
||||
"reset_pin_code": "Lähtesta PIN-kood",
|
||||
"reset_sqlite": "Lähtesta SQLite andmebaas",
|
||||
"reset_sqlite_confirmation": "Kas oled kindel, et soovid SQLite andmebaasi lähtestada? Andmete uuesti sünkroonimiseks pead välja ja jälle sisse logima",
|
||||
"reset_sqlite_success": "SQLite andmebaas edukalt lähtestatud",
|
||||
"reset_to_default": "Lähtesta",
|
||||
"resolve_duplicates": "Lahenda duplikaadid",
|
||||
"resolved_all_duplicates": "Kõik duplikaadid lahendatud",
|
||||
"restore": "Taasta",
|
||||
"restore_all": "Taasta kõik",
|
||||
"restore_trash_action_prompt": "{count} prügikastust taastatud",
|
||||
"restore_user": "Taasta kasutaja",
|
||||
"restored_asset": "Üksus taastatud",
|
||||
"resume": "Jätka",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "Roll",
|
||||
"role_editor": "Muutja",
|
||||
"role_viewer": "Vaataja",
|
||||
"running": "Käimas",
|
||||
"save": "Salvesta",
|
||||
"save_to_gallery": "Salvesta galeriisse",
|
||||
"saved_api_key": "API võti salvestatud",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Talletuskvoot",
|
||||
"storage_usage": "{used}/{available} kasutatud",
|
||||
"submit": "Saada",
|
||||
"success": "Õnnestus",
|
||||
"suggestions": "Soovitused",
|
||||
"sunrise_on_the_beach": "Päikesetõus rannal",
|
||||
"support": "Tugi",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "Sünkrooni",
|
||||
"sync_albums": "Sünkrooni albumid",
|
||||
"sync_albums_manual_subtitle": "Sünkrooni kõik üleslaaditud videod ja fotod valitud varundusalbumitesse",
|
||||
"sync_local": "Sünkrooni lokaalsed üksused",
|
||||
"sync_remote": "Sünkrooni kaugüksused",
|
||||
"sync_upload_album_setting_subtitle": "Loo ja laadi oma pildid ja videod üles Immich'isse valitud albumitesse",
|
||||
"tag": "Silt",
|
||||
"tag_assets": "Sildista üksuseid",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Muudetud silt: {tag}",
|
||||
"tagged_assets": "{count, plural, one {# üksus} other {# üksust}} sildistatud",
|
||||
"tags": "Sildid",
|
||||
"tap_to_run_job": "Puuduta tööte käivitamiseks",
|
||||
"template": "Mall",
|
||||
"theme": "Teema",
|
||||
"theme_selection": "Teema valik",
|
||||
|
||||
28
i18n/fr.json
28
i18n/fr.json
@@ -406,6 +406,7 @@
|
||||
"album_options": "Options de l'album",
|
||||
"album_remove_user": "Supprimer l'utilisateur ?",
|
||||
"album_remove_user_confirmation": "Êtes-vous sûr de vouloir supprimer {user} ?",
|
||||
"album_search_not_found": "Aucun album trouvé ne correspond à votre recherche",
|
||||
"album_share_no_users": "Il semble que vous ayez partagé cet album avec tous les utilisateurs ou que vous n'ayez aucun utilisateur avec lequel le partager.",
|
||||
"album_updated": "Album mis à jour",
|
||||
"album_updated_setting_description": "Recevoir une notification par courriel lorsqu'un album partagé a de nouveaux médias",
|
||||
@@ -425,6 +426,7 @@
|
||||
"albums_default_sort_order": "Ordre de tri par défaut des albums",
|
||||
"albums_default_sort_order_description": "Ordre de tri des médias pour les nouveaux albums créés.",
|
||||
"albums_feature_description": "Bibliothèques de médias pouvant être partagés avec d'autres utilisateurs.",
|
||||
"albums_on_device_count": "Album sur l'appareil ({count})",
|
||||
"all": "Tout",
|
||||
"all_albums": "Tous les albums",
|
||||
"all_people": "Toutes les personnes",
|
||||
@@ -571,6 +573,8 @@
|
||||
"backup_options_page_title": "Options de sauvegarde",
|
||||
"backup_setting_subtitle": "Ajuster les paramètres d'envoi au premier et en arrière-plan",
|
||||
"backward": "Arrière",
|
||||
"beta_sync": "Statut de la synchronisation béta",
|
||||
"beta_sync_subtitle": "Gérer le nouveau système de synchronisation",
|
||||
"biometric_auth_enabled": "Authentification biométrique activée",
|
||||
"biometric_locked_out": "L'authentification biométrique est verrouillé",
|
||||
"biometric_no_options": "Aucune option biométrique disponible",
|
||||
@@ -605,6 +609,7 @@
|
||||
"cancel": "Annuler",
|
||||
"cancel_search": "Annuler la recherche",
|
||||
"canceled": "Annulé",
|
||||
"canceling": "Annulation",
|
||||
"cannot_merge_people": "Impossible de fusionner les personnes",
|
||||
"cannot_undo_this_action": "Vous ne pouvez pas annuler cette action !",
|
||||
"cannot_update_the_description": "Impossible de mettre à jour la description",
|
||||
@@ -765,6 +770,7 @@
|
||||
"description": "Description",
|
||||
"description_input_hint_text": "Ajouter une description...",
|
||||
"description_input_submit_error": "Erreur de mise à jour de la description, vérifier le journal pour plus de détails",
|
||||
"deselect_all": "Tout désélectionner",
|
||||
"details": "Détails",
|
||||
"direction": "Ordre",
|
||||
"disabled": "Désactivé",
|
||||
@@ -839,6 +845,7 @@
|
||||
"empty_trash": "Vider la corbeille",
|
||||
"empty_trash_confirmation": "Êtes-vous sûr de vouloir vider la corbeille ? Cela supprimera définitivement de Immich tous les médias qu'elle contient.\nVous ne pouvez pas annuler cette action !",
|
||||
"enable": "Active",
|
||||
"enable_backup": "Activer Backup",
|
||||
"enable_biometric_auth_description": "Entrez votre code PIN pour activer l'authentification biométrique",
|
||||
"enabled": "Activé",
|
||||
"end_date": "Date de fin",
|
||||
@@ -1046,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Activer le retour haptique",
|
||||
"haptic_feedback_title": "Retour haptique",
|
||||
"has_quota": "Quota",
|
||||
"hash_asset": "Hasher le média",
|
||||
"hashed_assets": "Média hashés",
|
||||
"hashing": "Hash",
|
||||
"header_settings_add_header_tip": "Ajouter un en-tête",
|
||||
"header_settings_field_validator_msg": "Cette valeur ne peut pas être vide",
|
||||
"header_settings_header_name_input": "Nom de l'en-tête",
|
||||
@@ -1160,7 +1170,9 @@
|
||||
"list": "Liste",
|
||||
"loading": "Chargement",
|
||||
"loading_search_results_failed": "Chargement des résultats échoué",
|
||||
"local": "Local",
|
||||
"local_asset_cast_failed": "Impossible de caster un média qui n'a pas envoyé vers le serveur",
|
||||
"local_assets": "Média locaux",
|
||||
"local_network": "Réseau local",
|
||||
"local_network_sheet_info": "L'application va se connecter au serveur via cette URL quand l'appareil est connecté à ce réseau Wi-Fi",
|
||||
"location_permission": "Autorisation de localisation",
|
||||
@@ -1317,6 +1329,7 @@
|
||||
"no_results": "Aucun résultat",
|
||||
"no_results_description": "Essayez un synonyme ou un mot-clé plus général",
|
||||
"no_shared_albums_message": "Créer un album pour partager vos photos et vidéos avec les personnes de votre réseau",
|
||||
"no_uploads_in_progress": "Pas d'envoi en cours",
|
||||
"not_in_any_album": "Dans aucun album",
|
||||
"not_selected": "Non sélectionné",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Note : Pour appliquer l'étiquette de stockage aux médias précédemment envoyés, exécutez",
|
||||
@@ -1354,6 +1367,7 @@
|
||||
"original": "original",
|
||||
"other": "Autre",
|
||||
"other_devices": "Autres appareils",
|
||||
"other_entities": "Autres entités",
|
||||
"other_variables": "Autres variables",
|
||||
"owned": "Possédé",
|
||||
"owner": "Propriétaire",
|
||||
@@ -1485,6 +1499,7 @@
|
||||
"purchase_server_description_2": "Statut de contributeur",
|
||||
"purchase_server_title": "Serveur",
|
||||
"purchase_settings_server_activated": "La clé du produit pour le Serveur est gérée par l'administrateur",
|
||||
"queue_status": "File d'attente {count}/{total}",
|
||||
"rating": "Étoile d'évaluation",
|
||||
"rating_clear": "Effacer l'évaluation",
|
||||
"rating_count": "{count, plural, one {# étoile} other {# étoiles}}",
|
||||
@@ -1513,6 +1528,8 @@
|
||||
"refreshing_faces": "Actualisation des visages",
|
||||
"refreshing_metadata": "Actualisation des métadonnées",
|
||||
"regenerating_thumbnails": "Regénération des miniatures",
|
||||
"remote": "A distance",
|
||||
"remote_assets": "Média à distance",
|
||||
"remove": "Supprimer",
|
||||
"remove_assets_album_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de l'album ?",
|
||||
"remove_assets_shared_link_confirmation": "Êtes-vous sûr de vouloir supprimer {count, plural, one {# média} other {# médias}} de ce lien partagé ?",
|
||||
@@ -1550,11 +1567,15 @@
|
||||
"reset_password": "Réinitialiser le mot de passe",
|
||||
"reset_people_visibility": "Réinitialiser la visibilité des personnes",
|
||||
"reset_pin_code": "Réinitialiser le code PIN",
|
||||
"reset_sqlite": "Réinitialiser la base de données SQLite",
|
||||
"reset_sqlite_confirmation": "Êtes vous sur que vous voulez réinitialiser la base de données SQLite ? Vous devrez vous déconnecter and vous reconnecter à nouveau pour re-synchroniser les données",
|
||||
"reset_sqlite_success": "La base de données SQLite à été réinitialisé avec succès",
|
||||
"reset_to_default": "Rétablir les valeurs par défaut",
|
||||
"resolve_duplicates": "Résoudre les doublons",
|
||||
"resolved_all_duplicates": "Résolution de tous les doublons",
|
||||
"restore": "Restaurer",
|
||||
"restore_all": "Tout restaurer",
|
||||
"restore_trash_action_prompt": "{count} restauré de la corbeille",
|
||||
"restore_user": "Restaurer l'utilisateur",
|
||||
"restored_asset": "Média restauré",
|
||||
"resume": "Reprendre",
|
||||
@@ -1563,6 +1584,7 @@
|
||||
"role": "Rôle",
|
||||
"role_editor": "Éditeur",
|
||||
"role_viewer": "Visionneuse",
|
||||
"running": "En marche",
|
||||
"save": "Sauvegarder",
|
||||
"save_to_gallery": "Enregistrer",
|
||||
"saved_api_key": "Clé API sauvegardée",
|
||||
@@ -1816,6 +1838,7 @@
|
||||
"storage_quota": "Quota de stockage",
|
||||
"storage_usage": "{used} sur {available} utilisé",
|
||||
"submit": "Soumettre",
|
||||
"success": "Réussi",
|
||||
"suggestions": "Suggestions",
|
||||
"sunrise_on_the_beach": "Lever de soleil sur la plage",
|
||||
"support": "Soutenir",
|
||||
@@ -1825,6 +1848,8 @@
|
||||
"sync": "Synchroniser",
|
||||
"sync_albums": "Synchroniser dans des albums",
|
||||
"sync_albums_manual_subtitle": "Synchroniser toutes les vidéos et photos envoyées dans les albums sélectionnés",
|
||||
"sync_local": "Synchronisation locale",
|
||||
"sync_remote": "Synchronisation à distance",
|
||||
"sync_upload_album_setting_subtitle": "Créez et envoyez vos photos et vidéos dans les albums sélectionnés sur Immich",
|
||||
"tag": "Étiquette",
|
||||
"tag_assets": "Étiqueter les médias",
|
||||
@@ -1835,6 +1860,7 @@
|
||||
"tag_updated": "Étiquette mise à jour : {tag}",
|
||||
"tagged_assets": "Étiquette ajoutée à {count, plural, one {# média} other {# médias}}",
|
||||
"tags": "Étiquettes",
|
||||
"tap_to_run_job": "Appuyez pour démarrer la tâche",
|
||||
"template": "Modèle",
|
||||
"theme": "Thème",
|
||||
"theme_selection": "Sélection du thème",
|
||||
@@ -1915,6 +1941,7 @@
|
||||
"updated_password": "Mot de passe mis à jour",
|
||||
"upload": "Envoyer",
|
||||
"upload_concurrency": "Envois simultanés",
|
||||
"upload_details": "Uploader les details",
|
||||
"upload_dialog_info": "Voulez-vous sauvegarder la sélection vers le serveur ?",
|
||||
"upload_dialog_title": "Envoyer le média",
|
||||
"upload_errors": "L'envoi s'est complété avec {count, plural, one {# erreur} other {# erreurs}}. Rafraîchissez la page pour voir les nouveaux médias envoyés.",
|
||||
@@ -1965,6 +1992,7 @@
|
||||
"view_album": "Afficher l'album",
|
||||
"view_all": "Voir tout",
|
||||
"view_all_users": "Voir tous les utilisateurs",
|
||||
"view_details": "Voir les détails",
|
||||
"view_in_timeline": "Voir dans la vue chronologique",
|
||||
"view_link": "Voir le lien",
|
||||
"view_links": "Voir les liens",
|
||||
|
||||
58
i18n/hu.json
58
i18n/hu.json
@@ -140,7 +140,7 @@
|
||||
"machine_learning_smart_search_description": "Képek szemantikai keresése CLIP beágyazások segítségével",
|
||||
"machine_learning_smart_search_enabled": "Okos keresés engedélyezése",
|
||||
"machine_learning_smart_search_enabled_description": "Ha ki van kapcsolva, a képek nem lesznek átalakítva okos kereséshez.",
|
||||
"machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem válaszoló szervereket átmenetileg figyelmen kívül hagyja, amíg újra online nem lesznek.",
|
||||
"machine_learning_url_description": "Gépi tanulás szerver URL címe. Ha többi, mint egy URL van megadva, mindegyik szervert egyenként próbálja meg, amíg az egyik sikeresen nem válaszol, sorrendben az elsőtől az utólsóig. A nem elérhető szervereket átmenetileg figyelmen kívül lesznek hagyva, amíg újra online nem lesznek.",
|
||||
"manage_concurrency": "Párhuzamos Feladatok Kezelése",
|
||||
"manage_log_settings": "Naplózási beállítások kezelése",
|
||||
"map_dark_style": "Sötét stílus",
|
||||
@@ -166,6 +166,12 @@
|
||||
"metadata_settings_description": "Metaadat beállítások kezelése",
|
||||
"migration_job": "Migrálás",
|
||||
"migration_job_description": "Az elemek és arcok bélyegképeinek migrálása a legújabb mappastruktúrába",
|
||||
"nightly_tasks_cluster_faces_setting_description": "Arcfelismerés futtatása az újonnan érzékelt arcokon",
|
||||
"nightly_tasks_database_cleanup_setting": "Adatbázis-tisztítási feladatok",
|
||||
"nightly_tasks_database_cleanup_setting_description": "A régi, lejárt adatok törlése az adatbázisból",
|
||||
"nightly_tasks_generate_memories_setting": "Emlékek generálása",
|
||||
"nightly_tasks_generate_memories_setting_description": "Új emlékek létrehozása elemekből",
|
||||
"nightly_tasks_missing_thumbnails_setting": "Hiányzó indexképek generálása",
|
||||
"no_paths_added": "Nincs megadva elérési útvonal",
|
||||
"no_pattern_added": "Nincs megadva minta (pattern)",
|
||||
"note_apply_storage_label_previous_assets": "Megjegyzés: Ha a korábban feltöltött elemekhez is szeretne Tárhely Címkéket társítani, akkor futtassa ezt",
|
||||
@@ -360,7 +366,7 @@
|
||||
"advanced_settings_enable_alternate_media_filter_subtitle": "Ezzel a beállítással a szinkronizálás során alternatív kritériumok alapján szűrheted a fájlokat. Csak akkor próbáld ki, ha problémáid vannak azzal, hogy az alkalmazás nem ismeri fel az összes albumot.",
|
||||
"advanced_settings_enable_alternate_media_filter_title": "[KÍSÉRLETI] Alternatív eszköz album szinkronizálási szűrő használata",
|
||||
"advanced_settings_log_level_title": "Naplózás szintje: {level}",
|
||||
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ez a beállítás inkább a távoli képeket tölti be helyettük.",
|
||||
"advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő indexképeket. Ez a beállítás inkább a távoli képeket (a szerverről) tölti be helyettük.",
|
||||
"advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése",
|
||||
"advanced_settings_proxy_headers_subtitle": "Add meg azokat a proxy fejléceket, amiket az app elküldjön minden hálózati kérésnél",
|
||||
"advanced_settings_proxy_headers_title": "Proxy Fejlécek",
|
||||
@@ -517,7 +523,7 @@
|
||||
"backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva",
|
||||
"backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása",
|
||||
"backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása",
|
||||
"backup_controller_page_background_wifi": "Csak WiFi-n",
|
||||
"backup_controller_page_background_wifi": "Csak Wi-Fi-n",
|
||||
"backup_controller_page_backup": "Mentés",
|
||||
"backup_controller_page_backup_selected": "Kiválasztva: ",
|
||||
"backup_controller_page_backup_sub": "Mentett fotók és videók",
|
||||
@@ -551,8 +557,8 @@
|
||||
"backup_setting_subtitle": "A háttérben és előtérben mentés beállításainak kezelése",
|
||||
"backward": "Visszafele",
|
||||
"biometric_auth_enabled": "Biometrikus azonosítás engedélyezve",
|
||||
"biometric_locked_out": "A biometrikus azonosításból kizárva",
|
||||
"biometric_no_options": "A biometrikus azonosítás nem elérhető",
|
||||
"biometric_locked_out": "Ki vagy zárva a biometrikus azonosításból",
|
||||
"biometric_no_options": "Nincsen elérhető biometrikus azonosítás",
|
||||
"biometric_not_available": "Biometrikus azonosítás ezen az eszközön nem elérhető",
|
||||
"birthdate_saved": "Születésnap elmentve",
|
||||
"birthdate_set_description": "A születés napját a rendszer arra használja, hogy kiírja, hogy a fénykép készítésekor a személy hány éves volt.",
|
||||
@@ -642,7 +648,7 @@
|
||||
"confirm_keep_this_delete_others": "Minden más elem a készletben törlésre kerül, kivéve ezt az elemet. Biztosan folytatni szeretnéd?",
|
||||
"confirm_new_pin_code": "Új PIN kód megerősítése",
|
||||
"confirm_password": "Jelszó megerősítése",
|
||||
"confirm_tag_face": "Szeretnéd ezt az arcot {name}-ként megjelölni?",
|
||||
"confirm_tag_face": "Szeretnéd ezt az arcot {name}-nak/nek megjelölni?",
|
||||
"confirm_tag_face_unnamed": "Szeretnéd ezt az arcot megjelölni?",
|
||||
"connected_device": "Kapcsolt eszköz",
|
||||
"connected_to": "Kapcsolódva",
|
||||
@@ -770,7 +776,7 @@
|
||||
"download_started": "Letöltés megkezdve",
|
||||
"download_sucess": "Sikeres letöltés",
|
||||
"download_sucess_android": "Média letöltve a DCIM/Immich mappába",
|
||||
"download_waiting_to_retry": "Várakozás újrapróbálkozáshoz",
|
||||
"download_waiting_to_retry": "Várás az újrapróbálkozásra",
|
||||
"downloading": "Letöltés",
|
||||
"downloading_asset_filename": "{filename} elem letöltése",
|
||||
"downloading_media": "Média letöltése",
|
||||
@@ -816,7 +822,7 @@
|
||||
"enqueued": "Sorba állítva",
|
||||
"enter_wifi_name": "Add meg a Wi-Fi hálózat nevét",
|
||||
"enter_your_pin_code": "Add meg a jelszavad",
|
||||
"enter_your_pin_code_subtitle": "Add meg a jelszavad a zárolt mappa megnyitásához",
|
||||
"enter_your_pin_code_subtitle": "Add meg a PIN kódodat a zárolt mappa megnyitásához",
|
||||
"error": "Hiba",
|
||||
"error_change_sort_album": "Album sorbarendezésének megváltoztatása sikertelen",
|
||||
"error_delete_face": "Hiba az arc törlése során",
|
||||
@@ -916,7 +922,7 @@
|
||||
"unable_to_remove_partner": "Partner eltávolítása sikertelen",
|
||||
"unable_to_remove_reaction": "Reakció eltávolítása sikertelen",
|
||||
"unable_to_reset_password": "Jelszó visszaállítása sikertelen",
|
||||
"unable_to_reset_pin_code": "Jelszó visszaállítása sikertelen",
|
||||
"unable_to_reset_pin_code": "PIN kód visszaállítása sikertelen",
|
||||
"unable_to_resolve_duplicate": "Duplikátum feloldása sikertelen",
|
||||
"unable_to_restore_assets": "Elemek visszaállítása sikertelen",
|
||||
"unable_to_restore_trash": "Az összes elem visszaállítása sikertelen",
|
||||
@@ -988,7 +994,7 @@
|
||||
"filetype": "Fájltípus",
|
||||
"filter": "Szűrő",
|
||||
"filter_people": "Személyek szűrése",
|
||||
"filter_places": "Helyek szűrése",
|
||||
"filter_places": "Helyszínek szűrése",
|
||||
"find_them_fast": "Név alapján kereséssel gyorsan megtalálhatóak",
|
||||
"fix_incorrect_match": "Hibás találat javítása",
|
||||
"folder": "Mappa",
|
||||
@@ -1029,9 +1035,9 @@
|
||||
"hide_person": "Személy elrejtése",
|
||||
"hide_unnamed_people": "Név nélküli személyek elrejtése",
|
||||
"home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.",
|
||||
"home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, kihagyás",
|
||||
"home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni, ki lesznek hagyva",
|
||||
"home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.",
|
||||
"home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, kihagyás",
|
||||
"home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, ki lesznek hagyva",
|
||||
"home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk",
|
||||
"home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk",
|
||||
"home_page_building_timeline": "Idővonal összeállítása",
|
||||
@@ -1040,7 +1046,7 @@
|
||||
"home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk",
|
||||
"home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk",
|
||||
"home_page_first_time_notice": "Ha most használod először az alkalmazást, a fotók és videók megjelenítéséhez az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés",
|
||||
"home_page_locked_error_local": "Helyi elemek nem mozgathatóak a zárolt mappába, átugorva",
|
||||
"home_page_locked_error_local": "A Helyi elemek nem mozgathatóak a zárolt mappába, ki lesznek hagyva",
|
||||
"home_page_locked_error_partner": "Partner elemek nem mozgathatóak a zárolt mappába, átugorva",
|
||||
"home_page_share_err_local": "Helyi elemekről nem lehet megosztott linket készíteni, úgyhogy kihagyjuk",
|
||||
"home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk",
|
||||
@@ -1087,10 +1093,10 @@
|
||||
"invite_people": "Személyek Meghívása",
|
||||
"invite_to_album": "Meghívás az albumba",
|
||||
"ios_debug_info_last_sync_at": "Utoljára szinkronizálva {dateTime}",
|
||||
"ios_debug_info_no_processes_queued": "Nincs sorba állított hátterfolyamat",
|
||||
"ios_debug_info_no_processes_queued": "Nincs a sorban háttérfolyamat jelenleg",
|
||||
"ios_debug_info_no_sync_yet": "Még nem futott szinkronizáló háttérfolyamat",
|
||||
"ios_debug_info_processes_queued": "{count, plural, one {{count} háttérfolyamat előkészítve} other {{count} háttérfolyamat előkészítve}}",
|
||||
"ios_debug_info_processing_ran_at": "Feldolgozás futott {dateTime}",
|
||||
"ios_debug_info_processing_ran_at": "A feldolgozás ekkor futott: {dateTime}",
|
||||
"items_count": "{count, plural, other {# elem}}",
|
||||
"jobs": "Feladatok",
|
||||
"keep": "Megtart",
|
||||
@@ -1099,7 +1105,7 @@
|
||||
"kept_this_deleted_others": "Ez az elem és a töröltek meg lettek hagyva {count, plural, one {# asset} other {# assets}}",
|
||||
"keyboard_shortcuts": "Billentyűparancsok",
|
||||
"language": "Nyelv",
|
||||
"language_no_results_subtitle": "Próbáld a keresésed módosítását",
|
||||
"language_no_results_subtitle": "Próbáld módosítani a szavaidat a keresésnél",
|
||||
"language_search_hint": "Nyelvek keresése...",
|
||||
"language_setting_description": "Válaszd ki preferált nyelvet",
|
||||
"last_seen": "Utoljára láttuk",
|
||||
@@ -1129,7 +1135,7 @@
|
||||
"local_network": "Helyi hálózat",
|
||||
"local_network_sheet_info": "Az alkalmazés ezen az URL címen fogja elérni a szervert, ha a megadott WiFi hálózathoz van csatlankozva",
|
||||
"location_permission": "Helymeghatározási engedély",
|
||||
"location_permission_content": "Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét",
|
||||
"location_permission_content": "A Hálózatok automatikus váltásához az Immich-nek szüksége van a pontos helymeghatározásra, hogy az alkalmazás le tudja kérni a Wi-Fi hálózat nevét",
|
||||
"location_picker_choose_on_map": "Válassz a térképen",
|
||||
"location_picker_latitude_error": "Érvényes szélességi kört írj be",
|
||||
"location_picker_latitude_hint": "Ide írd a szélességi kört",
|
||||
@@ -1139,7 +1145,7 @@
|
||||
"locked_folder": "Zárolt mappa",
|
||||
"log_out": "Kijelentkezés",
|
||||
"log_out_all_devices": "Kijelentkezés Minden Eszközön",
|
||||
"logged_in_as": "{user}-ként belépve",
|
||||
"logged_in_as": "Belépve: {user} néven",
|
||||
"logged_out_all_devices": "Minden eszköz kijelentkeztetve",
|
||||
"logged_out_device": "Eszköz kijelentkeztetve",
|
||||
"login": "Bejelentkezés",
|
||||
@@ -1234,9 +1240,9 @@
|
||||
"monthly_title_text_date_format": "y MMMM",
|
||||
"more": "Továbbiak",
|
||||
"move": "Áthelyezés",
|
||||
"move_off_locked_folder": "Zárolt mappából kivonás",
|
||||
"move_off_locked_folder": "Átmozgatás a zárolt mappából",
|
||||
"move_to_locked_folder": "Áthelyezés a zárolt mappába",
|
||||
"move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappából lesznek elérhetőek",
|
||||
"move_to_locked_folder_confirmation": "Ezek a képek és videók az összes albumból kikerülnek, és csak a zárolt mappában lesznek elérhetőek",
|
||||
"moved_to_archive": "{count, plural, one {# Elem} other {# Elemek}} archiválva",
|
||||
"moved_to_library": "{count, plural, one {# Elem} other {# Elemek}} másik könyvtárba költöztetve",
|
||||
"moved_to_trash": "Áthelyezve a lomtárba",
|
||||
@@ -1254,7 +1260,7 @@
|
||||
"new_password": "Új jelszó",
|
||||
"new_person": "Új személy",
|
||||
"new_pin_code": "Új PIN kód",
|
||||
"new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót az oldal biztosítására",
|
||||
"new_pin_code_subtitle": "Ez az első alkalom hogy megnyitod a zárolt mappát. Hozz létre egy jelszót a mappa biztonságos eléréséhez",
|
||||
"new_user_created": "Új felhasználó létrehozva",
|
||||
"new_version_available": "ÚJ VERZIÓ ÉRHETŐ EL",
|
||||
"newest_first": "Legújabb először",
|
||||
@@ -1283,7 +1289,7 @@
|
||||
"not_selected": "Nincs kiválasztva",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Megjegyzés: a korábban feltöltött elemek Tárhely Címkézéséhez futtasd a(z)",
|
||||
"notes": "Megjegyzések",
|
||||
"nothing_here_yet": "Itt még nincs semmi",
|
||||
"nothing_here_yet": "Még semmi sincs itt",
|
||||
"notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.",
|
||||
"notification_permission_list_tile_content": "Értesítések engedélyezése.",
|
||||
"notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása",
|
||||
@@ -1293,7 +1299,7 @@
|
||||
"notifications_setting_description": "Értesítések kezelése",
|
||||
"oauth": "OAuth",
|
||||
"official_immich_resources": "Hivatalos Immich Források",
|
||||
"offline": "Offline",
|
||||
"offline": "Nem elérhető (offline)",
|
||||
"ok": "Rendben",
|
||||
"oldest_first": "Legrégebbi először",
|
||||
"on_this_device": "Ezen az eszközön",
|
||||
@@ -1303,7 +1309,7 @@
|
||||
"onboarding_theme_description": "Válassz egy színtémát. Ezt bármikor megváltoztathatod a beállításokban.",
|
||||
"onboarding_user_welcome_description": "Kezdjünk bele!",
|
||||
"onboarding_welcome_user": "Üdvözöllek {user}",
|
||||
"online": "Online",
|
||||
"online": "Online (elérhető)",
|
||||
"only_favorites": "Csak kedvencek",
|
||||
"open": "Nyitva",
|
||||
"open_in_map_view": "Megnyitás térkép nézetben",
|
||||
@@ -1754,7 +1760,7 @@
|
||||
"stack_select_one_photo": "Válassz egy fő képet a csoportból",
|
||||
"stack_selected_photos": "Kiválasztott fényképek csoportosítása",
|
||||
"stacked_assets_count": "{count, plural, other {# elem}} csoportosítva",
|
||||
"stacktrace": "Hibaleírás",
|
||||
"stacktrace": "Hiba leírása",
|
||||
"start": "Elindít",
|
||||
"start_date": "Kezdő dátum",
|
||||
"state": "Megye/Állam",
|
||||
@@ -1882,7 +1888,7 @@
|
||||
"user_liked": "{user} felhasználónak {type, select, photo {ez a fénykép} video {ez a videó} asset {ez az elem} other {ez}} tetszik",
|
||||
"user_pin_code_settings": "PIN kód",
|
||||
"user_pin_code_settings_description": "PIN kód kezelése",
|
||||
"user_privacy": "Felhasználói biztonság",
|
||||
"user_privacy": "Felhasználói adatvédelem",
|
||||
"user_purchase_settings": "Megvásárlás",
|
||||
"user_purchase_settings_description": "Vásárlás kezelése",
|
||||
"user_role_set": "{user} felhasználónak {role} jogkör biztosítása",
|
||||
|
||||
10
i18n/id.json
10
i18n/id.json
@@ -169,15 +169,23 @@
|
||||
"nightly_tasks_cluster_faces_setting_description": "Mulai pengenalan wajah pada semua wajah yang baru saja terdeteksi",
|
||||
"nightly_tasks_cluster_new_faces_setting": "Kelompokkan semua wajah baru",
|
||||
"nightly_tasks_database_cleanup_setting": "Tugas pembersihan basis data",
|
||||
"nightly_tasks_database_cleanup_setting_description": "Membersihkan data lama, kadaluarsa dari database",
|
||||
"nightly_tasks_generate_memories_setting": "Buat kenang-kenangan",
|
||||
"nightly_tasks_generate_memories_setting_description": "Buat kenang-kenangan baru dari berbagai aset",
|
||||
"nightly_tasks_missing_thumbnails_setting": "Membuat thumbnail yang hilang",
|
||||
"nightly_tasks_missing_thumbnails_setting_description": "Mengantrikan aset tanpa thumbnail untuk pembuatan thumbnail",
|
||||
"nightly_tasks_settings": "Pengaturan Tugas Malam",
|
||||
"nightly_tasks_settings_description": "Atur tugas malam",
|
||||
"nightly_tasks_start_time_setting": "Waktu mulai",
|
||||
"nightly_tasks_start_time_setting_description": "Waktu saat server mulai menjalankan tugas malam",
|
||||
"nightly_tasks_sync_quota_usage_setting": "Sinkronisasi penggunaan kuota",
|
||||
"nightly_tasks_sync_quota_usage_setting_description": "Pembaruan kuota penyimpanan pengguna, berdasarkan penggunaan sekarang",
|
||||
"no_paths_added": "Tidak ada jalur yang ditambahkan",
|
||||
"no_pattern_added": "Tidak ada pola yang ditambahkan",
|
||||
"note_apply_storage_label_previous_assets": "Catatan: Untuk menerapkan Label Penyimpanan untuk aset yang telah diunggah sebelumnya, jalankan",
|
||||
"note_cannot_be_changed_later": "CATATAN: Ini tidak akan dapat diubah lagi!",
|
||||
"notification_email_from_address": "Dari alamat",
|
||||
"notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich <noreply@example.com>\". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email",
|
||||
"notification_email_from_address_description": "Alamat surel pengirim, misalnya: \"Server Foto Immich <noreply@example.com>\". Pastikan untuk menggunakan alamat yang diizinkan untuk mengirim email.",
|
||||
"notification_email_host_description": "Hos server surel (mis. smtp.immich.app)",
|
||||
"notification_email_ignore_certificate_errors": "Abaikan eror sertifikat",
|
||||
"notification_email_ignore_certificate_errors_description": "Abaikan eror validasi sertifikat TLS (tidak disarankan)",
|
||||
|
||||
12
i18n/it.json
12
i18n/it.json
@@ -406,6 +406,7 @@
|
||||
"album_options": "Impostazioni Album",
|
||||
"album_remove_user": "Rimuovi l'utente?",
|
||||
"album_remove_user_confirmation": "Sicuro di voler rimuovere l'utente {user}?",
|
||||
"album_search_not_found": "Nessun album trovato corrispondente alla tua ricerca",
|
||||
"album_share_no_users": "Sembra che tu abbia condiviso questo album con tutti gli utenti oppure non hai nessun utente con cui condividere.",
|
||||
"album_updated": "Album aggiornato",
|
||||
"album_updated_setting_description": "Ricevi una notifica email quando un album condiviso ha nuovi media",
|
||||
@@ -425,6 +426,7 @@
|
||||
"albums_default_sort_order": "Ordinamento predefinito degli album",
|
||||
"albums_default_sort_order_description": "Ordine iniziale degli elementi alla creazione di nuovi album.",
|
||||
"albums_feature_description": "Raggruppamento di elementi che possono essere condivisi con altri utenti.",
|
||||
"albums_on_device_count": "Album sul dispositivo ({count})",
|
||||
"all": "Tutti",
|
||||
"all_albums": "Tutti gli album",
|
||||
"all_people": "Tutte le persone",
|
||||
@@ -605,6 +607,7 @@
|
||||
"cancel": "Annulla",
|
||||
"cancel_search": "Annulla ricerca",
|
||||
"canceled": "Annullato",
|
||||
"canceling": "Annullamento",
|
||||
"cannot_merge_people": "Impossibile unire le persone",
|
||||
"cannot_undo_this_action": "Non puoi annullare questa azione!",
|
||||
"cannot_update_the_description": "Impossibile aggiornare la descrizione",
|
||||
@@ -751,6 +754,7 @@
|
||||
"delete_key": "Elimina chiave",
|
||||
"delete_library": "Elimina libreria",
|
||||
"delete_link": "Elimina link",
|
||||
"delete_local_action_prompt": "{count} elementi rimossi in locale",
|
||||
"delete_local_dialog_ok_backed_up_only": "Elimina solo con backup",
|
||||
"delete_local_dialog_ok_force": "Elimina comunque",
|
||||
"delete_others": "Elimina gli altri",
|
||||
@@ -764,6 +768,7 @@
|
||||
"description": "Descrizione",
|
||||
"description_input_hint_text": "Aggiungi descrizione...",
|
||||
"description_input_submit_error": "Errore modificare descrizione, controlli I log per maggiori dettagli",
|
||||
"deselect_all": "Deseleziona Tutto",
|
||||
"details": "Dettagli",
|
||||
"direction": "Direzione",
|
||||
"disabled": "Disabilitato",
|
||||
@@ -781,6 +786,7 @@
|
||||
"documentation": "Documentazione",
|
||||
"done": "Fatto",
|
||||
"download": "Scarica",
|
||||
"download_action_prompt": "Scaricando {count} elementi",
|
||||
"download_canceled": "Download annullato",
|
||||
"download_complete": "Download completato",
|
||||
"download_enqueue": "Download in coda",
|
||||
@@ -837,6 +843,7 @@
|
||||
"empty_trash": "Svuota cestino",
|
||||
"empty_trash_confirmation": "Sei sicuro di volere svuotare il cestino? Questo rimuoverà tutte le risorse nel cestino in modo permanente da Immich.\nNon puoi annullare questa azione!",
|
||||
"enable": "Abilita",
|
||||
"enable_backup": "Abilita Backup",
|
||||
"enable_biometric_auth_description": "Inserire il codice PIN per abilitare l'autenticazione biometrica",
|
||||
"enabled": "Abilitato",
|
||||
"end_date": "Data Fine",
|
||||
@@ -1483,6 +1490,7 @@
|
||||
"purchase_server_description_2": "Stato di Contributore",
|
||||
"purchase_server_title": "Server",
|
||||
"purchase_settings_server_activated": "La chiave del prodotto del server è gestita dall'amministratore",
|
||||
"queue_status": "Messi in coda {count}/{total}",
|
||||
"rating": "Valutazione a stelle",
|
||||
"rating_clear": "Crea valutazione",
|
||||
"rating_count": "{count, plural, one {# stella} other {# stelle}}",
|
||||
@@ -1518,6 +1526,7 @@
|
||||
"remove_custom_date_range": "Rimuovi intervallo data personalizzato",
|
||||
"remove_deleted_assets": "Rimuovi file offline",
|
||||
"remove_from_album": "Rimuovere dall'album",
|
||||
"remove_from_album_action_prompt": "{count} elementi rimossi dall'album",
|
||||
"remove_from_favorites": "Rimuovi dai preferiti",
|
||||
"remove_from_lock_folder_action_prompt": "{count} elementi rimossi dalla cartella sicura",
|
||||
"remove_from_locked_folder": "Rimuovi dalla cartella privata",
|
||||
@@ -1691,6 +1700,7 @@
|
||||
"settings_saved": "Impostazioni salvate",
|
||||
"setup_pin_code": "Configura un codice PIN",
|
||||
"share": "Condivisione",
|
||||
"share_action_prompt": "Condivisi {count} elementi",
|
||||
"share_add_photos": "Aggiungi foto",
|
||||
"share_assets_selected": "{count} selezionati",
|
||||
"share_dialog_preparing": "Preparo…",
|
||||
@@ -1792,6 +1802,7 @@
|
||||
"sort_title": "Titolo",
|
||||
"source": "Fonte",
|
||||
"stack": "Raggruppa",
|
||||
"stack_action_prompt": "{count} elementi raggruppati",
|
||||
"stack_duplicates": "Raggruppa i duplicati",
|
||||
"stack_select_one_photo": "Seleziona una foto principale per il gruppo",
|
||||
"stack_selected_photos": "Impila foto selezionate",
|
||||
@@ -1880,6 +1891,7 @@
|
||||
"unable_to_change_pin_code": "Impossibile cambiare il codice PIN",
|
||||
"unable_to_setup_pin_code": "Impossibile configurare il codice PIN",
|
||||
"unarchive": "Annulla l'archiviazione",
|
||||
"unarchive_action_prompt": "{count} elementi rimossi dall'Archivio",
|
||||
"unarchived_count": "{count, plural, other {Non archiviati #}}",
|
||||
"undo": "Annulla",
|
||||
"unfavorite": "Rimuovi preferito",
|
||||
|
||||
11
i18n/lv.json
11
i18n/lv.json
@@ -707,6 +707,9 @@
|
||||
"next_memory": "Nākamā atmiņa",
|
||||
"no": "Nē",
|
||||
"no_albums_message": "Izveido albumu, lai organizētu savas fotogrāfijas un video",
|
||||
"no_albums_with_name_yet": "Izskatās, ka tev vēl nav albumu ar šādu nosaukumu.",
|
||||
"no_albums_yet": "Izskatās, ka tev vēl nav neviena albuma.",
|
||||
"no_archived_assets_message": "Arhivē fotoattēlus un videoklipus, lai paslēptu tos no Fotoattēli skata",
|
||||
"no_assets_message": "NOKLIKŠĶINIET, LAI AUGŠUPIELĀDĒTU SAVU PIRMO FOTOATTĒLU",
|
||||
"no_assets_to_show": "Nav uzrādāmo aktīvu",
|
||||
"no_duplicates_found": "Dublikāti netika atrasti.",
|
||||
@@ -730,6 +733,10 @@
|
||||
"official_immich_resources": "Oficiālie Immich resursi",
|
||||
"offline": "Bezsaistē",
|
||||
"ok": "Labi",
|
||||
"onboarding": "Uzņemšana",
|
||||
"onboarding_locale_description": "Izvēlies vēlamo valodu. To vēlāk var mainīt iestatījumos.",
|
||||
"onboarding_theme_description": "Izvēlies savas instances krāsu motīvu. To vēlāk var mainīt iestatījumos.",
|
||||
"onboarding_user_welcome_description": "Sāksim darbu!",
|
||||
"online": "Tiešsaistē",
|
||||
"only_favorites": "Tikai izlase",
|
||||
"open_in_map_view": "Atvērt kartes skatā",
|
||||
@@ -737,13 +744,16 @@
|
||||
"open_the_search_filters": "Atvērt meklēšanas filtrus",
|
||||
"options": "Iestatījumi",
|
||||
"or": "vai",
|
||||
"organize_your_library": "Bibliotēkas organizēšana",
|
||||
"original": "oriģināls",
|
||||
"other": "Citi",
|
||||
"other_devices": "Citas ierīces",
|
||||
"other_variables": "Citi mainīgie",
|
||||
"owned": "Īpašumā",
|
||||
"owner": "Īpašnieks",
|
||||
"partner": "Partneris",
|
||||
"partner_can_access": "{partner} var piekļūt",
|
||||
"partner_can_access_location": "Fotogrāfiju uzņemšanas vieta",
|
||||
"partner_list_user_photos": "{user} fotoattēli",
|
||||
"partner_list_view_all": "Apskatīt visu",
|
||||
"partner_page_empty_message": "Jūsu fotogrāfijas pagaidām nav kopīgotas ar nevienu partneri.",
|
||||
@@ -757,6 +767,7 @@
|
||||
"password_does_not_match": "Parole nesakrīt",
|
||||
"path": "Ceļš",
|
||||
"pause": "Pauzēt",
|
||||
"pause_memories": "Pauzēt atmiņas",
|
||||
"paused": "Nopauzēts",
|
||||
"people": "Cilvēki",
|
||||
"permission_onboarding_back": "Atpakaļ",
|
||||
|
||||
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Backupinnstillinger",
|
||||
"backup_setting_subtitle": "Administrer opplastingsinnstillinger for bakgrunn og forgrunn",
|
||||
"backward": "Bakover",
|
||||
"beta_sync": "Beta synkroniseringsstatus",
|
||||
"beta_sync_subtitle": "Håndter det nye synkroniseringssystemet",
|
||||
"biometric_auth_enabled": "Biometrisk autentisering aktivert",
|
||||
"biometric_locked_out": "Du er låst ute av biometrisk verifisering",
|
||||
"biometric_no_options": "Ingen biometriske valg tilgjengelige",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Tøm buffer",
|
||||
"cache_settings_clear_cache_button_title": "Tømmer app-ens buffer. Dette vil ha betydelig innvirkning på appens ytelse inntil bufferen er gjenoppbygd.",
|
||||
"cache_settings_duplicated_assets_clear_button": "TØM",
|
||||
"cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er svartelistet av app'en",
|
||||
"cache_settings_duplicated_assets_subtitle": "Bilder og videoer som er ignorert av app'en",
|
||||
"cache_settings_duplicated_assets_title": "Dupliserte objekter ({count})",
|
||||
"cache_settings_statistics_album": "Bibliotekminiatyrbilder",
|
||||
"cache_settings_statistics_full": "Originalbilder",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Aktivert haptisk tilbakemelding",
|
||||
"haptic_feedback_title": "Haptisk tilbakemelding",
|
||||
"has_quota": "Kvote",
|
||||
"hash_asset": "Hash objekter",
|
||||
"hashed_assets": "Hashede objekter",
|
||||
"hashing": "Hasher",
|
||||
"header_settings_add_header_tip": "Legg til header",
|
||||
"header_settings_field_validator_msg": "Verdi kan ikke være null",
|
||||
"header_settings_header_name_input": "Header navn",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Vert",
|
||||
"hour": "Time",
|
||||
"id": "ID",
|
||||
"idle": "Uvirksom",
|
||||
"ignore_icloud_photos": "Ignorer iCloud bilder",
|
||||
"ignore_icloud_photos_description": "Bilder som er lagret på iCloud vil ikke lastes opp til Immich",
|
||||
"image": "Bilde",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Liste",
|
||||
"loading": "Laster",
|
||||
"loading_search_results_failed": "Klarte ikke å laste inn søkeresultater",
|
||||
"local": "Lokal",
|
||||
"local_asset_cast_failed": "Kan ikke caste et bilde som ikke er lastet opp til serveren",
|
||||
"local_assets": "Lokale objekter",
|
||||
"local_network": "Lokalt nettverk",
|
||||
"local_network_sheet_info": "Appen vil koble til serveren via denne URL-en når du bruker det angitte Wi-Fi-nettverket",
|
||||
"location_permission": "Stedstillatelse",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Ingen resultater",
|
||||
"no_results_description": "Prøv et synonym eller mer generelt søkeord",
|
||||
"no_shared_albums_message": "Opprett et album for å dele bilder og videoer med personer i nettverket ditt",
|
||||
"no_uploads_in_progress": "Ingen opplasting pågår",
|
||||
"not_in_any_album": "Ikke i noe album",
|
||||
"not_selected": "Ikke valgt",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Merk: For å bruke lagringsetiketten på tidligere opplastede filer, kjør",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "original",
|
||||
"other": "Annet",
|
||||
"other_devices": "Andre enheter",
|
||||
"other_entities": "Andre objekter",
|
||||
"other_variables": "Andre variabler",
|
||||
"owned": "Dine",
|
||||
"owner": "Eier",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Oppdaterer ansikter",
|
||||
"refreshing_metadata": "Oppdaterer matadata",
|
||||
"regenerating_thumbnails": "Regenererer miniatyrbilder",
|
||||
"remote": "Eksternt",
|
||||
"remote_assets": "Eksterne objekter",
|
||||
"remove": "Fjern",
|
||||
"remove_assets_album_confirmation": "Er du sikker på at du fil slette {count, plural, one {# asset} other {# assets}} fra albumet?",
|
||||
"remove_assets_shared_link_confirmation": "Er du sikker på at du vil slette {count, plural, one {# asset} other {# assets}} fra den delte lenken?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "Tilbakestill passord",
|
||||
"reset_people_visibility": "Tilbakestill personsynlighet",
|
||||
"reset_pin_code": "Resett PINkode",
|
||||
"reset_sqlite": "Reset SQLite Databasen",
|
||||
"reset_sqlite_confirmation": "Er du sikker på at du vil resette SQLite databasen? Du blir nødt til å logge ut og inn igjen for å resynkronisere data",
|
||||
"reset_sqlite_success": "Vellykket resetting av SQLite databasen",
|
||||
"reset_to_default": "Tilbakestill til standard",
|
||||
"resolve_duplicates": "Løs duplikater",
|
||||
"resolved_all_duplicates": "Løste alle duplikater",
|
||||
"restore": "Gjenopprett",
|
||||
"restore_all": "Gjenopprett alle",
|
||||
"restore_trash_action_prompt": "{count} gjenopprettet fra søppelbøtten",
|
||||
"restore_user": "Gjenopprett bruker",
|
||||
"restored_asset": "Gjenopprettet ressurs",
|
||||
"resume": "Fortsett",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "Rolle",
|
||||
"role_editor": "Redigerer",
|
||||
"role_viewer": "Visning",
|
||||
"running": "Kjører",
|
||||
"save": "Lagre",
|
||||
"save_to_gallery": "Lagre til galleriet",
|
||||
"saved_api_key": "Lagret API-nøkkel",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Lagringsplass",
|
||||
"storage_usage": "{used} av {available} brukt",
|
||||
"submit": "Send inn",
|
||||
"success": "Vellykket",
|
||||
"suggestions": "Forslag",
|
||||
"sunrise_on_the_beach": "Soloppgang på stranden",
|
||||
"support": "Støtte",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "Synkroniser",
|
||||
"sync_albums": "Synkroniser albumer",
|
||||
"sync_albums_manual_subtitle": "Synkroniser alle opplastede videoer og bilder til det valgte backupalbumet",
|
||||
"sync_local": "Synkroniser lokalt",
|
||||
"sync_remote": "Synkroniser eksternt",
|
||||
"sync_upload_album_setting_subtitle": "Opprett og last opp dine bilder og videoer til det valgte albumet på Immich",
|
||||
"tag": "Tagg",
|
||||
"tag_assets": "Merk ressurser",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Oppdater merke: {tag}",
|
||||
"tagged_assets": "Merket {count, plural, one {# asset} other {# assets}}",
|
||||
"tags": "Merker",
|
||||
"tap_to_run_job": "Trykk for å kjøre jobben",
|
||||
"template": "Mal",
|
||||
"theme": "Tema",
|
||||
"theme_selection": "Temavalg",
|
||||
|
||||
24
i18n/nl.json
24
i18n/nl.json
@@ -426,6 +426,7 @@
|
||||
"albums_default_sort_order": "Standaard sorteervolgorde album",
|
||||
"albums_default_sort_order_description": "Initiële sorteervolgorde bij het maken van nieuwe albums.",
|
||||
"albums_feature_description": "Collectie van assets die je kan delen met andere gebruikers.",
|
||||
"albums_on_device_count": "Albums op apparaat ({count})",
|
||||
"all": "Alle",
|
||||
"all_albums": "Alle albums",
|
||||
"all_people": "Alle mensen",
|
||||
@@ -572,6 +573,8 @@
|
||||
"backup_options_page_title": "Back-up instellingen",
|
||||
"backup_setting_subtitle": "Beheer achtergrond en voorgrond uploadinstellingen",
|
||||
"backward": "Achteruit",
|
||||
"beta_sync": "Beta Sync Status",
|
||||
"beta_sync_subtitle": "Beheer het nieuwe synchronisatiesysteem",
|
||||
"biometric_auth_enabled": "Biometrische authenticatie ingeschakeld",
|
||||
"biometric_locked_out": "Biometrische authenticatie is vergrendeld",
|
||||
"biometric_no_options": "Geen biometrische opties beschikbaar",
|
||||
@@ -589,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Cache wissen",
|
||||
"cache_settings_clear_cache_button_title": "Wist de cache van de app. Dit zal de presentaties van de app aanzienlijk beïnvloeden totdat de cache opnieuw is opgebouwd.",
|
||||
"cache_settings_duplicated_assets_clear_button": "MAAK VRIJ",
|
||||
"cache_settings_duplicated_assets_subtitle": "Foto's en video's op de zwarte lijst van de app",
|
||||
"cache_settings_duplicated_assets_subtitle": "Foto’s en video's die de app negeert",
|
||||
"cache_settings_duplicated_assets_title": "Gedupliceerde assets ({count})",
|
||||
"cache_settings_statistics_album": "Bibliotheekthumbnails",
|
||||
"cache_settings_statistics_full": "Volledige afbeeldingen",
|
||||
@@ -1050,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Aanraaktrillingen inschakelen",
|
||||
"haptic_feedback_title": "Aanraaktrillingen",
|
||||
"has_quota": "Heeft limiet",
|
||||
"hash_asset": "Hash asset",
|
||||
"hashed_assets": "Gehashte assets",
|
||||
"hashing": "Hashen",
|
||||
"header_settings_add_header_tip": "Header toevoegen",
|
||||
"header_settings_field_validator_msg": "Waarde kan niet leeg zijn",
|
||||
"header_settings_header_name_input": "Header naam",
|
||||
@@ -1082,6 +1088,7 @@
|
||||
"host": "Host",
|
||||
"hour": "Uur",
|
||||
"id": "ID",
|
||||
"idle": "Idle",
|
||||
"ignore_icloud_photos": "Negeer iCloud foto's",
|
||||
"ignore_icloud_photos_description": "Foto's die op iCloud zijn opgeslagen, worden niet geüpload naar de Immich server",
|
||||
"image": "Afbeelding",
|
||||
@@ -1164,7 +1171,9 @@
|
||||
"list": "Lijst",
|
||||
"loading": "Laden",
|
||||
"loading_search_results_failed": "Laden van zoekresultaten mislukt",
|
||||
"local": "Lokaal",
|
||||
"local_asset_cast_failed": "Kan geen asset casten die nog niet geüpload is naar de server",
|
||||
"local_assets": "Lokale Assets",
|
||||
"local_network": "Lokaal netwerk",
|
||||
"local_network_sheet_info": "De app maakt verbinding met de server via deze URL wanneer het opgegeven WiFi-netwerk wordt gebruikt",
|
||||
"location_permission": "Locatietoestemming",
|
||||
@@ -1321,6 +1330,7 @@
|
||||
"no_results": "Geen resultaten",
|
||||
"no_results_description": "Probeer een synoniem of een algemener zoekwoord",
|
||||
"no_shared_albums_message": "Maak een album om foto's en video's te delen met mensen in je netwerk",
|
||||
"no_uploads_in_progress": "Geen uploads bezig",
|
||||
"not_in_any_album": "Niet in een album",
|
||||
"not_selected": "Niet geselecteerd",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Opmerking: om het opslaglabel toe te passen op eerder geüploade assets, voer de volgende taak uit",
|
||||
@@ -1358,6 +1368,7 @@
|
||||
"original": "origineel",
|
||||
"other": "Overige",
|
||||
"other_devices": "Andere apparaten",
|
||||
"other_entities": "Andere entities",
|
||||
"other_variables": "Andere variabelen",
|
||||
"owned": "Eigenaar",
|
||||
"owner": "Eigenaar",
|
||||
@@ -1518,6 +1529,8 @@
|
||||
"refreshing_faces": "Gezichten aan het vernieuwen",
|
||||
"refreshing_metadata": "Metadata aan het vernieuwen",
|
||||
"regenerating_thumbnails": "Thumbnails opnieuw aan het genereren",
|
||||
"remote": "Remote",
|
||||
"remote_assets": "Remote Assets",
|
||||
"remove": "Verwijderen",
|
||||
"remove_assets_album_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit het album wilt verwijderen?",
|
||||
"remove_assets_shared_link_confirmation": "Weet je zeker dat je {count, plural, one {# asset} other {# assets}} uit deze gedeelde link wilt verwijderen?",
|
||||
@@ -1555,11 +1568,15 @@
|
||||
"reset_password": "Wachtwoord resetten",
|
||||
"reset_people_visibility": "Zichtbaarheid mensen resetten",
|
||||
"reset_pin_code": "Reset PIN code",
|
||||
"reset_sqlite": "Reset SQLite Database",
|
||||
"reset_sqlite_confirmation": "Ben je zeker dat je de SQLite database wilt resetten? Je zal moetenn uitloggen om de data opnieuw te synchroniseren.",
|
||||
"reset_sqlite_success": "De SQLite database is succesvol gereset",
|
||||
"reset_to_default": "Resetten naar standaard",
|
||||
"resolve_duplicates": "Duplicaten oplossen",
|
||||
"resolved_all_duplicates": "Alle duplicaten opgelost",
|
||||
"restore": "Herstellen",
|
||||
"restore_all": "Herstel alle",
|
||||
"restore_trash_action_prompt": "{count} teruggezet uit prullenbak",
|
||||
"restore_user": "Gebruiker herstellen",
|
||||
"restored_asset": "Asset hersteld",
|
||||
"resume": "Hervatten",
|
||||
@@ -1568,6 +1585,7 @@
|
||||
"role": "Rol",
|
||||
"role_editor": "Bewerker",
|
||||
"role_viewer": "Bekijker",
|
||||
"running": "Actief",
|
||||
"save": "Opslaan",
|
||||
"save_to_gallery": "Opslaan in galerij",
|
||||
"saved_api_key": "API-sleutel opgeslagen",
|
||||
@@ -1821,6 +1839,7 @@
|
||||
"storage_quota": "Opslaglimiet",
|
||||
"storage_usage": "{used} van {available} gebruikt",
|
||||
"submit": "Verzenden",
|
||||
"success": "Succes",
|
||||
"suggestions": "Suggesties",
|
||||
"sunrise_on_the_beach": "Zonsopkomst op het strand",
|
||||
"support": "Ondersteuning",
|
||||
@@ -1830,6 +1849,8 @@
|
||||
"sync": "Sync",
|
||||
"sync_albums": "Albums synchroniseren",
|
||||
"sync_albums_manual_subtitle": "Synchroniseer alle geüploade video’s en foto’s naar de geselecteerde back-up albums",
|
||||
"sync_local": "Lokaal synchroniseren",
|
||||
"sync_remote": "Op afstand synchroniseren",
|
||||
"sync_upload_album_setting_subtitle": "Maak en upload je foto's en video's naar de geselecteerde albums op Immich",
|
||||
"tag": "Tag",
|
||||
"tag_assets": "Assets taggen",
|
||||
@@ -1840,6 +1861,7 @@
|
||||
"tag_updated": "Tag bijgewerkt: {tag}",
|
||||
"tagged_assets": "{count, plural, one {# asset} other {# assets}} getagd",
|
||||
"tags": "Tags",
|
||||
"tap_to_run_job": "Klik om job te starten",
|
||||
"template": "Template",
|
||||
"theme": "Thema",
|
||||
"theme_selection": "Thema selectie",
|
||||
|
||||
47
i18n/ru.json
47
i18n/ru.json
@@ -228,7 +228,7 @@
|
||||
"password_settings_description": "Управление настройками входа по паролю",
|
||||
"paths_validated_successfully": "Все пути успешно прошли проверку",
|
||||
"person_cleanup_job": "Очистка персоны",
|
||||
"quota_size_gib": "Размер квоты (ГБ)",
|
||||
"quota_size_gib": "Размер квоты (GiB)",
|
||||
"refreshing_all_libraries": "Обновление всех библиотек",
|
||||
"registration": "Регистрация администратора",
|
||||
"registration_description": "Первый зарегистрированный пользователь будет назначен администратором. В дальнейшем этой учетной записи будет доступно создание дополнительных пользователей и управление сервером.",
|
||||
@@ -241,7 +241,7 @@
|
||||
"server_external_domain_settings": "Внешний домен",
|
||||
"server_external_domain_settings_description": "Домен для публичных ссылок, включая http(s)://",
|
||||
"server_public_users": "Публичные пользователи",
|
||||
"server_public_users_description": "Отображать всех пользователей (имена и email) для добавления в общие альбомы. Когда отключено, список пользователей будет доступен только администраторам.",
|
||||
"server_public_users_description": "Выводить список пользователей (имена и email) в общих альбомах. Когда отключено, список доступен только администраторам, пользователи смогут делиться только ссылкой.",
|
||||
"server_settings": "Настройки сервера",
|
||||
"server_settings_description": "Управление настройками сервера",
|
||||
"server_welcome_message": "Приветственное сообщение",
|
||||
@@ -407,7 +407,7 @@
|
||||
"album_remove_user": "Удалить пользователя?",
|
||||
"album_remove_user_confirmation": "Вы уверены, что хотите удалить пользователя {user}?",
|
||||
"album_search_not_found": "Не найдено альбомов по вашему запросу",
|
||||
"album_share_no_users": "Похоже, вы поделились этим альбомом со всеми пользователями или у вас нет пользователей, с которыми можно поделиться.",
|
||||
"album_share_no_users": "Нет доступных пользователей, с которыми можно поделиться альбомом.",
|
||||
"album_updated": "Альбом обновлён",
|
||||
"album_updated_setting_description": "Получать уведомление по электронной почте при добавлении новых ресурсов в общий альбом",
|
||||
"album_user_left": "Вы покинули {album}",
|
||||
@@ -433,8 +433,8 @@
|
||||
"all_videos": "Все видео",
|
||||
"allow_dark_mode": "Разрешить темный режим",
|
||||
"allow_edits": "Разрешить редактирование",
|
||||
"allow_public_user_to_download": "Разрешить скачивание публичным пользователям",
|
||||
"allow_public_user_to_upload": "Разрешить публичным пользователям загружать файлы",
|
||||
"allow_public_user_to_download": "Разрешить скачивание",
|
||||
"allow_public_user_to_upload": "Разрешить добавление файлов",
|
||||
"alt_text_qr_code": "QR-код",
|
||||
"anti_clockwise": "Против часовой",
|
||||
"api_key": "API ключ",
|
||||
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Резервное копирование",
|
||||
"backup_setting_subtitle": "Настройка активного и фонового резервного копирования",
|
||||
"backward": "Назад",
|
||||
"beta_sync": "Статус бета-синхронизации",
|
||||
"beta_sync_subtitle": "Управление новой системой синхронизации",
|
||||
"biometric_auth_enabled": "Биометрическая аутентификация включена",
|
||||
"biometric_locked_out": "Вам закрыт доступ к биометрической аутентификации",
|
||||
"biometric_no_options": "Биометрическая аутентификация недоступна",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Очистить кэш",
|
||||
"cache_settings_clear_cache_button_title": "Очищает кэш приложения. Это негативно повлияет на производительность, пока кэш не будет создан заново.",
|
||||
"cache_settings_duplicated_assets_clear_button": "ОЧИСТИТЬ",
|
||||
"cache_settings_duplicated_assets_subtitle": "Фото и видео, занесенные приложением в черный список",
|
||||
"cache_settings_duplicated_assets_subtitle": "Фото и видео, пропускаемые приложением",
|
||||
"cache_settings_duplicated_assets_title": "Дублирующиеся объекты ({count})",
|
||||
"cache_settings_statistics_album": "Миниатюры библиотеки",
|
||||
"cache_settings_statistics_full": "Полные изображения",
|
||||
@@ -616,7 +618,7 @@
|
||||
"change_date": "Изменить дату",
|
||||
"change_description": "Изменить описание",
|
||||
"change_display_order": "Изменить порядок отображения",
|
||||
"change_expiration_time": "Изменить время окончания",
|
||||
"change_expiration_time": "Изменить срок действия",
|
||||
"change_location": "Изменить местоположение",
|
||||
"change_name": "Изменить имя",
|
||||
"change_name_successfully": "Имя успешно изменено",
|
||||
@@ -692,7 +694,7 @@
|
||||
"copy_link": "Копировать ссылку",
|
||||
"copy_link_to_clipboard": "Скопировать ссылку в буфер обмена",
|
||||
"copy_password": "Скопировать пароль",
|
||||
"copy_to_clipboard": "Скопировать в буфер обмена",
|
||||
"copy_to_clipboard": "Скопировать настройки в буфер обмена",
|
||||
"country": "Страна",
|
||||
"cover": "Обложка",
|
||||
"covers": "Обложки",
|
||||
@@ -830,7 +832,7 @@
|
||||
"edit_people": "Редактировать людей",
|
||||
"edit_tag": "Изменить тег",
|
||||
"edit_title": "Редактировать Заголовок",
|
||||
"edit_user": "Редактирование пользователя",
|
||||
"edit_user": "Изменить пользователя",
|
||||
"edited": "Отредактировано",
|
||||
"editor": "Редактор",
|
||||
"editor_close_without_save_prompt": "Изменения не будут сохранены",
|
||||
@@ -994,7 +996,7 @@
|
||||
"experimental_settings_subtitle": "Используйте на свой страх и риск!",
|
||||
"experimental_settings_title": "Экспериментальные функции",
|
||||
"expire_after": "Истекает через",
|
||||
"expired": "Срок действия истек",
|
||||
"expired": "Срок действия истёк",
|
||||
"expires_date": "Срок действия до {date}",
|
||||
"explore": "Поиск",
|
||||
"explorer": "Проводник",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Включить тактильную отдачу",
|
||||
"haptic_feedback_title": "Тактильная отдача",
|
||||
"has_quota": "Квота",
|
||||
"hash_asset": "Хешированный объект",
|
||||
"hashed_assets": "Хешированные объекты",
|
||||
"hashing": "Хеширование",
|
||||
"header_settings_add_header_tip": "Добавить заголовок",
|
||||
"header_settings_field_validator_msg": "Значение не может быть пустым",
|
||||
"header_settings_header_name_input": "Имя заголовка",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Хост",
|
||||
"hour": "Час",
|
||||
"id": "ID",
|
||||
"idle": "В ожидании",
|
||||
"ignore_icloud_photos": "Пропускать файлы из iCloud",
|
||||
"ignore_icloud_photos_description": "Не загружать файлы в Immich, если они хранятся в iCloud",
|
||||
"image": "Изображения",
|
||||
@@ -1109,8 +1115,8 @@
|
||||
"include_archived": "Отображать архив",
|
||||
"include_shared_albums": "Включать общие альбомы",
|
||||
"include_shared_partner_assets": "Включать общие ресурсы партнера",
|
||||
"individual_share": "Персональный доступ",
|
||||
"individual_shares": "Индивидуальный доступ",
|
||||
"individual_share": "Индивидуальная подборка",
|
||||
"individual_shares": "Подборки",
|
||||
"info": "Информация",
|
||||
"interval": {
|
||||
"day_at_onepm": "Каждый день в 13:00",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Список",
|
||||
"loading": "Загрузка",
|
||||
"loading_search_results_failed": "Загрузка результатов поиска не удалась",
|
||||
"local": "На устройстве",
|
||||
"local_asset_cast_failed": "Невозможно транслировать объект, который ещё не загружен на сервер",
|
||||
"local_assets": "Объекты на устройстве",
|
||||
"local_network": "Локальная сеть",
|
||||
"local_network_sheet_info": "Приложение будет подключаться к серверу по этому адресу, когда устройство подключено к выбранной Wi-Fi сети",
|
||||
"location_permission": "Доступ к местоположению",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Нет результатов",
|
||||
"no_results_description": "Попробуйте использовать синоним или более общее ключевое слово",
|
||||
"no_shared_albums_message": "Создайте альбом для обмена фотографиями и видеозаписями с людьми в вашей сети",
|
||||
"no_uploads_in_progress": "Нет активных загрузок",
|
||||
"not_in_any_album": "Ни в одном альбоме",
|
||||
"not_selected": "Не выбрано",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Примечание: Чтобы применить метку хранилища к ранее загруженным ресурсам, запустите",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "оригинал",
|
||||
"other": "Другое",
|
||||
"other_devices": "Другие устройства",
|
||||
"other_entities": "Другие объекты",
|
||||
"other_variables": "Другие переменные",
|
||||
"owned": "Мои",
|
||||
"owner": "Владелец",
|
||||
@@ -1456,7 +1466,7 @@
|
||||
"profile_drawer_server_out_of_date_minor": "Версия сервера устарела. Пожалуйста, обновите его.",
|
||||
"profile_image_of_user": "Изображение профиля {user}",
|
||||
"profile_picture_set": "Фото профиля установлено.",
|
||||
"public_album": "Публичный альбом",
|
||||
"public_album": "Общий альбом",
|
||||
"public_share": "Публичный доступ",
|
||||
"purchase_account_info": "Поддержка",
|
||||
"purchase_activated_subtitle": "Благодарим вас за поддержку Immich и программного обеспечения с открытым исходным кодом",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Обновление лиц",
|
||||
"refreshing_metadata": "Обновление метаданных",
|
||||
"regenerating_thumbnails": "Восстановление миниатюр",
|
||||
"remote": "На сервере",
|
||||
"remote_assets": "Объекты на сервере",
|
||||
"remove": "Удалить",
|
||||
"remove_assets_album_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из альбома?",
|
||||
"remove_assets_shared_link_confirmation": "Вы действительно хотите удалить {count, plural, one {# объект} many {# объектов} other {# объекта}} из публичного доступа по этой ссылке?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "Сброс пароля",
|
||||
"reset_people_visibility": "Восстановить видимость людей",
|
||||
"reset_pin_code": "Сбросить PIN-код",
|
||||
"reset_sqlite": "Очистить базу данных SQLite",
|
||||
"reset_sqlite_confirmation": "Вы уверены, что хотите очистить базу данных SQLite? Вам потребуется выйти из системы и снова войти для повторной синхронизации данных.",
|
||||
"reset_sqlite_success": "База данных SQLite успешно очищена",
|
||||
"reset_to_default": "Восстановление значений по умолчанию",
|
||||
"resolve_duplicates": "Устранить дубликаты",
|
||||
"resolved_all_duplicates": "Все дубликаты устранены",
|
||||
"restore": "Восстановить",
|
||||
"restore_all": "Восстановить все",
|
||||
"restore_trash_action_prompt": "{count} восстановлено из корзины",
|
||||
"restore_user": "Восстановить пользователя",
|
||||
"restored_asset": "Восстановленный объект",
|
||||
"resume": "Продолжить",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "Роль",
|
||||
"role_editor": "Редактор",
|
||||
"role_viewer": "Зритель",
|
||||
"running": "Выполняется",
|
||||
"save": "Сохранить",
|
||||
"save_to_gallery": "Сохранить в галерею",
|
||||
"saved_api_key": "API ключ изменён",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Квота хранилища",
|
||||
"storage_usage": "{used} из {available}",
|
||||
"submit": "Подтвердить",
|
||||
"success": "Успешно",
|
||||
"suggestions": "Предложения",
|
||||
"sunrise_on_the_beach": "Восход солнца на пляже",
|
||||
"support": "Поддержка",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "Синхр.",
|
||||
"sync_albums": "Синхронизировать альбомы",
|
||||
"sync_albums_manual_subtitle": "Синхронизировать все загруженные фото и видео в выбранные альбомы для резервного копирования",
|
||||
"sync_local": "Синхронизировать локально",
|
||||
"sync_remote": "Синхронизация с сервером",
|
||||
"sync_upload_album_setting_subtitle": "Создавайте и загружайте свои фотографии и видео в выбранные альбомы на сервер Immich",
|
||||
"tag": "Тег",
|
||||
"tag_assets": "Добавить теги",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Тег {tag} изменен",
|
||||
"tagged_assets": "Тег назначен для {count, plural, one {# объекта} other {# объектов}}",
|
||||
"tags": "Теги",
|
||||
"tap_to_run_job": "Нажмите для запуска задачи",
|
||||
"template": "Шаблон",
|
||||
"theme": "Тема",
|
||||
"theme_selection": "Выбор темы",
|
||||
|
||||
117
i18n/sk.json
117
i18n/sk.json
@@ -45,14 +45,14 @@
|
||||
"backup_database_enable_description": "Povoliť výpisy z databázy",
|
||||
"backup_keep_last_amount": "Množstvo predchádzajúcich výpisov, ktoré sa majú zachovať",
|
||||
"backup_settings": "Nastavenia výpisu databázy",
|
||||
"backup_settings_description": "Správa nastavení výpisu databázy.",
|
||||
"backup_settings_description": "Spravovať nastavenia výpisu databázy.",
|
||||
"cleared_jobs": "Hotové úlohy pre: {job}",
|
||||
"config_set_by_file": "Konfigurácia je v súčasnosti nastavená konfiguračným súborom",
|
||||
"confirm_delete_library": "Naozaj chcete vymazať knižnicu {library}?",
|
||||
"confirm_delete_library_assets": "Ste si istí, že chcete vymazať túto knižnicu? Tato operácia nenávratne odstráni {count, plural, one {# zahrnutú položku} few {# zahrnuté položky} other {všetkých # zahrnutých položiek}} z aplikácie Immich. Súbory budú ponechané na disku.",
|
||||
"confirm_email_below": "Pre potvrdenie zadajte \"{email}\" nižšie",
|
||||
"confirm_reprocess_all_faces": "Naozaj chcete spracovať všetky tváre znova? Tento proces vymaže pomenovaných ľudí.",
|
||||
"confirm_user_password_reset": "Naozaj chcete resetovať heslo pre {user}?",
|
||||
"confirm_user_password_reset": "Naozaj chcete obnoviť heslo pre {user}?",
|
||||
"confirm_user_pin_code_reset": "Ste si istí, že chcete opätovne nastaviť PIN kód používateľa {user}?",
|
||||
"create_job": "Vytvoriť úlohu",
|
||||
"cron_expression": "Výraz cron",
|
||||
@@ -61,10 +61,10 @@
|
||||
"disable_login": "Zakázať prihlásenie",
|
||||
"duplicate_detection_job_description": "Spustite strojové učenie na položkách pre detekciu podobných obrázkov. Spolieha sa na inteligentné vyhľadávanie",
|
||||
"exclusion_pattern_description": "Vylučovacie vzory Vám umožňujú ignorovať súbory a priečinky pri skenovaní Vašej knižnice. Toto je užitočné, ak máte priečinky obsahujúce súbory, ktoré nechcete importovať, napríklad RAW súbory.",
|
||||
"external_library_management": "Správa Externej Knižnice",
|
||||
"external_library_management": "Spravovanie externej knižnice",
|
||||
"face_detection": "Detekcia tvárí",
|
||||
"face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Obnoviť“ (znovu) spracuje všetky položky. „Resetovať“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.",
|
||||
"facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Resetovať“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.",
|
||||
"face_detection_description": "Rozpoznajte tváre v položkách pomocou strojového učenia. V prípade videí sa berie do úvahy len náhľad. „Aktualizovať“ (znovu) spracuje všetky položky. „Obnoviť“ dodatočne vymaže všetky aktuálne údaje o tvárach. „Chýbajúce“ zaradí do poradia médiá, ktoré ešte neboli spracované. Zistené tváre sa po dokončení rozpoznávania tvárí zaradia do poradia na rozpoznávanie tvárí, pričom sa zoskupia do existujúcich alebo nových osôb.",
|
||||
"facial_recognition_job_description": "Zoskupte rozpoznané tváre do osôb. Tento krok sa vykoná po dokončení rozpoznávania tvárí. „Obnoviť“ (znovu) zoskupí všetky tváre. „Chýbajúce“ zaradí tváre, ktoré nemajú pridelenú osobu.",
|
||||
"failed_job_command": "Príkaz {command} zlyhal pre úlohu: {job}",
|
||||
"force_delete_user_warning": "VAROVANIE: Toto okamžite odstráni používateľa a všetky položky. Tento krok nie je možné vrátiť späť a súbory nebude možné obnoviť.",
|
||||
"image_format": "Formát",
|
||||
@@ -94,7 +94,7 @@
|
||||
"job_not_concurrency_safe": "Táto úloha nie je bezpečná pre súbežné spracovanie.",
|
||||
"job_settings": "Úlohy",
|
||||
"job_settings_description": "Spravovať súbežnosť úloh",
|
||||
"job_status": "Stav Úloh",
|
||||
"job_status": "Stav úloh",
|
||||
"jobs_delayed": "{jobCount, plural, one {# oneskorený} few {# oneskorené} other {# oneskorených}}",
|
||||
"jobs_failed": "{jobCount, plural, one {# neúspešný} few {# neúspešné} other {# neúspešných}}",
|
||||
"library_created": "Vytvorená knižnica: {library}",
|
||||
@@ -141,15 +141,15 @@
|
||||
"machine_learning_smart_search_enabled": "Povoliť inteligentné vyhľadávanie",
|
||||
"machine_learning_smart_search_enabled_description": "Ak je vypnuté, obrázky nebudú spracované pre inteligentné vyhľadávanie.",
|
||||
"machine_learning_url_description": "URL adresa servera strojového učenia. Ak je zadaných viacero adries URL, každý server bude testovaný postupne, kým jeden z nich neodpovie úspešne, v poradí od prvého po posledný. Servery, ktoré neodpovedajú, budú dočasne ignorované, kým nebudú opäť online.",
|
||||
"manage_concurrency": "Správa súbežnosti",
|
||||
"manage_concurrency": "Spravovať súbežnosť",
|
||||
"manage_log_settings": "Spravovať nastavenia ukladania záznamov",
|
||||
"map_dark_style": "Tmavý štýl",
|
||||
"map_enable_description": "Povoliť funkcie mapy",
|
||||
"map_gps_settings": "Mapa a nastavenia GPS",
|
||||
"map_gps_settings_description": "Spravujte nastavenia mapy a GPS (reverzné geokódovanie)",
|
||||
"map_gps_settings_description": "Spravovať nastavenia mapy a GPS (reverzné geokódovanie)",
|
||||
"map_implications": "Táto funkčnosť sa spolieha na externý servis spracovania mapových dlaždíc (tiles.immich.cloud)",
|
||||
"map_light_style": "Svetlý štýl",
|
||||
"map_manage_reverse_geocoding_settings": "Správa nastavení <link>Reverzného geokódovania</link>",
|
||||
"map_manage_reverse_geocoding_settings": "Spravovať nastavenia <link>reverzného geokódovania</link>",
|
||||
"map_reverse_geocoding": "Reverzné Geokódovanie",
|
||||
"map_reverse_geocoding_enable_description": "Povoliť reverzné geokódovanie",
|
||||
"map_reverse_geocoding_settings": "Reverzné geokódovanie",
|
||||
@@ -214,7 +214,7 @@
|
||||
"oauth_role_claim_description": "Automaticky udeliť prístup správcu na základe prítomnosti tejto požiadavky. Požiadavka môže mať príznak „user“ alebo „admin“.",
|
||||
"oauth_settings": "OAuth",
|
||||
"oauth_settings_description": "Spravovať nastavenia prihlásenia OAuth",
|
||||
"oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na <link>docs</link>.",
|
||||
"oauth_settings_more_details": "Pre viac informácii o tejto funkcii, prejdite na <link>dokumentáciu</link>.",
|
||||
"oauth_storage_label_claim": "Nárokovať Štítok úložiska",
|
||||
"oauth_storage_label_claim_description": "Automaticky nastaviť štítok úložiska používateľa na hodnotu tohto nároku.",
|
||||
"oauth_storage_quota_claim": "Deklarácia kvóty úložiska",
|
||||
@@ -234,7 +234,7 @@
|
||||
"registration_description": "Keďže ste prvým používateľom v systéme, budú vám pridelené správcovské práva na vykonávanie všetkých úloh a vrátane tvorby nových používateľov.",
|
||||
"require_password_change_on_login": "Vyžadovať od používateľa zmenu hesla pri prvom prihlásení",
|
||||
"reset_settings_to_default": "Obnoviť pôvodné nastavenia",
|
||||
"reset_settings_to_recent_saved": "Obnoviť naposledy uložené nastavenia",
|
||||
"reset_settings_to_recent_saved": "Nastavenia boli obnovené na posledné uložené nastavenia",
|
||||
"scanning_library": "Knižnica sa skenuje",
|
||||
"search_jobs": "Vyhľadať úlohy…",
|
||||
"send_welcome_email": "Odoslať uvítací e-mail",
|
||||
@@ -259,7 +259,7 @@
|
||||
"storage_template_migration_description": "Použite aktuálnu <link>{template}</link> na predtým nahrané médiá",
|
||||
"storage_template_migration_info": "Šablóna úložiska skonvertuje všetky prípony na malé písmená. Zmeny šablón sa budú vzťahovať iba na nové diela. Ak chcete šablónu spätne použiť na predtým nahrané médiá, spustite <link>{job}</link>.",
|
||||
"storage_template_migration_job": "Úloha migrácie šablóny úložiska",
|
||||
"storage_template_more_details": "Ďalšie podrobnosti o tejto funkcii nájdete v <template-link>Šablóna úložiska</template-link> a jej <implications-link>dôsledky</implications-link>",
|
||||
"storage_template_more_details": "Podrobnejšie informácie o tejto funkcii nájdete v časti <template-link>šablóna úložiska</template-link> a jej <implications-link>následky</implications-link>",
|
||||
"storage_template_onboarding_description_v2": "Ak je táto funkcia zapnutá, automaticky usporiada súbory na základe šablóny definovanej používateľom. Ďalšie informácie nájdete v <link>dokumentácii</link>.",
|
||||
"storage_template_path_length": "Približný limit dĺžky cesty: <b>{length, number}</b>/{limit, number}",
|
||||
"storage_template_settings": "Šablóna úložiska",
|
||||
@@ -278,9 +278,9 @@
|
||||
"template_settings_description": "Spravovanie vlastných šablón upozornení",
|
||||
"theme_custom_css_settings": "Vlastné CSS",
|
||||
"theme_custom_css_settings_description": "CSS štýly umožňujú prispôsobiť dizajn Immich.",
|
||||
"theme_settings": "Motívy",
|
||||
"theme_settings": "Nastavenia témy",
|
||||
"theme_settings_description": "Spravovať prispôsobenie webového rozhrania Immich",
|
||||
"thumbnail_generation_job": "Generovať Miniatúry",
|
||||
"thumbnail_generation_job": "Generovať miniatúry",
|
||||
"thumbnail_generation_job_description": "Generujte veľké, malé a rozmazané miniatúry pre každú položku, ako aj miniatúry pre každú osobu",
|
||||
"transcoding_acceleration_api": "API pre akceleráciu",
|
||||
"transcoding_acceleration_api_description": "Rozhranie API, ktoré bude spolupracovať s vaším zariadením s cieľom urýchliť prekódovanie. Toto nastavenie je „najlepšie úsilie“: pri zlyhaní sa vráti k softvérovému prekódovaniu. VP9 môže alebo nemusí fungovať v závislosti od vášho hardvéru.",
|
||||
@@ -300,7 +300,7 @@
|
||||
"transcoding_bitrate_description": "Videá presahujúce maximálnu bitovú rýchlosť alebo videá, ktoré nie sú v akceptovanom formáte",
|
||||
"transcoding_codecs_learn_more": "Ak sa chcete dozvedieť viac o tu použitej terminológii, pozrite si dokumentáciu FFmpeg pre <h264-link>kodek H.264</h264-link>, <hevc-link>kodek HEVC</hevc-link> a <vp9-link>VP9 kodek</vp9-link>.",
|
||||
"transcoding_constant_quality_mode": "Režim konštantnej kvality",
|
||||
"transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované spoločnosťou NVENC, pretože nepodporuje ICQ.",
|
||||
"transcoding_constant_quality_mode_description": "ICQ je lepšie ako CQP, ale niektoré zariadenia na hardvérovú akceleráciu tento režim nepodporujú. Nastavenie tejto možnosti uprednostní špecifikovaný režim pri použití kódovania založeného na kvalite. Ignorované funkciou NVENC, pretože nepodporuje ICQ.",
|
||||
"transcoding_constant_rate_factor": "Faktor konštantnej rýchlosti (-crf)",
|
||||
"transcoding_constant_rate_factor_description": "Úroveň kvality videa. Typické hodnoty sú 23 pre H.264, 28 pre HEVC, 31 pre VP9 a 35 pre AV1. Nižšie je lepšie, ale vytvára väčšie súbory.",
|
||||
"transcoding_disabled_description": "Neprekódovať žiadne videá, na niektorých klientoch môže prerušiť prehrávanie",
|
||||
@@ -321,13 +321,13 @@
|
||||
"transcoding_policy_description": "Nastavte, kedy bude video prekódované",
|
||||
"transcoding_preferred_hardware_device": "Uprednostňované hardvérové zariadenie",
|
||||
"transcoding_preferred_hardware_device_description": "Platí len pre VAAPI a QSV. Nastavuje uzol dri, ktorý sa používa na hardvérové prekódovanie.",
|
||||
"transcoding_preset_preset": "Prednastavenie (-preset)",
|
||||
"transcoding_preset_preset": "Predvoľba (-preset)",
|
||||
"transcoding_preset_preset_description": "Rýchlosť kompresie. Pomalšie predvoľby vytvárajú menšie súbory a zvyšujú kvalitu, keď sa zameriavajú na určitý dátový tok. VP9 ignoruje rýchlosti vyššie ako „rýchlejšie“.",
|
||||
"transcoding_reference_frames": "Referenčné snímky",
|
||||
"transcoding_reference_frames_description": "Počet snímok, na ktoré sa má odkazovať pri kompresii daného snímku. Vyššie hodnoty zvyšujú účinnosť kompresie, ale spomaľujú kódovanie. Hodnota 0 sa nastavuje automaticky.",
|
||||
"transcoding_required_description": "Iba videá, ktoré nie sú v prijatom formáte",
|
||||
"transcoding_settings": "Nastavenia prekódovania videa",
|
||||
"transcoding_settings_description": "Spravujte, ktoré videá sa majú prekódovať a ako ich spracovať",
|
||||
"transcoding_settings_description": "Spravovať, ktoré videá sa majú prekódovať a ako sa majú spracovať",
|
||||
"transcoding_target_resolution": "Cieľové rozlíšenie",
|
||||
"transcoding_target_resolution_description": "Vyššie rozlíšenia môžu zachovať viac detailov, ale ich kódovanie trvá dlhšie, majú väčšiu veľkosť súborov a môžu znížiť odozvu aplikácie.",
|
||||
"transcoding_temporal_aq": "Časové AQ",
|
||||
@@ -349,13 +349,13 @@
|
||||
"trash_settings_description": "Spravovať nastavenia koša",
|
||||
"user_cleanup_job": "Premazanie používateľov",
|
||||
"user_delete_delay": "Konto <b>{user}</b> a jeho médiá budú podľa plánu natrvalo vymazané za {delay, plural, one {# deň} few {# dni} other {# dní}}.",
|
||||
"user_delete_delay_settings": "Odstrániť oneskorenie",
|
||||
"user_delete_delay_settings_description": "Počet dní po odstránení na trvalé vymazanie účtu a médií používateľa. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.",
|
||||
"user_delete_delay_settings": "Oneskorenie vymazania",
|
||||
"user_delete_delay_settings_description": "Počet dní, po ktorých sa po odstránení používateľa natrvalo odstráni jeho účet a položky. Úloha odstraňovania používateľov sa spúšťa o polnoci, aby sa skontrolovali používatelia, ktorí sú pripravení na odstránenie. Zmeny tohto nastavenia sa vyhodnotia pri ďalšom spustení.",
|
||||
"user_delete_immediately": "Konto a médiá používateľa <b>{user}</b> budú zaradené do poradia na trvalé vymazanie <b>okamžite</b>.",
|
||||
"user_delete_immediately_checkbox": "Používateľ a médiá budú zaradení do frontu na okamžité vymazanie",
|
||||
"user_details": "Podrobnosti o používateľovi",
|
||||
"user_management": "Správa používateľov",
|
||||
"user_password_has_been_reset": "Heslo používateľa bolo resetované:",
|
||||
"user_management": "Spravovanie používateľov",
|
||||
"user_password_has_been_reset": "Heslo používateľa bolo obnovené:",
|
||||
"user_password_reset_description": "Poskytnite používateľovi dočasné heslo a informujte ho, že si ho bude musieť zmeniť pri ďalšom prihlásení.",
|
||||
"user_restore_description": "<b>{user}</b> bude účet obnovený.",
|
||||
"user_restore_scheduled_removal": "Obnoviť používateľa - plánované odstránenie na {date, date, long}",
|
||||
@@ -393,7 +393,7 @@
|
||||
"age_year_months": "Vek 1 rok, {months, plural, one {# month} other {# months}}",
|
||||
"age_years": "{years, plural, other {Vek #}}",
|
||||
"album_added": "Album bol pridaný",
|
||||
"album_added_notification_setting_description": "Obdržať upozornenie emailom, keď ste pridaní do zdieľaného albumu",
|
||||
"album_added_notification_setting_description": "Obdržať upozornenie emailom, keď vás pridajú do zdieľaného albumu",
|
||||
"album_cover_updated": "Obal albumu aktualizovaný",
|
||||
"album_delete_confirmation": "Ste si istý, že chcete odstrániť album {album}?",
|
||||
"album_delete_confirmation_description": "Ak je tento album zdieľaný, ostatní používatelia k nemu už nebudú mať prístup.",
|
||||
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Možnosti zálohovania",
|
||||
"backup_setting_subtitle": "Spravovať nastavenia odosielania na pozadí a v popredí",
|
||||
"backward": "Dozadu",
|
||||
"beta_sync": "Stav synchronizácie verzie Beta",
|
||||
"beta_sync_subtitle": "Spravovať nový systém synchronizácie",
|
||||
"biometric_auth_enabled": "Biometrické overovanie je povolené",
|
||||
"biometric_locked_out": "Ste vymknutí z biometrického overovania",
|
||||
"biometric_no_options": "Nie sú k dispozícii žiadne biometrické možnosti",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Vymazať vyrovnávaciu pamäť",
|
||||
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávaciu pamäť aplikácie. To výrazne ovplyvní výkon aplikácie, kým sa vyrovnávacia pamäť neobnoví.",
|
||||
"cache_settings_duplicated_assets_clear_button": "VYČISTIŤ",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotky a videá ktoré sú na čiernej listine zvolené aplikáciou",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotografie a videá, ktoré aplikácia ignoruje podľa zoznamu",
|
||||
"cache_settings_duplicated_assets_title": "Duplicitné položky ({count})",
|
||||
"cache_settings_statistics_album": "Knižnica náhľadov",
|
||||
"cache_settings_statistics_full": "Kompletné fotografie",
|
||||
@@ -628,7 +630,7 @@
|
||||
"change_password_form_password_mismatch": "Heslá sa nezhodujú",
|
||||
"change_password_form_reenter_new_password": "Znova zadajte nové heslo",
|
||||
"change_pin_code": "Zmeniť PIN kód",
|
||||
"change_your_password": "Zmeňte si heslo",
|
||||
"change_your_password": "Zmeniť heslo",
|
||||
"changed_visibility_successfully": "Viditeľnosť bola úspešne zmenená",
|
||||
"check_corrupt_asset_backup": "Skontrolovať, či nie sú poškodené zálohy položiek",
|
||||
"check_corrupt_asset_backup_button": "Vykonať kontrolu",
|
||||
@@ -723,7 +725,7 @@
|
||||
"custom_locale_description": "Formátovanie dátumov a čísel podľa jazyka a regiónu",
|
||||
"daily_title_text_date": "EEEE, d. MMMM",
|
||||
"daily_title_text_date_year": "EEEE, d. MMMM y",
|
||||
"dark": "Tmavý",
|
||||
"dark": "Tmavá",
|
||||
"dark_theme": "Prepnúť tmavú tému",
|
||||
"date_after": "Dátum po",
|
||||
"date_and_time": "Dátum a Čas",
|
||||
@@ -949,7 +951,7 @@
|
||||
"unable_to_remove_library": "Nie je možné odstrániť knižnicu",
|
||||
"unable_to_remove_partner": "Nie je možné odstrániť partnera",
|
||||
"unable_to_remove_reaction": "Nie je možné odstrániť reakciu",
|
||||
"unable_to_reset_password": "Nie je možné resetovať heslo",
|
||||
"unable_to_reset_password": "Nie je možné obnoviť heslo",
|
||||
"unable_to_reset_pin_code": "Nie je možné obnoviť PIN kód",
|
||||
"unable_to_resolve_duplicate": "Nie je možné vyriešiť duplikát",
|
||||
"unable_to_restore_assets": "Nie je možné obnoviť položky",
|
||||
@@ -987,7 +989,7 @@
|
||||
"exif_bottom_sheet_person_age_months": "Vek {months} mesiacov",
|
||||
"exif_bottom_sheet_person_age_year_months": "Vek 1 rok, {months} mesiacov",
|
||||
"exif_bottom_sheet_person_age_years": "Vek {years}",
|
||||
"exit_slideshow": "Opustiť Slideshow",
|
||||
"exit_slideshow": "Opustiť prezentáciu",
|
||||
"expand_all": "Rozbaliť všetko",
|
||||
"experimental_settings_new_asset_list_subtitle": "Prebiehajúca práca",
|
||||
"experimental_settings_new_asset_list_title": "Povolenie experimentálnej mriežky fotografií",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Povoliť hmatovú odozvu",
|
||||
"haptic_feedback_title": "Hmatová odozva",
|
||||
"has_quota": "Má kvótu",
|
||||
"hash_asset": "Hashovať položku",
|
||||
"hashed_assets": "Hashované položky",
|
||||
"hashing": "Hashovanie",
|
||||
"header_settings_add_header_tip": "Pridať hlavičku",
|
||||
"header_settings_field_validator_msg": "Hodnota nemôže byť prázdna",
|
||||
"header_settings_header_name_input": "Názov hlavičky",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Hostiteľ",
|
||||
"hour": "Hodina",
|
||||
"id": "ID",
|
||||
"idle": "Nečinné",
|
||||
"ignore_icloud_photos": "Ignorovať fotky v službe iCloud",
|
||||
"ignore_icloud_photos_description": "Fotografie uložené v službe iCloud sa nebudú odosielať na server Immich",
|
||||
"image": "Obrázok",
|
||||
@@ -1139,7 +1145,7 @@
|
||||
"language_no_results_subtitle": "Skúste upraviť hľadaný výraz",
|
||||
"language_no_results_title": "Neboli nájdené žiadne jazyky",
|
||||
"language_search_hint": "Vyhľadať jazyky...",
|
||||
"language_setting_description": "Vyberte preferovaný jazyk",
|
||||
"language_setting_description": "Vyberte požadovaný jazyk",
|
||||
"last_seen": "Naposledy videné",
|
||||
"latest_version": "Najnovšia verzia",
|
||||
"latitude": "Zemepisná šírka",
|
||||
@@ -1156,7 +1162,7 @@
|
||||
"library_page_sort_last_modified": "Naposledy upravené",
|
||||
"library_page_sort_title": "Podľa názvu albumu",
|
||||
"licenses": "Licencie",
|
||||
"light": "Svetlý",
|
||||
"light": "Svetlá",
|
||||
"like_deleted": "Like odstránený",
|
||||
"link_motion_video": "Pripojiť pohyblivé video",
|
||||
"link_options": "Možnosti odkazu",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Zoznam",
|
||||
"loading": "Načítavanie",
|
||||
"loading_search_results_failed": "Načítanie výsledkov hľadania sa nepodarilo",
|
||||
"local": "Lokálne",
|
||||
"local_asset_cast_failed": "Nie je možné preniesť médium, ktoré nie je nahrané na serveri",
|
||||
"local_assets": "Lokálne položky",
|
||||
"local_network": "Miestna sieť",
|
||||
"local_network_sheet_info": "Pri použití zadanej siete Wi-Fi sa aplikácia pripojí k serveru prostredníctvom tejto URL adresy",
|
||||
"location_permission": "Povolenie na určenie polohy",
|
||||
@@ -1277,7 +1285,7 @@
|
||||
"move_off_locked_folder": "Presunúť zo zamknutého priečinka",
|
||||
"move_to_lock_folder_action_prompt": "{count} pridaných do zamknutého priečinka",
|
||||
"move_to_locked_folder": "Presunúť do zamknutého priečinka",
|
||||
"move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odstránené zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku",
|
||||
"move_to_locked_folder_confirmation": "Tieto fotografie a videá budú odobrané zo všetkých albumov a bude ich možné zobraziť len v zamknutom priečinku",
|
||||
"moved_to_archive": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do archívu",
|
||||
"moved_to_library": "{count, plural, one {Presunutá # položka} few {Presunuté # položky} other {Presunutých # položiek}} do knižnice",
|
||||
"moved_to_trash": "Presunuté do koša",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Žiadne výsledky",
|
||||
"no_results_description": "Skúste synonymum alebo všeobecnejší výraz",
|
||||
"no_shared_albums_message": "Vytvorí album na zdieľanie fotiek a videí s ľuďmi vo vašej sieti",
|
||||
"no_uploads_in_progress": "Žiadne prebiehajúce nahrávanie",
|
||||
"not_in_any_album": "Nie je v žiadnom albume",
|
||||
"not_selected": "Nevybrané",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Poznámka: Ak chcete použiť Štítok úložiska na predtým nahrané médiá, spustite príkaz",
|
||||
@@ -1343,7 +1352,7 @@
|
||||
"onboarding": "Na palube",
|
||||
"onboarding_locale_description": "Vyberte požadovaný jazyk. Neskôr ho môžete zmeniť v nastaveniach.",
|
||||
"onboarding_privacy_description": "Nasledujúce (voliteľné) funkcie závisia na externých službách a kedykoľvek ich môžete vypnúť nastaveniach.",
|
||||
"onboarding_server_welcome_description": "Nastavme vašu inštanciu pomocou bežných nastavení.",
|
||||
"onboarding_server_welcome_description": "Poďme si nastaviť vašu inštanciu s niekoľkými bežnými nastaveniami.",
|
||||
"onboarding_theme_description": "Vyberte farbu témy pre váš server. Môžete to aj neskôr zmeniť vo vašich nastaveniach.",
|
||||
"onboarding_user_welcome_description": "Začnime!",
|
||||
"onboarding_welcome_user": "Vitaj, {user}",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "originál",
|
||||
"other": "Ostatné",
|
||||
"other_devices": "Ďalšie zariadenia",
|
||||
"other_entities": "Ostatné subjekty",
|
||||
"other_variables": "Ostatné premenné",
|
||||
"owned": "Vlastnené",
|
||||
"owner": "Vlastník",
|
||||
@@ -1434,9 +1444,9 @@
|
||||
"play_or_pause_video": "Pustí alebo pozastaví video",
|
||||
"please_auth_to_access": "Prosím, potvrďte overenie pre prístup",
|
||||
"port": "Port",
|
||||
"preferences_settings_subtitle": "Spravujte predvoľby aplikácie",
|
||||
"preferences_settings_subtitle": "Spravovať predvoľby aplikácie",
|
||||
"preferences_settings_title": "Predvoľby",
|
||||
"preset": "Prednastavenie",
|
||||
"preset": "Predvoľba",
|
||||
"preview": "Náhľad",
|
||||
"previous": "Predošlé",
|
||||
"previous_memory": "Predošlá spomienka",
|
||||
@@ -1508,7 +1518,7 @@
|
||||
"recently_added_page_title": "Nedávno pridané",
|
||||
"recently_taken": "Nedávno nasnímané",
|
||||
"recently_taken_page_title": "Nedávno zhotovené",
|
||||
"refresh": "Obnoviť",
|
||||
"refresh": "Aktualizovať",
|
||||
"refresh_encoded_videos": "Obnoviť enkódované videá",
|
||||
"refresh_faces": "Obnoviť tváre",
|
||||
"refresh_metadata": "Obnoviť metadáta",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Obnovovanie tvárí",
|
||||
"refreshing_metadata": "Obnovovanie metadát",
|
||||
"regenerating_thumbnails": "Pregenerovanie náhľadov",
|
||||
"remote": "Vzdialené",
|
||||
"remote_assets": "Vzdialené položky",
|
||||
"remove": "Odstrániť",
|
||||
"remove_assets_album_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z albumu?",
|
||||
"remove_assets_shared_link_confirmation": "Naozaj chcete odstrániť {count, plural, one {# položku} few {# položky} other {# položiek}} z tohoto zdieľaného odkazu?",
|
||||
@@ -1529,8 +1541,8 @@
|
||||
"remove_from_album_action_prompt": "{count} odstránené z albumu",
|
||||
"remove_from_favorites": "Odstrániť z obľúbených",
|
||||
"remove_from_lock_folder_action_prompt": "{count} odobrané zo zamknutého priečinka",
|
||||
"remove_from_locked_folder": "Odstrániť zo zamknutého priečinka",
|
||||
"remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá presunúť zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.",
|
||||
"remove_from_locked_folder": "Odobrať zo zamknutého priečinka",
|
||||
"remove_from_locked_folder_confirmation": "Ste si istí, že chcete tieto fotografie a videá odobrať zo zamknutého priečinka? Budú viditeľné vo vašej knižnici.",
|
||||
"remove_from_shared_link": "Odstrániť zo zdieľaného odkazu",
|
||||
"remove_memory": "Odstrániť spomienku",
|
||||
"remove_photo_from_memory": "Odstrániť fotografiu z tejto spomienky",
|
||||
@@ -1552,28 +1564,33 @@
|
||||
"require_password": "Vyžadovať heslo",
|
||||
"require_user_to_change_password_on_first_login": "Vyžadovať zmenu hesla po prvom prihlásení",
|
||||
"rescan": "Opätovné vyhľadávanie",
|
||||
"reset": "Resetovať",
|
||||
"reset": "Obnoviť",
|
||||
"reset_password": "Obnoviť heslo",
|
||||
"reset_people_visibility": "Resetovať viditeľnosť ľudí",
|
||||
"reset_people_visibility": "Obnoviť viditeľnosť ľudí",
|
||||
"reset_pin_code": "Obnoviť PIN kód",
|
||||
"reset_to_default": "Resetovať na predvolené",
|
||||
"reset_sqlite": "Obnoviť SQLite databázu",
|
||||
"reset_sqlite_confirmation": "Ste si istí, že chcete obnoviť SQLite databázu? Na opätovnú synchronizáciu údajov sa budete musieť odhlásiť a znova prihlásiť",
|
||||
"reset_sqlite_success": "Úspešné obnovenie databázy SQLite",
|
||||
"reset_to_default": "Obnoviť na predvolené",
|
||||
"resolve_duplicates": "Vyriešiť duplicity",
|
||||
"resolved_all_duplicates": "Vyriešené všetky duplicity",
|
||||
"restore": "Navrátiť",
|
||||
"restore_all": "Navrátit všetko",
|
||||
"restore_trash_action_prompt": "{count} obnovených z koša",
|
||||
"restore_user": "Navrátiť používateľa",
|
||||
"restored_asset": "Navrátené položky",
|
||||
"resume": "Pokračovať",
|
||||
"retry_upload": "Zopakovať nahrávanie",
|
||||
"review_duplicates": "Prezrieť duplikáty",
|
||||
"review_duplicates": "Preskúmať duplikáty",
|
||||
"role": "Rola",
|
||||
"role_editor": "Editor",
|
||||
"role_viewer": "Divák",
|
||||
"running": "Spustené",
|
||||
"save": "Uložiť",
|
||||
"save_to_gallery": "Uložiť do galérie",
|
||||
"saved_api_key": "Uložený API Kľúč",
|
||||
"saved_profile": "Uložený profil",
|
||||
"saved_settings": "Uložené nastavenia",
|
||||
"saved_settings": "Nastavenia boli uložené",
|
||||
"say_something": "Napíšte niečo",
|
||||
"scaffold_body_error_occurred": "Vyskytla sa chyba",
|
||||
"scan_all_libraries": "Preskenovať všetky knižnice",
|
||||
@@ -1585,7 +1602,7 @@
|
||||
"search_by_context": "Hľadať s kontextom",
|
||||
"search_by_description": "Vyhľadávanie podľa popisu",
|
||||
"search_by_description_example": "Pešia turistika v Sape",
|
||||
"search_by_filename": "Hľadať s názvom alebo príponou súboru",
|
||||
"search_by_filename": "Hľadať podľa názvu alebo prípony súboru",
|
||||
"search_by_filename_example": "napr. IMG_1234.JPG alebo PNG",
|
||||
"search_camera_make": "Hľadať značku fotoaparátu...",
|
||||
"search_camera_model": "Hľadať model fotoaparátu...",
|
||||
@@ -1809,7 +1826,7 @@
|
||||
"stacked_assets_count": "{count, plural, one {Zoskupená # položka} few {Zoskupené # položky} other {Zoskupených # položiek}}",
|
||||
"stacktrace": "Výpis zásobníku",
|
||||
"start": "Štart",
|
||||
"start_date": "Začiatočný dátum",
|
||||
"start_date": "Počiatočný dátum",
|
||||
"state": "Štát",
|
||||
"status": "Stav",
|
||||
"stop_casting": "Zastaviť prenos",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Úložný limit",
|
||||
"storage_usage": "Využitých {used} z {available}",
|
||||
"submit": "Odoslať",
|
||||
"success": "Úspech",
|
||||
"suggestions": "Návrhy",
|
||||
"sunrise_on_the_beach": "Východ slnka na pláži",
|
||||
"support": "Podpora",
|
||||
@@ -1831,9 +1849,11 @@
|
||||
"sync": "Synchronizovať",
|
||||
"sync_albums": "Synchronizovať albumy",
|
||||
"sync_albums_manual_subtitle": "Synchronizujte všetky nahrané videá a fotografie s vybranými záložnými albumami",
|
||||
"sync_local": "Synchronizovať lokálne",
|
||||
"sync_remote": "Synchronizovať vzdialené",
|
||||
"sync_upload_album_setting_subtitle": "Vytvárajte a nahrávajte svoje fotografie a videá do vybraných albumov na Immich",
|
||||
"tag": "Štítok",
|
||||
"tag_assets": "Označiť položky",
|
||||
"tag_assets": "Pridať štítky",
|
||||
"tag_created": "Vytvorený štítok: {tag}",
|
||||
"tag_feature_description": "Prehliadanie fotiek a videá zoskupených podľa tematických štítkov",
|
||||
"tag_not_found_question": "Neviete nájsť štítok? <link>Vytvorte nový štítok.</link>",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Upravený štítok: {tag}",
|
||||
"tagged_assets": "Štítok priradený {count, plural, one {# položke} other {# položkám}}",
|
||||
"tags": "Štítky",
|
||||
"tap_to_run_job": "Ťuknutím na položku spustíte úlohu",
|
||||
"template": "Šablóna",
|
||||
"theme": "Téma",
|
||||
"theme_selection": "Výber témy",
|
||||
@@ -1863,7 +1884,7 @@
|
||||
"time_based_memories": "Časové spomienky",
|
||||
"timeline": "Časová os",
|
||||
"timezone": "Časové pásmo",
|
||||
"to_archive": "Archív",
|
||||
"to_archive": "Archivovať",
|
||||
"to_change_password": "Zmeniť heslo",
|
||||
"to_favorite": "Obľúbiť",
|
||||
"to_login": "Prihlásiť",
|
||||
@@ -1898,7 +1919,7 @@
|
||||
"unfavorite_action_prompt": "{count} odstránené z Obľúbených",
|
||||
"unhide_person": "Odkryť osobu",
|
||||
"unknown": "Neznáme",
|
||||
"unknown_country": "Neznámy štát",
|
||||
"unknown_country": "Neznáma krajina",
|
||||
"unknown_year": "Neznámy rok",
|
||||
"unlimited": "Neobmedzené",
|
||||
"unlink_motion_video": "Odpojiť pohyblivé video",
|
||||
@@ -1986,7 +2007,7 @@
|
||||
"viewer_stack_use_as_main_asset": "Použiť ako hlavnú fotku",
|
||||
"viewer_unstack": "Odskupiť",
|
||||
"visibility_changed": "Viditeľnosť zmenená pre {count, plural, one {# osobu} few {# osoby} other {# osôb}}",
|
||||
"waiting": "Čaká",
|
||||
"waiting": "Čakajúce",
|
||||
"warning": "Varovanie",
|
||||
"week": "Týždeň",
|
||||
"welcome": "Vitajte",
|
||||
@@ -1996,7 +2017,7 @@
|
||||
"year": "Rok",
|
||||
"years_ago": "pred {years, plural, one {# rokom} other {# rokmi}}",
|
||||
"yes": "Áno",
|
||||
"you_dont_have_any_shared_links": "Nemáte žiadne zdielané linky",
|
||||
"you_dont_have_any_shared_links": "Nemáte žiadne zdielané odkazy",
|
||||
"your_wifi_name": "Váš názov siete Wi-Fi",
|
||||
"zoom_image": "Priblížiť obrázok"
|
||||
}
|
||||
|
||||
25
i18n/sl.json
25
i18n/sl.json
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "Možnosti varnostne kopije",
|
||||
"backup_setting_subtitle": "Upravljaj nastavitve nalaganja v ozadju in ospredju",
|
||||
"backward": "Nazaj",
|
||||
"beta_sync": "Stanje sinhronizacije beta različice",
|
||||
"beta_sync_subtitle": "Upravljanje novega sistema sinhronizacije",
|
||||
"biometric_auth_enabled": "Biometrična avtentikacija omogočena",
|
||||
"biometric_locked_out": "Biometrična avtentikacija vam je onemogočena",
|
||||
"biometric_no_options": "Biometrične možnosti niso na voljo",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "Počisti predpomnilnik",
|
||||
"cache_settings_clear_cache_button_title": "Počisti predpomnilnik aplikacije. To bo znatno vplivalo na delovanje aplikacije, dokler se predpomnilnik ne obnovi.",
|
||||
"cache_settings_duplicated_assets_clear_button": "POČISTI",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki jih je aplikacija uvrstila na črni seznam",
|
||||
"cache_settings_duplicated_assets_subtitle": "Fotografije in videoposnetki, ki so prezrti s strani aplikacije",
|
||||
"cache_settings_duplicated_assets_title": "Podvojena sredstva ({count})",
|
||||
"cache_settings_statistics_album": "Sličice knjižnice",
|
||||
"cache_settings_statistics_full": "Izvirne slike",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "Uporabi haptičen odziv",
|
||||
"haptic_feedback_title": "Haptičen odziv",
|
||||
"has_quota": "Ima kvoto",
|
||||
"hash_asset": "Zgoščeno sredstvo",
|
||||
"hashed_assets": "Zgoščena sredstva",
|
||||
"hashing": "Zgoščevanje",
|
||||
"header_settings_add_header_tip": "Dodaj glavo",
|
||||
"header_settings_field_validator_msg": "Vrednost ne sme biti prazna",
|
||||
"header_settings_header_name_input": "Ime glave",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "Gostitelj",
|
||||
"hour": "Ura",
|
||||
"id": "ID",
|
||||
"idle": "Nedejavnost",
|
||||
"ignore_icloud_photos": "Ignoriraj fotografije iCloud",
|
||||
"ignore_icloud_photos_description": "Fotografije, shranjene v iCloud, ne bodo naložene na strežnik Immich",
|
||||
"image": "Slika",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "Seznam",
|
||||
"loading": "Nalaganje",
|
||||
"loading_search_results_failed": "Nalaganje rezultatov iskanja ni uspelo",
|
||||
"local": "Lokalno",
|
||||
"local_asset_cast_failed": "Sredstva, ki niso naložena na strežnik, ni mogoče predvajati",
|
||||
"local_assets": "Lokalna sredstva",
|
||||
"local_network": "Lokalno omrežje",
|
||||
"local_network_sheet_info": "Aplikacija se bo povezala s strežnikom prek tega URL-ja, ko bo uporabljala navedeno omrežje Wi-Fi",
|
||||
"location_permission": "Dovoljenje za lokacijo",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "Brez rezultatov",
|
||||
"no_results_description": "Poskusite s sinonimom ali bolj splošno ključno besedo",
|
||||
"no_shared_albums_message": "Ustvarite album za skupno rabo fotografij in videoposnetkov z osebami v vašem omrežju",
|
||||
"no_uploads_in_progress": "Ni nalaganj v teku",
|
||||
"not_in_any_album": "Ni v nobenem albumu",
|
||||
"not_selected": "Ni izbrano",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "Opomba: Če želite oznako za shranjevanje uporabiti za predhodno naložena sredstva, zaženite",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "izvirnik",
|
||||
"other": "drugo",
|
||||
"other_devices": "Druge naprave",
|
||||
"other_entities": "Drugi subjekti",
|
||||
"other_variables": "Druge spremenljivke",
|
||||
"owned": "V lasti",
|
||||
"owner": "Lastnik",
|
||||
@@ -1390,7 +1400,7 @@
|
||||
"pause": "Premor",
|
||||
"pause_memories": "Zaustavi spomine",
|
||||
"paused": "Zaustavljeno",
|
||||
"pending": "V teku",
|
||||
"pending": "Čakanje",
|
||||
"people": "Osebe",
|
||||
"people_edits_count": "{count, plural, one {Urejena # oseba} two {Urejeni # osebi} few {Urejene # osebe} other {Urejenih # oseb}}",
|
||||
"people_feature_description": "Brskanje po fotografijah in videoposnetkih, razvrščenih po osebah",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "Osveževanje obrazev",
|
||||
"refreshing_metadata": "Osveževanje metapodatkov",
|
||||
"regenerating_thumbnails": "Obnavljanje sličic",
|
||||
"remote": "Oddaljeno",
|
||||
"remote_assets": "Oddaljena sredstva",
|
||||
"remove": "Odstrani",
|
||||
"remove_assets_album_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz albuma?",
|
||||
"remove_assets_shared_link_confirmation": "Ali ste prepričani, da želite odstraniti {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}} iz te skupne povezave?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "Ponastavi geslo",
|
||||
"reset_people_visibility": "Ponastavi vidnost ljudi",
|
||||
"reset_pin_code": "Ponastavi PIN kodo",
|
||||
"reset_sqlite": "Ponastavi bazo podatkov SQLite",
|
||||
"reset_sqlite_confirmation": "Ali ste prepričani, da želite ponastaviti bazo podatkov SQLite? Za ponovno sinhronizacijo podatkov se boste morali odjaviti in znova prijaviti",
|
||||
"reset_sqlite_success": "Uspešno ponastavljena baza podatkov SQLite",
|
||||
"reset_to_default": "Ponastavi na privzeto",
|
||||
"resolve_duplicates": "Razreši dvojnike",
|
||||
"resolved_all_duplicates": "Razrešeni vsi dvojniki",
|
||||
"restore": "Obnovi",
|
||||
"restore_all": "Obnovi vse",
|
||||
"restore_trash_action_prompt": "{count} obnovljenih iz koša",
|
||||
"restore_user": "Obnovi uporabnika",
|
||||
"restored_asset": "Obnovljeno sredstvo",
|
||||
"resume": "Nadaljuj",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "Vloga",
|
||||
"role_editor": "Urejevalec",
|
||||
"role_viewer": "Gledalec",
|
||||
"running": "V teku",
|
||||
"save": "Shrani",
|
||||
"save_to_gallery": "Shrani v galerijo",
|
||||
"saved_api_key": "Shranjen API ključ",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "Kvota shranjevanja",
|
||||
"storage_usage": "uporabljeno {used} od {available}",
|
||||
"submit": "Predloži",
|
||||
"success": "Uspeh",
|
||||
"suggestions": "Predlogi",
|
||||
"sunrise_on_the_beach": "Sončni vzhod na plaži",
|
||||
"support": "Podpora",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "Sinhronizacija",
|
||||
"sync_albums": "Sinhronizacija albumov",
|
||||
"sync_albums_manual_subtitle": "Sinhronizirajte vse naložene videoposnetke in fotografije v izbrane varnostne albume",
|
||||
"sync_local": "Sinhroniziraj lokalno",
|
||||
"sync_remote": "Sinhroniziraj oddaljeno",
|
||||
"sync_upload_album_setting_subtitle": "Ustvarite in naložite svoje fotografije in videoposnetke v izbrane albume na Immich",
|
||||
"tag": "Oznaka",
|
||||
"tag_assets": "Označi sredstva",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "Posodobljena oznaka: {tag}",
|
||||
"tagged_assets": "Označeno {count, plural, one {# sredstvo} two {# sredstvi} few {# sredstva} other {# sredstev}}",
|
||||
"tags": "Oznake",
|
||||
"tap_to_run_job": "Dotaknite se za zagon opravila",
|
||||
"template": "Predloga",
|
||||
"theme": "Tema",
|
||||
"theme_selection": "Izbira teme",
|
||||
|
||||
@@ -573,6 +573,8 @@
|
||||
"backup_options_page_title": "备份选项",
|
||||
"backup_setting_subtitle": "管理后台和前台上传设置",
|
||||
"backward": "后退",
|
||||
"beta_sync": "测试版同步状态",
|
||||
"beta_sync_subtitle": "管理新的同步系统",
|
||||
"biometric_auth_enabled": "生物识别身份验证已启用",
|
||||
"biometric_locked_out": "您被锁定在生物识别身份验证之外",
|
||||
"biometric_no_options": "没有可用的生物识别选项",
|
||||
@@ -590,7 +592,7 @@
|
||||
"cache_settings_clear_cache_button": "清除缓存",
|
||||
"cache_settings_clear_cache_button_title": "清除应用缓存。在重新生成缓存之前,将显著影响应用的性能。",
|
||||
"cache_settings_duplicated_assets_clear_button": "清除",
|
||||
"cache_settings_duplicated_assets_subtitle": "已加入黑名单的照片和视频",
|
||||
"cache_settings_duplicated_assets_subtitle": "应用程序忽略的照片和视频",
|
||||
"cache_settings_duplicated_assets_title": "重复项目({count})",
|
||||
"cache_settings_statistics_album": "图库缩略图",
|
||||
"cache_settings_statistics_full": "完整图像",
|
||||
@@ -1051,6 +1053,9 @@
|
||||
"haptic_feedback_switch": "启用振动反馈",
|
||||
"haptic_feedback_title": "振动反馈",
|
||||
"has_quota": "配额大小",
|
||||
"hash_asset": "哈希项目",
|
||||
"hashed_assets": "已哈希的项目",
|
||||
"hashing": "正在哈希",
|
||||
"header_settings_add_header_tip": "添加标头",
|
||||
"header_settings_field_validator_msg": "设置不可为空",
|
||||
"header_settings_header_name_input": "标头名称",
|
||||
@@ -1083,6 +1088,7 @@
|
||||
"host": "服务器",
|
||||
"hour": "时",
|
||||
"id": "ID",
|
||||
"idle": "空闲",
|
||||
"ignore_icloud_photos": "忽略 iCloud 照片",
|
||||
"ignore_icloud_photos_description": "存储在 iCloud 中的照片不会上传至 Immich 服务器",
|
||||
"image": "图片",
|
||||
@@ -1165,7 +1171,9 @@
|
||||
"list": "列表",
|
||||
"loading": "加载中",
|
||||
"loading_search_results_failed": "加载搜索结果失败",
|
||||
"local": "本地",
|
||||
"local_asset_cast_failed": "无法投放未上传至服务器的项目",
|
||||
"local_assets": "本地项目",
|
||||
"local_network": "本地网络",
|
||||
"local_network_sheet_info": "当使用指定的 Wi-Fi 网络时,应用程序将通过此 URL 访问服务器",
|
||||
"location_permission": "定位权限",
|
||||
@@ -1322,6 +1330,7 @@
|
||||
"no_results": "无结果",
|
||||
"no_results_description": "尝试使用同义词或更通用的关键词",
|
||||
"no_shared_albums_message": "创建相册以共享照片和视频",
|
||||
"no_uploads_in_progress": "没有正在进行的上传",
|
||||
"not_in_any_album": "不在任何相册中",
|
||||
"not_selected": "未选择",
|
||||
"note_apply_storage_label_to_previously_uploaded assets": "提示:要将存储标签应用于之前上传的项目,需要运行",
|
||||
@@ -1359,6 +1368,7 @@
|
||||
"original": "原图",
|
||||
"other": "其它",
|
||||
"other_devices": "其它设备",
|
||||
"other_entities": "其他实体",
|
||||
"other_variables": "其它变量",
|
||||
"owned": "我的",
|
||||
"owner": "所有者",
|
||||
@@ -1519,6 +1529,8 @@
|
||||
"refreshing_faces": "正在面部重新识别",
|
||||
"refreshing_metadata": "正在刷新元数据",
|
||||
"regenerating_thumbnails": "正在重新生成缩略图",
|
||||
"remote": "远程",
|
||||
"remote_assets": "远程项目",
|
||||
"remove": "移除",
|
||||
"remove_assets_album_confirmation": "确定要从图库中移除{count, plural, one {#个项目} other {#个项目}}?",
|
||||
"remove_assets_shared_link_confirmation": "确定要从共享链接中移除{count, plural, one {#个项目} other {#个项目}}?",
|
||||
@@ -1556,11 +1568,15 @@
|
||||
"reset_password": "重置密码",
|
||||
"reset_people_visibility": "重置人物识别",
|
||||
"reset_pin_code": "重置PIN码",
|
||||
"reset_sqlite": "重置 SQLite 数据库",
|
||||
"reset_sqlite_confirmation": "您确定要重置 SQLite 数据库吗?您需要注销并重新登录才能重新同步数据",
|
||||
"reset_sqlite_success": "已成功重置 SQLite 数据库",
|
||||
"reset_to_default": "恢复默认值",
|
||||
"resolve_duplicates": "处理重复项",
|
||||
"resolved_all_duplicates": "处理所有重复项",
|
||||
"restore": "恢复",
|
||||
"restore_all": "恢复全部",
|
||||
"restore_trash_action_prompt": "从回收站中恢复了 {count} 项",
|
||||
"restore_user": "恢复用户",
|
||||
"restored_asset": "已恢复项目",
|
||||
"resume": "继续",
|
||||
@@ -1569,6 +1585,7 @@
|
||||
"role": "选择用户权限",
|
||||
"role_editor": "可编辑",
|
||||
"role_viewer": "仅查看",
|
||||
"running": "正在运行",
|
||||
"save": "保存",
|
||||
"save_to_gallery": "保存到图库",
|
||||
"saved_api_key": "已保存的 API 密钥",
|
||||
@@ -1822,6 +1839,7 @@
|
||||
"storage_quota": "存储配额",
|
||||
"storage_usage": "已用:{used}/{available}",
|
||||
"submit": "提交",
|
||||
"success": "成功",
|
||||
"suggestions": "建议",
|
||||
"sunrise_on_the_beach": "海滩上的日出",
|
||||
"support": "支持",
|
||||
@@ -1831,6 +1849,8 @@
|
||||
"sync": "同步",
|
||||
"sync_albums": "同步相册",
|
||||
"sync_albums_manual_subtitle": "将所有上传的视频和照片同步到选定的备份相册",
|
||||
"sync_local": "同步本地",
|
||||
"sync_remote": "同步远程",
|
||||
"sync_upload_album_setting_subtitle": "创建照片和视频并上传到 Immich 上的选定相册中",
|
||||
"tag": "标签",
|
||||
"tag_assets": "标记项目",
|
||||
@@ -1841,6 +1861,7 @@
|
||||
"tag_updated": "已更新标签:{tag}",
|
||||
"tagged_assets": "{count, plural, one {# 个项目} other {# 个项目}}被加上标签",
|
||||
"tags": "标签",
|
||||
"tap_to_run_job": "点击运行作业",
|
||||
"template": "模版",
|
||||
"theme": "主题",
|
||||
"theme_selection": "主题选项",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"flutter": "3.32.6"
|
||||
"flutter": "3.32.8"
|
||||
}
|
||||
6
mobile/.vscode/settings.json
vendored
6
mobile/.vscode/settings.json
vendored
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"dart.flutterSdkPath": ".fvm/versions/3.32.6",
|
||||
"dart.flutterSdkPath": ".fvm/versions/3.32.8",
|
||||
"dart.lineLength": 120,
|
||||
"[dart]": {
|
||||
"editor.rulers": [120],
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/.fvm": true
|
||||
},
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
formatter:
|
||||
page_width: 120
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
|
||||
@@ -72,20 +72,6 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "default"
|
||||
productFlavors {
|
||||
production {
|
||||
dimension "default"
|
||||
applicationId "app.alextran.immich"
|
||||
}
|
||||
|
||||
beta {
|
||||
dimension "default"
|
||||
applicationId "app.alextran.immich.beta"
|
||||
versionNameSuffix "-BETA"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix '.debug'
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<application android:label="Immich Beta" tools:replace="android:label" />
|
||||
</manifest>
|
||||
@@ -88,7 +88,8 @@ data class PlatformAsset (
|
||||
val width: Long? = null,
|
||||
val height: Long? = null,
|
||||
val durationInSeconds: Long,
|
||||
val orientation: Long
|
||||
val orientation: Long,
|
||||
val isFavorite: Boolean
|
||||
)
|
||||
{
|
||||
companion object {
|
||||
@@ -102,7 +103,8 @@ data class PlatformAsset (
|
||||
val height = pigeonVar_list[6] as Long?
|
||||
val durationInSeconds = pigeonVar_list[7] as Long
|
||||
val orientation = pigeonVar_list[8] as Long
|
||||
return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation)
|
||||
val isFavorite = pigeonVar_list[9] as Boolean
|
||||
return PlatformAsset(id, name, type, createdAt, updatedAt, width, height, durationInSeconds, orientation, isFavorite)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
@@ -116,6 +118,7 @@ data class PlatformAsset (
|
||||
height,
|
||||
durationInSeconds,
|
||||
orientation,
|
||||
isFavorite,
|
||||
)
|
||||
}
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
||||
@@ -42,6 +42,7 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
MediaStore.MediaColumns.HEIGHT,
|
||||
MediaStore.MediaColumns.DURATION,
|
||||
MediaStore.MediaColumns.ORIENTATION,
|
||||
MediaStore.MediaColumns.IS_FAVORITE,
|
||||
)
|
||||
|
||||
const val HASH_BUFFER_SIZE = 2 * 1024 * 1024
|
||||
@@ -77,6 +78,7 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
val durationColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.DURATION)
|
||||
val orientationColumn =
|
||||
c.getColumnIndexOrThrow(MediaStore.MediaColumns.ORIENTATION)
|
||||
val favoriteColumn = c.getColumnIndexOrThrow(MediaStore.MediaColumns.IS_FAVORITE)
|
||||
|
||||
while (c.moveToNext()) {
|
||||
val id = c.getLong(idColumn).toString()
|
||||
@@ -105,6 +107,7 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
else c.getLong(durationColumn) / 1000
|
||||
val bucketId = c.getString(bucketIdColumn)
|
||||
val orientation = c.getInt(orientationColumn)
|
||||
val isFavorite = c.getInt(favoriteColumn) != 0;
|
||||
|
||||
val asset = PlatformAsset(
|
||||
id,
|
||||
@@ -116,6 +119,7 @@ open class NativeSyncApiImplBase(context: Context) {
|
||||
height,
|
||||
duration,
|
||||
orientation.toLong(),
|
||||
isFavorite,
|
||||
)
|
||||
yield(AssetResult.ValidAsset(asset, bucketId))
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class ImageDownloadWorker(
|
||||
.build()
|
||||
|
||||
manager.enqueueUniqueWork(
|
||||
"$uniqueWorkName-$appWidgetId",
|
||||
"$uniqueWorkName-$appWidgetId-singleShot",
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
workRequest
|
||||
)
|
||||
|
||||
@@ -28,19 +28,21 @@ class MemoryReceiver : GlanceAppWidgetReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false)
|
||||
val provider = ComponentName(context, MemoryReceiver::class.java)
|
||||
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
|
||||
|
||||
// Launch coroutine to setup a single shot if the app requested the update
|
||||
if (fromMainApp) {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
val provider = ComponentName(context, MemoryReceiver::class.java)
|
||||
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
|
||||
|
||||
glanceIds.forEach { widgetID ->
|
||||
ImageDownloadWorker.singleShot(context, widgetID, WidgetType.MEMORIES)
|
||||
}
|
||||
glanceIds.forEach { widgetID ->
|
||||
ImageDownloadWorker.singleShot(context, widgetID, WidgetType.MEMORIES)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the periodic jobs are running
|
||||
glanceIds.forEach { widgetID ->
|
||||
ImageDownloadWorker.enqueuePeriodic(context, widgetID, WidgetType.MEMORIES)
|
||||
}
|
||||
|
||||
super.onReceive(context, intent)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,19 +28,21 @@ class RandomReceiver : GlanceAppWidgetReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val fromMainApp = intent.getBooleanExtra(HomeWidgetPlugin.TRIGGERED_FROM_HOME_WIDGET, false)
|
||||
val provider = ComponentName(context, RandomReceiver::class.java)
|
||||
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
|
||||
|
||||
// Launch coroutine to setup a single shot if the app requested the update
|
||||
if (fromMainApp) {
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
val provider = ComponentName(context, RandomReceiver::class.java)
|
||||
val glanceIds = AppWidgetManager.getInstance(context).getAppWidgetIds(provider)
|
||||
|
||||
glanceIds.forEach { widgetID ->
|
||||
ImageDownloadWorker.singleShot(context, widgetID, WidgetType.RANDOM)
|
||||
}
|
||||
glanceIds.forEach { widgetID ->
|
||||
ImageDownloadWorker.singleShot(context, widgetID, WidgetType.RANDOM)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the periodic jobs are running
|
||||
glanceIds.forEach { widgetID ->
|
||||
ImageDownloadWorker.enqueuePeriodic(context, widgetID, WidgetType.RANDOM)
|
||||
}
|
||||
|
||||
super.onReceive(context, intent)
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 204,
|
||||
"android.injected.version.name" => "1.135.3",
|
||||
"android.injected.version.code" => 205,
|
||||
"android.injected.version.name" => "1.136.0",
|
||||
}
|
||||
)
|
||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||
|
||||
2
mobile/drift_schemas/main/drift_schema_v4.json
generated
2
mobile/drift_schemas/main/drift_schema_v4.json
generated
File diff suppressed because one or more lines are too long
1
mobile/drift_schemas/main/drift_schema_v5.json
generated
Normal file
1
mobile/drift_schemas/main/drift_schema_v5.json
generated
Normal file
File diff suppressed because one or more lines are too long
@@ -139,6 +139,7 @@ struct PlatformAsset: Hashable {
|
||||
var height: Int64? = nil
|
||||
var durationInSeconds: Int64
|
||||
var orientation: Int64
|
||||
var isFavorite: Bool
|
||||
|
||||
|
||||
// swift-format-ignore: AlwaysUseLowerCamelCase
|
||||
@@ -152,6 +153,7 @@ struct PlatformAsset: Hashable {
|
||||
let height: Int64? = nilOrValue(pigeonVar_list[6])
|
||||
let durationInSeconds = pigeonVar_list[7] as! Int64
|
||||
let orientation = pigeonVar_list[8] as! Int64
|
||||
let isFavorite = pigeonVar_list[9] as! Bool
|
||||
|
||||
return PlatformAsset(
|
||||
id: id,
|
||||
@@ -162,7 +164,8 @@ struct PlatformAsset: Hashable {
|
||||
width: width,
|
||||
height: height,
|
||||
durationInSeconds: durationInSeconds,
|
||||
orientation: orientation
|
||||
orientation: orientation,
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
func toList() -> [Any?] {
|
||||
@@ -176,6 +179,7 @@ struct PlatformAsset: Hashable {
|
||||
height,
|
||||
durationInSeconds,
|
||||
orientation,
|
||||
isFavorite,
|
||||
]
|
||||
}
|
||||
static func == (lhs: PlatformAsset, rhs: PlatformAsset) -> Bool {
|
||||
|
||||
@@ -28,7 +28,8 @@ extension PHAsset {
|
||||
width: Int64(pixelWidth),
|
||||
height: Int64(pixelHeight),
|
||||
durationInSeconds: Int64(duration),
|
||||
orientation: 0
|
||||
orientation: 0,
|
||||
isFavorite: isFavorite
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -171,7 +172,8 @@ class NativeSyncApiImpl: NativeSyncApi {
|
||||
name: "",
|
||||
type: 0,
|
||||
durationInSeconds: 0,
|
||||
orientation: 0
|
||||
orientation: 0,
|
||||
isFavorite: false
|
||||
)
|
||||
if (updatedAssets.contains(AssetWrapper(with: predicate))) {
|
||||
continue
|
||||
|
||||
@@ -22,7 +22,7 @@ platform :ios do
|
||||
path: "./Runner.xcodeproj",
|
||||
)
|
||||
increment_version_number(
|
||||
version_number: "1.135.3"
|
||||
version_number: "1.136.0"
|
||||
)
|
||||
increment_build_number(
|
||||
build_number: latest_testflight_build_number + 1,
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum ImmichColorPreset {
|
||||
indigo,
|
||||
deepPurple,
|
||||
pink,
|
||||
red,
|
||||
orange,
|
||||
yellow,
|
||||
lime,
|
||||
green,
|
||||
cyan,
|
||||
slateGray
|
||||
}
|
||||
enum ImmichColorPreset { indigo, deepPurple, pink, red, orange, yellow, lime, green, cyan, slateGray }
|
||||
|
||||
const ImmichColorPreset defaultColorPreset = ImmichColorPreset.indigo;
|
||||
const String defaultColorPresetName = "indigo";
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
enum SortOrder {
|
||||
asc,
|
||||
desc,
|
||||
}
|
||||
enum SortOrder { asc, desc }
|
||||
|
||||
enum TextSearchType {
|
||||
context,
|
||||
filename,
|
||||
description,
|
||||
}
|
||||
enum TextSearchType { context, filename, description }
|
||||
|
||||
enum AssetVisibilityEnum { timeline, hidden, archive, locked }
|
||||
|
||||
|
||||
@@ -2,511 +2,49 @@ import 'package:flutter/material.dart';
|
||||
|
||||
const List<ColorFilter> filters = [
|
||||
//Original
|
||||
ColorFilter.matrix([
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Vintage
|
||||
ColorFilter.matrix([
|
||||
0.8,
|
||||
0.1,
|
||||
0.1,
|
||||
0,
|
||||
20,
|
||||
0.1,
|
||||
0.8,
|
||||
0.1,
|
||||
0,
|
||||
20,
|
||||
0.1,
|
||||
0.1,
|
||||
0.8,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.8, 0.1, 0.1, 0, 20, 0.1, 0.8, 0.1, 0, 20, 0.1, 0.1, 0.8, 0, 20, 0, 0, 0, 1, 0]),
|
||||
//Mood
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0.1,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
0.1,
|
||||
1,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
0.1,
|
||||
0.1,
|
||||
1,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.2, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 10, 0, 0, 0, 1, 0]),
|
||||
//Crisp
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Cool
|
||||
ColorFilter.matrix([
|
||||
0.9,
|
||||
0,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.9, 0, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Blush
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
0.1,
|
||||
1,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
0.1,
|
||||
0.1,
|
||||
1,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.1, 0.1, 0.1, 0, 10, 0.1, 1, 0.1, 0, 10, 0.1, 0.1, 1, 0, 5, 0, 0, 0, 1, 0]),
|
||||
//Sunkissed
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0,
|
||||
0.1,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
1.1,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
0.9,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.3, 0, 0.1, 0, 15, 0, 1.1, 0.1, 0, 10, 0, 0, 0.9, 0, 5, 0, 0, 0, 1, 0]),
|
||||
//Fresh
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
0,
|
||||
1.1,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.2, 0, 0, 0, 20, 0, 1.2, 0, 0, 20, 0, 0, 1.1, 0, 20, 0, 0, 0, 1, 0]),
|
||||
//Classic
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0,
|
||||
-0.1,
|
||||
0,
|
||||
10,
|
||||
-0.1,
|
||||
1.1,
|
||||
0.1,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
-0.1,
|
||||
1.1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.1, 0, -0.1, 0, 10, -0.1, 1.1, 0.1, 0, 5, 0, -0.1, 1.1, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Lomo-ish
|
||||
ColorFilter.matrix([
|
||||
1.5,
|
||||
0,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.45,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0,
|
||||
1.3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.5, 0, 0.1, 0, 0, 0, 1.45, 0, 0, 0, 0.1, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Nashville
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0.15,
|
||||
-0.15,
|
||||
0,
|
||||
15,
|
||||
0.1,
|
||||
1.1,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
-0.05,
|
||||
0.2,
|
||||
1.25,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.2, 0.15, -0.15, 0, 15, 0.1, 1.1, 0.1, 0, 10, -0.05, 0.2, 1.25, 0, 5, 0, 0, 0, 1, 0]),
|
||||
//Valencia
|
||||
ColorFilter.matrix([
|
||||
1.15,
|
||||
0.1,
|
||||
0.1,
|
||||
0,
|
||||
20,
|
||||
0.1,
|
||||
1.1,
|
||||
0,
|
||||
0,
|
||||
10,
|
||||
0.1,
|
||||
0.1,
|
||||
1.2,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.15, 0.1, 0.1, 0, 20, 0.1, 1.1, 0, 0, 10, 0.1, 0.1, 1.2, 0, 5, 0, 0, 0, 1, 0]),
|
||||
//Clarendon
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
1.25,
|
||||
0,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
1.3,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.2, 0, 0, 0, 10, 0, 1.25, 0, 0, 10, 0, 0, 1.3, 0, 10, 0, 0, 0, 1, 0]),
|
||||
//Moon
|
||||
ColorFilter.matrix([
|
||||
0.33,
|
||||
0.33,
|
||||
0.33,
|
||||
0,
|
||||
0,
|
||||
0.33,
|
||||
0.33,
|
||||
0.33,
|
||||
0,
|
||||
0,
|
||||
0.33,
|
||||
0.33,
|
||||
0.33,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0.33, 0.33, 0.33, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Willow
|
||||
ColorFilter.matrix([
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0,
|
||||
20,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0,
|
||||
20,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0.5, 0.5, 0.5, 0, 20, 0, 0, 0, 1, 0]),
|
||||
//Kodak
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0.1,
|
||||
-0.1,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
1.25,
|
||||
0.1,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
-0.1,
|
||||
1.1,
|
||||
0,
|
||||
5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.3, 0.1, -0.1, 0, 10, 0, 1.25, 0.1, 0, 10, 0, -0.1, 1.1, 0, 5, 0, 0, 0, 1, 0]),
|
||||
//Frost
|
||||
ColorFilter.matrix([
|
||||
0.8,
|
||||
0.2,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.2,
|
||||
1.1,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0.1,
|
||||
1.2,
|
||||
0,
|
||||
10,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.8, 0.2, 0.1, 0, 0, 0.2, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.2, 0, 10, 0, 0, 0, 1, 0]),
|
||||
//Night Vision
|
||||
ColorFilter.matrix([
|
||||
0.1,
|
||||
0.95,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
1.5,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.2,
|
||||
0.7,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.1, 0.95, 0.2, 0, 0, 0.1, 1.5, 0.1, 0, 0, 0.2, 0.7, 0, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Sunset
|
||||
ColorFilter.matrix([
|
||||
1.5,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0.9,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
-0.1,
|
||||
-0.2,
|
||||
1.3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.5, 0.2, 0, 0, 0, 0.1, 0.9, 0.1, 0, 0, -0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Noir
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
-0.3,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
-0.1,
|
||||
1.2,
|
||||
-0.1,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
-0.2,
|
||||
1.3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.3, -0.3, 0.1, 0, 0, -0.1, 1.2, -0.1, 0, 0, 0.1, -0.2, 1.3, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Dreamy
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
1.1,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0.1,
|
||||
1.1,
|
||||
0,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.1, 0.1, 0.1, 0, 0, 0.1, 1.1, 0.1, 0, 0, 0.1, 0.1, 1.1, 0, 15, 0, 0, 0, 1, 0]),
|
||||
//Sepia
|
||||
ColorFilter.matrix([
|
||||
0.393,
|
||||
0.769,
|
||||
0.189,
|
||||
0,
|
||||
0,
|
||||
0.349,
|
||||
0.686,
|
||||
0.168,
|
||||
0,
|
||||
0,
|
||||
0.272,
|
||||
0.534,
|
||||
0.131,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Radium
|
||||
ColorFilter.matrix([
|
||||
1.438,
|
||||
@@ -554,212 +92,23 @@ const List<ColorFilter> filters = [
|
||||
0,
|
||||
]),
|
||||
//Purple Haze
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.2,
|
||||
0,
|
||||
1.3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.3, 0, 1.2, 0, 0, 0, 1.1, 0, 0, 0, 0.2, 0, 1.3, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Lemonade
|
||||
ColorFilter.matrix([
|
||||
1.2,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.1,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0,
|
||||
0.7,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.2, 0.1, 0, 0, 0, 0, 1.1, 0.2, 0, 0, 0.1, 0, 0.7, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Caramel
|
||||
ColorFilter.matrix([
|
||||
1.6,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
1.3,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0.9,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.6, 0.2, 0, 0, 0, 0.1, 1.3, 0.1, 0, 0, 0, 0.1, 0.9, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Peachy
|
||||
ColorFilter.matrix([
|
||||
1.3,
|
||||
0.5,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.2,
|
||||
1.1,
|
||||
0.3,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0.1,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.3, 0.5, 0, 0, 0, 0.2, 1.1, 0.3, 0, 0, 0.1, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Neon
|
||||
ColorFilter.matrix([
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Cold Morning
|
||||
ColorFilter.matrix([
|
||||
0.9,
|
||||
0.1,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0.1,
|
||||
0,
|
||||
0,
|
||||
0.1,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.9, 0.1, 0.2, 0, 0, 0, 1, 0.1, 0, 0, 0.1, 0, 1.2, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Lush
|
||||
ColorFilter.matrix([
|
||||
0.9,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1.1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.9, 0.2, 0, 0, 0, 0, 1.2, 0, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Urban Neon
|
||||
ColorFilter.matrix([
|
||||
1.1,
|
||||
0,
|
||||
0.3,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.9,
|
||||
0.3,
|
||||
0,
|
||||
0,
|
||||
0.3,
|
||||
0.1,
|
||||
1.2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([1.1, 0, 0.3, 0, 0, 0, 0.9, 0.3, 0, 0, 0.3, 0.1, 1.2, 0, 0, 0, 0, 0, 1, 0]),
|
||||
//Monochrome
|
||||
ColorFilter.matrix([
|
||||
0.6,
|
||||
0.2,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0.2,
|
||||
0.6,
|
||||
0.2,
|
||||
0,
|
||||
0,
|
||||
0.2,
|
||||
0.2,
|
||||
0.7,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]),
|
||||
ColorFilter.matrix([0.6, 0.2, 0.2, 0, 0, 0.2, 0.6, 0.2, 0, 0, 0.2, 0.2, 0.7, 0, 0, 0, 0, 0, 1, 0]),
|
||||
];
|
||||
|
||||
const List<String> filterNames = [
|
||||
|
||||
@@ -7,10 +7,8 @@ const Map<String, Locale> locales = {
|
||||
'Arabic (ar)': Locale('ar'),
|
||||
'Bulgarian (bg)': Locale('bg'),
|
||||
'Catalan (ca)': Locale('ca'),
|
||||
'Chinese Simplified (zh_CN)':
|
||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
||||
'Chinese Traditional (zh_TW)':
|
||||
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
||||
'Chinese Simplified (zh_CN)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'SIMPLIFIED'),
|
||||
'Chinese Traditional (zh_TW)': Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
||||
'Croatian (hr)': Locale('hr'),
|
||||
'Czech (cs)': Locale('cs'),
|
||||
'Danish (da)': Locale('da'),
|
||||
@@ -37,10 +35,8 @@ const Map<String, Locale> locales = {
|
||||
'Portuguese (pt)': Locale('pt'),
|
||||
'Romanian (ro)': Locale('ro'),
|
||||
'Russian (ru)': Locale('ru'),
|
||||
'Serbian Cyrillic (sr_Cyrl)':
|
||||
Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'),
|
||||
'Serbian Latin (sr_Latn)':
|
||||
Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'),
|
||||
'Serbian Cyrillic (sr_Cyrl)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Cyrl'),
|
||||
'Serbian Latin (sr_Latn)': Locale.fromSubtags(languageCode: 'sr', scriptCode: 'Latn'),
|
||||
'Slovak (sk)': Locale('sk'),
|
||||
'Slovenian (sl)': Locale('sl'),
|
||||
'Spanish (es)': Locale('es'),
|
||||
@@ -55,7 +51,4 @@ const Map<String, Locale> locales = {
|
||||
|
||||
const String translationsPath = 'assets/i18n';
|
||||
|
||||
const List<Locale> localesNotSupportedByOverpass = [
|
||||
Locale('el', 'GR'),
|
||||
Locale('sr', 'Cyrl'),
|
||||
];
|
||||
const List<Locale> localesNotSupportedByOverpass = [Locale('el', 'GR'), Locale('sr', 'Cyrl')];
|
||||
|
||||
@@ -9,11 +9,7 @@ enum AssetType {
|
||||
audio,
|
||||
}
|
||||
|
||||
enum AssetState {
|
||||
local,
|
||||
remote,
|
||||
merged,
|
||||
}
|
||||
enum AssetState { local, remote, merged }
|
||||
|
||||
sealed class BaseAsset {
|
||||
final String name;
|
||||
@@ -53,10 +49,8 @@ sealed class BaseAsset {
|
||||
return const Duration();
|
||||
}
|
||||
|
||||
bool get hasRemote =>
|
||||
storage == AssetState.remote || storage == AssetState.merged;
|
||||
bool get hasLocal =>
|
||||
storage == AssetState.local || storage == AssetState.merged;
|
||||
bool get hasRemote => storage == AssetState.remote || storage == AssetState.merged;
|
||||
bool get hasLocal => storage == AssetState.local || storage == AssetState.merged;
|
||||
bool get isLocalOnly => storage == AssetState.local;
|
||||
bool get isRemoteOnly => storage == AssetState.remote;
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ class LocalAsset extends BaseAsset {
|
||||
});
|
||||
|
||||
@override
|
||||
AssetState get storage =>
|
||||
remoteId == null ? AssetState.local : AssetState.merged;
|
||||
AssetState get storage => remoteId == null ? AssetState.local : AssetState.merged;
|
||||
|
||||
@override
|
||||
String get heroTag => '${id}_${remoteId ?? checksum}';
|
||||
@@ -54,8 +53,7 @@ class LocalAsset extends BaseAsset {
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode;
|
||||
int get hashCode => super.hashCode ^ id.hashCode ^ remoteId.hashCode ^ orientation.hashCode;
|
||||
|
||||
LocalAsset copyWith({
|
||||
String? id,
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
part of 'base_asset.model.dart';
|
||||
|
||||
enum AssetVisibility {
|
||||
timeline,
|
||||
hidden,
|
||||
archive,
|
||||
locked,
|
||||
}
|
||||
enum AssetVisibility { timeline, hidden, archive, locked }
|
||||
|
||||
// Model for an asset stored in the server
|
||||
class RemoteAsset extends BaseAsset {
|
||||
@@ -15,7 +10,6 @@ class RemoteAsset extends BaseAsset {
|
||||
final AssetVisibility visibility;
|
||||
final String ownerId;
|
||||
final String? stackId;
|
||||
final int stackCount;
|
||||
|
||||
const RemoteAsset({
|
||||
required this.id,
|
||||
@@ -34,12 +28,10 @@ class RemoteAsset extends BaseAsset {
|
||||
this.visibility = AssetVisibility.timeline,
|
||||
super.livePhotoVideoId,
|
||||
this.stackId,
|
||||
this.stackCount = 0,
|
||||
});
|
||||
|
||||
@override
|
||||
AssetState get storage =>
|
||||
localId == null ? AssetState.remote : AssetState.merged;
|
||||
AssetState get storage => localId == null ? AssetState.remote : AssetState.merged;
|
||||
|
||||
@override
|
||||
String get heroTag => '${localId ?? checksum}_$id';
|
||||
@@ -61,7 +53,6 @@ class RemoteAsset extends BaseAsset {
|
||||
thumbHash: ${thumbHash ?? "<NA>"},
|
||||
visibility: $visibility,
|
||||
stackId: ${stackId ?? "<NA>"},
|
||||
stackCount: $stackCount,
|
||||
checksum: $checksum,
|
||||
livePhotoVideoId: ${livePhotoVideoId ?? "<NA>"},
|
||||
}''';
|
||||
@@ -77,8 +68,7 @@ class RemoteAsset extends BaseAsset {
|
||||
ownerId == other.ownerId &&
|
||||
thumbHash == other.thumbHash &&
|
||||
visibility == other.visibility &&
|
||||
stackId == other.stackId &&
|
||||
stackCount == other.stackCount;
|
||||
stackId == other.stackId;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -89,8 +79,7 @@ class RemoteAsset extends BaseAsset {
|
||||
localId.hashCode ^
|
||||
thumbHash.hashCode ^
|
||||
visibility.hashCode ^
|
||||
stackId.hashCode ^
|
||||
stackCount.hashCode;
|
||||
stackId.hashCode;
|
||||
|
||||
RemoteAsset copyWith({
|
||||
String? id,
|
||||
@@ -109,7 +98,6 @@ class RemoteAsset extends BaseAsset {
|
||||
AssetVisibility? visibility,
|
||||
String? livePhotoVideoId,
|
||||
String? stackId,
|
||||
int? stackCount,
|
||||
}) {
|
||||
return RemoteAsset(
|
||||
id: id ?? this.id,
|
||||
@@ -128,7 +116,6 @@ class RemoteAsset extends BaseAsset {
|
||||
visibility: visibility ?? this.visibility,
|
||||
livePhotoVideoId: livePhotoVideoId ?? this.livePhotoVideoId,
|
||||
stackId: stackId ?? this.stackId,
|
||||
stackCount: stackCount ?? this.stackCount,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,19 +5,13 @@ class DeviceAsset {
|
||||
final Uint8List hash;
|
||||
final DateTime modifiedTime;
|
||||
|
||||
const DeviceAsset({
|
||||
required this.assetId,
|
||||
required this.hash,
|
||||
required this.modifiedTime,
|
||||
});
|
||||
const DeviceAsset({required this.assetId, required this.hash, required this.modifiedTime});
|
||||
|
||||
@override
|
||||
bool operator ==(covariant DeviceAsset other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.assetId == assetId &&
|
||||
other.hash == hash &&
|
||||
other.modifiedTime == modifiedTime;
|
||||
return other.assetId == assetId && other.hash == hash && other.modifiedTime == modifiedTime;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -30,11 +24,7 @@ class DeviceAsset {
|
||||
return 'DeviceAsset(assetId: $assetId, hash: $hash, modifiedTime: $modifiedTime)';
|
||||
}
|
||||
|
||||
DeviceAsset copyWith({
|
||||
String? assetId,
|
||||
Uint8List? hash,
|
||||
DateTime? modifiedTime,
|
||||
}) {
|
||||
DeviceAsset copyWith({String? assetId, Uint8List? hash, DateTime? modifiedTime}) {
|
||||
return DeviceAsset(
|
||||
assetId: assetId ?? this.assetId,
|
||||
hash: hash ?? this.hash,
|
||||
|
||||
@@ -25,8 +25,7 @@ class ExifInfo {
|
||||
final int? iso;
|
||||
final double? exposureSeconds;
|
||||
|
||||
bool get hasCoordinates =>
|
||||
latitude != null && longitude != null && latitude != 0 && longitude != 0;
|
||||
bool get hasCoordinates => latitude != null && longitude != null && latitude != 0 && longitude != 0;
|
||||
|
||||
String get exposureTime {
|
||||
if (exposureSeconds == null) {
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
/// Log levels according to dart logging [Level]
|
||||
enum LogLevel {
|
||||
all,
|
||||
finest,
|
||||
finer,
|
||||
fine,
|
||||
config,
|
||||
info,
|
||||
warning,
|
||||
severe,
|
||||
shout,
|
||||
off,
|
||||
}
|
||||
enum LogLevel { all, finest, finer, fine, config, info, warning, severe, shout, off }
|
||||
|
||||
class LogMessage {
|
||||
final String message;
|
||||
@@ -43,12 +32,7 @@ class LogMessage {
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return message.hashCode ^
|
||||
level.hashCode ^
|
||||
createdAt.hashCode ^
|
||||
logger.hashCode ^
|
||||
error.hashCode ^
|
||||
stack.hashCode;
|
||||
return message.hashCode ^ level.hashCode ^ createdAt.hashCode ^ logger.hashCode ^ error.hashCode ^ stack.hashCode;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
18
mobile/lib/domain/models/map.model.dart
Normal file
18
mobile/lib/domain/models/map.model.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
|
||||
class Marker {
|
||||
final LatLng location;
|
||||
final String assetId;
|
||||
|
||||
const Marker({required this.location, required this.assetId});
|
||||
|
||||
@override
|
||||
bool operator ==(covariant Marker other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.location == location && other.assetId == assetId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => location.hashCode ^ assetId.hashCode;
|
||||
}
|
||||
@@ -13,34 +13,23 @@ enum MemoryTypeEnum {
|
||||
class MemoryData {
|
||||
final int year;
|
||||
|
||||
const MemoryData({
|
||||
required this.year,
|
||||
});
|
||||
const MemoryData({required this.year});
|
||||
|
||||
MemoryData copyWith({
|
||||
int? year,
|
||||
}) {
|
||||
return MemoryData(
|
||||
year: year ?? this.year,
|
||||
);
|
||||
MemoryData copyWith({int? year}) {
|
||||
return MemoryData(year: year ?? this.year);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
'year': year,
|
||||
};
|
||||
return <String, dynamic>{'year': year};
|
||||
}
|
||||
|
||||
factory MemoryData.fromMap(Map<String, dynamic> map) {
|
||||
return MemoryData(
|
||||
year: map['year'] as int,
|
||||
);
|
||||
return MemoryData(year: map['year'] as int);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory MemoryData.fromJson(String source) =>
|
||||
MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
factory MemoryData.fromJson(String source) => MemoryData.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() => 'MemoryData(year: $year)';
|
||||
|
||||
@@ -55,22 +55,17 @@ class PersonDto {
|
||||
factory PersonDto.fromMap(Map<String, dynamic> map) {
|
||||
return PersonDto(
|
||||
id: map['id'] as String,
|
||||
birthDate: map['birthDate'] != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int)
|
||||
: null,
|
||||
birthDate: map['birthDate'] != null ? DateTime.fromMillisecondsSinceEpoch(map['birthDate'] as int) : null,
|
||||
isHidden: map['isHidden'] as bool,
|
||||
name: map['name'] as String,
|
||||
thumbnailPath: map['thumbnailPath'] as String,
|
||||
updatedAt: map['updatedAt'] != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int)
|
||||
: null,
|
||||
updatedAt: map['updatedAt'] != null ? DateTime.fromMillisecondsSinceEpoch(map['updatedAt'] as int) : null,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory PersonDto.fromJson(String source) =>
|
||||
PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
factory PersonDto.fromJson(String source) => PersonDto.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
bool operator ==(covariant PersonDto other) {
|
||||
@@ -96,7 +91,7 @@ class PersonDto {
|
||||
}
|
||||
|
||||
// Model for a person stored in the server
|
||||
class Person {
|
||||
class DriftPerson {
|
||||
final String id;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
@@ -108,7 +103,7 @@ class Person {
|
||||
final String? color;
|
||||
final DateTime? birthDate;
|
||||
|
||||
const Person({
|
||||
const DriftPerson({
|
||||
required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
@@ -121,7 +116,7 @@ class Person {
|
||||
this.birthDate,
|
||||
});
|
||||
|
||||
Person copyWith({
|
||||
DriftPerson copyWith({
|
||||
String? id,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
@@ -133,7 +128,7 @@ class Person {
|
||||
String? color,
|
||||
DateTime? birthDate,
|
||||
}) {
|
||||
return Person(
|
||||
return DriftPerson(
|
||||
id: id ?? this.id,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
@@ -164,7 +159,7 @@ class Person {
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant Person other) {
|
||||
bool operator ==(covariant DriftPerson other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.id == id &&
|
||||
|
||||
@@ -5,21 +5,12 @@ class SearchResult {
|
||||
final List<BaseAsset> assets;
|
||||
final int? nextPage;
|
||||
|
||||
const SearchResult({
|
||||
required this.assets,
|
||||
this.nextPage,
|
||||
});
|
||||
const SearchResult({required this.assets, this.nextPage});
|
||||
|
||||
int get totalAssets => assets.length;
|
||||
|
||||
SearchResult copyWith({
|
||||
List<BaseAsset>? assets,
|
||||
int? nextPage,
|
||||
}) {
|
||||
return SearchResult(
|
||||
assets: assets ?? this.assets,
|
||||
nextPage: nextPage ?? this.nextPage,
|
||||
);
|
||||
SearchResult copyWith({List<BaseAsset>? assets, int? nextPage}) {
|
||||
return SearchResult(assets: assets ?? this.assets, nextPage: nextPage ?? this.nextPage);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -8,7 +8,7 @@ enum Setting<T> {
|
||||
loadOriginalVideo<bool>(StoreKey.loadOriginalVideo, false),
|
||||
preferRemoteImage<bool>(StoreKey.preferRemoteImage, false),
|
||||
advancedTroubleshooting<bool>(StoreKey.advancedTroubleshooting, false),
|
||||
;
|
||||
enableBackup<bool>(StoreKey.enableBackup, false);
|
||||
|
||||
const Setting(this.storeKey, this.defaultValue);
|
||||
|
||||
|
||||
@@ -14,13 +14,7 @@ class Stack {
|
||||
required this.primaryAssetId,
|
||||
});
|
||||
|
||||
Stack copyWith({
|
||||
String? id,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
String? ownerId,
|
||||
String? primaryAssetId,
|
||||
}) {
|
||||
Stack copyWith({String? id, DateTime? createdAt, DateTime? updatedAt, String? ownerId, String? primaryAssetId}) {
|
||||
return Stack(
|
||||
id: id ?? this.id,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
@@ -54,11 +48,7 @@ class Stack {
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return id.hashCode ^
|
||||
createdAt.hashCode ^
|
||||
updatedAt.hashCode ^
|
||||
ownerId.hashCode ^
|
||||
primaryAssetId.hashCode;
|
||||
return id.hashCode ^ createdAt.hashCode ^ updatedAt.hashCode ^ ownerId.hashCode ^ primaryAssetId.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,19 +57,13 @@ class StackResponse {
|
||||
final String primaryAssetId;
|
||||
final List<String> assetIds;
|
||||
|
||||
const StackResponse({
|
||||
required this.id,
|
||||
required this.primaryAssetId,
|
||||
required this.assetIds,
|
||||
});
|
||||
const StackResponse({required this.id, required this.primaryAssetId, required this.assetIds});
|
||||
|
||||
@override
|
||||
bool operator ==(covariant StackResponse other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.id == id &&
|
||||
other.primaryAssetId == primaryAssetId &&
|
||||
other.assetIds == assetIds;
|
||||
return other.id == id && other.primaryAssetId == primaryAssetId && other.assetIds == assetIds;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||
|
||||
enum GroupAssetsBy {
|
||||
day,
|
||||
month,
|
||||
none;
|
||||
}
|
||||
enum GroupAssetsBy { day, month, auto, none }
|
||||
|
||||
enum HeaderType {
|
||||
none,
|
||||
month,
|
||||
day,
|
||||
monthAndDay;
|
||||
}
|
||||
enum HeaderType { none, month, day, monthAndDay }
|
||||
|
||||
class Bucket {
|
||||
final int assetCount;
|
||||
@@ -44,3 +35,13 @@ class TimeBucket extends Bucket {
|
||||
class TimelineReloadEvent extends Event {
|
||||
const TimelineReloadEvent();
|
||||
}
|
||||
|
||||
class ScrollToTopEvent extends Event {
|
||||
const ScrollToTopEvent();
|
||||
}
|
||||
|
||||
class ScrollToDateEvent extends Event {
|
||||
final DateTime date;
|
||||
|
||||
const ScrollToDateEvent(this.date);
|
||||
}
|
||||
|
||||
@@ -74,22 +74,21 @@ quotaSizeInBytes: $quotaSizeInBytes,
|
||||
bool? isPartnerSharedWith,
|
||||
int? quotaUsageInBytes,
|
||||
int? quotaSizeInBytes,
|
||||
}) =>
|
||||
UserDto(
|
||||
id: id ?? this.id,
|
||||
email: email ?? this.email,
|
||||
name: name ?? this.name,
|
||||
isAdmin: isAdmin ?? this.isAdmin,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
profileImagePath: profileImagePath ?? this.profileImagePath,
|
||||
avatarColor: avatarColor ?? this.avatarColor,
|
||||
memoryEnabled: memoryEnabled ?? this.memoryEnabled,
|
||||
inTimeline: inTimeline ?? this.inTimeline,
|
||||
isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy,
|
||||
isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith,
|
||||
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
|
||||
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
|
||||
);
|
||||
}) => UserDto(
|
||||
id: id ?? this.id,
|
||||
email: email ?? this.email,
|
||||
name: name ?? this.name,
|
||||
isAdmin: isAdmin ?? this.isAdmin,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
profileImagePath: profileImagePath ?? this.profileImagePath,
|
||||
avatarColor: avatarColor ?? this.avatarColor,
|
||||
memoryEnabled: memoryEnabled ?? this.memoryEnabled,
|
||||
inTimeline: inTimeline ?? this.inTimeline,
|
||||
isPartnerSharedBy: isPartnerSharedBy ?? this.isPartnerSharedBy,
|
||||
isPartnerSharedWith: isPartnerSharedWith ?? this.isPartnerSharedWith,
|
||||
quotaUsageInBytes: quotaUsageInBytes ?? this.quotaUsageInBytes,
|
||||
quotaSizeInBytes: quotaSizeInBytes ?? this.quotaSizeInBytes,
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(covariant UserDto other) {
|
||||
@@ -143,13 +142,7 @@ class PartnerUserDto {
|
||||
this.profileImagePath,
|
||||
});
|
||||
|
||||
PartnerUserDto copyWith({
|
||||
String? id,
|
||||
String? email,
|
||||
String? name,
|
||||
bool? inTimeline,
|
||||
String? profileImagePath,
|
||||
}) {
|
||||
PartnerUserDto copyWith({String? id, String? email, String? name, bool? inTimeline, String? profileImagePath}) {
|
||||
return PartnerUserDto(
|
||||
id: id ?? this.id,
|
||||
email: email ?? this.email,
|
||||
@@ -175,16 +168,13 @@ class PartnerUserDto {
|
||||
email: map['email'] as String,
|
||||
name: map['name'] as String,
|
||||
inTimeline: map['inTimeline'] as bool,
|
||||
profileImagePath: map['profileImagePath'] != null
|
||||
? map['profileImagePath'] as String
|
||||
: null,
|
||||
profileImagePath: map['profileImagePath'] != null ? map['profileImagePath'] as String : null,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory PartnerUserDto.fromJson(String source) =>
|
||||
PartnerUserDto.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
factory PartnerUserDto.fromJson(String source) => PartnerUserDto.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -204,10 +194,6 @@ class PartnerUserDto {
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return id.hashCode ^
|
||||
email.hashCode ^
|
||||
name.hashCode ^
|
||||
inTimeline.hashCode ^
|
||||
profileImagePath.hashCode;
|
||||
return id.hashCode ^ email.hashCode ^ name.hashCode ^ inTimeline.hashCode ^ profileImagePath.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,18 +24,17 @@ enum AvatarColor {
|
||||
const AvatarColor(this.value);
|
||||
|
||||
Color toColor({bool isDarkTheme = false}) => switch (this) {
|
||||
AvatarColor.primary =>
|
||||
isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
|
||||
AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182),
|
||||
AvatarColor.red => const Color.fromARGB(255, 239, 68, 68),
|
||||
AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8),
|
||||
AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246),
|
||||
AvatarColor.green => const Color.fromARGB(255, 22, 163, 74),
|
||||
AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234),
|
||||
AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12),
|
||||
AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99),
|
||||
AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6),
|
||||
};
|
||||
AvatarColor.primary => isDarkTheme ? const Color(0xFFABCBFA) : const Color(0xFF4250AF),
|
||||
AvatarColor.pink => const Color.fromARGB(255, 244, 114, 182),
|
||||
AvatarColor.red => const Color.fromARGB(255, 239, 68, 68),
|
||||
AvatarColor.yellow => const Color.fromARGB(255, 234, 179, 8),
|
||||
AvatarColor.blue => const Color.fromARGB(255, 59, 130, 246),
|
||||
AvatarColor.green => const Color.fromARGB(255, 22, 163, 74),
|
||||
AvatarColor.purple => const Color.fromARGB(255, 147, 51, 234),
|
||||
AvatarColor.orange => const Color.fromARGB(255, 234, 88, 12),
|
||||
AvatarColor.gray => const Color.fromARGB(255, 75, 85, 99),
|
||||
AvatarColor.amber => const Color.fromARGB(255, 217, 119, 6),
|
||||
};
|
||||
}
|
||||
|
||||
class Onboarding {
|
||||
@@ -194,17 +193,9 @@ class License {
|
||||
final String activationKey;
|
||||
final String licenseKey;
|
||||
|
||||
const License({
|
||||
required this.activatedAt,
|
||||
required this.activationKey,
|
||||
required this.licenseKey,
|
||||
});
|
||||
const License({required this.activatedAt, required this.activationKey, required this.licenseKey});
|
||||
|
||||
License copyWith({
|
||||
DateTime? activatedAt,
|
||||
String? activationKey,
|
||||
String? licenseKey,
|
||||
}) {
|
||||
License copyWith({DateTime? activatedAt, String? activationKey, String? licenseKey}) {
|
||||
return License(
|
||||
activatedAt: activatedAt ?? this.activatedAt,
|
||||
activationKey: activationKey ?? this.activationKey,
|
||||
@@ -241,14 +232,11 @@ licenseKey: $licenseKey,
|
||||
bool operator ==(covariant License other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return activatedAt == other.activatedAt &&
|
||||
activationKey == other.activationKey &&
|
||||
licenseKey == other.licenseKey;
|
||||
return activatedAt == other.activatedAt && activationKey == other.activationKey && licenseKey == other.licenseKey;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
|
||||
int get hashCode => activatedAt.hashCode ^ activationKey.hashCode ^ licenseKey.hashCode;
|
||||
}
|
||||
|
||||
// Model for a user metadata stored in the server
|
||||
@@ -259,16 +247,11 @@ class UserMetadata {
|
||||
final Preferences? preferences;
|
||||
final License? license;
|
||||
|
||||
const UserMetadata({
|
||||
required this.userId,
|
||||
required this.key,
|
||||
this.onboarding,
|
||||
this.preferences,
|
||||
this.license,
|
||||
}) : assert(
|
||||
onboarding != null || preferences != null || license != null,
|
||||
'One of onboarding, preferences and license must be provided',
|
||||
);
|
||||
const UserMetadata({required this.userId, required this.key, this.onboarding, this.preferences, this.license})
|
||||
: assert(
|
||||
onboarding != null || preferences != null || license != null,
|
||||
'One of onboarding, preferences and license must be provided',
|
||||
);
|
||||
|
||||
UserMetadata copyWith({
|
||||
String? userId,
|
||||
@@ -310,10 +293,6 @@ license: ${license ?? "<NA>"},
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return userId.hashCode ^
|
||||
key.hashCode ^
|
||||
onboarding.hashCode ^
|
||||
preferences.hashCode ^
|
||||
license.hashCode;
|
||||
return userId.hashCode ^ key.hashCode ^ onboarding.hashCode ^ preferences.hashCode ^ license.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,15 +13,17 @@ class AssetService {
|
||||
const AssetService({
|
||||
required RemoteAssetRepository remoteAssetRepository,
|
||||
required DriftLocalAssetRepository localAssetRepository,
|
||||
}) : _remoteAssetRepository = remoteAssetRepository,
|
||||
_localAssetRepository = localAssetRepository,
|
||||
_platform = const LocalPlatform();
|
||||
}) : _remoteAssetRepository = remoteAssetRepository,
|
||||
_localAssetRepository = localAssetRepository,
|
||||
_platform = const LocalPlatform();
|
||||
|
||||
Stream<BaseAsset?> watchAsset(BaseAsset asset) {
|
||||
final id = asset is LocalAsset ? asset.id : (asset as RemoteAsset).id;
|
||||
return asset is LocalAsset
|
||||
? _localAssetRepository.watchAsset(id)
|
||||
: _remoteAssetRepository.watchAsset(id);
|
||||
return asset is LocalAsset ? _localAssetRepository.watchAsset(id) : _remoteAssetRepository.watchAsset(id);
|
||||
}
|
||||
|
||||
Future<RemoteAsset?> getRemoteAsset(String id) {
|
||||
return _remoteAssetRepository.get(id);
|
||||
}
|
||||
|
||||
Future<List<RemoteAsset>> getStack(RemoteAsset asset) async {
|
||||
@@ -40,8 +42,7 @@ class AssetService {
|
||||
return null;
|
||||
}
|
||||
|
||||
final id =
|
||||
asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
|
||||
final id = asset is LocalAsset ? asset.remoteId! : (asset as RemoteAsset).id;
|
||||
return _remoteAssetRepository.getExif(id);
|
||||
}
|
||||
|
||||
@@ -56,8 +57,7 @@ class AssetService {
|
||||
width = exif?.width ?? asset.width?.toDouble();
|
||||
height = exif?.height ?? asset.height?.toDouble();
|
||||
} else if (asset is LocalAsset) {
|
||||
isFlipped = _platform.isAndroid &&
|
||||
(asset.orientation == 90 || asset.orientation == 270);
|
||||
isFlipped = _platform.isAndroid && (asset.orientation == 90 || asset.orientation == 270);
|
||||
width = asset.width?.toDouble();
|
||||
height = asset.height?.toDouble();
|
||||
} else {
|
||||
@@ -78,10 +78,7 @@ class AssetService {
|
||||
}
|
||||
|
||||
Future<(int local, int remote)> getAssetCounts() async {
|
||||
return (
|
||||
await _localAssetRepository.getCount(),
|
||||
await _remoteAssetRepository.getCount()
|
||||
);
|
||||
return (await _localAssetRepository.getCount(), await _remoteAssetRepository.getCount());
|
||||
}
|
||||
|
||||
Future<int> getLocalHashedCount() {
|
||||
|
||||
@@ -25,24 +25,20 @@ class HashService {
|
||||
required NativeSyncApi nativeSyncApi,
|
||||
this.batchSizeLimit = kBatchHashSizeLimit,
|
||||
this.batchFileLimit = kBatchHashFileLimit,
|
||||
}) : _localAlbumRepository = localAlbumRepository,
|
||||
_localAssetRepository = localAssetRepository,
|
||||
_storageRepository = storageRepository,
|
||||
_nativeSyncApi = nativeSyncApi;
|
||||
}) : _localAlbumRepository = localAlbumRepository,
|
||||
_localAssetRepository = localAssetRepository,
|
||||
_storageRepository = storageRepository,
|
||||
_nativeSyncApi = nativeSyncApi;
|
||||
|
||||
Future<void> hashAssets() async {
|
||||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
// Sorted by backupSelection followed by isCloud
|
||||
final localAlbums = await _localAlbumRepository.getAll(
|
||||
sortBy: {
|
||||
SortLocalAlbumsBy.backupSelection,
|
||||
SortLocalAlbumsBy.isIosSharedAlbum,
|
||||
},
|
||||
sortBy: {SortLocalAlbumsBy.backupSelection, SortLocalAlbumsBy.isIosSharedAlbum},
|
||||
);
|
||||
|
||||
for (final album in localAlbums) {
|
||||
final assetsToHash =
|
||||
await _localAlbumRepository.getAssetsToHash(album.id);
|
||||
final assetsToHash = await _localAlbumRepository.getAssetsToHash(album.id);
|
||||
if (assetsToHash.isNotEmpty) {
|
||||
await _hashAssets(assetsToHash);
|
||||
}
|
||||
@@ -88,8 +84,7 @@ class HashService {
|
||||
_log.fine("Hashing ${toHash.length} files");
|
||||
|
||||
final hashed = <LocalAsset>[];
|
||||
final hashes =
|
||||
await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
|
||||
final hashes = await _nativeSyncApi.hashPaths(toHash.map((e) => e.path).toList());
|
||||
assert(
|
||||
hashes.length == toHash.length,
|
||||
"Hashes length does not match toHash length: ${hashes.length} != ${toHash.length}",
|
||||
|
||||
@@ -21,9 +21,9 @@ class LocalSyncService {
|
||||
required DriftLocalAlbumRepository localAlbumRepository,
|
||||
required NativeSyncApi nativeSyncApi,
|
||||
Platform? platform,
|
||||
}) : _localAlbumRepository = localAlbumRepository,
|
||||
_nativeSyncApi = nativeSyncApi,
|
||||
_platform = platform ?? const LocalPlatform();
|
||||
}) : _localAlbumRepository = localAlbumRepository,
|
||||
_nativeSyncApi = nativeSyncApi,
|
||||
_platform = platform ?? const LocalPlatform();
|
||||
|
||||
Future<void> sync({bool full = false}) async {
|
||||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
@@ -66,14 +66,11 @@ class LocalSyncService {
|
||||
// On iOS, we need to full sync albums that are marked as cloud as the delta sync
|
||||
// does not include changes for cloud albums. If ignoreIcloudAssets is enabled,
|
||||
// remove the albums from the local database from the previous sync
|
||||
final cloudAlbums =
|
||||
deviceAlbums.where((a) => a.isCloud).toLocalAlbums();
|
||||
final cloudAlbums = deviceAlbums.where((a) => a.isCloud).toLocalAlbums();
|
||||
for (final album in cloudAlbums) {
|
||||
final dbAlbum = dbAlbums.firstWhereOrNull((a) => a.id == album.id);
|
||||
if (dbAlbum == null) {
|
||||
_log.warning(
|
||||
"Cloud album ${album.name} not found in local database. Skipping sync.",
|
||||
);
|
||||
_log.warning("Cloud album ${album.name} not found in local database. Skipping sync.");
|
||||
continue;
|
||||
}
|
||||
await updateAlbum(dbAlbum, album);
|
||||
@@ -95,8 +92,7 @@ class LocalSyncService {
|
||||
final Stopwatch stopwatch = Stopwatch()..start();
|
||||
|
||||
final deviceAlbums = await _nativeSyncApi.getAlbums();
|
||||
final dbAlbums =
|
||||
await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
|
||||
final dbAlbums = await _localAlbumRepository.getAll(sortBy: {SortLocalAlbumsBy.id});
|
||||
|
||||
await diffSortedLists(
|
||||
dbAlbums,
|
||||
@@ -120,14 +116,9 @@ class LocalSyncService {
|
||||
try {
|
||||
_log.fine("Adding device album ${album.name}");
|
||||
|
||||
final assets = album.assetCount > 0
|
||||
? await _nativeSyncApi.getAssetsForAlbum(album.id)
|
||||
: <PlatformAsset>[];
|
||||
final assets = album.assetCount > 0 ? await _nativeSyncApi.getAssetsForAlbum(album.id) : <PlatformAsset>[];
|
||||
|
||||
await _localAlbumRepository.upsert(
|
||||
album,
|
||||
toUpsert: assets.toLocalAssets(),
|
||||
);
|
||||
await _localAlbumRepository.upsert(album, toUpsert: assets.toLocalAssets());
|
||||
_log.fine("Successfully added device album ${album.name}");
|
||||
} catch (e, s) {
|
||||
_log.warning("Error while adding device album", e, s);
|
||||
@@ -150,9 +141,7 @@ class LocalSyncService {
|
||||
_log.fine("Syncing device album ${dbAlbum.name}");
|
||||
|
||||
if (_albumsEqual(deviceAlbum, dbAlbum)) {
|
||||
_log.fine(
|
||||
"Device album ${dbAlbum.name} has not changed. Skipping sync.",
|
||||
);
|
||||
_log.fine("Device album ${dbAlbum.name} has not changed. Skipping sync.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -176,10 +165,7 @@ class LocalSyncService {
|
||||
@visibleForTesting
|
||||
// The [deviceAlbum] is expected to be refreshed before calling this method
|
||||
// with modified time and asset count
|
||||
Future<bool> checkAddition(
|
||||
LocalAlbum dbAlbum,
|
||||
LocalAlbum deviceAlbum,
|
||||
) async {
|
||||
Future<bool> checkAddition(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async {
|
||||
try {
|
||||
_log.fine("Fast syncing device album ${dbAlbum.name}");
|
||||
// Assets has been modified
|
||||
@@ -188,16 +174,12 @@ class LocalSyncService {
|
||||
return false;
|
||||
}
|
||||
|
||||
final updatedTime =
|
||||
(dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1;
|
||||
final newAssetsCount =
|
||||
await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime);
|
||||
final updatedTime = (dbAlbum.updatedAt.millisecondsSinceEpoch ~/ 1000) + 1;
|
||||
final newAssetsCount = await _nativeSyncApi.getAssetsCountSince(deviceAlbum.id, updatedTime);
|
||||
|
||||
// Early return if no new assets were found
|
||||
if (newAssetsCount == 0) {
|
||||
_log.fine(
|
||||
"No new assets found despite album having changes. Proceeding to full sync for ${dbAlbum.name}",
|
||||
);
|
||||
_log.fine("No new assets found despite album having changes. Proceeding to full sync for ${dbAlbum.name}");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -207,10 +189,7 @@ class LocalSyncService {
|
||||
return false;
|
||||
}
|
||||
|
||||
final newAssets = await _nativeSyncApi.getAssetsForAlbum(
|
||||
deviceAlbum.id,
|
||||
updatedTimeCond: updatedTime,
|
||||
);
|
||||
final newAssets = await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id, updatedTimeCond: updatedTime);
|
||||
|
||||
await _localAlbumRepository.upsert(
|
||||
deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection),
|
||||
@@ -230,18 +209,12 @@ class LocalSyncService {
|
||||
Future<bool> fullDiff(LocalAlbum dbAlbum, LocalAlbum deviceAlbum) async {
|
||||
try {
|
||||
final assetsInDevice = deviceAlbum.assetCount > 0
|
||||
? await _nativeSyncApi
|
||||
.getAssetsForAlbum(deviceAlbum.id)
|
||||
.then((a) => a.toLocalAssets())
|
||||
: <LocalAsset>[];
|
||||
final assetsInDb = dbAlbum.assetCount > 0
|
||||
? await _localAlbumRepository.getAssets(dbAlbum.id)
|
||||
? await _nativeSyncApi.getAssetsForAlbum(deviceAlbum.id).then((a) => a.toLocalAssets())
|
||||
: <LocalAsset>[];
|
||||
final assetsInDb = dbAlbum.assetCount > 0 ? await _localAlbumRepository.getAssets(dbAlbum.id) : <LocalAsset>[];
|
||||
|
||||
if (deviceAlbum.assetCount == 0) {
|
||||
_log.fine(
|
||||
"Device album ${deviceAlbum.name} is empty. Removing assets from DB.",
|
||||
);
|
||||
_log.fine("Device album ${deviceAlbum.name} is empty. Removing assets from DB.");
|
||||
await _localAlbumRepository.upsert(
|
||||
deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection),
|
||||
toDelete: assetsInDb.map((a) => a.id),
|
||||
@@ -249,18 +222,11 @@ class LocalSyncService {
|
||||
return true;
|
||||
}
|
||||
|
||||
final updatedDeviceAlbum = deviceAlbum.copyWith(
|
||||
backupSelection: dbAlbum.backupSelection,
|
||||
);
|
||||
final updatedDeviceAlbum = deviceAlbum.copyWith(backupSelection: dbAlbum.backupSelection);
|
||||
|
||||
if (dbAlbum.assetCount == 0) {
|
||||
_log.fine(
|
||||
"Device album ${deviceAlbum.name} is empty. Adding assets to DB.",
|
||||
);
|
||||
await _localAlbumRepository.upsert(
|
||||
updatedDeviceAlbum,
|
||||
toUpsert: assetsInDevice,
|
||||
);
|
||||
_log.fine("Device album ${deviceAlbum.name} is empty. Adding assets to DB.");
|
||||
await _localAlbumRepository.upsert(updatedDeviceAlbum, toUpsert: assetsInDevice);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -292,18 +258,12 @@ class LocalSyncService {
|
||||
);
|
||||
|
||||
if (assetsToUpsert.isEmpty && assetsToDelete.isEmpty) {
|
||||
_log.fine(
|
||||
"No asset changes detected in album ${deviceAlbum.name}. Updating metadata.",
|
||||
);
|
||||
_log.fine("No asset changes detected in album ${deviceAlbum.name}. Updating metadata.");
|
||||
_localAlbumRepository.upsert(updatedDeviceAlbum);
|
||||
return true;
|
||||
}
|
||||
|
||||
await _localAlbumRepository.upsert(
|
||||
updatedDeviceAlbum,
|
||||
toUpsert: assetsToUpsert,
|
||||
toDelete: assetsToDelete,
|
||||
);
|
||||
await _localAlbumRepository.upsert(updatedDeviceAlbum, toUpsert: assetsToUpsert, toDelete: assetsToDelete);
|
||||
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
@@ -321,9 +281,7 @@ class LocalSyncService {
|
||||
}
|
||||
|
||||
bool _albumsEqual(LocalAlbum a, LocalAlbum b) {
|
||||
return a.name == b.name &&
|
||||
a.assetCount == b.assetCount &&
|
||||
a.updatedAt.isAtSameMomentAs(b.updatedAt);
|
||||
return a.name == b.name && a.assetCount == b.assetCount && a.updatedAt.isAtSameMomentAs(b.updatedAt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,9 +291,7 @@ extension on Iterable<PlatformAlbum> {
|
||||
(e) => LocalAlbum(
|
||||
id: e.id,
|
||||
name: e.name,
|
||||
updatedAt: e.updatedAt == null
|
||||
? DateTime.now()
|
||||
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
|
||||
updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
|
||||
assetCount: e.assetCount,
|
||||
),
|
||||
).toList();
|
||||
@@ -350,16 +306,13 @@ extension on Iterable<PlatformAsset> {
|
||||
name: e.name,
|
||||
checksum: null,
|
||||
type: AssetType.values.elementAtOrNull(e.type) ?? AssetType.other,
|
||||
createdAt: e.createdAt == null
|
||||
? DateTime.now()
|
||||
: DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),
|
||||
updatedAt: e.updatedAt == null
|
||||
? DateTime.now()
|
||||
: DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
|
||||
createdAt: e.createdAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.createdAt! * 1000),
|
||||
updatedAt: e.updatedAt == null ? DateTime.now() : DateTime.fromMillisecondsSinceEpoch(e.updatedAt! * 1000),
|
||||
width: e.width,
|
||||
height: e.height,
|
||||
durationInSeconds: e.durationInSeconds,
|
||||
orientation: e.orientation,
|
||||
isFavorite: e.isFavorite,
|
||||
),
|
||||
).toList();
|
||||
}
|
||||
|
||||
@@ -56,17 +56,12 @@ class LogService {
|
||||
}) async {
|
||||
final instance = LogService._(logRepository, storeRepository, shouldBuffer);
|
||||
await logRepository.truncate(limit: kLogTruncateLimit);
|
||||
final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ??
|
||||
LogLevel.info.index;
|
||||
final level = await instance._storeRepository.tryGet(StoreKey.logLevel) ?? LogLevel.info.index;
|
||||
Logger.root.level = Level.LEVELS.elementAtOrNull(level) ?? Level.INFO;
|
||||
return instance;
|
||||
}
|
||||
|
||||
LogService._(
|
||||
this._logRepository,
|
||||
this._storeRepository,
|
||||
this._shouldBuffer,
|
||||
) {
|
||||
LogService._(this._logRepository, this._storeRepository, this._shouldBuffer) {
|
||||
_logSubscription = Logger.root.onRecord.listen(_handleLogRecord);
|
||||
}
|
||||
|
||||
@@ -90,10 +85,7 @@ class LogService {
|
||||
|
||||
if (_shouldBuffer) {
|
||||
_msgBuffer.add(record);
|
||||
_flushTimer ??= Timer(
|
||||
const Duration(seconds: 5),
|
||||
() => unawaited(flushBuffer()),
|
||||
);
|
||||
_flushTimer ??= Timer(const Duration(seconds: 5), () => unawaited(flushBuffer()));
|
||||
} else {
|
||||
unawaited(_logRepository.insert(record));
|
||||
}
|
||||
@@ -146,9 +138,7 @@ class LoggerUnInitializedException implements Exception {
|
||||
|
||||
/// Log levels according to dart logging [Level]
|
||||
extension LevelDomainToInfraExtension on Level {
|
||||
LogLevel toLogLevel() =>
|
||||
LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ??
|
||||
LogLevel.info;
|
||||
LogLevel toLogLevel() => LogLevel.values.elementAtOrNull(Level.LEVELS.indexOf(this)) ?? LogLevel.info;
|
||||
}
|
||||
|
||||
extension on LogLevel {
|
||||
|
||||
23
mobile/lib/domain/services/map.service.dart
Normal file
23
mobile/lib/domain/services/map.service.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:immich_mobile/domain/models/map.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/map.repository.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
|
||||
typedef MapMarkerSource = Future<List<Marker>> Function(LatLngBounds? bounds);
|
||||
|
||||
typedef MapQuery = ({MapMarkerSource markerSource});
|
||||
|
||||
class MapFactory {
|
||||
final DriftMapRepository _mapRepository;
|
||||
|
||||
const MapFactory({required DriftMapRepository mapRepository}) : _mapRepository = mapRepository;
|
||||
|
||||
MapService remote(String ownerId) => MapService(_mapRepository.remote(ownerId));
|
||||
}
|
||||
|
||||
class MapService {
|
||||
final MapMarkerSource _markerSource;
|
||||
|
||||
MapService(MapQuery query) : _markerSource = query.markerSource;
|
||||
|
||||
Future<List<Marker>> Function(LatLngBounds? bounds) get getMarkers => _markerSource;
|
||||
}
|
||||
@@ -13,6 +13,10 @@ class DriftMemoryService {
|
||||
return _repository.getAll(ownerId);
|
||||
}
|
||||
|
||||
Future<DriftMemory?> get(String memoryId) {
|
||||
return _repository.get(memoryId);
|
||||
}
|
||||
|
||||
Future<int> getCount() {
|
||||
return _repository.getCount();
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ class DriftPartnerService {
|
||||
final DriftPartnerRepository _driftPartnerRepository;
|
||||
final PartnerApiRepository _partnerApiRepository;
|
||||
|
||||
const DriftPartnerService(
|
||||
this._driftPartnerRepository,
|
||||
this._partnerApiRepository,
|
||||
);
|
||||
const DriftPartnerService(this._driftPartnerRepository, this._partnerApiRepository);
|
||||
|
||||
Future<List<PartnerUserDto>> getSharedWith(String userId) {
|
||||
return _driftPartnerRepository.getSharedWith(userId);
|
||||
@@ -20,13 +17,9 @@ class DriftPartnerService {
|
||||
return _driftPartnerRepository.getSharedBy(userId);
|
||||
}
|
||||
|
||||
Future<List<PartnerUserDto>> getAvailablePartners(
|
||||
String currentUserId,
|
||||
) async {
|
||||
final otherUsers =
|
||||
await _driftPartnerRepository.getAvailablePartners(currentUserId);
|
||||
final currentPartners =
|
||||
await _driftPartnerRepository.getSharedBy(currentUserId);
|
||||
Future<List<PartnerUserDto>> getAvailablePartners(String currentUserId) async {
|
||||
final otherUsers = await _driftPartnerRepository.getAvailablePartners(currentUserId);
|
||||
final currentPartners = await _driftPartnerRepository.getSharedBy(currentUserId);
|
||||
final available = otherUsers.where((user) {
|
||||
return !currentPartners.any((partner) => partner.id == user.id);
|
||||
}).toList();
|
||||
@@ -41,10 +34,7 @@ class DriftPartnerService {
|
||||
return;
|
||||
}
|
||||
|
||||
await _partnerApiRepository.update(
|
||||
partnerId,
|
||||
inTimeline: !partner.inTimeline,
|
||||
);
|
||||
await _partnerApiRepository.update(partnerId, inTimeline: !partner.inTimeline);
|
||||
|
||||
await _driftPartnerRepository.toggleShowInTimeline(partner, userId);
|
||||
}
|
||||
|
||||
30
mobile/lib/domain/services/people.service.dart
Normal file
30
mobile/lib/domain/services/people.service.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:immich_mobile/domain/models/person.model.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/people.repository.dart';
|
||||
import 'package:immich_mobile/repositories/person_api.repository.dart';
|
||||
|
||||
class DriftPeopleService {
|
||||
final DriftPeopleRepository _repository;
|
||||
final PersonApiRepository _personApiRepository;
|
||||
|
||||
const DriftPeopleService(this._repository, this._personApiRepository);
|
||||
|
||||
Future<List<DriftPerson>> getAssetPeople(String assetId) {
|
||||
return _repository.getAssetPeople(assetId);
|
||||
}
|
||||
|
||||
Future<List<DriftPerson>> getAllPeople() {
|
||||
return _repository.getAllPeople();
|
||||
}
|
||||
|
||||
Future<int> updateName(String personId, String name) async {
|
||||
await _personApiRepository.update(personId, name: name);
|
||||
return _repository.updateName(personId, name);
|
||||
}
|
||||
|
||||
Future<int> updateBrithday(String personId, DateTime birthday) async {
|
||||
await _personApiRepository.update(personId, birthday: birthday);
|
||||
return _repository.updateBirthday(personId, birthday);
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,11 @@ class RemoteAlbumService {
|
||||
return _repository.getAll();
|
||||
}
|
||||
|
||||
List<RemoteAlbum> sortAlbums(
|
||||
List<RemoteAlbum> albums,
|
||||
RemoteAlbumSortMode sortMode, {
|
||||
bool isReverse = false,
|
||||
}) {
|
||||
Future<RemoteAlbum?> get(String albumId) {
|
||||
return _repository.get(albumId);
|
||||
}
|
||||
|
||||
List<RemoteAlbum> sortAlbums(List<RemoteAlbum> albums, RemoteAlbumSortMode sortMode, {bool isReverse = false}) {
|
||||
return sortMode.sortFn(albums, isReverse);
|
||||
}
|
||||
|
||||
@@ -44,8 +44,7 @@ class RemoteAlbumService {
|
||||
filtered = filtered
|
||||
.where(
|
||||
(album) =>
|
||||
album.name.toLowerCase().contains(lowerQuery) ||
|
||||
album.description.toLowerCase().contains(lowerQuery),
|
||||
album.name.toLowerCase().contains(lowerQuery) || album.description.toLowerCase().contains(lowerQuery),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
@@ -53,12 +52,10 @@ class RemoteAlbumService {
|
||||
if (userId != null) {
|
||||
switch (filterMode) {
|
||||
case QuickFilterMode.myAlbums:
|
||||
filtered =
|
||||
filtered.where((album) => album.ownerId == userId).toList();
|
||||
filtered = filtered.where((album) => album.ownerId == userId).toList();
|
||||
break;
|
||||
case QuickFilterMode.sharedWithMe:
|
||||
filtered =
|
||||
filtered.where((album) => album.ownerId != userId).toList();
|
||||
filtered = filtered.where((album) => album.ownerId != userId).toList();
|
||||
break;
|
||||
case QuickFilterMode.all:
|
||||
break;
|
||||
@@ -68,16 +65,8 @@ class RemoteAlbumService {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
Future<RemoteAlbum> createAlbum({
|
||||
required String title,
|
||||
required List<String> assetIds,
|
||||
String? description,
|
||||
}) async {
|
||||
final album = await _albumApiRepository.createDriftAlbum(
|
||||
title,
|
||||
description: description,
|
||||
assetIds: assetIds,
|
||||
);
|
||||
Future<RemoteAlbum> createAlbum({required String title, required List<String> assetIds, String? description}) async {
|
||||
final album = await _albumApiRepository.createDriftAlbum(title, description: description, assetIds: assetIds);
|
||||
|
||||
await _repository.create(album, assetIds);
|
||||
|
||||
@@ -119,14 +108,8 @@ class RemoteAlbumService {
|
||||
return _repository.getAssets(albumId);
|
||||
}
|
||||
|
||||
Future<int> addAssets({
|
||||
required String albumId,
|
||||
required List<String> assetIds,
|
||||
}) async {
|
||||
final album = await _albumApiRepository.addAssets(
|
||||
albumId,
|
||||
assetIds,
|
||||
);
|
||||
Future<int> addAssets({required String albumId, required List<String> assetIds}) async {
|
||||
final album = await _albumApiRepository.addAssets(albumId, assetIds);
|
||||
|
||||
await _repository.addAssets(albumId, album.added);
|
||||
|
||||
@@ -139,10 +122,7 @@ class RemoteAlbumService {
|
||||
await _repository.deleteAlbum(albumId);
|
||||
}
|
||||
|
||||
Future<void> addUsers({
|
||||
required String albumId,
|
||||
required List<String> userIds,
|
||||
}) async {
|
||||
Future<void> addUsers({required String albumId, required List<String> userIds}) async {
|
||||
await _albumApiRepository.addUsers(albumId, userIds);
|
||||
|
||||
return _repository.addUsers(albumId, userIds);
|
||||
|
||||
@@ -83,10 +83,10 @@ extension on AssetResponseDto {
|
||||
|
||||
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'),
|
||||
};
|
||||
AssetTypeEnum.IMAGE => AssetType.image,
|
||||
AssetTypeEnum.VIDEO => AssetType.video,
|
||||
AssetTypeEnum.AUDIO => AssetType.audio,
|
||||
AssetTypeEnum.OTHER => AssetType.other,
|
||||
_ => throw Exception('Unknown AssetType value: $this'),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,16 +9,11 @@ final AppSetting = SettingsService(storeService: StoreService.I);
|
||||
class SettingsService {
|
||||
final StoreService _storeService;
|
||||
|
||||
const SettingsService({required StoreService storeService})
|
||||
: _storeService = storeService;
|
||||
const SettingsService({required StoreService storeService}) : _storeService = storeService;
|
||||
|
||||
T get<T>(Setting<T> setting) =>
|
||||
_storeService.get(setting.storeKey, setting.defaultValue);
|
||||
T get<T>(Setting<T> setting) => _storeService.get(setting.storeKey, setting.defaultValue);
|
||||
|
||||
Future<void> set<T>(Setting<T> setting, T value) =>
|
||||
_storeService.put(setting.storeKey, value);
|
||||
Future<void> set<T>(Setting<T> setting, T value) => _storeService.put(setting.storeKey, value);
|
||||
|
||||
Stream<T> watch<T>(Setting<T> setting) => _storeService
|
||||
.watch(setting.storeKey)
|
||||
.map((v) => v ?? setting.defaultValue);
|
||||
Stream<T> watch<T>(Setting<T> setting) => _storeService.watch(setting.storeKey).map((v) => v ?? setting.defaultValue);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ class StoreService {
|
||||
final Map<int, Object?> _cache = {};
|
||||
late final StreamSubscription<StoreDto> _storeUpdateSubscription;
|
||||
|
||||
StoreService._({required IsarStoreRepository storeRepository})
|
||||
: _storeRepository = storeRepository;
|
||||
StoreService._({required IsarStoreRepository storeRepository}) : _storeRepository = storeRepository;
|
||||
|
||||
// TODO: Temporary typedef to make minimal changes. Remove this and make the presentation layer access store through a provider
|
||||
static StoreService? _instance;
|
||||
@@ -25,16 +24,12 @@ class StoreService {
|
||||
}
|
||||
|
||||
// TODO: Replace the implementation with the one from create after removing the typedef
|
||||
static Future<StoreService> init({
|
||||
required IsarStoreRepository storeRepository,
|
||||
}) async {
|
||||
static Future<StoreService> init({required IsarStoreRepository storeRepository}) async {
|
||||
_instance ??= await create(storeRepository: storeRepository);
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
static Future<StoreService> create({
|
||||
required IsarStoreRepository storeRepository,
|
||||
}) async {
|
||||
static Future<StoreService> create({required IsarStoreRepository storeRepository}) async {
|
||||
final instance = StoreService._(storeRepository: storeRepository);
|
||||
await instance._populateCache();
|
||||
instance._storeUpdateSubscription = instance._listenForChange();
|
||||
@@ -48,10 +43,9 @@ class StoreService {
|
||||
}
|
||||
}
|
||||
|
||||
StreamSubscription<StoreDto> _listenForChange() =>
|
||||
_storeRepository.watchAll().listen((event) {
|
||||
_cache[event.key.id] = event.value;
|
||||
});
|
||||
StreamSubscription<StoreDto> _listenForChange() => _storeRepository.watchAll().listen((event) {
|
||||
_cache[event.key.id] = event.value;
|
||||
});
|
||||
|
||||
/// Disposes the store and cancels the subscription. To reuse the store call init() again
|
||||
void dispose() async {
|
||||
|
||||
@@ -18,14 +18,14 @@ class SyncStreamService {
|
||||
required SyncApiRepository syncApiRepository,
|
||||
required SyncStreamRepository syncStreamRepository,
|
||||
bool Function()? cancelChecker,
|
||||
}) : _syncApiRepository = syncApiRepository,
|
||||
_syncStreamRepository = syncStreamRepository,
|
||||
_cancelChecker = cancelChecker;
|
||||
}) : _syncApiRepository = syncApiRepository,
|
||||
_syncStreamRepository = syncStreamRepository,
|
||||
_cancelChecker = cancelChecker;
|
||||
|
||||
bool get isCancelled => _cancelChecker?.call() ?? false;
|
||||
|
||||
Future<void> sync() {
|
||||
_logger.info("Remote sync request for userr");
|
||||
_logger.info("Remote sync request for user");
|
||||
DLog.log("Remote sync request for user");
|
||||
// Start the sync stream and handle events
|
||||
return _syncApiRepository.streamChanges(_handleEvents);
|
||||
@@ -34,9 +34,7 @@ class SyncStreamService {
|
||||
Future<void> handleWsAssetUploadReadyV1Batch(List<dynamic> batchData) async {
|
||||
if (batchData.isEmpty) return;
|
||||
|
||||
_logger.info(
|
||||
'Processing batch of ${batchData.length} AssetUploadReadyV1 events',
|
||||
);
|
||||
_logger.info('Processing batch of ${batchData.length} AssetUploadReadyV1 events');
|
||||
|
||||
final List<SyncAssetV1> assets = [];
|
||||
final List<SyncAssetExifV1> exifs = [];
|
||||
@@ -65,22 +63,12 @@ class SyncStreamService {
|
||||
}
|
||||
|
||||
if (assets.isNotEmpty && exifs.isNotEmpty) {
|
||||
await _syncStreamRepository.updateAssetsV1(
|
||||
assets,
|
||||
debugLabel: 'websocket-batch',
|
||||
);
|
||||
await _syncStreamRepository.updateAssetsExifV1(
|
||||
exifs,
|
||||
debugLabel: 'websocket-batch',
|
||||
);
|
||||
await _syncStreamRepository.updateAssetsV1(assets, debugLabel: 'websocket-batch');
|
||||
await _syncStreamRepository.updateAssetsExifV1(exifs, debugLabel: 'websocket-batch');
|
||||
_logger.info('Successfully processed ${assets.length} assets in batch');
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
_logger.severe(
|
||||
"Error processing AssetUploadReadyV1 websocket batch events",
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
_logger.severe("Error processing AssetUploadReadyV1 websocket batch events", error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +102,7 @@ class SyncStreamService {
|
||||
batch.clear();
|
||||
}
|
||||
|
||||
Future<void> _handleSyncData(
|
||||
SyncEntityType type,
|
||||
Iterable<Object> data,
|
||||
) async {
|
||||
Future<void> _handleSyncData(SyncEntityType type, Iterable<Object> data) async {
|
||||
_logger.fine("Processing sync data for $type of length ${data.length}");
|
||||
switch (type) {
|
||||
case SyncEntityType.userV1:
|
||||
@@ -135,30 +120,15 @@ class SyncStreamService {
|
||||
case SyncEntityType.assetExifV1:
|
||||
return _syncStreamRepository.updateAssetsExifV1(data.cast());
|
||||
case SyncEntityType.partnerAssetV1:
|
||||
return _syncStreamRepository.updateAssetsV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'partner');
|
||||
case SyncEntityType.partnerAssetBackfillV1:
|
||||
return _syncStreamRepository.updateAssetsV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'partner backfill');
|
||||
case SyncEntityType.partnerAssetDeleteV1:
|
||||
return _syncStreamRepository.deleteAssetsV1(
|
||||
data.cast(),
|
||||
debugLabel: "partner",
|
||||
);
|
||||
return _syncStreamRepository.deleteAssetsV1(data.cast(), debugLabel: "partner");
|
||||
case SyncEntityType.partnerAssetExifV1:
|
||||
return _syncStreamRepository.updateAssetsExifV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner');
|
||||
case SyncEntityType.partnerAssetExifBackfillV1:
|
||||
return _syncStreamRepository.updateAssetsExifV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'partner backfill');
|
||||
case SyncEntityType.albumV1:
|
||||
return _syncStreamRepository.updateAlbumsV1(data.cast());
|
||||
case SyncEntityType.albumDeleteV1:
|
||||
@@ -166,39 +136,21 @@ class SyncStreamService {
|
||||
case SyncEntityType.albumUserV1:
|
||||
return _syncStreamRepository.updateAlbumUsersV1(data.cast());
|
||||
case SyncEntityType.albumUserBackfillV1:
|
||||
return _syncStreamRepository.updateAlbumUsersV1(
|
||||
data.cast(),
|
||||
debugLabel: 'backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateAlbumUsersV1(data.cast(), debugLabel: 'backfill');
|
||||
case SyncEntityType.albumUserDeleteV1:
|
||||
return _syncStreamRepository.deleteAlbumUsersV1(data.cast());
|
||||
case SyncEntityType.albumAssetV1:
|
||||
return _syncStreamRepository.updateAssetsV1(
|
||||
data.cast(),
|
||||
debugLabel: 'album',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album');
|
||||
case SyncEntityType.albumAssetBackfillV1:
|
||||
return _syncStreamRepository.updateAssetsV1(
|
||||
data.cast(),
|
||||
debugLabel: 'album backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsV1(data.cast(), debugLabel: 'album backfill');
|
||||
case SyncEntityType.albumAssetExifV1:
|
||||
return _syncStreamRepository.updateAssetsExifV1(
|
||||
data.cast(),
|
||||
debugLabel: 'album',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album');
|
||||
case SyncEntityType.albumAssetExifBackfillV1:
|
||||
return _syncStreamRepository.updateAssetsExifV1(
|
||||
data.cast(),
|
||||
debugLabel: 'album backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateAssetsExifV1(data.cast(), debugLabel: 'album backfill');
|
||||
case SyncEntityType.albumToAssetV1:
|
||||
return _syncStreamRepository.updateAlbumToAssetsV1(data.cast());
|
||||
case SyncEntityType.albumToAssetBackfillV1:
|
||||
return _syncStreamRepository.updateAlbumToAssetsV1(
|
||||
data.cast(),
|
||||
debugLabel: 'backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateAlbumToAssetsV1(data.cast(), debugLabel: 'backfill');
|
||||
case SyncEntityType.albumToAssetDeleteV1:
|
||||
return _syncStreamRepository.deleteAlbumToAssetsV1(data.cast());
|
||||
// No-op. SyncAckV1 entities are checkpoints in the sync stream
|
||||
@@ -218,28 +170,15 @@ class SyncStreamService {
|
||||
case SyncEntityType.stackDeleteV1:
|
||||
return _syncStreamRepository.deleteStacksV1(data.cast());
|
||||
case SyncEntityType.partnerStackV1:
|
||||
return _syncStreamRepository.updateStacksV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner',
|
||||
);
|
||||
return _syncStreamRepository.updateStacksV1(data.cast(), debugLabel: 'partner');
|
||||
case SyncEntityType.partnerStackBackfillV1:
|
||||
return _syncStreamRepository.updateStacksV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner backfill',
|
||||
);
|
||||
return _syncStreamRepository.updateStacksV1(data.cast(), debugLabel: 'partner backfill');
|
||||
case SyncEntityType.partnerStackDeleteV1:
|
||||
return _syncStreamRepository.deleteStacksV1(
|
||||
data.cast(),
|
||||
debugLabel: 'partner',
|
||||
);
|
||||
return _syncStreamRepository.deleteStacksV1(data.cast(), debugLabel: 'partner');
|
||||
case SyncEntityType.userMetadataV1:
|
||||
return _syncStreamRepository.updateUserMetadatasV1(
|
||||
data.cast(),
|
||||
);
|
||||
return _syncStreamRepository.updateUserMetadatasV1(data.cast());
|
||||
case SyncEntityType.userMetadataDeleteV1:
|
||||
return _syncStreamRepository.deleteUserMetadatasV1(
|
||||
data.cast(),
|
||||
);
|
||||
return _syncStreamRepository.deleteUserMetadatasV1(data.cast());
|
||||
case SyncEntityType.personV1:
|
||||
return _syncStreamRepository.updatePeopleV1(data.cast());
|
||||
case SyncEntityType.personDeleteV1:
|
||||
|
||||
@@ -10,35 +10,29 @@ import 'package:immich_mobile/domain/services/setting.service.dart';
|
||||
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/timeline.repository.dart';
|
||||
import 'package:immich_mobile/utils/async_mutex.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
|
||||
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(
|
||||
int index,
|
||||
int count,
|
||||
);
|
||||
typedef TimelineAssetSource = Future<List<BaseAsset>> Function(int index, int count);
|
||||
|
||||
typedef TimelineBucketSource = Stream<List<Bucket>> Function();
|
||||
|
||||
typedef TimelineQuery = ({
|
||||
TimelineAssetSource assetSource,
|
||||
TimelineBucketSource bucketSource,
|
||||
});
|
||||
typedef TimelineQuery = ({TimelineAssetSource assetSource, TimelineBucketSource bucketSource});
|
||||
|
||||
class TimelineFactory {
|
||||
final DriftTimelineRepository _timelineRepository;
|
||||
final SettingsService _settingsService;
|
||||
|
||||
const TimelineFactory({
|
||||
required DriftTimelineRepository timelineRepository,
|
||||
required SettingsService settingsService,
|
||||
}) : _timelineRepository = timelineRepository,
|
||||
_settingsService = settingsService;
|
||||
const TimelineFactory({required DriftTimelineRepository timelineRepository, required SettingsService settingsService})
|
||||
: _timelineRepository = timelineRepository,
|
||||
_settingsService = settingsService;
|
||||
|
||||
GroupAssetsBy get groupBy =>
|
||||
GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)];
|
||||
GroupAssetsBy get groupBy {
|
||||
final group = GroupAssetsBy.values[_settingsService.get(Setting.groupAssetsBy)];
|
||||
// We do not support auto grouping in the new timeline yet, fallback to day grouping
|
||||
return group == GroupAssetsBy.auto ? GroupAssetsBy.day : group;
|
||||
}
|
||||
|
||||
TimelineService main(List<String> timelineUsers) =>
|
||||
TimelineService(_timelineRepository.main(timelineUsers, groupBy));
|
||||
TimelineService main(List<String> timelineUsers) => TimelineService(_timelineRepository.main(timelineUsers, groupBy));
|
||||
|
||||
TimelineService localAlbum({required String albumId}) =>
|
||||
TimelineService(_timelineRepository.localAlbum(albumId, groupBy));
|
||||
@@ -46,29 +40,26 @@ class TimelineFactory {
|
||||
TimelineService remoteAlbum({required String albumId}) =>
|
||||
TimelineService(_timelineRepository.remoteAlbum(albumId, groupBy));
|
||||
|
||||
TimelineService remoteAssets(String userId) =>
|
||||
TimelineService(_timelineRepository.remote(userId, groupBy));
|
||||
TimelineService remoteAssets(String userId) => TimelineService(_timelineRepository.remote(userId, groupBy));
|
||||
|
||||
TimelineService favorite(String userId) =>
|
||||
TimelineService(_timelineRepository.favorite(userId, groupBy));
|
||||
TimelineService favorite(String userId) => TimelineService(_timelineRepository.favorite(userId, groupBy));
|
||||
|
||||
TimelineService trash(String userId) =>
|
||||
TimelineService(_timelineRepository.trash(userId, groupBy));
|
||||
TimelineService trash(String userId) => TimelineService(_timelineRepository.trash(userId, groupBy));
|
||||
|
||||
TimelineService archive(String userId) =>
|
||||
TimelineService(_timelineRepository.archived(userId, groupBy));
|
||||
TimelineService archive(String userId) => TimelineService(_timelineRepository.archived(userId, groupBy));
|
||||
|
||||
TimelineService lockedFolder(String userId) =>
|
||||
TimelineService(_timelineRepository.locked(userId, groupBy));
|
||||
TimelineService lockedFolder(String userId) => TimelineService(_timelineRepository.locked(userId, groupBy));
|
||||
|
||||
TimelineService video(String userId) =>
|
||||
TimelineService(_timelineRepository.video(userId, groupBy));
|
||||
TimelineService video(String userId) => TimelineService(_timelineRepository.video(userId, groupBy));
|
||||
|
||||
TimelineService place(String place) =>
|
||||
TimelineService(_timelineRepository.place(place, groupBy));
|
||||
TimelineService place(String place) => TimelineService(_timelineRepository.place(place, groupBy));
|
||||
|
||||
TimelineService fromAssets(List<BaseAsset> assets) =>
|
||||
TimelineService(_timelineRepository.fromAssets(assets));
|
||||
TimelineService person(String userId, String personId) =>
|
||||
TimelineService(_timelineRepository.person(userId, personId, groupBy));
|
||||
|
||||
TimelineService fromAssets(List<BaseAsset> assets) => TimelineService(_timelineRepository.fromAssets(assets));
|
||||
|
||||
TimelineService map(LatLngBounds bounds) => TimelineService(_timelineRepository.map(bounds, groupBy));
|
||||
}
|
||||
|
||||
class TimelineService {
|
||||
@@ -78,26 +69,18 @@ class TimelineService {
|
||||
int _bufferOffset = 0;
|
||||
List<BaseAsset> _buffer = [];
|
||||
StreamSubscription? _bucketSubscription;
|
||||
final _log = Logger('TimelineService');
|
||||
|
||||
int _totalAssets = 0;
|
||||
int get totalAssets => _totalAssets;
|
||||
|
||||
TimelineService(TimelineQuery query)
|
||||
: this._(
|
||||
assetSource: query.assetSource,
|
||||
bucketSource: query.bucketSource,
|
||||
);
|
||||
TimelineService(TimelineQuery query) : this._(assetSource: query.assetSource, bucketSource: query.bucketSource);
|
||||
|
||||
TimelineService._({
|
||||
required TimelineAssetSource assetSource,
|
||||
required TimelineBucketSource bucketSource,
|
||||
}) : _assetSource = assetSource,
|
||||
_bucketSource = bucketSource {
|
||||
TimelineService._({required TimelineAssetSource assetSource, required TimelineBucketSource bucketSource})
|
||||
: _assetSource = assetSource,
|
||||
_bucketSource = bucketSource {
|
||||
_bucketSubscription = _bucketSource().listen((buckets) {
|
||||
_mutex.run(() async {
|
||||
final totalAssets =
|
||||
buckets.fold<int>(0, (acc, bucket) => acc + bucket.assetCount);
|
||||
final totalAssets = buckets.fold<int>(0, (acc, bucket) => acc + bucket.assetCount);
|
||||
|
||||
if (totalAssets == 0) {
|
||||
_bufferOffset = 0;
|
||||
@@ -112,10 +95,7 @@ class TimelineService {
|
||||
count = kTimelineAssetLoadBatchSize;
|
||||
} else {
|
||||
offset = _bufferOffset;
|
||||
count = math.min(
|
||||
_buffer.length,
|
||||
totalAssets - _bufferOffset,
|
||||
);
|
||||
count = math.min(_buffer.length, totalAssets - _bufferOffset);
|
||||
}
|
||||
_buffer = await _assetSource(offset, count);
|
||||
_bufferOffset = offset;
|
||||
@@ -130,10 +110,9 @@ class TimelineService {
|
||||
|
||||
Stream<List<Bucket>> Function() get watchBuckets => _bucketSource;
|
||||
|
||||
Future<List<BaseAsset>?> loadAssets(int index, int count) =>
|
||||
_mutex.run(() => _loadAssets(index, count));
|
||||
Future<List<BaseAsset>> loadAssets(int index, int count) => _mutex.run(() => _loadAssets(index, count));
|
||||
|
||||
Future<List<BaseAsset>?> _loadAssets(int index, int count) async {
|
||||
Future<List<BaseAsset>> _loadAssets(int index, int count) async {
|
||||
if (hasRange(index, count)) {
|
||||
return getAssets(index, count);
|
||||
}
|
||||
@@ -144,10 +123,7 @@ class TimelineService {
|
||||
// make sure to load a meaningful amount of data (and not only the requested slice)
|
||||
// otherwise, each call to [loadAssets] would result in DB call trashing performance
|
||||
// fills small requests to [kTimelineAssetLoadBatchSize], adds some legroom into the opposite scroll direction for large requests
|
||||
final len = math.max(
|
||||
kTimelineAssetLoadBatchSize,
|
||||
count + kTimelineAssetLoadOppositeSize,
|
||||
);
|
||||
final len = math.max(kTimelineAssetLoadBatchSize, count + kTimelineAssetLoadOppositeSize);
|
||||
// when scrolling forward, start shortly before the requested offset
|
||||
// when scrolling backward, end shortly after the requested offset to guard against the user scrolling
|
||||
// in the other direction a tiny bit resulting in another required load from the DB
|
||||
@@ -171,21 +147,18 @@ class TimelineService {
|
||||
index + count <= _bufferOffset + _buffer.length &&
|
||||
index + count <= _totalAssets;
|
||||
|
||||
List<BaseAsset>? getAssets(int index, int count) {
|
||||
List<BaseAsset> getAssets(int index, int count) {
|
||||
if (!hasRange(index, count)) {
|
||||
_log.warning('TimelineService::getAssets Index out of range');
|
||||
return null;
|
||||
throw RangeError('TimelineService::getAssets Index out of range');
|
||||
}
|
||||
int start = index - _bufferOffset;
|
||||
return _buffer.slice(start, start + count);
|
||||
}
|
||||
|
||||
// Pre-cache assets around the given index for asset viewer
|
||||
Future<void> preCacheAssets(int index) =>
|
||||
_mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
|
||||
Future<void> preCacheAssets(int index) => _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
|
||||
|
||||
BaseAsset getRandomAsset() =>
|
||||
_buffer.elementAt(math.Random().nextInt(_buffer.length));
|
||||
BaseAsset getRandomAsset() => _buffer.elementAt(math.Random().nextInt(_buffer.length));
|
||||
|
||||
BaseAsset getAsset(int index) {
|
||||
if (!hasRange(index, 1)) {
|
||||
|
||||
@@ -18,9 +18,9 @@ class UserService {
|
||||
required IsarUserRepository isarUserRepository,
|
||||
required UserApiRepository userApiRepository,
|
||||
required StoreService storeService,
|
||||
}) : _isarUserRepository = isarUserRepository,
|
||||
_userApiRepository = userApiRepository,
|
||||
_storeService = storeService;
|
||||
}) : _isarUserRepository = isarUserRepository,
|
||||
_userApiRepository = userApiRepository,
|
||||
_storeService = storeService;
|
||||
|
||||
UserDto getMyUser() {
|
||||
return _storeService.get(StoreKey.currentUser);
|
||||
@@ -44,10 +44,7 @@ class UserService {
|
||||
|
||||
Future<String?> createProfileImage(String name, Uint8List image) async {
|
||||
try {
|
||||
final path = await _userApiRepository.createProfileImage(
|
||||
name: name,
|
||||
data: image,
|
||||
);
|
||||
final path = await _userApiRepository.createProfileImage(name: name, data: image);
|
||||
final updatedUser = getMyUser().copyWith(profileImagePath: path);
|
||||
await _storeService.put(StoreKey.currentUser, updatedUser);
|
||||
await _isarUserRepository.update(updatedUser);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user